ruby-next-core 0.13.3 → 0.15.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 (59) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +44 -0
  3. data/README.md +65 -5
  4. data/bin/transform +5 -1
  5. data/lib/.rbnext/2.1/ruby-next/core.rb +7 -1
  6. data/lib/.rbnext/2.1/ruby-next/language.rb +44 -23
  7. data/lib/.rbnext/2.3/ruby-next/commands/nextify.rb +15 -2
  8. data/lib/.rbnext/2.3/ruby-next/language/eval.rb +1 -0
  9. data/lib/.rbnext/2.3/ruby-next/language/rewriters/{endless_range.rb → 2.6/endless_range.rb} +0 -0
  10. data/lib/.rbnext/2.3/ruby-next/language/rewriters/{pattern_matching.rb → 2.7/pattern_matching.rb} +121 -34
  11. data/lib/.rbnext/2.3/ruby-next/language/rewriters/3.1/anonymous_block.rb +68 -0
  12. data/lib/.rbnext/2.3/ruby-next/language/rewriters/base.rb +14 -2
  13. data/lib/.rbnext/2.7/ruby-next/core.rb +7 -1
  14. data/lib/.rbnext/2.7/ruby-next/language/rewriters/2.7/pattern_matching.rb +1061 -0
  15. data/lib/ruby-next/commands/nextify.rb +15 -2
  16. data/lib/ruby-next/config.rb +2 -2
  17. data/lib/ruby-next/core/enumerable/compact.rb +22 -0
  18. data/lib/ruby-next/core/integer/try_convert.rb +16 -0
  19. data/lib/ruby-next/core/matchdata/match.rb +9 -0
  20. data/lib/ruby-next/core/refinement/import.rb +60 -0
  21. data/lib/ruby-next/core.rb +7 -1
  22. data/lib/ruby-next/irb.rb +24 -0
  23. data/lib/ruby-next/language/eval.rb +1 -0
  24. data/lib/ruby-next/language/rewriters/{numeric_literals.rb → 2.1/numeric_literals.rb} +0 -0
  25. data/lib/ruby-next/language/rewriters/{required_kwargs.rb → 2.1/required_kwargs.rb} +0 -0
  26. data/lib/ruby-next/language/rewriters/{safe_navigation.rb → 2.3/safe_navigation.rb} +0 -0
  27. data/lib/ruby-next/language/rewriters/{squiggly_heredoc.rb → 2.3/squiggly_heredoc.rb} +0 -0
  28. data/lib/ruby-next/language/rewriters/{runtime → 2.4}/dir.rb +0 -0
  29. data/lib/ruby-next/language/rewriters/2.5/rescue_within_block.rb +39 -0
  30. data/lib/ruby-next/language/rewriters/{endless_range.rb → 2.6/endless_range.rb} +0 -0
  31. data/lib/ruby-next/language/rewriters/{args_forward.rb → 2.7/args_forward.rb} +0 -0
  32. data/lib/ruby-next/language/rewriters/{numbered_params.rb → 2.7/numbered_params.rb} +0 -0
  33. data/lib/ruby-next/language/rewriters/{pattern_matching.rb → 2.7/pattern_matching.rb} +121 -34
  34. data/lib/ruby-next/language/rewriters/{args_forward_leading.rb → 3.0/args_forward_leading.rb} +0 -0
  35. data/lib/ruby-next/language/rewriters/{endless_method.rb → 3.0/endless_method.rb} +15 -12
  36. data/lib/ruby-next/language/rewriters/{find_pattern.rb → 3.0/find_pattern.rb} +1 -3
  37. data/lib/ruby-next/language/rewriters/3.0/in_pattern.rb +22 -0
  38. data/lib/ruby-next/language/rewriters/3.1/anonymous_block.rb +68 -0
  39. data/lib/ruby-next/language/rewriters/3.1/endless_method_command.rb +46 -0
  40. data/lib/ruby-next/language/rewriters/3.1/oneline_pattern_parensless.rb +41 -0
  41. data/lib/ruby-next/language/rewriters/3.1/pin_vars_pattern.rb +50 -0
  42. data/lib/ruby-next/language/rewriters/3.1/refinement_import_methods.rb +60 -0
  43. data/lib/ruby-next/language/rewriters/{shorthand_hash.rb → 3.1/shorthand_hash.rb} +6 -4
  44. data/lib/ruby-next/language/rewriters/base.rb +14 -2
  45. data/lib/ruby-next/language/{edge.rb → rewriters/edge.rb} +0 -0
  46. data/lib/ruby-next/language/rewriters/proposed/bind_vars_pattern.rb +50 -0
  47. data/lib/ruby-next/language/rewriters/{method_reference.rb → proposed/method_reference.rb} +0 -0
  48. data/lib/ruby-next/language/rewriters/proposed.rb +9 -0
  49. data/lib/ruby-next/language/rewriters/runtime.rb +1 -2
  50. data/lib/ruby-next/language/setup.rb +1 -1
  51. data/lib/ruby-next/language.rb +44 -23
  52. data/lib/ruby-next/pry.rb +90 -0
  53. data/lib/ruby-next/rubocop.rb +24 -4
  54. data/lib/ruby-next/version.rb +1 -1
  55. data/lib/uby-next/irb.rb +3 -0
  56. data/lib/uby-next/pry.rb +3 -0
  57. metadata +40 -43
  58. data/lib/ruby-next/language/proposed.rb +0 -9
  59. data/lib/ruby-next/language/rewriters/in_pattern.rb +0 -56
@@ -24,6 +24,8 @@ module RubyNext
24
24
  contents = File.read(path)
25
25
  transpile path, contents
26
26
  end
27
+
28
+ ensure_rbnext!
27
29
  end
28
30
 
29
31
  def parse!(args)
@@ -48,11 +50,11 @@ module RubyNext
48
50
  end
49
51
 
50
52
  opts.on("--edge", "Enable edge (master) Ruby features") do |val|
51
- require "ruby-next/language/edge"
53
+ require "ruby-next/language/rewriters/edge"
52
54
  end
53
55
 
54
56
  opts.on("--proposed", "Enable proposed/experimental Ruby features") do |val|
55
- require "ruby-next/language/proposed"
57
+ require "ruby-next/language/rewriters/proposed"
56
58
  end
57
59
 
58
60
  opts.on(
@@ -185,6 +187,17 @@ module RubyNext
185
187
  FileUtils.rm_r(next_dir_path)
186
188
  end
187
189
 
190
+ def ensure_rbnext!
191
+ return if CLI.dry_run? || stdout?
192
+
193
+ return if File.directory?(next_dir_path)
194
+
195
+ return if next_dir_path.end_with?(".rb")
196
+
197
+ FileUtils.mkdir_p next_dir_path
198
+ File.write(File.join(next_dir_path, ".keep"), "")
199
+ end
200
+
188
201
  def next_dir_path
189
202
  @next_dir_path ||= (out_path || File.join(lib_path, RUBY_NEXT_DIR))
190
203
  end
@@ -10,10 +10,10 @@ module RubyNext
10
10
  # Defines last minor version for every major version
11
11
  LAST_MINOR_VERSIONS = {
12
12
  2 => 8, # 2.8 is required for backward compatibility: some gems already uses it
13
- 3 => 0
13
+ 3 => 1
14
14
  }.freeze
15
15
 
16
- LATEST_VERSION = [3, 0].freeze
16
+ LATEST_VERSION = [3, 1].freeze
17
17
 
18
18
  # A virtual version number used for proposed features
19
19
  NEXT_VERSION = "1995.next.0"
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ RubyNext::Core.patch Enumerable, method: :compact, version: "3.1" do
4
+ <<-RUBY
5
+ def compact
6
+ reduce([]) do |acc, val|
7
+ acc << val unless val.nil?
8
+ acc
9
+ end
10
+ end
11
+ RUBY
12
+ end
13
+
14
+ RubyNext::Core.patch Enumerator::Lazy, method: :compact, version: "3.1" do
15
+ <<-RUBY
16
+ def compact
17
+ Enumerator::Lazy.new(self) do |yielder, value|
18
+ yielder << value unless value.nil?
19
+ end
20
+ end
21
+ RUBY
22
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ RubyNext::Core.patch Integer.singleton_class, method: :try_convert, singleton: Integer, version: "3.1" do
4
+ <<-'RUBY'
5
+ def try_convert(val)
6
+ return val if val.is_a?(Integer)
7
+
8
+ if val.respond_to?(:to_int)
9
+ val.to_int.tap do |res|
10
+ next if res.is_a?(Integer) || res.nil?
11
+ raise TypeError, "Can't convert #{res.class} to Integer"
12
+ end
13
+ end
14
+ end
15
+ RUBY
16
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ RubyNext::Core.patch MatchData, method: :match, version: "3.1" do
4
+ <<-RUBY
5
+ def match(index_or_name)
6
+ self[index_or_name]
7
+ end
8
+ RUBY
9
+ end
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+
3
+ # We cannot use refinements here, since Ruby 2.6- doesn't support them in refine modules.
4
+ # So, we use a defined method instead (and transpile source code to use it).
5
+ # NOTE: We have to transpile the source code anyway, since we need to pass a binding.
6
+ RubyNext::Core.singleton_class.module_eval do
7
+ def import_methods(other, bind)
8
+ import = []
9
+
10
+ other.instance_methods(false).each do |mid|
11
+ # check for non-Ruby methods
12
+ meth = other.instance_method(mid)
13
+ location = meth.source_location
14
+
15
+ if location.nil? || location.first.match?(/(<internal:|resource:\/truffleruby\/core)/)
16
+ raise ArgumentError, "Can't import method: #{other}##{mid} from #{location}"
17
+ end
18
+
19
+ source_file, lineno = *location
20
+
21
+ raise ArgumentError, "Can't import dynamicly added methods: #{other}##{mid}" unless File.file?(source_file)
22
+
23
+ lines = File.open(source_file).readlines
24
+
25
+ buffer = []
26
+
27
+ lines[(lineno - 1)..-1].each do |line|
28
+ buffer << line + "\n"
29
+
30
+ begin
31
+ if defined?(::RubyNext::Language) && ::RubyNext::Language.runtime?
32
+ new_source = ::RubyNext::Language.transform(buffer.join, rewriters: RubyNext::Language.current_rewriters, using: false)
33
+ # Transformed successfully => valid method => evaluate transpiled code
34
+ import << [new_source, source_file, lineno]
35
+ buffer.clear
36
+ break
37
+ end
38
+
39
+ # Borrowed from https://github.com/banister/method_source/blob/81d039c966ffd95d26e12eb2e205c0eb8377f49d/lib/method_source/code_helpers.rb#L66
40
+ catch(:valid) do
41
+ eval("BEGIN{throw :valid}\nObject.new.instance_eval { #{buffer.join} }") # rubocop:disable all
42
+ end
43
+ break
44
+ rescue SyntaxError
45
+ end
46
+ end
47
+
48
+ import << [buffer.join, source_file, lineno] unless buffer.empty?
49
+ end
50
+
51
+ import.each do |(definition, file, lino)|
52
+ Kernel.eval definition, bind, file, lino
53
+ end
54
+
55
+ # Copy constants (they could be accessed from methods)
56
+ other.constants.each do |name|
57
+ Kernel.eval "#{name} = #{other}::#{name}", bind
58
+ end
59
+ end
60
+ end
@@ -62,7 +62,7 @@ module RubyNext
62
62
  mod_name = singleton? ? singleton.name : mod.name
63
63
  camelized_method_name = method_name.to_s.split("_").map(&:capitalize).join
64
64
 
65
- "#{mod_name}#{camelized_method_name}".gsub(/\W/, "")
65
+ "#{mod_name}#{camelized_method_name}".gsub(/\W/, "") # rubocop:disable Performance/StringReplacement
66
66
  end
67
67
 
68
68
  def build_location(trace_locations)
@@ -173,6 +173,8 @@ require "ruby-next/core/unboundmethod/bind_call"
173
173
  require "ruby-next/core/time/floor"
174
174
  require "ruby-next/core/time/ceil"
175
175
 
176
+ require "ruby-next/core/refinement/import"
177
+
176
178
  # Core extensions required for pattern matching
177
179
  # Required for pattern matching with refinements
178
180
  unless defined?(NoMatchingPatternError)
@@ -191,6 +193,10 @@ require "ruby-next/core/hash/except"
191
193
 
192
194
  require "ruby-next/core/array/intersect"
193
195
 
196
+ require "ruby-next/core/matchdata/match"
197
+ require "ruby-next/core/enumerable/compact"
198
+ require "ruby-next/core/integer/try_convert"
199
+
194
200
  # Generate refinements
195
201
  RubyNext.module_eval do
196
202
  RubyNext::Core.patches.refined.each do |mod, patches|
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "ruby-next"
4
+ # Include RubyNext into TOPLEVEL_BINDING for polyfills to work
5
+ eval("using RubyNext", TOPLEVEL_BINDING, __FILE__, __LINE__)
6
+
7
+ require "ruby-next/language"
8
+
9
+ # IRB extension to transpile code before evaluating
10
+ module RubyNext
11
+ module IRBExt
12
+ def evaluate(context, statements, *args)
13
+ new_statements = ::RubyNext::Language.transform(
14
+ statements,
15
+ rewriters: ::RubyNext::Language.current_rewriters,
16
+ using: false
17
+ )
18
+
19
+ super(context, new_statements, *args)
20
+ end
21
+ end
22
+ end
23
+
24
+ IRB::WorkSpace.prepend(RubyNext::IRBExt)
@@ -37,6 +37,7 @@ module RubyNext
37
37
 
38
38
  source = args.shift
39
39
  new_source = ::RubyNext::Language::Runtime.transform(source, using: false)
40
+
40
41
  RubyNext.debug_source(new_source, "(#{caller_locations(1, 1).first})")
41
42
  super new_source, *args
42
43
  end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyNext
4
+ module Language
5
+ module Rewriters
6
+ class RescueWithinBlock < Base
7
+ NAME = "rescue-within-block"
8
+ SYNTAX_PROBE = "lambda do
9
+ raise 'err'
10
+ rescue
11
+ $! # => #<RuntimeError: err>
12
+ end.call"
13
+
14
+ MIN_SUPPORTED_VERSION = Gem::Version.new("2.5.0")
15
+
16
+ def on_block(block_node)
17
+ exception_node = block_node.children.find do |node|
18
+ node.type == :rescue || node.type == :ensure
19
+ end
20
+
21
+ return unless exception_node
22
+
23
+ context.track! self
24
+
25
+ insert_before(exception_node.loc.expression, "begin;")
26
+ insert_after(exception_node.loc.expression, ";end")
27
+
28
+ new_childrens = block_node.children.map do |child|
29
+ next s(:kwbegin, exception_node) if child == exception_node
30
+
31
+ child
32
+ end
33
+
34
+ block_node.updated(:block, new_childrens)
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -243,6 +243,7 @@ module RubyNext
243
243
 
244
244
  @deconstructed_keys = {}
245
245
  @predicates = Predicates::CaseIn.new
246
+ @lvars = []
246
247
 
247
248
  matchee_ast =
248
249
  s(:begin, s(:lvasgn, MATCHEE, node.children[0]))
@@ -272,6 +273,7 @@ module RubyNext
272
273
 
273
274
  @deconstructed_keys = {}
274
275
  @predicates = Predicates::Noop.new
276
+ @lvars = []
275
277
 
276
278
  matchee =
277
279
  s(:begin, s(:lvasgn, MATCHEE, node.children[0]))
@@ -282,10 +284,12 @@ module RubyNext
282
284
  arr: MATCHEE_ARR,
283
285
  hash: MATCHEE_HASH
284
286
  ) do
285
- send(
286
- :"#{node.children[1].type}_clause",
287
- node.children[1]
288
- ).then do |node|
287
+ with_declared_locals do
288
+ send(
289
+ :"#{node.children[1].type}_clause",
290
+ node.children[1]
291
+ )
292
+ end.then do |node|
289
293
  s(:begin,
290
294
  s(:or,
291
295
  node,
@@ -306,6 +310,41 @@ module RubyNext
306
310
 
307
311
  alias on_in_match on_match_pattern
308
312
 
313
+ def on_match_pattern_p(node)
314
+ context.track! self
315
+
316
+ @deconstructed_keys = {}
317
+ @predicates = Predicates::Noop.new
318
+ @lvars = []
319
+
320
+ matchee =
321
+ s(:begin, s(:lvasgn, MATCHEE, node.children[0]))
322
+
323
+ pattern =
324
+ locals.with(
325
+ matchee: MATCHEE,
326
+ arr: MATCHEE_ARR,
327
+ hash: MATCHEE_HASH
328
+ ) do
329
+ with_declared_locals do
330
+ send(
331
+ :"#{node.children[1].type}_clause",
332
+ node.children[1]
333
+ )
334
+ end
335
+ end
336
+
337
+ node.updated(
338
+ :and,
339
+ [
340
+ matchee,
341
+ pattern
342
+ ]
343
+ ).tap do |new_node|
344
+ replace(node.loc.expression, inline_blocks(unparse(new_node)))
345
+ end
346
+ end
347
+
309
348
  private
310
349
 
311
350
  def rewrite_case_in!(node, matchee, new_node)
@@ -363,13 +402,15 @@ module RubyNext
363
402
  def build_when_clause(clause)
364
403
  predicates.reset!
365
404
  [
366
- with_guard(
367
- send(
368
- :"#{clause.children[0].type}_clause",
369
- clause.children[0]
370
- ),
371
- clause.children[1] # guard
372
- ),
405
+ with_declared_locals do
406
+ with_guard(
407
+ send(
408
+ :"#{clause.children[0].type}_clause",
409
+ clause.children[0]
410
+ ),
411
+ clause.children[1] # guard
412
+ )
413
+ end,
373
414
  process(clause.children[2] || s(:nil)) # expression
374
415
  ].then do |children|
375
416
  s(:when, *children)
@@ -407,13 +448,14 @@ module RubyNext
407
448
  end
408
449
 
409
450
  def match_var_clause(node, left = s(:lvar, locals[:matchee]))
410
- return s(:true) if node.children[0] == :_
451
+ var = node.children[0]
452
+ return s(:true) if var == :_
411
453
 
412
- check_match_var_alternation! node.children[0]
454
+ check_match_var_alternation!(var)
413
455
 
414
456
  s(:begin,
415
457
  s(:or,
416
- s(:begin, s(:lvasgn, node.children[0], left)),
458
+ s(:begin, build_var_assignment(var, left)),
417
459
  s(:true)))
418
460
  end
419
461
 
@@ -508,11 +550,10 @@ module RubyNext
508
550
  def array_find(head, *nodes, tail)
509
551
  index = s(:lvar, :__i__)
510
552
 
511
- match_vars = []
512
-
513
553
  head_match =
514
554
  unless head.children.empty?
515
- match_vars << s(:lvasgn, head.children[0].children[0])
555
+ # we only need to call this to track the lvar usage
556
+ build_var_assignment(head.children[0].children[0])
516
557
 
517
558
  arr_take = s(:send,
518
559
  s(:lvar, locals[:arr]),
@@ -524,16 +565,19 @@ module RubyNext
524
565
 
525
566
  tail_match =
526
567
  unless tail.children.empty?
527
- match_vars << s(:lvasgn, tail.children[0].children[0])
568
+ # we only need to call this to track the lvar usage
569
+ build_var_assignment(tail.children[0].children[0])
528
570
 
529
571
  match_var_clause(tail.children[0], arr_slice(index + nodes.size, -1))
530
572
  end
531
573
 
532
574
  nodes.each do |node|
533
575
  if node.type == :match_var
534
- match_vars << s(:lvasgn, node.children[0])
576
+ # we only need to call this to track the lvar usage
577
+ build_var_assignment(node.children[0])
535
578
  elsif node.type == :match_as
536
- match_vars << s(:lvasgn, node.children[1].children[0])
579
+ # we only need to call this to track the lvar usage
580
+ build_var_assignment(node.children[1].children[0])
537
581
  end
538
582
  end
539
583
 
@@ -561,19 +605,7 @@ module RubyNext
561
605
  s(:args,
562
606
  s(:arg, :_),
563
607
  s(:arg, :__i__)),
564
- pattern).then do |block|
565
- next block if match_vars.empty?
566
-
567
- # We need to declare match vars outside of `find` block
568
- locals_declare = s(:begin, s(:masgn,
569
- s(:mlhs, *match_vars),
570
- s(:nil)))
571
-
572
- s(:begin,
573
- s(:or,
574
- locals_declare,
575
- block))
576
- end
608
+ pattern)
577
609
  end
578
610
 
579
611
  def array_match_rest(index, node, *tail)
@@ -616,6 +648,14 @@ module RubyNext
616
648
  end
617
649
  end
618
650
 
651
+ def find_pattern_array_element(node, index)
652
+ element = arr_item_at(index)
653
+ locals.with(arr: locals[:arr, index]) do
654
+ predicates.push :"i#{index}"
655
+ find_pattern_clause(node, element).tap { predicates.pop }
656
+ end
657
+ end
658
+
619
659
  def hash_pattern_array_element(node, index)
620
660
  element = arr_item_at(index)
621
661
  locals.with(hash: locals[:arr, index]) do
@@ -796,6 +836,15 @@ module RubyNext
796
836
  end
797
837
  end
798
838
 
839
+ def find_pattern_hash_element(node, key)
840
+ element = hash_value_at(key)
841
+ key_index = deconstructed_key(key)
842
+ locals.with(arr: locals[:hash, key_index]) do
843
+ predicates.push :"k#{key_index}"
844
+ find_pattern_clause(node, element).tap { predicates.pop }
845
+ end
846
+ end
847
+
799
848
  def hash_element(head, *tail)
800
849
  send("#{head.type}_hash_element", head).then do |node|
801
850
  next node if tail.empty?
@@ -861,6 +910,10 @@ module RubyNext
861
910
  match_var_clause(child, s(:lvar, locals[:hash]))
862
911
  end
863
912
 
913
+ def pin_hash_element(node, index)
914
+ case_eq_hash_element node.children[0], index
915
+ end
916
+
864
917
  def case_eq_hash_element(node, key)
865
918
  case_eq_clause node, hash_value_at(key)
866
919
  end
@@ -911,6 +964,24 @@ module RubyNext
911
964
  end
912
965
  end
913
966
 
967
+ def with_declared_locals
968
+ lvars.clear
969
+ node = yield
970
+
971
+ return node if lvars.empty?
972
+
973
+ # We need to declare match lvars outside of the outer `find` block,
974
+ # so we do that for that whole pattern
975
+ locals_declare = s(:begin, s(:masgn,
976
+ s(:mlhs, *lvars.uniq.map { s(:lvasgn, _1) }),
977
+ s(:nil)))
978
+
979
+ s(:begin,
980
+ s(:or,
981
+ locals_declare,
982
+ node))
983
+ end
984
+
914
985
  def no_matching_pattern
915
986
  raise_error(
916
987
  :NoMatchingPatternError,
@@ -945,13 +1016,17 @@ module RubyNext
945
1016
 
946
1017
  private
947
1018
 
948
- attr_reader :deconstructed_keys, :predicates
1019
+ attr_reader :deconstructed_keys, :predicates, :lvars
949
1020
 
950
1021
  # Raise SyntaxError if match-var is used within alternation
951
1022
  # https://github.com/ruby/ruby/blob/672213ef1ca2b71312084057e27580b340438796/compile.c#L5900
952
1023
  def check_match_var_alternation!(name)
953
1024
  return unless locals.key?(ALTERNATION_MARKER)
954
1025
 
1026
+ if name.is_a?(::Parser::AST::Node)
1027
+ raise ::SyntaxError, "illegal variable in alternative pattern (#{name.children.first})"
1028
+ end
1029
+
955
1030
  return if name.start_with?("_")
956
1031
 
957
1032
  raise ::SyntaxError, "illegal variable in alternative pattern (#{name})"
@@ -968,6 +1043,18 @@ module RubyNext
968
1043
  def inline_blocks(source)
969
1044
  source.gsub(/(?:do|{) \|_, __i__\|\n\s*([^\n]+)\n\s*(?:end|})/, '{ |_, __i__| \1 }')
970
1045
  end
1046
+
1047
+ # Value could be omitted for mass assignment
1048
+ def build_var_assignment(var, value = nil)
1049
+ unless var.is_a?(::Parser::AST::Node)
1050
+ lvars << var
1051
+ return s(:lvasgn, *[var, value].compact)
1052
+ end
1053
+
1054
+ asign_type = :"#{var.type.to_s[0]}vasgn"
1055
+
1056
+ s(asign_type, *[var.children[0], value].compact)
1057
+ end
971
1058
  end
972
1059
  end
973
1060
  end
@@ -8,14 +8,13 @@ module RubyNext
8
8
  SYNTAX_PROBE = "obj = Object.new; def obj.foo() = 42"
9
9
  MIN_SUPPORTED_VERSION = Gem::Version.new("3.0.0")
10
10
 
11
- unless Parser::Meta::NODE_TYPES.include?(:def_e)
12
- def on_def(node)
13
- return on_def_e(node) if node.loc.end.nil?
14
- super(node)
15
- end
11
+ def on_def(node)
12
+ return process_def(node) if endless?(node)
13
+
14
+ super(node)
16
15
  end
17
16
 
18
- def on_def_e(node)
17
+ def process_def(node)
19
18
  context.track! self
20
19
 
21
20
  replace(node.loc.assignment, "; ")
@@ -33,14 +32,12 @@ module RubyNext
33
32
  )
34
33
  end
35
34
 
36
- unless Parser::Meta::NODE_TYPES.include?(:def_e)
37
- def on_defs(node)
38
- return on_defs_e(node) if node.loc.end.nil?
39
- super(node)
40
- end
35
+ def on_defs(node)
36
+ return process_defs(node) if endless?(node)
37
+ super(node)
41
38
  end
42
39
 
43
- def on_defs_e(node)
40
+ def process_defs(node)
44
41
  context.track! self
45
42
 
46
43
  replace(node.loc.assignment, "; ")
@@ -57,6 +54,12 @@ module RubyNext
57
54
  )
58
55
  )
59
56
  end
57
+
58
+ private
59
+
60
+ def endless?(node)
61
+ node.loc.end.nil?
62
+ end
60
63
  end
61
64
  end
62
65
  end
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "ruby-next/language/rewriters/pattern_matching"
4
-
5
3
  module RubyNext
6
4
  module Language
7
5
  module Rewriters
@@ -22,7 +20,7 @@ module RubyNext
22
20
  end
23
21
  end
24
22
 
25
- def on_in_match(node)
23
+ def on_match_pattern(node)
26
24
  @has_find_pattern = false
27
25
  process_regular_node(node).then do |new_node|
28
26
  return new_node unless has_find_pattern
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyNext
4
+ module Language
5
+ module Rewriters
6
+ using RubyNext
7
+
8
+ # Separate pattern matching rewriter for Ruby 2.7 to
9
+ # transpile only `in` patterns
10
+ class InPattern < PatternMatching
11
+ NAME = "pattern-matching-in"
12
+ SYNTAX_PROBE = "1 in 2"
13
+ MIN_SUPPORTED_VERSION = Gem::Version.new("3.0.0")
14
+
15
+ # Make case-match no-op
16
+ def on_case_match(node)
17
+ process_regular_node(node)
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end