unparser 0.4.8 → 0.5.3

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