ruby-next-core 0.14.0 → 0.15.1
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 +4 -4
- data/CHANGELOG.md +22 -0
- data/README.md +36 -2
- data/lib/.rbnext/2.1/ruby-next/core.rb +1 -1
- data/lib/.rbnext/2.1/ruby-next/language.rb +3 -0
- data/lib/.rbnext/2.3/ruby-next/commands/nextify.rb +14 -0
- data/lib/.rbnext/2.3/ruby-next/language/rewriters/2.7/pattern_matching.rb +78 -38
- data/lib/.rbnext/2.3/ruby-next/language/rewriters/base.rb +1 -1
- data/lib/.rbnext/2.7/ruby-next/core.rb +1 -1
- data/lib/.rbnext/2.7/ruby-next/language/rewriters/2.7/pattern_matching.rb +1060 -0
- data/lib/ruby-next/cli.rb +10 -12
- data/lib/ruby-next/commands/nextify.rb +14 -0
- data/lib/ruby-next/core/proc/compose.rb +0 -1
- data/lib/ruby-next/core/refinement/import.rb +1 -1
- data/lib/ruby-next/core.rb +1 -1
- data/lib/ruby-next/irb.rb +24 -0
- data/lib/ruby-next/language/rewriters/2.5/rescue_within_block.rb +41 -0
- data/lib/ruby-next/language/rewriters/2.7/pattern_matching.rb +78 -38
- data/lib/ruby-next/language/rewriters/base.rb +1 -1
- data/lib/ruby-next/language/runtime.rb +1 -1
- data/lib/ruby-next/language/setup.rb +1 -1
- data/lib/ruby-next/language.rb +3 -0
- data/lib/ruby-next/pry.rb +90 -0
- data/lib/ruby-next/version.rb +1 -1
- data/lib/uby-next/irb.rb +3 -0
- data/lib/uby-next/pry.rb +3 -0
- metadata +9 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fc36fd395eedfde5c29e65f1f3a75c683630d5111349b3070d3b4e6d200477ad
|
4
|
+
data.tar.gz: e53e28aec62f7e425a98ba1eeb9591778ca1dbab13a0390113fc7440aab9663d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 50069c2ef6b59005d7efc640e1d84a74e17e4e385aaadce3ac54c2e3e061c7f71b727943140899210af997196f0bdf5a1157b86b97ce7af3de307e68a1cffe12
|
7
|
+
data.tar.gz: edf464100a254380bee320c586f48afc35782027303840fd319f32260ac5cf771c6f349d7447b9ed2f8a55bab424395664099dbd58600a05ffcd79e49080509f
|
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,28 @@
|
|
2
2
|
|
3
3
|
## master
|
4
4
|
|
5
|
+
## 0.15.1 (2022-04-05)
|
6
|
+
|
7
|
+
- Fix transpiling `rescue` within nested blocks. ([@palkan][])
|
8
|
+
|
9
|
+
## 0.15.0 (2022-03-21)
|
10
|
+
|
11
|
+
- Support IRB ([@palkan][])
|
12
|
+
|
13
|
+
- Create empty `.rbnext` folder during `nextify` if nothing to transpile. ([@palkan][])
|
14
|
+
|
15
|
+
This would prevent from auto-transpiling a library every time when no files should be transpiled.
|
16
|
+
|
17
|
+
- Auto-transpile using the current Ruby version. ([@palkan][])
|
18
|
+
|
19
|
+
- Support Pry. ([@baygeldin][])
|
20
|
+
|
21
|
+
- Add `rescue/ensure/else` within block rewriter for Ruby < 2.5. ([@fargelus][])
|
22
|
+
|
23
|
+
## 0.14.1 (2022-01-21)
|
24
|
+
|
25
|
+
- Fix nested find patterns transpiling. ([@palkan][])
|
26
|
+
|
5
27
|
## 0.14.0 🎄
|
6
28
|
|
7
29
|
- Add `Integer.try_convert`. ([@palkan][])
|
data/README.md
CHANGED
@@ -71,6 +71,8 @@ _Please, submit a PR to add your project to the list!_
|
|
71
71
|
- [`ruby -ruby-next`](#uby-next)
|
72
72
|
- [Logging & Debugging](#logging-and-debugging)
|
73
73
|
- [RuboCop](#rubocop)
|
74
|
+
- [Using with IRB](#irb)
|
75
|
+
- [Using with Pry](#pry)
|
74
76
|
- [Using with EOL Rubies](#using-with-eol-rubies)
|
75
77
|
- [Proposed & edge features](#proposed-and-edge-features)
|
76
78
|
- [Known limitations](#known-limitations)
|
@@ -454,6 +456,38 @@ AllCops:
|
|
454
456
|
|
455
457
|
**NOTE:** you need `ruby-next` gem available in the environment where you run RuboCop (having `ruby-next-core` is not enough).
|
456
458
|
|
459
|
+
## IRB
|
460
|
+
|
461
|
+
Ruby Next supports IRB. In order to enable edge Ruby features for your REPL, add the following line to your `.irbrc`:
|
462
|
+
|
463
|
+
```ruby
|
464
|
+
require "ruby-next/irb"
|
465
|
+
```
|
466
|
+
|
467
|
+
Alternatively, you can require it at startup:
|
468
|
+
|
469
|
+
```sh
|
470
|
+
irb -r ruby-next/irb
|
471
|
+
# or
|
472
|
+
irb -ruby-next/irb
|
473
|
+
```
|
474
|
+
|
475
|
+
## Pry
|
476
|
+
|
477
|
+
Ruby Next supports Pry. In order to enable edge Ruby features for your REPL, add the following line to your `.pryrc`:
|
478
|
+
|
479
|
+
```ruby
|
480
|
+
require "ruby-next/pry"
|
481
|
+
```
|
482
|
+
|
483
|
+
Alternatively, you can require it at startup:
|
484
|
+
|
485
|
+
```sh
|
486
|
+
pry -r ruby-next/pry
|
487
|
+
# or
|
488
|
+
pry -ruby-next/pry
|
489
|
+
```
|
490
|
+
|
457
491
|
## Using with EOL Rubies
|
458
492
|
|
459
493
|
We currently provide support for Ruby 2.2, 2.3 and 2.4.
|
@@ -510,9 +544,9 @@ These features are disabled by default, you must opt-in in one of the following
|
|
510
544
|
# It's important to load language module first
|
511
545
|
require "ruby-next/language"
|
512
546
|
|
513
|
-
require "ruby-next/language/edge"
|
547
|
+
require "ruby-next/language/rewriters/edge"
|
514
548
|
# or
|
515
|
-
require "ruby-next/language/proposed"
|
549
|
+
require "ruby-next/language/rewriters/proposed"
|
516
550
|
|
517
551
|
# and then activate the runtime mode
|
518
552
|
require "ruby-next/language/runtime"
|
@@ -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/, "")
|
66
66
|
end
|
67
67
|
|
68
68
|
def build_location(trace_locations)
|
@@ -186,6 +186,9 @@ module RubyNext
|
|
186
186
|
require "ruby-next/language/rewriters/2.3/safe_navigation"
|
187
187
|
rewriters << Rewriters::SafeNavigation
|
188
188
|
|
189
|
+
require "ruby-next/language/rewriters/2.5/rescue_within_block"
|
190
|
+
rewriters << Rewriters::RescueWithinBlock
|
191
|
+
|
189
192
|
require "ruby-next/language/rewriters/2.7/args_forward"
|
190
193
|
rewriters << Rewriters::ArgsForward
|
191
194
|
|
@@ -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)
|
@@ -150,6 +152,7 @@ module RubyNext
|
|
150
152
|
transpile path, contents, version: version
|
151
153
|
rescue SyntaxError, StandardError => e
|
152
154
|
warn "Failed to transpile #{path}: #{e.class} — #{e.message}"
|
155
|
+
warn e.backtrace.take(10).join("\n") if ENV["RUBY_NEXT_DEBUG"] == "1"
|
153
156
|
exit 1
|
154
157
|
end
|
155
158
|
|
@@ -185,6 +188,17 @@ module RubyNext
|
|
185
188
|
FileUtils.rm_r(next_dir_path)
|
186
189
|
end
|
187
190
|
|
191
|
+
def ensure_rbnext!
|
192
|
+
return if CLI.dry_run? || stdout?
|
193
|
+
|
194
|
+
return if File.directory?(next_dir_path)
|
195
|
+
|
196
|
+
return if next_dir_path.end_with?(".rb")
|
197
|
+
|
198
|
+
FileUtils.mkdir_p next_dir_path
|
199
|
+
File.write(File.join(next_dir_path, ".keep"), "")
|
200
|
+
end
|
201
|
+
|
188
202
|
def next_dir_path
|
189
203
|
@next_dir_path ||= (out_path || File.join(lib_path, RUBY_NEXT_DIR))
|
190
204
|
end
|
@@ -182,7 +182,6 @@ module RubyNext
|
|
182
182
|
end
|
183
183
|
end
|
184
184
|
|
185
|
-
# rubocop:disable Style/MethodMissingSuper
|
186
185
|
# rubocop:disable Style/MissingRespondToMissing
|
187
186
|
class Noop < Base
|
188
187
|
# Return node itself, no memoization
|
@@ -243,6 +242,7 @@ module RubyNext
|
|
243
242
|
|
244
243
|
@deconstructed_keys = {}
|
245
244
|
@predicates = Predicates::CaseIn.new
|
245
|
+
@lvars = []
|
246
246
|
|
247
247
|
matchee_ast =
|
248
248
|
s(:begin, s(:lvasgn, MATCHEE, node.children[0]))
|
@@ -272,6 +272,7 @@ module RubyNext
|
|
272
272
|
|
273
273
|
@deconstructed_keys = {}
|
274
274
|
@predicates = Predicates::Noop.new
|
275
|
+
@lvars = []
|
275
276
|
|
276
277
|
matchee =
|
277
278
|
s(:begin, s(:lvasgn, MATCHEE, node.children[0]))
|
@@ -282,10 +283,12 @@ module RubyNext
|
|
282
283
|
arr: MATCHEE_ARR,
|
283
284
|
hash: MATCHEE_HASH
|
284
285
|
) do
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
286
|
+
with_declared_locals do
|
287
|
+
send(
|
288
|
+
:"#{node.children[1].type}_clause",
|
289
|
+
node.children[1]
|
290
|
+
)
|
291
|
+
end.then do |node|
|
289
292
|
s(:begin,
|
290
293
|
s(:or,
|
291
294
|
node,
|
@@ -311,6 +314,7 @@ module RubyNext
|
|
311
314
|
|
312
315
|
@deconstructed_keys = {}
|
313
316
|
@predicates = Predicates::Noop.new
|
317
|
+
@lvars = []
|
314
318
|
|
315
319
|
matchee =
|
316
320
|
s(:begin, s(:lvasgn, MATCHEE, node.children[0]))
|
@@ -321,10 +325,12 @@ module RubyNext
|
|
321
325
|
arr: MATCHEE_ARR,
|
322
326
|
hash: MATCHEE_HASH
|
323
327
|
) do
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
+
with_declared_locals do
|
329
|
+
send(
|
330
|
+
:"#{node.children[1].type}_clause",
|
331
|
+
node.children[1]
|
332
|
+
)
|
333
|
+
end
|
328
334
|
end
|
329
335
|
|
330
336
|
node.updated(
|
@@ -395,13 +401,15 @@ module RubyNext
|
|
395
401
|
def build_when_clause(clause)
|
396
402
|
predicates.reset!
|
397
403
|
[
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
404
|
+
with_declared_locals do
|
405
|
+
with_guard(
|
406
|
+
send(
|
407
|
+
:"#{clause.children[0].type}_clause",
|
408
|
+
clause.children[0]
|
409
|
+
),
|
410
|
+
clause.children[1] # guard
|
411
|
+
)
|
412
|
+
end,
|
405
413
|
process(clause.children[2] || s(:nil)) # expression
|
406
414
|
].then do |children|
|
407
415
|
s(:when, *children)
|
@@ -442,7 +450,7 @@ module RubyNext
|
|
442
450
|
var = node.children[0]
|
443
451
|
return s(:true) if var == :_
|
444
452
|
|
445
|
-
check_match_var_alternation!(var)
|
453
|
+
check_match_var_alternation!(var)
|
446
454
|
|
447
455
|
s(:begin,
|
448
456
|
s(:or,
|
@@ -541,11 +549,10 @@ module RubyNext
|
|
541
549
|
def array_find(head, *nodes, tail)
|
542
550
|
index = s(:lvar, :__i__)
|
543
551
|
|
544
|
-
match_vars = []
|
545
|
-
|
546
552
|
head_match =
|
547
553
|
unless head.children.empty?
|
548
|
-
|
554
|
+
# we only need to call this to track the lvar usage
|
555
|
+
build_var_assignment(head.children[0].children[0])
|
549
556
|
|
550
557
|
arr_take = s(:send,
|
551
558
|
s(:lvar, locals[:arr]),
|
@@ -557,16 +564,19 @@ module RubyNext
|
|
557
564
|
|
558
565
|
tail_match =
|
559
566
|
unless tail.children.empty?
|
560
|
-
|
567
|
+
# we only need to call this to track the lvar usage
|
568
|
+
build_var_assignment(tail.children[0].children[0])
|
561
569
|
|
562
570
|
match_var_clause(tail.children[0], arr_slice(index + nodes.size, -1))
|
563
571
|
end
|
564
572
|
|
565
573
|
nodes.each do |node|
|
566
574
|
if node.type == :match_var
|
567
|
-
|
575
|
+
# we only need to call this to track the lvar usage
|
576
|
+
build_var_assignment(node.children[0])
|
568
577
|
elsif node.type == :match_as
|
569
|
-
|
578
|
+
# we only need to call this to track the lvar usage
|
579
|
+
build_var_assignment(node.children[1].children[0])
|
570
580
|
end
|
571
581
|
end
|
572
582
|
|
@@ -594,19 +604,7 @@ module RubyNext
|
|
594
604
|
s(:args,
|
595
605
|
s(:arg, :_),
|
596
606
|
s(:arg, :__i__)),
|
597
|
-
pattern)
|
598
|
-
next block if match_vars.empty?
|
599
|
-
|
600
|
-
# We need to declare match vars outside of `find` block
|
601
|
-
locals_declare = s(:begin, s(:masgn,
|
602
|
-
s(:mlhs, *match_vars),
|
603
|
-
s(:nil)))
|
604
|
-
|
605
|
-
s(:begin,
|
606
|
-
s(:or,
|
607
|
-
locals_declare,
|
608
|
-
block))
|
609
|
-
end
|
607
|
+
pattern)
|
610
608
|
end
|
611
609
|
|
612
610
|
def array_match_rest(index, node, *tail)
|
@@ -649,6 +647,14 @@ module RubyNext
|
|
649
647
|
end
|
650
648
|
end
|
651
649
|
|
650
|
+
def find_pattern_array_element(node, index)
|
651
|
+
element = arr_item_at(index)
|
652
|
+
locals.with(arr: locals[:arr, index]) do
|
653
|
+
predicates.push :"i#{index}"
|
654
|
+
find_pattern_clause(node, element).tap { predicates.pop }
|
655
|
+
end
|
656
|
+
end
|
657
|
+
|
652
658
|
def hash_pattern_array_element(node, index)
|
653
659
|
element = arr_item_at(index)
|
654
660
|
locals.with(hash: locals[:arr, index]) do
|
@@ -829,6 +835,15 @@ module RubyNext
|
|
829
835
|
end
|
830
836
|
end
|
831
837
|
|
838
|
+
def find_pattern_hash_element(node, key)
|
839
|
+
element = hash_value_at(key)
|
840
|
+
key_index = deconstructed_key(key)
|
841
|
+
locals.with(arr: locals[:hash, key_index]) do
|
842
|
+
predicates.push :"k#{key_index}"
|
843
|
+
find_pattern_clause(node, element).tap { predicates.pop }
|
844
|
+
end
|
845
|
+
end
|
846
|
+
|
832
847
|
def hash_element(head, *tail)
|
833
848
|
send("#{head.type}_hash_element", head).then do |node|
|
834
849
|
next node if tail.empty?
|
@@ -948,6 +963,24 @@ module RubyNext
|
|
948
963
|
end
|
949
964
|
end
|
950
965
|
|
966
|
+
def with_declared_locals
|
967
|
+
lvars.clear
|
968
|
+
node = yield
|
969
|
+
|
970
|
+
return node if lvars.empty?
|
971
|
+
|
972
|
+
# We need to declare match lvars outside of the outer `find` block,
|
973
|
+
# so we do that for that whole pattern
|
974
|
+
locals_declare = s(:begin, s(:masgn,
|
975
|
+
s(:mlhs, *lvars.uniq.map { |_1| s(:lvasgn, _1) }),
|
976
|
+
s(:nil)))
|
977
|
+
|
978
|
+
s(:begin,
|
979
|
+
s(:or,
|
980
|
+
locals_declare,
|
981
|
+
node))
|
982
|
+
end
|
983
|
+
|
951
984
|
def no_matching_pattern
|
952
985
|
raise_error(
|
953
986
|
:NoMatchingPatternError,
|
@@ -982,13 +1015,17 @@ module RubyNext
|
|
982
1015
|
|
983
1016
|
private
|
984
1017
|
|
985
|
-
attr_reader :deconstructed_keys, :predicates
|
1018
|
+
attr_reader :deconstructed_keys, :predicates, :lvars
|
986
1019
|
|
987
1020
|
# Raise SyntaxError if match-var is used within alternation
|
988
1021
|
# https://github.com/ruby/ruby/blob/672213ef1ca2b71312084057e27580b340438796/compile.c#L5900
|
989
1022
|
def check_match_var_alternation!(name)
|
990
1023
|
return unless locals.key?(ALTERNATION_MARKER)
|
991
1024
|
|
1025
|
+
if name.is_a?(::Parser::AST::Node)
|
1026
|
+
raise ::SyntaxError, "illegal variable in alternative pattern (#{name.children.first})"
|
1027
|
+
end
|
1028
|
+
|
992
1029
|
return if name.start_with?("_")
|
993
1030
|
|
994
1031
|
raise ::SyntaxError, "illegal variable in alternative pattern (#{name})"
|
@@ -1008,7 +1045,10 @@ module RubyNext
|
|
1008
1045
|
|
1009
1046
|
# Value could be omitted for mass assignment
|
1010
1047
|
def build_var_assignment(var, value = nil)
|
1011
|
-
|
1048
|
+
unless var.is_a?(::Parser::AST::Node)
|
1049
|
+
lvars << var
|
1050
|
+
return s(:lvasgn, *[var, value].compact)
|
1051
|
+
end
|
1012
1052
|
|
1013
1053
|
asign_type = :"#{var.type.to_s[0]}vasgn"
|
1014
1054
|
|
@@ -65,7 +65,7 @@ module RubyNext
|
|
65
65
|
end
|
66
66
|
|
67
67
|
class << self
|
68
|
-
# Returns true if the syntax is supported
|
68
|
+
# Returns true if the syntax is not supported
|
69
69
|
# by the current Ruby (performs syntax check, not version check)
|
70
70
|
def unsupported_syntax?
|
71
71
|
save_verbose, $VERBOSE = $VERBOSE, nil
|
@@ -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/, "")
|
66
66
|
end
|
67
67
|
|
68
68
|
def build_location(trace_locations)
|