unparser 0.1.5 → 0.1.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (96) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +38 -2
  3. data/.travis.yml +3 -6
  4. data/Changelog.md +7 -0
  5. data/Gemfile +1 -0
  6. data/Gemfile.devtools +22 -17
  7. data/README.md +3 -4
  8. data/TODO +3 -2
  9. data/bin/unparser +10 -0
  10. data/circle.yml +2 -0
  11. data/config/flay.yml +1 -1
  12. data/config/flog.yml +1 -1
  13. data/config/reek.yml +10 -0
  14. data/config/rubocop.yml +9 -17
  15. data/lib/unparser.rb +8 -1
  16. data/lib/unparser/buffer.rb +2 -0
  17. data/lib/unparser/cli.rb +113 -0
  18. data/lib/unparser/cli/differ.rb +30 -0
  19. data/lib/unparser/cli/preprocessor.rb +196 -0
  20. data/lib/unparser/cli/source.rb +118 -0
  21. data/lib/unparser/comments.rb +64 -23
  22. data/lib/unparser/constants.rb +19 -7
  23. data/lib/unparser/emitter.rb +23 -25
  24. data/lib/unparser/emitter/alias.rb +2 -0
  25. data/lib/unparser/emitter/argument.rb +2 -0
  26. data/lib/unparser/emitter/assignment.rb +3 -1
  27. data/lib/unparser/emitter/begin.rb +3 -6
  28. data/lib/unparser/emitter/binary.rb +2 -0
  29. data/lib/unparser/emitter/block.rb +2 -0
  30. data/lib/unparser/emitter/break.rb +4 -5
  31. data/lib/unparser/emitter/case.rb +2 -0
  32. data/lib/unparser/emitter/cbase.rb +2 -0
  33. data/lib/unparser/emitter/class.rb +4 -3
  34. data/lib/unparser/emitter/def.rb +2 -0
  35. data/lib/unparser/emitter/defined.rb +2 -0
  36. data/lib/unparser/emitter/empty.rb +2 -0
  37. data/lib/unparser/emitter/ensure.rb +2 -0
  38. data/lib/unparser/emitter/flipflop.rb +2 -0
  39. data/lib/unparser/emitter/for.rb +2 -0
  40. data/lib/unparser/emitter/hookexe.rb +2 -0
  41. data/lib/unparser/emitter/if.rb +2 -0
  42. data/lib/unparser/emitter/literal.rb +2 -0
  43. data/lib/unparser/emitter/literal/array.rb +33 -0
  44. data/lib/unparser/emitter/literal/dynamic.rb +21 -1
  45. data/lib/unparser/emitter/literal/dynamic_body.rb +9 -5
  46. data/lib/unparser/emitter/literal/execute_string.rb +2 -0
  47. data/lib/unparser/emitter/literal/hash.rb +136 -0
  48. data/lib/unparser/emitter/literal/primitive.rb +4 -2
  49. data/lib/unparser/emitter/literal/range.rb +2 -0
  50. data/lib/unparser/emitter/literal/regexp.rb +4 -2
  51. data/lib/unparser/emitter/literal/singleton.rb +2 -0
  52. data/lib/unparser/emitter/match.rb +2 -0
  53. data/lib/unparser/emitter/module.rb +2 -3
  54. data/lib/unparser/emitter/next.rb +2 -0
  55. data/lib/unparser/emitter/op_assign.rb +3 -1
  56. data/lib/unparser/emitter/redo.rb +2 -0
  57. data/lib/unparser/emitter/repetition.rb +2 -0
  58. data/lib/unparser/emitter/resbody.rb +2 -0
  59. data/lib/unparser/emitter/rescue.rb +2 -0
  60. data/lib/unparser/emitter/retry.rb +2 -0
  61. data/lib/unparser/emitter/return.rb +19 -4
  62. data/lib/unparser/emitter/root.rb +13 -0
  63. data/lib/unparser/emitter/send.rb +26 -22
  64. data/lib/unparser/emitter/send/arguments.rb +46 -0
  65. data/lib/unparser/emitter/send/attribute_assignment.rb +35 -0
  66. data/lib/unparser/emitter/send/binary.rb +2 -0
  67. data/lib/unparser/emitter/send/index.rb +2 -0
  68. data/lib/unparser/emitter/send/regular.rb +4 -2
  69. data/lib/unparser/emitter/send/unary.rb +3 -1
  70. data/lib/unparser/emitter/splat.rb +2 -0
  71. data/lib/unparser/emitter/super.rb +2 -0
  72. data/lib/unparser/emitter/undef.rb +2 -0
  73. data/lib/unparser/emitter/variable.rb +2 -0
  74. data/lib/unparser/emitter/yield.rb +2 -0
  75. data/lib/unparser/finalize.rb +2 -0
  76. data/lib/unparser/node_helpers.rb +19 -0
  77. data/spec/spec_helper.rb +10 -0
  78. data/spec/unit/unparser/buffer/append_spec.rb +2 -0
  79. data/spec/unit/unparser/buffer/append_without_prefix_spec.rb +2 -0
  80. data/spec/unit/unparser/buffer/capture_content_spec.rb +2 -0
  81. data/spec/unit/unparser/buffer/content_spec.rb +3 -1
  82. data/spec/unit/unparser/buffer/fresh_line_spec.rb +2 -0
  83. data/spec/unit/unparser/buffer/indent_spec.rb +3 -1
  84. data/spec/unit/unparser/buffer/nl_spec.rb +2 -0
  85. data/spec/unit/unparser/buffer/unindent_spec.rb +2 -0
  86. data/spec/unit/unparser/comments/consume_spec.rb +2 -1
  87. data/spec/unit/unparser/comments/take_all_spec.rb +2 -1
  88. data/spec/unit/unparser/comments/take_before_spec.rb +6 -5
  89. data/spec/unit/unparser/comments/take_eol_comments_spec.rb +2 -1
  90. data/spec/unit/unparser/emitter/class_methods/handle_spec.rb +2 -0
  91. data/spec/unit/unparser_spec.rb +110 -57
  92. data/unparser.gemspec +5 -4
  93. metadata +32 -12
  94. data/bin/test-unparser +0 -26
  95. data/lib/unparser/emitter/literal/composed.rb +0 -64
  96. data/spec/unit/unparser/comments/skip_eol_comment_spec.rb +0 -29
@@ -0,0 +1,46 @@
1
+ # encoding: utf-8
2
+
3
+ module Unparser
4
+ class Emitter
5
+ class Send
6
+
7
+ # Emitter for arguments of send nodes
8
+ class Arguments < Emitter
9
+
10
+ private
11
+
12
+ # Perform dispatch
13
+ #
14
+ # @return [undefined]
15
+ #
16
+ # @api private
17
+ #
18
+ def dispatch
19
+ return if children.empty?
20
+
21
+ parentheses do
22
+ delimited(effective_arguments)
23
+ end
24
+ end
25
+
26
+ # Return effective arguments
27
+ #
28
+ # @return [Parser::AST::Node]
29
+ #
30
+ # @api private
31
+ #
32
+ def effective_arguments
33
+ last = children.length - 1
34
+ children.each_with_index.map do |argument, index|
35
+ if last == index && argument.type == :hash && argument.children.any?
36
+ argument.updated(:hash_body)
37
+ else
38
+ argument
39
+ end
40
+ end
41
+ end
42
+
43
+ end # Arguments
44
+ end # Send
45
+ end # Emitter
46
+ end # Unparser
@@ -0,0 +1,35 @@
1
+ # encoding: utf-8
2
+
3
+ module Unparser
4
+ class Emitter
5
+ class Send
6
+ # Emitter for send as attribute assignment
7
+ class AttributeAssignment < self
8
+
9
+ # Perform regular dispatch
10
+ #
11
+ # @return [undefined]
12
+ #
13
+ # @api private
14
+ #
15
+ def dispatch
16
+ emit_receiver
17
+ emit_selector
18
+ visit_terminated(arguments.first)
19
+ end
20
+
21
+ # Emit receiver
22
+ #
23
+ # @return [Parser::AST::Node]
24
+ #
25
+ # @api private
26
+ #
27
+ def emit_receiver
28
+ visit_terminated(receiver)
29
+ write(T_DOT)
30
+ end
31
+
32
+ end # AttributeAssignment
33
+ end # Send
34
+ end # Emitter
35
+ end # Unparser
@@ -1,3 +1,5 @@
1
+ # encoding: utf-8
2
+
1
3
  module Unparser
2
4
  class Emitter
3
5
  class Send
@@ -1,3 +1,5 @@
1
+ # encoding: utf-8
2
+
1
3
  module Unparser
2
4
  class Emitter
3
5
  class Send
@@ -1,3 +1,5 @@
1
+ # encoding: utf-8
2
+
1
3
  module Unparser
2
4
  class Emitter
3
5
  class Send
@@ -18,9 +20,9 @@ module Unparser
18
20
  emit_arguments
19
21
  end
20
22
 
21
- # Return receiver
23
+ # Emit receiver
22
24
  #
23
- # @return [Parser::AST::Node]
25
+ # @return [undefined]
24
26
  #
25
27
  # @api private
26
28
  #
@@ -1,3 +1,5 @@
1
+ # encoding: utf-8
2
+
1
3
  module Unparser
2
4
  class Emitter
3
5
  class Send
@@ -20,7 +22,7 @@ module Unparser
20
22
  def dispatch
21
23
  name = selector
22
24
  write(MAP.fetch(name, name).to_s)
23
- visit(receiver)
25
+ visit_terminated(receiver)
24
26
  end
25
27
 
26
28
  end # Unary
@@ -1,3 +1,5 @@
1
+ # encoding: utf-8
2
+
1
3
  module Unparser
2
4
  class Emitter
3
5
  # Emitter for splats
@@ -1,3 +1,5 @@
1
+ # encoding: utf-8
2
+
1
3
  module Unparser
2
4
  class Emitter
3
5
 
@@ -1,3 +1,5 @@
1
+ # encoding: utf-8
2
+
1
3
  module Unparser
2
4
  class Emitter
3
5
  # Emitter for undef nodes
@@ -1,3 +1,5 @@
1
+ # encoding: utf-8
2
+
1
3
  module Unparser
2
4
  class Emitter
3
5
 
@@ -1,3 +1,5 @@
1
+ # encoding: utf-8
2
+
1
3
  module Unparser
2
4
  class Emitter
3
5
 
@@ -1 +1,3 @@
1
+ # encoding: utf-8
2
+
1
3
  Unparser::Emitter::REGISTRY.freeze
@@ -0,0 +1,19 @@
1
+ # encoding: UTF-8
2
+
3
+ module Unparser
4
+ module NodeHelpers
5
+
6
+ # Helper for building nodes
7
+ #
8
+ # @param [Symbol]
9
+ #
10
+ # @return [Parser::AST::Node]
11
+ #
12
+ # @api private
13
+ #
14
+ def s(type, *children)
15
+ Parser::AST::Node.new(type, *children)
16
+ end
17
+
18
+ end # NodeHelpers
19
+ end # Unparser
data/spec/spec_helper.rb CHANGED
@@ -1,12 +1,22 @@
1
+ # encoding: utf-8
2
+
1
3
  require 'unparser'
2
4
  require 'devtools/spec_helper'
3
5
 
6
+ require 'parser/current'
4
7
  require 'parser/ruby21'
5
8
 
6
9
  module SpecHelper
7
10
  def s(type, *children)
8
11
  Parser::AST::Node.new(type, children)
9
12
  end
13
+
14
+ def strip(source)
15
+ source = source.rstrip
16
+ indent = source.scan(/^\s*/).min_by(&:length)
17
+ source.gsub(/^#{indent}/, '')
18
+ end
19
+
10
20
  end
11
21
 
12
22
  RSpec.configure do |config|
@@ -1,3 +1,5 @@
1
+ # encoding: utf-8
2
+
1
3
  require 'spec_helper'
2
4
 
3
5
  describe Unparser::Buffer, '#append' do
@@ -1,3 +1,5 @@
1
+ # encoding: utf-8
2
+
1
3
  require 'spec_helper'
2
4
 
3
5
  describe Unparser::Buffer, '#append_without_prefix' do
@@ -1,3 +1,5 @@
1
+ # encoding: utf-8
2
+
1
3
  require 'spec_helper'
2
4
 
3
5
  describe Unparser::Buffer, '#capture_content' do
@@ -1,3 +1,5 @@
1
+ # encoding: utf-8
2
+
1
3
  require 'spec_helper'
2
4
 
3
5
  describe Unparser::Buffer, '#content' do
@@ -16,7 +18,7 @@ describe Unparser::Buffer, '#content' do
16
18
  first = object.content
17
19
  second = object.content
18
20
  expect(first).to eql(second)
19
- expect(first).to_not be(second)
21
+ expect(first).not_to be(second)
20
22
  end
21
23
  end
22
24
 
@@ -1,3 +1,5 @@
1
+ # encoding: utf-8
2
+
1
3
  require 'spec_helper'
2
4
 
3
5
  describe Unparser::Buffer, '#fresh_line?' do
@@ -1,3 +1,5 @@
1
+ # encoding: utf-8
2
+
1
3
  require 'spec_helper'
2
4
 
3
5
  describe Unparser::Buffer, '#indent' do
@@ -5,7 +7,7 @@ describe Unparser::Buffer, '#indent' do
5
7
 
6
8
  subject { object.indent }
7
9
 
8
- it 'should indent with two chars' do
10
+ it 'should indent with two spaces' do
9
11
  object.append('foo')
10
12
  object.nl
11
13
  object.indent
@@ -1,3 +1,5 @@
1
+ # encoding: utf-8
2
+
1
3
  require 'spec_helper'
2
4
 
3
5
  describe Unparser::Buffer, '#nl' do
@@ -1,3 +1,5 @@
1
+ # encoding: utf-8
2
+
1
3
  require 'spec_helper'
2
4
 
3
5
  describe Unparser::Buffer, '#unindent' do
@@ -1,5 +1,6 @@
1
+ # encoding: utf-8
2
+
1
3
  require 'spec_helper'
2
- require 'parser/current'
3
4
 
4
5
  describe Unparser::Comments, '#consume' do
5
6
 
@@ -1,5 +1,6 @@
1
+ # encoding: utf-8
2
+
1
3
  require 'spec_helper'
2
- require 'parser/current'
3
4
 
4
5
  describe Unparser::Comments, '#take_all' do
5
6
 
@@ -1,5 +1,6 @@
1
+ # encoding: utf-8
2
+
1
3
  require 'spec_helper'
2
- require 'parser/current'
3
4
 
4
5
  describe Unparser::Comments, '#take_before' do
5
6
 
@@ -17,11 +18,11 @@ describe Unparser::Comments, '#take_before' do
17
18
  RUBY
18
19
  end
19
20
 
20
- it 'should return no comments none are before the node' do
21
+ it 'should return no comments if none are before the node' do
21
22
  expect(object.take_before(ast, :expression)).to eql([])
22
23
  end
23
24
 
24
- it 'should only the comments that are before the specified part of the node' do
25
+ it 'should return only the comments that are before the specified part of the node' do
25
26
  expect(object.take_before(ast, :end)).to eql(comments.first(2))
26
27
  expect(object.take_all).to eql([comments[2]])
27
28
  end
@@ -36,11 +37,11 @@ describe Unparser::Comments, '#take_before' do
36
37
  RUBY
37
38
  end
38
39
 
39
- it 'should return no comments none are before the node' do
40
+ it 'should return no comments if none are before the node' do
40
41
  expect(object.take_before(ast, :expression)).to eql([])
41
42
  end
42
43
 
43
- it 'should only the comments that are before the specified part of the node' do
44
+ it 'should return only the comments that are before the specified part of the node' do
44
45
  expect(object.take_before(ast, :end)).to eql([])
45
46
  end
46
47
  end
@@ -1,5 +1,6 @@
1
+ # encoding: utf-8
2
+
1
3
  require 'spec_helper'
2
- require 'parser/current'
3
4
 
4
5
  describe Unparser::Comments, '#take_eol_comments' do
5
6
 
@@ -1,3 +1,5 @@
1
+ # encoding: utf-8
2
+
1
3
  require 'spec_helper'
2
4
 
3
5
  describe Unparser::Emitter, '.handle' do
@@ -1,3 +1,5 @@
1
+ # encoding: utf-8
2
+
1
3
  require 'spec_helper'
2
4
 
3
5
  describe Unparser do
@@ -19,62 +21,45 @@ describe Unparser do
19
21
 
20
22
  def self.with_versions(versions)
21
23
  versions.each do |version|
22
- parser = parser_for_ruby_version(version)
23
- yield version, parser
24
+ yield parser_for_ruby_version(version)
24
25
  end
25
26
  end
26
27
 
27
- def self.strip(ruby)
28
- return ruby if ruby.empty?
29
- lines = ruby.lines
30
- match = /\A[ ]*/.match(lines.first)
31
- length = match[0].length
32
- source = lines.map do |line|
33
- line[(length..-1)]
34
- end.join
35
- source.chomp
36
- end
37
-
38
- def assert_round_trip(input, parser_class)
39
- ast, comments = parser_class.parse_with_comments(input)
28
+ def assert_round_trip(input, parser)
29
+ ast, comments = parser.parse_with_comments(input)
40
30
  generated = Unparser.unparse(ast, comments)
41
31
  generated.should eql(input)
42
32
  end
43
33
 
44
- def self.assert_generates_one_way(ast, expected, versions = RUBIES)
45
- with_versions(versions) do |version, parser_class|
46
- it "should generate #{ast.inspect} as #{expected} under #{version}" do
47
- comments = []
48
- if ast.kind_of?(String)
49
- ast, comments = parser_class.parse_with_comments(input)
50
- end
51
- generated = Unparser.unparse(ast, comments)
52
- generated.should eql(expected)
53
- end
54
- end
34
+ def assert_generates_from_string(parser, string, expected)
35
+ string = strip(string)
36
+ ast_with_comments = parser.parse_with_comments(string)
37
+ assert_generates_from_ast(parser, ast_with_comments, expected)
38
+ end
39
+
40
+ def assert_generates_from_ast(parser, ast_with_comments, expected)
41
+ generated = Unparser.unparse(*ast_with_comments)
42
+ generated.should eql(expected)
43
+ ast, comments = parser.parse_with_comments(generated)
44
+ Unparser.unparse(ast, comments).should eql(expected)
55
45
  end
56
46
 
57
47
  def self.assert_generates(ast_or_string, expected, versions = RUBIES)
58
- ast_or_string = strip(ast_or_string) if ast_or_string.is_a?(String)
59
- expected = strip(expected)
60
- with_versions(versions) do |version, parser_class|
61
- it "should generate #{ast_or_string.inspect} as #{expected} under #{version}" do
62
- ast, comments = if ast_or_string.kind_of?(String)
63
- parser_class.parse_with_comments(ast_or_string)
64
- else
65
- [ast_or_string, []]
66
- end
67
- generated = Unparser.unparse(ast, comments)
68
- generated.should eql(expected)
69
- ast, comments = parser_class.parse_with_comments(generated)
70
- Unparser.unparse(ast, comments).should eql(expected)
48
+ with_versions(versions) do |parser|
49
+ it "should generate #{ast_or_string} as #{expected} under #{parser.inspect}" do
50
+ if ast_or_string.kind_of?(String)
51
+ expected = strip(expected)
52
+ assert_generates_from_string(parser, ast_or_string, expected)
53
+ else
54
+ assert_generates_from_ast(parser, [ast_or_string, []], expected)
55
+ end
71
56
  end
72
57
  end
73
58
  end
74
59
 
75
60
  def self.assert_round_trip(input, versions = RUBIES)
76
- with_versions(versions) do |version, parser|
77
- it "should round trip #{input.inspect} under #{version}" do
61
+ with_versions(versions) do |parser|
62
+ it "should round trip #{input} under #{parser.inspect}" do
78
63
  assert_round_trip(input, parser)
79
64
  end
80
65
  end
@@ -92,15 +77,35 @@ describe Unparser do
92
77
  assert_generates '0x1', '1'
93
78
  assert_generates '1_000', '1000'
94
79
  assert_generates '1e10', '10000000000.0'
95
- assert_generates '?c', '"c"'
96
80
  end
97
81
 
98
82
  context 'string' do
99
- assert_generates %q("foo" "bar"), %q("foobar")
100
- assert_generates %q(%Q(foo"#{@bar})), %q("foo\"#{@bar}")
83
+ assert_generates '?c', '"c"'
84
+ assert_source %q("foo" "bar")
85
+ assert_generates %q(%Q(foo"#{@bar})), %q("foo\\"#{@bar}")
101
86
  assert_source %q("\"")
102
87
  assert_source %q("foo#{1}bar")
103
88
  assert_source %q("\"#{@a}")
89
+ assert_source %q("\\\\#{}")
90
+ assert_source %q("foo bar")
91
+ assert_source %q("foo\nbar")
92
+ assert_source %q("foo bar #{}")
93
+ assert_source %q("foo\nbar #{}")
94
+ # Within indentation
95
+ assert_generates <<-'RUBY', <<-'RUBY'
96
+ if foo
97
+ "
98
+ #{foo}
99
+ "
100
+ end
101
+ RUBY
102
+ if foo
103
+ "\n #{foo}\n "
104
+ end
105
+ RUBY
106
+
107
+ assert_source %q("foo#{@bar}")
108
+ assert_source %q("fo\no#{bar}b\naz")
104
109
  end
105
110
 
106
111
  context 'execute string' do
@@ -128,14 +133,17 @@ describe Unparser do
128
133
  assert_source "/\n/"
129
134
  assert_source '/\n/'
130
135
  assert_source "/\n/x"
136
+ # Within indentation
137
+ assert_source <<-RUBY
138
+ if foo
139
+ /
140
+ /
141
+ end
142
+ RUBY
131
143
  assert_generates '%r(/)', '/\//'
132
144
  assert_generates '%r(\))', '/)/'
133
145
  assert_generates '%r(#{@bar}baz)', '/#{@bar}baz/'
134
- end
135
-
136
- context 'dynamic string' do
137
- assert_source %q("foo#{@bar}")
138
- assert_source %q("fo\no#{bar}b\naz")
146
+ assert_source '/\/\//x'
139
147
  end
140
148
 
141
149
  context 'dynamic symbol' do
@@ -175,8 +183,15 @@ describe Unparser do
175
183
 
176
184
  context 'hash' do
177
185
  assert_source '{}'
178
- assert_source '{1 => 2}'
179
- assert_source '{1 => 2, 3 => 4}'
186
+ assert_source '{ 1 => 2 }'
187
+ assert_source '{ 1 => 2, 3 => 4 }'
188
+
189
+ context 'with symbol keys' do
190
+ assert_source '{ a: 1, b: 2 }'
191
+ assert_source '{ a: :a }'
192
+ assert_source '{ :"a b" => 1 }'
193
+ assert_source '{ :-@ => 1 }'
194
+ end
180
195
  end
181
196
  end
182
197
 
@@ -192,11 +207,6 @@ describe Unparser do
192
207
  assert_source '::TOPLEVEL::CONST'
193
208
  end
194
209
 
195
- context 'break' do
196
- assert_source 'break'
197
- assert_source 'break(a)'
198
- end
199
-
200
210
  context 'next' do
201
211
  assert_source 'next'
202
212
  assert_source 'next(bar)'
@@ -231,6 +241,7 @@ describe Unparser do
231
241
  assert_source '$a = 1'
232
242
  assert_source 'CONST = 1'
233
243
  assert_source 'Name::Spaced::CONST = 1'
244
+ assert_source '::Foo = ::Bar'
234
245
  end
235
246
 
236
247
  context 'multiple' do
@@ -247,7 +258,6 @@ describe Unparser do
247
258
  assert_source '$a, $b = 1, 2'
248
259
  assert_source 'a, b = foo'
249
260
  assert_source 'a, (b, c) = 1, [2, 3]'
250
- assert_generates_one_way s(:mlhs, s(:lvasgn, :a), s(:lvasgn, :b)), 'a, b'
251
261
  end
252
262
  end
253
263
 
@@ -259,6 +269,26 @@ describe Unparser do
259
269
  assert_source <<-'RUBY'
260
270
  return(1)
261
271
  RUBY
272
+
273
+ assert_source <<-'RUBY'
274
+ return(1), (2)
275
+ RUBY
276
+
277
+ assert_generates <<-'RUBY', <<-'RUBY'
278
+ return(a ? b : c)
279
+ RUBY
280
+ return(if a
281
+ b
282
+ else
283
+ c
284
+ end)
285
+ RUBY
286
+ end
287
+
288
+ context 'break' do
289
+ assert_source 'break'
290
+ assert_source 'break(a)'
291
+ assert_source 'break(a), (b)'
262
292
  end
263
293
 
264
294
  context 'send' do
@@ -359,6 +389,13 @@ describe Unparser do
359
389
  assert_source '(array[i] = 1).foo'
360
390
  assert_source 'array[1..2].foo'
361
391
  assert_source '(a.attribute ||= foo).bar'
392
+ assert_source 'foo.bar=baz[1]'
393
+ assert_source 'foo.bar=(baz || foo)'
394
+ assert_source 'foo.bar=baz.bar'
395
+ assert_source 'foo << (bar * baz)'
396
+ assert_source <<-'RUBY'
397
+ foo ||= (a, _ = b)
398
+ RUBY
362
399
 
363
400
  assert_source <<-'RUBY'
364
401
  begin
@@ -439,6 +476,11 @@ describe Unparser do
439
476
  assert_source 'foo.bar(:baz, &baz)'
440
477
  assert_source 'foo.bar=(:baz)'
441
478
  assert_source 'self.foo=(:bar)'
479
+
480
+ assert_source 'foo.bar(baz: boz)'
481
+ assert_source 'foo.bar(foo, "baz" => boz)'
482
+ assert_source 'foo.bar({ foo: boz }, boz)'
483
+ assert_source 'foo.bar(foo, {})'
442
484
  end
443
485
 
444
486
  context 'begin; end' do
@@ -1134,6 +1176,7 @@ describe Unparser do
1134
1176
  context 'unary operators' do
1135
1177
  assert_source '!1'
1136
1178
  assert_source '!!1'
1179
+ assert_source '!!(foo || bar)'
1137
1180
  assert_source '!(!1).baz'
1138
1181
  assert_source '~a'
1139
1182
  assert_source '-a'
@@ -1215,6 +1258,16 @@ describe Unparser do
1215
1258
  # last
1216
1259
  RUBY
1217
1260
 
1261
+ assert_generates <<-'RUBY', <<-'RUBY'
1262
+ foo if bar
1263
+ # comment
1264
+ RUBY
1265
+ if bar
1266
+ foo
1267
+ end
1268
+ # comment
1269
+ RUBY
1270
+
1218
1271
  assert_source <<-'RUBY'
1219
1272
  def noop
1220
1273
  # do nothing