html2haml-2.3.0/0000755000004100000410000000000014327674307013451 5ustar www-datawww-datahtml2haml-2.3.0/test/0000755000004100000410000000000014327674307014430 5ustar www-datawww-datahtml2haml-2.3.0/test/erb_test.rb0000644000004100000410000002426714327674307016577 0ustar www-datawww-datarequire 'test_helper' class ErbTest < MiniTest::Unit::TestCase def test_erb assert_equal '- foo = bar', render_erb('<% foo = bar %>') assert_equal '- foo = bar', render_erb('<% foo = bar -%>') assert_equal '= h @item.title', render_erb('<%=h @item.title %>') assert_equal '= h @item.title', render_erb('<%=h @item.title -%>') end def test_inline_erb assert_equal("%p= foo", render_erb("

<%= foo %>

")) assert_equal(<<%= foo %>

HTML end def test_non_inline_erb assert_equal(< <%= foo %>

HTML assert_equal(< <%= foo %>

HTML end def test_erb_in_cdata assert_equal(< baz]]> HTML end def test_erb_in_script assert_equal(< function foo() { return <%= foo.to_json %>; } HTML end def test_erb_in_style assert_equal(< foo { bar: <%= "baz" %>; } HTML end def test_erb_in_line assert_equal 'foo bar #{baz}', render_erb('foo bar <%= baz %>') assert_equal 'foo bar #{baz}! Bang.', render_erb('foo bar <%= baz %>! Bang.') end def test_erb_multi_in_line assert_equal('foo bar #{baz}! Bang #{bop}.', render_erb('foo bar <%= baz %>! Bang <%= bop %>.')) assert_equal('foo bar #{baz}#{bop}!', render_erb('foo bar <%= baz %><%= bop %>!')) end def test_erb_with_html_special_chars assert_equal '= 3 < 5 ? "OK" : "Your computer is b0rken"', render_erb('<%= 3 < 5 ? "OK" : "Your computer is b0rken" %>') end def test_erb_in_class_attribute assert_equal "%div{:class => dyna_class} I have a dynamic attribute", render_erb('
I have a dynamic attribute
') end def test_erb_in_id_attribute assert_equal "%div{:id => dyna_id} I have a dynamic attribute", render_erb('
I have a dynamic attribute
') end def test_erb_in_attribute_results_in_string_interpolation assert_equal('%div{:id => "item_#{i}"} Ruby string interpolation FTW', render_erb('
Ruby string interpolation FTW
')) end def test_erb_in_attribute_with_trailing_content assert_equal('%div{:class => "#{12}!"} Bang!', render_erb('
Bang!
')) end def test_erb_in_html_escaped_attribute assert_equal '%div{:class => "foo"} Bang!', render_erb('
">Bang!
') end def test_erb_in_html_escaped_attribute_with_symbol assert_equal '%div{:class => :foo} Bang!', render_erb('
Bang!
') end def test_empty_erb_in_attribute assert_equal '%div{:class => ""}', render_erb('
') end def test_erb_in_attribute_to_multiple_interpolations assert_equal('%div{:class => "#{12} + #{13}"} Math is super', render_erb('
Math is super
')) end def test_whitespace_eating_erb_tags assert_equal '- form_for', render_erb('<%- form_for -%>') end def test_interpolation_in_erb assert_equal('= "Foo #{bar} baz"', render_erb('<%= "Foo #{bar} baz" %>')) end def test_interpolation_in_erb_attrs assert_equal('%p{:foo => "#{bar} baz"}', render_erb('

">

')) end def test_multiline_erb_silent_script assert_equal(< <% foo bar baz %>

foo

ERB end def test_multiline_erb_loud_script assert_equal(< <%= foo + bar.baz.bang + baz %>

foo

ERB end def test_weirdly_indented_multiline_erb_loud_script assert_equal(< <%= foo + bar.baz.bang + baz %>

foo

ERB end def test_two_multiline_erb_loud_scripts assert_equal(< <%= foo + bar.baz.bang + baz %> <%= foo.bar do bang end %>

foo

ERB end def test_multiline_then_single_line_erb_loud_scripts assert_equal(< <%= foo + bar.baz.bang + baz %> <%= foo.bar %>

foo

ERB end def test_multiline_erb_but_really_single_line assert_equal(< <%= foo %>

foo

ERB end ### Block Parsing def test_block_parsing assert_equal(<

bar

<% end %> ERB end def test_block_parsing_with_args assert_equal(<

bar

<% end %> ERB end def test_block_parsing_with_equals assert_equal(<

bar

<% end %> ERB end def test_block_parsing_with_modified_end assert_equal(< blah <% end.bip %> ERB end def test_block_parsing_with_modified_end_with_block assert_equal(< blah <% end.bip do %> brang <% end %> ERB end def test_multiline_block_opener assert_equal(< foo <% end %> ERB end def test_if_elsif_else_parsing assert_equal(<

bar

<% elsif bar.foo("zip") %>
baz
<% else %> bibble <% end %> ERB end def test_case_when_parsing assert_equal(< <% when "bip" %>

bip

<% when "bop" %>

BOP

<% when bizzle.bang.boop.blip %> BIZZLE BANG BOOP BLIP <% end %> ERB assert_equal(<

bip

<% when "bop" %>

BOP

<% when bizzle.bang.boop.blip %> BIZZLE BANG BOOP BLIP <% end %> ERB end def test_begin_rescue_ensure assert_equal(< e %p b - ensure %p c HAML <% begin %>

a

<% rescue FooException => e %>

b

<% ensure %>

c

<% end %> ERB end # Regression def test_tag_inside_block assert_equal(< <% foo.each do %> <% end %> ERB end def test_silent_inside_block_inside_tag assert_equal(< <% foo.each do %> <% haml_puts "foo" %> <% end %> ERB end def test_commented_erb_should_not_cause_indentation assert_equal(< html2haml and multiline titles <%=# stylesheet_link_tag :first %> <%#= stylesheet_link_tag :second %> <%# stylesheet_link_tag :third %> <%= stylesheet_link_tag 'another file' %> ERB end def test_can_parse_ruby_19_hashes_as_arguments erb = "<%= foobar 'foo', {bar: 'baz'} %>" begin Html2haml::HTML::ERB.new(erb) rescue flunk "should not raise an error" end end def test_should_wrap_in_silent assert_equal(< some_variable_or_function \n HTML <% some_variable_or_function %> ERB end #comment content is removed by erubis def test_should_wrap_process_comments_as_empty_lines assert_equal(<\n HTML <%# some_variable_or_function %> ERB end def test_conditional_structure_in_argument assert_equal(< "\#{"active" if condition}"} HAML "> HTML end def test_method_call_without_brackets_in_argument assert_equal(< "\#{call_me maybe}"} HAML HTML end def test_multiline_erb_comment assert_equal(<

hi

ERB end ## # <%== %> is supposed to be equal to <%= raw %> def test_erb_with_double_equals assert_equal(< ERB end #https://github.com/haml/html2haml/issues/43 def test_escaped_ruby_call_when_preceded_by_text assert_equal(< <%= submit_tag "cdcd" %> <% end %> ERB end end html2haml-2.3.0/test/jruby/0000755000004100000410000000000014327674307015563 5ustar www-datawww-datahtml2haml-2.3.0/test/jruby/erb_test.rb0000644000004100000410000000070714327674307017723 0ustar www-datawww-data#reopen classes that need to be modified for JRuby specific behavior class ErbTest def test_two_multiline_erb_loud_scripts assert_equal(< <%= foo + bar.baz.bang + baz %> <%= foo.bar do bang end %>

foo

ERB end end html2haml-2.3.0/test/jruby/html2haml_test.rb0000644000004100000410000000472614327674307021050 0ustar www-datawww-dataclass Html2HamlTest def test_doctype empty_body = "\n%html\n %head\n %body" assert_equal '!!!' + empty_body, render("") assert_equal '!!! 1.1' + empty_body, render('') assert_equal '!!! Strict' + empty_body, render('') assert_equal '!!! Frameset' + empty_body, render('') assert_equal '!!! Mobile 1.2' + empty_body, render('') assert_equal '!!! Basic 1.1' + empty_body, render('') assert_equal '!!!' + empty_body, render('') assert_equal '!!! Strict' + empty_body, render('') assert_equal '!!! Frameset' + empty_body, render('') assert_equal '!!!' + empty_body, render('') end def test_xhtml_strict_doctype assert_equal(< HTML end def test_html_document_without_doctype assert_equal(< Hello

Hello

HTML end def test_should_have_attributes_without_values assert_equal('%input{:disabled => ""}/', render('')) end def test_style_to_css_filter_with_following_content assert_equal(< Hello HTML end end html2haml-2.3.0/test/html2haml_test.rb0000644000004100000410000002257414327674307017716 0ustar www-datawww-data# encoding: UTF-8 require 'test_helper' class Html2HamlTest < MiniTest::Unit::TestCase def test_empty_render_should_remain_empty assert_equal '', render('') end def test_doctype assert_equal '!!!', render("") assert_equal '!!! 1.1', render('') assert_equal '!!! Strict', render('') assert_equal '!!! Frameset', render('') assert_equal '!!! Mobile 1.2', render('') assert_equal '!!! Basic 1.1', render('') assert_equal '!!!', render('') assert_equal '!!! Strict', render('') assert_equal '!!! Frameset', render('') assert_equal '!!!', render('') end def test_id_and_class_should_be_removed_from_hash assert_equal '%span#foo.bar', render(' ') end def test_no_tag_name_for_div_if_class_or_id_is_present assert_equal '#foo', render('
') assert_equal '.foo', render('
') end def test_multiple_class_names assert_equal '.foo.bar.baz', render('
') end def test_should_have_pretty_attributes assert_equal('%input{:name => "login", :type => "text"}/', render('')) assert_equal('%meta{:content => "text/html", "http-equiv" => "Content-Type"}/', render('')) end def test_should_have_html_style_attributes assert_equal('%input(name="login" type="text")/', render('', :html_style_attributes => true)) assert_equal('%meta(content="text/html" http-equiv="Content-Type")/', render('', :html_style_attributes => true)) end def test_should_have_ruby_19_hash_style_attributes assert_equal('%input{name: "login", type: "text"}/', render('', :ruby19_style_attributes => true)) assert_equal('%meta{content: "text/html", "http-equiv" => "Content-Type"}/', render('', :ruby19_style_attributes => true)) end def test_should_have_attributes_without_values assert_equal('%input{:disabled => "disabled"}/', render('')) end def test_class_with_dot_and_hash assert_equal('%div{:class => "foo.bar"}', render("
")) assert_equal('%div{:class => "foo#bar"}', render("
")) assert_equal('.foo.bar{:class => "foo#bar foo.bar"}', render("
")) end def test_id_with_dot_and_hash assert_equal('%div{:id => "foo.bar"}', render("
")) assert_equal('%div{:id => "foo#bar"}', render("
")) end def test_interpolation assert_equal('Foo \#{bar} baz', render('Foo #{bar} baz')) end def test_interpolation_in_attrs assert_equal('%p{:foo => "\#{bar} baz"}', render('

')) end def test_cdata assert_equal(<
flop
HAML

flop
]]>

HTML end def test_self_closing_tag assert_equal("%img/", render("")) end def test_inline_text assert_equal("%p foo", render("

foo

")) end def test_inline_comment assert_equal("/ foo", render("")) assert_equal(<

bar

HTML end def test_non_inline_comment assert_equal(< HTML end def test_non_inline_text assert_equal(< foo

HTML assert_equal(< foo

HTML assert_equal(<foo

HTML end def test_script_tag assert_equal(< function foo() { return "12" & "13"; } HTML end def test_script_tag_with_html_escaped_javascript assert_equal(< function foo() { return "12" & "13"; } HTML end def test_script_tag_with_cdata assert_equal(< HTML end def test_pre assert_equal(<foo bar baz HTML end def test_pre_code assert_equal(<foo bar baz HTML end def test_code_without_pre assert_equal(<foo bar baz HTML end def test_conditional_comment assert_equal(< bar baz HTML end def test_style_to_css_filter assert_equal(< foo { bar: baz; } HTML end def test_style_to_css_filter_with_following_content assert_equal(< Hello HTML end def test_style_to_css_filter_with_no_content assert_equal(< HTML assert_equal(< HTML end def test_filter_with_inconsistent_indentation assert_equal(< foo { badly: indented; } HTML end def test_inline_conditional_comment assert_equal(< bar baz HTML end def test_minus_in_tag assert_equal("%p - foo bar -", render("

- foo bar -

")) end def test_equals_in_tag assert_equal("%p = foo bar =", render("

= foo bar =

")) end def test_hash_in_tag assert_equal("%p # foo bar #", render("

# foo bar #

")) end def test_comma_post_tag assert_equal(< Foo , %span bar Foo %span> bar , %span baz HAML
Foo, bar Foobar, baz
HTML end def test_comma_post_tag_with_text_before assert_equal(< Batch Foo, Bar HTML end def test_haml_tags_should_be_on_new_line_after_tag_with_blank_content xml = " \n102" haml = "%weight\n%pages 102" assert_equal haml, render(xml) end # Encodings def test_encoding_error render("foo\nbar\nb\xFEaz".force_encoding("utf-8")) assert(false, "Expected exception") rescue Haml::Error => e assert_equal(3, e.line) assert_match(/Invalid UTF-8 character/, e.message) end def test_ascii_incompatible_encoding_error template = "foo\nbar\nb_z".encode("utf-16le") template[9] = "\xFE".force_encoding("utf-16le") render(template) assert(false, "Expected exception") rescue Haml::Error => e assert_equal(3, e.line) assert_match(/Invalid UTF-16LE character/, e.message) end # Regression Tests def test_xhtml_strict_doctype assert_equal('!!! Strict', render(< HTML end def test_html_document_without_doctype assert_equal(< "text/html; charset=UTF-8", "http-equiv" => "Content-Type"}/ %title Hello %body %p Hello HAML Hello

Hello

HTML end end html2haml-2.3.0/test/test_helper.rb0000644000004100000410000000063114327674307017273 0ustar www-datawww-datarequire "rubygems" if ENV["COVERAGE"] require "simplecov" SimpleCov.start end require "bundler/setup" require "minitest/autorun" require "html2haml" require 'html2haml/html' require 'html2haml/html/erb' class MiniTest::Unit::TestCase protected def render(text, options = {}) Html2haml::HTML.new(text, options).render.rstrip end def render_erb(text) render(text, :erb => true) end end html2haml-2.3.0/README.md0000644000004100000410000000716214327674307014736 0ustar www-datawww-data# Html2haml [![Build Status](https://github.com/haml/html2haml/workflows/test/badge.svg)](https://github.com/haml/html2haml/actions) [![Code Climate](https://codeclimate.com/github/haml/html2haml.svg)](https://codeclimate.com/github/haml/html2haml) [![Gem Version](https://badge.fury.io/rb/html2haml.svg)](https://rubygems.org/gems/html2haml) Html2haml, not surprisingly, converts HTML to Haml. It works on HTML with embedded ERB tags as well as plain old HTML. ## Installation Add this line to your application's Gemfile: gem 'html2haml' And then execute: $ bundle Or install it yourself as: $ gem install html2haml ## Usage ### To convert a project from .erb to .haml If your system has `sed` and `xargs` available and none of your .erb file names have whitespace in them, you can convert all your templates like so: find . -name \*.erb -print | sed 'p;s/.erb$/.haml/' | xargs -n2 html2haml If some of your file names have whitespace or you need finer-grained control over the process, you can convert your files using `gsed` or multi-line script techniques discussed [here](http://stackoverflow.com/questions/17576814/). ### Documentation #### About version 2.0 Html2haml 2.0 differs from 1.x primarily in that it uses Nokgiri as its HTML parser rather than Hpricot. At the current time however, there are some problems running Html2haml 2.0 on JRuby due to differences in the way the Java version of Nokogiri parses HTML. If you are using JRuby you may wish to run HTML2Haml on MRI or use a 1.x version until these problems have been resolved. #### Options Here are the options currently available to Html2haml: See `html2haml --help`: Usage: html2haml [options] [INPUT] [OUTPUT] Description: Transforms an HTML file into corresponding Haml code. Options: -e, --erb Parse ERB tags. --no-erb Don't parse ERB tags. --html-attributes Use HTML style attributes instead of Ruby hash style. --ruby19-attributes Use Ruby 1.9-style attributes when possible. -E ex[:in] Specify the default external and internal character encodings. -s, --stdin Read input from standard input instead of an input file --trace Show a full traceback on error --unix-newlines Use Unix-style newlines in written files. -?, -h, --help Show this message -v, --version Print version ## License Copyright (c) 2006-2017 Hampton Catlin, Natalie Weizenbaum and Norman Clarke Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. html2haml-2.3.0/bin/0000755000004100000410000000000014327674307014221 5ustar www-datawww-datahtml2haml-2.3.0/bin/html2haml0000755000004100000410000000023414327674307016036 0ustar www-datawww-data#!/usr/bin/env ruby require File.dirname(__FILE__) + '/../lib/html2haml' require 'html2haml/exec' opts = Html2haml::Exec::HTML2Haml.new(ARGV) opts.parse! html2haml-2.3.0/.gitignore0000644000004100000410000000011714327674307015440 0ustar www-datawww-data/.yardoc /coverage /doc /pkg *.rbc .rbenv-version Gemfile.lock .rvmrc .rbx tmp html2haml-2.3.0/Rakefile0000644000004100000410000000076514327674307015126 0ustar www-datawww-datarequire "bundler/gem_tasks" require "rake/clean" require "rake/testtask" task :default => :test CLEAN.replace %w(pkg doc coverage .yardoc) Rake::TestTask.new do |t| t.libs << 'lib' << 'test' if RUBY_PLATFORM == 'java' t.test_files = FileList["test/**/*_test.rb"] else t.test_files = FileList["test/**/*_test.rb"].exclude(/jruby/) end t.verbose = true end task :set_coverage_env do ENV["COVERAGE"] = "true" end desc "Run Simplecov" task :coverage => [:set_coverage_env, :test] html2haml-2.3.0/lib/0000755000004100000410000000000014327674307014217 5ustar www-datawww-datahtml2haml-2.3.0/lib/html2haml/0000755000004100000410000000000014327674307016107 5ustar www-datawww-datahtml2haml-2.3.0/lib/html2haml/exec.rb0000644000004100000410000002006714327674307017365 0ustar www-datawww-datarequire 'optparse' require 'fileutils' require 'rbconfig' module Html2haml # This module handles the Html2haml executable. module Exec # An abstract class that encapsulates the executable code for the Html2haml executable. # It's split into a base class and a subclass for historic reasons: this previously # was used by all the executables in the Haml project, before Html2haml was moved # into its own gem. class Generic # @param args [Array] The command-line arguments def initialize(args) @args = args @options = {:for_engine => {}} end # Parses the command-line arguments and runs the executable. # Calls `Kernel#exit` at the end, so it never returns. # # @see #parse def parse! begin parse rescue Exception => e raise e if @options[:trace] || e.is_a?(SystemExit) $stderr.print "#{e.class}: " unless e.class == RuntimeError $stderr.puts "#{e.message}" $stderr.puts " Use --trace for backtrace." exit 1 end exit 0 end # Parses the command-line arguments and runs the executable. # This does not handle exceptions or exit the program. # # @see #parse! def parse @opts = OptionParser.new(&method(:set_opts)) @opts.parse!(@args) process_result @options end # @return [String] A description of the executable def to_s @opts.to_s end protected # Finds the line of the source template # on which an exception was raised. # # @param exception [Exception] The exception # @return [String] The line number def get_line(exception) # SyntaxErrors have weird line reporting # when there's trailing whitespace, # which there is for Haml documents. return (exception.message.scan(/:(\d+)/).first || ["??"]).first if exception.is_a?(::SyntaxError) (exception.backtrace[0].scan(/:(\d+)/).first || ["??"]).first end # Tells optparse how to parse the arguments # available for all executables. # # This is meant to be overridden by subclasses # so they can add their own options. # # @param opts [OptionParser] def set_opts(opts) opts.on('-s', '--stdin', :NONE, 'Read input from standard input instead of an input file') do @options[:input] = $stdin end opts.on('--trace', :NONE, 'Show a full traceback on error') do @options[:trace] = true end opts.on('--unix-newlines', 'Use Unix-style newlines in written files.') do # Note that this is the preferred way to check for Windows, since # JRuby and Rubinius also run there. if RbConfig::CONFIG['host_os'] =~ /mswin|windows|mingw/i @options[:unix_newlines] = true end end opts.on_tail("-?", "-h", "--help", "Show this message") do puts opts exit end opts.on_tail("-v", "--version", "Print version") do puts("html2haml #{::Html2haml::VERSION}") exit end end # Processes the options set by the command-line arguments. # In particular, sets `@options[:input]` and `@options[:output]` # to appropriate IO streams. # # This is meant to be overridden by subclasses # so they can run their respective programs. def process_result input, output = @options[:input], @options[:output] args = @args.dup input ||= begin filename = args.shift @options[:filename] = filename open_file(filename) || $stdin end output ||= open_file(args.shift, 'w') || $stdout @options[:input], @options[:output] = input, output end COLORS = { :red => 31, :green => 32, :yellow => 33 } # Prints a status message about performing the given action, # colored using the given color (via terminal escapes) if possible. # # @param name [#to_s] A short name for the action being performed. # Shouldn't be longer than 11 characters. # @param color [Symbol] The name of the color to use for this action. # Can be `:red`, `:green`, or `:yellow`. def puts_action(name, color, arg) return if @options[:for_engine][:quiet] printf color(color, "%11s %s\n"), name, arg end # Same as `Kernel.puts`, but doesn't print anything if the `--quiet` option is set. # # @param args [Array] Passed on to `Kernel.puts` def puts(*args) return if @options[:for_engine][:quiet] Kernel.puts(*args) end # Wraps the given string in terminal escapes # causing it to have the given color. # If terminal esapes aren't supported on this platform, # just returns the string instead. # # @param color [Symbol] The name of the color to use. # Can be `:red`, `:green`, or `:yellow`. # @param str [String] The string to wrap in the given color. # @return [String] The wrapped string. def color(color, str) raise "[BUG] Unrecognized color #{color}" unless COLORS[color] # Almost any real Unix terminal will support color, # so we just filter for Windows terms (which don't set TERM) # and not-real terminals, which aren't ttys. return str if ENV["TERM"].nil? || ENV["TERM"].empty? || !STDOUT.tty? return "\e[#{COLORS[color]}m#{str}\e[0m" end private def open_file(filename, flag = 'r') return if filename.nil? flag = 'wb' if @options[:unix_newlines] && flag == 'w' File.open(filename, flag) end def handle_load_error(err) dep = err.message[/^no such file to load -- (.*)/, 1] raise err if @options[:trace] || dep.nil? || dep.empty? $stderr.puts <] The command-line arguments def initialize(args) super @module_opts = {} end # Tells optparse how to parse the arguments. # # @param opts [OptionParser] def set_opts(opts) opts.banner = < e raise "#{e.is_a?(::Haml::SyntaxError) ? "Syntax error" : "Error"} on line " + "#{get_line e}: #{e.message}" rescue LoadError => err handle_load_error(err) end end end end html2haml-2.3.0/lib/html2haml/html/0000755000004100000410000000000014327674307017053 5ustar www-datawww-datahtml2haml-2.3.0/lib/html2haml/html/erb.rb0000644000004100000410000001315114327674307020151 0ustar www-datawww-datarequire 'cgi' require 'erubis' require 'ruby_parser' module Html2haml class HTML # A class for converting ERB code into a format that's easier # for the {Html2haml::HTML} Nokogiri-based parser to understand. # # Uses [Erubis](http://www.kuwata-lab.com/erubis)'s extensible parsing powers # to parse the ERB in a reliable way, # and [ruby_parser](http://parsetree.rubyforge.org/)'s Ruby knowledge # to figure out whether a given chunk of Ruby code starts a block or not. # # The ERB tags are converted to HTML tags in the following way. # `<% ... %>` is converted into ` ... `. # `<%= ... %>` is converted into ` ... `. # `<%== ... %>` is converted into ` ... `. # Finally, if either of these opens a Ruby block, # ` ... ` will wrap the entire contents of the block - # that is, everything that should be indented beneath the previous silent or loud tag. class ERB < Erubis::Basic::Engine # Compiles an ERB template into a HTML document containing `haml_*` tags. # # @param template [String] The ERB template # @return [String] The output document # @see Html2haml::HTML::ERB def self.compile(template) new(template).src end # The ERB-to-Hamlized-HTML conversion has no preamble. def add_preamble(src); end # The ERB-to-Hamlized-HTML conversion has no postamble. def add_postamble(src); end # Concatenates the text onto the source buffer. # # @param src [String] The source buffer # @param text [String] The raw text to add to the buffer def add_text(src, text) src << text end # Concatenates a silent Ruby statement onto the source buffer. # This uses the `` tag, # and may close and/or open a Ruby block with the `` tag. # # In particular, a block is closed if this statement is some form of `end`, # opened if it's a block opener like `do`, `if`, or `begin`, # and both closed and opened if it's a mid-block keyword # like `else` or `when`. # # @param src [String] The source buffer # @param code [String] The Ruby statement to add to the buffer def add_stmt(src, code) src << '' if block_closer?(code) || mid_block?(code) src << '' << h(code) << '' unless code.strip == "end" src << '' if block_opener?(code) || mid_block?(code) end # Concatenates a Ruby expression that's printed to the document # onto the source buffer. # This uses the `` tag, # and may open a Ruby block with the `` tag. # An expression never closes a block. # # @param src [String] The source buffer # @param code [String] The Ruby expression to add to the buffer def add_expr_literal(src, code) src << '' << h(code) << '' src << '' if block_opener?(code) end def add_expr_escaped(src, code) src << "" << h(code) << "" end # `html2haml` doesn't support debugging expressions. def add_expr_debug(src, code) raise Haml::Error.new("html2haml doesn't support debugging expressions.") end private # HTML-escaped some text (in practice, always Ruby code). # A utility method. # # @param text [String] The text to escape # @return [String] The escaped text def h(text) CGI.escapeHTML(text) end # Returns whether the code is valid Ruby code on its own. # # @param code [String] Ruby code to check # @return [Boolean] def valid_ruby?(code) RubyParser.for_current_ruby.parse(code) rescue Racc::ParseError, RubyParser::SyntaxError false end # Returns whether the code has any content # This is used to test whether lines have been removed by erubis, such as comments # # @param code [String] Ruby code to check # @return [Boolean] def has_code?(code) return false if code == "\n" return false if valid_ruby?(code) == nil true end # Checks if a string of Ruby code opens a block. # This could either be something like `foo do |a|` # or a keyword that requires a matching `end` # like `if`, `begin`, or `case`. # # @param code [String] Ruby code to check # @return [Boolean] def block_opener?(code) return unless has_code?(code) valid_ruby?(code + "\nend") || valid_ruby?(code + "\nwhen foo\nend") end # Checks if a string of Ruby code closes a block. # This is always `end` followed optionally by some method calls. # # @param code [String] Ruby code to check # @return [Boolean] def block_closer?(code) return unless has_code?(code) valid_ruby?("begin\n" + code) end # Checks if a string of Ruby code comes in the middle of a block. # This could be a keyword like `else`, `rescue`, or `when`, # or even `end` with a method call that takes a block. # # @param code [String] Ruby code to check # @return [Boolean] def mid_block?(code) return unless has_code?(code) return if valid_ruby?(code) valid_ruby?("if foo\n#{code}\nend") || # else, elsif valid_ruby?("begin\n#{code}\nend") || # rescue, ensure valid_ruby?("case foo\n#{code}\nend") # when end end end end html2haml-2.3.0/lib/html2haml/version.rb0000644000004100000410000000005114327674307020115 0ustar www-datawww-datamodule Html2haml VERSION = "2.3.0" end html2haml-2.3.0/lib/html2haml/html.rb0000644000004100000410000004176314327674307017413 0ustar www-datawww-datarequire 'cgi' require 'nokogiri' require 'html2haml/html/erb' # Haml monkeypatches various Nokogiri classes # to add methods for conversion to Haml. # @private module Nokogiri module XML # @see Nokogiri class Node # Whether this node has already been converted to Haml. # Only used for text nodes and elements. # # @return [Boolean] attr_accessor :converted_to_haml # Returns the Haml representation of the given node. # # @param tabs [Fixnum] The indentation level of the resulting Haml. # @option options (see Html2haml::HTML#initialize) def to_haml(tabs, options) return "" if converted_to_haml || to_s.strip.empty? text = uninterp(self.to_s) #ending in a newline stops the inline nodes if text.end_with?("\n") parse_text_with_interpolation(text, tabs) else text << process_inline_nodes(next_sibling) parse_text_with_interpolation(text, tabs) end end private def erb_to_interpolation(text, options) return text unless options[:erb] text = CGI.escapeHTML(uninterp(text)) %w[ ].each {|str| text.gsub!(CGI.escapeHTML(str), str)} ::Nokogiri::XML.fragment(text).children.inject("") do |str, elem| if elem.is_a?(::Nokogiri::XML::Text) str + CGI.unescapeHTML(elem.to_s) else # element str + '#{' + CGI.unescapeHTML(elem.inner_text.strip) + '}' end end end def tabulate(tabs) ' ' * tabs end def uninterp(text) text.gsub('#{', '\#{') #' end def attr_hash Hash[attributes.map {|k, v| [k.to_s, v.to_s]}] end def parse_text(text, tabs) parse_text_with_interpolation(uninterp(text), tabs) end def parse_text_with_interpolation(text, tabs) text.strip! return "" if text.empty? text.split("\n").map do |line| line.strip! "#{tabulate(tabs)}#{'\\' if Haml::Parser::SPECIAL_CHARACTERS.include?(line[0])}#{line}\n" end.join end def process_inline_nodes(node) text = "" while node.is_a?(::Nokogiri::XML::Element) && node.name == "haml_loud" node.converted_to_haml = true text << '#{' << CGI.unescapeHTML(node.inner_text).gsub(/\n\s*/, ' ').strip << '}' if node.next_sibling.is_a?(::Nokogiri::XML::Text) node = node.next_sibling text << uninterp(node.to_s) node.converted_to_haml = true end node = node.next_sibling end text end end end end # @private HAML_TAGS = %w[haml_block haml_loud haml_silent] # # HAML_TAGS.each do |t| # Nokogiri::XML::ElementContent[t] = {} # Nokogiri::XML::ElementContent.keys.each do |key| # Nokogiri::XML::ElementContent[t][key.hash] = true # end # end # # Nokogiri::XML::ElementContent.keys.each do |k| # HAML_TAGS.each do |el| # val = Nokogiri::XML::ElementContent[k] # val[el.hash] = true if val.is_a?(Hash) # end # end module Html2haml # Converts HTML documents into Haml templates. # Depends on [Nokogiri](http://nokogiri.org/) for HTML parsing. # If ERB conversion is being used, also depends on # [Erubis](http://www.kuwata-lab.com/erubis) to parse the ERB # and [ruby_parser](http://parsetree.rubyforge.org/) to parse the Ruby code. # # Example usage: # # HTML.new("Blat").render # #=> "%a{:href => 'http://google.com'} Blat" class HTML # @param template [String, Nokogiri::Node] The HTML template to convert # @option options :erb [Boolean] (false) Whether or not to parse # ERB's `<%= %>` and `<% %>` into Haml's `=` and `-` # @option options :xhtml [Boolean] (false) Whether or not to parse # the HTML strictly as XHTML def initialize(template, options = {}) @options = options if template.is_a? Nokogiri::XML::Node @template = template else if template.is_a? IO template = template.read end template = Haml::Util.check_encoding(template) {|msg, line| raise Haml::Error.new(msg, line)} if @options[:erb] require 'html2haml/html/erb' template = ERB.compile(template) end @template = detect_proper_parser(template) end end def detect_proper_parser(template) if template =~ /^\s*\n/, "") end end # @see Nokogiri # @private class ::Nokogiri::XML::DTD # @see Html2haml::HTML::Node#to_haml def to_haml(tabs, options) attrs = external_id.nil? ? ["", "", ""] : external_id.scan(/DTD\s+([^\s]+)\s*([^\s]*)\s*([^\s]*)\s*\/\//)[0] raise Haml::SyntaxError.new("Invalid doctype") if attrs == nil type, version, strictness = attrs.map { |a| a.downcase } if type == "html" version = "" strictness = "strict" if strictness == "" end if version == "1.0" || version.empty? version = nil end if strictness == 'transitional' || strictness.empty? strictness = nil end version = " #{version.capitalize}" if version strictness = " #{strictness.capitalize}" if strictness "#{tabulate(tabs)}!!!#{version}#{strictness}\n" end end # @see Nokogiri # @private class ::Nokogiri::XML::Comment # @see Html2haml::HTML::Node#to_haml def to_haml(tabs, options) content = self.content if content =~ /\A(\[[^\]]+\])>(.*) 1 # Multiline script block # Normalize the indentation so that the last line is the base indent_str = lines.last[/^[ \t]*/] indent_re = /^[ \t]{0,#{indent_str.count(" ") + 8 * indent_str.count("\t")}}/ lines.map! {|s| s.gsub!(indent_re, '')} # Add an extra " " to make it indented relative to "= " lines[1..-1].each {|s| s.gsub!(/^/, " ")} # Add | at the end, properly aligned length = lines.map {|s| s.size}.max + 1 lines.map! {|s| "%#{-length}s|" % s} if next_sibling && next_sibling.is_a?(Nokogiri::XML::Element) && next_sibling.name == "haml_loud" && next_sibling.inner_text.split("\n").reject {|s| s.strip.empty?}.size > 1 lines << "-#" end end return lines.map {|s| output + s + "\n"}.join when "haml_silent" return CGI.unescapeHTML(inner_text).split("\n").map do |line| next "" if line.strip.empty? "#{output}- #{line.strip}\n" end.join when "haml_block" return render_children("", tabs, options) end end if self.next && self.next.text? && self.next.content =~ /\A[^\s]/ if self.previous.nil? || self.previous.text? && (self.previous.content =~ /[^\s]\Z/ || self.previous.content =~ /\A\s*\Z/ && self.previous.previous.nil?) nuke_outer_whitespace = true else output << "= succeed #{self.next.content.slice!(/\A[^\s]+/).dump} do\n" tabs += 1 output << tabulate(tabs) #empty the text node since it was inserted into the block self.next.content = "" end end output << "%#{name}" unless name.to_s == 'div' && (static_id?(options) || static_classname?(options) && attr_hash['class'].to_s.split(' ').any?(&method(:haml_css_attr?))) if attr_hash if static_id?(options) output << "##{attr_hash['id'].to_s}" remove_attribute('id') end if static_classname?(options) leftover = attr_hash['class'].to_s.split(' ').reject do |c| next unless haml_css_attr?(c) output << ".#{c}" end remove_attribute('class') set_attribute('class', leftover.join(' ')) unless leftover.empty? end output << haml_attributes(options) if attr_hash.length > 0 end output << ">" if nuke_outer_whitespace output << "/" if to_xhtml.end_with?("/>") if children && children.size == 1 child = children.first if child.is_a?(::Nokogiri::XML::Text) if !child.to_s.include?("\n") text = child.to_haml(tabs + 1, options) return output + " " + text.lstrip.gsub(/^\\/, '') unless text.chomp.include?("\n") || text.empty? return output + "\n" + text elsif ["pre", "textarea"].include?(name) || (name == "code" && parent.is_a?(::Nokogiri::XML::Element) && parent.name == "pre") return output + "\n#{tabulate(tabs + 1)}:preserve\n" + inner_text.gsub(/^/, tabulate(tabs + 2)) end elsif child.is_a?(::Nokogiri::XML::Element) && child.name == "haml_loud" return output + child.to_haml(tabs + 1, options).lstrip end end render_children(output + "\n", tabs, options) end private def render_children(so_far, tabs, options) (self.children || []).inject(so_far) do |output, child| output + child.to_haml(tabs + 1, options) end end def dynamic_attributes #reject any attrs without @dynamic_attributes = attr_hash.select {|name, value| value =~ %r{ #{value}" end if options[:ruby19_style_attributes] return "#{name}: #{value}" end ":#{name} => #{value}" end end end end html2haml-2.3.0/lib/html2haml.rb0000644000004100000410000000032114327674307016430 0ustar www-datawww-datarequire "rubygems" gem "haml", ">= 3.2" require File.expand_path("../html2haml/version", __FILE__) require "haml/util" require "haml/parser" require "haml/error" require "html2haml/html" module Html2haml end html2haml-2.3.0/.yardopts0000644000004100000410000000002214327674307015311 0ustar www-datawww-data--markup markdown html2haml-2.3.0/Gemfile0000644000004100000410000000050314327674307014742 0ustar www-datawww-datasource 'https://rubygems.org' gemspec gem 'nokogiri', RUBY_VERSION < '2.1' ? '~> 1.6.0' : '>= 1.7' if RUBY_VERSION < '2.1' gem 'ruby_parser', '< 3.14' elsif RUBY_VERSION < '2.3' gem 'ruby_parser', '< 3.18' else gem 'ruby_parser', '>= 3.18' end gem 'sexp_processor', RUBY_VERSION < '2.1' ? '< 4.14.0' : '> 4.14.0' html2haml-2.3.0/.github/0000755000004100000410000000000014327674307015011 5ustar www-datawww-datahtml2haml-2.3.0/.github/workflows/0000755000004100000410000000000014327674307017046 5ustar www-datawww-datahtml2haml-2.3.0/.github/workflows/main.yml0000644000004100000410000000142114327674307020513 0ustar www-datawww-dataname: test on: [push, pull_request] jobs: tests: runs-on: ubuntu-18.04 strategy: fail-fast: false matrix: ruby-version: - '1.9' - '2.0' - '2.1' - '2.2' - '2.3' - '2.4' - '2.5' - '2.6' - '2.7' - '3.0' - '3.1' - ruby-head - jruby steps: - uses: actions/checkout@v3 - uses: ruby/setup-ruby@v1 with: ruby-version: ${{ matrix.ruby-version }} bundler-cache: true continue-on-error: ${{ matrix.ruby-version == 'ruby-head' }} - run: | bundle exec rake continue-on-error: ${{ (matrix.ruby-version == 'ruby-head') || (matrix.ruby-version == 'jruby') }} html2haml-2.3.0/MIT-LICENSE0000644000004100000410000000211414327674307015103 0ustar www-datawww-dataCopyright (c) 2006-2017 Hampton Catlin, Natalie Weizenbaum and Norman Clarke Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.html2haml-2.3.0/html2haml.gemspec0000644000004100000410000000207014327674307016705 0ustar www-datawww-data# -*- encoding: utf-8 -*- require File.expand_path('../lib/html2haml/version', __FILE__) Gem::Specification.new do |gem| gem.authors = ["Akira Matsuda", "Stefan Natchev"] gem.email = ["ronnie@dio.jp", "stefan.natchev@gmail.com"] gem.description = %q{Converts HTML into Haml} gem.summary = %q{Converts HTML into Haml} gem.homepage = "http://haml.info" gem.license = "MIT" gem.files = `git ls-files`.split($\) gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) } gem.test_files = gem.files.grep(%r{^(test|spec|features)/}) gem.name = "html2haml" gem.require_paths = ["lib"] gem.version = Html2haml::VERSION gem.required_ruby_version = '>= 1.9.2' gem.add_dependency 'nokogiri', '>= 1.6.0' gem.add_dependency 'erubis', '~> 2.7.0' gem.add_dependency 'ruby_parser', '~> 3.5' gem.add_dependency 'haml', '>= 4.0' gem.add_development_dependency 'simplecov', '~> 0.7.1' gem.add_development_dependency 'minitest', '>= 4.4.0' gem.add_development_dependency 'rake' end html2haml-2.3.0/Changelog.markdown0000644000004100000410000000207514327674307017110 0ustar www-datawww-data# HTML2Haml Changelog ## 2.3.0 * Haml 6+ support. * Fixed a bug that embedded ruby code was not parsed with the current version of ruby. ## 2.2.0 * Haml 5 support. ## 2.1.0 * Reduce specificity of Haml 4.0 version dependency. (thanks to [Ben Sheldon](https://github.com/bensheldon)) ## 2.0.0 * Switch to Nokogiri for XML parsing. (thanks to [Stefan Natchev](https://github.com/snatchev) and [Norman Clarke](https://github.com/norman)) * Add Ruby 2.0 support. (thanks to [Yasuharu Ozaki](https://github.com/yasuoza)) * Add option to use Ruby 1.9-style attributes when possible. (thanks to [Yoshinori Kawasaki](https://github.com/luvtechno) and [Alexander Egorov](https://github.com/qatsi)) * Updated dependency versions. * Removed some deprecated configuration flags. * Move the internal HTML class from the Haml namespace into the Html2haml namespace. ## 1.0.1 Rescue from `RubyParser::SyntaxError` in check for valid ruby. ## 1.0.0 * Extracted from Haml and released as an independent gem. For changes from previous versions, see the Haml changelog.