haml 4.0.7 → 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 (89) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +1 -1
  3. data/CHANGELOG.md +42 -4
  4. data/FAQ.md +4 -14
  5. data/MIT-LICENSE +1 -1
  6. data/README.md +85 -42
  7. data/REFERENCE.md +108 -57
  8. data/Rakefile +46 -54
  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 +22 -132
  13. data/lib/haml/compiler.rb +87 -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 +18 -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 +36 -58
  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 +4 -1
  25. data/lib/haml/helpers/xss_mods.rb +18 -12
  26. data/lib/haml/helpers.rb +133 -90
  27. data/lib/haml/options.rb +38 -47
  28. data/lib/haml/parser.rb +278 -216
  29. data/lib/haml/{template/plugin.rb → plugin.rb} +8 -15
  30. data/lib/haml/railtie.rb +21 -12
  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 +1 -0
  39. data/test/attribute_parser_test.rb +101 -0
  40. data/test/engine_test.rb +287 -176
  41. data/test/filters_test.rb +32 -19
  42. data/test/gemfiles/Gemfile.rails-4.0.x +9 -3
  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 +224 -112
  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 +77 -76
  67. data/test/template_test.rb +24 -56
  68. data/test/template_test_helper.rb +38 -0
  69. data/test/templates/bemit.haml +3 -0
  70. data/test/templates/just_stuff.haml +1 -0
  71. data/test/templates/standard_ugly.haml +1 -0
  72. data/test/templates/with_bom.haml +1 -0
  73. data/test/temple_line_counter_test.rb +40 -0
  74. data/test/test_helper.rb +26 -8
  75. data/test/util_test.rb +6 -47
  76. metadata +53 -43
  77. data/test/gemfiles/Gemfile.rails-3.0.x +0 -5
  78. data/test/gemfiles/Gemfile.rails-3.1.x +0 -6
  79. data/test/gemfiles/Gemfile.rails-3.2.x +0 -5
  80. data/test/haml-spec/LICENSE +0 -14
  81. data/test/haml-spec/README.md +0 -106
  82. data/test/haml-spec/lua_haml_spec.lua +0 -38
  83. data/test/haml-spec/perl_haml_test.pl +0 -81
  84. data/test/haml-spec/ruby_haml_test.rb +0 -23
  85. data/test/haml-spec/tests.json +0 -660
  86. data/test/templates/_av_partial_1_ugly.haml +0 -9
  87. data/test/templates/_av_partial_2_ugly.haml +0 -5
  88. data/test/templates/action_view_ugly.haml +0 -47
  89. data/test/templates/standard_ugly.haml +0 -43
data/lib/haml/util.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: false
2
+
1
3
  begin
2
4
  require 'erubis/tiny'
3
5
  rescue LoadError
@@ -12,38 +14,6 @@ module Haml
12
14
  module Util
13
15
  extend self
14
16
 
15
- # Computes the powerset of the given array.
16
- # This is the set of all subsets of the array.
17
- #
18
- # @example
19
- # powerset([1, 2, 3]) #=>
20
- # Set[Set[], Set[1], Set[2], Set[3], Set[1, 2], Set[2, 3], Set[1, 3], Set[1, 2, 3]]
21
- # @param arr [Enumerable]
22
- # @return [Set<Set>] The subsets of `arr`
23
- def powerset(arr)
24
- arr.inject([Set.new].to_set) do |powerset, el|
25
- new_powerset = Set.new
26
- powerset.each do |subset|
27
- new_powerset << subset
28
- new_powerset << subset + [el]
29
- end
30
- new_powerset
31
- end
32
- end
33
-
34
- # Returns information about the caller of the previous method.
35
- #
36
- # @param entry [String] An entry in the `#caller` list, or a similarly formatted string
37
- # @return [[String, Fixnum, (String, nil)]] An array containing the filename, line, and method name of the caller.
38
- # The method name may be nil
39
- def caller_info(entry = caller[1])
40
- info = entry.scan(/^(.*?):(-?.*?)(?::.*`(.+)')?$/).first
41
- info[1] = info[1].to_i
42
- # This is added by Rubinius to designate a block, but we don't care about it.
43
- info[2].sub!(/ \{\}\Z/, '') if info[2]
44
- info
45
- end
46
-
47
17
  # Silence all output to STDERR within a block.
48
18
  #
49
19
  # @yield A block in which no output will be printed to STDERR
@@ -54,19 +24,6 @@ module Haml
54
24
  $stderr = the_real_stderr
55
25
  end
56
26
 
57
- # Returns an ActionView::Template* class.
58
- # In pre-3.0 versions of Rails, most of these classes
59
- # were of the form `ActionView::TemplateFoo`,
60
- # while afterwards they were of the form `ActionView;:Template::Foo`.
61
- #
62
- # @param name [#to_s] The name of the class to get.
63
- # For example, `:Error` will return `ActionView::TemplateError`
64
- # or `ActionView::Template::Error`.
65
- def av_template_class(name)
66
- return ActionView.const_get("Template#{name}") if ActionView.const_defined?("Template#{name}")
67
- return ActionView::Template.const_get(name.to_s)
68
- end
69
-
70
27
  ## Rails XSS Safety
71
28
 
72
29
  # Whether or not ActionView's XSS protection is available and enabled,
@@ -82,6 +39,9 @@ module Haml
82
39
  # With older versions of the Rails XSS-safety mechanism,
83
40
  # this destructively modifies the HTML-safety of `text`.
84
41
  #
42
+ # It only works if you are using ActiveSupport or the parameter `text`
43
+ # implements the #html_safe method.
44
+ #
85
45
  # @param text [String, nil]
86
46
  # @return [String, nil] `text`, marked as HTML-safe
87
47
  def html_safe(text)
@@ -89,174 +49,89 @@ module Haml
89
49
  text.html_safe
90
50
  end
91
51
 
92
- # Checks that the encoding of a string is valid in Ruby 1.9
52
+ # Checks that the encoding of a string is valid
93
53
  # and cleans up potential encoding gotchas like the UTF-8 BOM.
94
54
  # If it's not, yields an error string describing the invalid character
95
- # and the line on which it occurrs.
55
+ # and the line on which it occurs.
96
56
  #
97
57
  # @param str [String] The string of which to check the encoding
98
58
  # @yield [msg] A block in which an encoding error can be raised.
99
59
  # Only yields if there is an encoding error
100
60
  # @yieldparam msg [String] The error message to be raised
101
61
  # @return [String] `str`, potentially with encoding gotchas like BOMs removed
102
- if RUBY_VERSION < "1.9"
103
- def check_encoding(str)
104
- str.gsub(/\A\xEF\xBB\xBF/, '') # Get rid of the UTF-8 BOM
105
- end
106
- else
107
-
108
- def check_encoding(str)
109
- if str.valid_encoding?
110
- # Get rid of the Unicode BOM if possible
111
- if str.encoding.name =~ /^UTF-(8|16|32)(BE|LE)?$/
112
- return str.gsub(Regexp.new("\\A\uFEFF".encode(str.encoding.name)), '')
113
- else
114
- return str
115
- end
62
+ def check_encoding(str)
63
+ if str.valid_encoding?
64
+ # Get rid of the Unicode BOM if possible
65
+ # Shortcut for UTF-8 which might be the majority case
66
+ if str.encoding == Encoding::UTF_8
67
+ return str.gsub(/\A\uFEFF/, '')
68
+ elsif str.encoding.name =~ /^UTF-(16|32)(BE|LE)?$/
69
+ return str.gsub(Regexp.new("\\A\uFEFF".encode(str.encoding)), '')
70
+ else
71
+ return str
116
72
  end
73
+ end
117
74
 
118
- encoding = str.encoding
119
- newlines = Regexp.new("\r\n|\r|\n".encode(encoding).force_encoding("binary"))
120
- str.force_encoding("binary").split(newlines).each_with_index do |line, i|
121
- begin
122
- line.encode(encoding)
123
- rescue Encoding::UndefinedConversionError => e
124
- yield <<MSG.rstrip, i + 1
75
+ encoding = str.encoding
76
+ newlines = Regexp.new("\r\n|\r|\n".encode(encoding).force_encoding(Encoding::ASCII_8BIT))
77
+ str.force_encoding(Encoding::ASCII_8BIT).split(newlines).each_with_index do |line, i|
78
+ begin
79
+ line.encode(encoding)
80
+ rescue Encoding::UndefinedConversionError => e
81
+ yield <<MSG.rstrip, i + 1
125
82
  Invalid #{encoding.name} character #{e.error_char.dump}
126
83
  MSG
127
- end
128
84
  end
129
- return str
130
85
  end
86
+ return str
131
87
  end
132
88
 
133
- if RUBY_VERSION < "1.9"
134
- # Like {\#check\_encoding}, but also checks for a Ruby-style `-# coding:` comment
135
- # at the beginning of the template and uses that encoding if it exists.
136
- #
137
- # The Haml encoding rules are simple.
138
- # If a `-# coding:` comment exists,
139
- # we assume that that's the original encoding of the document.
140
- # Otherwise, we use whatever encoding Ruby has.
141
- #
142
- # Haml uses the same rules for parsing coding comments as Ruby.
143
- # This means that it can understand Emacs-style comments
144
- # (e.g. `-*- encoding: "utf-8" -*-`),
145
- # and also that it cannot understand non-ASCII-compatible encodings
146
- # such as `UTF-16` and `UTF-32`.
147
- #
148
- # @param str [String] The Haml template of which to check the encoding
149
- # @yield [msg] A block in which an encoding error can be raised.
150
- # Only yields if there is an encoding error
151
- # @yieldparam msg [String] The error message to be raised
152
- # @return [String] The original string encoded properly
153
- # @raise [ArgumentError] if the document declares an unknown encoding
154
- def check_haml_encoding(str, &block)
155
- check_encoding(str, &block)
156
- end
157
- else
158
- def check_haml_encoding(str, &block)
159
- str = str.dup if str.frozen?
160
-
161
- bom, encoding = parse_haml_magic_comment(str)
162
- if encoding; str.force_encoding(encoding)
163
- elsif bom; str.force_encoding("UTF-8")
164
- end
165
-
166
- return check_encoding(str, &block)
167
- end
168
- end
169
-
170
- if RUBY_VERSION < "1.9.2"
171
- def inspect_obj(obj)
172
- return obj.inspect
173
- end
174
- else
175
- # Like `Object#inspect`, but preserves non-ASCII characters rather than escaping them under Ruby 1.9.2.
176
- # This is necessary so that the precompiled Haml template can be `#encode`d into `@options[:encoding]`
177
- # before being evaluated.
178
- #
179
- # @param obj {Object}
180
- # @return {String}
181
- def inspect_obj(obj)
182
- return ':' + inspect_obj(obj.to_s) if obj.is_a?(Symbol)
183
- return obj.inspect unless obj.is_a?(String)
184
- '"' + obj.gsub(/[\x00-\x7F]+/) {|s| s.inspect[1...-1]} + '"'
185
- end
186
- end
187
-
188
- ## Static Method Stuff
189
-
190
- # The context in which the ERB for \{#def\_static\_method} will be run.
191
- class StaticConditionalContext
192
- # @param set [#include?] The set of variables that are defined for this context.
193
- def initialize(set)
194
- @set = set
195
- end
196
-
197
- # Checks whether or not a variable is defined for this context.
198
- #
199
- # @param name [Symbol] The name of the variable
200
- # @return [Boolean]
201
- def method_missing(name, *args, &block)
202
- super unless args.empty? && block.nil?
203
- @set.include?(name)
204
- end
205
- end
206
-
207
- # This is used for methods in {Haml::Buffer} that need to be very fast,
208
- # and take a lot of boolean parameters
209
- # that are known at compile-time.
210
- # Instead of passing the parameters in normally,
211
- # a separate method is defined for every possible combination of those parameters;
212
- # these are then called using \{#static\_method\_name}.
89
+ # Like {\#check\_encoding}, but also checks for a Ruby-style `-# coding:` comment
90
+ # at the beginning of the template and uses that encoding if it exists.
213
91
  #
214
- # To define a static method, an ERB template for the method is provided.
215
- # All conditionals based on the static parameters
216
- # are done as embedded Ruby within this template.
217
- # For example:
218
- #
219
- # def_static_method(Foo, :my_static_method, [:foo, :bar], :baz, :bang, <<RUBY)
220
- # <% if baz && bang %>
221
- # return foo + bar
222
- # <% elsif baz || bang %>
223
- # return foo - bar
224
- # <% else %>
225
- # return 17
226
- # <% end %>
227
- # RUBY
92
+ # The Haml encoding rules are simple.
93
+ # If a `-# coding:` comment exists,
94
+ # we assume that that's the original encoding of the document.
95
+ # Otherwise, we use whatever encoding Ruby has.
228
96
  #
229
- # \{#static\_method\_name} can be used to call static methods.
97
+ # Haml uses the same rules for parsing coding comments as Ruby.
98
+ # This means that it can understand Emacs-style comments
99
+ # (e.g. `-*- encoding: "utf-8" -*-`),
100
+ # and also that it cannot understand non-ASCII-compatible encodings
101
+ # such as `UTF-16` and `UTF-32`.
230
102
  #
231
- # @overload def_static_method(klass, name, args, *vars, erb)
232
- # @param klass [Module] The class on which to define the static method
233
- # @param name [#to_s] The (base) name of the static method
234
- # @param args [Array<Symbol>] The names of the arguments to the defined methods
235
- # (**not** to the ERB template)
236
- # @param vars [Array<Symbol>] The names of the static boolean variables
237
- # to be made available to the ERB template
238
- def def_static_method(klass, name, args, *vars)
239
- erb = vars.pop
240
- info = caller_info
241
- powerset(vars).each do |set|
242
- context = StaticConditionalContext.new(set).instance_eval {binding}
243
- method_content = (defined?(Erubis::TinyEruby) && Erubis::TinyEruby || ERB).new(erb).result(context)
103
+ # @param str [String] The Haml template of which to check the encoding
104
+ # @yield [msg] A block in which an encoding error can be raised.
105
+ # Only yields if there is an encoding error
106
+ # @yieldparam msg [String] The error message to be raised
107
+ # @return [String] The original string encoded properly
108
+ # @raise [ArgumentError] if the document declares an unknown encoding
109
+ def check_haml_encoding(str, &block)
110
+ str = str.dup if str.frozen?
244
111
 
245
- klass.class_eval(<<METHOD, info[0], info[1])
246
- def #{static_method_name(name, *vars.map {|v| set.include?(v)})}(#{args.join(', ')})
247
- #{method_content}
248
- end
249
- METHOD
112
+ bom, encoding = parse_haml_magic_comment(str)
113
+ if encoding; str.force_encoding(encoding)
114
+ elsif bom; str.force_encoding(Encoding::UTF_8)
250
115
  end
116
+
117
+ return check_encoding(str, &block)
251
118
  end
252
119
 
253
- # Computes the name for a method defined via \{#def\_static\_method}.
120
+ # Like `Object#inspect`, but preserves non-ASCII characters rather than escaping them.
121
+ # This is necessary so that the precompiled Haml template can be `#encode`d into `@options[:encoding]`
122
+ # before being evaluated.
254
123
  #
255
- # @param name [String] The base name of the static method
256
- # @param vars [Array<Boolean>] The static variable assignment
257
- # @return [String] The real name of the static method
258
- def static_method_name(name, *vars)
259
- :"#{name}_#{vars.map {|v| !!v}.join('_')}"
124
+ # @param obj {Object}
125
+ # @return {String}
126
+ def inspect_obj(obj)
127
+ case obj
128
+ when String
129
+ %Q!"#{obj.gsub(/[\x00-\x7F]+/) {|s| s.inspect[1...-1]}}"!
130
+ when Symbol
131
+ ":#{inspect_obj(obj.to_s)}"
132
+ else
133
+ obj.inspect
134
+ end
260
135
  end
261
136
 
262
137
  # Scans through a string looking for the interoplation-opening `#{`
@@ -271,7 +146,7 @@ METHOD
271
146
  # @return [String] The text remaining in the scanner after all `#{`s have been processed
272
147
  def handle_interpolation(str)
273
148
  scan = StringScanner.new(str)
274
- yield scan while scan.scan(/(.*?)(\\*)\#\{/)
149
+ yield scan while scan.scan(/(.*?)(\\*)#([\{@$])/)
275
150
  scan.rest
276
151
  end
277
152
 
@@ -283,10 +158,8 @@ METHOD
283
158
  # from to
284
159
  #
285
160
  # @param scanner [StringScanner] The string scanner to move
286
- # @param start [Character] The character opening the balanced pair.
287
- # A `Fixnum` in 1.8, a `String` in 1.9
288
- # @param finish [Character] The character closing the balanced pair.
289
- # A `Fixnum` in 1.8, a `String` in 1.9
161
+ # @param start [String] The character opening the balanced pair.
162
+ # @param finish [String] The character closing the balanced pair.
290
163
  # @param count [Fixnum] The number of opening characters matched
291
164
  # before calling this method
292
165
  # @return [(String, String)] The string matched within the balanced pair
@@ -322,20 +195,28 @@ METHOD
322
195
  end
323
196
 
324
197
  def contains_interpolation?(str)
325
- str.include?('#{')
198
+ /#[\{$@]/ === str
326
199
  end
327
200
 
328
201
  def unescape_interpolation(str, escape_html = nil)
329
202
  res = ''
330
203
  rest = Haml::Util.handle_interpolation str.dump do |scan|
331
204
  escapes = (scan[2].size - 1) / 2
205
+ char = scan[3] # '{', '@' or '$'
332
206
  res << scan.matched[0...-3 - escapes]
333
207
  if escapes % 2 == 1
334
- res << '#{'
208
+ res << "\##{char}"
335
209
  else
336
- 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 == '$'
337
217
  content = "Haml::Helpers.html_escape((#{content}))" if escape_html
338
- res << '#{' + content + "}"# Use eval to get rid of string escapes
218
+
219
+ res << "\#{#{content}}"
339
220
  end
340
221
  end
341
222
  res + rest
@@ -350,7 +231,7 @@ METHOD
350
231
  # Whether the document begins with a UTF-8 BOM,
351
232
  # and the declared encoding of the document (or nil if none is declared)
352
233
  def parse_haml_magic_comment(str)
353
- scanner = StringScanner.new(str.dup.force_encoding("BINARY"))
234
+ scanner = StringScanner.new(str.dup.force_encoding(Encoding::ASCII_8BIT))
354
235
  bom = scanner.scan(/\xEF\xBB\xBF/n)
355
236
  return bom unless scanner.scan(/-\s*#\s*/n)
356
237
  if coding = try_parse_haml_emacs_magic_comment(scanner)
data/lib/haml/version.rb CHANGED
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Haml
2
- VERSION = '4.0.7'
3
+ VERSION = "5.0.0"
3
4
  end
data/lib/haml.rb CHANGED
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require 'haml/version'
2
3
 
3
4
  # The module that contains everything Haml-related:
@@ -0,0 +1,101 @@
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(nil, '') }
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
+ it { assert_parse(nil, '{}.merge({})') }
24
+ end
25
+
26
+ describe 'non single hash' do
27
+ it { assert_parse(nil, '{ a: 0 };{}') }
28
+ it { assert_parse(nil, '{ a: 0 }[nil] = {}') }
29
+ end
30
+
31
+ describe 'dynamic key' do
32
+ it { assert_parse(nil, '{foo => bar}') }
33
+ it { assert_parse(nil, '{[] => bar}') }
34
+ it { assert_parse(nil, '{[1,2,3] => bar}') }
35
+ end
36
+
37
+ describe 'foo: bar' do
38
+ it { assert_parse({ '_' => '1' }, '{_:1,}') }
39
+ it { assert_parse({ 'foo' => 'bar' }, '{ foo: bar }') }
40
+ it { assert_parse({ 'a' => 'b', 'c' => ':d' }, '{a: b, c: :d}') }
41
+ it { assert_parse({ 'a' => '[]', 'c' => '"d"' }, '{a: [], c: "d"}') }
42
+ end
43
+
44
+ describe ':foo => bar' do
45
+ it { assert_parse({ 'foo' => ':bar' }, '{ :foo => :bar }') }
46
+ it { assert_parse({ '_' => '"foo"' }, '{:_=>"foo"}') }
47
+ it { assert_parse({ 'a' => '[]', 'c' => '""', 'b' => '"#{3}"' }, '{:a => [], c: "", :b => "#{3}"}') }
48
+ it { assert_parse(nil, '{:"f#{o}o" => bar}') }
49
+ it { assert_parse(nil, '{:"#{f}oo" => bar}') }
50
+ it { assert_parse(nil, '{:"#{foo}" => bar}') }
51
+ end
52
+
53
+ describe '"foo" => bar' do
54
+ it { assert_parse({ 'foo' => '[1]' }, '{"foo"=>[1]}') }
55
+ it { assert_parse({ 'foo' => 'nya' }, "{ 'foo' => nya }") }
56
+ it { assert_parse({ 'foo' => 'bar' }, '{%q[foo] => bar }') }
57
+ it { assert_parse({ 'foo' => '[1]' }, ' { "foo"=>[1] } ') }
58
+ it { assert_parse({ 'foo' => 'nya' }, " { 'foo' => nya } ") }
59
+ it { assert_parse({ 'foo' => 'bar' }, ' { %q[foo] => bar } ') }
60
+ it { assert_parse(nil, '{"f#{o}o" => bar}') }
61
+ it { assert_parse(nil, '{"#{f}oo" => bar}') }
62
+ it { assert_parse(nil, '{"#{foo}" => bar}') }
63
+ it { assert_parse({ 'f#{o}o' => 'bar' }, '{ %q[f#{o}o] => bar }') }
64
+ it { assert_parse({ 'f#{o}o' => 'bar' }, '{ %q[f#{o}o] => bar, }') }
65
+ it { assert_parse(nil, '%Q[f#{o}o] => bar ') }
66
+ end
67
+
68
+ describe 'multi lines' do
69
+ it { assert_parse({ 'a' => 'b', 'c' => 'd' }, "{a: b,\nc: d}") }
70
+ end
71
+
72
+ if RUBY_VERSION >= '2.2.0'
73
+ describe '"foo": bar' do
74
+ it { assert_parse({ 'foo' => '()' }, '{"foo":()}') }
75
+ it { assert_parse({ 'foo' => 'nya' }, " {'foo': nya} ") }
76
+ it { assert_parse({ 'foo' => '()' }, ' { "foo":() , }') }
77
+ it { assert_parse({ 'foo' => 'nya' }, " { 'foo': nya , }") }
78
+ it { assert_parse(nil, '{"f#{o}o": bar}') }
79
+ it { assert_parse(nil, '{"#{f}oo": bar}') }
80
+ it { assert_parse(nil, '{"#{foo}": bar}') }
81
+ end
82
+ end
83
+
84
+ describe 'nested array' do
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
+ end
95
+
96
+ describe 'nested method' do
97
+ it { assert_parse({ 'foo' => 'bar(a, b)', 'hoge' => 'piyo(a, b,)' }, '{ foo: bar(a, b), hoge: piyo(a, b,), }') }
98
+ end
99
+ end
100
+ end
101
+ end