ruby-next-core 0.9.2 → 0.10.4

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 (57) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +40 -0
  3. data/README.md +15 -4
  4. data/lib/.rbnext/2.3/ruby-next/commands/core_ext.rb +167 -0
  5. data/lib/.rbnext/2.3/ruby-next/commands/nextify.rb +201 -0
  6. data/lib/.rbnext/2.3/ruby-next/language/eval.rb +66 -0
  7. data/lib/.rbnext/2.3/ruby-next/language/rewriters/base.rb +121 -0
  8. data/lib/.rbnext/2.3/ruby-next/language/rewriters/endless_range.rb +63 -0
  9. data/lib/.rbnext/2.3/ruby-next/language/rewriters/pattern_matching.rb +944 -0
  10. data/lib/.rbnext/2.3/ruby-next/language/rewriters/right_hand_assignment.rb +107 -0
  11. data/lib/.rbnext/2.3/ruby-next/utils.rb +65 -0
  12. data/lib/ruby-next.rb +8 -6
  13. data/lib/ruby-next/cli.rb +2 -2
  14. data/lib/ruby-next/commands/core_ext.rb +1 -1
  15. data/lib/ruby-next/commands/nextify.rb +3 -0
  16. data/lib/ruby-next/core.rb +27 -21
  17. data/lib/ruby-next/core/array/deconstruct.rb +9 -9
  18. data/lib/ruby-next/core/array/difference_union_intersection.rb +12 -12
  19. data/lib/ruby-next/core/constants/no_matching_pattern_error.rb +3 -3
  20. data/lib/ruby-next/core/enumerable/filter.rb +8 -8
  21. data/lib/ruby-next/core/enumerable/filter_map.rb +25 -25
  22. data/lib/ruby-next/core/enumerable/tally.rb +7 -7
  23. data/lib/ruby-next/core/enumerator/produce.rb +12 -12
  24. data/lib/ruby-next/core/hash/deconstruct_keys.rb +9 -9
  25. data/lib/ruby-next/core/hash/except.rb +11 -0
  26. data/lib/ruby-next/core/hash/merge.rb +8 -8
  27. data/lib/ruby-next/core/kernel/then.rb +2 -2
  28. data/lib/ruby-next/core/proc/compose.rb +11 -11
  29. data/lib/ruby-next/core/string/split.rb +6 -6
  30. data/lib/ruby-next/core/struct/deconstruct.rb +2 -2
  31. data/lib/ruby-next/core/struct/deconstruct_keys.rb +17 -17
  32. data/lib/ruby-next/core/symbol/end_with.rb +4 -4
  33. data/lib/ruby-next/core/symbol/start_with.rb +4 -4
  34. data/lib/ruby-next/core/time/ceil.rb +6 -6
  35. data/lib/ruby-next/core/time/floor.rb +4 -4
  36. data/lib/ruby-next/core/unboundmethod/bind_call.rb +4 -4
  37. data/lib/ruby-next/core_ext.rb +1 -1
  38. data/lib/ruby-next/language.rb +12 -1
  39. data/lib/ruby-next/language/parser.rb +0 -3
  40. data/lib/ruby-next/language/proposed.rb +3 -0
  41. data/lib/ruby-next/language/rewriters/args_forward.rb +23 -20
  42. data/lib/ruby-next/language/rewriters/base.rb +1 -1
  43. data/lib/ruby-next/language/rewriters/endless_method.rb +25 -3
  44. data/lib/ruby-next/language/rewriters/find_pattern.rb +44 -0
  45. data/lib/ruby-next/language/rewriters/method_reference.rb +1 -1
  46. data/lib/ruby-next/language/rewriters/pattern_matching.rb +102 -12
  47. data/lib/ruby-next/language/rewriters/right_hand_assignment.rb +73 -11
  48. data/lib/ruby-next/language/rewriters/safe_navigation.rb +87 -0
  49. data/lib/ruby-next/language/rewriters/shorthand_hash.rb +47 -0
  50. data/lib/ruby-next/language/rewriters/squiggly_heredoc.rb +36 -0
  51. data/lib/ruby-next/language/unparser.rb +0 -14
  52. data/lib/ruby-next/logging.rb +1 -1
  53. data/lib/ruby-next/rubocop.rb +91 -9
  54. data/lib/ruby-next/setup_self.rb +22 -0
  55. data/lib/ruby-next/version.rb +1 -1
  56. data/lib/uby-next.rb +8 -4
  57. metadata +23 -9
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 31bef7eea12c9a2c8b04f3daa62816e96b764bcbaf7cfc0f01d4bf1b040f34b9
4
- data.tar.gz: 793834fef3c0a00944b7026a975f7ee4b97219ae42b2b3ebfb5327d4a3e5311c
3
+ metadata.gz: eb05945d60839251b2e4ab0ee2969bb1ecc5f9d5470ad55ced6529973b0368c4
4
+ data.tar.gz: 32b2af2bfae9a8b660df2ea2b101a59864ad007cca6e82713e30fffc4b154e46
5
5
  SHA512:
6
- metadata.gz: 690f42ac5954bbe4b2c6a0e4ee0a05f4842c87a4ade5bccb3f7be90d76b92df89e715a07c785f5286bb4137ac3357fe4341e90b41f010db8716fab5a9bdcfb83
7
- data.tar.gz: 48bd02bbd66656cd9892cad1c8fe767c205bfba5eb47c59cfacdf3060af3c7cf886fbba6396283f3e19eb1da66cd53e9b6a5125595ec694cd8c37ad6ecb4e0f1
6
+ metadata.gz: '0388183958efacdbadfe5b34f87a962b6529453c7be8882313bec5b0259b8d264d1697ce182048d1d2cc068e6f6eb15950aada4d70714aa3ac0d16ab6e6b4add'
7
+ data.tar.gz: a2beada149efd56af672802667e3e6dcc38e59cd281a5e9e6b84ec72dbb3faad5fae299d166715b06dfccfbbecfc0d6690a531a14571ec65862ea6ef7485f142
@@ -2,6 +2,46 @@
2
2
 
3
3
  ## master
4
4
 
5
+ ## 0.10.4 (2020-10-09)
6
+
7
+ - Restrict Unparser dependency. ([@palkan][])
8
+
9
+ Unparser 0.5.0 is currently not supported.
10
+
11
+ ## 0.10.3 (2020-09-28)
12
+
13
+ - Update RuboCop integration to handle the latest Parser changes. ([@palkan][])
14
+
15
+ Parser 2.7.1.5 unified endless and normal methods and rightward and leftward assignments, thus, making some cops report false negatives.
16
+
17
+ ## 0.10.2 (2020-09-09)
18
+
19
+ - Fix regression when `nextify` produces incorrect files for 2.7. ([@palkan][])
20
+
21
+ ## ~~0.10.1~~
22
+
23
+ ## 0.10.0 (2020-09-02)
24
+
25
+ - Add proposed shorthand Hash syntax. ([@palkan][])
26
+
27
+ You can try it: `x = 1; y = 2; data = {x, y}`.
28
+
29
+ - Add leading argument support to args forwarding. ([@palkan][])
30
+
31
+ `def a(...) b(1, ...); end`.
32
+
33
+ - Add `Hash#except`. ([@palkan][])
34
+
35
+ `{a: 1, b: 2}.except(:a) == {b: 2}`
36
+
37
+ - Add find pattern support. ([@palkan][])
38
+
39
+ Now you can do: `[0, 1, 2] in [*, 1 => a, *c]`.
40
+
41
+ - Add Ruby 2.2 support. ([@palkan][])
42
+
43
+ With support for safe navigation operator (`&.`) and squiggly heredocs (`<<~TXT`).
44
+
5
45
  ## 0.9.2 (2020-06-24)
6
46
 
7
47
  - Support passing rewriters to CLI. ([@sl4vr][])
data/README.md CHANGED
@@ -35,8 +35,11 @@ Read more about the motivation behind the Ruby Next in this post: [Ruby Next: Ma
35
35
  ## Examples
36
36
 
37
37
  - Ruby gems
38
+ - [action_policy](https://github.com/palkan/action_policy)
38
39
  - [anyway_config](https://github.com/palkan/anyway_config)
39
40
  - [graphql-fragment_cache](https://github.com/DmitryTsepelev/graphql-ruby-fragment_cache)
41
+ - Rails applications
42
+ - [anycable_rails_demo](https://github.com/anycable/anycable_rails_demo)
40
43
  - mruby
41
44
  - [ACLI](https://github.com/palkan/acli)
42
45
 
@@ -68,7 +71,7 @@ Core provides **polyfills** for Ruby core classes APIs via Refinements (default
68
71
  Language is responsible for **transpiling** edge Ruby syntax into older versions. It could be done
69
72
  programmatically or via CLI. It also could be done in runtime.
70
73
 
71
- Currently, Ruby Next supports Ruby versions 2.3+, including JRuby 9.2.8+ and TruffleRuby 20.1+ (with some limitations). Support for EOL versions (<2.5) slightly differs though ([see below](#using-with-eol-rubies)).
74
+ Currently, Ruby Next supports Ruby versions 2.2+, including JRuby 9.2.8+ and TruffleRuby 20.1+ (with some limitations). Support for EOL versions (<2.5) slightly differs though ([see below](#using-with-eol-rubies)).
72
75
 
73
76
  Please, [open an issue](https://github.com/ruby-next/ruby-next/issues/new/choose) or join the discussion in the existing ones if you would like us to support older Ruby versions.
74
77
 
@@ -139,7 +142,7 @@ The following _rule of thumb_ is recommended when choosing between refinements a
139
142
  - Using core extensions could be considered for application development (no need to think about `using RubyNext`); this approach could potentially lead to conflicts with dependencies (if these dependencies are not using refinements 🙂)
140
143
  - Use core extensions if refinements are not supported by your platform
141
144
 
142
- **NOTE:** TruffleRuby doesn't fully support refinements (refining modules is not supported as of v20.1.0).
145
+ **NOTE:** _Edge_ APIs (i.e., from the Ruby's master branch) are included by default.
143
146
 
144
147
  [**The list of supported APIs.**][features_core]
145
148
 
@@ -427,6 +430,8 @@ You must set `TargetRubyVersion: next` to make RuboCop use a Ruby Next parser.
427
430
 
428
431
  Alternatively, you can load the patch from the command line by running: `rubocop -r ruby-next/rubocop ...`.
429
432
 
433
+ We recommend using the latest RuboCop version, 'cause it has support for new nodes built-in.
434
+
430
435
  Also, when pre-transpiling source code with `ruby-next nextify`, we suggest ignoring the transpiled files:
431
436
 
432
437
  ```yml
@@ -439,7 +444,7 @@ AllCops:
439
444
 
440
445
  ## Using with EOL Rubies
441
446
 
442
- We currently provide support for Ruby 2.3 and 2.4. Work on 2.2 is in progress.
447
+ We currently provide support for Ruby 2.2, 2.3 and 2.4.
443
448
 
444
449
  Ruby Next itself relies on 2.5 features and contains polyfills only for version 2.5+ (and that won't change).
445
450
  Thus, to make it work with <2.5 we need to backport some APIs ourselves.
@@ -469,6 +474,8 @@ RUBY_NEXT_CORE_STRATEGY=backports ruby-next nextify lib/
469
474
 
470
475
  **NOTE:** Make sure you have `backports` gem installed globally or added to your bundle (if you're using `bundle exec ruby-next ...`).
471
476
 
477
+ **NOTE:** For Ruby 2.2, safe navigation operator (`&.`) and squiggly heredocs (`<<~TXT`) support is provided.
478
+
472
479
  ## Proposed and edge features
473
480
 
474
481
  Ruby Next aims to bring edge and proposed features to Ruby community before they (hopefully) reach an official Ruby release.
@@ -502,12 +509,16 @@ require "ruby-next/language/runtime"
502
509
 
503
510
  - "Endless" method definition (`def foo() = 42`) ([#16746](https://bugs.ruby-lang.org/issues/16746)).
504
511
 
505
- - Right-hand assignment (`13.divmod(5) => a,b`) ([#15921](https://bugs.ruby-lang.org/issues/15921))
512
+ - Right-hand assignment (`13.divmod(5) => a,b`) ([#15921](https://bugs.ruby-lang.org/issues/15921)).
513
+
514
+ - Find pattern (`[0, 1, 2] in [*, 1 => a, *c]`) ([#16828](https://bugs.ruby-lang.org/issues/16828)).
506
515
 
507
516
  ### Supported proposed features
508
517
 
509
518
  - _Method reference_ operator (`.:`) ([#13581](https://bugs.ruby-lang.org/issues/13581)).
510
519
 
520
+ - Shorthand Hash notation (`data = {x, y}`) ([#15236](https://bugs.ruby-lang.org/issues/15236)).
521
+
511
522
  ## Contributing
512
523
 
513
524
  Bug reports and pull requests are welcome on GitHub at [https://github.com/ruby-next/ruby-next](ttps://github.com/ruby-next/ruby-next).
@@ -0,0 +1,167 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "fileutils"
4
+ require "pathname"
5
+
6
+ module RubyNext
7
+ module Commands
8
+ class CoreExt < Base
9
+ using RubyNext
10
+
11
+ attr_reader :out_path, :min_version, :names, :list, :filter, :original_command
12
+ alias list? list
13
+
14
+ def run
15
+ log "Select core extensions for Ruby v#{min_version}" \
16
+ "#{filter ? " and matching #{filter.inspect}" : ""}"
17
+
18
+ matching_patches.then do |patches|
19
+ next print_list(patches) if list?
20
+ generate_core_ext(patches)
21
+ end
22
+ end
23
+
24
+ def parse!(args)
25
+ print_help = false
26
+ @min_version = MIN_SUPPORTED_VERSION
27
+ @original_command = "ruby-next core_ext #{args.join(" ")}"
28
+ @names = []
29
+ @list = false
30
+ @out_path = File.join(Dir.pwd, "core_ext.rb")
31
+
32
+ optparser = base_parser do |opts|
33
+ opts.banner = "Usage: ruby-next core_ext [options]"
34
+
35
+ opts.on("-o", "--output=OUTPUT", "Specify output file or stdout (default: ./core_ext.rb)") do |val|
36
+ @out_path = val
37
+ end
38
+
39
+ opts.on("-l", "--list", "List all available extensions") do
40
+ @list = true
41
+ end
42
+
43
+ opts.on("--min-version=VERSION", "Specify the minimum Ruby version to support") do |val|
44
+ @min_version = Gem::Version.new(val)
45
+ end
46
+
47
+ opts.on("-n", "--name=NAME", "Filter extensions by name") do |val|
48
+ names << val
49
+ end
50
+
51
+ opts.on("-h", "--help", "Print help") do
52
+ print_help = true
53
+ end
54
+ end
55
+
56
+ optparser.parse!(args)
57
+
58
+ if print_help
59
+ $stdout.puts optparser.help
60
+ exit 0
61
+ end
62
+
63
+ @filter = /(#{names.join("|")})/i unless names.empty?
64
+ end
65
+
66
+ private
67
+
68
+ def matching_patches
69
+ RubyNext::Core.patches.extensions
70
+ .values
71
+ .flatten
72
+ .select do |patch|
73
+ next if min_version && Gem::Version.new(patch.version) <= min_version
74
+ next if filter && !filter.match?(patch.name)
75
+ true
76
+ end
77
+ end
78
+
79
+ def print_list(patches)
80
+ grouped_patches = patches.group_by(&:version).sort_by(&:first)
81
+ grouped_patches.each do |(group, patches)|
82
+ $stdout.puts "#{group} extensions:\n"
83
+ $stdout.puts patches.sort_by(&:name).map { |patch| " - #{patch.name}" }.join("\n")
84
+ $stdout.puts "\n"
85
+ end
86
+ end
87
+
88
+ def generate_core_ext(patches)
89
+ grouped_patches = patches.group_by(&:mod).sort_by { |(mod, patch)| mod.singleton_class? ? mod.inspect : mod.name }
90
+
91
+ buffer = []
92
+
93
+ buffer << "# frozen_string_literal: true\n"
94
+
95
+ buffer << generation_meta
96
+
97
+ grouped_patches.each do |mod, patches|
98
+ singleton = mod.singleton_class?
99
+ extend_name = singleton ? patches.first.singleton.name : mod.name
100
+ prepend_name = singleton ? "#{patches.first.singleton.name}.singleton_class" : mod.name
101
+
102
+ prepended, extended = patches.partition(&:prepend?)
103
+
104
+ prepended.map do |patch|
105
+ name = "RubyNext::Core::#{patch.name}"
106
+
107
+ buffer << <<-RUBY
108
+ module #{name}
109
+ #{indent_and_trim(patch.body)}
110
+ end
111
+ #{prepend_name}.prepend #{name}
112
+ RUBY
113
+
114
+ name
115
+ end
116
+
117
+ class_or_module = mod.is_a?(Class) ? "class" : "module"
118
+
119
+ buffer << "#{class_or_module} #{extend_name}"
120
+
121
+ buffer << " class << self" if singleton
122
+
123
+ indent_size = singleton ? 4 : 2
124
+
125
+ buffer << extended.map do |patch|
126
+ indent_and_trim(patch.body, indent_size)
127
+ end.join("\n\n")
128
+
129
+ buffer << " end" if singleton
130
+
131
+ buffer << "end\n"
132
+ end
133
+
134
+ contents = buffer.join("\n")
135
+
136
+ return $stdout.puts(contents) if out_path == "stdout"
137
+
138
+ unless CLI.dry_run?
139
+ FileUtils.mkdir_p File.dirname(out_path)
140
+ File.write(out_path, contents)
141
+ end
142
+
143
+ log "Generated: #{out_path}"
144
+ end
145
+
146
+ def generation_meta
147
+ <<-MSG
148
+ # Generated by Ruby Next v#{RubyNext::VERSION} using the following command:
149
+ #
150
+ # #{original_command}
151
+ #
152
+ MSG
153
+ end
154
+
155
+ def indent_and_trim(src, size = 2)
156
+ new_src = src.dup
157
+ # indent code using <size> spaces
158
+ new_src.gsub!(/^/, " " * size)
159
+ # remove empty lines
160
+ new_src.gsub!(/^\s+$/, "")
161
+ # remove traling blank lines
162
+ new_src.delete_suffix!("\n")
163
+ new_src
164
+ end
165
+ end
166
+ end
167
+ end
@@ -0,0 +1,201 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "fileutils"
4
+ require "pathname"
5
+
6
+ require "ruby-next/language"
7
+
8
+ module RubyNext
9
+ module Commands
10
+ class Nextify < Base
11
+ using RubyNext
12
+
13
+ attr_reader :lib_path, :paths, :out_path, :min_version, :single_version, :specified_rewriters
14
+
15
+ def run
16
+ log "RubyNext core strategy: #{RubyNext::Core.strategy}"
17
+ log "RubyNext transpile mode: #{RubyNext::Language.mode}"
18
+
19
+ remove_rbnext!
20
+
21
+ @min_version ||= MIN_SUPPORTED_VERSION
22
+
23
+ paths.each do |path|
24
+ contents = File.read(path)
25
+ transpile path, contents
26
+ end
27
+ end
28
+
29
+ def parse!(args)
30
+ print_help = false
31
+ print_rewriters = false
32
+ rewriter_names = []
33
+ @single_version = false
34
+
35
+ optparser = base_parser do |opts|
36
+ opts.banner = "Usage: ruby-next nextify DIRECTORY_OR_FILE [options]"
37
+
38
+ opts.on("-o", "--output=OUTPUT", "Specify output directory or file or stdout") do |val|
39
+ @out_path = val
40
+ end
41
+
42
+ opts.on("--min-version=VERSION", "Specify the minimum Ruby version to support") do |val|
43
+ @min_version = Gem::Version.new(val)
44
+ end
45
+
46
+ opts.on("--single-version", "Only create one version of a file (for the earliest Ruby version)") do
47
+ @single_version = true
48
+ end
49
+
50
+ opts.on("--edge", "Enable edge (master) Ruby features") do |val|
51
+ require "ruby-next/language/edge"
52
+ end
53
+
54
+ opts.on("--proposed", "Enable proposed/experimental Ruby features") do |val|
55
+ require "ruby-next/language/proposed"
56
+ end
57
+
58
+ opts.on(
59
+ "--transpile-mode=MODE",
60
+ "Transpiler mode (ast or rewrite). Default: ast"
61
+ ) do |val|
62
+ Language.mode = val.to_sym
63
+ end
64
+
65
+ opts.on("--[no-]refine", "Do not inject `using RubyNext`") do |val|
66
+ Core.strategy = :core_ext unless val
67
+ end
68
+
69
+ opts.on("--list-rewriters", "List available rewriters") do |val|
70
+ print_rewriters = true
71
+ end
72
+
73
+ opts.on("--rewrite=REWRITERS...", "Specify particular Ruby features to rewrite") do |val|
74
+ rewriter_names << val
75
+ end
76
+
77
+ opts.on("-h", "--help", "Print help") do
78
+ print_help = true
79
+ end
80
+ end
81
+
82
+ optparser.parse!(args)
83
+
84
+ @lib_path = args[0]
85
+
86
+ if print_help
87
+ $stdout.puts optparser.help
88
+ exit 0
89
+ end
90
+
91
+ if print_rewriters
92
+ Language.rewriters.each do |rewriter|
93
+ $stdout.puts "#{rewriter::NAME} (\"#{rewriter::SYNTAX_PROBE}\")"
94
+ end
95
+ exit 0
96
+ end
97
+
98
+ unless ((!lib_path.nil?) || nil) && lib_path.then(&File.method(:exist?))
99
+ $stdout.puts "Path not found: #{lib_path}"
100
+ $stdout.puts optparser.help
101
+ exit 2
102
+ end
103
+
104
+ if rewriter_names.any? && min_version
105
+ $stdout.puts "--rewrite cannot be used with --min-version simultaneously"
106
+ exit 2
107
+ end
108
+
109
+ @specified_rewriters =
110
+ if rewriter_names.any?
111
+ begin
112
+ Language.select_rewriters(*rewriter_names)
113
+ rescue Language::RewriterNotFoundError => error
114
+ $stdout.puts error.message
115
+ $stdout.puts "Try --list-rewriters to see list of available rewriters"
116
+ exit 2
117
+ end
118
+ end
119
+
120
+ @paths =
121
+ if File.directory?(lib_path)
122
+ Dir[File.join(lib_path, "**/*.rb")]
123
+ elsif File.file?(lib_path)
124
+ [lib_path].tap do |_|
125
+ @lib_path = File.dirname(lib_path)
126
+ end
127
+ end
128
+ end
129
+
130
+ private
131
+
132
+ def transpile(path, contents, version: min_version)
133
+ rewriters = specified_rewriters || Language.rewriters.select { |rw| rw.unsupported_version?(version) }
134
+
135
+ context = Language::TransformContext.new
136
+
137
+ new_contents = Language.transform contents, context: context, rewriters: rewriters
138
+
139
+ return unless context.dirty?
140
+
141
+ versions = context.sorted_versions
142
+ version = versions.shift
143
+
144
+ # First, store already transpiled contents in the minimum required version dir
145
+ save new_contents, path, version
146
+
147
+ return if versions.empty? || single_version?
148
+
149
+ # Then, generate the source code for the next version
150
+ transpile path, contents, version: version
151
+ rescue SyntaxError, StandardError => e
152
+ warn "Failed to transpile #{path}: #{e.class} — #{e.message}"
153
+ exit 1
154
+ end
155
+
156
+ def save(contents, path, version)
157
+ return $stdout.puts(contents) if stdout?
158
+
159
+ paths = [Pathname.new(path).relative_path_from(Pathname.new(lib_path))]
160
+
161
+ paths.unshift(version.segments[0..1].join(".")) unless single_version?
162
+
163
+ next_path =
164
+ if next_dir_path.end_with?(".rb")
165
+ out_path
166
+ else
167
+ File.join(next_dir_path, *paths)
168
+ end
169
+
170
+ unless CLI.dry_run?
171
+ FileUtils.mkdir_p File.dirname(next_path)
172
+
173
+ File.write(next_path, contents)
174
+ end
175
+
176
+ log "Generated: #{next_path}"
177
+ end
178
+
179
+ def remove_rbnext!
180
+ return if CLI.dry_run? || stdout?
181
+
182
+ return unless File.directory?(next_dir_path)
183
+
184
+ log "Remove old files: #{next_dir_path}"
185
+ FileUtils.rm_r(next_dir_path)
186
+ end
187
+
188
+ def next_dir_path
189
+ @next_dir_path ||= (out_path || File.join(lib_path, RUBY_NEXT_DIR))
190
+ end
191
+
192
+ def stdout?
193
+ out_path == "stdout"
194
+ end
195
+
196
+ def single_version?
197
+ single_version || specified_rewriters
198
+ end
199
+ end
200
+ end
201
+ end