unparser 0.4.7 → 0.6.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (157) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +40 -9
  3. data/bin/unparser +2 -2
  4. data/lib/unparser/abstract_type.rb +121 -0
  5. data/lib/unparser/adamantium/method_builder.rb +111 -0
  6. data/lib/unparser/adamantium.rb +150 -0
  7. data/lib/unparser/anima/attribute.rb +59 -0
  8. data/lib/unparser/anima/error.rb +23 -0
  9. data/lib/unparser/anima.rb +184 -0
  10. data/lib/unparser/ast/local_variable_scope.rb +6 -76
  11. data/lib/unparser/ast.rb +1 -3
  12. data/lib/unparser/buffer.rb +14 -25
  13. data/lib/unparser/cli.rb +85 -77
  14. data/lib/unparser/{cli/color.rb → color.rb} +4 -14
  15. data/lib/unparser/comments.rb +0 -26
  16. data/lib/unparser/concord.rb +114 -0
  17. data/lib/unparser/constants.rb +4 -53
  18. data/lib/unparser/diff.rb +98 -0
  19. data/lib/unparser/dsl.rb +0 -32
  20. data/lib/unparser/either.rb +153 -0
  21. data/lib/unparser/emitter/alias.rb +2 -8
  22. data/lib/unparser/emitter/args.rb +45 -0
  23. data/lib/unparser/emitter/argument.rb +13 -169
  24. data/lib/unparser/emitter/array.rb +27 -0
  25. data/lib/unparser/emitter/array_pattern.rb +29 -0
  26. data/lib/unparser/emitter/assignment.rb +36 -127
  27. data/lib/unparser/emitter/begin.rb +9 -84
  28. data/lib/unparser/emitter/binary.rb +7 -20
  29. data/lib/unparser/emitter/block.rb +57 -41
  30. data/lib/unparser/emitter/case.rb +6 -48
  31. data/lib/unparser/emitter/case_guard.rb +27 -0
  32. data/lib/unparser/emitter/case_match.rb +40 -0
  33. data/lib/unparser/emitter/cbase.rb +1 -3
  34. data/lib/unparser/emitter/class.rb +6 -26
  35. data/lib/unparser/emitter/const_pattern.rb +24 -0
  36. data/lib/unparser/emitter/def.rb +7 -51
  37. data/lib/unparser/emitter/defined.rb +2 -12
  38. data/lib/unparser/emitter/dstr.rb +22 -0
  39. data/lib/unparser/emitter/dsym.rb +41 -0
  40. data/lib/unparser/emitter/find_pattern.rb +18 -0
  41. data/lib/unparser/emitter/flipflop.rb +11 -10
  42. data/lib/unparser/emitter/float.rb +29 -0
  43. data/lib/unparser/emitter/flow_modifier.rb +15 -53
  44. data/lib/unparser/emitter/for.rb +5 -19
  45. data/lib/unparser/emitter/hash.rb +36 -0
  46. data/lib/unparser/emitter/hash_pattern.rb +67 -0
  47. data/lib/unparser/emitter/hookexe.rb +5 -11
  48. data/lib/unparser/emitter/if.rb +15 -71
  49. data/lib/unparser/emitter/in_match.rb +21 -0
  50. data/lib/unparser/emitter/in_pattern.rb +36 -0
  51. data/lib/unparser/emitter/index.rb +22 -89
  52. data/lib/unparser/emitter/kwargs.rb +13 -0
  53. data/lib/unparser/emitter/kwbegin.rb +31 -0
  54. data/lib/unparser/emitter/lambda.rb +0 -8
  55. data/lib/unparser/emitter/masgn.rb +20 -0
  56. data/lib/unparser/emitter/match.rb +3 -17
  57. data/lib/unparser/emitter/match_alt.rb +23 -0
  58. data/lib/unparser/emitter/match_as.rb +21 -0
  59. data/lib/unparser/emitter/match_pattern.rb +30 -0
  60. data/lib/unparser/emitter/match_pattern_p.rb +20 -0
  61. data/lib/unparser/emitter/match_rest.rb +33 -0
  62. data/lib/unparser/emitter/match_var.rb +19 -0
  63. data/lib/unparser/emitter/mlhs.rb +40 -0
  64. data/lib/unparser/emitter/module.rb +3 -9
  65. data/lib/unparser/emitter/op_assign.rb +14 -29
  66. data/lib/unparser/emitter/pair.rb +33 -0
  67. data/lib/unparser/emitter/pin.rb +19 -0
  68. data/lib/unparser/emitter/primitive.rb +93 -0
  69. data/lib/unparser/emitter/range.rb +35 -0
  70. data/lib/unparser/emitter/regexp.rb +35 -0
  71. data/lib/unparser/emitter/repetition.rb +17 -57
  72. data/lib/unparser/emitter/rescue.rb +1 -97
  73. data/lib/unparser/emitter/root.rb +17 -1
  74. data/lib/unparser/emitter/send.rb +10 -219
  75. data/lib/unparser/emitter/simple.rb +33 -0
  76. data/lib/unparser/emitter/splat.rb +13 -19
  77. data/lib/unparser/emitter/super.rb +1 -29
  78. data/lib/unparser/emitter/undef.rb +1 -9
  79. data/lib/unparser/emitter/variable.rb +1 -31
  80. data/lib/unparser/emitter/xstr.rb +72 -0
  81. data/lib/unparser/emitter/yield.rb +1 -9
  82. data/lib/unparser/emitter.rb +24 -425
  83. data/lib/unparser/equalizer.rb +98 -0
  84. data/lib/unparser/generation.rb +252 -0
  85. data/lib/unparser/node_details/send.rb +65 -0
  86. data/lib/unparser/node_details.rb +21 -0
  87. data/lib/unparser/node_helpers.rb +48 -6
  88. data/lib/unparser/validation.rb +172 -0
  89. data/lib/unparser/writer/binary.rb +99 -0
  90. data/lib/unparser/writer/dynamic_string.rb +211 -0
  91. data/lib/unparser/writer/resbody.rb +40 -0
  92. data/lib/unparser/writer/rescue.rb +43 -0
  93. data/lib/unparser/{emitter → writer}/send/attribute_assignment.rb +11 -26
  94. data/lib/unparser/writer/send/binary.rb +27 -0
  95. data/lib/unparser/writer/send/conditional.rb +25 -0
  96. data/lib/unparser/writer/send/regular.rb +33 -0
  97. data/lib/unparser/{emitter → writer}/send/unary.rb +10 -17
  98. data/lib/unparser/writer/send.rb +115 -0
  99. data/lib/unparser/writer.rb +15 -0
  100. data/lib/unparser.rb +161 -77
  101. metadata +100 -157
  102. data/.circleci/config.yml +0 -49
  103. data/.gitignore +0 -37
  104. data/.rspec +0 -4
  105. data/.rubocop.yml +0 -9
  106. data/Changelog.md +0 -156
  107. data/Gemfile +0 -9
  108. data/Gemfile.lock +0 -181
  109. data/LICENSE +0 -20
  110. data/Rakefile +0 -22
  111. data/config/devtools.yml +0 -2
  112. data/config/flay.yml +0 -3
  113. data/config/flog.yml +0 -2
  114. data/config/mutant.yml +0 -6
  115. data/config/reek.yml +0 -98
  116. data/config/rubocop.yml +0 -122
  117. data/config/yardstick.yml +0 -2
  118. data/lib/unparser/cli/differ.rb +0 -152
  119. data/lib/unparser/cli/source.rb +0 -267
  120. data/lib/unparser/emitter/empty.rb +0 -23
  121. data/lib/unparser/emitter/ensure.rb +0 -37
  122. data/lib/unparser/emitter/literal/array.rb +0 -29
  123. data/lib/unparser/emitter/literal/dynamic.rb +0 -53
  124. data/lib/unparser/emitter/literal/dynamic_body.rb +0 -132
  125. data/lib/unparser/emitter/literal/execute_string.rb +0 -38
  126. data/lib/unparser/emitter/literal/hash.rb +0 -156
  127. data/lib/unparser/emitter/literal/primitive.rb +0 -145
  128. data/lib/unparser/emitter/literal/range.rb +0 -36
  129. data/lib/unparser/emitter/literal/regexp.rb +0 -114
  130. data/lib/unparser/emitter/literal/singleton.rb +0 -26
  131. data/lib/unparser/emitter/literal.rb +0 -10
  132. data/lib/unparser/emitter/meta.rb +0 -16
  133. data/lib/unparser/emitter/redo.rb +0 -25
  134. data/lib/unparser/emitter/resbody.rb +0 -76
  135. data/lib/unparser/emitter/retry.rb +0 -25
  136. data/lib/unparser/emitter/send/binary.rb +0 -57
  137. data/lib/unparser/emitter/send/conditional.rb +0 -40
  138. data/lib/unparser/emitter/send/regular.rb +0 -40
  139. data/lib/unparser/preprocessor.rb +0 -159
  140. data/spec/integration/unparser/corpus_spec.rb +0 -111
  141. data/spec/integrations.yml +0 -92
  142. data/spec/spec_helper.rb +0 -20
  143. data/spec/unit/unparser/buffer/append_spec.rb +0 -24
  144. data/spec/unit/unparser/buffer/append_without_prefix_spec.rb +0 -23
  145. data/spec/unit/unparser/buffer/capture_content_spec.rb +0 -17
  146. data/spec/unit/unparser/buffer/content_spec.rb +0 -38
  147. data/spec/unit/unparser/buffer/fresh_line_spec.rb +0 -20
  148. data/spec/unit/unparser/buffer/indent_spec.rb +0 -20
  149. data/spec/unit/unparser/buffer/nl_spec.rb +0 -16
  150. data/spec/unit/unparser/buffer/unindent_spec.rb +0 -20
  151. data/spec/unit/unparser/comments/consume_spec.rb +0 -22
  152. data/spec/unit/unparser/comments/take_all_spec.rb +0 -19
  153. data/spec/unit/unparser/comments/take_before_spec.rb +0 -46
  154. data/spec/unit/unparser/comments/take_eol_comments_spec.rb +0 -32
  155. data/spec/unit/unparser/emitter/class_methods/handle_spec.rb +0 -17
  156. data/spec/unit/unparser_spec.rb +0 -1849
  157. data/unparser.gemspec +0 -32
@@ -0,0 +1,211 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Unparser
4
+ module Writer
5
+ class DynamicString
6
+ include Writer, Adamantium
7
+
8
+ PATTERNS_2 =
9
+ [
10
+ %i[str_empty begin].freeze,
11
+ %i[begin str_nl].freeze
12
+ ].freeze
13
+
14
+ PATTERNS_3 =
15
+ [
16
+ %i[begin str_nl_eol str_nl_eol].freeze,
17
+ %i[str_nl_eol begin str_nl_eol].freeze,
18
+ %i[str_ws begin str_nl_eol].freeze
19
+ ].freeze
20
+
21
+ FLAT_INTERPOLATION = %i[ivar cvar gvar nth_ref].to_set.freeze
22
+
23
+ private_constant(*constants(false))
24
+
25
+ def emit_heredoc_reminder
26
+ return unless heredoc?
27
+
28
+ emit_heredoc_body
29
+ emit_heredoc_footer
30
+ end
31
+
32
+ def dispatch
33
+ if heredoc?
34
+ emit_heredoc_header
35
+ else
36
+ emit_dstr
37
+ end
38
+ end
39
+
40
+ private
41
+
42
+ def heredoc_header
43
+ '<<-HEREDOC'
44
+ end
45
+
46
+ def heredoc?
47
+ !children.empty? && (nl_last_child? && heredoc_pattern?)
48
+ end
49
+
50
+ def emit_heredoc_header
51
+ write(heredoc_header)
52
+ end
53
+
54
+ def emit_heredoc_body
55
+ nl
56
+ emit_normal_heredoc_body
57
+ end
58
+
59
+ def emit_heredoc_footer
60
+ write('HEREDOC')
61
+ end
62
+
63
+ def classify(node)
64
+ if n_str?(node)
65
+ classify_str(node)
66
+ else
67
+ node.type
68
+ end
69
+ end
70
+
71
+ def classify_str(node)
72
+ if str_nl?(node)
73
+ :str_nl
74
+ elsif node.children.first.end_with?("\n")
75
+ :str_nl_eol
76
+ elsif str_ws?(node)
77
+ :str_ws
78
+ elsif str_empty?(node)
79
+ :str_empty
80
+ end
81
+ end
82
+
83
+ def str_nl?(node)
84
+ node.eql?(s(:str, "\n"))
85
+ end
86
+
87
+ def str_empty?(node)
88
+ node.eql?(s(:str, ''))
89
+ end
90
+
91
+ def str_ws?(node)
92
+ /\A( |\t)+\z/.match?(node.children.first)
93
+ end
94
+
95
+ def heredoc_pattern?
96
+ heredoc_pattern_2? || heredoc_pattern_3?
97
+ end
98
+
99
+ def heredoc_pattern_3?
100
+ children.each_cons(3).any? do |group|
101
+ PATTERNS_3.include?(group.map(&method(:classify)))
102
+ end
103
+ end
104
+
105
+ def heredoc_pattern_2?
106
+ children.each_cons(2).any? do |group|
107
+ PATTERNS_2.include?(group.map(&method(:classify)))
108
+ end
109
+ end
110
+
111
+ def nl_last_child?
112
+ last = children.last
113
+ n_str?(last) && last.children.first[-1].eql?("\n")
114
+ end
115
+
116
+ def emit_normal_heredoc_body
117
+ buffer.root_indent do
118
+ children.each do |child|
119
+ if n_str?(child)
120
+ write(escape_dynamic(child.children.first))
121
+ else
122
+ emit_dynamic(child)
123
+ end
124
+ end
125
+ end
126
+ end
127
+
128
+ def escape_dynamic(string)
129
+ string.gsub('#', '\#')
130
+ end
131
+
132
+ def emit_dynamic(child)
133
+ if FLAT_INTERPOLATION.include?(child.type)
134
+ write('#')
135
+ visit(child)
136
+ elsif n_dstr?(child)
137
+ emit_body(child.children)
138
+ else
139
+ write('#{')
140
+ emit_dynamic_component(child.children.first)
141
+ write('}')
142
+ end
143
+ end
144
+
145
+ def emit_dynamic_component(node)
146
+ visit(node) if node
147
+ end
148
+
149
+ def emit_dstr
150
+ if children.empty?
151
+ write('%()')
152
+ else
153
+ segments.each_with_index do |children, index|
154
+ emit_segment(children, index)
155
+ end
156
+ end
157
+ end
158
+
159
+ def breakpoint?(child, current)
160
+ last_type = current.last&.type
161
+
162
+ [
163
+ n_str?(child) && last_type.equal?(:str) && current.none?(&method(:n_begin?)),
164
+ last_type.equal?(:dstr),
165
+ n_dstr?(child) && last_type
166
+ ].any?
167
+ end
168
+
169
+ def segments
170
+ segments = []
171
+
172
+ segments << current = []
173
+
174
+ children.each do |child|
175
+ if breakpoint?(child, current)
176
+ segments << current = []
177
+ end
178
+
179
+ current << child
180
+ end
181
+
182
+ segments
183
+ end
184
+
185
+ def emit_segment(children, index)
186
+ write(' ') unless index.zero?
187
+
188
+ write('"')
189
+ emit_body(children)
190
+ write('"')
191
+ end
192
+
193
+ def emit_body(children)
194
+ buffer.root_indent do
195
+ children.each_with_index do |child, index|
196
+ if n_str?(child)
197
+ string = child.children.first
198
+ if string.eql?("\n") && children.fetch(index.pred).type.equal?(:begin)
199
+ write("\n")
200
+ else
201
+ write(string.inspect[1..-2])
202
+ end
203
+ else
204
+ emit_dynamic(child)
205
+ end
206
+ end
207
+ end
208
+ end
209
+ end # DynamicString
210
+ end # Writer
211
+ end # Unparser
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Unparser
4
+ module Writer
5
+ # Writer for rescue bodies
6
+ class Resbody
7
+ include Writer
8
+
9
+ children :exception, :assignment, :body
10
+
11
+ def emit_postcontrol
12
+ write(' rescue ')
13
+ visit(body)
14
+ end
15
+
16
+ def emit_regular
17
+ write('rescue')
18
+ emit_exception
19
+ emit_assignment
20
+ emit_optional_body(body)
21
+ end
22
+
23
+ private
24
+
25
+ def emit_exception
26
+ return unless exception
27
+
28
+ ws
29
+ delimited(exception.children)
30
+ end
31
+
32
+ def emit_assignment
33
+ return unless assignment
34
+
35
+ write(' => ')
36
+ visit(assignment)
37
+ end
38
+ end # Resbody
39
+ end # Writer
40
+ end # Unparser
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Unparser
4
+ module Writer
5
+ class Rescue
6
+ include Writer, Adamantium
7
+
8
+ children :body, :rescue_body
9
+
10
+ define_group :rescue_bodies, 1..-2
11
+
12
+ def emit_regular
13
+ emit_optional_body(body)
14
+
15
+ rescue_bodies.each(&method(:emit_rescue_body))
16
+
17
+ if else_node
18
+ write('else')
19
+ emit_body(else_node)
20
+ end
21
+ end
22
+
23
+ def emit_heredoc_reminders
24
+ emitter(body).emit_heredoc_reminders
25
+ end
26
+
27
+ def emit_postcontrol
28
+ visit(body)
29
+ writer_with(Resbody, rescue_body).emit_postcontrol
30
+ end
31
+
32
+ private
33
+
34
+ def else_node
35
+ children.last
36
+ end
37
+
38
+ def emit_rescue_body(node)
39
+ writer_with(Resbody, node).emit_regular
40
+ end
41
+ end # Rescue
42
+ end # Writer
43
+ end # Unparser
@@ -1,24 +1,16 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Unparser
4
- class Emitter
4
+ module Writer
5
5
  class Send
6
- # Emitter for send as attribute assignment
6
+ # Writer for send as attribute assignment
7
7
  class AttributeAssignment < self
8
- include Unterminated
9
-
10
8
  children :receiver, :selector, :first_argument
11
9
 
12
- # Perform regular dispatch
13
- #
14
- # @return [undefined]
15
- #
16
- # @api private
17
- #
18
10
  def dispatch
19
11
  emit_receiver
20
12
  emit_attribute
21
- write(T_ASN)
13
+ write('=')
22
14
 
23
15
  if arguments.one?
24
16
  visit(first_argument)
@@ -27,29 +19,22 @@ module Unparser
27
19
  end
28
20
  end
29
21
 
22
+ def emit_send_mlhs
23
+ emit_receiver
24
+ write(details.non_assignment_selector)
25
+ end
26
+
30
27
  private
31
28
 
32
- # Emit receiver
33
- #
34
- # @return [Parser::AST::Node]
35
- #
36
- # @api private
37
- #
38
29
  def emit_receiver
39
30
  visit(receiver)
40
- write(T_DOT)
31
+ emit_operator
41
32
  end
42
33
 
43
- # Emit attribute
44
- #
45
- # @return [undefined]
46
- #
47
- # @api private
48
- #
49
34
  def emit_attribute
50
- write(non_assignment_selector)
35
+ write(details.non_assignment_selector)
51
36
  end
52
37
  end # AttributeAssignment
53
38
  end # Send
54
- end # Emitter
39
+ end # Writer
55
40
  end # Unparser
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Unparser
4
+ module Writer
5
+ class Send
6
+ # Writer for binary sends
7
+ class Binary < self
8
+ def dispatch
9
+ visit(receiver)
10
+ emit_operator
11
+ emit_right
12
+ end
13
+
14
+ private
15
+
16
+ def emit_operator
17
+ write(' ', details.string_selector, ' ')
18
+ end
19
+
20
+ def emit_right
21
+ emit_send_regular(children.fetch(2))
22
+ end
23
+
24
+ end # Binary
25
+ end # Send
26
+ end # Writer
27
+ end # Unparser
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Unparser
4
+ module Writer
5
+ class Send
6
+ # Writer for "conditional" receiver&.selector(arguments...) case
7
+ class Conditional < self
8
+
9
+ private
10
+
11
+ def dispatch
12
+ emit_receiver
13
+ emit_selector
14
+ emit_arguments
15
+ end
16
+
17
+ def emit_receiver
18
+ visit(receiver)
19
+ write('&.')
20
+ end
21
+
22
+ end # Regular
23
+ end # Send
24
+ end # Writer
25
+ end # Unparser
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Unparser
4
+ module Writer
5
+ class Send
6
+ # Writer for "regular" receiver.selector(arguments...) case
7
+ class Regular < self
8
+ def dispatch
9
+ emit_receiver
10
+ emit_selector
11
+ emit_arguments
12
+ end
13
+
14
+ def emit_send_mlhs
15
+ dispatch
16
+ end
17
+
18
+ def emit_arguments_without_heredoc_body
19
+ emit_normal_arguments if arguments.any?
20
+ end
21
+
22
+ def emit_receiver
23
+ return unless receiver
24
+
25
+ emit_send_regular(receiver)
26
+
27
+ emit_operator
28
+ end
29
+
30
+ end # Regular
31
+ end # Send
32
+ end # Writer
33
+ end # Unparser
@@ -1,36 +1,29 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Unparser
4
- class Emitter
4
+ module Writer
5
5
  class Send
6
- # Emitter for unary sends
6
+ # Writer for unary sends
7
7
  class Unary < self
8
- include Unterminated
9
-
10
- private
11
-
12
- MAP = IceNine.deep_freeze(
8
+ MAP = {
13
9
  '-@': '-',
14
10
  '+@': '+'
15
- )
11
+ }.freeze
12
+
13
+ private_constant(*constants(false))
16
14
 
17
- # Perform dispatch
18
- #
19
- # @return [undefined]
20
- #
21
- # @api private
22
- #
23
15
  def dispatch
24
16
  name = selector
17
+
25
18
  write(MAP.fetch(name, name).to_s)
26
- if receiver.type.equal?(:int) && selector.equal?(:'+@')
19
+
20
+ if n_int?(receiver) && selector.equal?(:+@)
27
21
  write('+')
28
22
  end
29
23
 
30
24
  visit(receiver)
31
25
  end
32
-
33
26
  end # Unary
34
27
  end # Send
35
- end # Emitter
28
+ end # Writer
36
29
  end # Unparser
@@ -0,0 +1,115 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Unparser
4
+ module Writer
5
+ # Writer for send
6
+ class Send
7
+ include Writer, Adamantium, Constants, Generation
8
+
9
+ INDEX_ASSIGN = :[]=
10
+ INDEX_REFERENCE = :[]
11
+
12
+ OPERATORS = {
13
+ csend: '&.',
14
+ send: '.'
15
+ }.freeze
16
+
17
+ private_constant(*constants(false))
18
+
19
+ children :receiver, :selector
20
+
21
+ def dispatch
22
+ effective_writer.dispatch
23
+ end
24
+
25
+ def emit_mlhs
26
+ effective_writer.emit_send_mlhs
27
+ end
28
+
29
+ def emit_selector
30
+ write(details.string_selector)
31
+ end
32
+
33
+ def emit_heredoc_reminders
34
+ emitter(receiver).emit_heredoc_reminders if receiver
35
+ arguments.each(&method(:emit_heredoc_reminder))
36
+ end
37
+
38
+ private
39
+
40
+ def effective_writer
41
+ writer_with(effective_writer_class, node)
42
+ end
43
+ memoize :effective_writer
44
+
45
+ def effective_writer_class
46
+ if details.binary_syntax_allowed?
47
+ Binary
48
+ elsif details.selector_unary_operator? && n_send?(node) && arguments.empty?
49
+ Unary
50
+ elsif write_as_attribute_assignment?
51
+ AttributeAssignment
52
+ else
53
+ Regular
54
+ end
55
+ end
56
+
57
+ def write_as_attribute_assignment?
58
+ details.assignment_operator?
59
+ end
60
+
61
+ def emit_operator
62
+ write(OPERATORS.fetch(node.type))
63
+ end
64
+
65
+ def emit_arguments
66
+ if arguments.empty?
67
+ write('()') if receiver.nil? && avoid_clash?
68
+ else
69
+ emit_normal_arguments
70
+ end
71
+ end
72
+
73
+ def arguments
74
+ details.arguments
75
+ end
76
+
77
+ def emit_normal_arguments
78
+ parentheses { delimited(arguments) }
79
+ end
80
+
81
+ def emit_heredoc_reminder(argument)
82
+ emitter(argument).emit_heredoc_reminders
83
+ end
84
+
85
+ def avoid_clash?
86
+ local_variable_clash? || parses_as_constant?
87
+ end
88
+
89
+ def local_variable_clash?
90
+ local_variable_scope.local_variable_defined_for_node?(node, selector)
91
+ end
92
+
93
+ def parses_as_constant?
94
+ test = Unparser.parse_either(selector.to_s).from_right do
95
+ fail InvalidNodeError.new("Invalid selector for send node: #{selector.inspect}", node)
96
+ end
97
+
98
+ n_const?(test)
99
+ end
100
+
101
+ def details
102
+ NodeDetails::Send.new(node)
103
+ end
104
+ memoize :details
105
+
106
+ def emit_send_regular(node)
107
+ if n_send?(node)
108
+ writer_with(Regular, node).dispatch
109
+ else
110
+ visit(node)
111
+ end
112
+ end
113
+ end # Send
114
+ end # Writer
115
+ end # Unparser
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Unparser
4
+ module Writer
5
+ include Generation, NodeHelpers
6
+
7
+ def self.included(descendant)
8
+ descendant.class_eval do
9
+ include Anima.new(:buffer, :comments, :node, :local_variable_scope)
10
+
11
+ extend DSL
12
+ end
13
+ end
14
+ end # Writer
15
+ end # Unparser