ruby-next-core 0.11.0 → 0.13.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (33) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +33 -0
  3. data/README.md +17 -3
  4. data/lib/.rbnext/2.1/ruby-next/core.rb +206 -0
  5. data/lib/.rbnext/2.1/ruby-next/language.rb +227 -0
  6. data/lib/.rbnext/2.3/ruby-next/commands/nextify.rb +1 -1
  7. data/lib/.rbnext/2.3/ruby-next/language/eval.rb +1 -1
  8. data/lib/.rbnext/2.3/ruby-next/language/rewriters/base.rb +4 -4
  9. data/lib/.rbnext/2.3/ruby-next/language/rewriters/endless_range.rb +1 -1
  10. data/lib/.rbnext/2.3/ruby-next/language/rewriters/pattern_matching.rb +3 -3
  11. data/lib/.rbnext/2.3/ruby-next/utils.rb +1 -1
  12. data/lib/.rbnext/2.7/ruby-next/core.rb +3 -0
  13. data/lib/ruby-next/config.rb +6 -1
  14. data/lib/ruby-next/core/array/intersect.rb +9 -0
  15. data/lib/ruby-next/core/constants/frozen_error.rb +15 -0
  16. data/lib/ruby-next/core/enumerable/tally.rb +46 -7
  17. data/lib/ruby-next/core.rb +3 -0
  18. data/lib/ruby-next/core_ext.rb +1 -1
  19. data/lib/ruby-next/language/parser.rb +0 -3
  20. data/lib/ruby-next/language/rewriters/args_forward.rb +6 -2
  21. data/lib/ruby-next/language/rewriters/args_forward_leading.rb +1 -1
  22. data/lib/ruby-next/language/rewriters/method_reference.rb +1 -1
  23. data/lib/ruby-next/language/rewriters/numeric_literals.rb +41 -0
  24. data/lib/ruby-next/language/rewriters/pattern_matching.rb +1 -1
  25. data/lib/ruby-next/language/rewriters/required_kwargs.rb +39 -0
  26. data/lib/ruby-next/language/rewriters/safe_navigation.rb +42 -29
  27. data/lib/ruby-next/language/rewriters/shorthand_hash.rb +1 -1
  28. data/lib/ruby-next/language/setup.rb +3 -2
  29. data/lib/ruby-next/language/unparser.rb +3 -8
  30. data/lib/ruby-next/language.rb +50 -43
  31. data/lib/ruby-next/setup_self.rb +3 -1
  32. data/lib/ruby-next/version.rb +1 -1
  33. metadata +14 -14
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 37dbd285f7d0d450d8458a2dc5c01e7b8c5f7744e54ea05d133ea7444dc9704c
4
- data.tar.gz: 7a881b5d76d032ce4ee5a94515542bff75a3a5b899b8412d828d9c4a27728eda
3
+ metadata.gz: 671c0ebc75d7ba834da83c55556fc9ed752fbbd6869788fc02435aef89f087b8
4
+ data.tar.gz: cb17c7ca0aafa112b50431f97170cdc16caba65fdbbb2bff6ebed039f1e2e489
5
5
  SHA512:
6
- metadata.gz: '0971fe638bfbd8c1ac3e5aa5485457fd9e9e70cfbb6f6430222d18ae13ce1820e97f3e28f93393d8c4ecc5578df0113d229b0179f5f07a2e1e19ae94087112ff'
7
- data.tar.gz: aefa941c90244ae1e7c68eb7bae6f79c2fb936495e28158f8eb18a8b90dc8eb7dcbf35a50d133b8b1653a0bbb118469c989ed97cb6e7039d383c6264aca2f6bd
6
+ metadata.gz: 0642f3a3353f99d8ed5e76c4b530c748b7fc712c2ed04ba8e840a853087b3d94299ade88b83fd0ea472223bd5ee61f8c80618f818987ae541d4dc291eff8f0c2
7
+ data.tar.gz: 326aaccb2ec27ca7a28a802f755fcfc44748a825283d82d19055afe3a84d1b42eb9a48d41d5025b9b5be33230f6f88681e16b88537770270245b0435f457d49e
data/CHANGELOG.md CHANGED
@@ -2,6 +2,38 @@
2
2
 
3
3
  ## master
4
4
 
5
+ ## 0.13.1 (2021-09-27)
6
+
7
+ - Fix checking for realpath during $LOAD_PATH setup. ([@palkan][])
8
+
9
+ ## 0.13.0 (2021-09-27)
10
+
11
+ - Added `Enumerable#tally` with the resulting hash. ([@skryukov][])
12
+
13
+ - Added `Array#intersect?`. ([@skryukov][])
14
+
15
+ ## 0.12.0 (2021-01-12)
16
+
17
+ - Added required keyword arguments rewriter. ([@palkan][])
18
+
19
+ Required kwargs were introduced in 2.1. Now we make them possible in 2.0.
20
+
21
+ - Added numeric literals rewriter. ([@palkan][])
22
+
23
+ Now it's possible to generate Ruby 2.0 compatible code from `2i + 1/3r`.
24
+
25
+ - Fixed several safe navigation (`&.`) bugs. ([@palkan][])
26
+
27
+ See [#68](https://github.com/ruby-next/ruby-next/issues/68) and [#69](https://github.com/ruby-next/ruby-next/issues/69).
28
+
29
+ ## 0.11.1 (2020-12-28)
30
+
31
+ - Use separate _namespace_ for proposed features to avoid conflicts with new Ruby version. ([@palkan][])
32
+
33
+ Previously, we used the upcoming Ruby version number for proposed features (e.g., `3.0.0`), which broke
34
+ the load path setup, since transpiled files were not loaded anymore.
35
+ Now that's fixed by using a _virtual_ version number for proposals (`1995.next.0`).
36
+
5
37
  ## 0.11.0 (2020-12-24) 🎄
6
38
 
7
39
  - Extended proposed shorthand Hash syntax to support kwargs as well. ([@palkan][])
@@ -259,3 +291,4 @@ p a #=> 1
259
291
  [@palkan]: https://github.com/palkan
260
292
  [backports]: https://github.com/marcandre/backports
261
293
  [@sl4vr]: https://github.com/sl4vr
294
+ [@skryukov]: https://github.com/skryukov
data/README.md CHANGED
@@ -21,8 +21,20 @@ That's why Ruby Next implements the `master` features as fast as possible.
21
21
 
22
22
  Read more about the motivation behind the Ruby Next in this post: [Ruby Next: Make all Rubies quack alike](https://evilmartians.com/chronicles/ruby-next-make-all-rubies-quack-alike).
23
23
 
24
- <a href="https://evilmartians.com/?utm_source=ruby-next">
25
- <img src="https://evilmartians.com/badges/sponsored-by-evil-martians.svg" alt="Sponsored by Evil Martians" width="236" height="54"></a>
24
+ <table style="border:none;">
25
+ <tr>
26
+ <td>
27
+ <a href="https://evilmartians.com/?utm_source=ruby-next">
28
+ <img src="https://evilmartians.com/badges/sponsored-by-evil-martians.svg" alt="Sponsored by Evil Martians" width="236" height="54">
29
+ </a>
30
+ </td>
31
+ <td>
32
+ <a href="http://www.digitalfukuoka.jp/topics/169">
33
+ <img src="http://www.digitalfukuoka.jp/javascripts/kcfinder/upload/images/excellence.jpg" width="200">
34
+ </a>
35
+ </td>
36
+ </tr>
37
+ </table>
26
38
 
27
39
  ## Posts
28
40
 
@@ -445,6 +457,8 @@ AllCops:
445
457
 
446
458
  We currently provide support for Ruby 2.2, 2.3 and 2.4.
447
459
 
460
+ **NOTE:** By "support" here we mean using `ruby-next` CLI and runtime transpiling. Transpiled code may run on Ruby 2.0+.
461
+
448
462
  Ruby Next itself relies on 2.5 features and contains polyfills only for version 2.5+ (and that won't change).
449
463
  Thus, to make it work with <2.5 we need to backport some APIs ourselves.
450
464
 
@@ -508,7 +522,7 @@ require "ruby-next/language/runtime"
508
522
 
509
523
  ### Supported edge features
510
524
 
511
- No new features since 3.0 release.
525
+ `Array#intersect?` ([#15198](https://bugs.ruby-lang.org/issues/15198))
512
526
 
513
527
  ### Supported proposed features
514
528
 
@@ -0,0 +1,206 @@
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/constants/frozen_error"
185
+ require "ruby-next/core/array/deconstruct"
186
+ require "ruby-next/core/hash/deconstruct_keys"
187
+ require "ruby-next/core/struct/deconstruct"
188
+ require "ruby-next/core/struct/deconstruct_keys"
189
+
190
+ require "ruby-next/core/hash/except"
191
+
192
+ require "ruby-next/core/array/intersect"
193
+
194
+ # Generate refinements
195
+ RubyNext.module_eval do
196
+ RubyNext::Core.patches.refined.each do |mod, patches|
197
+ # Only refine modules when supported
198
+ next unless mod.is_a?(Class) || RubyNext::Utils.refine_modules?
199
+
200
+ refine mod do
201
+ patches.each do |patch|
202
+ module_eval(patch.body, *patch.location)
203
+ end
204
+ end
205
+ end
206
+ end
@@ -0,0 +1,227 @@
1
+ # frozen_string_literal: true
2
+
3
+ gem "ruby-next-parser", ">= 2.8.0.3"
4
+ gem "unparser", ">= 0.4.7"
5
+
6
+ require "set"
7
+
8
+ require "ruby-next"
9
+
10
+ module RubyNext
11
+ # Language module contains tools to transpile newer Ruby syntax
12
+ # into an older one.
13
+ #
14
+ # It works the following way:
15
+ # - Takes a Ruby source code as input
16
+ # - Generates the AST using the edge parser (via the `parser` gem)
17
+ # - Pass this AST through the list of processors (one feature = one processor)
18
+ # - Each processor may modify the AST
19
+ # - Generates a transpiled source code from the transformed AST (via the `unparser` gem)
20
+ module Language
21
+ using RubyNext
22
+
23
+ require "ruby-next/language/parser"
24
+ require "ruby-next/language/unparser"
25
+
26
+ RewriterNotFoundError = Class.new(StandardError)
27
+
28
+ class TransformContext
29
+ attr_reader :versions, :use_ruby_next
30
+
31
+ def initialize
32
+ # Minimum supported RubyNext version
33
+ @min_version = MIN_SUPPORTED_VERSION
34
+ @dirty = false
35
+ @versions = Set.new
36
+ @use_ruby_next = false
37
+ end
38
+
39
+ # Called by rewriter when it performs transfomrations
40
+ def track!(rewriter)
41
+ @dirty = true
42
+ versions << rewriter.class::MIN_SUPPORTED_VERSION
43
+ end
44
+
45
+ def use_ruby_next!
46
+ @use_ruby_next = true
47
+ end
48
+
49
+ alias use_ruby_next? use_ruby_next
50
+
51
+ def dirty?
52
+ @dirty == true
53
+ end
54
+
55
+ def min_version
56
+ versions.min
57
+ end
58
+
59
+ def sorted_versions
60
+ versions.to_a.sort
61
+ end
62
+ end
63
+
64
+ class << self
65
+ attr_accessor :rewriters
66
+ attr_reader :watch_dirs
67
+
68
+ attr_accessor :strategy
69
+
70
+ MODES = %i[rewrite ast].freeze
71
+
72
+ attr_reader :mode
73
+
74
+ def mode=(val)
75
+ raise ArgumentError, "Unknown mode: #{val}. Available: #{MODES.join(",")}" unless MODES.include?(val)
76
+ @mode = val
77
+ end
78
+
79
+ def rewrite?
80
+ mode == :rewrite?
81
+ end
82
+
83
+ def ast?
84
+ mode == :ast
85
+ end
86
+
87
+ def runtime!
88
+ require "ruby-next/language/rewriters/runtime"
89
+
90
+ @runtime = true
91
+ end
92
+
93
+ def runtime?
94
+ @runtime
95
+ end
96
+
97
+ def transform(source, rewriters: self.rewriters, using: RubyNext::Core.refine?, context: TransformContext.new)
98
+ retried = 0
99
+ new_source = nil
100
+ begin
101
+ new_source =
102
+ if mode == :rewrite
103
+ rewrite(source, rewriters: rewriters, using: using, context: context)
104
+ else
105
+ regenerate(source, rewriters: rewriters, using: using, context: context)
106
+ end
107
+ rescue Unparser::UnknownNodeError => err
108
+ 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" \
109
+ "Try upgrading the Unparser or set transpiling mode to \"rewrite\" in case you use some edge or experimental syntax."
110
+ self.mode = :rewrite
111
+ retried += 1
112
+ retry unless retried > 1
113
+ raise
114
+ end
115
+
116
+ return new_source unless RubyNext::Core.refine?
117
+ return new_source unless using && context.use_ruby_next?
118
+
119
+ Core.inject! new_source.dup
120
+ end
121
+
122
+ def transformable?(path)
123
+ watch_dirs.any? { |dir| path.start_with?(dir) }
124
+ end
125
+
126
+ # Rewriters required for the current version
127
+ def current_rewriters
128
+ @current_rewriters ||= rewriters.select(&:unsupported_syntax?)
129
+ end
130
+
131
+ # This method guarantees that rewriters will be returned in order they defined in Language module
132
+ def select_rewriters(*names)
133
+ rewriters_delta = names - rewriters.map { |rewriter| rewriter::NAME }
134
+ if rewriters_delta.any?
135
+ raise RewriterNotFoundError, "Rewriters not found: #{rewriters_delta.join(",")}"
136
+ end
137
+
138
+ rewriters.select { |rewriter| names.include?(rewriter::NAME) }
139
+ end
140
+
141
+ private
142
+
143
+ def regenerate(source, rewriters: ::Kernel.raise(::ArgumentError, "missing keyword: rewriters"), using: ::Kernel.raise(::ArgumentError, "missing keyword: using"), context: ::Kernel.raise(::ArgumentError, "missing keyword: context"))
144
+ parse_with_comments(source).then do |(ast, comments)|
145
+ rewriters.inject(ast) do |tree, rewriter|
146
+ rewriter.new(context).process(tree)
147
+ end.then do |new_ast|
148
+ next source unless context.dirty?
149
+
150
+ Unparser.unparse(new_ast, comments)
151
+ end
152
+ end
153
+ end
154
+
155
+ def rewrite(source, rewriters: ::Kernel.raise(::ArgumentError, "missing keyword: rewriters"), using: ::Kernel.raise(::ArgumentError, "missing keyword: using"), context: ::Kernel.raise(::ArgumentError, "missing keyword: context"))
156
+ rewriters.inject(source) do |src, rewriter|
157
+ buffer = Parser::Source::Buffer.new("<dynamic>")
158
+ buffer.source = src
159
+
160
+ rewriter.new(context).rewrite(buffer, parse(src))
161
+ end.then do |new_source|
162
+ next source unless context.dirty?
163
+
164
+ new_source
165
+ end
166
+ end
167
+
168
+ attr_writer :watch_dirs
169
+ end
170
+
171
+ self.rewriters = []
172
+ self.watch_dirs = %w[app lib spec test].map { |path| File.join(Dir.pwd, path) }
173
+ self.mode = ENV.fetch("RUBY_NEXT_TRANSPILE_MODE", "rewrite").to_sym
174
+
175
+ require "ruby-next/language/rewriters/base"
176
+
177
+ require "ruby-next/language/rewriters/squiggly_heredoc"
178
+ rewriters << Rewriters::SquigglyHeredoc
179
+
180
+ require "ruby-next/language/rewriters/safe_navigation"
181
+ rewriters << Rewriters::SafeNavigation
182
+
183
+ require "ruby-next/language/rewriters/numeric_literals"
184
+ rewriters << Rewriters::NumericLiterals
185
+
186
+ require "ruby-next/language/rewriters/required_kwargs"
187
+ rewriters << Rewriters::RequiredKwargs
188
+
189
+ require "ruby-next/language/rewriters/args_forward"
190
+ rewriters << Rewriters::ArgsForward
191
+
192
+ # Must be added after general args forward rewriter to become
193
+ # no-op in Ruby <2.7
194
+ require "ruby-next/language/rewriters/args_forward_leading"
195
+ rewriters << Rewriters::ArgsForwardLeading
196
+
197
+ require "ruby-next/language/rewriters/numbered_params"
198
+ rewriters << Rewriters::NumberedParams
199
+
200
+ require "ruby-next/language/rewriters/pattern_matching"
201
+ rewriters << Rewriters::PatternMatching
202
+
203
+ # Must be added after general pattern matching rewriter to become
204
+ # no-op in Ruby <2.7
205
+ require "ruby-next/language/rewriters/find_pattern"
206
+ rewriters << Rewriters::FindPattern
207
+
208
+ require "ruby-next/language/rewriters/in_pattern"
209
+ rewriters << Rewriters::InPattern
210
+
211
+ # Put endless range in the end, 'cause Parser fails to parse it in
212
+ # pattern matching
213
+ require "ruby-next/language/rewriters/endless_range"
214
+ rewriters << Rewriters::EndlessRange
215
+
216
+ require "ruby-next/language/rewriters/endless_method"
217
+ RubyNext::Language.rewriters << RubyNext::Language::Rewriters::EndlessMethod
218
+
219
+ if ENV["RUBY_NEXT_EDGE"] == "1"
220
+ require "ruby-next/language/edge"
221
+ end
222
+
223
+ if ENV["RUBY_NEXT_PROPOSED"] == "1"
224
+ require "ruby-next/language/proposed"
225
+ end
226
+ end
227
+ end
@@ -95,7 +95,7 @@ module RubyNext
95
95
  exit 0
96
96
  end
97
97
 
98
- unless ((!lib_path.nil? || nil) && lib_path.then(&File.method(:exist?)))
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: ((!bind.nil? || nil) && bind.receiver) == TOPLEVEL_BINDING.receiver || ((!((!bind.nil? || nil) && bind.receiver).nil? || nil) && ((!bind.nil? || nil) && bind.receiver).is_a?(Module))
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
- ((!@source_rewriter.nil? || nil) && @source_rewriter.replace(range, unparse(ast)))
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
- ((!@source_rewriter.nil? || nil) && @source_rewriter.remove(range))
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
- ((!@source_rewriter.nil? || nil) && @source_rewriter.insert_after(range, unparse(ast)))
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
- ((!@source_rewriter.nil? || nil) && @source_rewriter.insert_before(range, unparse(ast)))
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
- ((!((!current_index.nil? || nil) && current_index.children).nil? || nil) && ((!current_index.nil? || nil) && current_index.children).include?(node))
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 ((!clause.nil? || nil) && clause.type) == :in_pattern
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 ((!clause.nil? || nil) && clause.type) == :in_pattern
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)
@@ -353,7 +353,7 @@ module RubyNext
353
353
 
354
354
  else_clause = (else_clause || no_matching_pattern).then do |node|
355
355
  next node unless node.type == :empty_else
356
- s(:empty)
356
+ nil
357
357
  end
358
358
 
359
359
  clauses << else_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
- ((!$LOAD_PATH.resolve_feature_path(feature).nil? || nil) && $LOAD_PATH.resolve_feature_path(feature).last)
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
@@ -181,6 +181,7 @@ unless defined?(NoMatchingPatternError)
181
181
  end
182
182
 
183
183
  require "ruby-next/core/constants/no_matching_pattern_error"
184
+ require "ruby-next/core/constants/frozen_error"
184
185
  require "ruby-next/core/array/deconstruct"
185
186
  require "ruby-next/core/hash/deconstruct_keys"
186
187
  require "ruby-next/core/struct/deconstruct"
@@ -188,6 +189,8 @@ require "ruby-next/core/struct/deconstruct_keys"
188
189
 
189
190
  require "ruby-next/core/hash/except"
190
191
 
192
+ require "ruby-next/core/array/intersect"
193
+
191
194
  # Generate refinements
192
195
  RubyNext.module_eval do
193
196
  RubyNext::Core.patches.refined.each do |mod, patches|
@@ -15,6 +15,9 @@ module RubyNext
15
15
 
16
16
  LATEST_VERSION = [3, 0].freeze
17
17
 
18
+ # A virtual version number used for proposed features
19
+ NEXT_VERSION = "1995.next.0"
20
+
18
21
  class << self
19
22
  # TruffleRuby claims it's 2.7.2 compatible but...
20
23
  if defined?(TruffleRuby) && ::RUBY_VERSION =~ /^2\.7/
@@ -28,9 +31,11 @@ module RubyNext
28
31
  end
29
32
 
30
33
  def next_ruby_version(version = current_ruby_version)
34
+ return if version == Gem::Version.new(NEXT_VERSION)
35
+
31
36
  major, minor = Gem::Version.new(version).segments.map(&:to_i)
32
37
 
33
- return if major >= LATEST_VERSION.first && minor >= LATEST_VERSION.last
38
+ return Gem::Version.new(NEXT_VERSION) if major >= LATEST_VERSION.first && minor >= LATEST_VERSION.last
34
39
 
35
40
  nxt =
36
41
  if LAST_MINOR_VERSIONS[major] == minor
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ RubyNext::Core.patch Array, method: :intersect?, version: "3.1" do
4
+ <<-RUBY
5
+ def intersect?(other)
6
+ !(self & other).empty?
7
+ end
8
+ RUBY
9
+ end