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.
- 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
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: eb05945d60839251b2e4ab0ee2969bb1ecc5f9d5470ad55ced6529973b0368c4
|
4
|
+
data.tar.gz: 32b2af2bfae9a8b660df2ea2b101a59864ad007cca6e82713e30fffc4b154e46
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: '0388183958efacdbadfe5b34f87a962b6529453c7be8882313bec5b0259b8d264d1697ce182048d1d2cc068e6f6eb15950aada4d70714aa3ac0d16ab6e6b4add'
|
7
|
+
data.tar.gz: a2beada149efd56af672802667e3e6dcc38e59cd281a5e9e6b84ec72dbb3faad5fae299d166715b06dfccfbbecfc0d6690a531a14571ec65862ea6ef7485f142
|
data/CHANGELOG.md
CHANGED
@@ -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.
|
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:**
|
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.
|
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
|