haml 4.0.7 → 5.0.4

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.
Files changed (123) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +18 -0
  3. data/.gitmodules +3 -0
  4. data/.travis.yml +54 -0
  5. data/.yardopts +1 -1
  6. data/CHANGELOG.md +96 -4
  7. data/FAQ.md +4 -14
  8. data/Gemfile +19 -0
  9. data/MIT-LICENSE +1 -1
  10. data/README.md +80 -42
  11. data/REFERENCE.md +116 -64
  12. data/Rakefile +46 -54
  13. data/TODO +24 -0
  14. data/benchmark.rb +66 -0
  15. data/haml.gemspec +38 -0
  16. data/lib/haml/.gitattributes +1 -0
  17. data/lib/haml/attribute_builder.rb +163 -0
  18. data/lib/haml/attribute_compiler.rb +223 -0
  19. data/lib/haml/attribute_parser.rb +148 -0
  20. data/lib/haml/buffer.rb +22 -132
  21. data/lib/haml/compiler.rb +89 -298
  22. data/lib/haml/engine.rb +25 -41
  23. data/lib/haml/error.rb +3 -0
  24. data/lib/haml/escapable.rb +49 -0
  25. data/lib/haml/exec.rb +38 -19
  26. data/lib/haml/filters.rb +18 -24
  27. data/lib/haml/generator.rb +41 -0
  28. data/lib/haml/helpers/action_view_extensions.rb +3 -2
  29. data/lib/haml/helpers/action_view_mods.rb +42 -60
  30. data/lib/haml/helpers/action_view_xss_mods.rb +1 -0
  31. data/lib/haml/helpers/safe_erubi_template.rb +19 -0
  32. data/lib/haml/helpers/safe_erubis_template.rb +4 -1
  33. data/lib/haml/helpers/xss_mods.rb +18 -12
  34. data/lib/haml/helpers.rb +132 -89
  35. data/lib/haml/options.rb +41 -47
  36. data/lib/haml/parser.rb +278 -216
  37. data/lib/haml/{template/plugin.rb → plugin.rb} +8 -15
  38. data/lib/haml/railtie.rb +38 -12
  39. data/lib/haml/sass_rails_filter.rb +17 -4
  40. data/lib/haml/template/options.rb +12 -2
  41. data/lib/haml/template.rb +12 -6
  42. data/lib/haml/temple_engine.rb +121 -0
  43. data/lib/haml/temple_line_counter.rb +29 -0
  44. data/lib/haml/util.rb +80 -199
  45. data/lib/haml/version.rb +2 -1
  46. data/lib/haml.rb +1 -0
  47. data/yard/default/.gitignore +1 -0
  48. data/yard/default/fulldoc/html/css/common.sass +15 -0
  49. data/yard/default/layout/html/footer.erb +12 -0
  50. metadata +50 -111
  51. data/test/engine_test.rb +0 -2013
  52. data/test/erb/_av_partial_1.erb +0 -12
  53. data/test/erb/_av_partial_2.erb +0 -8
  54. data/test/erb/action_view.erb +0 -62
  55. data/test/erb/standard.erb +0 -55
  56. data/test/filters_test.rb +0 -254
  57. data/test/gemfiles/Gemfile.rails-3.0.x +0 -5
  58. data/test/gemfiles/Gemfile.rails-3.1.x +0 -6
  59. data/test/gemfiles/Gemfile.rails-3.2.x +0 -5
  60. data/test/gemfiles/Gemfile.rails-4.0.x +0 -5
  61. data/test/haml-spec/LICENSE +0 -14
  62. data/test/haml-spec/README.md +0 -106
  63. data/test/haml-spec/lua_haml_spec.lua +0 -38
  64. data/test/haml-spec/perl_haml_test.pl +0 -81
  65. data/test/haml-spec/ruby_haml_test.rb +0 -23
  66. data/test/haml-spec/tests.json +0 -660
  67. data/test/helper_test.rb +0 -583
  68. data/test/markaby/standard.mab +0 -52
  69. data/test/mocks/article.rb +0 -6
  70. data/test/parser_test.rb +0 -105
  71. data/test/results/content_for_layout.xhtml +0 -12
  72. data/test/results/eval_suppressed.xhtml +0 -9
  73. data/test/results/helpers.xhtml +0 -70
  74. data/test/results/helpful.xhtml +0 -10
  75. data/test/results/just_stuff.xhtml +0 -70
  76. data/test/results/list.xhtml +0 -12
  77. data/test/results/nuke_inner_whitespace.xhtml +0 -40
  78. data/test/results/nuke_outer_whitespace.xhtml +0 -148
  79. data/test/results/original_engine.xhtml +0 -20
  80. data/test/results/partial_layout.xhtml +0 -5
  81. data/test/results/partial_layout_erb.xhtml +0 -5
  82. data/test/results/partials.xhtml +0 -21
  83. data/test/results/render_layout.xhtml +0 -3
  84. data/test/results/silent_script.xhtml +0 -74
  85. data/test/results/standard.xhtml +0 -162
  86. data/test/results/tag_parsing.xhtml +0 -23
  87. data/test/results/very_basic.xhtml +0 -5
  88. data/test/results/whitespace_handling.xhtml +0 -90
  89. data/test/template_test.rb +0 -354
  90. data/test/templates/_av_partial_1.haml +0 -9
  91. data/test/templates/_av_partial_1_ugly.haml +0 -9
  92. data/test/templates/_av_partial_2.haml +0 -5
  93. data/test/templates/_av_partial_2_ugly.haml +0 -5
  94. data/test/templates/_layout.erb +0 -3
  95. data/test/templates/_layout_for_partial.haml +0 -3
  96. data/test/templates/_partial.haml +0 -8
  97. data/test/templates/_text_area.haml +0 -3
  98. data/test/templates/_text_area_helper.html.haml +0 -4
  99. data/test/templates/action_view.haml +0 -47
  100. data/test/templates/action_view_ugly.haml +0 -47
  101. data/test/templates/breakage.haml +0 -8
  102. data/test/templates/content_for_layout.haml +0 -8
  103. data/test/templates/eval_suppressed.haml +0 -11
  104. data/test/templates/helpers.haml +0 -55
  105. data/test/templates/helpful.haml +0 -11
  106. data/test/templates/just_stuff.haml +0 -85
  107. data/test/templates/list.haml +0 -12
  108. data/test/templates/nuke_inner_whitespace.haml +0 -32
  109. data/test/templates/nuke_outer_whitespace.haml +0 -144
  110. data/test/templates/original_engine.haml +0 -17
  111. data/test/templates/partial_layout.haml +0 -3
  112. data/test/templates/partial_layout_erb.erb +0 -4
  113. data/test/templates/partialize.haml +0 -1
  114. data/test/templates/partials.haml +0 -12
  115. data/test/templates/render_layout.haml +0 -2
  116. data/test/templates/silent_script.haml +0 -45
  117. data/test/templates/standard.haml +0 -43
  118. data/test/templates/standard_ugly.haml +0 -43
  119. data/test/templates/tag_parsing.haml +0 -21
  120. data/test/templates/very_basic.haml +0 -4
  121. data/test/templates/whitespace_handling.haml +0 -87
  122. data/test/test_helper.rb +0 -81
  123. data/test/util_test.rb +0 -63
@@ -1,31 +1,24 @@
1
+ # frozen_string_literal: true
1
2
  module Haml
2
3
 
3
4
  # This module makes Haml work with Rails using the template handler API.
4
- class Plugin < ActionView::Template::Handlers::ERB.superclass
5
-
6
- # Rails 3.1+, template handlers don't inherit from anything. In <= 3.0, they
7
- # do. To avoid messy logic figuring this out, we just inherit from whatever
8
- # the ERB handler does.
9
-
10
- # In Rails 3.1+, we don't need to include Compilable.
11
- if (ActionPack::VERSION::MAJOR == 3) && (ActionPack::VERSION::MINOR < 1)
12
- include ActionView::Template::Handlers::Compilable
13
- end
14
-
5
+ class Plugin
15
6
  def handles_encoding?; true; end
16
7
 
17
8
  def compile(template)
18
9
  options = Haml::Template.options.dup
19
- if (ActionPack::VERSION::MAJOR >= 4) && template.respond_to?(:type)
10
+ if template.respond_to?(:type)
20
11
  options[:mime_type] = template.type
21
12
  elsif template.respond_to? :mime_type
22
13
  options[:mime_type] = template.mime_type
23
14
  end
24
15
  options[:filename] = template.identifier
25
- Haml::Engine.new(template.source, options).compiler.precompiled_with_ambles([])
16
+ Haml::Engine.new(template.source, options).compiler.precompiled_with_ambles(
17
+ [],
18
+ after_preamble: '@output_buffer = output_buffer ||= ActionView::OutputBuffer.new if defined?(ActionView::OutputBuffer)',
19
+ )
26
20
  end
27
21
 
28
- # In Rails 3.1+, #call takes the place of #compile
29
22
  def self.call(template)
30
23
  new.compile(template)
31
24
  end
@@ -38,4 +31,4 @@ module Haml
38
31
  end
39
32
  end
40
33
 
41
- ActionView::Template.register_template_handler(:haml, Haml::Plugin)
34
+ ActionView::Template.register_template_handler(:haml, Haml::Plugin)
data/lib/haml/railtie.rb CHANGED
@@ -1,22 +1,48 @@
1
- if defined?(ActiveSupport)
2
- require 'haml/template/options'
3
- ActiveSupport.on_load(:before_initialize) do
4
- ActiveSupport.on_load(:action_view) do
5
- require "haml/template"
6
- end
1
+ # frozen_string_literal: true
2
+ require 'haml/template/options'
3
+
4
+ # check for a compatible Rails version when Haml is loaded
5
+ if (activesupport_spec = Gem.loaded_specs['activesupport'])
6
+ if activesupport_spec.version.to_s < '3.2'
7
+ raise Exception.new("\n\n** Haml now requires Rails 3.2 and later. Use Haml version 4.0.4\n\n")
7
8
  end
8
9
  end
9
10
 
10
11
  module Haml
12
+ module Filters
13
+ module RailsErb
14
+ extend Plain
15
+ extend TiltFilter
16
+ extend PrecompiledTiltFilter
17
+ end
18
+ end
19
+
11
20
  class Railtie < ::Rails::Railtie
12
21
  initializer :haml do |app|
13
- require "haml/template"
14
- if defined?(::Sass::Rails::SassTemplate) && app.config.assets.enabled
15
- require "haml/sass_rails_filter"
22
+ ActiveSupport.on_load(:action_view) do
23
+ require "haml/template"
24
+
25
+ if defined?(::Sass::Rails::SassTemplate) && app.config.assets.enabled
26
+ require "haml/sass_rails_filter"
27
+ end
28
+
29
+ # Any object under ActionView::Template will be defined as the root constant with the same
30
+ # name if it exists. If Erubi is loaded at all, ActionView::Template::Handlers::ERB::Erubi
31
+ # will turn out to be a reference to the ::Erubi module.
32
+ # In Rails 4.2, calling const_defined? results in odd exceptions, which seems to be
33
+ # solved by looking for ::Erubi first.
34
+ # However, in JRuby, the const_defined? finds it anyway, so we must make sure that it's
35
+ # not just a reference to ::Erubi.
36
+ if defined?(::Erubi) && const_defined?('ActionView::Template::Handlers::ERB::Erubi') &&
37
+ ActionView::Template::Handlers::ERB::Erubi != ::Erubi
38
+ require "haml/helpers/safe_erubi_template"
39
+ Haml::Filters::RailsErb.template_class = Haml::SafeErubiTemplate
40
+ else
41
+ require "haml/helpers/safe_erubis_template"
42
+ Haml::Filters::RailsErb.template_class = Haml::SafeErubisTemplate
43
+ end
44
+ Haml::Template.options[:filters] = { 'erb' => Haml::Filters::RailsErb }
16
45
  end
17
46
  end
18
47
  end
19
48
  end
20
-
21
- require "haml/helpers/safe_erubis_template"
22
- Haml::Filters::Erb.template_class = Haml::SafeErubisTemplate
@@ -1,11 +1,24 @@
1
+ # frozen_string_literal: true
1
2
  module Haml
2
3
  module Filters
3
4
  # This is an extension of Sass::Rails's SassTemplate class that allows
4
5
  # Rails's asset helpers to be used inside Haml Sass filter.
5
6
  class SassRailsTemplate < ::Sass::Rails::SassTemplate
6
- def render(scope=Object.new, locals={}, &block)
7
- scope = ::Rails.application.assets.context_class.new(::Rails.application.assets, "/", "/")
8
- super
7
+ if Gem::Version.new(Sprockets::VERSION) >= Gem::Version.new('3.0.0')
8
+ def render(scope=Object.new, locals={}, &block)
9
+ environment = ::Sprockets::Railtie.build_environment(::Rails.application)
10
+ scope = environment.context_class.new(
11
+ environment: environment,
12
+ filename: "/",
13
+ metadata: {}
14
+ )
15
+ super
16
+ end
17
+ else
18
+ def render(scope=Object.new, locals={}, &block)
19
+ scope = ::Rails.application.assets.context_class.new(::Rails.application.assets, "/", "/")
20
+ super
21
+ end
9
22
  end
10
23
 
11
24
  def sass_options(scope)
@@ -30,4 +43,4 @@ module Haml
30
43
  register_tilt_filter "Sass", :extend => "Css", :template_class => SassRailsTemplate
31
44
  register_tilt_filter "Scss", :extend => "Css", :template_class => ScssRailsTemplate
32
45
  end
33
- end
46
+ end
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  # We keep options in its own self-contained file
2
3
  # so that we can load it independently in Rails 3,
3
4
  # where the full template stuff is lazy-loaded.
@@ -6,11 +7,20 @@ module Haml
6
7
  module Template
7
8
  extend self
8
9
 
9
- @options = {}
10
+ class Options < Hash
11
+ def []=(key, value)
12
+ super
13
+ if Haml::Options.buffer_defaults.key?(key)
14
+ Haml::Options.buffer_defaults[key] = value
15
+ end
16
+ end
17
+ end
18
+
19
+ @options = ::Haml::Template::Options.new
10
20
  # The options hash for Haml when used within Rails.
11
21
  # See {file:REFERENCE.md#options the Haml options documentation}.
12
22
  #
13
- # @return [{Symbol => Object}]
23
+ # @return [Haml::Template::Options<Symbol => Object>]
14
24
  attr_accessor :options
15
25
  end
16
26
  end
data/lib/haml/template.rb CHANGED
@@ -1,12 +1,19 @@
1
+ # frozen_string_literal: true
1
2
  require 'haml/template/options'
2
- require 'haml/engine'
3
- require 'haml/helpers/action_view_mods'
4
- require 'haml/helpers/action_view_extensions'
3
+ if defined?(ActiveSupport)
4
+ ActiveSupport.on_load(:action_view) do
5
+ require 'haml/helpers/action_view_mods'
6
+ require 'haml/helpers/action_view_extensions'
7
+ end
8
+ else
9
+ require 'haml/helpers/action_view_mods'
10
+ require 'haml/helpers/action_view_extensions'
11
+ end
5
12
  require 'haml/helpers/xss_mods'
6
13
  require 'haml/helpers/action_view_xss_mods'
7
14
 
8
15
  module Haml
9
- class Compiler
16
+ class TempleEngine
10
17
  def precompiled_method_return_value_with_haml_xss
11
18
  "::Haml::Util.html_safe(#{precompiled_method_return_value_without_haml_xss})"
12
19
  end
@@ -26,7 +33,6 @@ module Haml
26
33
  end
27
34
 
28
35
 
29
- Haml::Template.options[:ugly] = defined?(Rails) ? !Rails.env.development? : true
30
36
  Haml::Template.options[:escape_html] = true
31
37
 
32
- require 'haml/template/plugin'
38
+ require 'haml/plugin'
@@ -0,0 +1,121 @@
1
+ # frozen_string_literal: false
2
+ require 'temple'
3
+ require 'haml/escapable'
4
+ require 'haml/generator'
5
+
6
+ module Haml
7
+ class TempleEngine < Temple::Engine
8
+ define_options(
9
+ attr_wrapper: "'",
10
+ autoclose: %w(area base basefont br col command embed frame
11
+ hr img input isindex keygen link menuitem meta
12
+ param source track wbr),
13
+ encoding: nil,
14
+ escape_attrs: true,
15
+ escape_html: false,
16
+ filename: '(haml)',
17
+ format: :html5,
18
+ hyphenate_data_attrs: true,
19
+ line: 1,
20
+ mime_type: 'text/html',
21
+ preserve: %w(textarea pre code),
22
+ remove_whitespace: false,
23
+ suppress_eval: false,
24
+ cdata: false,
25
+ parser_class: ::Haml::Parser,
26
+ compiler_class: ::Haml::Compiler,
27
+ trace: false,
28
+ filters: {},
29
+ )
30
+
31
+ use :Parser, -> { options[:parser_class] }
32
+ use :Compiler, -> { options[:compiler_class] }
33
+ use Escapable
34
+ filter :ControlFlow
35
+ filter :MultiFlattener
36
+ filter :StaticMerger
37
+ use Generator
38
+
39
+ def compile(template)
40
+ initialize_encoding(template, options[:encoding])
41
+ @precompiled = call(template)
42
+ end
43
+
44
+ # The source code that is evaluated to produce the Haml document.
45
+ #
46
+ # This is automatically converted to the correct encoding
47
+ # (see {file:REFERENCE.md#encodings the `:encoding` option}).
48
+ #
49
+ # @return [String]
50
+ def precompiled
51
+ encoding = Encoding.find(@encoding || '')
52
+ return @precompiled.force_encoding(encoding) if encoding == Encoding::ASCII_8BIT
53
+ return @precompiled.encode(encoding)
54
+ end
55
+
56
+ def precompiled_with_return_value
57
+ "#{precompiled};#{precompiled_method_return_value}"
58
+ end
59
+
60
+ # The source code that is evaluated to produce the Haml document.
61
+ #
62
+ # This is automatically converted to the correct encoding
63
+ # (see {file:REFERENCE.md#encodings the `:encoding` option}).
64
+ #
65
+ # @return [String]
66
+ def precompiled_with_ambles(local_names, after_preamble: '')
67
+ preamble = <<END.tr!("\n", ';')
68
+ begin
69
+ extend Haml::Helpers
70
+ _hamlout = @haml_buffer = Haml::Buffer.new(haml_buffer, #{Options.new(options).for_buffer.inspect})
71
+ _erbout = _hamlout.buffer
72
+ #{after_preamble}
73
+ END
74
+ postamble = <<END.tr!("\n", ';')
75
+ #{precompiled_method_return_value}
76
+ ensure
77
+ @haml_buffer = @haml_buffer.upper if @haml_buffer
78
+ end
79
+ END
80
+ "#{preamble}#{locals_code(local_names)}#{precompiled}#{postamble}"
81
+ end
82
+
83
+ private
84
+
85
+ def initialize_encoding(template, given_value)
86
+ if given_value
87
+ @encoding = given_value
88
+ else
89
+ @encoding = Encoding.default_internal || template.encoding
90
+ end
91
+ end
92
+
93
+ # Returns the string used as the return value of the precompiled method.
94
+ # This method exists so it can be monkeypatched to return modified values.
95
+ def precompiled_method_return_value
96
+ "_erbout"
97
+ end
98
+
99
+ def locals_code(names)
100
+ names = names.keys if Hash === names
101
+
102
+ names.each_with_object('') do |name, code|
103
+ # Can't use || because someone might explicitly pass in false with a symbol
104
+ sym_local = "_haml_locals[#{inspect_obj(name.to_sym)}]"
105
+ str_local = "_haml_locals[#{inspect_obj(name.to_s)}]"
106
+ code << "#{name} = #{sym_local}.nil? ? #{str_local} : #{sym_local};"
107
+ end
108
+ end
109
+
110
+ def inspect_obj(obj)
111
+ case obj
112
+ when String
113
+ %Q!"#{obj.gsub(/[\x00-\x7F]+/) {|s| s.inspect[1...-1]}}"!
114
+ when Symbol
115
+ ":#{inspect_obj(obj.to_s)}"
116
+ else
117
+ obj.inspect
118
+ end
119
+ end
120
+ end
121
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+ module Haml
3
+ # A module to count lines of expected code. This would be faster than actual code generation
4
+ # and counting newlines in it.
5
+ module TempleLineCounter
6
+ class UnexpectedExpression < StandardError; end
7
+
8
+ def self.count_lines(exp)
9
+ type, *args = exp
10
+ case type
11
+ when :multi
12
+ args.map { |a| count_lines(a) }.reduce(:+) || 0
13
+ when :dynamic, :code
14
+ args.first.count("\n")
15
+ when :static
16
+ 0 # It has not real newline "\n" but escaped "\\n".
17
+ when :case
18
+ arg, *cases = args
19
+ arg.count("\n") + cases.map do |cond, e|
20
+ (cond == :else ? 0 : cond.count("\n")) + count_lines(e)
21
+ end.reduce(:+)
22
+ when :escape
23
+ count_lines(args[1])
24
+ else
25
+ raise UnexpectedExpression.new("[HAML BUG] Unexpected Temple expression '#{type}' is given!")
26
+ end
27
+ end
28
+ end
29
+ end