ruby-next-core 0.11.1 → 0.12.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +14 -0
- data/README.md +2 -0
- data/lib/.rbnext/2.1/ruby-next/core.rb +203 -0
- data/lib/.rbnext/2.3/ruby-next/commands/nextify.rb +1 -1
- data/lib/.rbnext/2.3/ruby-next/language/eval.rb +1 -1
- data/lib/.rbnext/2.3/ruby-next/language/rewriters/base.rb +4 -4
- data/lib/.rbnext/2.3/ruby-next/language/rewriters/endless_range.rb +1 -1
- data/lib/.rbnext/2.3/ruby-next/language/rewriters/pattern_matching.rb +2 -2
- data/lib/.rbnext/2.3/ruby-next/utils.rb +1 -1
- data/lib/ruby-next/core_ext.rb +1 -1
- data/lib/ruby-next/language.rb +6 -0
- data/lib/ruby-next/language/rewriters/numeric_literals.rb +41 -0
- data/lib/ruby-next/language/rewriters/required_kwargs.rb +39 -0
- data/lib/ruby-next/language/rewriters/safe_navigation.rb +42 -29
- data/lib/ruby-next/language/setup.rb +1 -1
- data/lib/ruby-next/language/unparser.rb +5 -0
- data/lib/ruby-next/version.rb +1 -1
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c248b303a7e6990efd5d93e042c4043a61a553fddf880f44d9a2f7f40e66eabb
|
4
|
+
data.tar.gz: 23aa24ec51098f2a73196c2ddb3c4ae1fdeece1b5232cb5832012466080f29e9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1b97768e53ff0e8841fbb7d045358728dcb2208ba79cdb0636b495de3112810b3d8f8deb1cbbe34a5fe52ef79c09044d4871db05caed04b211dfbbca8e6c4238
|
7
|
+
data.tar.gz: 700ad59a1f0e094bf162dc2d2e30af843b4f95b9bfc3d104c58ea2f7d8a46c57537792c507dd0189e2c93850c0cccc4b0e8bb57e10eef22041ee0dac5b4b537c
|
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,20 @@
|
|
2
2
|
|
3
3
|
## master
|
4
4
|
|
5
|
+
## 0.12.0 (2021-01-12)
|
6
|
+
|
7
|
+
- Added required keyword arguments rewriter. ([@palkan][])
|
8
|
+
|
9
|
+
Required kwargs were introduced in 2.1. Now we make them possible in 2.0.
|
10
|
+
|
11
|
+
- Added numeric literals rewriter. ([@palkan][])
|
12
|
+
|
13
|
+
Now it's possible to generate Ruby 2.0 compatible code from `2i + 1/3r`.
|
14
|
+
|
15
|
+
- Fixed several safe navigation (`&.`) bugs. ([@palkan][])
|
16
|
+
|
17
|
+
See [#68](https://github.com/ruby-next/ruby-next/issues/68) and [#69](https://github.com/ruby-next/ruby-next/issues/69).
|
18
|
+
|
5
19
|
## 0.11.1 (2020-12-28)
|
6
20
|
|
7
21
|
- Use separate _namespace_ for proposed features to avoid conflicts with new Ruby version. ([@palkan][])
|
data/README.md
CHANGED
@@ -445,6 +445,8 @@ AllCops:
|
|
445
445
|
|
446
446
|
We currently provide support for Ruby 2.2, 2.3 and 2.4.
|
447
447
|
|
448
|
+
**NOTE:** By "support" here we mean using `ruby-next` CLI and runtime transpiling. Transpiled code may run on Ruby 2.0+.
|
449
|
+
|
448
450
|
Ruby Next itself relies on 2.5 features and contains polyfills only for version 2.5+ (and that won't change).
|
449
451
|
Thus, to make it work with <2.5 we need to backport some APIs ourselves.
|
450
452
|
|
@@ -0,0 +1,203 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "set"
|
4
|
+
|
5
|
+
require "ruby-next/config"
|
6
|
+
require "ruby-next/utils"
|
7
|
+
|
8
|
+
module RubyNext
|
9
|
+
module Core
|
10
|
+
# Patch contains the extension implementation
|
11
|
+
# and meta information (e.g., Ruby version).
|
12
|
+
class Patch
|
13
|
+
attr_reader :refineables, :name, :mod, :method_name, :version, :body, :singleton, :core_ext, :supported, :native, :location
|
14
|
+
|
15
|
+
# Create a new patch for module/class (mod)
|
16
|
+
# with the specified uniq name
|
17
|
+
#
|
18
|
+
# `core_ext` defines the strategy for core extensions:
|
19
|
+
# - :patch — extend class directly
|
20
|
+
# - :prepend — extend class by prepending a module (e.g., when needs `super`)
|
21
|
+
def initialize(mod = nil, method: ::Kernel.raise(::ArgumentError, "missing keyword: method"), version: ::Kernel.raise(::ArgumentError, "missing keyword: version"), name: nil, supported: nil, native: nil, location: nil, refineable: mod, core_ext: :patch, singleton: nil)
|
22
|
+
@mod = mod
|
23
|
+
@method_name = method
|
24
|
+
@version = version
|
25
|
+
if method_name && mod
|
26
|
+
@supported = supported.nil? ? mod.method_defined?(method_name) : supported
|
27
|
+
# define whether running Ruby has a native implementation for this method
|
28
|
+
# for that, we check the source_location (which is nil for C defined methods)
|
29
|
+
@native = native.nil? ? (supported? && native_location?(mod.instance_method(method_name).source_location)) : native
|
30
|
+
end
|
31
|
+
@singleton = singleton
|
32
|
+
@refineables = Array(refineable)
|
33
|
+
@body = yield
|
34
|
+
@core_ext = core_ext
|
35
|
+
@location = location || build_location(caller_locations(1, 5))
|
36
|
+
@name = name || build_module_name
|
37
|
+
end
|
38
|
+
|
39
|
+
def prepend?
|
40
|
+
core_ext == :prepend
|
41
|
+
end
|
42
|
+
|
43
|
+
def core_ext?
|
44
|
+
!mod.nil?
|
45
|
+
end
|
46
|
+
|
47
|
+
alias supported? supported
|
48
|
+
alias native? native
|
49
|
+
alias singleton? singleton
|
50
|
+
|
51
|
+
def to_module
|
52
|
+
Module.new.tap do |ext|
|
53
|
+
ext.module_eval(body, *location)
|
54
|
+
|
55
|
+
RubyNext::Core.const_set(name, ext)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
private
|
60
|
+
|
61
|
+
def build_module_name
|
62
|
+
mod_name = singleton? ? singleton.name : mod.name
|
63
|
+
camelized_method_name = method_name.to_s.split("_").map(&:capitalize).join
|
64
|
+
|
65
|
+
"#{mod_name}#{camelized_method_name}".gsub(/\W/, "")
|
66
|
+
end
|
67
|
+
|
68
|
+
def build_location(trace_locations)
|
69
|
+
# The caller_locations behaviour depends on implementaion,
|
70
|
+
# e.g. in JRuby https://github.com/jruby/jruby/issues/6055
|
71
|
+
while trace_locations.first.label != "patch"
|
72
|
+
trace_locations.shift
|
73
|
+
end
|
74
|
+
|
75
|
+
trace_location = trace_locations[1]
|
76
|
+
|
77
|
+
[trace_location.absolute_path, trace_location.lineno + 2]
|
78
|
+
end
|
79
|
+
|
80
|
+
def native_location?(location)
|
81
|
+
location.nil? || location.first.match?(/(<internal:|resource:\/truffleruby\/core)/)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
# Registry for patches
|
86
|
+
class Patches
|
87
|
+
attr_reader :extensions, :refined
|
88
|
+
|
89
|
+
def initialize
|
90
|
+
@names = Set.new
|
91
|
+
@extensions = Hash.new { |h, k| h[k] = [] }
|
92
|
+
@refined = Hash.new { |h, k| h[k] = [] }
|
93
|
+
end
|
94
|
+
|
95
|
+
# Register new patch
|
96
|
+
def <<(patch)
|
97
|
+
raise ArgumentError, "Patch already registered: #{patch.name}" if @names.include?(patch.name)
|
98
|
+
@names << patch.name
|
99
|
+
@extensions[patch.mod] << patch if patch.core_ext?
|
100
|
+
patch.refineables.each { |r| @refined[r] << patch } unless patch.native?
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
class << self
|
105
|
+
STRATEGIES = %i[refine core_ext backports].freeze
|
106
|
+
|
107
|
+
attr_reader :strategy
|
108
|
+
|
109
|
+
def strategy=(val)
|
110
|
+
raise ArgumentError, "Unknown strategy: #{val}. Available: #{STRATEGIES.join(",")}" unless STRATEGIES.include?(val)
|
111
|
+
@strategy = val
|
112
|
+
end
|
113
|
+
|
114
|
+
def refine?
|
115
|
+
strategy == :refine
|
116
|
+
end
|
117
|
+
|
118
|
+
def core_ext?
|
119
|
+
strategy == :core_ext || strategy == :backports
|
120
|
+
end
|
121
|
+
|
122
|
+
def backports?
|
123
|
+
strategy == :backports
|
124
|
+
end
|
125
|
+
|
126
|
+
def patch(*__rest__, &__block__)
|
127
|
+
patches << Patch.new(*__rest__, &__block__)
|
128
|
+
end
|
129
|
+
|
130
|
+
# Inject `using RubyNext` at the top of the source code
|
131
|
+
def inject!(contents)
|
132
|
+
if contents.frozen?
|
133
|
+
contents = contents.sub(/^(\s*[^#\s].*)/, 'using RubyNext;\1')
|
134
|
+
else
|
135
|
+
contents.sub!(/^(\s*[^#\s].*)/, 'using RubyNext;\1')
|
136
|
+
end
|
137
|
+
contents
|
138
|
+
end
|
139
|
+
|
140
|
+
def patches
|
141
|
+
@patches ||= Patches.new
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
# Use refinements by default
|
146
|
+
self.strategy = ENV.fetch("RUBY_NEXT_CORE_STRATEGY", "refine").to_sym
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
require "backports/2.5" if RubyNext::Core.backports?
|
151
|
+
|
152
|
+
require "ruby-next/core/kernel/then"
|
153
|
+
|
154
|
+
require "ruby-next/core/proc/compose"
|
155
|
+
|
156
|
+
require "ruby-next/core/enumerable/tally"
|
157
|
+
require "ruby-next/core/enumerable/filter"
|
158
|
+
require "ruby-next/core/enumerable/filter_map"
|
159
|
+
|
160
|
+
require "ruby-next/core/enumerator/produce"
|
161
|
+
|
162
|
+
require "ruby-next/core/array/difference_union_intersection"
|
163
|
+
|
164
|
+
require "ruby-next/core/hash/merge"
|
165
|
+
|
166
|
+
require "ruby-next/core/string/split"
|
167
|
+
|
168
|
+
require "ruby-next/core/symbol/start_with"
|
169
|
+
require "ruby-next/core/symbol/end_with"
|
170
|
+
|
171
|
+
require "ruby-next/core/unboundmethod/bind_call"
|
172
|
+
|
173
|
+
require "ruby-next/core/time/floor"
|
174
|
+
require "ruby-next/core/time/ceil"
|
175
|
+
|
176
|
+
# Core extensions required for pattern matching
|
177
|
+
# Required for pattern matching with refinements
|
178
|
+
unless defined?(NoMatchingPatternError)
|
179
|
+
class NoMatchingPatternError < StandardError
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
require "ruby-next/core/constants/no_matching_pattern_error"
|
184
|
+
require "ruby-next/core/array/deconstruct"
|
185
|
+
require "ruby-next/core/hash/deconstruct_keys"
|
186
|
+
require "ruby-next/core/struct/deconstruct"
|
187
|
+
require "ruby-next/core/struct/deconstruct_keys"
|
188
|
+
|
189
|
+
require "ruby-next/core/hash/except"
|
190
|
+
|
191
|
+
# Generate refinements
|
192
|
+
RubyNext.module_eval do
|
193
|
+
RubyNext::Core.patches.refined.each do |mod, patches|
|
194
|
+
# Only refine modules when supported
|
195
|
+
next unless mod.is_a?(Class) || RubyNext::Utils.refine_modules?
|
196
|
+
|
197
|
+
refine mod do
|
198
|
+
patches.each do |patch|
|
199
|
+
module_eval(patch.body, *patch.location)
|
200
|
+
end
|
201
|
+
end
|
202
|
+
end
|
203
|
+
end
|
@@ -95,7 +95,7 @@ module RubyNext
|
|
95
95
|
exit 0
|
96
96
|
end
|
97
97
|
|
98
|
-
unless ((!
|
98
|
+
unless ((((__safe_lvar__ = lib_path) || true) && (!__safe_lvar__.nil? || nil)) && __safe_lvar__.then(&File.method(:exist?)))
|
99
99
|
$stdout.puts "Path not found: #{lib_path}"
|
100
100
|
$stdout.puts optparser.help
|
101
101
|
exit 2
|
@@ -8,7 +8,7 @@ module RubyNext
|
|
8
8
|
def eval(source, bind = nil, *args)
|
9
9
|
new_source = ::RubyNext::Language::Runtime.transform(
|
10
10
|
source,
|
11
|
-
using: ((!
|
11
|
+
using: ((((__safe_lvar__ = bind) || true) && (!__safe_lvar__.nil? || nil)) && __safe_lvar__.receiver) == TOPLEVEL_BINDING.receiver || ((((__safe_lvar__ = ((((__safe_lvar__ = bind) || true) && (!__safe_lvar__.nil? || nil)) && __safe_lvar__.receiver)) || true) && (!__safe_lvar__.nil? || nil)) && __safe_lvar__.is_a?(Module))
|
12
12
|
)
|
13
13
|
RubyNext.debug_source(new_source, "(#{caller_locations(1, 1).first})")
|
14
14
|
super new_source, bind, *args
|
@@ -112,19 +112,19 @@ module RubyNext
|
|
112
112
|
end
|
113
113
|
|
114
114
|
def replace(range, ast)
|
115
|
-
((
|
115
|
+
((((__safe_lvar__ = @source_rewriter) || true) && (!__safe_lvar__.nil? || nil)) && __safe_lvar__.replace(range, unparse(ast)))
|
116
116
|
end
|
117
117
|
|
118
118
|
def remove(range)
|
119
|
-
((
|
119
|
+
((((__safe_lvar__ = @source_rewriter) || true) && (!__safe_lvar__.nil? || nil)) && __safe_lvar__.remove(range))
|
120
120
|
end
|
121
121
|
|
122
122
|
def insert_after(range, ast)
|
123
|
-
((
|
123
|
+
((((__safe_lvar__ = @source_rewriter) || true) && (!__safe_lvar__.nil? || nil)) && __safe_lvar__.insert_after(range, unparse(ast)))
|
124
124
|
end
|
125
125
|
|
126
126
|
def insert_before(range, ast)
|
127
|
-
((
|
127
|
+
((((__safe_lvar__ = @source_rewriter) || true) && (!__safe_lvar__.nil? || nil)) && __safe_lvar__.insert_before(range, unparse(ast)))
|
128
128
|
end
|
129
129
|
|
130
130
|
def unparse(ast)
|
@@ -55,7 +55,7 @@ module RubyNext
|
|
55
55
|
attr_reader :current_index
|
56
56
|
|
57
57
|
def index_arg?(node)
|
58
|
-
((
|
58
|
+
((((__safe_lvar__ = ((((__safe_lvar__ = current_index) || true) && (!__safe_lvar__.nil? || nil)) && __safe_lvar__.children)) || true) && (!__safe_lvar__.nil? || nil)) && __safe_lvar__.include?(node))
|
59
59
|
end
|
60
60
|
end
|
61
61
|
end
|
@@ -313,7 +313,7 @@ module RubyNext
|
|
313
313
|
remove(node.children[0].loc.expression)
|
314
314
|
|
315
315
|
node.children[1..-1].each.with_index do |clause, i|
|
316
|
-
if ((!
|
316
|
+
if ((((__safe_lvar__ = clause) || true) && (!__safe_lvar__.nil? || nil)) && __safe_lvar__.type) == :in_pattern
|
317
317
|
# handle multiline clauses differently
|
318
318
|
if clause.loc.last_line > clause.children[0].loc.last_line + 1
|
319
319
|
height = clause.loc.last_line - clause.children[0].loc.last_line
|
@@ -344,7 +344,7 @@ module RubyNext
|
|
344
344
|
clauses = []
|
345
345
|
|
346
346
|
nodes.each do |clause|
|
347
|
-
if ((!
|
347
|
+
if ((((__safe_lvar__ = clause) || true) && (!__safe_lvar__.nil? || nil)) && __safe_lvar__.type) == :in_pattern
|
348
348
|
clauses << build_when_clause(clause)
|
349
349
|
else
|
350
350
|
else_clause = process(clause)
|
@@ -6,7 +6,7 @@ module RubyNext
|
|
6
6
|
|
7
7
|
if $LOAD_PATH.respond_to?(:resolve_feature_path)
|
8
8
|
def resolve_feature_path(feature)
|
9
|
-
((
|
9
|
+
((((__safe_lvar__ = $LOAD_PATH.resolve_feature_path(feature)) || true) && (!__safe_lvar__.nil? || nil)) && __safe_lvar__.last)
|
10
10
|
rescue LoadError
|
11
11
|
end
|
12
12
|
else
|
data/lib/ruby-next/core_ext.rb
CHANGED
data/lib/ruby-next/language.rb
CHANGED
@@ -179,6 +179,12 @@ module RubyNext
|
|
179
179
|
require "ruby-next/language/rewriters/safe_navigation"
|
180
180
|
rewriters << Rewriters::SafeNavigation
|
181
181
|
|
182
|
+
require "ruby-next/language/rewriters/numeric_literals"
|
183
|
+
rewriters << Rewriters::NumericLiterals
|
184
|
+
|
185
|
+
require "ruby-next/language/rewriters/required_kwargs"
|
186
|
+
rewriters << Rewriters::RequiredKwargs
|
187
|
+
|
182
188
|
require "ruby-next/language/rewriters/args_forward"
|
183
189
|
rewriters << Rewriters::ArgsForward
|
184
190
|
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RubyNext
|
4
|
+
module Language
|
5
|
+
module Rewriters
|
6
|
+
class NumericLiterals < Base
|
7
|
+
using RubyNext
|
8
|
+
|
9
|
+
NAME = "numeric-literals"
|
10
|
+
SYNTAX_PROBE = "2i + 1/2r"
|
11
|
+
MIN_SUPPORTED_VERSION = Gem::Version.new("2.1.0")
|
12
|
+
|
13
|
+
def on_rational(node)
|
14
|
+
context.track! self
|
15
|
+
|
16
|
+
val = node.children.first
|
17
|
+
|
18
|
+
parts = [s(:int, val.numerator)]
|
19
|
+
|
20
|
+
parts << s(:int, val.denominator) unless val.denominator == 1
|
21
|
+
|
22
|
+
s(:send, nil, :Rational, *parts).tap do |new_node|
|
23
|
+
replace(node.loc.expression, new_node)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def on_complex(node)
|
28
|
+
context.track! self
|
29
|
+
|
30
|
+
val = node.children.first
|
31
|
+
|
32
|
+
s(:send, nil, :Complex,
|
33
|
+
s(:int, val.real),
|
34
|
+
s(:int, val.imaginary)).tap do |new_node|
|
35
|
+
replace(node.loc.expression, new_node)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RubyNext
|
4
|
+
module Language
|
5
|
+
module Rewriters
|
6
|
+
class RequiredKwargs < Base
|
7
|
+
using RubyNext
|
8
|
+
|
9
|
+
NAME = "required-kwargs"
|
10
|
+
SYNTAX_PROBE = "obj = Object.new; def obj.foo(x:, y: 1); end"
|
11
|
+
MIN_SUPPORTED_VERSION = Gem::Version.new("2.1.0")
|
12
|
+
|
13
|
+
def on_kwarg(node)
|
14
|
+
context.track! self
|
15
|
+
|
16
|
+
name = node.children[0]
|
17
|
+
|
18
|
+
new_node = node.updated(
|
19
|
+
:kwoptarg,
|
20
|
+
[name, raise_missing_keyword(name)]
|
21
|
+
)
|
22
|
+
|
23
|
+
replace(node.loc.expression, "#{name}: ::Kernel.raise(::ArgumentError, \"missing keyword: #{name}\")")
|
24
|
+
|
25
|
+
new_node
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def raise_missing_keyword(name)
|
31
|
+
s(:send,
|
32
|
+
s(:const, s(:cbase), :Kernel), :raise,
|
33
|
+
s(:const, s(:cbase), :ArgumentError),
|
34
|
+
s(:str, "missing keyword: #{name}"))
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -8,6 +8,8 @@ module RubyNext
|
|
8
8
|
SYNTAX_PROBE = "nil&.x&.nil?"
|
9
9
|
MIN_SUPPORTED_VERSION = Gem::Version.new("2.3.0")
|
10
10
|
|
11
|
+
SAFE_LVAR = :__safe_lvar__
|
12
|
+
|
11
13
|
def on_csend(node)
|
12
14
|
node = super(node)
|
13
15
|
|
@@ -20,7 +22,7 @@ module RubyNext
|
|
20
22
|
:and,
|
21
23
|
[
|
22
24
|
process(safe_navigation(receiver)),
|
23
|
-
s(:send,
|
25
|
+
s(:send, safe_lvar, *args)
|
24
26
|
]
|
25
27
|
))
|
26
28
|
|
@@ -34,18 +36,15 @@ module RubyNext
|
|
34
36
|
|
35
37
|
context.track!(self)
|
36
38
|
|
37
|
-
|
38
|
-
|
39
|
-
:and,
|
40
|
-
[
|
41
|
-
process(safe_navigation(node.children[0].children[0])),
|
42
|
-
process(node.updated(nil, node.children.map(&method(:decsendize))))
|
43
|
-
]
|
44
|
-
)))
|
39
|
+
super(decsendize(node))
|
40
|
+
end
|
45
41
|
|
46
|
-
|
42
|
+
def on_numblock(node)
|
43
|
+
return super(node) unless node.children[0].type == :csend
|
47
44
|
|
48
|
-
|
45
|
+
context.track!(self)
|
46
|
+
|
47
|
+
super(decsendize(node))
|
49
48
|
end
|
50
49
|
|
51
50
|
def on_op_asgn(node)
|
@@ -53,37 +52,51 @@ module RubyNext
|
|
53
52
|
|
54
53
|
context.track!(self)
|
55
54
|
|
55
|
+
super(decsendize(node))
|
56
|
+
end
|
57
|
+
|
58
|
+
private
|
59
|
+
|
60
|
+
def decsendize(node)
|
61
|
+
csend, *children = node.children
|
62
|
+
|
63
|
+
receiver, *other = csend.children
|
64
|
+
|
65
|
+
new_csend = csend.updated(:send, [safe_lvar, *other])
|
66
|
+
|
56
67
|
new_node = s(:begin,
|
57
|
-
|
68
|
+
node.updated(
|
58
69
|
:and,
|
59
70
|
[
|
60
|
-
process(safe_navigation(
|
61
|
-
process(node.updated(nil,
|
71
|
+
process(safe_navigation(receiver)),
|
72
|
+
process(node.updated(nil, [new_csend, *children]))
|
62
73
|
]
|
63
|
-
))
|
74
|
+
))
|
64
75
|
|
65
76
|
replace(node.loc.expression, new_node)
|
66
77
|
|
67
78
|
new_node
|
68
79
|
end
|
69
80
|
|
70
|
-
|
71
|
-
|
72
|
-
def decsendize(node)
|
73
|
-
return node unless node.is_a?(::Parser::AST::Node) && node.type == :csend
|
74
|
-
|
75
|
-
node.updated(:send, node.children.map(&method(:decsendize)))
|
76
|
-
end
|
77
|
-
|
78
|
-
# Transform: x&.y -> (!x.nil? && x.y) || nil
|
81
|
+
# Transform: x&.y -> ((_tmp_ = x) || true) && (!_tmp_.nil? || nil) && _tmp_.y
|
79
82
|
# This allows us to handle `false&.to_s == "false"`
|
80
83
|
def safe_navigation(node)
|
81
84
|
s(:begin,
|
82
|
-
s(:
|
83
|
-
s(:
|
84
|
-
s(:
|
85
|
-
|
86
|
-
|
85
|
+
s(:and,
|
86
|
+
s(:begin,
|
87
|
+
s(:or,
|
88
|
+
s(:begin, s(:lvasgn, SAFE_LVAR, node)),
|
89
|
+
s(:true))),
|
90
|
+
s(:begin,
|
91
|
+
s(:or,
|
92
|
+
s(:send,
|
93
|
+
s(:send, safe_lvar, :nil?),
|
94
|
+
:!),
|
95
|
+
s(:nil)))))
|
96
|
+
end
|
97
|
+
|
98
|
+
def safe_lvar
|
99
|
+
s(:lvar, SAFE_LVAR)
|
87
100
|
end
|
88
101
|
end
|
89
102
|
end
|
@@ -30,7 +30,7 @@ module RubyNext
|
|
30
30
|
|
31
31
|
def setup_gem_load_path(lib_dir = "lib", rbnext_dir: RUBY_NEXT_DIR, transpile: false)
|
32
32
|
called_from = caller_locations(1, 1).first.path
|
33
|
-
dirname = File.dirname(called_from)
|
33
|
+
dirname = File.realpath(File.dirname(called_from))
|
34
34
|
|
35
35
|
loop do
|
36
36
|
basename = File.basename(dirname)
|
@@ -6,3 +6,8 @@ require "parser/current"
|
|
6
6
|
$VERBOSE = save_verbose
|
7
7
|
|
8
8
|
require "unparser"
|
9
|
+
|
10
|
+
# For backward compatibility with older Unparser
|
11
|
+
if RubyNext::Language::Builder.respond_to?(:emit_kwargs=) && !defined?(Unparser::Emitter::Kwargs)
|
12
|
+
RubyNext::Language::Builder.emit_kwargs = false
|
13
|
+
end
|
data/lib/ruby-next/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ruby-next-core
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.12.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Vladimir Dementyev
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-01-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: ruby-next-parser
|
@@ -62,6 +62,7 @@ files:
|
|
62
62
|
- bin/reparse
|
63
63
|
- bin/ruby-next
|
64
64
|
- bin/transform
|
65
|
+
- lib/.rbnext/2.1/ruby-next/core.rb
|
65
66
|
- lib/.rbnext/2.3/ruby-next/commands/core_ext.rb
|
66
67
|
- lib/.rbnext/2.3/ruby-next/commands/nextify.rb
|
67
68
|
- lib/.rbnext/2.3/ruby-next/language/eval.rb
|
@@ -114,7 +115,9 @@ files:
|
|
114
115
|
- lib/ruby-next/language/rewriters/in_pattern.rb
|
115
116
|
- lib/ruby-next/language/rewriters/method_reference.rb
|
116
117
|
- lib/ruby-next/language/rewriters/numbered_params.rb
|
118
|
+
- lib/ruby-next/language/rewriters/numeric_literals.rb
|
117
119
|
- lib/ruby-next/language/rewriters/pattern_matching.rb
|
120
|
+
- lib/ruby-next/language/rewriters/required_kwargs.rb
|
118
121
|
- lib/ruby-next/language/rewriters/runtime.rb
|
119
122
|
- lib/ruby-next/language/rewriters/runtime/dir.rb
|
120
123
|
- lib/ruby-next/language/rewriters/safe_navigation.rb
|