ruby-next-core 0.9.2 → 0.10.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +40 -0
- data/README.md +15 -4
- data/lib/.rbnext/2.3/ruby-next/commands/core_ext.rb +167 -0
- data/lib/.rbnext/2.3/ruby-next/commands/nextify.rb +201 -0
- data/lib/.rbnext/2.3/ruby-next/language/eval.rb +66 -0
- data/lib/.rbnext/2.3/ruby-next/language/rewriters/base.rb +121 -0
- data/lib/.rbnext/2.3/ruby-next/language/rewriters/endless_range.rb +63 -0
- data/lib/.rbnext/2.3/ruby-next/language/rewriters/pattern_matching.rb +944 -0
- data/lib/.rbnext/2.3/ruby-next/language/rewriters/right_hand_assignment.rb +107 -0
- data/lib/.rbnext/2.3/ruby-next/utils.rb +65 -0
- data/lib/ruby-next.rb +8 -6
- data/lib/ruby-next/cli.rb +2 -2
- data/lib/ruby-next/commands/core_ext.rb +1 -1
- data/lib/ruby-next/commands/nextify.rb +3 -0
- data/lib/ruby-next/core.rb +27 -21
- data/lib/ruby-next/core/array/deconstruct.rb +9 -9
- data/lib/ruby-next/core/array/difference_union_intersection.rb +12 -12
- data/lib/ruby-next/core/constants/no_matching_pattern_error.rb +3 -3
- data/lib/ruby-next/core/enumerable/filter.rb +8 -8
- data/lib/ruby-next/core/enumerable/filter_map.rb +25 -25
- data/lib/ruby-next/core/enumerable/tally.rb +7 -7
- data/lib/ruby-next/core/enumerator/produce.rb +12 -12
- data/lib/ruby-next/core/hash/deconstruct_keys.rb +9 -9
- data/lib/ruby-next/core/hash/except.rb +11 -0
- data/lib/ruby-next/core/hash/merge.rb +8 -8
- data/lib/ruby-next/core/kernel/then.rb +2 -2
- data/lib/ruby-next/core/proc/compose.rb +11 -11
- data/lib/ruby-next/core/string/split.rb +6 -6
- data/lib/ruby-next/core/struct/deconstruct.rb +2 -2
- data/lib/ruby-next/core/struct/deconstruct_keys.rb +17 -17
- data/lib/ruby-next/core/symbol/end_with.rb +4 -4
- data/lib/ruby-next/core/symbol/start_with.rb +4 -4
- data/lib/ruby-next/core/time/ceil.rb +6 -6
- data/lib/ruby-next/core/time/floor.rb +4 -4
- data/lib/ruby-next/core/unboundmethod/bind_call.rb +4 -4
- data/lib/ruby-next/core_ext.rb +1 -1
- data/lib/ruby-next/language.rb +12 -1
- data/lib/ruby-next/language/parser.rb +0 -3
- data/lib/ruby-next/language/proposed.rb +3 -0
- data/lib/ruby-next/language/rewriters/args_forward.rb +23 -20
- data/lib/ruby-next/language/rewriters/base.rb +1 -1
- data/lib/ruby-next/language/rewriters/endless_method.rb +25 -3
- data/lib/ruby-next/language/rewriters/find_pattern.rb +44 -0
- data/lib/ruby-next/language/rewriters/method_reference.rb +1 -1
- data/lib/ruby-next/language/rewriters/pattern_matching.rb +102 -12
- data/lib/ruby-next/language/rewriters/right_hand_assignment.rb +73 -11
- data/lib/ruby-next/language/rewriters/safe_navigation.rb +87 -0
- data/lib/ruby-next/language/rewriters/shorthand_hash.rb +47 -0
- data/lib/ruby-next/language/rewriters/squiggly_heredoc.rb +36 -0
- data/lib/ruby-next/language/unparser.rb +0 -14
- data/lib/ruby-next/logging.rb +1 -1
- data/lib/ruby-next/rubocop.rb +91 -9
- data/lib/ruby-next/setup_self.rb +22 -0
- data/lib/ruby-next/version.rb +1 -1
- data/lib/uby-next.rb +8 -4
- metadata +23 -9
@@ -3,36 +3,36 @@
|
|
3
3
|
# Refine Array seprately, 'cause refining modules is vulnerable to prepend:
|
4
4
|
# - https://bugs.ruby-lang.org/issues/13446
|
5
5
|
RubyNext::Core.patch Enumerable, method: :filter_map, version: "2.7", refineable: [Enumerable, Array] do
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
end
|
22
|
-
result
|
23
|
-
end
|
6
|
+
<<-RUBY
|
7
|
+
def filter_map
|
8
|
+
if block_given?
|
9
|
+
result = []
|
10
|
+
each do |element|
|
11
|
+
res = yield element
|
12
|
+
result << res if res
|
13
|
+
end
|
14
|
+
result
|
15
|
+
else
|
16
|
+
Enumerator.new do |yielder|
|
17
|
+
result = []
|
18
|
+
each do |element|
|
19
|
+
res = yielder.yield element
|
20
|
+
result << res if res
|
24
21
|
end
|
22
|
+
result
|
25
23
|
end
|
24
|
+
end
|
25
|
+
end
|
26
26
|
RUBY
|
27
27
|
end
|
28
28
|
|
29
29
|
RubyNext::Core.patch Enumerator::Lazy, method: :filter_map, version: "2.7" do
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
30
|
+
<<-RUBY
|
31
|
+
def filter_map
|
32
|
+
Enumerator::Lazy.new(self) do |yielder, *values|
|
33
|
+
result = yield(*values)
|
34
|
+
yielder << result if result
|
35
|
+
end
|
36
|
+
end
|
37
37
|
RUBY
|
38
38
|
end
|
@@ -3,12 +3,12 @@
|
|
3
3
|
# Refine Array seprately, 'cause refining modules is vulnerable to prepend:
|
4
4
|
# - https://bugs.ruby-lang.org/issues/13446
|
5
5
|
RubyNext::Core.patch Enumerable, method: :tally, version: "2.7", refineable: [Enumerable, Array] do
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
6
|
+
<<-RUBY
|
7
|
+
def tally
|
8
|
+
each_with_object({}) do |v, acc|
|
9
|
+
acc[v] ||= 0
|
10
|
+
acc[v] += 1
|
11
|
+
end
|
12
|
+
end
|
13
13
|
RUBY
|
14
14
|
end
|
@@ -1,20 +1,20 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
RubyNext::Core.patch Enumerator.singleton_class, method: :produce, singleton: Enumerator, version: "2.7" do
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
4
|
+
<<-'RUBY'
|
5
|
+
# Based on https://github.com/zverok/enumerator_generate
|
6
|
+
def produce(*rest, &block)
|
7
|
+
raise ArgumentError, "wrong number of arguments (given #{rest.size}, expected 0..1)" if rest.size > 1
|
8
|
+
raise ArgumentError, "No block given" unless block
|
9
9
|
|
10
|
-
|
11
|
-
|
10
|
+
Enumerator.new(Float::INFINITY) do |y|
|
11
|
+
val = rest.empty? ? yield() : rest.pop
|
12
12
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
end
|
17
|
-
end
|
13
|
+
loop do
|
14
|
+
y << val
|
15
|
+
val = yield(val)
|
18
16
|
end
|
17
|
+
end
|
18
|
+
end
|
19
19
|
RUBY
|
20
20
|
end
|
@@ -1,21 +1,21 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
RubyNext::Core.patch Hash, method: :deconstruct_keys, version: "2.7" do
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
4
|
+
<<-RUBY
|
5
|
+
def deconstruct_keys(_)
|
6
|
+
self
|
7
|
+
end
|
8
8
|
RUBY
|
9
9
|
end
|
10
10
|
|
11
11
|
# We need to hack `respond_to?` in Ruby 2.5, since it's not working with refinements
|
12
12
|
if Gem::Version.new(RUBY_VERSION) < Gem::Version.new("2.6")
|
13
13
|
RubyNext::Core.patch refineable: Hash, name: "HashRespondToDeconstructKeys", method: :deconstruct_keys, version: "2.7" do
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
14
|
+
<<-RUBY
|
15
|
+
def respond_to?(mid, *)
|
16
|
+
return true if mid == :deconstruct_keys
|
17
|
+
super
|
18
|
+
end
|
19
19
|
RUBY
|
20
20
|
end
|
21
21
|
end
|
@@ -1,14 +1,14 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
RubyNext::Core.patch Hash, method: :merge, version: "2.6", supported: {}.method(:merge).arity < 0, core_ext: :prepend do
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
4
|
+
<<-RUBY
|
5
|
+
def merge(*others)
|
6
|
+
return super if others.size == 1
|
7
|
+
return dup if others.size == 0
|
8
8
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
9
|
+
merge(others.shift).tap do |new_h|
|
10
|
+
others.each { |h| new_h.merge!(h) }
|
11
|
+
end
|
12
|
+
end
|
13
13
|
RUBY
|
14
14
|
end
|
@@ -4,7 +4,7 @@
|
|
4
4
|
# - https://bugs.ruby-lang.org/issues/13446
|
5
5
|
# - Rails added `Kernel.prepend` in 6.1: https://github.com/rails/rails/commit/3124007bd674dcdc9c3b5c6b2964dfb7a1a0733c
|
6
6
|
RubyNext::Core.patch Kernel, method: :then, version: "2.6", refineable: Object do
|
7
|
-
|
8
|
-
|
7
|
+
<<-RUBY
|
8
|
+
alias then yield_self
|
9
9
|
RUBY
|
10
10
|
end
|
@@ -2,18 +2,18 @@
|
|
2
2
|
|
3
3
|
# rubocop:disable Style/LambdaCall
|
4
4
|
RubyNext::Core.patch Proc, name: "ProcCompose", method: :<<, version: "2.6" do
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
5
|
+
<<-RUBY
|
6
|
+
def <<(other)
|
7
|
+
raise TypeError, "callable object is expected" unless other.respond_to?(:call)
|
8
|
+
this = self
|
9
|
+
proc { |*args, &block| this.(other.(*args, &block)) }
|
10
|
+
end
|
11
11
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
12
|
+
def >>(other)
|
13
|
+
raise TypeError, "callable object is expected" unless other.respond_to?(:call)
|
14
|
+
this = self
|
15
|
+
proc { |*args, &block| other.(this.(*args, &block)) }
|
16
|
+
end
|
17
17
|
RUBY
|
18
18
|
end
|
19
19
|
# rubocop:enable Style/LambdaCall
|
@@ -1,11 +1,11 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
RubyNext::Core.patch String, method: :split, version: "2.6", supported: ("a b".split(" ", &proc {}) == "a b"), core_ext: :prepend do
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
4
|
+
<<-RUBY
|
5
|
+
def split(*args, &block)
|
6
|
+
return super unless block_given?
|
7
|
+
super.each { |el| yield el }
|
8
|
+
self
|
9
|
+
end
|
10
10
|
RUBY
|
11
11
|
end
|
@@ -2,31 +2,31 @@
|
|
2
2
|
|
3
3
|
# Source: https://github.com/ruby/ruby/blob/b76a21aa45fff75909a66f8b20fc5856705f7862/struct.c#L953-L980
|
4
4
|
RubyNext::Core.patch Struct, method: :deconstruct_keys, version: "2.7" do
|
5
|
-
|
6
|
-
|
7
|
-
|
5
|
+
<<-'RUBY'
|
6
|
+
def deconstruct_keys(keys)
|
7
|
+
raise TypeError, "wrong argument type #{keys.class} (expected Array or nil)" if keys && !keys.is_a?(Array)
|
8
8
|
|
9
|
-
|
9
|
+
return to_h unless keys
|
10
10
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
11
|
+
keys.each_with_object({}) do |k, acc|
|
12
|
+
# if k is Symbol and not a member of a Struct return {}
|
13
|
+
next if (Symbol === k || String === k) && !members.include?(k.to_sym)
|
14
|
+
# if k is Integer check that index is not ouf of bounds
|
15
|
+
next if Integer === k && k > size - 1
|
16
|
+
acc[k] = self[k]
|
17
|
+
end
|
18
|
+
end
|
19
19
|
RUBY
|
20
20
|
end
|
21
21
|
|
22
22
|
# We need to hack `respond_to?` in Ruby 2.5, since it's not working with refinements
|
23
23
|
if Gem::Version.new(RUBY_VERSION) < Gem::Version.new("2.6")
|
24
24
|
RubyNext::Core.patch refineable: Struct, name: "StructRespondToDeconstruct", method: :deconstruct_keys, version: "2.7" do
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
25
|
+
<<-RUBY
|
26
|
+
def respond_to?(mid, *)
|
27
|
+
return true if mid == :deconstruct_keys || mid == :deconstruct
|
28
|
+
super
|
29
|
+
end
|
30
30
|
RUBY
|
31
31
|
end
|
32
32
|
end
|
@@ -1,9 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
RubyNext::Core.patch Symbol, method: :start_with?, version: "2.7" do
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
4
|
+
<<-RUBY
|
5
|
+
def start_with?(*prefixes)
|
6
|
+
to_s.start_with?(*prefixes)
|
7
|
+
end
|
8
8
|
RUBY
|
9
9
|
end
|
@@ -1,11 +1,11 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
RubyNext::Core.patch Time, method: :ceil, version: "2.7" do
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
4
|
+
<<-RUBY
|
5
|
+
def ceil(den = 0)
|
6
|
+
sceil = (subsec * 10**den).ceil.to_r / 10**den
|
7
|
+
change = sceil - subsec
|
8
|
+
self + change
|
9
|
+
end
|
10
10
|
RUBY
|
11
11
|
end
|
@@ -1,9 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
RubyNext::Core.patch UnboundMethod, method: :bind_call, version: "2.7" do
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
4
|
+
<<-RUBY
|
5
|
+
def bind_call(receiver, *args, &block)
|
6
|
+
bind(receiver).call(*args, &block)
|
7
|
+
end
|
8
8
|
RUBY
|
9
9
|
end
|
data/lib/ruby-next/core_ext.rb
CHANGED
data/lib/ruby-next/language.rb
CHANGED
@@ -100,7 +100,7 @@ module RubyNext
|
|
100
100
|
else
|
101
101
|
regenerate(*args, **kwargs)
|
102
102
|
end
|
103
|
-
rescue Unparser::
|
103
|
+
rescue Unparser::UnknownNodeError
|
104
104
|
if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new("2.7.0")
|
105
105
|
RubyNext.warn "Ruby Next fallbacks to \"rewrite\" transpiling mode since Unparser doesn't support 2.7+ AST yet.\n" \
|
106
106
|
"See https://github.com/mbj/unparser/pull/142"
|
@@ -173,6 +173,12 @@ module RubyNext
|
|
173
173
|
|
174
174
|
require "ruby-next/language/rewriters/base"
|
175
175
|
|
176
|
+
require "ruby-next/language/rewriters/squiggly_heredoc"
|
177
|
+
rewriters << Rewriters::SquigglyHeredoc
|
178
|
+
|
179
|
+
require "ruby-next/language/rewriters/safe_navigation"
|
180
|
+
rewriters << Rewriters::SafeNavigation
|
181
|
+
|
176
182
|
require "ruby-next/language/rewriters/args_forward"
|
177
183
|
rewriters << Rewriters::ArgsForward
|
178
184
|
|
@@ -182,6 +188,11 @@ module RubyNext
|
|
182
188
|
require "ruby-next/language/rewriters/pattern_matching"
|
183
189
|
rewriters << Rewriters::PatternMatching
|
184
190
|
|
191
|
+
# Must be added after general pattern matching rewriter to become
|
192
|
+
# no-op in Ruby <2.7
|
193
|
+
require "ruby-next/language/rewriters/find_pattern"
|
194
|
+
rewriters << Rewriters::FindPattern
|
195
|
+
|
185
196
|
# Put endless range in the end, 'cause Parser fails to parse it in
|
186
197
|
# pattern matching
|
187
198
|
require "ruby-next/language/rewriters/endless_range"
|
@@ -4,3 +4,6 @@
|
|
4
4
|
|
5
5
|
require "ruby-next/language/rewriters/method_reference"
|
6
6
|
RubyNext::Language.rewriters << RubyNext::Language::Rewriters::MethodReference
|
7
|
+
|
8
|
+
require "ruby-next/language/rewriters/shorthand_hash"
|
9
|
+
RubyNext::Language.rewriters << RubyNext::Language::Rewriters::ShorthandHash
|
@@ -5,16 +5,18 @@ module RubyNext
|
|
5
5
|
module Rewriters
|
6
6
|
class ArgsForward < Base
|
7
7
|
NAME = "args-forward"
|
8
|
-
SYNTAX_PROBE = "obj = Object.new; def obj.foo(...) super(...); end"
|
9
|
-
MIN_SUPPORTED_VERSION = Gem::Version.new("
|
8
|
+
SYNTAX_PROBE = "obj = Object.new; def obj.foo(...) super(1, ...); end"
|
9
|
+
MIN_SUPPORTED_VERSION = Gem::Version.new("3.0.0")
|
10
10
|
|
11
11
|
REST = :__rest__
|
12
12
|
BLOCK = :__block__
|
13
13
|
|
14
|
-
def
|
14
|
+
def on_forward_arg(node)
|
15
15
|
context.track! self
|
16
16
|
|
17
|
-
|
17
|
+
node = super(node)
|
18
|
+
|
19
|
+
replace(node.loc.expression, "*#{REST}, &#{BLOCK}")
|
18
20
|
|
19
21
|
node.updated(
|
20
22
|
:args,
|
@@ -26,34 +28,35 @@ module RubyNext
|
|
26
28
|
end
|
27
29
|
|
28
30
|
def on_send(node)
|
29
|
-
|
31
|
+
fargs = node.children.find { |child| child.is_a?(::Parser::AST::Node) && child.type == :forwarded_args }
|
32
|
+
return super(node) unless fargs
|
33
|
+
|
34
|
+
process_fargs(node, fargs)
|
35
|
+
end
|
36
|
+
|
37
|
+
def on_super(node)
|
38
|
+
fargs = node.children.find { |child| child.is_a?(::Parser::AST::Node) && child.type == :forwarded_args }
|
39
|
+
return super(node) unless fargs
|
40
|
+
|
41
|
+
process_fargs(node, fargs)
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
30
45
|
|
31
|
-
|
46
|
+
def process_fargs(node, fargs)
|
47
|
+
replace(fargs.loc.expression, "*#{REST}, &#{BLOCK}")
|
32
48
|
|
33
49
|
process(
|
34
50
|
node.updated(
|
35
51
|
nil,
|
36
52
|
[
|
37
|
-
*node.children
|
53
|
+
*node.children.take(node.children.index(fargs)),
|
38
54
|
*forwarded_args
|
39
55
|
]
|
40
56
|
)
|
41
57
|
)
|
42
58
|
end
|
43
59
|
|
44
|
-
def on_super(node)
|
45
|
-
return super(node) unless node.children[0]&.type == :forwarded_args
|
46
|
-
|
47
|
-
replace(node.children[0].loc.expression, "*#{REST}, &#{BLOCK}")
|
48
|
-
|
49
|
-
node.updated(
|
50
|
-
nil,
|
51
|
-
forwarded_args
|
52
|
-
)
|
53
|
-
end
|
54
|
-
|
55
|
-
private
|
56
|
-
|
57
60
|
def forwarded_args
|
58
61
|
[
|
59
62
|
s(:splat, s(:lvar, REST)),
|