ruby-next-core 0.9.2 → 0.10.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +40 -0
- data/README.md +15 -4
- data/lib/.rbnext/2.3/ruby-next/commands/core_ext.rb +167 -0
- data/lib/.rbnext/2.3/ruby-next/commands/nextify.rb +201 -0
- data/lib/.rbnext/2.3/ruby-next/language/eval.rb +66 -0
- data/lib/.rbnext/2.3/ruby-next/language/rewriters/base.rb +121 -0
- data/lib/.rbnext/2.3/ruby-next/language/rewriters/endless_range.rb +63 -0
- data/lib/.rbnext/2.3/ruby-next/language/rewriters/pattern_matching.rb +944 -0
- data/lib/.rbnext/2.3/ruby-next/language/rewriters/right_hand_assignment.rb +107 -0
- data/lib/.rbnext/2.3/ruby-next/utils.rb +65 -0
- data/lib/ruby-next.rb +8 -6
- data/lib/ruby-next/cli.rb +2 -2
- data/lib/ruby-next/commands/core_ext.rb +1 -1
- data/lib/ruby-next/commands/nextify.rb +3 -0
- data/lib/ruby-next/core.rb +27 -21
- data/lib/ruby-next/core/array/deconstruct.rb +9 -9
- data/lib/ruby-next/core/array/difference_union_intersection.rb +12 -12
- data/lib/ruby-next/core/constants/no_matching_pattern_error.rb +3 -3
- data/lib/ruby-next/core/enumerable/filter.rb +8 -8
- data/lib/ruby-next/core/enumerable/filter_map.rb +25 -25
- data/lib/ruby-next/core/enumerable/tally.rb +7 -7
- data/lib/ruby-next/core/enumerator/produce.rb +12 -12
- data/lib/ruby-next/core/hash/deconstruct_keys.rb +9 -9
- data/lib/ruby-next/core/hash/except.rb +11 -0
- data/lib/ruby-next/core/hash/merge.rb +8 -8
- data/lib/ruby-next/core/kernel/then.rb +2 -2
- data/lib/ruby-next/core/proc/compose.rb +11 -11
- data/lib/ruby-next/core/string/split.rb +6 -6
- data/lib/ruby-next/core/struct/deconstruct.rb +2 -2
- data/lib/ruby-next/core/struct/deconstruct_keys.rb +17 -17
- data/lib/ruby-next/core/symbol/end_with.rb +4 -4
- data/lib/ruby-next/core/symbol/start_with.rb +4 -4
- data/lib/ruby-next/core/time/ceil.rb +6 -6
- data/lib/ruby-next/core/time/floor.rb +4 -4
- data/lib/ruby-next/core/unboundmethod/bind_call.rb +4 -4
- data/lib/ruby-next/core_ext.rb +1 -1
- data/lib/ruby-next/language.rb +12 -1
- data/lib/ruby-next/language/parser.rb +0 -3
- data/lib/ruby-next/language/proposed.rb +3 -0
- data/lib/ruby-next/language/rewriters/args_forward.rb +23 -20
- data/lib/ruby-next/language/rewriters/base.rb +1 -1
- data/lib/ruby-next/language/rewriters/endless_method.rb +25 -3
- data/lib/ruby-next/language/rewriters/find_pattern.rb +44 -0
- data/lib/ruby-next/language/rewriters/method_reference.rb +1 -1
- data/lib/ruby-next/language/rewriters/pattern_matching.rb +102 -12
- data/lib/ruby-next/language/rewriters/right_hand_assignment.rb +73 -11
- data/lib/ruby-next/language/rewriters/safe_navigation.rb +87 -0
- data/lib/ruby-next/language/rewriters/shorthand_hash.rb +47 -0
- data/lib/ruby-next/language/rewriters/squiggly_heredoc.rb +36 -0
- data/lib/ruby-next/language/unparser.rb +0 -14
- data/lib/ruby-next/logging.rb +1 -1
- data/lib/ruby-next/rubocop.rb +91 -9
- data/lib/ruby-next/setup_self.rb +22 -0
- data/lib/ruby-next/version.rb +1 -1
- data/lib/uby-next.rb +8 -4
- metadata +23 -9
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
|