sirop 0.2 → 0.4

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1641ee60187094fe9dcdeebefbfc5283c0d2ea535aa161b17f7bf6f720d63854
4
- data.tar.gz: c9abaef1a8b7116760f92e143bcb2e58fbc4424fe3d4afe110bc10bf552852cf
3
+ metadata.gz: b6ffcc66301949fc52bae4b2eef554243263b06a9bdf699d6be61d9d38f1ade1
4
+ data.tar.gz: 6aeba8547c161f56a20e64d7cf219489bfd0f2195063ca8b651c821134944232
5
5
  SHA512:
6
- metadata.gz: 3900ece58c932df6181676abb597fa6deedfbd8801e28f4993cc36cce7584a188e88b73e6ef2b0fea33b5dbc8a8d284949159973cb108e149dd0d9b3ea5dd762
7
- data.tar.gz: 7f848b0e842792a33e3fc7c9b7d6cf72e924040307e2db5ccb0cff16af1e947e7053ee81e54ab688c131532b66432dc1283651ceeef5820ded58c3b8447d193a
6
+ metadata.gz: 8dde7126119287b24f05352b5c62922a5023c80ff9ffb3f258ddf8824b6ce947b7f2551bc1818202036ac152815458e3126a838b3e91d147ed413cb6fb181818
7
+ data.tar.gz: 83856a27062116324228881ff61172c62234ca3ce6992ba5ef8355db3f5a823e018695eb6e9e61b61b852cfa1b497039c1ad3fcbf6e7451bb0a9b14b64801da0
data/CHANGELOG.md CHANGED
@@ -1,3 +1,15 @@
1
+ # 2024-04-29 0.4
2
+
3
+ - Improve sourcifier to support all Ruby syntax, based on Prism test fixtures
4
+ - Update Prism
5
+
6
+ # 2024-04-19 0.3
7
+
8
+ - Add support for injecting (prefixed) parameters to a lambda node
9
+ - Fix whitespace adjustment in DSL compiler
10
+ - Improve DSL compiler to support embedded string expressions
11
+ - Correctly handle eval'd proc
12
+
1
13
  # 2024-02-27 0.2
2
14
 
3
15
  - Update README
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Sirop
4
+ class Injection
5
+ attr_reader :slice
6
+
7
+ def initialize(slice)
8
+ @slice = slice
9
+ end
10
+ end
11
+ end
@@ -8,3 +8,27 @@ class Prism::BasicVisitor
8
8
  self
9
9
  end
10
10
  end
11
+
12
+ class Prism::ParametersNode
13
+ attr_accessor :injected_prefix
14
+ end
15
+
16
+ class Prism::BlockParametersNode
17
+ attr_accessor :injected_parameters
18
+ end
19
+
20
+ class Prism::LambdaNode
21
+ # @param params [String] injected parameters
22
+ # @return [void]
23
+ def inject_parameters(params)
24
+ if parameters
25
+ if parameters.parameters
26
+ parameters.parameters.injected_prefix = Sirop::Injection.new(params)
27
+ else
28
+ parameters.injected_parameters = Sirop::Injection.new(params)
29
+ end
30
+ else
31
+ instance_variable_set(:@parameters, Sirop::Injection.new("(#{params})"))
32
+ end
33
+ end
34
+ end
@@ -5,6 +5,90 @@ require 'prism'
5
5
  module Sirop
6
6
  #
7
7
  class Sourcifier < Prism::BasicVisitor
8
+ VISIT_PLANS = {
9
+ alias_global_variable: [:keyword_loc, :new_name, :old_name],
10
+ alias_method: [:keyword_loc, :new_name, :old_name],
11
+ and: [:left, :operator_loc, :right],
12
+ assoc: [:key, :operator_loc, :value],
13
+ assoc_splat: [:operator_loc, :value],
14
+ back_reference_read: :emit_verbatim,
15
+ block: [:opening_loc, :parameters, :body, :closing_loc],
16
+ block_argument: [:operator_loc, :expression],
17
+ block_local_variable: :emit_verbatim,
18
+ block_parameter: [:operator_loc, :name_loc],
19
+ break: [:keyword_loc, :arguments],
20
+ capture_pattern: [:value, :operator_loc, :target],
21
+ class_variable_read: :emit_verbatim,
22
+ class_variable_target: :emit_verbatim,
23
+ class_variable_write: [:name_loc, :operator_loc, :value],
24
+ constant_path: [:parent, :delimiter_loc, :child],
25
+ constant_path_write: [:target, :operator_loc, :value],
26
+ constant_read: :emit_verbatim,
27
+ constant_write: [:name_loc, :operator_loc, :value],
28
+ defined: [:keyword_loc, :lparen_loc, :value, :rparen_loc],
29
+ embedded_statements: [:opening_loc, :statements, :closing_loc],
30
+ embedded_variable: [:operator_loc, :variable],
31
+ false: :emit_verbatim,
32
+ flip_flop: [:left, :operator_loc, :right],
33
+ float: :emit_verbatim,
34
+ forwarding_arguments: :emit_verbatim,
35
+ forwarding_parameter: :emit_verbatim,
36
+ forwarding_super: :emit_verbatim,
37
+ global_variable_read: :emit_verbatim,
38
+ global_variable_target: :emit_verbatim,
39
+ global_variable_write: [:name_loc, :operator_loc, :value],
40
+ imaginary: :emit_verbatim,
41
+ implicit: :emit_nothing,
42
+ implicit_rest: :emit_nothing,
43
+ in: [:in_loc, :pattern, :then_loc],
44
+ index_target: [:receiver, :opening_loc, :arguments, :closing_loc],
45
+ instance_variable_read: :emit_verbatim,
46
+ instance_variable_target: :emit_verbatim,
47
+ instance_variable_write: [:name_loc, :operator_loc, :value],
48
+ integer: :emit_verbatim,
49
+ keyword_rest_parameter: [:operator_loc, :name_loc],
50
+ keyword_parameter: :emit_verbatim,
51
+ local_variable_and_write: [:name_loc, :operator_loc, :value],
52
+ local_variable_operator_write: [:name_loc, :operator_loc, :value],
53
+ local_variable_or_write: [:name_loc, :operator_loc, :value],
54
+ local_variable_read: :emit_verbatim,
55
+ local_variable_target: :emit_verbatim,
56
+ local_variable_write: [:name_loc, :operator_loc, :value],
57
+ match_predicate: [:value, :operator_loc, :pattern],
58
+ match_required: [:value, :operator_loc, :pattern],
59
+ match_write: [:call],
60
+ next: [:keyword_loc, :arguments],
61
+ nil: :emit_verbatim,
62
+ no_keywords_parameter: :emit_verbatim,
63
+ numbered_parameters: :emit_nothing,
64
+ optional_parameter: [:name_loc, :operator_loc, :value],
65
+ optional_keyword_parameter: [:name_loc, :value],
66
+ or: [:left, :operator_loc, :right],
67
+ parentheses: [:opening_loc, :body, :closing_loc],
68
+ pinned_expression: [:operator_loc, :lparen_loc, :expression, :rparen_loc],
69
+ pinned_variable: [:operator_loc, :variable],
70
+ range: [:left, :operator_loc, :right],
71
+ rational: :emit_verbatim,
72
+ redo: :emit_verbatim,
73
+ regular_expression: :emit_verbatim,
74
+ required_parameter: :emit_verbatim,
75
+ required_keyword_parameter: :emit_verbatim,
76
+ rescue_modifier: [:expression, :keyword_loc, :rescue_expression],
77
+ rest_parameter: [:operator_loc, :name_loc],
78
+ retry: :emit_verbatim,
79
+ return: [:keyword_loc, :arguments],
80
+ self: :emit_verbatim,
81
+ source_encoding: :emit_verbatim,
82
+ source_file: :emit_verbatim,
83
+ source_line: :emit_verbatim,
84
+ splat: [:operator_loc, :expression],
85
+ string: [:opening_loc, :content_loc, :closing_loc],
86
+ symbol: :emit_verbatim,
87
+ true: :emit_verbatim,
88
+ x_string: :emit_verbatim,
89
+ yield: [:keyword_loc, :lparen_loc, :arguments, :rparen_loc]
90
+ }
91
+
8
92
  attr_reader :buffer
9
93
 
10
94
  def initialize
@@ -30,11 +114,14 @@ module Sirop
30
114
  end
31
115
 
32
116
  def adjust_whitespace(loc)
117
+ return if loc.is_a?(Sirop::Injection)
118
+
33
119
  if @last_loc_start
34
- if @last_loc_end.first != loc.start_line
35
- @buffer << "\n" * (loc.start_line - @last_loc_end.first)
120
+ line_diff = loc.start_line - @last_loc_end.first
121
+ if line_diff > 0
122
+ @buffer << "\n" * line_diff
36
123
  @buffer << ' ' * loc.start_column
37
- else
124
+ elsif line_diff == 0
38
125
  ofs = loc.start_column - @last_loc_end.last
39
126
  if ofs > 0
40
127
  @buffer << ' ' * ofs
@@ -49,20 +136,34 @@ module Sirop
49
136
  @last_loc_end = loc_end(loc)
50
137
  end
51
138
 
52
- def emit_code(loc, semicolon: false)
139
+ def emit_code(loc, semicolon: false, chomp: false)
53
140
  return if !loc
54
141
 
142
+ if @last_loc
143
+ loc_loc = loc.is_a?(Prism::Node) ? loc.location : loc
144
+ return if loc_loc.slice == @last_loc.slice && loc_loc.start_line == @last_loc.start_line &&
145
+ loc_loc.start_column == @last_loc.start_column
146
+ end
147
+
148
+ semicolon ||= @semicolon
149
+ @semicolon = false
55
150
  emit_semicolon(loc) if semicolon
56
151
  return visit(loc) if loc.is_a?(Prism::Node)
57
152
 
58
153
  adjust_whitespace(loc)
59
- emit(loc.slice)
154
+ str = loc.slice
155
+ str = str.chomp if chomp
156
+ emit(str)
60
157
  end
61
158
 
62
159
  def emit_verbatim(node)
63
160
  emit_code(node.location)
64
161
  end
65
162
 
163
+ def emit_nothing(node)
164
+ # emit nothing
165
+ end
166
+
66
167
  def emit_str(str)
67
168
  emit(str)
68
169
  @last_loc_end[1] += str.size
@@ -74,7 +175,11 @@ module Sirop
74
175
 
75
176
  def emit_semicolon(loc)
76
177
  loc = loc.location if loc.is_a?(Prism::Node)
77
- emit_str(';') if loc.start_line == @last_loc.end_line
178
+ if @last_loc && loc.start_line == @last_loc.end_line
179
+ if @buffer[-1] != ';' && loc.start_column > @last_loc_end[1]
180
+ emit_str(';')
181
+ end
182
+ end
78
183
  end
79
184
 
80
185
  def method_missing(sym, node, *args)
@@ -84,41 +189,6 @@ module Sirop
84
189
  visit_child_nodes(node)
85
190
  end
86
191
 
87
- VISIT_PLANS = {
88
- and: [:left, :operator_loc, :right],
89
- assoc: :visit_child_nodes,
90
- assoc_splat: [:operator_loc, :value],
91
- block: [:opening_loc, :parameters, :body, :closing_loc],
92
- block_argument: [:operator_loc, :expression],
93
- block_parameter: [:operator_loc, :name_loc],
94
- block_parameters: [:opening_loc, :parameters, :closing_loc],
95
- break: [:keyword_loc, :arguments],
96
- constant_path: [:parent, :delimiter_loc, :child],
97
- constant_read: :emit_verbatim,
98
- else: [:else_keyword_loc, :statements],
99
- embedded_statements: [:opening_loc, :statements, :closing_loc],
100
- false: :emit_verbatim,
101
- integer: :emit_verbatim,
102
- keyword_rest_parameter: [:operator_loc, :name_loc],
103
- lambda: [:operator_loc, :parameters, :opening_loc, :body,
104
- :closing_loc],
105
- local_variable_read: :emit_verbatim,
106
- local_variable_write: [:name_loc, :operator_loc, :value],
107
- next: [:keyword_loc, :arguments],
108
- nil: :emit_verbatim,
109
- optional_parameter: [:name_loc, :operator_loc, :value],
110
- or: [:left, :operator_loc, :right],
111
- parentheses: [:opening_loc, :body, :closing_loc],
112
- required_parameter: :emit_verbatim,
113
- rest_parameter: [:operator_loc, :name_loc],
114
- splat: [:operator_loc, :expression],
115
- statements: :visit_child_nodes,
116
- string: :emit_verbatim,
117
- symbol: :emit_verbatim,
118
- true: :emit_verbatim,
119
- yield: [:keyword_loc, :lparen_loc, :arguments, :rparen_loc],
120
- }
121
-
122
192
  VISIT_PLANS.each do |key, plan|
123
193
  sym = :"visit_#{key}_node"
124
194
  define_method(sym) { |n| visit_plan(plan, n) }
@@ -142,7 +212,7 @@ module Sirop
142
212
 
143
213
  def visit_comma_separated_nodes(list, comma = false)
144
214
  if list
145
- list.each_with_index do |child, idx|
215
+ list.each do |child|
146
216
  emit_comma if comma
147
217
  emit_code(child)
148
218
  comma = true
@@ -151,15 +221,40 @@ module Sirop
151
221
  comma
152
222
  end
153
223
 
224
+ def visit_space_separated_nodes(list)
225
+ if list
226
+ list.each do |child|
227
+ emit_code(child)
228
+ end
229
+ end
230
+ end
231
+
154
232
  def visit_parameters_node(node)
155
- comma = visit_comma_separated_nodes(node.requireds)
233
+ comma = false
234
+ # injected_prefix is a custom attribute added by Sirop to the
235
+ # ParametersNode class (in lib/sirop/prism_ext.rb). It is used
236
+ # as a way to add a first parameter to a block or method.
237
+ if node.injected_prefix
238
+ emit_code(node.injected_prefix)
239
+ # adjust last_loc_end for proper whitespace after comma
240
+ @last_loc_end[1] -= 2 if @last_loc_end
241
+ # binding.irb
242
+ comma = true
243
+ end
244
+ comma = visit_comma_separated_nodes(node.requireds, comma)
156
245
  comma = visit_comma_separated_nodes(node.optionals, comma)
157
- comma = visit_comma_separated_nodes(node.posts, comma)
158
246
  if node.rest
159
247
  emit_comma if comma
160
- comma = true
161
248
  emit_code(node.rest)
249
+ comma = true
162
250
  end
251
+ comma = visit_comma_separated_nodes(node.posts, comma)
252
+ comma = visit_comma_separated_nodes(node.keywords, comma)
253
+ # if node.rest
254
+ # emit_comma if comma
255
+ # comma = true
256
+ # emit_code(node.rest)
257
+ # end
163
258
  if node.keyword_rest
164
259
  emit_comma if comma
165
260
  comma = true
@@ -172,8 +267,8 @@ module Sirop
172
267
  end
173
268
  end
174
269
 
175
- def visit_arguments_node(node)
176
- visit_comma_separated_nodes(node.arguments)
270
+ def visit_arguments_node(node, subscript = 0..-1)
271
+ visit_comma_separated_nodes(node.arguments[subscript])
177
272
  end
178
273
 
179
274
  def visit_keyword_hash_node(node)
@@ -190,9 +285,9 @@ module Sirop
190
285
  emit_code(node.if_keyword_loc)
191
286
  emit_code(node.predicate)
192
287
  emit_code(node.then_keyword_loc)
193
- emit_code(node.statements)
288
+ emit_code(node.statements, semicolon: true)
194
289
  emit_code(node.consequent) if node.consequent
195
- emit_code(node.end_keyword_loc) if node.if_keyword_loc.slice == 'if'
290
+ emit_code(node.end_keyword_loc, semicolon: true) if node.if_keyword_loc.slice == 'if'
196
291
  end
197
292
 
198
293
  def visit_if_node_ternary(node)
@@ -208,18 +303,38 @@ module Sirop
208
303
  emit_code(node.predicate)
209
304
  end
210
305
 
306
+ def visit_unless_node(node)
307
+ if !node.end_keyword_loc
308
+ return visit_unless_node_guard(node)
309
+ end
310
+
311
+ emit_code(node.keyword_loc)
312
+ emit_code(node.predicate)
313
+ emit_code(node.then_keyword_loc)
314
+ @semicolon = true
315
+ emit_code(node.statements)
316
+ emit_code(node.consequent) if node.consequent
317
+ emit_code(node.end_keyword_loc, semicolon: true) if node.keyword_loc.slice == 'unless'
318
+ end
319
+
320
+ def visit_unless_node_guard(node)
321
+ emit_code(node.statements)
322
+ emit_code(node.keyword_loc)
323
+ emit_code(node.predicate)
324
+ end
325
+
211
326
  def visit_case_node(node)
212
327
  emit_code(node.case_keyword_loc)
213
328
  emit_code(node.predicate)
214
- node.conditions.each { |c| emit_code(c) }
215
- emit_code(node.consequent)
216
- emit_code(node.end_keyword_loc)
329
+ node.conditions.each { |c| emit_code(c, semicolon: true) }
330
+ emit_code(node.consequent, semicolon: true)
331
+ emit_code(node.end_keyword_loc, semicolon: true)
217
332
  end
218
333
 
219
334
  def visit_when_node(node)
220
335
  emit_code(node.keyword_loc)
221
336
  visit_comma_separated_nodes(node.conditions)
222
- emit_code(node.statements)
337
+ emit_code(node.statements, semicolon: true)
223
338
  end
224
339
 
225
340
  def visit_interpolated_symbol_node(node)
@@ -230,36 +345,49 @@ module Sirop
230
345
  alias_method :visit_interpolated_string_node, :visit_interpolated_symbol_node
231
346
 
232
347
  def visit_def_node(node)
233
- emit_code(node.def_keyword_loc)
348
+ emit_code(node.def_keyword_loc, semicolon: true)
349
+ emit_code(node.receiver)
350
+ emit_code(node.operator_loc)
234
351
  emit_code(node.name_loc)
235
- last_loc = node.name_loc
236
352
 
353
+ emit_code(node.lparen_loc)
237
354
  if node.parameters
238
- emit_str('(')
239
355
  emit_code(node.parameters)
240
- emit_str(')')
241
- last_loc = node.parameters.location
242
356
  end
243
-
244
- emit_code(node.body, semicolon: true)
357
+ emit_code(node.rparen_loc)
358
+ emit_code(node.equal_loc)
359
+ emit_code(node.body, semicolon: !node.equal_loc)
245
360
  emit_code(node.end_keyword_loc, semicolon: true)
361
+ @semicolon = true
246
362
  end
247
363
 
248
364
  def visit_call_node(node)
249
- if node.receiver && !node.call_operator_loc && !node.arguments
365
+ if node.receiver && !node.call_operator_loc && !node.arguments && node.name != :[]
366
+ return visit_call_node_unary_op(node)
367
+ end
368
+
369
+ if node.receiver && !node.call_operator_loc && node.name == :!
250
370
  return visit_call_node_unary_op(node)
251
371
  end
252
372
 
373
+ if node.attribute_write?
374
+ return visit_call_node_attribute_write(node)
375
+ end
376
+
253
377
  block = node.block
254
378
 
255
379
  emit_code(node.receiver)
256
380
  emit_code(node.call_operator_loc)
257
- emit_code(node.message_loc)
381
+ if (ml = node.message_loc)
382
+ ol = node.opening_loc
383
+ emit_message_loc = !ol || (ol.start_line != ml.start_line) || (ol.start_column != ml.start_column)
384
+ emit_code(node.message_loc) if emit_message_loc
385
+ end
258
386
  emit_code(node.opening_loc)
259
387
  emit_code(node.arguments)
260
388
 
261
389
  if block.is_a?(Prism::BlockArgumentNode)
262
- emit_comma if node.arguments&.arguments.size > 0
390
+ emit_comma if node.arguments && node.arguments.arguments.size > 0
263
391
  emit_code(block)
264
392
  block = nil
265
393
  end
@@ -269,7 +397,33 @@ module Sirop
269
397
 
270
398
  def visit_call_node_unary_op(node)
271
399
  emit_code(node.message_loc)
400
+ emit_code(node.opening_loc)
401
+ emit_code(node.receiver)
402
+ emit_code(node.closing_loc)
403
+ end
404
+
405
+ def visit_call_node_attribute_write(node)
406
+ emit_code(node.receiver)
407
+ if node.call_operator_loc
408
+ emit_code(node.call_operator_loc)
409
+ emit_code(node.message_loc)
410
+ end
411
+ emit_code(node.opening_loc)
412
+ comma = visit_arguments_node(node.arguments, 0..-2)
413
+ if node.block
414
+ emit_comma if comma
415
+ emit_code(node.block)
416
+ end
417
+ emit_code(node.closing_loc)
418
+ emit_str(" = ")
419
+ emit_code(node.arguments.arguments[-1])
420
+ return
421
+ end
422
+
423
+ def visit_call_target_node(node)
272
424
  emit_code(node.receiver)
425
+ emit_code(node.call_operator_loc)
426
+ emit_code(node.message_loc)
273
427
  end
274
428
 
275
429
  def visit_while_node(node)
@@ -286,5 +440,241 @@ module Sirop
286
440
  emit_code(node.keyword_loc)
287
441
  emit_code(node.predicate)
288
442
  end
443
+
444
+ def visit_until_node(node)
445
+ return visit_until_node_guard(node) if !node.closing_loc
446
+
447
+ emit_code(node.keyword_loc)
448
+ emit_code(node.predicate)
449
+ emit_code(node.statements, semicolon: true)
450
+ emit_code(node.closing_loc, semicolon: true)
451
+ end
452
+
453
+ def visit_until_node_guard(node)
454
+ emit_code(node.statements)
455
+ emit_code(node.keyword_loc)
456
+ emit_code(node.predicate)
457
+ end
458
+
459
+ def visit_hash_node(node)
460
+ emit_code(node.opening_loc)
461
+ visit_comma_separated_nodes(node.elements)
462
+ emit_code(node.closing_loc)
463
+ end
464
+
465
+ def visit_array_node(node)
466
+ emit_code(node.opening_loc)
467
+ if node.opening_loc && node.opening_loc.slice =~ /^%/
468
+ visit_space_separated_nodes(node.elements)
469
+ else
470
+ visit_comma_separated_nodes(node.elements)
471
+ end
472
+ emit_code(node.closing_loc)
473
+ end
474
+
475
+ def visit_multi_write_node(node)
476
+ emit_code(node.lparen_loc)
477
+ comma = visit_comma_separated_nodes(node.lefts)
478
+ if node.rest
479
+ emit_comma if comma
480
+ emit_code(node.rest)
481
+ comma = true
482
+ end
483
+ visit_comma_separated_nodes(node.rights, comma)
484
+ emit_code(node.rparen_loc)
485
+ emit_code(node.operator_loc)
486
+ emit_code(node.value)
487
+ end
488
+
489
+ def visit_rescue_node(node)
490
+ emit_code(node.keyword_loc, semicolon: true)
491
+ visit_comma_separated_nodes(node.exceptions)
492
+ emit_code(node.operator_loc)
493
+ emit_code(node.reference)
494
+ emit_code(node.statements, semicolon: true)
495
+ emit_code(node.consequent)
496
+ end
497
+
498
+ def visit_begin_node(node)
499
+ emit_code(node.begin_keyword_loc) #, semicolon: true)
500
+ emit_code(node.statements, semicolon: true)
501
+ emit_code(node.rescue_clause)
502
+ emit_code(node.else_clause)
503
+ emit_code(node.ensure_clause)
504
+ emit_code(node.end_keyword_loc, semicolon: true) if node.begin_keyword_loc
505
+ end
506
+
507
+ def visit_index_operator_write_node(node)
508
+ emit_code(node.receiver)
509
+ emit_code(node.opening_loc)
510
+ emit_code(node.arguments)
511
+ if node.block
512
+ if !node.arguments.arguments.empty?
513
+ emit_comma
514
+ end
515
+ emit_code(node.block)
516
+ end
517
+ emit_code(node.closing_loc)
518
+ emit_code(node.operator_loc)
519
+ emit_code(node.value)
520
+ end
521
+ alias_method :visit_index_and_write_node, :visit_index_operator_write_node
522
+ alias_method :visit_index_or_write_node, :visit_index_operator_write_node
523
+
524
+ def visit_ensure_node(node)
525
+ emit_code(node.ensure_keyword_loc, semicolon: true)
526
+ emit_code(node.statements, semicolon: true)
527
+ emit_code(node.end_keyword_loc, semicolon: true)
528
+ end
529
+
530
+ def visit_else_node(node)
531
+ emit_code(node.else_keyword_loc, semicolon: node.else_keyword_loc.slice == 'else')
532
+ emit_code(node.statements, semicolon: node.else_keyword_loc.slice == 'else')
533
+ end
534
+
535
+ def visit_case_match_node(node)
536
+ emit_code(node.case_keyword_loc)
537
+ emit_code(node.predicate)
538
+ @semicolon = true
539
+ visit_comma_separated_nodes(node.conditions)
540
+ emit_code(node.end_keyword_loc)
541
+ end
542
+
543
+ def visit_class_node(node)
544
+ emit_code(node.class_keyword_loc)
545
+ emit_code(node.constant_path)
546
+ emit_code(node.inheritance_operator_loc)
547
+ emit_code(node.superclass)
548
+ emit_code(node.body, semicolon: true)
549
+ emit_code(node.end_keyword_loc, semicolon: true)
550
+ end
551
+
552
+ def visit_module_node(node)
553
+ emit_code(node.module_keyword_loc)
554
+ emit_code(node.constant_path)
555
+ emit_code(node.body, semicolon: true)
556
+ emit_code(node.end_keyword_loc, semicolon: true)
557
+ end
558
+
559
+ def visit_singleton_class_node(node)
560
+ emit_code(node.class_keyword_loc)
561
+ emit_code(node.operator_loc)
562
+ emit_code(node.expression)
563
+ emit_code(node.body, semicolon: true)
564
+ emit_code(node.end_keyword_loc, semicolon: true)
565
+ end
566
+
567
+ def visit_interpolated_x_string_node(node)
568
+ emit_code(node.opening_loc)
569
+ node.parts.each { |p| emit_code(p) }
570
+ emit_code(node.closing_loc, chomp: true)
571
+ end
572
+
573
+ def visit_for_node(node)
574
+ emit_code(node.for_keyword_loc)
575
+ emit_code(node.index)
576
+ emit_code(node.in_keyword_loc)
577
+ emit_code(node.collection)
578
+ emit_code(node.do_keyword_loc)
579
+ emit_code(node.statements, semicolon: true)
580
+ emit_code(node.end_keyword_loc, semicolon: true)
581
+ end
582
+
583
+ def visit_multi_target_node(node)
584
+ emit_code(node.lparen_loc)
585
+ comma = visit_comma_separated_nodes(node.lefts)
586
+ if node.rest
587
+ emit_comma if comma
588
+ emit_code(node.rest)
589
+ comma = true
590
+ end
591
+ visit_comma_separated_nodes(node.rights, comma)
592
+ emit_code(node.rparen_loc)
593
+ end
594
+
595
+ def visit_find_pattern_node(node)
596
+ emit_code(node.constant)
597
+ emit_code(node.opening_loc)
598
+ emit_code(node.left)
599
+ comma = node.left
600
+ comma = visit_comma_separated_nodes(node.requireds, comma)
601
+ if node.right
602
+ emit_comma if comma
603
+ emit_code(node.right)
604
+ end
605
+ emit_code(node.closing_loc)
606
+ end
607
+
608
+ def visit_array_pattern_node(node)
609
+ emit_code(node.constant)
610
+ emit_code(node.opening_loc)
611
+ comma = visit_comma_separated_nodes(node.requireds, comma)
612
+ if node.rest
613
+ emit_comma if comma
614
+ emit_code(node.rest)
615
+ comma = true
616
+ end
617
+ visit_comma_separated_nodes(node.posts, comma)
618
+ emit_code(node.closing_loc)
619
+ end
620
+
621
+ def visit_hash_pattern_node(node)
622
+ emit_code(node.constant)
623
+ emit_code(node.opening_loc)
624
+ visit_comma_separated_nodes(node.elements)
625
+ emit_code(node.closing_loc)
626
+ end
627
+
628
+ def visit_statements_node(node)
629
+ first = true
630
+ node.body&.each do |n|
631
+ @semicolon = !first
632
+ visit(n)
633
+ first = false
634
+ end
635
+ end
636
+
637
+ def visit_block_parameters_node(node)
638
+ emit_code(node.opening_loc)
639
+ emit_code(node.injected_parameters)
640
+ emit_code(node.parameters)
641
+ @semicolon = true if node.parameters
642
+ visit_comma_separated_nodes(node.locals)
643
+ emit_code(node.closing_loc)
644
+ @semicolon = false
645
+ end
646
+
647
+ def visit_lambda_node(node)
648
+ emit_code(node.operator_loc)
649
+ emit_code(node.parameters)
650
+ emit_code(node.opening_loc)
651
+ emit_code(node.body, semicolon: node.opening_loc.slice == 'do')
652
+ emit_code(node.closing_loc, semicolon: node.closing_loc.slice == 'end')
653
+ end
654
+
655
+ def visit_interpolated_regular_expression_node(node)
656
+ emit_code(node.opening_loc)
657
+ node.parts.each { |p| emit_code(p) }
658
+ emit_code(node.closing_loc)
659
+ end
660
+
661
+ def visit_super_node(node)
662
+ emit_code(node.keyword_loc)
663
+ emit_code(node.lparen_loc)
664
+ emit_code(node.arguments)
665
+ emit_block_pre_rparen = node.block.is_a?(Prism::BlockArgumentNode)
666
+ if emit_block_pre_rparen
667
+ emit_comma if node.arguments
668
+ emit_code(node.block)
669
+ end
670
+ emit_code(node.rparen_loc)
671
+ emit_code(node.block) if !emit_block_pre_rparen
672
+ end
673
+
674
+ def visit_undef_node(node)
675
+ emit_code(node.keyword_loc)
676
+ visit_comma_separated_nodes(node.names)
677
+ end
678
+
289
679
  end
290
680
  end
data/lib/sirop/version.rb CHANGED
@@ -1,4 +1,4 @@
1
1
  module Sirop
2
2
  # Sirop version
3
- VERSION = '0.2'
3
+ VERSION = '0.4'
4
4
  end
data/lib/sirop.rb CHANGED
@@ -1,11 +1,15 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'prism'
4
+ require 'sirop/injection'
4
5
  require 'sirop/prism_ext'
5
6
  require 'sirop/finder'
6
7
  require 'sirop/sourcifier'
7
8
 
8
9
  module Sirop
10
+ class Error < StandardError
11
+ end
12
+
9
13
  class << self
10
14
  def to_ast(obj)
11
15
  case obj
@@ -43,6 +47,8 @@ module Sirop
43
47
  super(node)
44
48
  end
45
49
  end
50
+ rescue Errno::ENOENT
51
+ raise Sirop::Error, "Could not get source for proc"
46
52
  end
47
53
 
48
54
  def method_ast(method)
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sirop
3
3
  version: !ruby/object:Gem::Version
4
- version: '0.2'
4
+ version: '0.4'
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sharon Rosner
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2024-02-27 00:00:00.000000000 Z
10
+ date: 2024-04-29 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: prism
@@ -16,14 +15,14 @@ dependencies:
16
15
  requirements:
17
16
  - - "~>"
18
17
  - !ruby/object:Gem::Version
19
- version: 0.19.0
18
+ version: 0.27.0
20
19
  type: :runtime
21
20
  prerelease: false
22
21
  version_requirements: !ruby/object:Gem::Requirement
23
22
  requirements:
24
23
  - - "~>"
25
24
  - !ruby/object:Gem::Version
26
- version: 0.19.0
25
+ version: 0.27.0
27
26
  - !ruby/object:Gem::Dependency
28
27
  name: minitest
29
28
  requirement: !ruby/object:Gem::Requirement
@@ -38,7 +37,6 @@ dependencies:
38
37
  - - "~>"
39
38
  - !ruby/object:Gem::Version
40
39
  version: 5.22.0
41
- description:
42
40
  email: sharon@noteflakes.com
43
41
  executables: []
44
42
  extensions: []
@@ -49,6 +47,7 @@ files:
49
47
  - README.md
50
48
  - lib/sirop.rb
51
49
  - lib/sirop/finder.rb
50
+ - lib/sirop/injection.rb
52
51
  - lib/sirop/prism_ext.rb
53
52
  - lib/sirop/sourcifier.rb
54
53
  - lib/sirop/version.rb
@@ -59,7 +58,6 @@ metadata:
59
58
  homepage_uri: https://github.com/digital-fabric/sirop
60
59
  documentation_uri: https://www.rubydoc.info/gems/sirop
61
60
  changelog_uri: https://github.com/digital-fabric/sirop/blob/main/CHANGELOG.md
62
- post_install_message:
63
61
  rdoc_options:
64
62
  - "--title"
65
63
  - Sirop
@@ -78,8 +76,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
78
76
  - !ruby/object:Gem::Version
79
77
  version: '0'
80
78
  requirements: []
81
- rubygems_version: 3.5.3
82
- signing_key:
79
+ rubygems_version: 3.6.0.dev
83
80
  specification_version: 4
84
81
  summary: 'Sirop: Ruby code rewriter'
85
82
  test_files: []