haml 4.1.0.beta.1 → 5.0.0.beta.2

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of haml might be problematic. Click here for more details.

Files changed (75) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +1 -1
  3. data/CHANGELOG.md +36 -6
  4. data/FAQ.md +4 -14
  5. data/MIT-LICENSE +1 -1
  6. data/README.md +81 -48
  7. data/REFERENCE.md +86 -50
  8. data/Rakefile +28 -41
  9. data/lib/haml/attribute_builder.rb +163 -0
  10. data/lib/haml/attribute_compiler.rb +214 -0
  11. data/lib/haml/attribute_parser.rb +112 -0
  12. data/lib/haml/buffer.rb +24 -126
  13. data/lib/haml/compiler.rb +62 -281
  14. data/lib/haml/engine.rb +16 -23
  15. data/lib/haml/error.rb +2 -0
  16. data/lib/haml/escapable.rb +48 -0
  17. data/lib/haml/exec.rb +23 -12
  18. data/lib/haml/filters.rb +3 -4
  19. data/lib/haml/generator.rb +36 -0
  20. data/lib/haml/helpers.rb +61 -48
  21. data/lib/haml/helpers/action_view_extensions.rb +1 -1
  22. data/lib/haml/helpers/action_view_mods.rb +32 -50
  23. data/lib/haml/helpers/safe_erubi_template.rb +26 -0
  24. data/lib/haml/helpers/safe_erubis_template.rb +2 -0
  25. data/lib/haml/helpers/xss_mods.rb +17 -12
  26. data/lib/haml/options.rb +32 -36
  27. data/lib/haml/parser.rb +61 -38
  28. data/lib/haml/{template/plugin.rb → plugin.rb} +5 -2
  29. data/lib/haml/railtie.rb +14 -6
  30. data/lib/haml/template.rb +11 -6
  31. data/lib/haml/temple_engine.rb +119 -0
  32. data/lib/haml/temple_line_counter.rb +28 -0
  33. data/lib/haml/util.rb +17 -112
  34. data/lib/haml/version.rb +1 -1
  35. data/test/attribute_parser_test.rb +105 -0
  36. data/test/engine_test.rb +202 -106
  37. data/test/filters_test.rb +32 -19
  38. data/test/gemfiles/Gemfile.rails-4.0.x +7 -1
  39. data/test/gemfiles/Gemfile.rails-4.0.x.lock +57 -71
  40. data/test/gemfiles/Gemfile.rails-4.1.x +5 -0
  41. data/test/gemfiles/Gemfile.rails-4.2.x +5 -0
  42. data/test/gemfiles/Gemfile.rails-5.0.x +4 -0
  43. data/test/helper_test.rb +156 -109
  44. data/test/options_test.rb +21 -0
  45. data/test/parser_test.rb +49 -4
  46. data/test/results/eval_suppressed.xhtml +4 -4
  47. data/test/results/helpers.xhtml +43 -41
  48. data/test/results/helpful.xhtml +6 -3
  49. data/test/results/just_stuff.xhtml +21 -20
  50. data/test/results/list.xhtml +9 -9
  51. data/test/results/nuke_inner_whitespace.xhtml +22 -22
  52. data/test/results/nuke_outer_whitespace.xhtml +84 -92
  53. data/test/results/original_engine.xhtml +17 -17
  54. data/test/results/partial_layout.xhtml +4 -3
  55. data/test/results/partial_layout_erb.xhtml +4 -3
  56. data/test/results/partials.xhtml +11 -10
  57. data/test/results/silent_script.xhtml +63 -63
  58. data/test/results/standard.xhtml +156 -159
  59. data/test/results/tag_parsing.xhtml +19 -19
  60. data/test/results/very_basic.xhtml +2 -2
  61. data/test/results/whitespace_handling.xhtml +77 -76
  62. data/test/template_test.rb +21 -48
  63. data/test/template_test_helper.rb +38 -0
  64. data/test/templates/just_stuff.haml +1 -0
  65. data/test/templates/standard_ugly.haml +1 -0
  66. data/test/temple_line_counter_test.rb +40 -0
  67. data/test/test_helper.rb +10 -10
  68. data/test/util_test.rb +1 -48
  69. metadata +49 -35
  70. data/lib/haml/temple.rb +0 -85
  71. data/test/gemfiles/Gemfile.rails-3.2.x +0 -4
  72. data/test/templates/_av_partial_1_ugly.haml +0 -9
  73. data/test/templates/_av_partial_2_ugly.haml +0 -5
  74. data/test/templates/action_view_ugly.haml +0 -47
  75. data/test/templates/standard_ugly.haml +0 -43
@@ -6,13 +6,16 @@ module Haml
6
6
 
7
7
  def compile(template)
8
8
  options = Haml::Template.options.dup
9
- if (ActionPack::VERSION::MAJOR >= 4) && template.respond_to?(:type)
9
+ if template.respond_to?(:type)
10
10
  options[:mime_type] = template.type
11
11
  elsif template.respond_to? :mime_type
12
12
  options[:mime_type] = template.mime_type
13
13
  end
14
14
  options[:filename] = template.identifier
15
- Haml::Engine.new(template.source, options).compiler.precompiled_with_ambles([])
15
+ Haml::Engine.new(template.source, options).compiler.precompiled_with_ambles(
16
+ [],
17
+ after_preamble: '@output_buffer = output_buffer ||= ActionView::OutputBuffer.new if defined?(ActionView::OutputBuffer)',
18
+ )
16
19
  end
17
20
 
18
21
  def self.call(template)
@@ -7,9 +7,15 @@ if defined?(ActiveSupport)
7
7
  end
8
8
 
9
9
  require 'haml/template/options'
10
- ActiveSupport.on_load(:before_initialize) do
11
- ActiveSupport.on_load(:action_view) do
12
- require "haml/template"
10
+ ActiveSupport.on_load(:action_view) do
11
+ require "haml/template"
12
+
13
+ if defined? Erubi
14
+ require "haml/helpers/safe_erubi_template"
15
+ Haml::Filters::Erb.template_class = Haml::SafeErubiTemplate
16
+ else
17
+ require "haml/helpers/safe_erubis_template"
18
+ Haml::Filters::Erb.template_class = Haml::SafeErubisTemplate
13
19
  end
14
20
  end
15
21
  end
@@ -21,9 +27,11 @@ module Haml
21
27
  if defined?(::Sass::Rails::SassTemplate) && app.config.assets.enabled
22
28
  require "haml/sass_rails_filter"
23
29
  end
30
+ Haml::Options.buffer_defaults.keys.each do |key|
31
+ if Haml::Template.options.key?(key)
32
+ Haml::Options.buffer_defaults[key] = Haml::Template.options[key]
33
+ end
34
+ end
24
35
  end
25
36
  end
26
37
  end
27
-
28
- require "haml/helpers/safe_erubis_template"
29
- Haml::Filters::Erb.template_class = Haml::SafeErubisTemplate
@@ -1,12 +1,18 @@
1
1
  require 'haml/template/options'
2
- require 'haml/engine'
3
- require 'haml/helpers/action_view_mods'
4
- require 'haml/helpers/action_view_extensions'
2
+ if defined?(ActiveSupport)
3
+ ActiveSupport.on_load(:action_view) do
4
+ require 'haml/helpers/action_view_mods'
5
+ require 'haml/helpers/action_view_extensions'
6
+ end
7
+ else
8
+ require 'haml/helpers/action_view_mods'
9
+ require 'haml/helpers/action_view_extensions'
10
+ end
5
11
  require 'haml/helpers/xss_mods'
6
12
  require 'haml/helpers/action_view_xss_mods'
7
13
 
8
14
  module Haml
9
- class Compiler
15
+ class TempleEngine
10
16
  def precompiled_method_return_value_with_haml_xss
11
17
  "::Haml::Util.html_safe(#{precompiled_method_return_value_without_haml_xss})"
12
18
  end
@@ -26,7 +32,6 @@ module Haml
26
32
  end
27
33
 
28
34
 
29
- Haml::Template.options[:ugly] = defined?(Rails) ? !Rails.env.development? : true
30
35
  Haml::Template.options[:escape_html] = true
31
36
 
32
- require 'haml/template/plugin'
37
+ require 'haml/plugin'
@@ -0,0 +1,119 @@
1
+ require 'temple'
2
+ require 'haml/escapable'
3
+ require 'haml/generator'
4
+
5
+ module Haml
6
+ class TempleEngine < Temple::Engine
7
+ define_options(
8
+ attr_wrapper: "'",
9
+ autoclose: %w(area base basefont br col command embed frame
10
+ hr img input isindex keygen link menuitem meta
11
+ param source track wbr),
12
+ encoding: nil,
13
+ escape_attrs: true,
14
+ escape_html: false,
15
+ filename: '(haml)',
16
+ format: :html5,
17
+ hyphenate_data_attrs: true,
18
+ line: 1,
19
+ mime_type: 'text/html',
20
+ preserve: %w(textarea pre code),
21
+ remove_whitespace: false,
22
+ suppress_eval: false,
23
+ cdata: false,
24
+ parser_class: ::Haml::Parser,
25
+ compiler_class: ::Haml::Compiler,
26
+ trace: false,
27
+ )
28
+
29
+ use :Parser, -> { options[:parser_class] }
30
+ use :Compiler, -> { options[:compiler_class] }
31
+ use Escapable
32
+ filter :ControlFlow
33
+ filter :MultiFlattener
34
+ filter :StaticMerger
35
+ use Generator
36
+
37
+ def compile(template)
38
+ initialize_encoding(template, options[:encoding])
39
+ @precompiled = call(template)
40
+ end
41
+
42
+ # The source code that is evaluated to produce the Haml document.
43
+ #
44
+ # This is automatically converted to the correct encoding
45
+ # (see {file:REFERENCE.md#encodings the `:encoding` option}).
46
+ #
47
+ # @return [String]
48
+ def precompiled
49
+ encoding = Encoding.find(@encoding || '')
50
+ return @precompiled.force_encoding(encoding) if encoding == Encoding::ASCII_8BIT
51
+ return @precompiled.encode(encoding)
52
+ end
53
+
54
+ def precompiled_with_return_value
55
+ "#{precompiled};#{precompiled_method_return_value}"
56
+ end
57
+
58
+ # The source code that is evaluated to produce the Haml document.
59
+ #
60
+ # This is automatically converted to the correct encoding
61
+ # (see {file:REFERENCE.md#encodings the `:encoding` option}).
62
+ #
63
+ # @return [String]
64
+ def precompiled_with_ambles(local_names, after_preamble: '')
65
+ preamble = <<END.tr!("\n", ';')
66
+ begin
67
+ extend Haml::Helpers
68
+ _hamlout = @haml_buffer = Haml::Buffer.new(haml_buffer, #{Options.new(options).for_buffer.inspect})
69
+ _erbout = _hamlout.buffer
70
+ #{after_preamble}
71
+ END
72
+ postamble = <<END.tr!("\n", ';')
73
+ #{precompiled_method_return_value}
74
+ ensure
75
+ @haml_buffer = @haml_buffer.upper if @haml_buffer
76
+ end
77
+ END
78
+ "#{preamble}#{locals_code(local_names)}#{precompiled}#{postamble}"
79
+ end
80
+
81
+ private
82
+
83
+ def initialize_encoding(template, given_value)
84
+ if given_value
85
+ @encoding = given_value
86
+ else
87
+ @encoding = Encoding.default_internal || template.encoding
88
+ end
89
+ end
90
+
91
+ # Returns the string used as the return value of the precompiled method.
92
+ # This method exists so it can be monkeypatched to return modified values.
93
+ def precompiled_method_return_value
94
+ "_erbout"
95
+ end
96
+
97
+ def locals_code(names)
98
+ names = names.keys if Hash === names
99
+
100
+ names.each_with_object('') do |name, code|
101
+ # Can't use || because someone might explicitly pass in false with a symbol
102
+ sym_local = "_haml_locals[#{inspect_obj(name.to_sym)}]"
103
+ str_local = "_haml_locals[#{inspect_obj(name.to_s)}]"
104
+ code << "#{name} = #{sym_local}.nil? ? #{str_local} : #{sym_local};"
105
+ end
106
+ end
107
+
108
+ def inspect_obj(obj)
109
+ case obj
110
+ when String
111
+ %Q!"#{obj.gsub(/[\x00-\x7F]+/) {|s| s.inspect[1...-1]}}"!
112
+ when Symbol
113
+ ":#{inspect_obj(obj.to_s)}"
114
+ else
115
+ obj.inspect
116
+ end
117
+ end
118
+ end
119
+ end
@@ -0,0 +1,28 @@
1
+ module Haml
2
+ # A module to count lines of expected code. This would be faster than actual code generation
3
+ # and counting newlines in it.
4
+ module TempleLineCounter
5
+ class UnexpectedExpression < StandardError; end
6
+
7
+ def self.count_lines(exp)
8
+ type, *args = exp
9
+ case type
10
+ when :multi
11
+ args.map { |a| count_lines(a) }.reduce(:+) || 0
12
+ when :dynamic, :code
13
+ args.first.count("\n")
14
+ when :static
15
+ 0 # It has not real newline "\n" but escaped "\\n".
16
+ when :case
17
+ arg, *cases = args
18
+ arg.count("\n") + cases.map do |cond, e|
19
+ (cond == :else ? 0 : cond.count("\n")) + count_lines(e)
20
+ end.reduce(:+)
21
+ when :escape
22
+ count_lines(args[1])
23
+ else
24
+ raise UnexpectedExpression.new("[HAML BUG] Unexpected Temple expression '#{type}' is given!")
25
+ end
26
+ end
27
+ end
28
+ end
@@ -14,38 +14,6 @@ module Haml
14
14
  module Util
15
15
  extend self
16
16
 
17
- # Computes the powerset of the given array.
18
- # This is the set of all subsets of the array.
19
- #
20
- # @example
21
- # powerset([1, 2, 3]) #=>
22
- # Set[Set[], Set[1], Set[2], Set[3], Set[1, 2], Set[2, 3], Set[1, 3], Set[1, 2, 3]]
23
- # @param arr [Enumerable]
24
- # @return [Set<Set>] The subsets of `arr`
25
- def powerset(arr)
26
- arr.inject([Set.new].to_set) do |powerset, el|
27
- new_powerset = Set.new
28
- powerset.each do |subset|
29
- new_powerset << subset
30
- new_powerset << subset + [el]
31
- end
32
- new_powerset
33
- end
34
- end
35
-
36
- # Returns information about the caller of the previous method.
37
- #
38
- # @param entry [String] An entry in the `#caller` list, or a similarly formatted string
39
- # @return [[String, Fixnum, (String, nil)]] An array containing the filename, line, and method name of the caller.
40
- # The method name may be nil
41
- def caller_info(entry = caller[1])
42
- info = entry.scan(/^(.*?):(-?.*?)(?::.*`(.+)')?$/).first
43
- info[1] = info[1].to_i
44
- # This is added by Rubinius to designate a block, but we don't care about it.
45
- info[2].sub!(/ \{\}\Z/, '') if info[2]
46
- info
47
- end
48
-
49
17
  # Silence all output to STDERR within a block.
50
18
  #
51
19
  # @yield A block in which no output will be printed to STDERR
@@ -71,6 +39,9 @@ module Haml
71
39
  # With older versions of the Rails XSS-safety mechanism,
72
40
  # this destructively modifies the HTML-safety of `text`.
73
41
  #
42
+ # It only works if you are using ActiveSupport or the parameter `text`
43
+ # implements the #html_safe method.
44
+ #
74
45
  # @param text [String, nil]
75
46
  # @return [String, nil] `text`, marked as HTML-safe
76
47
  def html_safe(text)
@@ -81,7 +52,7 @@ module Haml
81
52
  # Checks that the encoding of a string is valid
82
53
  # and cleans up potential encoding gotchas like the UTF-8 BOM.
83
54
  # If it's not, yields an error string describing the invalid character
84
- # and the line on which it occurrs.
55
+ # and the line on which it occurs.
85
56
  #
86
57
  # @param str [String] The string of which to check the encoding
87
58
  # @yield [msg] A block in which an encoding error can be raised.
@@ -163,80 +134,6 @@ MSG
163
134
  end
164
135
  end
165
136
 
166
- ## Static Method Stuff
167
-
168
- # The context in which the ERB for \{#def\_static\_method} will be run.
169
- class StaticConditionalContext
170
- # @param set [#include?] The set of variables that are defined for this context.
171
- def initialize(set)
172
- @set = set
173
- end
174
-
175
- # Checks whether or not a variable is defined for this context.
176
- #
177
- # @param name [Symbol] The name of the variable
178
- # @return [Boolean]
179
- def method_missing(name, *args, &block)
180
- super unless args.empty? && block.nil?
181
- @set.include?(name)
182
- end
183
- end
184
-
185
- # This is used for methods in {Haml::Buffer} that need to be very fast,
186
- # and take a lot of boolean parameters
187
- # that are known at compile-time.
188
- # Instead of passing the parameters in normally,
189
- # a separate method is defined for every possible combination of those parameters;
190
- # these are then called using \{#static\_method\_name}.
191
- #
192
- # To define a static method, an ERB template for the method is provided.
193
- # All conditionals based on the static parameters
194
- # are done as embedded Ruby within this template.
195
- # For example:
196
- #
197
- # def_static_method(Foo, :my_static_method, [:foo, :bar], :baz, :bang, <<RUBY)
198
- # <% if baz && bang %>
199
- # return foo + bar
200
- # <% elsif baz || bang %>
201
- # return foo - bar
202
- # <% else %>
203
- # return 17
204
- # <% end %>
205
- # RUBY
206
- #
207
- # \{#static\_method\_name} can be used to call static methods.
208
- #
209
- # @overload def_static_method(klass, name, args, *vars, erb)
210
- # @param klass [Module] The class on which to define the static method
211
- # @param name [#to_s] The (base) name of the static method
212
- # @param args [Array<Symbol>] The names of the arguments to the defined methods
213
- # (**not** to the ERB template)
214
- # @param vars [Array<Symbol>] The names of the static boolean variables
215
- # to be made available to the ERB template
216
- def def_static_method(klass, name, args, *vars)
217
- erb = vars.pop
218
- info = caller_info
219
- powerset(vars).each do |set|
220
- context = StaticConditionalContext.new(set).instance_eval {binding}
221
- method_content = (defined?(Erubis::TinyEruby) && Erubis::TinyEruby || ERB).new(erb).result(context)
222
-
223
- klass.class_eval(<<METHOD, info[0], info[1])
224
- def #{static_method_name(name, *vars.map {|v| set.include?(v)})}(#{args.join(', ')})
225
- #{method_content}
226
- end
227
- METHOD
228
- end
229
- end
230
-
231
- # Computes the name for a method defined via \{#def\_static\_method}.
232
- #
233
- # @param name [String] The base name of the static method
234
- # @param vars [Array<Boolean>] The static variable assignment
235
- # @return [String] The real name of the static method
236
- def static_method_name(name, *vars)
237
- :"#{name}_#{vars.map {|v| !!v}.join('_')}"
238
- end
239
-
240
137
  # Scans through a string looking for the interoplation-opening `#{`
241
138
  # and, when it's found, yields the scanner to the calling code
242
139
  # so it can handle it properly.
@@ -249,7 +146,7 @@ METHOD
249
146
  # @return [String] The text remaining in the scanner after all `#{`s have been processed
250
147
  def handle_interpolation(str)
251
148
  scan = StringScanner.new(str)
252
- yield scan while scan.scan(/(.*?)(\\*)\#\{/)
149
+ yield scan while scan.scan(/(.*?)(\\*)#([\{@$])/)
253
150
  scan.rest
254
151
  end
255
152
 
@@ -298,20 +195,28 @@ METHOD
298
195
  end
299
196
 
300
197
  def contains_interpolation?(str)
301
- str.include?('#{')
198
+ /#[\{$@]/ === str
302
199
  end
303
200
 
304
201
  def unescape_interpolation(str, escape_html = nil)
305
202
  res = ''
306
203
  rest = Haml::Util.handle_interpolation str.dump do |scan|
307
204
  escapes = (scan[2].size - 1) / 2
205
+ char = scan[3] # '{', '@' or '$'
308
206
  res << scan.matched[0...-3 - escapes]
309
207
  if escapes % 2 == 1
310
- res << '#{'
208
+ res << "\##{char}"
311
209
  else
312
- content = eval('"' + balance(scan, ?{, ?}, 1)[0][0...-1] + '"')
210
+ interpolated = if char == '{'
211
+ balance(scan, ?{, ?}, 1)[0][0...-1]
212
+ else
213
+ scan.scan(/\w+/)
214
+ end
215
+ content = eval('"' + interpolated + '"')
216
+ content.prepend(char) if char == '@' || char == '$'
313
217
  content = "Haml::Helpers.html_escape((#{content}))" if escape_html
314
- res << '#{' + content + "}"# Use eval to get rid of string escapes
218
+
219
+ res << "\#{#{content}}"
315
220
  end
316
221
  end
317
222
  res + rest
@@ -1,3 +1,3 @@
1
1
  module Haml
2
- VERSION = "4.1.0.beta.1"
2
+ VERSION = "5.0.0.beta.2"
3
3
  end
@@ -0,0 +1,105 @@
1
+ require 'test_helper'
2
+
3
+ class AttributeParserTeset < Haml::TestCase
4
+ describe '.parse' do
5
+ def assert_parse(expected, haml)
6
+ actual = Haml::AttributeParser.parse(haml)
7
+ if expected.nil?
8
+ assert_nil actual
9
+ else
10
+ assert_equal expected, actual
11
+ end
12
+ end
13
+
14
+ if Haml::AttributeParser.available?
15
+ it { assert_parse({}, '') }
16
+ it { assert_parse({}, '{}') }
17
+
18
+ describe 'invalid hash' do
19
+ it { assert_parse(nil, ' hash ') }
20
+ it { assert_parse(nil, 'hash, foo: bar') }
21
+ it { assert_parse(nil, ' {hash} ') }
22
+ it { assert_parse(nil, ' { hash, foo: bar } ') }
23
+ end
24
+
25
+ describe 'dynamic key' do
26
+ it { assert_parse(nil, 'foo => bar') }
27
+ it { assert_parse(nil, '[] => bar') }
28
+ it { assert_parse(nil, '[1,2,3] => bar') }
29
+ end
30
+
31
+ describe 'foo: bar' do
32
+ it { assert_parse({ '_' => '1' }, '_:1,') }
33
+ it { assert_parse({ 'foo' => 'bar' }, ' foo: bar ') }
34
+ it { assert_parse({ 'a' => 'b', 'c' => ':d' }, 'a: b, c: :d') }
35
+ it { assert_parse({ 'a' => '[]', 'c' => '"d"' }, 'a: [], c: "d"') }
36
+ it { assert_parse({ '_' => '1' }, ' { _:1, } ') }
37
+ it { assert_parse({ 'foo' => 'bar' }, ' { foo: bar } ') }
38
+ it { assert_parse({ 'a' => 'b', 'c' => ':d' }, ' { a: b, c: :d } ') }
39
+ it { assert_parse({ 'a' => '[]', 'c' => '"d"' }, ' { a: [], c: "d" } ') }
40
+ end
41
+
42
+ describe ':foo => bar' do
43
+ it { assert_parse({ 'foo' => ':bar' }, ' :foo => :bar ') }
44
+ it { assert_parse({ '_' => '"foo"' }, ':_=>"foo"') }
45
+ it { assert_parse({ 'a' => '[]', 'c' => '""', 'b' => '"#{3}"' }, ':a => [], c: "", :b => "#{3}"') }
46
+ it { assert_parse({ 'foo' => ':bar' }, ' { :foo => :bar } ') }
47
+ it { assert_parse({ '_' => '"foo"' }, ' { :_=>"foo" } ') }
48
+ it { assert_parse({ 'a' => '[]', 'c' => '""', 'b' => '"#{3}"' }, ' { :a => [], c: "", :b => "#{3}" } ') }
49
+ it { assert_parse(nil, ':"f#{o}o" => bar') }
50
+ it { assert_parse(nil, ':"#{f}oo" => bar') }
51
+ it { assert_parse(nil, ':"#{foo}" => bar') }
52
+ end
53
+
54
+ describe '"foo" => bar' do
55
+ it { assert_parse({ 'foo' => '[1]' }, '"foo"=>[1]') }
56
+ it { assert_parse({ 'foo' => 'nya' }, " 'foo' => nya ") }
57
+ it { assert_parse({ 'foo' => 'bar' }, '%q[foo] => bar ') }
58
+ it { assert_parse({ 'foo' => '[1]' }, ' { "foo"=>[1] } ') }
59
+ it { assert_parse({ 'foo' => 'nya' }, " { 'foo' => nya } ") }
60
+ it { assert_parse({ 'foo' => 'bar' }, ' { %q[foo] => bar } ') }
61
+ it { assert_parse(nil, '"f#{o}o" => bar') }
62
+ it { assert_parse(nil, '"#{f}oo" => bar') }
63
+ it { assert_parse(nil, '"#{foo}" => bar') }
64
+ it { assert_parse({ 'f#{o}o' => 'bar' }, '%q[f#{o}o] => bar ') }
65
+ it { assert_parse({ 'f#{o}o' => 'bar' }, ' { %q[f#{o}o] => bar, } ') }
66
+ it { assert_parse(nil, '%Q[f#{o}o] => bar ') }
67
+ end
68
+
69
+ if RUBY_VERSION >= '2.2.0'
70
+ describe '"foo": bar' do
71
+ it { assert_parse({ 'foo' => '()' }, '"foo":()') }
72
+ it { assert_parse({ 'foo' => 'nya' }, " 'foo': nya ") }
73
+ it { assert_parse({ 'foo' => '()' }, ' { "foo":() , }') }
74
+ it { assert_parse({ 'foo' => 'nya' }, " { 'foo': nya , }") }
75
+ it { assert_parse(nil, '"f#{o}o": bar') }
76
+ it { assert_parse(nil, '"#{f}oo": bar') }
77
+ it { assert_parse(nil, '"#{foo}": bar') }
78
+ end
79
+ end
80
+
81
+ describe 'nested array' do
82
+ it { assert_parse({ 'foo' => '[1,2,]' }, 'foo: [1,2,],') }
83
+ it { assert_parse({ 'foo' => '[1,2,[3,4],5]' }, 'foo: [1,2,[3,4],5],') }
84
+ it { assert_parse({ 'foo' => '[1,2,[3,4],5]', 'bar' => '[[1,2],]'}, 'foo: [1,2,[3,4],5],bar: [[1,2],],') }
85
+ it { assert_parse({ 'foo' => '[1,2,]' }, ' { foo: [1,2,], } ') }
86
+ it { assert_parse({ 'foo' => '[1,2,[3,4],5]' }, ' { foo: [1,2,[3,4],5], } ') }
87
+ it { assert_parse({ 'foo' => '[1,2,[3,4],5]', 'bar' => '[[1,2],]'}, ' { foo: [1,2,[3,4],5],bar: [[1,2],], } ') }
88
+ end
89
+
90
+ describe 'nested hash' do
91
+ it { assert_parse({ 'foo' => '{ }', 'bar' => '{}' }, 'foo: { }, bar: {}') }
92
+ it { assert_parse({ 'foo' => '{ bar: baz, hoge: fuga, }' }, 'foo: { bar: baz, hoge: fuga, }, ') }
93
+ it { assert_parse({ 'data' => '{ confirm: true, disable: false }', 'hello' => '{ world: foo, }' }, 'data: { confirm: true, disable: false }, :hello => { world: foo, },') }
94
+ it { assert_parse({ 'foo' => '{ }', 'bar' => '{}' }, ' { foo: { }, bar: {} } ') }
95
+ it { assert_parse({ 'foo' => '{ bar: baz, hoge: fuga, }' }, ' { foo: { bar: baz, hoge: fuga, }, } ') }
96
+ it { assert_parse({ 'data' => '{ confirm: true, disable: false }', 'hello' => '{ world: foo, }' }, ' { data: { confirm: true, disable: false }, :hello => { world: foo, }, } ') }
97
+ end
98
+
99
+ describe 'nested method' do
100
+ it { assert_parse({ 'foo' => 'bar(a, b)', 'hoge' => 'piyo(a, b,)' }, 'foo: bar(a, b), hoge: piyo(a, b,),') }
101
+ it { assert_parse({ 'foo' => 'bar(a, b)', 'hoge' => 'piyo(a, b,)' }, ' { foo: bar(a, b), hoge: piyo(a, b,), } ') }
102
+ end
103
+ end
104
+ end
105
+ end