-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Extract logic to classes * Update specs
- Loading branch information
Showing
5 changed files
with
273 additions
and
202 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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("<p>text</p>") | ||
# | ||
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 = '<p>some text</p>' | ||
expected_output = '<p dir="auto">some text</p>' | ||
it '#bidify_html_string calls HtmlStringBidifier#apply with the given input' do | ||
input = '<p>some text</p>' | ||
|
||
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 | ||
<div>Content</div> | ||
<h1>Content</h1> | ||
<h2>Content</h2> | ||
<h3>Content</h3> | ||
<h4>Content</h4> | ||
<h5>Content</h5> | ||
<h6>Content</h6> | ||
<p>Content</p> | ||
<blockquote>Content</blockquote> | ||
HTML | ||
|
||
expected_output = <<~HTML | ||
<div dir="auto">Content</div> | ||
<h1 dir="auto">Content</h1> | ||
<h2 dir="auto">Content</h2> | ||
<h3 dir="auto">Content</h3> | ||
<h4 dir="auto">Content</h4> | ||
<h5 dir="auto">Content</h5> | ||
<h6 dir="auto">Content</h6> | ||
<p dir="auto">Content</p> | ||
<blockquote dir="auto">Content</blockquote> | ||
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 | ||
<blockquote> | ||
<p>Item 1</p> | ||
<p>Item 2</p> | ||
</blockquote> | ||
HTML | ||
|
||
expected_output = <<~HTML | ||
<blockquote dir="auto"> | ||
<p>Item 1</p> | ||
<p dir="auto">Item 2</p> | ||
</blockquote> | ||
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 | ||
<ul> | ||
<li> | ||
Item 1 | ||
<p>with paragraph</p> | ||
</li> | ||
<li> | ||
<p>Paragram at the begining of</p> | ||
Item 2 | ||
</li> | ||
</ul> | ||
HTML | ||
|
||
expected_output = <<~HTML | ||
<ul dir="auto"> | ||
<li> | ||
Item 1 | ||
<p dir="auto">with paragraph</p> | ||
</li> | ||
<li> | ||
<p>Paragram at the begining of</p> | ||
Item 2 | ||
</li> | ||
</ul> | ||
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 | ||
<blockquote> | ||
blah | ||
<p>Item 1</p> | ||
<p>Item 2</p> | ||
</blockquote> | ||
HTML | ||
|
||
expected_output = <<~HTML | ||
<blockquote dir="auto"> | ||
blah | ||
<p dir="auto">Item 1</p> | ||
<p dir="auto">Item 2</p> | ||
</blockquote> | ||
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 | ||
<blockquote> | ||
<!-- comment --> | ||
<p>Item 1</p> | ||
<p>Item 2</p> | ||
</blockquote> | ||
HTML | ||
|
||
expected_output = <<~HTML | ||
<blockquote dir="auto"> | ||
<!-- comment --> | ||
<p>Item 1</p> | ||
<p dir="auto">Item 2</p> | ||
</blockquote> | ||
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 | ||
<span>Not getting affected</span> | ||
<img src="image.png"> | ||
<main>content</main> | ||
<section>content</section> | ||
<aside>content</aside> | ||
<a>content</a> | ||
HTML | ||
|
||
expected_output = input | ||
|
||
actual_output = Bidify.bidify(input) | ||
|
||
expect(actual_output).to eq expected_output | ||
end | ||
|
||
it 'skips blank lines' do | ||
input = <<~HTML | ||
<blockquote> | ||
<p>Item 1</p> | ||
<p>Item 2</p> | ||
</blockquote> | ||
HTML | ||
|
||
expected_output = <<~HTML | ||
<blockquote dir="auto"> | ||
<p>Item 1</p> | ||
<p dir="auto">Item 2</p> | ||
</blockquote> | ||
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 |
Oops, something went wrong.