ruby-next-core 0.11.0 → 0.13.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.
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