ruby-next-core 0.14.0 → 1.0.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 +70 -0
- data/README.md +163 -56
- data/bin/mspec +11 -0
- data/lib/.rbnext/2.1/ruby-next/commands/nextify.rb +295 -0
- data/lib/.rbnext/2.1/ruby-next/core.rb +12 -4
- data/lib/.rbnext/2.1/ruby-next/language.rb +62 -12
- data/lib/.rbnext/2.3/ruby-next/commands/nextify.rb +97 -3
- data/lib/.rbnext/2.3/ruby-next/config.rb +79 -0
- data/lib/.rbnext/2.3/ruby-next/core/data.rb +163 -0
- data/lib/.rbnext/2.3/ruby-next/language/eval.rb +4 -4
- data/lib/.rbnext/2.3/ruby-next/language/rewriters/2.7/args_forward.rb +134 -0
- data/lib/.rbnext/2.3/ruby-next/language/rewriters/2.7/pattern_matching.rb +122 -47
- data/lib/.rbnext/2.3/ruby-next/language/rewriters/base.rb +6 -32
- data/lib/.rbnext/2.3/ruby-next/utils.rb +3 -22
- data/lib/.rbnext/2.6/ruby-next/core/data.rb +163 -0
- data/lib/.rbnext/2.7/ruby-next/core/data.rb +163 -0
- data/lib/.rbnext/2.7/ruby-next/core.rb +12 -4
- data/lib/.rbnext/2.7/ruby-next/language/paco_parsers/string_literals.rb +109 -0
- data/lib/.rbnext/2.7/ruby-next/language/rewriters/2.7/pattern_matching.rb +1095 -0
- data/lib/.rbnext/2.7/ruby-next/language/rewriters/text.rb +132 -0
- data/lib/.rbnext/3.2/ruby-next/commands/base.rb +55 -0
- data/lib/.rbnext/3.2/ruby-next/language/rewriters/2.7/pattern_matching.rb +1095 -0
- data/lib/.rbnext/3.2/ruby-next/rubocop.rb +210 -0
- data/lib/ruby-next/cli.rb +10 -15
- data/lib/ruby-next/commands/nextify.rb +99 -3
- data/lib/ruby-next/config.rb +31 -4
- data/lib/ruby-next/core/data.rb +163 -0
- data/lib/ruby-next/core/matchdata/deconstruct.rb +9 -0
- data/lib/ruby-next/core/matchdata/deconstruct_keys.rb +20 -0
- data/lib/ruby-next/core/matchdata/named_captures.rb +11 -0
- data/lib/ruby-next/core/proc/compose.rb +0 -1
- data/lib/ruby-next/core/refinement/import.rb +44 -36
- data/lib/ruby-next/core/time/deconstruct_keys.rb +30 -0
- data/lib/ruby-next/core.rb +11 -3
- data/lib/ruby-next/irb.rb +24 -0
- data/lib/ruby-next/language/bootsnap.rb +2 -25
- data/lib/ruby-next/language/eval.rb +4 -4
- data/lib/ruby-next/language/paco_parser.rb +7 -0
- data/lib/ruby-next/language/paco_parsers/base.rb +47 -0
- data/lib/ruby-next/language/paco_parsers/comments.rb +26 -0
- data/lib/ruby-next/language/paco_parsers/string_literals.rb +109 -0
- data/lib/ruby-next/language/parser.rb +31 -6
- data/lib/ruby-next/language/rewriters/2.5/rescue_within_block.rb +41 -0
- data/lib/ruby-next/language/rewriters/2.7/args_forward.rb +57 -0
- data/lib/ruby-next/language/rewriters/2.7/pattern_matching.rb +120 -45
- data/lib/ruby-next/language/rewriters/3.0/args_forward_leading.rb +2 -2
- data/lib/ruby-next/language/rewriters/3.1/oneline_pattern_parensless.rb +1 -1
- data/lib/ruby-next/language/rewriters/3.1/shorthand_hash.rb +2 -1
- data/lib/ruby-next/language/rewriters/3.2/anonymous_restargs.rb +104 -0
- data/lib/ruby-next/language/rewriters/abstract.rb +57 -0
- data/lib/ruby-next/language/rewriters/base.rb +6 -32
- data/lib/ruby-next/language/rewriters/edge/it_param.rb +58 -0
- data/lib/ruby-next/language/rewriters/edge.rb +12 -0
- data/lib/ruby-next/language/rewriters/proposed/bind_vars_pattern.rb +3 -0
- data/lib/ruby-next/language/rewriters/proposed/method_reference.rb +9 -20
- data/lib/ruby-next/language/rewriters/text.rb +132 -0
- data/lib/ruby-next/language/runtime.rb +9 -86
- data/lib/ruby-next/language/setup.rb +5 -2
- data/lib/ruby-next/language/unparser.rb +5 -0
- data/lib/ruby-next/language.rb +62 -12
- data/lib/ruby-next/pry.rb +90 -0
- data/lib/ruby-next/rubocop.rb +2 -0
- data/lib/ruby-next/utils.rb +3 -22
- data/lib/ruby-next/version.rb +1 -1
- data/lib/uby-next/irb.rb +3 -0
- data/lib/uby-next/pry.rb +3 -0
- data/lib/uby-next.rb +2 -2
- metadata +70 -10
@@ -1,33 +1,22 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "parser/rubynext"
|
4
|
+
RubyNext::Language.parser_class = ::Parser::RubyNext
|
5
|
+
|
3
6
|
module RubyNext
|
4
7
|
module Language
|
5
8
|
module Rewriters
|
6
|
-
class MethodReference <
|
9
|
+
class MethodReference < Text
|
7
10
|
NAME = "method-reference"
|
8
11
|
SYNTAX_PROBE = "Language.:transform"
|
9
12
|
MIN_SUPPORTED_VERSION = Gem::Version.new(RubyNext::NEXT_VERSION)
|
10
13
|
|
11
|
-
def
|
12
|
-
|
13
|
-
|
14
|
-
receiver, mid = *node.children
|
15
|
-
|
16
|
-
replace(
|
17
|
-
node.children.first.loc.expression.end.join(
|
18
|
-
node.loc.expression.end
|
19
|
-
),
|
20
|
-
".method(:#{mid})"
|
21
|
-
)
|
14
|
+
def safe_rewrite(source)
|
15
|
+
source.gsub(/\.:([\w_]+)/) do |match|
|
16
|
+
context.track! self
|
22
17
|
|
23
|
-
|
24
|
-
|
25
|
-
[
|
26
|
-
receiver,
|
27
|
-
:method,
|
28
|
-
s(:sym, mid)
|
29
|
-
]
|
30
|
-
)
|
18
|
+
".method(:#{$1})"
|
19
|
+
end
|
31
20
|
end
|
32
21
|
end
|
33
22
|
end
|
@@ -0,0 +1,132 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "ruby-next/language/paco_parser"
|
4
|
+
|
5
|
+
module RubyNext
|
6
|
+
module Language
|
7
|
+
module Rewriters
|
8
|
+
class Text < Abstract
|
9
|
+
using RubyNext
|
10
|
+
|
11
|
+
class Normalizer < PacoParsers::Base
|
12
|
+
attr_reader :store
|
13
|
+
|
14
|
+
def initialize
|
15
|
+
@store = []
|
16
|
+
end
|
17
|
+
|
18
|
+
def normalizing(source)
|
19
|
+
many(
|
20
|
+
alt(
|
21
|
+
ruby_comment,
|
22
|
+
ruby_string,
|
23
|
+
ruby_code
|
24
|
+
)
|
25
|
+
).parse(source, with_callstack: true)
|
26
|
+
.then(&:join)
|
27
|
+
.then do
|
28
|
+
if block_given?
|
29
|
+
yield _1
|
30
|
+
else
|
31
|
+
_1
|
32
|
+
end
|
33
|
+
end
|
34
|
+
.then do |new_source|
|
35
|
+
restore(new_source)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def ruby_comment
|
40
|
+
parse_comments.fmap do |result|
|
41
|
+
store << result
|
42
|
+
"# A#{store.size}Я\n"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def ruby_string
|
47
|
+
parse_strings.fmap do |result|
|
48
|
+
result.each_with_object([]) do |(type, str), acc|
|
49
|
+
if type == :literal
|
50
|
+
store << str
|
51
|
+
acc << "_A#{store.size}Я_"
|
52
|
+
else
|
53
|
+
acc << str
|
54
|
+
end
|
55
|
+
acc
|
56
|
+
end.join
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def ruby_code
|
61
|
+
any_char
|
62
|
+
end
|
63
|
+
|
64
|
+
def restore(source)
|
65
|
+
source.gsub(/(?:\# |_)A(\d+)Я(?:_|\n)/m) do |*args|
|
66
|
+
store[$1.to_i - 1]
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def parse_comments
|
71
|
+
memoize { PacoParsers::Comments.new.default }
|
72
|
+
end
|
73
|
+
|
74
|
+
def parse_strings
|
75
|
+
memoize { PacoParsers::StringLiterals.new.default }
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
# Base class for rewriting parsers which adds the #track! method
|
80
|
+
class PacoParser < PacoParsers::Base
|
81
|
+
attr_reader :rewriter, :context
|
82
|
+
|
83
|
+
def initialize(rewriter, context)
|
84
|
+
@rewriter = rewriter
|
85
|
+
@context = context
|
86
|
+
end
|
87
|
+
|
88
|
+
def track!
|
89
|
+
context.track!(rewriter)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
class << self
|
94
|
+
def parser(&block)
|
95
|
+
@paco_parser = Class.new(PacoParser, &block)
|
96
|
+
end
|
97
|
+
|
98
|
+
def paco_parser
|
99
|
+
return @paco_parser if @paco_parser
|
100
|
+
|
101
|
+
superclass.paco_parser if superclass.respond_to?(:paco_parser)
|
102
|
+
end
|
103
|
+
|
104
|
+
def text?
|
105
|
+
true
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
# Rewrite source code by ignoring string literals and comments
|
110
|
+
def rewrite(source)
|
111
|
+
Normalizer.new.normalizing(source) do |normalized|
|
112
|
+
safe_rewrite(normalized)
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
def safe_rewrite(source)
|
117
|
+
source
|
118
|
+
end
|
119
|
+
|
120
|
+
private
|
121
|
+
|
122
|
+
def parse(source)
|
123
|
+
parser_class = self.class.paco_parser
|
124
|
+
raise "No parser defined for #{self.class}" unless parser_class
|
125
|
+
|
126
|
+
paco_parser = self.class.paco_parser.new(self, context)
|
127
|
+
paco_parser.parse(source)
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
@@ -1,9 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "
|
3
|
+
require "require-hooks/setup"
|
4
4
|
|
5
5
|
require "ruby-next"
|
6
|
-
require "ruby-next/utils"
|
7
6
|
require "ruby-next/language"
|
8
7
|
require "ruby-next/language/eval"
|
9
8
|
|
@@ -16,102 +15,26 @@ module RubyNext
|
|
16
15
|
using RubyNext
|
17
16
|
|
18
17
|
class << self
|
19
|
-
|
20
|
-
|
21
|
-
def load(path, wrap: false)
|
22
|
-
raise "RubyNext cannot handle `load(smth, wrap: true)`" if wrap
|
23
|
-
|
24
|
-
contents = File.read(path)
|
18
|
+
def load(path, contents)
|
19
|
+
contents ||= File.read(path)
|
25
20
|
new_contents = transform contents
|
26
21
|
|
27
22
|
RubyNext.debug_source new_contents, path
|
28
23
|
|
29
|
-
|
30
|
-
true
|
24
|
+
new_contents
|
31
25
|
end
|
32
26
|
|
33
27
|
def transform(contents, **options)
|
34
28
|
Language.transform(contents, rewriters: Language.current_rewriters, **options)
|
35
29
|
end
|
36
|
-
|
37
|
-
def feature_path(path)
|
38
|
-
path = resolve_feature_path(path)
|
39
|
-
return if path.nil?
|
40
|
-
return if File.extname(path) != ".rb"
|
41
|
-
return unless Language.transformable?(path)
|
42
|
-
path
|
43
|
-
end
|
44
|
-
|
45
|
-
if defined?(JRUBY_VERSION) || defined?(TruffleRuby)
|
46
|
-
def evaluate(code, filepath)
|
47
|
-
new_toplevel.eval(code, filepath)
|
48
|
-
end
|
49
|
-
|
50
|
-
def new_toplevel
|
51
|
-
# Create new "toplevel" binding to avoid lexical scope re-use
|
52
|
-
# (aka "leaking refinements")
|
53
|
-
eval "proc{binding}.call", TOPLEVEL_BINDING, __FILE__, __LINE__
|
54
|
-
end
|
55
|
-
else
|
56
|
-
def evaluate(code, filepath)
|
57
|
-
# This is workaround to solve the "leaking refinements" problem in MRI
|
58
|
-
RubyVM::InstructionSequence.compile(code, filepath).then do |iseq|
|
59
|
-
iseq.eval
|
60
|
-
end
|
61
|
-
end
|
62
|
-
end
|
63
30
|
end
|
64
31
|
end
|
65
32
|
end
|
66
33
|
end
|
67
34
|
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
def require(path)
|
74
|
-
realpath = RubyNext::Language::Runtime.feature_path(path)
|
75
|
-
return require_without_ruby_next(path) unless realpath
|
76
|
-
|
77
|
-
return false if $LOADED_FEATURES.include?(realpath)
|
78
|
-
|
79
|
-
$LOADED_FEATURES << realpath
|
80
|
-
|
81
|
-
RubyNext::Language::Runtime.load(realpath)
|
82
|
-
|
83
|
-
true
|
84
|
-
rescue => e
|
85
|
-
$LOADED_FEATURES.delete realpath
|
86
|
-
RubyNext.warn "RubyNext failed to require '#{path}': #{e.message}"
|
87
|
-
require_without_ruby_next(path)
|
88
|
-
end
|
89
|
-
|
90
|
-
alias_method :require_relative_without_ruby_next, :require_relative
|
91
|
-
def require_relative(path)
|
92
|
-
loc = caller_locations(1..1).first
|
93
|
-
from = loc.absolute_path || loc.path || File.join(Dir.pwd, "main")
|
94
|
-
realpath = File.absolute_path(
|
95
|
-
File.join(
|
96
|
-
File.dirname(File.absolute_path(from)),
|
97
|
-
path
|
98
|
-
)
|
99
|
-
)
|
100
|
-
require(realpath)
|
101
|
-
rescue => e
|
102
|
-
RubyNext.warn "RubyNext failed to require relative '#{path}' from #{from}: #{e.message}"
|
103
|
-
require_relative_without_ruby_next(path)
|
104
|
-
end
|
105
|
-
|
106
|
-
alias_method :load_without_ruby_next, :load
|
107
|
-
def load(path, wrap = false)
|
108
|
-
realpath = RubyNext::Language::Runtime.feature_path(path)
|
109
|
-
|
110
|
-
return load_without_ruby_next(path, wrap) unless realpath
|
111
|
-
|
112
|
-
RubyNext::Language::Runtime.load(realpath, wrap: wrap)
|
113
|
-
rescue => e
|
114
|
-
RubyNext.warn "RubyNext failed to load '#{path}': #{e.message}"
|
115
|
-
load_without_ruby_next(path)
|
116
|
-
end
|
35
|
+
RequireHooks.source_transform(
|
36
|
+
patterns: RubyNext::Language.include_patterns,
|
37
|
+
exclude_patterns: RubyNext::Language.exclude_patterns
|
38
|
+
) do |path, contents|
|
39
|
+
RubyNext::Language::Runtime.load(path, contents)
|
117
40
|
end
|
@@ -12,7 +12,10 @@ module RubyNext
|
|
12
12
|
return if File.directory?(target_dir)
|
13
13
|
|
14
14
|
Dir.chdir(root_dir) do
|
15
|
-
|
15
|
+
command = "bundle exec ruby-next nextify " \
|
16
|
+
"./#{lib_dir} -o #{target_dir} --min-version=#{RubyNext.current_ruby_version}"
|
17
|
+
|
18
|
+
unless system("#{command} > /dev/null 2>&1")
|
16
19
|
RubyNext.warn "Traspiled files are missing in: #{target_dir}. \n" \
|
17
20
|
"Make sure you have gem 'ruby-next' in your Gemfile to auto-transpile the required files from source on load. " \
|
18
21
|
"Otherwise the code from #{root_dir} may not work correctly."
|
@@ -43,7 +46,7 @@ module RubyNext
|
|
43
46
|
|
44
47
|
dirname = File.realpath(dirname)
|
45
48
|
|
46
|
-
return if Language.runtime? && Language.
|
49
|
+
return if Language.runtime? && Language.target_dir?(dirname)
|
47
50
|
|
48
51
|
next_dirname = File.join(dirname, rbnext_dir)
|
49
52
|
|
@@ -5,6 +5,11 @@ save_verbose, $VERBOSE = $VERBOSE, nil
|
|
5
5
|
require "parser/current"
|
6
6
|
$VERBOSE = save_verbose
|
7
7
|
|
8
|
+
# For backward compatibility with older Unparser for EOL Rubies
|
9
|
+
if !Parser::Lexer.const_defined?(:ESCAPES)
|
10
|
+
Parser::Lexer::ESCAPES = Parser::LexerStrings::ESCAPES
|
11
|
+
end
|
12
|
+
|
8
13
|
require "unparser"
|
9
14
|
|
10
15
|
# For backward compatibility with older Unparser
|
data/lib/ruby-next/language.rb
CHANGED
@@ -1,9 +1,12 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
gem
|
4
|
-
|
3
|
+
# Checking gem specs doesn't work in ruby.wasm
|
4
|
+
unless RUBY_PLATFORM.match?(/wasm/)
|
5
|
+
gem "ruby-next-parser", ">= 2.8.0.3"
|
6
|
+
gem "unparser", ">= 0.4.7"
|
7
|
+
end
|
5
8
|
|
6
|
-
require "set"
|
9
|
+
require "set" # rubocop:disable Lint/RedundantRequireStatement
|
7
10
|
|
8
11
|
require "ruby-next"
|
9
12
|
|
@@ -62,8 +65,15 @@ module RubyNext
|
|
62
65
|
end
|
63
66
|
|
64
67
|
class << self
|
68
|
+
attr_reader :include_patterns
|
69
|
+
attr_reader :exclude_patterns
|
70
|
+
|
71
|
+
def watch_dirs
|
72
|
+
warn "[DEPRECATED] Use `RubyNext::Language.include_patterns` instead of `RubyNext::Language.watch_dirs`"
|
73
|
+
@watch_dirs
|
74
|
+
end
|
75
|
+
|
65
76
|
attr_accessor :rewriters
|
66
|
-
attr_reader :watch_dirs
|
67
77
|
|
68
78
|
attr_accessor :strategy
|
69
79
|
|
@@ -95,14 +105,17 @@ module RubyNext
|
|
95
105
|
end
|
96
106
|
|
97
107
|
def transform(source, rewriters: self.rewriters, using: RubyNext::Core.refine?, context: TransformContext.new)
|
108
|
+
text_rewriters, ast_rewriters = rewriters.partition(&:text?)
|
109
|
+
|
98
110
|
retried = 0
|
99
|
-
new_source =
|
111
|
+
new_source = text_rewrite(source, rewriters: text_rewriters, using: using, context: context)
|
112
|
+
|
100
113
|
begin
|
101
114
|
new_source =
|
102
115
|
if mode == :rewrite
|
103
|
-
rewrite(
|
116
|
+
rewrite(new_source, rewriters: ast_rewriters, using: using, context: context)
|
104
117
|
else
|
105
|
-
regenerate(
|
118
|
+
regenerate(new_source, rewriters: ast_rewriters, using: using, context: context)
|
106
119
|
end
|
107
120
|
rescue Unparser::UnknownNodeError => err
|
108
121
|
RubyNext.warn "Ruby Next fallbacks to \"rewrite\" transpiling mode since the version of Unparser you use doesn't support some syntax yet: #{err.message}.\n" \
|
@@ -119,8 +132,17 @@ module RubyNext
|
|
119
132
|
Core.inject! new_source.dup
|
120
133
|
end
|
121
134
|
|
135
|
+
def target_dir?(dirname)
|
136
|
+
# fnmatch? requires a file name, not a folder
|
137
|
+
fname = File.join(dirname, "x.rb")
|
138
|
+
|
139
|
+
include_patterns.any? { |pattern| File.fnmatch?(pattern, fname) } &&
|
140
|
+
exclude_patterns.none? { |pattern| File.fnmatch?(pattern, fname) }
|
141
|
+
end
|
142
|
+
|
122
143
|
def transformable?(path)
|
123
|
-
|
144
|
+
include_patterns.any? { |pattern| File.fnmatch?(pattern, path) } &&
|
145
|
+
exclude_patterns.none? { |pattern| File.fnmatch?(pattern, path) }
|
124
146
|
end
|
125
147
|
|
126
148
|
# Rewriters required for the current version
|
@@ -165,14 +187,36 @@ module RubyNext
|
|
165
187
|
end
|
166
188
|
end
|
167
189
|
|
190
|
+
def text_rewrite(source, rewriters:, using:, context:)
|
191
|
+
rewriters.inject(source) do |src, rewriter|
|
192
|
+
rewriter.new(context).rewrite(src)
|
193
|
+
end.then do |new_source|
|
194
|
+
next source unless context.dirty?
|
195
|
+
|
196
|
+
new_source
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
168
200
|
attr_writer :watch_dirs
|
201
|
+
attr_writer :include_patterns, :exclude_patterns
|
169
202
|
end
|
170
203
|
|
171
204
|
self.rewriters = []
|
172
|
-
self.watch_dirs =
|
205
|
+
self.watch_dirs = [].tap do |dirs|
|
206
|
+
# For backward compatibility
|
207
|
+
dirs.define_singleton_method(:<<) do |dir|
|
208
|
+
super(dir)
|
209
|
+
RubyNext::Language.include_patterns << File.join(dir, "*.rb")
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
self.include_patterns = %w[app lib spec test].map { |path| File.join(Dir.pwd, path, "*.rb") }
|
214
|
+
self.exclude_patterns = %w[vendor/bundle].map { |path| File.join(Dir.pwd, path, "*") }
|
173
215
|
self.mode = ENV.fetch("RUBY_NEXT_TRANSPILE_MODE", "rewrite").to_sym
|
174
216
|
|
217
|
+
require "ruby-next/language/rewriters/abstract"
|
175
218
|
require "ruby-next/language/rewriters/base"
|
219
|
+
require "ruby-next/language/rewriters/text"
|
176
220
|
|
177
221
|
require "ruby-next/language/rewriters/2.1/numeric_literals"
|
178
222
|
rewriters << Rewriters::NumericLiterals
|
@@ -186,6 +230,9 @@ module RubyNext
|
|
186
230
|
require "ruby-next/language/rewriters/2.3/safe_navigation"
|
187
231
|
rewriters << Rewriters::SafeNavigation
|
188
232
|
|
233
|
+
require "ruby-next/language/rewriters/2.5/rescue_within_block"
|
234
|
+
rewriters << Rewriters::RescueWithinBlock
|
235
|
+
|
189
236
|
require "ruby-next/language/rewriters/2.7/args_forward"
|
190
237
|
rewriters << Rewriters::ArgsForward
|
191
238
|
|
@@ -209,7 +256,7 @@ module RubyNext
|
|
209
256
|
rewriters << Rewriters::InPattern
|
210
257
|
|
211
258
|
require "ruby-next/language/rewriters/3.0/endless_method"
|
212
|
-
|
259
|
+
rewriters << RubyNext::Language::Rewriters::EndlessMethod
|
213
260
|
|
214
261
|
require "ruby-next/language/rewriters/3.1/oneline_pattern_parensless"
|
215
262
|
rewriters << Rewriters::OnelinePatternParensless
|
@@ -229,16 +276,19 @@ module RubyNext
|
|
229
276
|
require "ruby-next/language/rewriters/3.1/shorthand_hash"
|
230
277
|
rewriters << RubyNext::Language::Rewriters::ShorthandHash
|
231
278
|
|
279
|
+
require "ruby-next/language/rewriters/3.2/anonymous_restargs"
|
280
|
+
rewriters << RubyNext::Language::Rewriters::AnonymousRestArgs
|
281
|
+
|
232
282
|
# Put endless range in the end, 'cause Parser fails to parse it in
|
233
283
|
# pattern matching
|
234
284
|
require "ruby-next/language/rewriters/2.6/endless_range"
|
235
285
|
rewriters << Rewriters::EndlessRange
|
236
286
|
|
237
|
-
if
|
287
|
+
if RubyNext.edge_syntax?
|
238
288
|
require "ruby-next/language/rewriters/edge"
|
239
289
|
end
|
240
290
|
|
241
|
-
if
|
291
|
+
if RubyNext.proposed_syntax?
|
242
292
|
require "ruby-next/language/rewriters/proposed"
|
243
293
|
end
|
244
294
|
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# This file contains patches for Pry integration.
|
4
|
+
# It's supposed to be required inside .pryrc files.
|
5
|
+
|
6
|
+
require "ruby-next/language/setup"
|
7
|
+
require "ruby-next/language/runtime"
|
8
|
+
|
9
|
+
# Enables refinements by injecting "using RubyNext"
|
10
|
+
# before Pry copies and memorizes the TOPLEVEL_BINDING.
|
11
|
+
Pry.singleton_class.prepend(Module.new do
|
12
|
+
def toplevel_binding
|
13
|
+
unless defined?(@_using_injected) && @_using_injected
|
14
|
+
orig_binding = super
|
15
|
+
|
16
|
+
# Copy TOPLEVEL_BINDING without local variables.
|
17
|
+
TOPLEVEL_BINDING.eval <<-RUBY
|
18
|
+
using RubyNext
|
19
|
+
|
20
|
+
def self.__pry__
|
21
|
+
binding
|
22
|
+
end
|
23
|
+
|
24
|
+
Pry.toplevel_binding = __pry__
|
25
|
+
|
26
|
+
class << self; undef __pry__; end
|
27
|
+
RUBY
|
28
|
+
|
29
|
+
# Inject local variables from the original binding.
|
30
|
+
orig_binding.local_variables.each do |var|
|
31
|
+
value = orig_binding.local_variable_get(var)
|
32
|
+
@toplevel_binding.local_variable_set(var, value)
|
33
|
+
end
|
34
|
+
|
35
|
+
@_using_injected = true
|
36
|
+
end
|
37
|
+
|
38
|
+
super
|
39
|
+
end
|
40
|
+
end)
|
41
|
+
|
42
|
+
# Enables edge Ruby syntax by transpiling the code
|
43
|
+
# before it's evaluated in the context of a binding.
|
44
|
+
Pry.prepend(Module.new do
|
45
|
+
def current_binding
|
46
|
+
super.tap do |obj|
|
47
|
+
next if obj.respond_to?(:__nextified__)
|
48
|
+
|
49
|
+
obj.instance_eval do
|
50
|
+
def eval(code, *args)
|
51
|
+
new_code = ::RubyNext::Language::Runtime.transform(code, using: false)
|
52
|
+
|
53
|
+
super(new_code, *args)
|
54
|
+
end
|
55
|
+
|
56
|
+
def __nextified__
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end)
|
62
|
+
|
63
|
+
# Enables edge Ruby syntax for multi-line input.
|
64
|
+
Pry::Code.singleton_class.prepend(Module.new do
|
65
|
+
def complete_expression?(str)
|
66
|
+
silence_stderr do
|
67
|
+
::RubyNext::Language.parser_class.parse(str)
|
68
|
+
end
|
69
|
+
|
70
|
+
true
|
71
|
+
rescue Parser::SyntaxError => ex
|
72
|
+
case ex.message
|
73
|
+
when /unexpected token \$end/
|
74
|
+
false
|
75
|
+
else
|
76
|
+
true
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
private
|
81
|
+
|
82
|
+
def silence_stderr
|
83
|
+
stderr = StringIO.new
|
84
|
+
orig_stderr, $stderr = $stderr, stderr
|
85
|
+
|
86
|
+
yield
|
87
|
+
|
88
|
+
$stderr = orig_stderr
|
89
|
+
end
|
90
|
+
end)
|
data/lib/ruby-next/rubocop.rb
CHANGED
@@ -4,6 +4,7 @@
|
|
4
4
|
# edge features and fix some bugs with 2.7+ syntax
|
5
5
|
|
6
6
|
require "parser/ruby-next/version"
|
7
|
+
require "ruby-next/config"
|
7
8
|
require "ruby-next/language/parser"
|
8
9
|
|
9
10
|
module RuboCop
|
@@ -38,6 +39,7 @@ module RuboCop
|
|
38
39
|
def parser_class(version)
|
39
40
|
return super unless version == RUBY_NEXT_VERSION
|
40
41
|
|
42
|
+
require "parser/rubynext"
|
41
43
|
Parser::RubyNext
|
42
44
|
end
|
43
45
|
end
|
data/lib/ruby-next/utils.rb
CHANGED
@@ -4,28 +4,6 @@ module RubyNext
|
|
4
4
|
module Utils
|
5
5
|
module_function
|
6
6
|
|
7
|
-
if $LOAD_PATH.respond_to?(:resolve_feature_path)
|
8
|
-
def resolve_feature_path(feature)
|
9
|
-
$LOAD_PATH.resolve_feature_path(feature)&.last
|
10
|
-
rescue LoadError
|
11
|
-
end
|
12
|
-
else
|
13
|
-
def resolve_feature_path(path)
|
14
|
-
if File.file?(relative = File.expand_path(path))
|
15
|
-
path = relative
|
16
|
-
end
|
17
|
-
|
18
|
-
path = "#{path}.rb" if File.extname(path).empty?
|
19
|
-
|
20
|
-
return path if Pathname.new(path).absolute?
|
21
|
-
|
22
|
-
$LOAD_PATH.find do |lp|
|
23
|
-
lpath = File.join(lp, path)
|
24
|
-
return File.realpath(lpath) if File.file?(lpath)
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
7
|
def source_with_lines(source, path)
|
30
8
|
source.lines.map.with_index do |line, i|
|
31
9
|
"#{(i + 1).to_s.rjust(4)}: #{line}"
|
@@ -36,6 +14,7 @@ module RubyNext
|
|
36
14
|
|
37
15
|
# Returns true if modules refinement is supported in current version
|
38
16
|
def refine_modules?
|
17
|
+
save_verbose, $VERBOSE = $VERBOSE, nil
|
39
18
|
@refine_modules ||=
|
40
19
|
begin
|
41
20
|
# Make sure that including modules within refinements works
|
@@ -61,6 +40,8 @@ module RubyNext
|
|
61
40
|
true
|
62
41
|
rescue TypeError, NoMethodError
|
63
42
|
false
|
43
|
+
ensure
|
44
|
+
$VERBOSE = save_verbose
|
64
45
|
end
|
65
46
|
end
|
66
47
|
end
|
data/lib/ruby-next/version.rb
CHANGED
data/lib/uby-next/irb.rb
ADDED
data/lib/uby-next/pry.rb
ADDED
data/lib/uby-next.rb
CHANGED
@@ -9,7 +9,7 @@ require "ruby-next/core/runtime"
|
|
9
9
|
|
10
10
|
using RubyNext
|
11
11
|
|
12
|
-
RubyNext::Language.
|
12
|
+
RubyNext::Language.include_patterns << File.join(Dir.pwd, ".rb")
|
13
13
|
|
14
14
|
require "stringio"
|
15
15
|
|
@@ -36,7 +36,7 @@ end
|
|
36
36
|
at_exit do
|
37
37
|
$stderr = orig_stderr
|
38
38
|
|
39
|
-
if NoMethodError === $! || SyntaxError === $!
|
39
|
+
if NoMethodError === $! || SyntaxError === $! || NameError === $!
|
40
40
|
if $0 && File.exist?($0)
|
41
41
|
load($0)
|
42
42
|
exit!(0)
|