html-to-haml 0.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 15bb392209552a1c2c5ed225486c98bb620bdb1c
4
+ data.tar.gz: 3b55b8c57a4577aed92b1766ffabb5ec6f0eb0e4
5
+ SHA512:
6
+ metadata.gz: c251c16238f91a8123f7d4f36a5a1516a5668ce43a0fe78be96915ce8d28134b1251632de2cf12d34528235e5767b3f53f5fa27fce1dfb8459581a115dbbb09b
7
+ data.tar.gz: f048b0b54befe18ff66d807f699664537954e803f67ae48003b963c1e39dc180e69f2fc0ba96f66c59367e39a3e5987a6abd0e93d692a1c510f4b972595cc22c
@@ -0,0 +1,45 @@
1
+ require_relative './use_cases/html/conversion_use_case'
2
+ require_relative './use_cases/erb/basic_conversion_use_case'
3
+ require_relative './use_cases/non_html_selector_blocks/style_conversion_use_case'
4
+ require_relative './use_cases/non_html_selector_blocks/script_conversion_use_case'
5
+
6
+ module HtmlToHaml
7
+ class Converter
8
+ def initialize(html)
9
+ @html = html
10
+ end
11
+
12
+ def convert
13
+ whitespace_free_html = remove_html_whitespace(html: @html)
14
+ erb_converted_haml = Erb::BasicConversionUseCase.new(whitespace_free_html).convert
15
+ haml = NonHtmlSelectorBlocks::StyleConversionUseCase.new(erb_converted_haml).convert
16
+ haml = NonHtmlSelectorBlocks::ScriptConversionUseCase.new(haml).convert
17
+ Html::ConversionUseCase.new(haml, remove_whitespace: false).convert
18
+ end
19
+
20
+ private
21
+
22
+ def remove_html_whitespace(html:)
23
+ html.gsub(/#{html_with_important_whitespace}|^\s*|\n/) do |matching_html|
24
+ case matching_html
25
+ when /#{html_with_important_whitespace}/
26
+ initial_indentation = matching_html.gsub("\n", '').match(/^\s*/).to_s
27
+ matching_html.gsub(/^#{initial_indentation}/, "\n")
28
+ else
29
+ ""
30
+ end
31
+ end
32
+ end
33
+
34
+ def html_with_important_whitespace
35
+ important_whitespace_classes.map do |klass|
36
+ "^\\s*<#{klass::HTML_TAG_NAME}.*?>(.|\n)*?<\/#{klass::HTML_TAG_NAME}>"
37
+ end.join("|")
38
+ end
39
+
40
+ def important_whitespace_classes
41
+ [NonHtmlSelectorBlocks::ScriptConversionUseCase,
42
+ NonHtmlSelectorBlocks::StyleConversionUseCase]
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,9 @@
1
+ module HtmlToHaml
2
+ module HamlWhitespaceCleaner
3
+ private
4
+
5
+ def remove_haml_whitespace(haml:)
6
+ haml.lstrip.gsub(/\n\s*\n/, "\n")
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,16 @@
1
+ module HtmlToHaml
2
+ INDENTATION_AMOUNT = 2
3
+
4
+ class ParseError < RuntimeError
5
+ end
6
+
7
+ module Html
8
+ class ParseError < HtmlToHaml::ParseError
9
+ end
10
+ end
11
+
12
+ module Erb
13
+ class ParseError < HtmlToHaml::ParseError
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,45 @@
1
+ require 'singleton'
2
+
3
+ module HtmlToHaml
4
+ module Erb
5
+ class ControlFlowMatcher
6
+ include Singleton
7
+
8
+ CONTROL_FLOW_MIDDLE_OF_LINE_KEYWORDS = ["do"]
9
+ CONTROL_FLOW_BEGINNING_OF_LINE_KEYWORDS = ["if", "unless"]
10
+ CONTROL_FLOW_CONTINUE_KEYWORDS = ["elsif", "else", "when"]
11
+
12
+ def begin_case_statement?(erb:)
13
+ matches_keywords_at_beginning_of_line?(erb: erb, keywords: ["case"])
14
+ end
15
+
16
+ def begin_indented_control_flow?(erb:)
17
+ matches_keywords?(erb: erb, keywords: CONTROL_FLOW_MIDDLE_OF_LINE_KEYWORDS) ||
18
+ matches_keywords_at_beginning_of_line?(erb: erb, keywords: CONTROL_FLOW_BEGINNING_OF_LINE_KEYWORDS)
19
+ end
20
+
21
+ def continue_indented_control_flow?(erb:)
22
+ matches_keywords_at_beginning_of_line?(erb: erb, keywords: CONTROL_FLOW_CONTINUE_KEYWORDS)
23
+ end
24
+
25
+ def end_of_block?(erb:)
26
+ erb_without_strings(erb: erb) =~ /\s*-\send/
27
+ end
28
+
29
+ private
30
+
31
+ def matches_keywords_at_beginning_of_line?(erb:, keywords:)
32
+ erb_without_strings(erb: erb) =~ /\s*(-|=)\s*(#{keywords.join("|")})(\s|$)/
33
+ end
34
+
35
+ def matches_keywords?(erb:, keywords:)
36
+ erb_without_strings(erb: erb) =~ /\s*(-|=)(.*)\s+(#{keywords.join("|")})(\s|$)/
37
+ end
38
+
39
+ def erb_without_strings(erb:)
40
+ erb.gsub(/".*?"/, '').gsub(/'.*?'/, '')
41
+ end
42
+ end
43
+ end
44
+ end
45
+
@@ -0,0 +1,37 @@
1
+ module HtmlToHaml
2
+ module Erb
3
+ class IndentationTracker
4
+ attr_accessor :indentation_level
5
+ attr_reader :indentation_amount, :case_statement_level
6
+ def initialize(indentation_level:, indentation_amount:)
7
+ @indentation_level = indentation_level
8
+ @indentation_amount = indentation_amount
9
+ @case_statement_level = []
10
+ end
11
+
12
+ def begin_case_statement
13
+ self.indentation_level += indentation_amount * 2
14
+ case_statement_level << indentation_level
15
+ end
16
+
17
+ def add_indentation
18
+ self.indentation_level += indentation_amount
19
+ end
20
+
21
+ def end_block
22
+ if indentation_level == @case_statement_level.last
23
+ case_statement_level.pop
24
+ self.indentation_level -= indentation_amount * 2
25
+ else
26
+ self.indentation_level -= indentation_amount
27
+ end
28
+ end
29
+
30
+ # I may allow people to use this for nested case statements,
31
+ # but reserve the right to be snarky about it when they do.
32
+ def nested_case_statement?
33
+ case_statement_level.length > 1
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,53 @@
1
+ module HtmlToHaml
2
+ module Html
3
+ class AttributeHandler
4
+ HTML_ONLY_ATTRIBUTE_REGEX = /=['"][^#\{]*['"]/
5
+
6
+ def initialize
7
+ @ids = []
8
+ @classes = []
9
+ @plain_attributes = []
10
+ end
11
+
12
+ def add_attribute(attr:)
13
+ if use_id_syntax?(attr: attr)
14
+ @ids += extract_attribute_value(attr: attr).split(' ')
15
+ elsif use_class_syntax?(attr: attr)
16
+ @classes += extract_attribute_value(attr: attr).split(' ')
17
+ else
18
+ @plain_attributes << attr.strip.gsub(/=/, ': ')
19
+ end
20
+ end
21
+
22
+ def attributes_string
23
+ "#{format_ids}#{format_classes}#{format_attributes}"
24
+ end
25
+
26
+ private
27
+
28
+ def use_id_syntax?(attr:)
29
+ attr =~ /id#{HTML_ONLY_ATTRIBUTE_REGEX}/
30
+ end
31
+
32
+ def use_class_syntax?(attr:)
33
+ attr =~ /class#{HTML_ONLY_ATTRIBUTE_REGEX}/
34
+ end
35
+
36
+ def extract_attribute_value(attr:)
37
+ attr.gsub(/.*=['"](.*)['"]/, '\1').strip
38
+ end
39
+
40
+ def format_attributes
41
+ @plain_attributes.empty? ? '' : "{ #{@plain_attributes.join(', ')} }"
42
+ end
43
+
44
+ def format_ids
45
+ @ids.empty? ? '' : "##{@ids.join('#')}"
46
+ end
47
+
48
+ def format_classes
49
+ @classes.empty? ? '' : ".#{@classes.join('.')}"
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,31 @@
1
+ require_relative '../../html_to_haml'
2
+
3
+ module HtmlToHaml::Html
4
+ class IndentationTracker
5
+ def initialize(indentation_amount:)
6
+ @indentation_level = 0
7
+ @inside_self_closing_tag = false
8
+ @indentation_amount = indentation_amount
9
+ end
10
+
11
+ def start_html_tag
12
+ @indentation_level += @indentation_amount unless @inside_self_closing_tag
13
+ @inside_self_closing_tag = false
14
+ end
15
+
16
+ def start_self_closing_tag
17
+ @inside_self_closing_tag = true
18
+ end
19
+
20
+ def close_html_tag
21
+ @indentation_level -= @indentation_amount
22
+ if @indentation_level < 0
23
+ raise ParseError, 'The html is malformed and is attempting to close an html tag that was never started'
24
+ end
25
+ end
26
+
27
+ def indentation
28
+ " " * @indentation_level
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,35 @@
1
+ module HtmlToHaml
2
+ module NonHtmlSelectorBlocks
3
+ class IndentationTracker
4
+ attr_reader :indented, :adjust_whitespace
5
+
6
+ def initialize(indented:, adjust_whitespace:)
7
+ @indented = indented
8
+ @reset_adjust_whitespace = false
9
+ @adjust_whitespace = adjust_whitespace
10
+ end
11
+
12
+ def indent
13
+ return if indented
14
+ @indented = true
15
+ @reset_adjust_whitespace = true
16
+ end
17
+
18
+ def outdent
19
+ return unless indented
20
+ @indented = false
21
+ @adjust_whitespace = false
22
+ @reset_adjust_whitespace = false
23
+ end
24
+
25
+ def adjust_whitespace?(reset_value: adjust_whitespace)
26
+ if @reset_adjust_whitespace
27
+ @reset_adjust_whitespace = false
28
+ @adjust_whitespace = reset_value
29
+ else
30
+ @adjust_whitespace
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,35 @@
1
+ module HtmlToHaml
2
+ module NonHtmlSelectorBlocks
3
+ module TagTypeMatchers
4
+ TAG_TYPE_REGEX = "type=('|\")(.*?)('|\")"
5
+ TAG_TYPE_FROM_REGEX = '\2'
6
+
7
+ private
8
+
9
+ def opening_tag?(tag:, in_block:)
10
+ !in_block && tag =~ /#{opening_tag_regex}/
11
+ end
12
+
13
+ def opening_tag_regex
14
+ "<#{self.class::HTML_TAG_NAME}.*?>"
15
+ end
16
+
17
+ def closing_tag?(tag:, in_block:)
18
+ in_block && tag =~ /#{closing_tag_regex}/
19
+ end
20
+
21
+ def closing_tag_regex
22
+ "<\/#{self.class::HTML_TAG_NAME}>"
23
+ end
24
+
25
+ def tag_type(tag:)
26
+ specified_tag_type(tag: tag) || self.class::DEFAULT_TAG_TYPE
27
+ end
28
+
29
+ def specified_tag_type(tag:)
30
+ type_match = tag.match(/#{self.class::TAG_TYPE_REGEX}/)
31
+ type_match && type_match.to_s.gsub(/#{self.class::TAG_TYPE_REGEX}/, self.class::TAG_TYPE_FROM_REGEX).split('/').last
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,39 @@
1
+ require_relative '../../html_to_haml'
2
+ require_relative '../../helpers/haml_whitespace_cleaner'
3
+ require_relative 'indentation_conversion_use_case'
4
+
5
+ module HtmlToHaml::Erb
6
+ class BasicConversionUseCase
7
+ include HtmlToHaml::HamlWhitespaceCleaner
8
+
9
+ def initialize(erb)
10
+ @erb = erb
11
+ end
12
+
13
+ def convert
14
+ sanitized_erb = remove_newlines_within_erb_statements(erb: @erb)
15
+ erb = convert_syntax(erb: sanitized_erb)
16
+ haml = convert_indentation(erb: erb)
17
+ remove_haml_whitespace(haml: haml)
18
+ end
19
+
20
+ private
21
+
22
+ def remove_newlines_within_erb_statements(erb:)
23
+ erb.gsub(/<%(.*?)\n(.*?)%>/) do |erb_statement|
24
+ erb_statement.gsub("\n", " ")
25
+ end
26
+ end
27
+
28
+ def convert_syntax(erb:)
29
+ erb.gsub(/\s*?\n?(<%=|<%-|<%)\s?/) do |erb_selector|
30
+ erb_selector_index = erb_selector =~ /-|=/
31
+ erb_selector_index ? "\n#{erb_selector[erb_selector_index]} " : "\n- "
32
+ end.gsub(/\s?(-%>|%>)/, "\n")
33
+ end
34
+
35
+ def convert_indentation(erb:)
36
+ IndentationConversionUseCase.instance.convert_indentation(erb: erb)
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,85 @@
1
+ require 'singleton'
2
+ require 'forwardable'
3
+ require_relative '../../html_to_haml'
4
+ require_relative '../../tools/erb/indentation_tracker'
5
+ require_relative '../../tools/erb/control_flow_matcher'
6
+
7
+ module HtmlToHaml::Erb
8
+ class IndentationConversionUseCase
9
+ include Singleton
10
+ extend ::Forwardable
11
+
12
+ SNARKY_COMMENT_FOR_HAVING_NESTED_CASE_STATEMENTS = <<-HAML
13
+ / It looks like this is the start of a nested case statement
14
+ / Are you REALLY sure you want or need one? Really?
15
+ / This converter will convert it for you below, but you should
16
+ / seriously rethink your code right now.
17
+ HAML
18
+
19
+ def convert_indentation(erb:)
20
+ indentation_converter = new_indentation_converter
21
+ erb.split("\n").map do |erb_line|
22
+ indentation = indentation_for_line_or_error(erb: erb_line, indentation_level: indentation_converter.indentation_level)
23
+ adjust_indentation_level(erb: erb_line, indentation_converter: indentation_converter)
24
+ construct_haml_line(erb: erb_line, indentation: indentation, indentation_converter: indentation_converter)
25
+ end.join
26
+ end
27
+
28
+ private
29
+
30
+ def_delegators :control_flow_matcher, :begin_case_statement?,
31
+ :begin_indented_control_flow?, :end_of_block?,
32
+ :continue_indented_control_flow?
33
+
34
+ def adjust_indentation_level(erb:, indentation_converter:)
35
+ if begin_case_statement?(erb: erb)
36
+ indentation_converter.begin_case_statement
37
+ elsif begin_indented_control_flow?(erb: erb)
38
+ indentation_converter.add_indentation
39
+ elsif end_of_block?(erb: erb)
40
+ indentation_converter.end_block
41
+ end
42
+ end
43
+
44
+ def indentation_for_line_or_error(erb:, indentation_level:)
45
+ adjusted_indentation_level = adjusted_indentation_level_for_line(erb: erb, indentation_level: indentation_level)
46
+ if adjusted_indentation_level < 0
47
+ raise ParseError, 'The erb is malformed. Please make sure you have the correct number of "end" statements'
48
+ else
49
+ " " * adjusted_indentation_level
50
+ end
51
+ end
52
+
53
+ def adjusted_indentation_level_for_line(erb:, indentation_level:)
54
+ if continue_indented_control_flow?(erb: erb)
55
+ indentation_level - HtmlToHaml::INDENTATION_AMOUNT
56
+ else
57
+ indentation_level
58
+ end
59
+ end
60
+
61
+ def construct_haml_line(erb:, indentation:, indentation_converter:)
62
+ indentation_adjusted_haml_line = "#{indentation}"
63
+ if begin_nested_case_statement?(erb: erb, indentation_converter: indentation_converter)
64
+ indentation_adjusted_haml_line << nested_case_statement_commentary(indentation: indentation)
65
+ end
66
+ indentation_adjusted_haml_line << "#{erb}\n" unless end_of_block?(erb: erb)
67
+ end
68
+
69
+ def begin_nested_case_statement?(erb:, indentation_converter:)
70
+ begin_case_statement?(erb: erb) && indentation_converter.nested_case_statement?
71
+ end
72
+
73
+ def nested_case_statement_commentary(indentation:)
74
+ SNARKY_COMMENT_FOR_HAVING_NESTED_CASE_STATEMENTS.gsub("\n", "\n#{indentation}")
75
+ end
76
+
77
+ def new_indentation_converter
78
+ IndentationTracker.new(indentation_level: 0, indentation_amount: HtmlToHaml::INDENTATION_AMOUNT)
79
+ end
80
+
81
+ def control_flow_matcher
82
+ ControlFlowMatcher.instance
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,48 @@
1
+ require 'singleton'
2
+ require_relative '../../html_to_haml'
3
+ require_relative '../../tools/html/attribute_handler'
4
+
5
+ module HtmlToHaml::Html
6
+ class AttributeConversionUseCase
7
+ include Singleton
8
+
9
+ HAML_TAG_LINES = "^\s*%(.*)$"
10
+ MULTILINE_ERB_ATTRIBUTES_REGEX = /^\s*%.*[a-zA-Z1-9]+?=('|")[^'"]*\s*\n\s*=.*\n\s*[^'"]*("|')/
11
+
12
+ def convert_attributes(html:)
13
+ erb_converted_html = remove_erb_newlines(html: html)
14
+ erb_converted_html.gsub(/#{HAML_TAG_LINES}/) do |matched_elem|
15
+ haml_with_replaced_attributes(haml: matched_elem)
16
+ end
17
+ end
18
+
19
+ private
20
+
21
+ def haml_with_replaced_attributes(haml:)
22
+ attribute_handler = AttributeHandler.new
23
+ haml_without_attributes = haml.gsub(/\s*([a-zA-Z1-9]+?)=('|").*?('|")/) do |matched_elem|
24
+ # This could go into the AttributeHandler, but at the moment this is the only place
25
+ # that is aware of the erb syntax and that makes the AttributeHandler more isolated.
26
+ attr = escape_erb_attributes(attr: matched_elem)
27
+ attribute_handler.add_attribute(attr: attr)
28
+ ''
29
+ end
30
+ "#{haml_without_attributes}#{attribute_handler.attributes_string}"
31
+ end
32
+
33
+ def remove_erb_newlines(html:)
34
+ # Erb attributes may be malformed to have their own line and a '=' in front
35
+ # (if the html already went through the erb converter)
36
+ # This changes them back into something that can be updated above
37
+ html.gsub(MULTILINE_ERB_ATTRIBUTES_REGEX) do |erb_attr|
38
+ erb_attr.gsub(/\n\s*(=|.*?'|.*?")/, ' \1')
39
+ end
40
+ end
41
+
42
+ def escape_erb_attributes(attr:)
43
+ attr.gsub(/=('|")(.*?)\s*=\s*([^\s]*)(\s*.*)('|")/, '=\1\2 #{\3}\4\5') # put erb text inside #{} globally
44
+ .gsub(/('|")\s*#\{(.*)\}\s*('|")/, '\2') # Remove strings and #{} around simple erb expressions (with no non-erb)
45
+ .gsub(/\s('|")$/, '\1') # Get rid of any extra whitespace.
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,34 @@
1
+ require_relative '../../html_to_haml'
2
+
3
+ module HtmlToHaml::Html
4
+ class CommentConversionUseCase
5
+ HTML_COMMENT_REGEX = "<!--(.|\n)*?-->"
6
+ HTML_USING_HAML_COMMENT_SYNTAX = "^\s*\/"
7
+
8
+ def initialize(html)
9
+ @html = html
10
+ end
11
+
12
+ def convert
13
+ haml = @html.gsub(/#{HTML_COMMENT_REGEX}|#{HTML_USING_HAML_COMMENT_SYNTAX}/) do |comment|
14
+ case comment
15
+ when /#{HTML_COMMENT_REGEX}/
16
+ "\n/ #{format_html_comment_for_haml(comment: comment)}\n"
17
+ when /#{HTML_USING_HAML_COMMENT_SYNTAX}/
18
+ escape_misleading_forward_slash(comment: comment)
19
+ end
20
+ end
21
+ haml.gsub(/\n\s*\n/, "\n")
22
+ end
23
+
24
+ private
25
+
26
+ def format_html_comment_for_haml(comment:)
27
+ comment.gsub(/\n\s*/, "\n/ ")[4..-4].strip
28
+ end
29
+
30
+ def escape_misleading_forward_slash(comment:)
31
+ comment.gsub(/^(\s*)\//, '\1\/')
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,19 @@
1
+ require_relative '../../html_to_haml'
2
+ require_relative './attribute_conversion_use_case'
3
+ require_relative './comment_conversion_use_case'
4
+ require_relative './default_conversion_use_case'
5
+
6
+ module HtmlToHaml::Html
7
+ class ConversionUseCase
8
+ def initialize(html, remove_whitespace: true)
9
+ @html = html
10
+ @remove_whitespace = remove_whitespace
11
+ end
12
+
13
+ def convert
14
+ html_with_haml_comments = CommentConversionUseCase.new(@html).convert
15
+ haml = DefaultConversionUseCase.new(html_with_haml_comments, remove_whitespace: @remove_whitespace).convert
16
+ AttributeConversionUseCase.instance.convert_attributes(html: haml)
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,73 @@
1
+ require_relative '../../html_to_haml'
2
+ require_relative '../../helpers/haml_whitespace_cleaner'
3
+ require_relative '../../tools/html/indentation_tracker'
4
+
5
+ module HtmlToHaml::Html
6
+ class DefaultConversionUseCase
7
+ include HtmlToHaml::HamlWhitespaceCleaner
8
+
9
+ HAML_SYMBOL_REGEX = ">\s*(\/|-|=)"
10
+ ERB_LINE_REGEX = "\n\s*(-|=).*$"
11
+ CLOSING_HTML_REGEX = "<\/.*?>"
12
+ # For self-closing html tags that aren't self-closing by default
13
+ SELF_CLOSING_HTML_REGEX = "\/>"
14
+ SELF_CLOSING_TAGS = %w(area base br col command embed hr img input keygen link meta param source track wbr)
15
+
16
+ def initialize(html, remove_whitespace: true)
17
+ # Since Haml uses whitespace in a way html doesn't, this starts by stripping
18
+ # whitespace to start the next gsub with a clean slate. Unless the caller opts
19
+ # out.
20
+ @html = if remove_whitespace
21
+ remove_html_whitespace(html: html)
22
+ else
23
+ html
24
+ end
25
+ end
26
+
27
+ def convert
28
+ indentation_tracker = IndentationTracker.new(indentation_amount: HtmlToHaml::INDENTATION_AMOUNT)
29
+ haml = @html.gsub(/#{ERB_LINE_REGEX}|#{CLOSING_HTML_REGEX}|#{SELF_CLOSING_HTML_REGEX}|#{self_closing_tag_regex}|#{HAML_SYMBOL_REGEX}|<|>|\n/) do |matched_elem|
30
+ adjust_indentation_level(html: matched_elem, indentation_tracker: indentation_tracker)
31
+ start_of_line = "\n#{indentation_tracker.indentation}"
32
+ case matched_elem
33
+ when /#{ERB_LINE_REGEX}/
34
+ "#{start_of_line}#{matched_elem[1..-1]}"
35
+ when /#{self_closing_tag_regex}/
36
+ "#{start_of_line}%#{matched_elem[1..-1]}"
37
+ when /#{HAML_SYMBOL_REGEX}/
38
+ "#{start_of_line}#{matched_elem[1..-1].insert(-2, "\\")}"
39
+ when "<"
40
+ "#{start_of_line}%"
41
+ else
42
+ start_of_line
43
+ end
44
+ end
45
+ remove_haml_whitespace(haml: haml)
46
+ end
47
+
48
+ def self_closing_tag_regex
49
+ "<#{SELF_CLOSING_TAGS.join('|<')}\\s"
50
+ end
51
+
52
+ private
53
+
54
+ def adjust_indentation_level(html:, indentation_tracker:)
55
+ case html
56
+ when /#{CLOSING_HTML_REGEX}/
57
+ indentation_tracker.close_html_tag
58
+ when /#{self_closing_tag_regex}/
59
+ indentation_tracker.start_self_closing_tag
60
+ when ">", /#{HAML_SYMBOL_REGEX}/
61
+ indentation_tracker.start_html_tag
62
+ end
63
+ end
64
+
65
+ def remove_html_whitespace(html:)
66
+ html.gsub(/^\s*/, "").delete("\n")
67
+ end
68
+
69
+ def remove_haml_whitespace(haml:)
70
+ haml.lstrip.gsub(/(\n\s*)\n\s*%/, '\1%').gsub(/\n\s*\n/, "\n")
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,74 @@
1
+ require_relative '../../html_to_haml'
2
+ require_relative '../../helpers/haml_whitespace_cleaner'
3
+ require_relative '../../tools/non_html_selector_blocks/indentation_tracker'
4
+ require_relative '../../tools/non_html_selector_blocks/tag_type_matchers'
5
+
6
+ module HtmlToHaml
7
+ module NonHtmlSelectorBlocks
8
+ class BasicConversionUseCase
9
+ include HtmlToHaml::HamlWhitespaceCleaner
10
+ include TagTypeMatchers
11
+
12
+ RUBY_HAML_REGEX = "\n\s*=.*\n"
13
+
14
+ def initialize(special_html)
15
+ @special_html = special_html
16
+ end
17
+
18
+ def convert
19
+ indentation_tracker = IndentationTracker.new(indented: false, adjust_whitespace: false)
20
+ haml = @special_html.gsub(/#{opening_tag_regex}|#{closing_tag_regex}|#{RUBY_HAML_REGEX}|(\n\s*)/) do |tag|
21
+ replace_tag_value(tag: tag, indentation_tracker: indentation_tracker)
22
+ end
23
+ remove_haml_whitespace(haml: haml)
24
+ end
25
+
26
+ private
27
+
28
+ def replace_tag_value(tag:, indentation_tracker:)
29
+ if opening_tag?(tag: tag, in_block: indentation_tracker.indented)
30
+ open_tag(tag: tag, indentation_tracker: indentation_tracker)
31
+ elsif closing_tag?(tag: tag, in_block: indentation_tracker.indented)
32
+ close_tag(indentation_tracker: indentation_tracker)
33
+ elsif use_string_interpolation?(tag: tag, in_block: indentation_tracker.indented)
34
+ string_interpolated_ruby(tag: tag)
35
+ elsif adjust_whitespace?(tag: tag, indentation_tracker: indentation_tracker)
36
+ "#{tag}#{indentation}"
37
+ else
38
+ tag
39
+ end
40
+ end
41
+
42
+ def open_tag(tag:, indentation_tracker:)
43
+ indentation_tracker.indent
44
+ opening_tag(tag: tag)
45
+ end
46
+
47
+ def opening_tag(tag:)
48
+ ":#{tag_type(tag: tag)}\n#{indentation}"
49
+ end
50
+
51
+ def close_tag(indentation_tracker:)
52
+ indentation_tracker.outdent
53
+ "\n"
54
+ end
55
+
56
+ def use_string_interpolation?(tag:, in_block:)
57
+ in_block && tag =~ /#{RUBY_HAML_REGEX}/
58
+ end
59
+
60
+ def string_interpolated_ruby(tag:)
61
+ "\#{#{tag.strip[1..-1].strip}}"
62
+ end
63
+
64
+ def adjust_whitespace?(indentation_tracker:, tag:)
65
+ tag_indented = tag.include?(indentation)
66
+ tag =~ /\n/ && indentation_tracker.adjust_whitespace?(reset_value: !tag_indented)
67
+ end
68
+
69
+ def indentation
70
+ " " * HtmlToHaml::INDENTATION_AMOUNT
71
+ end
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,16 @@
1
+ require_relative 'basic_conversion_use_case'
2
+
3
+ module HtmlToHaml
4
+ module NonHtmlSelectorBlocks
5
+ class ScriptConversionUseCase < BasicConversionUseCase
6
+ HTML_TAG_NAME = "script"
7
+ DEFAULT_TAG_TYPE = "javascript"
8
+
9
+ private
10
+
11
+ def opening_tag?(tag:, in_block:)
12
+ super && tag !~ (/\ssrc=['"]/)
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,10 @@
1
+ require_relative 'basic_conversion_use_case'
2
+
3
+ module HtmlToHaml
4
+ module NonHtmlSelectorBlocks
5
+ class StyleConversionUseCase < BasicConversionUseCase
6
+ HTML_TAG_NAME = "style"
7
+ DEFAULT_TAG_TYPE = "css"
8
+ end
9
+ end
10
+ end
metadata ADDED
@@ -0,0 +1,63 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: html-to-haml
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.5
5
+ platform: ruby
6
+ authors:
7
+ - Natasha Hull-Richter
8
+ autorequire: html_to_haml/converter.rb
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-05-06 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: |-
14
+ This app takes in html and erb code and turns it into haml. It supports script and style tags
15
+ and html comments as well.
16
+ email: nhull-richter@pivotal.io
17
+ executables: []
18
+ extensions: []
19
+ extra_rdoc_files: []
20
+ files:
21
+ - lib/html_to_haml/converter.rb
22
+ - lib/html_to_haml/helpers/haml_whitespace_cleaner.rb
23
+ - lib/html_to_haml/html_to_haml.rb
24
+ - lib/html_to_haml/tools/erb/control_flow_matcher.rb
25
+ - lib/html_to_haml/tools/erb/indentation_tracker.rb
26
+ - lib/html_to_haml/tools/html/attribute_handler.rb
27
+ - lib/html_to_haml/tools/html/indentation_tracker.rb
28
+ - lib/html_to_haml/tools/non_html_selector_blocks/indentation_tracker.rb
29
+ - lib/html_to_haml/tools/non_html_selector_blocks/tag_type_matchers.rb
30
+ - lib/html_to_haml/use_cases/erb/basic_conversion_use_case.rb
31
+ - lib/html_to_haml/use_cases/erb/indentation_conversion_use_case.rb
32
+ - lib/html_to_haml/use_cases/html/attribute_conversion_use_case.rb
33
+ - lib/html_to_haml/use_cases/html/comment_conversion_use_case.rb
34
+ - lib/html_to_haml/use_cases/html/conversion_use_case.rb
35
+ - lib/html_to_haml/use_cases/html/default_conversion_use_case.rb
36
+ - lib/html_to_haml/use_cases/non_html_selector_blocks/basic_conversion_use_case.rb
37
+ - lib/html_to_haml/use_cases/non_html_selector_blocks/script_conversion_use_case.rb
38
+ - lib/html_to_haml/use_cases/non_html_selector_blocks/style_conversion_use_case.rb
39
+ homepage: https://github.com/NatashaHull/html-to-haml.git
40
+ licenses:
41
+ - MIT
42
+ metadata: {}
43
+ post_install_message:
44
+ rdoc_options: []
45
+ require_paths:
46
+ - lib
47
+ required_ruby_version: !ruby/object:Gem::Requirement
48
+ requirements:
49
+ - - ">="
50
+ - !ruby/object:Gem::Version
51
+ version: '2.0'
52
+ required_rubygems_version: !ruby/object:Gem::Requirement
53
+ requirements:
54
+ - - ">="
55
+ - !ruby/object:Gem::Version
56
+ version: '0'
57
+ requirements: []
58
+ rubyforge_project:
59
+ rubygems_version: 2.5.1
60
+ signing_key:
61
+ specification_version: 4
62
+ summary: A program that turns html.erb code into haml code.
63
+ test_files: []