From 1d131f8c1297f9935b0998023830216781bc1ef4 Mon Sep 17 00:00:00 2001 From: Mostafa Ahangarha Date: Sun, 2 Jul 2023 18:10:21 +0330 Subject: [PATCH] Refactor to class (#8) * Extract logic to classes * Update specs --- lib/bidify.rb | 45 +++---- lib/bidify/bidifier.rb | 38 ++++++ lib/bidify/html_string_bidifier.rb | 31 +++++ spec/bidify_spec.rb | 178 ++-------------------------- spec/html_string_bidifier_spec.rb | 183 +++++++++++++++++++++++++++++ 5 files changed, 273 insertions(+), 202 deletions(-) create mode 100644 lib/bidify/bidifier.rb create mode 100644 lib/bidify/html_string_bidifier.rb create mode 100644 spec/html_string_bidifier_spec.rb diff --git a/lib/bidify.rb b/lib/bidify.rb index 8c01bae..c317b82 100644 --- a/lib/bidify.rb +++ b/lib/bidify.rb @@ -1,43 +1,26 @@ # frozen_string_literal: true -require 'nokogiri' +require 'bidify/html_string_bidifier' -# Bidify applies `dir="auto"` to the given html string +# == Bidify module # -# ### Example: +# The namespace and helper methods for bidiying HTML contents # -# bidified_html = Bidify.bidify(regular_html) +# == Example: +# +# bidified_html = Bidify.bidify_html_string(regular_html) module Bidify - @bidifiable_tags = %w[div h1 h2 h3 h4 h5 h6 p ul ol blockquote] + DEFAULT_BIDIFIABLE_TAGS = %w[div h1 h2 h3 h4 h5 h6 p ul ol blockquote].freeze class << self ### - # bidify applies dir="auto" to the given html string - def bidify(input_html) - html_node = Nokogiri::HTML.fragment(input_html) - bidify_recursively(html_node, { root: true }) - - html_node.to_s - end - - private - - def bidify_recursively(html_node, options = {}) - seen_the_first_bidifiable_element = false - - html_node.children.each do |child_node| - bidify_recursively(child_node) - - if (options[:root] || seen_the_first_bidifiable_element) && @bidifiable_tags.include?(child_node.name) - child_node.set_attribute('dir', 'auto') - end - - seen_the_first_bidifiable_element = true if actual_content?(child_node) - end - end - - def actual_content?(node) - node.element? || (node.text? && !node.blank?) + # Applies dir="auto" to the given html string with default configuration + # + # @param [String] html_string a stringified HTML content + # @return [String] Bidified version of the input string + # + def bidify_html_string(html_string) + Bidify::HtmlStringBidifier.new.apply(html_string) end end end diff --git a/lib/bidify/bidifier.rb b/lib/bidify/bidifier.rb new file mode 100644 index 0000000..6685a6b --- /dev/null +++ b/lib/bidify/bidifier.rb @@ -0,0 +1,38 @@ +# frozen_string_literal: true + +module Bidify + # Super class for custom bidifiers + class Bidifier + def initialize + configure + end + + def apply + raise NotImplementedError + end + + private + + def configure + @bidifiable_tags = DEFAULT_BIDIFIABLE_TAGS.dup + end + + def bidify_recursively(html_node, options = {}) + seen_the_first_bidifiable_element = false + + html_node.children.each do |child_node| + bidify_recursively(child_node) + + if (options[:root] || seen_the_first_bidifiable_element) && @bidifiable_tags.include?(child_node.name) + child_node.set_attribute('dir', 'auto') + end + + seen_the_first_bidifiable_element = true if actual_content?(child_node) + end + end + + def actual_content?(node) + node.element? || (node.text? && !node.blank?) + end + end +end diff --git a/lib/bidify/html_string_bidifier.rb b/lib/bidify/html_string_bidifier.rb new file mode 100644 index 0000000..d3e7509 --- /dev/null +++ b/lib/bidify/html_string_bidifier.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true + +require 'nokogiri' +require_relative 'bidifier' + +module Bidify + ### + # Bidifying html input as string + # + # == Example Usage + # + # Here's an example of how to use the class: + # + # bidifier = HtmlStringBidifier.new + # bidifier.apply("

text

") + # + class HtmlStringBidifier < Bidifier + ### + # Applies dir="auto" to the given html string with default configuration + # + # @param [String] html_string a stringified HTML content + # @return [String] Bidified version of the input string + # + def apply(html_input) + html_node = Nokogiri::HTML.fragment(html_input) + bidify_recursively(html_node, { root: true }) + + html_node.to_s + end + end +end diff --git a/spec/bidify_spec.rb b/spec/bidify_spec.rb index 254b127..cdd194b 100644 --- a/spec/bidify_spec.rb +++ b/spec/bidify_spec.rb @@ -1,181 +1,17 @@ # frozen_string_literal: true require 'bidify' +require 'bidify/html_string_bidifier' describe 'Bidify' do - describe '#bidify' do - it 'bidifies a single paragraph' do - input = '

some text

' - expected_output = '

some text

' + it '#bidify_html_string calls HtmlStringBidifier#apply with the given input' do + input = '

some text

' - actual_output = Bidify.bidify(input) + html_string_bidifier = instance_spy(Bidify::HtmlStringBidifier) + allow(Bidify::HtmlStringBidifier).to receive(:new).and_return(html_string_bidifier) - expect(actual_output).to eq expected_output - end + Bidify.bidify_html_string(input) - it 'bidifies all non-list tags in bidifiable tags list' do - input = <<~HTML -
Content
-

Content

-

Content

-

Content

-

Content

-
Content
-
Content
-

Content

-
Content
- HTML - - expected_output = <<~HTML -
Content
-

Content

-

Content

-

Content

-

Content

-
Content
-
Content
-

Content

-
Content
- HTML - - actual_output = Bidify.bidify(input) - - expect(actual_output).to eq expected_output - end - - it 'bidifies non list nested elements and ignore the first inner element' do - input = <<~HTML -
-

Item 1

-

Item 2

-
- HTML - - expected_output = <<~HTML -
-

Item 1

-

Item 2

-
- HTML - - actual_output = Bidify.bidify(input) - - expect(actual_output).to eq expected_output - end - - it "doesn't bidify li elements by default" do - input = <<~HTML - - HTML - - expected_output = <<~HTML - - HTML - - actual_output = Bidify.bidify(input) - - expect(actual_output).to eq expected_output - end - - it 'bidifies non-list nested elements with plain text as the first content' do - input = <<~HTML -
- blah -

Item 1

-

Item 2

-
- HTML - - expected_output = <<~HTML -
- blah -

Item 1

-

Item 2

-
- HTML - - actual_output = Bidify.bidify(input) - - expect(actual_output).to eq expected_output - end - - it 'bidifies non-list nested elements and ignores html comments' do - input = <<~HTML -
- -

Item 1

-

Item 2

-
- HTML - - expected_output = <<~HTML -
- -

Item 1

-

Item 2

-
- HTML - - actual_output = Bidify.bidify(input) - - expect(actual_output).to eq expected_output - end - - it 'skips tags not included in bidifiable tags by default' do - input = <<~HTML - Not getting affected - -
content
-
content
- - content - HTML - - expected_output = input - - actual_output = Bidify.bidify(input) - - expect(actual_output).to eq expected_output - end - - it 'skips blank lines' do - input = <<~HTML -
- -

Item 1

-

Item 2

-
- HTML - - expected_output = <<~HTML -
- -

Item 1

-

Item 2

-
- HTML - - actual_output = Bidify.bidify(input) - - expect(actual_output).to eq expected_output - end + expect(html_string_bidifier).to have_received(:apply).with(input) end end diff --git a/spec/html_string_bidifier_spec.rb b/spec/html_string_bidifier_spec.rb new file mode 100644 index 0000000..77c5f25 --- /dev/null +++ b/spec/html_string_bidifier_spec.rb @@ -0,0 +1,183 @@ +# frozen_string_literal: true + +require 'bidify' + +describe 'Bidify' do + describe '::StringHtmlBidifier.apply' do + let(:bidifier) { Bidify::HtmlStringBidifier.new } + + it 'bidifies a single paragraph' do + input = '

some text

' + expected_output = '

some text

' + + actual_output = bidifier.apply(input) + + expect(actual_output).to eq expected_output + end + + it 'bidifies all non-list tags in bidifiable tags list' do + input = <<~HTML +
Content
+

Content

+

Content

+

Content

+

Content

+
Content
+
Content
+

Content

+
Content
+ HTML + + expected_output = <<~HTML +
Content
+

Content

+

Content

+

Content

+

Content

+
Content
+
Content
+

Content

+
Content
+ HTML + + actual_output = bidifier.apply(input) + + expect(actual_output).to eq expected_output + end + + it 'bidifies non list nested elements and ignore the first inner element' do + input = <<~HTML +
+

Item 1

+

Item 2

+
+ HTML + + expected_output = <<~HTML +
+

Item 1

+

Item 2

+
+ HTML + + actual_output = bidifier.apply(input) + + expect(actual_output).to eq expected_output + end + + it "doesn't bidify li elements by default" do + input = <<~HTML + + HTML + + expected_output = <<~HTML + + HTML + + actual_output = bidifier.apply(input) + + expect(actual_output).to eq expected_output + end + + it 'bidifies non-list nested elements with plain text as the first content' do + input = <<~HTML +
+ blah +

Item 1

+

Item 2

+
+ HTML + + expected_output = <<~HTML +
+ blah +

Item 1

+

Item 2

+
+ HTML + + actual_output = bidifier.apply(input) + + expect(actual_output).to eq expected_output + end + + it 'bidifies non-list nested elements and ignores html comments' do + input = <<~HTML +
+ +

Item 1

+

Item 2

+
+ HTML + + expected_output = <<~HTML +
+ +

Item 1

+

Item 2

+
+ HTML + + actual_output = bidifier.apply(input) + + expect(actual_output).to eq expected_output + end + + it 'skips tags not included in bidifiable tags by default' do + input = <<~HTML + Not getting affected + +
content
+
content
+ + content + HTML + + expected_output = input + + actual_output = bidifier.apply(input) + + expect(actual_output).to eq expected_output + end + + it 'skips blank lines' do + input = <<~HTML +
+ +

Item 1

+

Item 2

+
+ HTML + + expected_output = <<~HTML +
+ +

Item 1

+

Item 2

+
+ HTML + + actual_output = bidifier.apply(input) + + expect(actual_output).to eq expected_output + end + end +end