ruby-next-core 0.6.0 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +25 -0
- data/README.md +37 -1
- data/lib/ruby-next/cli.rb +17 -1
- data/lib/ruby-next/commands/base.rb +15 -2
- data/lib/ruby-next/commands/core_ext.rb +4 -2
- data/lib/ruby-next/commands/nextify.rb +9 -4
- data/lib/ruby-next/language/parser.rb +4 -0
- data/lib/ruby-next/language/rewriters/method_reference.rb +0 -6
- data/lib/ruby-next/language/setup.rb +21 -2
- data/lib/ruby-next/logging.rb +1 -1
- data/lib/ruby-next/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 293ae08c0e4ae536624da190361e2825a5b17ee9c0589626540c05ff87e6ef0a
|
4
|
+
data.tar.gz: 45da1dcbc37d0c87c7f47cb300c38540dcd04085d8a85298747ca27e1c1ae99f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2e93d7c73f2d90cdc5005c62d85aef1c55fdc05fc8ae333a05749518e0a61e4d6317d378d9df39ed5e4afc8ee2c6853f3fac714ad6751a7204c75f9a0754e244
|
7
|
+
data.tar.gz: '053942e5c78cac2092a36491dc36d54e1f83aaa9a91dc4ecc021dfdc9c8c62572a549c063d1df70d618094694c1f8c4d13b69d3a50727551184a3bc5a38c40be'
|
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,31 @@
|
|
2
2
|
|
3
3
|
## master
|
4
4
|
|
5
|
+
- Try to auto-transpile the source code on load in `.setup_gem_load_path` if transpiled files are missing. ([@palkan][])
|
6
|
+
|
7
|
+
This would make it possible to install gems from source if transpiled files do not exist in the repository.
|
8
|
+
|
9
|
+
- Use`./.rbnextrc` to define CLI args. ([@palkan][])
|
10
|
+
|
11
|
+
You can define CLI options in the configuration file to re-use them between environments or
|
12
|
+
simply avoid typing every time:
|
13
|
+
|
14
|
+
```yml
|
15
|
+
# .rbnextrc
|
16
|
+
nextify: |
|
17
|
+
--transpiler-mode=rewrite
|
18
|
+
--edge
|
19
|
+
```
|
20
|
+
|
21
|
+
- Add `--dry-run` option to CLI. ([@palkan][])
|
22
|
+
|
23
|
+
- Raise `SyntaxError` when parsing fails. ([@palkan][])
|
24
|
+
|
25
|
+
Previously, we let Parser to raise its `Parser::SyntaxError` but some exceptions
|
26
|
+
are not reported by Parser and should be handled by transpiler (and we raised `SyntaxError` in that case, as MRI does).
|
27
|
+
|
28
|
+
This change unifies the exceptions raised during transpiling.
|
29
|
+
|
5
30
|
## 0.6.0 (2020-04-23)
|
6
31
|
|
7
32
|
- Changed the way edge/proposed features are activated. ([@palkan][])
|
data/README.md
CHANGED
@@ -181,6 +181,7 @@ Usage: ruby-next nextify DIRECTORY_OR_FILE [options]
|
|
181
181
|
--[no-]refine Do not inject `using RubyNext`
|
182
182
|
-h, --help Print help
|
183
183
|
-V Turn on verbose mode
|
184
|
+
--dry-run Print verbose output without generating files
|
184
185
|
```
|
185
186
|
|
186
187
|
The behaviour depends on whether you transpile a single file or a directory:
|
@@ -212,6 +213,7 @@ Usage: ruby-next core_ext [options]
|
|
212
213
|
-n, --name=NAME Filter extensions by name
|
213
214
|
-h, --help Print help
|
214
215
|
-V Turn on verbose mode
|
216
|
+
--dry-run Print verbose output without generating files
|
215
217
|
```
|
216
218
|
|
217
219
|
The most common use-case is to backport the APIs required by pattern matching. You can do this, for example,
|
@@ -238,7 +240,21 @@ $ ruby-next core_ext -l --name=filter --name=deconstruct
|
|
238
240
|
- StructDeconstruct
|
239
241
|
```
|
240
242
|
|
241
|
-
###
|
243
|
+
### CLI configuration file
|
244
|
+
|
245
|
+
You can define CLI options in the `.rbnextrc` file located in the root of your project to avoid adding them every time you run `ruby-next`.
|
246
|
+
|
247
|
+
Configuration file is a YAML with commands as keys and options as multiline strings:
|
248
|
+
|
249
|
+
```yml
|
250
|
+
# ./.rbnextrc
|
251
|
+
|
252
|
+
nextify: |
|
253
|
+
--transpiler-mode=rewrite
|
254
|
+
--edge
|
255
|
+
```
|
256
|
+
|
257
|
+
## Integrating into a gem development
|
242
258
|
|
243
259
|
We recommend _pre-transpiling_ source code to work with older versions before releasing it.
|
244
260
|
|
@@ -275,6 +291,24 @@ If you're using [runtime mode](#runtime-usage) a long with `setup_gem_load_path`
|
|
275
291
|
|
276
292
|
\* Ruby Next avoids storing duplicates; instead, only the code for the earlier version is created and is assumed to be used with other versions. For example, if the transpiled code is the same for Ruby 2.5 and Ruby 2.6, only the `.rbnext/2.7/path/to/file.rb` is kept. That's why multiple entries are added to the `$LOAD_PATH` (`.rbnext/2.6` and `.rbnext/2.7` in the specified order for Ruby 2.5 and only `.rbnext/2.7` for Ruby 2.6).
|
277
293
|
|
294
|
+
### Transpiled files vs. VSC vs. installing from source
|
295
|
+
|
296
|
+
It's a best practice to not keep generated files in repositories. In case of Ruby Next, it's a `lib/.rbnext` folder.
|
297
|
+
|
298
|
+
We recommend adding this folder only to the gem package (i.e., it should be added to your `spec.files`) and ignore it in your VSC (e.g., `echo ".rbnext/" >> .gitignore`). That would make transpiled files available in releases without polluting your repository.
|
299
|
+
|
300
|
+
What if someone decides to install your gem from the VSC source? They would likely face some syntax errors due to the missing transpiled files.
|
301
|
+
|
302
|
+
To solve this problem, Ruby Next _tries_ to transpile the source code when you call `#setup_gem_load_path`. It does this by calling `bundle exec ruby-next nextify <lib_dir> -o <next_dir>`. We make the following assumptions:
|
303
|
+
|
304
|
+
- We in the Bundler context (since that's the most common way of installing gems from source).
|
305
|
+
- Our Gemfile contains `ruby-next` gem.
|
306
|
+
- We use [`.rbnextrc`](#CLI-configuration-file) for transpiling options.
|
307
|
+
|
308
|
+
If the command fails we warn the end user.
|
309
|
+
|
310
|
+
This feature, _auto-transpiling_, is **disabled** by default (will likely be enabled in future versions). You can enable it by calling `RubyNext::Language.setup_gem_load_path(transpile: true)`.
|
311
|
+
|
278
312
|
## Runtime usage
|
279
313
|
|
280
314
|
It is also possible to transpile Ruby source code in run-time via Ruby Next.
|
@@ -364,6 +398,8 @@ AllCops:
|
|
364
398
|
- 'lib/.rbnext/**/*'
|
365
399
|
```
|
366
400
|
|
401
|
+
**NOTE:** you need `ruby-next` gem available in the environment where you run RuboCop (having `ruby-next-core` is not enough).
|
402
|
+
|
367
403
|
## Proposed and edge features
|
368
404
|
|
369
405
|
Ruby Next aims to bring edge and proposed features to Ruby community before they (hopefully) reach an official Ruby release.
|
data/lib/ruby-next/cli.rb
CHANGED
@@ -10,10 +10,14 @@ module RubyNext
|
|
10
10
|
# Command line interface for RubyNext
|
11
11
|
class CLI
|
12
12
|
class << self
|
13
|
-
attr_accessor :verbose
|
13
|
+
attr_accessor :verbose, :dry_run
|
14
|
+
|
15
|
+
alias verbose? verbose
|
16
|
+
alias dry_run? dry_run
|
14
17
|
end
|
15
18
|
|
16
19
|
self.verbose = false
|
20
|
+
self.dry_run = false
|
17
21
|
|
18
22
|
COMMANDS = {
|
19
23
|
"nextify" => Commands::Nextify,
|
@@ -36,6 +40,8 @@ module RubyNext
|
|
36
40
|
|
37
41
|
args.delete(command)
|
38
42
|
|
43
|
+
args.unshift(*load_args_from_rc(command))
|
44
|
+
|
39
45
|
COMMANDS.fetch(command) do
|
40
46
|
raise "Unknown command: #{command}. Available commands: #{COMMANDS.keys.join(",")}"
|
41
47
|
end.run(args)
|
@@ -89,5 +95,15 @@ module RubyNext
|
|
89
95
|
end
|
90
96
|
end
|
91
97
|
end
|
98
|
+
|
99
|
+
def load_args_from_rc(command)
|
100
|
+
return [] unless File.file?(".rbnextrc")
|
101
|
+
|
102
|
+
require "yaml"
|
103
|
+
command_args = YAML.load_file(".rbnextrc")[command]
|
104
|
+
return [] unless command_args
|
105
|
+
|
106
|
+
command_args.lines.flat_map { |line| line.chomp.split(/\s+/) }
|
107
|
+
end
|
92
108
|
end
|
93
109
|
end
|
@@ -11,6 +11,9 @@ module RubyNext
|
|
11
11
|
end
|
12
12
|
end
|
13
13
|
|
14
|
+
attr_reader :dry_run
|
15
|
+
alias dry_run? dry_run
|
16
|
+
|
14
17
|
def initialize(args)
|
15
18
|
parse! args
|
16
19
|
end
|
@@ -24,8 +27,13 @@ module RubyNext
|
|
24
27
|
end
|
25
28
|
|
26
29
|
def log(msg)
|
27
|
-
return unless CLI.verbose
|
28
|
-
|
30
|
+
return unless CLI.verbose?
|
31
|
+
|
32
|
+
if CLI.dry_run?
|
33
|
+
$stdout.puts "[DRY RUN] #{msg}"
|
34
|
+
else
|
35
|
+
$stdout.puts msg
|
36
|
+
end
|
29
37
|
end
|
30
38
|
|
31
39
|
def base_parser
|
@@ -35,6 +43,11 @@ module RubyNext
|
|
35
43
|
opts.on("-V", "Turn on verbose mode") do
|
36
44
|
CLI.verbose = true
|
37
45
|
end
|
46
|
+
|
47
|
+
opts.on("--dry-run", "Print verbose output without generating files") do
|
48
|
+
CLI.dry_run = true
|
49
|
+
CLI.verbose = true
|
50
|
+
end
|
38
51
|
end
|
39
52
|
end
|
40
53
|
end
|
@@ -136,8 +136,10 @@ module RubyNext
|
|
136
136
|
|
137
137
|
return $stdout.puts(contents) if out_path == "stdout"
|
138
138
|
|
139
|
-
|
140
|
-
|
139
|
+
unless CLI.dry_run?
|
140
|
+
FileUtils.mkdir_p File.dirname(out_path)
|
141
|
+
File.write(out_path, contents)
|
142
|
+
end
|
141
143
|
|
142
144
|
log "Generated: #{out_path}"
|
143
145
|
end
|
@@ -14,6 +14,8 @@ module RubyNext
|
|
14
14
|
|
15
15
|
def run
|
16
16
|
log "RubyNext core strategy: #{RubyNext::Core.strategy}"
|
17
|
+
log "RubyNext transpile mode: #{RubyNext::Language.mode}"
|
18
|
+
|
17
19
|
paths.each do |path|
|
18
20
|
contents = File.read(path)
|
19
21
|
transpile path, contents
|
@@ -64,6 +66,8 @@ module RubyNext
|
|
64
66
|
end
|
65
67
|
end
|
66
68
|
|
69
|
+
optparser.parse!(args)
|
70
|
+
|
67
71
|
@lib_path = args[0]
|
68
72
|
|
69
73
|
if print_help
|
@@ -72,12 +76,11 @@ module RubyNext
|
|
72
76
|
end
|
73
77
|
|
74
78
|
unless lib_path&.then(&File.method(:exist?))
|
79
|
+
$stdout.puts "Path not found: #{lib_path}"
|
75
80
|
$stdout.puts optparser.help
|
76
81
|
exit 2
|
77
82
|
end
|
78
83
|
|
79
|
-
optparser.parse!(args)
|
80
|
-
|
81
84
|
@paths =
|
82
85
|
if File.directory?(lib_path)
|
83
86
|
Dir[File.join(lib_path, "**/*.rb")]
|
@@ -132,9 +135,11 @@ module RubyNext
|
|
132
135
|
)
|
133
136
|
end
|
134
137
|
|
135
|
-
|
138
|
+
unless CLI.dry_run?
|
139
|
+
FileUtils.mkdir_p File.dirname(next_path)
|
136
140
|
|
137
|
-
|
141
|
+
File.write(next_path, contents)
|
142
|
+
end
|
138
143
|
|
139
144
|
log "Generated: #{next_path}"
|
140
145
|
end
|
@@ -23,6 +23,8 @@ module RubyNext
|
|
23
23
|
end
|
24
24
|
|
25
25
|
parser.parse(buffer)
|
26
|
+
rescue ::Parser::SyntaxError => e
|
27
|
+
raise ::SyntaxError, e.message
|
26
28
|
end
|
27
29
|
|
28
30
|
def parse_with_comments(source, file = "(string)")
|
@@ -31,6 +33,8 @@ module RubyNext
|
|
31
33
|
end
|
32
34
|
|
33
35
|
parser.parse_with_comments(buffer)
|
36
|
+
rescue ::Parser::SyntaxError => e
|
37
|
+
raise ::SyntaxError, e.message
|
34
38
|
end
|
35
39
|
end
|
36
40
|
end
|
@@ -5,6 +5,21 @@ require "ruby-next"
|
|
5
5
|
|
6
6
|
module RubyNext
|
7
7
|
module Language
|
8
|
+
# Module responsible for transpiling a library at load time
|
9
|
+
module GemTranspiler
|
10
|
+
def self.maybe_transpile(root_dir, lib_dir, target_dir)
|
11
|
+
return if File.directory?(target_dir)
|
12
|
+
|
13
|
+
Dir.chdir(root_dir) do
|
14
|
+
unless system("bundle exec ruby-next nextify ./#{lib_dir} -o #{target_dir} > /dev/null 2>&1")
|
15
|
+
RubyNext.warn "Traspiled files are missing in: #{target_dir}. \n" \
|
16
|
+
"Make sure you have gem 'ruby-next' in your Gemfile to auto-transpile the required files from source on load. " \
|
17
|
+
"Otherwise the code from #{root_dir} may not work correctly."
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
8
23
|
class << self
|
9
24
|
unless method_defined?(:runtime?)
|
10
25
|
def runtime?
|
@@ -12,7 +27,7 @@ module RubyNext
|
|
12
27
|
end
|
13
28
|
end
|
14
29
|
|
15
|
-
def setup_gem_load_path(lib_dir = "lib", rbnext_dir: RUBY_NEXT_DIR)
|
30
|
+
def setup_gem_load_path(lib_dir = "lib", rbnext_dir: RUBY_NEXT_DIR, transpile: false)
|
16
31
|
called_from = caller_locations(1, 1).first.path
|
17
32
|
dirname = File.dirname(called_from)
|
18
33
|
|
@@ -29,6 +44,10 @@ module RubyNext
|
|
29
44
|
|
30
45
|
return if Language.runtime? && Language.watch_dirs.include?(dirname)
|
31
46
|
|
47
|
+
next_dirname = File.join(dirname, rbnext_dir)
|
48
|
+
|
49
|
+
GemTranspiler.maybe_transpile(File.dirname(dirname), lib_dir, next_dirname) if transpile
|
50
|
+
|
32
51
|
current_index = $LOAD_PATH.index(dirname)
|
33
52
|
|
34
53
|
raise "Gem's lib is not in the $LOAD_PATH: #{dirname}" if current_index.nil?
|
@@ -38,7 +57,7 @@ module RubyNext
|
|
38
57
|
loop do
|
39
58
|
break unless version
|
40
59
|
|
41
|
-
version_dir = File.join(
|
60
|
+
version_dir = File.join(next_dirname, version.segments[0..1].join("."))
|
42
61
|
|
43
62
|
if File.exist?(version_dir)
|
44
63
|
$LOAD_PATH.insert current_index, version_dir
|
data/lib/ruby-next/logging.rb
CHANGED
data/lib/ruby-next/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ruby-next-core
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.7.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Vladimir Dementyev
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-04-
|
11
|
+
date: 2020-04-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: ruby-next-parser
|