unparser 0.4.5 → 0.5.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 (143) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -3
  3. data/bin/unparser +1 -1
  4. data/lib/unparser.rb +117 -62
  5. data/lib/unparser/ast.rb +1 -2
  6. data/lib/unparser/ast/local_variable_scope.rb +9 -79
  7. data/lib/unparser/buffer.rb +19 -16
  8. data/lib/unparser/cli.rb +84 -77
  9. data/lib/unparser/{cli/color.rb → color.rb} +0 -13
  10. data/lib/unparser/comments.rb +0 -26
  11. data/lib/unparser/constants.rb +4 -53
  12. data/lib/unparser/diff.rb +98 -0
  13. data/lib/unparser/dsl.rb +0 -32
  14. data/lib/unparser/emitter.rb +25 -428
  15. data/lib/unparser/emitter/alias.rb +2 -8
  16. data/lib/unparser/emitter/args.rb +45 -0
  17. data/lib/unparser/emitter/argument.rb +17 -179
  18. data/lib/unparser/emitter/array.rb +27 -0
  19. data/lib/unparser/emitter/array_pattern.rb +29 -0
  20. data/lib/unparser/emitter/assignment.rb +36 -127
  21. data/lib/unparser/emitter/begin.rb +9 -84
  22. data/lib/unparser/emitter/binary.rb +7 -20
  23. data/lib/unparser/emitter/block.rb +57 -41
  24. data/lib/unparser/emitter/case.rb +6 -48
  25. data/lib/unparser/emitter/case_guard.rb +27 -0
  26. data/lib/unparser/emitter/case_match.rb +40 -0
  27. data/lib/unparser/emitter/cbase.rb +1 -3
  28. data/lib/unparser/emitter/class.rb +6 -26
  29. data/lib/unparser/emitter/const_pattern.rb +24 -0
  30. data/lib/unparser/emitter/def.rb +7 -51
  31. data/lib/unparser/emitter/defined.rb +2 -12
  32. data/lib/unparser/emitter/dstr.rb +22 -0
  33. data/lib/unparser/emitter/dsym.rb +41 -0
  34. data/lib/unparser/emitter/flipflop.rb +11 -10
  35. data/lib/unparser/emitter/float.rb +29 -0
  36. data/lib/unparser/emitter/flow_modifier.rb +8 -55
  37. data/lib/unparser/emitter/for.rb +5 -19
  38. data/lib/unparser/emitter/hash.rb +74 -0
  39. data/lib/unparser/emitter/hash_pattern.rb +67 -0
  40. data/lib/unparser/emitter/hookexe.rb +5 -11
  41. data/lib/unparser/emitter/if.rb +9 -73
  42. data/lib/unparser/emitter/in_match.rb +21 -0
  43. data/lib/unparser/emitter/in_pattern.rb +34 -0
  44. data/lib/unparser/emitter/index.rb +21 -88
  45. data/lib/unparser/emitter/kwbegin.rb +31 -0
  46. data/lib/unparser/emitter/lambda.rb +0 -8
  47. data/lib/unparser/emitter/masgn.rb +20 -0
  48. data/lib/unparser/emitter/match.rb +3 -17
  49. data/lib/unparser/emitter/match_alt.rb +23 -0
  50. data/lib/unparser/emitter/match_as.rb +21 -0
  51. data/lib/unparser/emitter/match_rest.rb +26 -0
  52. data/lib/unparser/emitter/match_var.rb +19 -0
  53. data/lib/unparser/emitter/mlhs.rb +40 -0
  54. data/lib/unparser/emitter/module.rb +3 -9
  55. data/lib/unparser/emitter/op_assign.rb +12 -27
  56. data/lib/unparser/emitter/pin.rb +19 -0
  57. data/lib/unparser/emitter/primitive.rb +93 -0
  58. data/lib/unparser/emitter/range.rb +35 -0
  59. data/lib/unparser/emitter/regexp.rb +35 -0
  60. data/lib/unparser/emitter/repetition.rb +17 -57
  61. data/lib/unparser/emitter/rescue.rb +1 -97
  62. data/lib/unparser/emitter/root.rb +17 -1
  63. data/lib/unparser/emitter/send.rb +10 -219
  64. data/lib/unparser/emitter/simple.rb +33 -0
  65. data/lib/unparser/emitter/splat.rb +2 -18
  66. data/lib/unparser/emitter/super.rb +1 -29
  67. data/lib/unparser/emitter/undef.rb +1 -9
  68. data/lib/unparser/emitter/variable.rb +1 -31
  69. data/lib/unparser/emitter/xstr.rb +72 -0
  70. data/lib/unparser/emitter/yield.rb +1 -9
  71. data/lib/unparser/generation.rb +250 -0
  72. data/lib/unparser/node_details.rb +21 -0
  73. data/lib/unparser/node_details/send.rb +62 -0
  74. data/lib/unparser/node_helpers.rb +49 -8
  75. data/lib/unparser/validation.rb +151 -0
  76. data/lib/unparser/writer.rb +15 -0
  77. data/lib/unparser/writer/binary.rb +99 -0
  78. data/lib/unparser/writer/dynamic_string.rb +229 -0
  79. data/lib/unparser/writer/resbody.rb +40 -0
  80. data/lib/unparser/writer/rescue.rb +39 -0
  81. data/lib/unparser/writer/send.rb +124 -0
  82. data/lib/unparser/{emitter → writer}/send/attribute_assignment.rb +11 -26
  83. data/lib/unparser/writer/send/binary.rb +27 -0
  84. data/lib/unparser/writer/send/conditional.rb +25 -0
  85. data/lib/unparser/writer/send/regular.rb +33 -0
  86. data/lib/unparser/{emitter → writer}/send/unary.rb +10 -17
  87. metadata +152 -101
  88. data/.circleci/config.yml +0 -41
  89. data/.gitignore +0 -37
  90. data/.rspec +0 -4
  91. data/.rubocop.yml +0 -9
  92. data/Changelog.md +0 -146
  93. data/Gemfile +0 -11
  94. data/Gemfile.lock +0 -180
  95. data/LICENSE +0 -20
  96. data/Rakefile +0 -22
  97. data/config/devtools.yml +0 -2
  98. data/config/flay.yml +0 -3
  99. data/config/flog.yml +0 -2
  100. data/config/mutant.yml +0 -6
  101. data/config/reek.yml +0 -98
  102. data/config/rubocop.yml +0 -122
  103. data/config/yardstick.yml +0 -2
  104. data/lib/unparser/cli/differ.rb +0 -152
  105. data/lib/unparser/cli/source.rb +0 -267
  106. data/lib/unparser/emitter/empty.rb +0 -23
  107. data/lib/unparser/emitter/ensure.rb +0 -37
  108. data/lib/unparser/emitter/literal.rb +0 -10
  109. data/lib/unparser/emitter/literal/array.rb +0 -29
  110. data/lib/unparser/emitter/literal/dynamic.rb +0 -53
  111. data/lib/unparser/emitter/literal/dynamic_body.rb +0 -132
  112. data/lib/unparser/emitter/literal/execute_string.rb +0 -38
  113. data/lib/unparser/emitter/literal/hash.rb +0 -156
  114. data/lib/unparser/emitter/literal/primitive.rb +0 -145
  115. data/lib/unparser/emitter/literal/range.rb +0 -36
  116. data/lib/unparser/emitter/literal/regexp.rb +0 -114
  117. data/lib/unparser/emitter/literal/singleton.rb +0 -26
  118. data/lib/unparser/emitter/meta.rb +0 -16
  119. data/lib/unparser/emitter/redo.rb +0 -25
  120. data/lib/unparser/emitter/resbody.rb +0 -76
  121. data/lib/unparser/emitter/retry.rb +0 -25
  122. data/lib/unparser/emitter/send/binary.rb +0 -57
  123. data/lib/unparser/emitter/send/conditional.rb +0 -40
  124. data/lib/unparser/emitter/send/regular.rb +0 -40
  125. data/lib/unparser/preprocessor.rb +0 -159
  126. data/spec/integration/unparser/corpus_spec.rb +0 -111
  127. data/spec/integrations.yml +0 -87
  128. data/spec/spec_helper.rb +0 -20
  129. data/spec/unit/unparser/buffer/append_spec.rb +0 -24
  130. data/spec/unit/unparser/buffer/append_without_prefix_spec.rb +0 -23
  131. data/spec/unit/unparser/buffer/capture_content_spec.rb +0 -17
  132. data/spec/unit/unparser/buffer/content_spec.rb +0 -38
  133. data/spec/unit/unparser/buffer/fresh_line_spec.rb +0 -20
  134. data/spec/unit/unparser/buffer/indent_spec.rb +0 -20
  135. data/spec/unit/unparser/buffer/nl_spec.rb +0 -16
  136. data/spec/unit/unparser/buffer/unindent_spec.rb +0 -20
  137. data/spec/unit/unparser/comments/consume_spec.rb +0 -22
  138. data/spec/unit/unparser/comments/take_all_spec.rb +0 -19
  139. data/spec/unit/unparser/comments/take_before_spec.rb +0 -46
  140. data/spec/unit/unparser/comments/take_eol_comments_spec.rb +0 -32
  141. data/spec/unit/unparser/emitter/class_methods/handle_spec.rb +0 -17
  142. data/spec/unit/unparser_spec.rb +0 -1841
  143. data/unparser.gemspec +0 -30
@@ -6,14 +6,6 @@ module Unparser
6
6
 
7
7
  private
8
8
 
9
- # Define remaining children
10
- #
11
- # @param [Enumerable<Symbol>] names
12
- #
13
- # @return [undefined]
14
- #
15
- # @api private
16
- #
17
9
  def define_remaining_children(names)
18
10
  range = names.length..-1
19
11
  define_method(:remaining_children) do
@@ -22,15 +14,6 @@ module Unparser
22
14
  private :remaining_children
23
15
  end
24
16
 
25
- # Define named child
26
- #
27
- # @param [Symbol] name
28
- # @param [Fixnum] index
29
- #
30
- # @return [undefined]
31
- #
32
- # @api private
33
- #
34
17
  def define_child(name, index)
35
18
  define_method(name) do
36
19
  children.at(index)
@@ -38,15 +21,6 @@ module Unparser
38
21
  private name
39
22
  end
40
23
 
41
- # Define a group of children
42
- #
43
- # @param [Symbol] name
44
- # @param [Range] range
45
- #
46
- # @return [undefined]
47
- #
48
- # @pai private
49
- #
50
24
  def define_group(name, range)
51
25
  define_method(name) do
52
26
  children[range]
@@ -55,12 +29,6 @@ module Unparser
55
29
  memoize(name)
56
30
  end
57
31
 
58
- # Create name helpers
59
- #
60
- # @return [undefined]
61
- #
62
- # @api private
63
- #
64
32
  def children(*names)
65
33
  define_remaining_children(names)
66
34
 
@@ -1,36 +1,23 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Unparser
4
+ UnknownNodeError = Class.new(ArgumentError)
4
5
 
5
6
  # Emitter base class
6
- #
7
- # buggy, argument values are sends to self
8
- #
9
- # ignore :reek:TooManyMethods
10
7
  class Emitter
11
- include Adamantium::Flat, AbstractType, Constants, NodeHelpers
12
- include Concord.new(:node, :parent)
13
- extend DSL
8
+ include Adamantium::Flat, AbstractType, Constants, Generation, NodeHelpers
9
+ include Anima.new(:buffer, :comments, :node, :local_variable_scope)
14
10
 
15
- # Registry for node emitters
16
- REGISTRY = {} # rubocop:disable MutableConstant
11
+ public :node
17
12
 
18
- NOINDENT = %i[rescue ensure].to_set.freeze
13
+ extend DSL
19
14
 
20
- module Unterminated
21
- def terminated?
22
- false
23
- end
24
- end
15
+ # Registry for node emitters
16
+ REGISTRY = {} # rubocop:disable Style/MutableConstant
25
17
 
26
- module Terminated
27
- def terminated?
28
- true
29
- end
30
- end
18
+ NO_INDENT = %i[ensure rescue].freeze
31
19
 
32
20
  module LocalVariableRoot
33
-
34
21
  # Return local variable root
35
22
  #
36
23
  # @return [Parser::AST::Node]
@@ -46,40 +33,15 @@ module Unparser
46
33
  memoize :local_variable_scope
47
34
  end
48
35
  end
49
-
50
36
  end # LocalVariableRoot
51
37
 
52
- # Return local variable root
53
- #
54
- # @return [Parser::AST::Node]
55
- #
56
- # @api private
57
- #
58
- def local_variable_scope
59
- parent.local_variable_scope
60
- end
61
-
62
- # Return assigned lvars
63
- #
64
- # @return [Array<Symbol>]
65
- #
66
- # @api private
67
- #
68
- abstract_method :local_variables
69
-
70
- # Return node type
71
- #
72
- # @return [Symbol]
73
- #
74
- # @api private
75
- #
76
38
  def node_type
77
39
  node.type
78
40
  end
79
41
 
80
42
  # Register emitter for type
81
43
  #
82
- # @param [Symbol] type
44
+ # @param [Symbol] types
83
45
  #
84
46
  # @return [undefined]
85
47
  #
@@ -87,25 +49,16 @@ module Unparser
87
49
  #
88
50
  def self.handle(*types)
89
51
  types.each do |type|
52
+ fail "Handler for type: #{type} already registered" if REGISTRY.key?(type)
53
+
90
54
  REGISTRY[type] = self
91
55
  end
92
56
  end
93
57
  private_class_method :handle
94
58
 
95
- # Trigger write to buffer
96
- #
97
- # @return [self]
98
- #
99
- # @api private
100
- #
101
- def write_to_buffer
102
- emit_comments_before if buffer.fresh_line?
59
+ def emit_mlhs
103
60
  dispatch
104
- comments.consume(node)
105
- emit_eof_comments if parent.is_a?(Root)
106
- self
107
61
  end
108
- memoize :write_to_buffer
109
62
 
110
63
  # Return emitter
111
64
  #
@@ -113,386 +66,30 @@ module Unparser
113
66
  #
114
67
  # @api private
115
68
  #
116
- def self.emitter(node, parent)
69
+ # rubocop:disable Metrics/ParameterLists
70
+ def self.emitter(buffer:, comments:, node:, local_variable_scope:)
117
71
  type = node.type
118
- klass = REGISTRY.fetch(type) do
119
- raise ArgumentError, "No emitter for node: #{type.inspect}"
120
- end
121
- klass.new(node, parent)
122
- end
123
-
124
- # Dispatch node
125
- #
126
- # @return [undefined]
127
- #
128
- # @api private
129
- #
130
- abstract_method :dispatch
131
-
132
- # Test if node is emitted as terminated expression
133
- #
134
- # @return [Boolean]
135
- #
136
- # @api private
137
- #
138
- abstract_method :terminated?
139
72
 
140
- protected
141
-
142
- # Return buffer
143
- #
144
- # @return [Buffer] buffer
145
- #
146
- # @api private
147
- #
148
- def buffer
149
- parent.buffer
150
- end
151
- memoize :buffer, freezer: :noop
152
-
153
- # Return comments
154
- #
155
- # @return [Comments] comments
156
- #
157
- # @api private
158
- #
159
- def comments
160
- parent.comments
161
- end
162
- memoize :comments, freezer: :noop
163
-
164
- private
165
-
166
- # Emit contents of block within parentheses
167
- #
168
- # @return [undefined]
169
- #
170
- # @api private
171
- #
172
- def parentheses(open = M_PO, close = M_PC)
173
- write(open)
174
- yield
175
- write(close)
176
- end
177
-
178
- # Visit node
179
- #
180
- # @param [Parser::AST::Node] node
181
- #
182
- # @return [undefined]
183
- #
184
- # @api private
185
- #
186
- def visit_plain(node)
187
- emitter = emitter(node)
188
- emitter.write_to_buffer
189
- end
190
-
191
- # Visit ambiguous node
192
- #
193
- # @param [Parser::AST::Node] node
194
- #
195
- # @return [undefined]
196
- #
197
- # @api private
198
- #
199
- def visit(node)
200
- emitter = emitter(node)
201
- conditional_parentheses(!emitter.terminated?) do
202
- emitter.write_to_buffer
203
- end
204
- end
205
-
206
- # Visit within parentheses
207
- #
208
- # @param [Parser::AST::Node] node
209
- #
210
- # @return [undefined]
211
- #
212
- # @api private
213
- #
214
- def visit_parentheses(node, *arguments)
215
- parentheses(*arguments) do
216
- visit_plain(node)
217
- end
218
- end
219
-
220
- # Call block in optional parentheses
221
- #
222
- # @param [true, false] flag
223
- #
224
- # @return [undefined]
225
- #
226
- # @api private
227
- #
228
- # ignore :reek:ControlParameter
229
- def conditional_parentheses(flag)
230
- if flag
231
- parentheses { yield }
232
- else
233
- yield
234
- end
235
- end
236
-
237
- # Return emitter for node
238
- #
239
- # @param [Parser::AST::Node] node
240
- #
241
- # @return [Emitter]
242
- #
243
- # @api private
244
- #
245
- def emitter(node)
246
- self.class.emitter(node, self)
247
- end
248
-
249
- # Emit delimited body
250
- #
251
- # @param [Enumerable<Parser::AST::Node>] nodes
252
- # @param [String] delimiter
253
- #
254
- # @return [undefined]
255
- #
256
- # @api private
257
- #
258
- def delimited_plain(nodes)
259
- delimited(nodes, &method(:visit_plain))
260
- end
261
-
262
- # Emit delimited body
263
- #
264
- # @param [Enumerable<Parser::AST::Node>] nodes
265
- # @param [String] delimiter
266
- #
267
- # @return [undefined]
268
- #
269
- # @api private
270
- #
271
- def delimited(nodes, &block)
272
- return if nodes.empty?
273
-
274
- block ||= method(:visit)
275
- head, *tail = nodes
276
- block.call(head)
277
- tail.each do |node|
278
- write(DEFAULT_DELIMITER)
279
- block.call(node)
280
- end
281
- end
282
-
283
- # Return children of node
284
- #
285
- # @return [Array<Parser::AST::Node>]
286
- #
287
- # @api private
288
- #
289
- def children
290
- node.children
291
- end
292
-
293
- # Write newline
294
- #
295
- # @return [undefined]
296
- #
297
- # @api private
298
- #
299
- def nl
300
- emit_eol_comments
301
- buffer.nl
302
- end
303
-
304
- # Write comments that appeared before source_part in the source
305
- #
306
- # @param [Symbol] source_part
307
- #
308
- # @return [undefined]
309
- #
310
- # @api private
311
- #
312
- def emit_comments_before(source_part = :expression)
313
- comments_before = comments.take_before(node, source_part)
314
- return if comments_before.empty?
315
-
316
- emit_comments(comments_before)
317
- buffer.nl
318
- end
319
-
320
- # Write end-of-line comments
321
- #
322
- # @return [undefined]
323
- #
324
- # @api private
325
- #
326
- def emit_eol_comments
327
- comments.take_eol_comments.each do |comment|
328
- write(WS, comment.text)
329
- end
330
- end
331
-
332
- # Write end-of-file comments
333
- #
334
- # @return [undefined]
335
- #
336
- # @api private
337
- #
338
- def emit_eof_comments
339
- emit_eol_comments
340
- comments_left = comments.take_all
341
- return if comments_left.empty?
342
-
343
- buffer.nl
344
- emit_comments(comments_left)
345
- end
346
-
347
- # Write each comment to a separate line
348
- #
349
- # @param [Array] comments
350
- #
351
- # @return [undefined]
352
- #
353
- # @api private
354
- #
355
- def emit_comments(comments)
356
- max = comments.size - 1
357
- comments.each_with_index do |comment, index|
358
- if comment.type.equal?(:document)
359
- buffer.append_without_prefix(comment.text.chomp)
360
- else
361
- write(comment.text)
362
- end
363
- buffer.nl if index < max
364
- end
365
- end
366
-
367
- # Write strings into buffer
368
- #
369
- # @return [undefined]
370
- #
371
- # @api private
372
- #
373
- def write(*strings)
374
- strings.each do |string|
375
- buffer.append(string)
376
- end
377
- end
378
-
379
- # Write end keyword
380
- #
381
- # @return [undefined]
382
- #
383
- # @api private
384
- #
385
- def k_end
386
- buffer.indent
387
- emit_comments_before(:end)
388
- buffer.unindent
389
- write(K_END)
390
- end
391
-
392
- # Return first child
393
- #
394
- # @return [Parser::AST::Node]
395
- # if present
396
- #
397
- # @return [nil]
398
- # otherwise
399
- #
400
- # @api private
401
- #
402
- def first_child
403
- children.first
404
- end
405
-
406
- # Write whitespace
407
- #
408
- # @return [undefined]
409
- #
410
- # @api private
411
- #
412
- def ws
413
- write(WS)
414
- end
415
-
416
- # Call emit contents of block indented
417
- #
418
- # @return [undefined]
419
- #
420
- # @api private
421
- #
422
- # False positive:
423
- #
424
- def indented
425
- buffer = buffer()
426
- buffer.indent
427
- nl
428
- yield
429
- nl
430
- buffer.unindent
431
- end
432
-
433
- # Emit non nil body
434
- #
435
- # @param [Parser::AST::Node] node
436
- #
437
- # @return [undefined]
438
- #
439
- # @api private
440
- #
441
- # rubocop:disable MethodCallWithoutArgsParentheses
442
- def emit_body(body = body())
443
- unless body
444
- buffer.indent
445
- nl
446
- buffer.unindent
447
- return
448
- end
449
- visit_indented(body)
450
- end
451
- # rubocop:enable MethodCallWithoutArgsParentheses
452
-
453
- # Visit indented node
454
- #
455
- # @param [Parser::AST::Node] node
456
- #
457
- # @return [undefined]
458
- #
459
- # @api private
460
- #
461
- def visit_indented(node)
462
- if NOINDENT.include?(node.type)
463
- visit_plain(node)
464
- else
465
- indented { visit_plain(node) }
73
+ klass = REGISTRY.fetch(type) do
74
+ fail UnknownNodeError, "Unknown node type: #{type.inspect}"
466
75
  end
467
- end
468
76
 
469
- # Return parent type
470
- #
471
- # @return [Symbol]
472
- # if parent is present
473
- #
474
- # @return [nil]
475
- # otherwise
476
- #
477
- # @api private
478
- #
479
- def parent_type
480
- parent.node_type
77
+ klass.new(
78
+ buffer: buffer,
79
+ comments: comments,
80
+ local_variable_scope: local_variable_scope,
81
+ node: node
82
+ )
481
83
  end
84
+ # rubocop:enable Metrics/ParameterLists
482
85
 
483
- # Delegate to emitter
484
- #
485
- # @param [Class:Emitter] emitter
86
+ # Dispatch node write as statement
486
87
  #
487
88
  # @return [undefined]
488
89
  #
489
90
  # @api private
490
91
  #
491
- # rubocop:disable MethodCallWithoutArgsParentheses
492
- def run(emitter, node = node())
493
- emitter.new(node, self).write_to_buffer
494
- end
495
- # rubocop:enable MethodCallWithoutArgsParentheses
92
+ abstract_method :dispatch
496
93
 
497
94
  end # Emitter
498
95
  end # Unparser