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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5447b309915122d9f6dc9a366c34a566891c9f9cc569722c0999e020ef891d6b
4
- data.tar.gz: 9c2da837b1c9e4d2d36ea8665a90f7d3c004d6175b1d0e82262396846ac00f6a
3
+ metadata.gz: 293ae08c0e4ae536624da190361e2825a5b17ee9c0589626540c05ff87e6ef0a
4
+ data.tar.gz: 45da1dcbc37d0c87c7f47cb300c38540dcd04085d8a85298747ca27e1c1ae99f
5
5
  SHA512:
6
- metadata.gz: 7644e4703b233a730a3af183efaae78ea53cf5915ea70cc297ab8ebc8ff9346aad233c642cbf1d38ec82dc49deeab266e20ed35667e6c4069a7bb2f16b6c4e16
7
- data.tar.gz: 42fe6bf61bfd0cc97c1107455b873d97065eeb3f8c0c6ae3d7921b1fa208c155114e0e6012045d335fa31f1591093fabb58a3a2f1828c9fe668c2e798335ee80
6
+ metadata.gz: 2e93d7c73f2d90cdc5005c62d85aef1c55fdc05fc8ae333a05749518e0a61e4d6317d378d9df39ed5e4afc8ee2c6853f3fac714ad6751a7204c75f9a0754e244
7
+ data.tar.gz: '053942e5c78cac2092a36491dc36d54e1f83aaa9a91dc4ecc021dfdc9c8c62572a549c063d1df70d618094694c1f8c4d13b69d3a50727551184a3bc5a38c40be'
@@ -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
- ### Integrating into a gem development
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.
@@ -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
- $stdout.puts msg
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
- FileUtils.mkdir_p File.dirname(out_path)
140
- File.write(out_path, contents)
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
- FileUtils.mkdir_p File.dirname(next_path)
138
+ unless CLI.dry_run?
139
+ FileUtils.mkdir_p File.dirname(next_path)
136
140
 
137
- File.write(next_path, contents)
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
@@ -28,12 +28,6 @@ module RubyNext
28
28
  ]
29
29
  )
30
30
  end
31
-
32
- begin
33
- transform(SYNTAX_PROBE)
34
- rescue ::Parser::SyntaxError
35
- warn_custom_parser_required_for("method reference")
36
- end
37
31
  end
38
32
  end
39
33
  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(dirname, rbnext_dir, version.segments[0..1].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
@@ -38,6 +38,6 @@ module RubyNext
38
38
  attr_reader :debug_filter
39
39
  end
40
40
 
41
- self.silence_warnings = ENV["RUBY_NEXT_WARN"] != "false"
41
+ self.silence_warnings = ENV["RUBY_NEXT_WARN"] == "false"
42
42
  self.debug_enabled = ENV["RUBY_NEXT_DEBUG"]
43
43
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module RubyNext
4
- VERSION = "0.6.0"
4
+ VERSION = "0.7.0"
5
5
  end
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.6.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-23 00:00:00.000000000 Z
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