haml 4.0.0 → 5.0.0

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 (87) hide show
  1. checksums.yaml +7 -0
  2. data/.yardopts +1 -1
  3. data/CHANGELOG.md +117 -5
  4. data/FAQ.md +7 -17
  5. data/MIT-LICENSE +1 -1
  6. data/README.md +85 -42
  7. data/REFERENCE.md +181 -86
  8. data/Rakefile +47 -51
  9. data/lib/haml/attribute_builder.rb +163 -0
  10. data/lib/haml/attribute_compiler.rb +215 -0
  11. data/lib/haml/attribute_parser.rb +144 -0
  12. data/lib/haml/buffer.rb +38 -128
  13. data/lib/haml/compiler.rb +88 -295
  14. data/lib/haml/engine.rb +25 -41
  15. data/lib/haml/error.rb +3 -0
  16. data/lib/haml/escapable.rb +49 -0
  17. data/lib/haml/exec.rb +33 -19
  18. data/lib/haml/filters.rb +20 -24
  19. data/lib/haml/generator.rb +41 -0
  20. data/lib/haml/helpers/action_view_extensions.rb +3 -2
  21. data/lib/haml/helpers/action_view_mods.rb +44 -66
  22. data/lib/haml/helpers/action_view_xss_mods.rb +1 -0
  23. data/lib/haml/helpers/safe_erubi_template.rb +27 -0
  24. data/lib/haml/helpers/safe_erubis_template.rb +16 -4
  25. data/lib/haml/helpers/xss_mods.rb +18 -12
  26. data/lib/haml/helpers.rb +122 -58
  27. data/lib/haml/options.rb +39 -46
  28. data/lib/haml/parser.rb +278 -217
  29. data/lib/haml/{template/plugin.rb → plugin.rb} +8 -15
  30. data/lib/haml/railtie.rb +21 -11
  31. data/lib/haml/sass_rails_filter.rb +17 -4
  32. data/lib/haml/template/options.rb +12 -2
  33. data/lib/haml/template.rb +12 -6
  34. data/lib/haml/temple_engine.rb +120 -0
  35. data/lib/haml/temple_line_counter.rb +29 -0
  36. data/lib/haml/util.rb +80 -199
  37. data/lib/haml/version.rb +2 -1
  38. data/lib/haml.rb +2 -1
  39. data/test/attribute_parser_test.rb +101 -0
  40. data/test/engine_test.rb +306 -176
  41. data/test/filters_test.rb +32 -19
  42. data/test/gemfiles/Gemfile.rails-4.0.x +11 -0
  43. data/test/gemfiles/Gemfile.rails-4.0.x.lock +87 -0
  44. data/test/gemfiles/Gemfile.rails-4.1.x +5 -0
  45. data/test/gemfiles/Gemfile.rails-4.2.x +5 -0
  46. data/test/gemfiles/Gemfile.rails-5.0.x +4 -0
  47. data/test/helper_test.rb +282 -96
  48. data/test/options_test.rb +22 -0
  49. data/test/parser_test.rb +71 -4
  50. data/test/results/bemit.xhtml +4 -0
  51. data/test/results/eval_suppressed.xhtml +4 -4
  52. data/test/results/helpers.xhtml +43 -41
  53. data/test/results/helpful.xhtml +6 -3
  54. data/test/results/just_stuff.xhtml +21 -20
  55. data/test/results/list.xhtml +9 -9
  56. data/test/results/nuke_inner_whitespace.xhtml +22 -22
  57. data/test/results/nuke_outer_whitespace.xhtml +84 -92
  58. data/test/results/original_engine.xhtml +17 -17
  59. data/test/results/partial_layout.xhtml +4 -3
  60. data/test/results/partial_layout_erb.xhtml +4 -3
  61. data/test/results/partials.xhtml +11 -10
  62. data/test/results/silent_script.xhtml +63 -63
  63. data/test/results/standard.xhtml +156 -159
  64. data/test/results/tag_parsing.xhtml +19 -19
  65. data/test/results/very_basic.xhtml +2 -2
  66. data/test/results/whitespace_handling.xhtml +56 -50
  67. data/test/template_test.rb +44 -53
  68. data/test/template_test_helper.rb +38 -0
  69. data/test/templates/_text_area_helper.html.haml +4 -0
  70. data/test/templates/bemit.haml +3 -0
  71. data/test/templates/just_stuff.haml +1 -0
  72. data/test/templates/partial_layout_erb.erb +1 -1
  73. data/test/templates/standard_ugly.haml +1 -0
  74. data/test/templates/with_bom.haml +1 -0
  75. data/test/temple_line_counter_test.rb +40 -0
  76. data/test/test_helper.rb +26 -12
  77. data/test/util_test.rb +6 -47
  78. metadata +88 -106
  79. data/lib/haml/helpers/rails_323_textarea_fix.rb +0 -24
  80. data/test/gemfiles/Gemfile.rails-3.0.x +0 -5
  81. data/test/gemfiles/Gemfile.rails-3.1.x +0 -6
  82. data/test/gemfiles/Gemfile.rails-3.2.x +0 -5
  83. data/test/gemfiles/Gemfile.rails-master +0 -4
  84. data/test/templates/_av_partial_1_ugly.haml +0 -9
  85. data/test/templates/_av_partial_2_ugly.haml +0 -5
  86. data/test/templates/action_view_ugly.haml +0 -47
  87. data/test/templates/standard_ugly.haml +0 -43
data/lib/haml/engine.rb CHANGED
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: false
1
2
  require 'forwardable'
2
3
 
3
4
  require 'haml/parser'
@@ -7,6 +8,7 @@ require 'haml/helpers'
7
8
  require 'haml/buffer'
8
9
  require 'haml/filters'
9
10
  require 'haml/error'
11
+ require 'haml/temple_engine'
10
12
 
11
13
  module Haml
12
14
  # This is the frontend for using Haml programmatically.
@@ -35,9 +37,6 @@ module Haml
35
37
  # @return [String]
36
38
  attr_accessor :indentation
37
39
 
38
- attr_accessor :compiler
39
- attr_accessor :parser
40
-
41
40
  # Tilt currently depends on these moved methods, provide a stable API
42
41
  def_delegators :compiler, :precompiled, :precompiled_method_return_value
43
42
 
@@ -58,19 +57,19 @@ module Haml
58
57
  raise Haml::Error.new(msg, line)
59
58
  end
60
59
 
61
- initialize_encoding options[:encoding]
62
-
63
- @parser = @options.parser_class.new(@template, @options)
64
- @compiler = @options.compiler_class.new(@options)
60
+ @temple_engine = TempleEngine.new(options)
61
+ @temple_engine.compile(@template)
62
+ end
65
63
 
66
- @compiler.compile(@parser.parse)
64
+ # Deprecated API for backword compatibility
65
+ def compiler
66
+ @temple_engine
67
67
  end
68
68
 
69
69
  # Processes the template and returns the result as a string.
70
70
  #
71
71
  # `scope` is the context in which the template is evaluated.
72
- # If it's a `Binding` or `Proc` object,
73
- # Haml uses it as the second argument to `Kernel#eval`;
72
+ # If it's a `Binding`, Haml uses it as the second argument to `Kernel#eval`;
74
73
  # otherwise, Haml just uses its `#instance_eval` context.
75
74
  #
76
75
  # Note that Haml modifies the evaluation context
@@ -95,23 +94,23 @@ module Haml
95
94
  # within the template.
96
95
  #
97
96
  # Due to some Ruby quirks,
98
- # if `scope` is a `Binding` or `Proc` object and a block is given,
97
+ # if `scope` is a `Binding` object and a block is given,
99
98
  # the evaluation context may not be quite what the user expects.
100
99
  # In particular, it's equivalent to passing `eval("self", scope)` as `scope`.
101
100
  # This won't have an effect in most cases,
102
101
  # but if you're relying on local variables defined in the context of `scope`,
103
102
  # they won't work.
104
103
  #
105
- # @param scope [Binding, Proc, Object] The context in which the template is evaluated
104
+ # @param scope [Binding, Object] The context in which the template is evaluated
106
105
  # @param locals [{Symbol => Object}] Local variables that will be made available
107
106
  # to the template
108
107
  # @param block [#to_proc] A block that can be yielded to within the template
109
108
  # @return [String] The rendered template
110
109
  def render(scope = Object.new, locals = {}, &block)
111
- parent = scope.instance_variable_defined?('@haml_buffer') ? scope.instance_variable_get('@haml_buffer') : nil
110
+ parent = scope.instance_variable_defined?(:@haml_buffer) ? scope.instance_variable_get(:@haml_buffer) : nil
112
111
  buffer = Haml::Buffer.new(parent, @options.for_buffer)
113
112
 
114
- if scope.is_a?(Binding) || scope.is_a?(Proc)
113
+ if scope.is_a?(Binding)
115
114
  scope_object = eval("self", scope)
116
115
  scope = scope_object.instance_eval{binding} if block_given?
117
116
  else
@@ -121,20 +120,16 @@ module Haml
121
120
 
122
121
  set_locals(locals.merge(:_hamlout => buffer, :_erbout => buffer.buffer), scope, scope_object)
123
122
 
124
- scope_object.instance_eval do
125
- extend Haml::Helpers
126
- @haml_buffer = buffer
127
- end
123
+ scope_object.extend(Haml::Helpers)
124
+ scope_object.instance_variable_set(:@haml_buffer, buffer)
128
125
  begin
129
- eval(@compiler.precompiled_with_return_value, scope, @options[:filename], @options[:line])
126
+ eval(@temple_engine.precompiled_with_return_value, scope, @options.filename, @options.line)
130
127
  rescue ::SyntaxError => e
131
128
  raise SyntaxError, e.message
132
129
  end
133
130
  ensure
134
131
  # Get rid of the current buffer
135
- scope_object.instance_eval do
136
- @haml_buffer = buffer.upper if buffer
137
- end
132
+ scope_object.instance_variable_set(:@haml_buffer, buffer.upper) if buffer
138
133
  end
139
134
  alias_method :to_html, :render
140
135
 
@@ -159,11 +154,11 @@ module Haml
159
154
  #
160
155
  # The proc doesn't take a block; any yields in the template will fail.
161
156
  #
162
- # @param scope [Binding, Proc, Object] The context in which the template is evaluated
157
+ # @param scope [Binding, Object] The context in which the template is evaluated
163
158
  # @param local_names [Array<Symbol>] The names of the locals that can be passed to the proc
164
159
  # @return [Proc] The proc that will run the template
165
160
  def render_proc(scope = Object.new, *local_names)
166
- if scope.is_a?(Binding) || scope.is_a?(Proc)
161
+ if scope.is_a?(Binding)
167
162
  scope_object = eval("self", scope)
168
163
  else
169
164
  scope_object = scope
@@ -171,8 +166,8 @@ module Haml
171
166
  end
172
167
 
173
168
  begin
174
- eval("Proc.new { |*_haml_locals| _haml_locals = _haml_locals[0] || {};" +
175
- compiler.precompiled_with_ambles(local_names) + "}\n", scope, @options[:filename], @options[:line])
169
+ eval("Proc.new { |*_haml_locals| _haml_locals = _haml_locals[0] || {};" <<
170
+ @temple_engine.precompiled_with_ambles(local_names) << "}\n", scope, @options.filename, @options.line)
176
171
  rescue ::SyntaxError => e
177
172
  raise SyntaxError, e.message
178
173
  end
@@ -182,7 +177,7 @@ module Haml
182
177
  # that renders the template and returns the result as a string.
183
178
  #
184
179
  # If `object` is a class or module,
185
- # the method will instead by defined as an instance method.
180
+ # the method will instead be defined as an instance method.
186
181
  # For example:
187
182
  #
188
183
  # t = Time.now
@@ -219,25 +214,14 @@ module Haml
219
214
  def def_method(object, name, *local_names)
220
215
  method = object.is_a?(Module) ? :module_eval : :instance_eval
221
216
 
222
- object.send(method, "def #{name}(_haml_locals = {}); #{compiler.precompiled_with_ambles(local_names)}; end",
223
- @options[:filename], @options[:line])
217
+ object.send(method, "def #{name}(_haml_locals = {}); #{@temple_engine.precompiled_with_ambles(local_names)}; end",
218
+ @options.filename, @options.line)
224
219
  end
225
220
 
226
221
  private
227
222
 
228
- if RUBY_VERSION < "1.9"
229
- def initialize_encoding(given_value)
230
- end
231
- else
232
- def initialize_encoding(given_value)
233
- unless given_value
234
- @options.encoding = Encoding.default_internal || @template.encoding
235
- end
236
- end
237
- end
238
-
239
223
  def set_locals(locals, scope, scope_object)
240
- scope_object.send(:instance_variable_set, '@_haml_locals', locals)
224
+ scope_object.instance_variable_set :@_haml_locals, locals
241
225
  set_locals = locals.keys.map { |k| "#{k} = @_haml_locals[#{k.inspect}]" }.join("\n")
242
226
  eval(set_locals, scope)
243
227
  end
data/lib/haml/error.rb CHANGED
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Haml
2
3
  # An exception raised by Haml code.
3
4
  class Error < StandardError
@@ -58,4 +59,6 @@ END
58
59
  # It's not particularly interesting,
59
60
  # except in that it's a subclass of {Haml::Error}.
60
61
  class SyntaxError < Error; end
62
+
63
+ class InvalidAttributeNameError < SyntaxError; end
61
64
  end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+ module Haml
3
+ # Like Temple::Filters::Escapable, but with support for escaping by
4
+ # Haml::Herlpers.html_escape and Haml::Herlpers.escape_once.
5
+ class Escapable < Temple::Filter
6
+ def initialize(*)
7
+ super
8
+ @escape_code = "::Haml::Helpers.html_escape((%s))"
9
+ @escaper = eval("proc {|v| #{@escape_code % 'v'} }")
10
+ @once_escape_code = "::Haml::Helpers.escape_once((%s))"
11
+ @once_escaper = eval("proc {|v| #{@once_escape_code % 'v'} }")
12
+ @escape = false
13
+ end
14
+
15
+ def on_escape(flag, exp)
16
+ old = @escape
17
+ @escape = flag
18
+ compile(exp)
19
+ ensure
20
+ @escape = old
21
+ end
22
+
23
+ # The same as Haml::AttributeBuilder.build_attributes
24
+ def on_static(value)
25
+ [:static,
26
+ if @escape == :once
27
+ @once_escaper[value]
28
+ elsif @escape
29
+ @escaper[value]
30
+ else
31
+ value
32
+ end
33
+ ]
34
+ end
35
+
36
+ # The same as Haml::AttributeBuilder.build_attributes
37
+ def on_dynamic(value)
38
+ [:dynamic,
39
+ if @escape == :once
40
+ @once_escape_code % value
41
+ elsif @escape
42
+ @escape_code % value
43
+ else
44
+ "(#{value}).to_s"
45
+ end
46
+ ]
47
+ end
48
+ end
49
+ end
data/lib/haml/exec.rb CHANGED
@@ -1,5 +1,5 @@
1
+ # frozen_string_literal: true
1
2
  require 'optparse'
2
- require 'fileutils'
3
3
  require 'rbconfig'
4
4
  require 'pp'
5
5
 
@@ -212,11 +212,6 @@ END
212
212
  @options[:output] = StringIO.new
213
213
  end
214
214
 
215
- opts.on('-t', '--style NAME',
216
- 'Output style. Can be indented (default) or ugly.') do |name|
217
- @options[:for_engine][:ugly] = true if name.to_sym == :ugly
218
- end
219
-
220
215
  opts.on('-f', '--format NAME',
221
216
  'Output format. Can be html5 (default), xhtml, or html4.') do |name|
222
217
  @options[:for_engine][:format] = name.to_sym
@@ -237,6 +232,11 @@ END
237
232
  @options[:for_engine][:attr_wrapper] = '"'
238
233
  end
239
234
 
235
+ opts.on('--remove-whitespace',
236
+ 'Remove whitespace surrounding and within tags') do
237
+ @options[:for_engine][:remove_whitespace] = true
238
+ end
239
+
240
240
  opts.on('--cdata',
241
241
  'Always add CDATA sections to javascript and css blocks.') do
242
242
  @options[:for_engine][:cdata] = true
@@ -260,15 +260,13 @@ END
260
260
  @options[:load_paths] << path
261
261
  end
262
262
 
263
- unless RUBY_VERSION < "1.9"
264
- opts.on('-E ex[:in]', 'Specify the default external and internal character encodings.') do |encoding|
265
- external, internal = encoding.split(':')
266
- Encoding.default_external = external if external && !external.empty?
267
- Encoding.default_internal = internal if internal && !internal.empty?
268
- end
263
+ opts.on('-E ex[:in]', 'Specify the default external and internal character encodings.') do |encoding|
264
+ external, internal = encoding.split(':')
265
+ Encoding.default_external = external if external && !external.empty?
266
+ Encoding.default_internal = internal if internal && !internal.empty?
269
267
  end
270
268
 
271
- opts.on('-d', '--debug', "Print out the precompiled Ruby source.") do
269
+ opts.on('-d', '--debug', "Print out the precompiled Ruby source, and show syntax errors in the Ruby code.") do
272
270
  @options[:debug] = true
273
271
  end
274
272
 
@@ -294,20 +292,28 @@ END
294
292
 
295
293
  begin
296
294
 
297
- engine = ::Haml::Engine.new(template, @options[:for_engine])
298
- if @options[:check_syntax]
299
- puts "Syntax OK"
295
+ if @options[:parse]
296
+ parser = ::Haml::Parser.new(::Haml::Options.new(@options))
297
+ pp parser.call(template)
300
298
  return
301
299
  end
302
300
 
303
- if @options[:parse]
304
- pp engine.parser.root
301
+ engine = ::Haml::Engine.new(template, @options[:for_engine])
302
+
303
+ if @options[:check_syntax]
304
+ puts "Syntax OK"
305
305
  return
306
306
  end
307
307
 
308
308
  if @options[:debug]
309
309
  puts engine.precompiled
310
- puts '=' * 100
310
+ error = validate_ruby(engine.precompiled)
311
+ if error
312
+ puts '=' * 100
313
+ puts error.message.split("\n")[0]
314
+ exit 1
315
+ end
316
+ return
311
317
  end
312
318
 
313
319
  result = engine.to_html
@@ -324,6 +330,14 @@ END
324
330
  output.write(result)
325
331
  output.close() if output.is_a? File
326
332
  end
333
+
334
+ def validate_ruby(code)
335
+ begin
336
+ eval("BEGIN {return nil}; #{code}")
337
+ rescue ::SyntaxError # Not to be confused with Haml::SyntaxError
338
+ $!
339
+ end
340
+ end
327
341
  end
328
342
  end
329
343
  end
data/lib/haml/filters.rb CHANGED
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: false
1
2
  require "tilt"
2
3
 
3
4
  module Haml
@@ -59,7 +60,7 @@ module Haml
59
60
  end
60
61
 
61
62
  # Removes a filter from Haml. If the filter was removed, it returns
62
- # the that was remove Module upon success, or nil on failure. If you try
63
+ # the Module that was removed upon success, or nil on failure. If you try
63
64
  # to redefine a filter, Haml will raise an error. Use this method first to
64
65
  # explicitly remove the filter before redefining it.
65
66
  # @return Module The filter module that has been removed
@@ -163,10 +164,10 @@ module Haml
163
164
  if contains_interpolation?(text)
164
165
  return if options[:suppress_eval]
165
166
 
166
- text = unescape_interpolation(text).gsub(/(\\+)n/) do |s|
167
+ text = unescape_interpolation(text, options[:escape_html]).gsub(/(\\+)n/) do |s|
167
168
  escapes = $1.size
168
169
  next s if escapes % 2 == 0
169
- ("\\" * (escapes - 1)) + "\n"
170
+ "#{'\\' * (escapes - 1)}\n"
170
171
  end
171
172
  # We need to add a newline at the beginning to get the
172
173
  # filter lines to line up (since the Haml filter contains
@@ -174,7 +175,7 @@ module Haml
174
175
  # filter name). Then we need to escape the trailing
175
176
  # newline so that the whole filter block doesn't take up
176
177
  # too many.
177
- text = "\n" + text.sub(/\n"\Z/, "\\n\"")
178
+ text = %[\n#{text.sub(/\n"\Z/, "\\n\"")}]
178
179
  push_script <<RUBY.rstrip, :escape_html => false
179
180
  find_and_preserve(#{filter.inspect}.render_with_options(#{text}, _hamlout.options))
180
181
  RUBY
@@ -182,12 +183,8 @@ RUBY
182
183
  end
183
184
 
184
185
  rendered = Haml::Helpers::find_and_preserve(filter.render_with_options(text, compiler.options), compiler.options[:preserve])
185
-
186
- if options[:ugly]
187
- push_text(rendered.rstrip)
188
- else
189
- push_text(rendered.rstrip.gsub("\n", "\n#{' ' * @output_tabs}"))
190
- end
186
+ rendered.rstrip!
187
+ push_text("#{rendered}\n")
191
188
  end
192
189
  end
193
190
  end
@@ -216,13 +213,10 @@ RUBY
216
213
  type = " type=#{options[:attr_wrapper]}text/javascript#{options[:attr_wrapper]}"
217
214
  end
218
215
 
219
- str = "<script#{type}>\n"
220
- str << " //<![CDATA[\n" if options[:cdata]
221
- str << "#{indent}#{text.rstrip.gsub("\n", "\n#{indent}")}\n"
222
- str << " //]]>\n" if options[:cdata]
223
- str << "</script>"
216
+ text = text.rstrip
217
+ text.gsub!("\n", "\n#{indent}")
224
218
 
225
- str
219
+ %!<script#{type}>\n#{" //<![CDATA[\n" if options[:cdata]}#{indent}#{text}\n#{" //]]>\n" if options[:cdata]}</script>!
226
220
  end
227
221
  end
228
222
 
@@ -240,13 +234,10 @@ RUBY
240
234
  type = " type=#{options[:attr_wrapper]}text/css#{options[:attr_wrapper]}"
241
235
  end
242
236
 
243
- str = "<style#{type}>\n"
244
- str << " /*<![CDATA[*/\n" if options[:cdata]
245
- str << "#{indent}#{text.rstrip.gsub("\n", "\n#{indent}")}\n"
246
- str << " /*]]>*/\n" if options[:cdata]
247
- str << "</style>"
237
+ text = text.rstrip
238
+ text.gsub!("\n", "\n#{indent}")
248
239
 
249
- str
240
+ %(<style#{type}>\n#{" /*<![CDATA[*/\n" if options[:cdata]}#{indent}#{text}\n#{" /*]]>*/\n" if options[:cdata]}</style>)
250
241
  end
251
242
  end
252
243
 
@@ -256,7 +247,10 @@ RUBY
256
247
 
257
248
  # @see Base#render
258
249
  def render(text)
259
- "<![CDATA[#{("\n" + text).rstrip.gsub("\n", "\n ")}\n]]>"
250
+ text = "\n#{text}"
251
+ text.rstrip!
252
+ text.gsub!("\n", "\n ")
253
+ "<![CDATA[#{text}\n]]>"
260
254
  end
261
255
  end
262
256
 
@@ -288,7 +282,7 @@ RUBY
288
282
  def compile(compiler, text)
289
283
  return if compiler.options[:suppress_eval]
290
284
  compiler.instance_eval do
291
- push_silent <<-FIRST.gsub("\n", ';') + text + <<-LAST.gsub("\n", ';')
285
+ push_silent <<-FIRST.tr("\n", ';') + text + <<-LAST.tr("\n", ';')
292
286
  begin
293
287
  haml_io = StringIO.new(_hamlout.buffer, 'a')
294
288
  FIRST
@@ -385,6 +379,8 @@ RUBY
385
379
  module Erb
386
380
  class << self
387
381
  def precompiled(text)
382
+ #workaround for https://github.com/rtomayko/tilt/pull/183
383
+ require 'erubis' if (defined?(::Erubis) && !defined?(::Erubis::Eruby))
388
384
  super.sub(/^#coding:.*?\n/, '')
389
385
  end
390
386
  end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+ module Haml
3
+ # Ruby code generator, which is a limited version of Temple::Generator.
4
+ # Limit methods since Haml doesn't need most of them.
5
+ class Generator
6
+ include Temple::Mixins::CompiledDispatcher
7
+ include Temple::Mixins::Options
8
+
9
+ define_options freeze_static: RUBY_VERSION >= '2.1'
10
+
11
+ def call(exp)
12
+ compile(exp)
13
+ end
14
+
15
+ def on_multi(*exp)
16
+ exp.map { |e| compile(e) }.join('; ')
17
+ end
18
+
19
+ def on_static(text)
20
+ concat(options[:freeze_static] ? "#{Util.inspect_obj(text)}.freeze" : Util.inspect_obj(text))
21
+ end
22
+
23
+ def on_dynamic(code)
24
+ concat(code)
25
+ end
26
+
27
+ def on_code(exp)
28
+ exp
29
+ end
30
+
31
+ def on_newline
32
+ "\n"
33
+ end
34
+
35
+ private
36
+
37
+ def concat(str)
38
+ "_hamlout.buffer << (#{str});"
39
+ end
40
+ end
41
+ end
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Haml
2
3
  module Helpers
3
4
  @@action_view_defined = true
@@ -32,7 +33,7 @@ module Haml
32
33
  #
33
34
  # @return [String] The class name for the current page
34
35
  def page_class
35
- controller.controller_name + " " + controller.action_name
36
+ "#{controller.controller_name} #{controller.action_name}"
36
37
  end
37
38
  alias_method :generate_content_class_names, :page_class
38
39
 
@@ -45,8 +46,8 @@ module Haml
45
46
  # @yield A block in which all input to `#haml_concat` is treated as raw.
46
47
  # @see Haml::Util#rails_xss_safe?
47
48
  def with_raw_haml_concat
49
+ old = instance_variable_defined?(:@_haml_concat_raw) ? @_haml_concat_raw : false
48
50
  @_haml_concat_raw = true
49
- old = @_haml_concat_raw
50
51
  yield
51
52
  ensure
52
53
  @_haml_concat_raw = old
@@ -1,60 +1,48 @@
1
- module ActionView
2
- class Base
3
- def render_with_haml(*args, &block)
4
- options = args.first
5
-
6
- # If render :layout is used with a block, it concats rather than returning
7
- # a string so we need it to keep thinking it's Haml until it hits the
8
- # sub-render.
9
- if is_haml? && !(options.is_a?(Hash) && options[:layout] && block_given?)
10
- return non_haml { render_without_haml(*args, &block) }
1
+ # frozen_string_literal: true
2
+ module Haml
3
+ module Helpers
4
+ module ActionViewMods
5
+ def render(*args, &block)
6
+ options = args.first
7
+
8
+ # If render :layout is used with a block, it concats rather than returning
9
+ # a string so we need it to keep thinking it's Haml until it hits the
10
+ # sub-render.
11
+ if is_haml? && !(options.is_a?(Hash) && options[:layout] && block_given?)
12
+ return non_haml { super }
13
+ end
14
+ super
11
15
  end
12
- render_without_haml(*args, &block)
13
- end
14
- alias_method :render_without_haml, :render
15
- alias_method :render, :render_with_haml
16
16
 
17
- def output_buffer_with_haml
18
- return haml_buffer.buffer if is_haml?
19
- output_buffer_without_haml
20
- end
21
- alias_method :output_buffer_without_haml, :output_buffer
22
- alias_method :output_buffer, :output_buffer_with_haml
17
+ def output_buffer
18
+ return haml_buffer.buffer if is_haml?
19
+ super
20
+ end
23
21
 
24
- def set_output_buffer_with_haml(new_buffer)
25
- if is_haml?
26
- if Haml::Util.rails_xss_safe? && new_buffer.is_a?(ActiveSupport::SafeBuffer)
27
- new_buffer = String.new(new_buffer)
22
+ def output_buffer=(new_buffer)
23
+ if is_haml?
24
+ if Haml::Util.rails_xss_safe? && new_buffer.is_a?(ActiveSupport::SafeBuffer)
25
+ new_buffer = String.new(new_buffer)
26
+ end
27
+ haml_buffer.buffer = new_buffer
28
+ else
29
+ super
28
30
  end
29
- haml_buffer.buffer = new_buffer
30
- else
31
- set_output_buffer_without_haml new_buffer
32
31
  end
33
32
  end
34
- alias_method :set_output_buffer_without_haml, :output_buffer=
35
- alias_method :output_buffer=, :set_output_buffer_with_haml
33
+ ActionView::Base.send(:prepend, ActionViewMods)
36
34
  end
35
+ end
37
36
 
37
+ module ActionView
38
38
  module Helpers
39
39
  module CaptureHelper
40
40
  def capture_with_haml(*args, &block)
41
41
  if Haml::Helpers.block_is_haml?(block)
42
42
  #double assignment is to avoid warnings
43
43
  _hamlout = _hamlout = eval('_hamlout', block.binding) # Necessary since capture_haml checks _hamlout
44
- value = nil
45
- buffer = capture_haml(*args) { value = yield(*args) }
46
- str =
47
- if !buffer.empty?
48
- buffer
49
- elsif value.is_a?(String)
50
- value
51
- else
52
- ''
53
- end
54
- # NonCattingString is present in Rails less than 3.1.0. When support
55
- # for 3.0 is dropped, this can be removed.
56
- return ActionView::NonConcattingString.new(str) if defined?(ActionView::NonConcattingString)
57
- return str
44
+
45
+ capture_haml(*args, &block)
58
46
  else
59
47
  capture_without_haml(*args, &block)
60
48
  end
@@ -67,7 +55,7 @@ module ActionView
67
55
  def content_tag_with_haml(name, *args, &block)
68
56
  return content_tag_without_haml(name, *args, &block) unless is_haml?
69
57
 
70
- preserve = haml_buffer.options[:preserve].include?(name.to_s)
58
+ preserve = haml_buffer.options.fetch(:preserve, %w[textarea pre code]).include?(name.to_s)
71
59
 
72
60
  if block_given? && block_is_haml?(block) && preserve
73
61
  return content_tag_without_haml(name, *args) {preserve(&block)}
@@ -82,8 +70,7 @@ module ActionView
82
70
  alias_method :content_tag, :content_tag_with_haml
83
71
  end
84
72
 
85
- class InstanceTag
86
- # Already includes TagHelper
73
+ module HamlSupport
87
74
  include Haml::Helpers
88
75
 
89
76
  def haml_buffer
@@ -93,6 +80,16 @@ module ActionView
93
80
  def is_haml?
94
81
  @template_object.send :is_haml?
95
82
  end
83
+ end
84
+
85
+ module Tags
86
+ class TextArea
87
+ include HamlSupport
88
+ end
89
+ end
90
+
91
+ class InstanceTag
92
+ include HamlSupport
96
93
 
97
94
  def content_tag(*args, &block)
98
95
  html_tag = content_tag_with_haml(*args, &block)
@@ -114,7 +111,7 @@ module ActionView
114
111
  with_tabs(1) {oldproc.call(*args)}
115
112
  end
116
113
  end
117
- res = form_tag_without_haml(url_for_options, options, *parameters_for_url, &proc) + "\n"
114
+ res = form_tag_without_haml(url_for_options, options, *parameters_for_url, &proc) << "\n"
118
115
  res << "\n" if wrap_block
119
116
  res
120
117
  else
@@ -124,24 +121,5 @@ module ActionView
124
121
  alias_method :form_tag_without_haml, :form_tag
125
122
  alias_method :form_tag, :form_tag_with_haml
126
123
  end
127
-
128
- module FormHelper
129
- def form_for_with_haml(object_name, *args, &proc)
130
- wrap_block = block_given? && is_haml? && block_is_haml?(proc)
131
- if wrap_block
132
- oldproc = proc
133
- proc = proc {|*subargs| with_tabs(1) {oldproc.call(*subargs)}}
134
- end
135
- res = form_for_without_haml(object_name, *args, &proc)
136
- res << "\n" if wrap_block
137
- res
138
- end
139
- alias_method :form_for_without_haml, :form_for
140
- alias_method :form_for, :form_for_with_haml
141
- end
142
124
  end
143
125
  end
144
-
145
- if ((ActionPack::VERSION::MAJOR == 3) && (ActionPack::VERSION::MINOR >= 2) && (ActionPack::VERSION::TINY >= 3) || (ActionPack::VERSION::MAJOR == 4))
146
- require "haml/helpers/rails_323_textarea_fix"
147
- end
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module ActionView
2
3
  module Helpers
3
4
  module CaptureHelper