ruby-next-core 0.8.0 → 0.10.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (62) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +47 -0
  3. data/README.md +85 -11
  4. data/bin/transform +9 -1
  5. data/lib/.rbnext/2.3/ruby-next/commands/core_ext.rb +167 -0
  6. data/lib/.rbnext/2.3/ruby-next/commands/nextify.rb +198 -0
  7. data/lib/.rbnext/2.3/ruby-next/language/eval.rb +66 -0
  8. data/lib/.rbnext/2.3/ruby-next/language/rewriters/base.rb +121 -0
  9. data/lib/.rbnext/2.3/ruby-next/language/rewriters/endless_range.rb +63 -0
  10. data/lib/.rbnext/2.3/ruby-next/language/rewriters/pattern_matching.rb +944 -0
  11. data/lib/.rbnext/2.3/ruby-next/utils.rb +65 -0
  12. data/lib/ruby-next.rb +8 -5
  13. data/lib/ruby-next/cli.rb +2 -2
  14. data/lib/ruby-next/commands/core_ext.rb +2 -2
  15. data/lib/ruby-next/commands/nextify.rb +64 -22
  16. data/lib/ruby-next/core.rb +39 -22
  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 -5
  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 +2 -2
  38. data/lib/ruby-next/language.rb +31 -5
  39. data/lib/ruby-next/language/eval.rb +10 -8
  40. data/lib/ruby-next/language/proposed.rb +3 -0
  41. data/lib/ruby-next/language/rewriters/args_forward.rb +24 -20
  42. data/lib/ruby-next/language/rewriters/base.rb +2 -2
  43. data/lib/ruby-next/language/rewriters/endless_method.rb +26 -3
  44. data/lib/ruby-next/language/rewriters/endless_range.rb +1 -0
  45. data/lib/ruby-next/language/rewriters/find_pattern.rb +44 -0
  46. data/lib/ruby-next/language/rewriters/method_reference.rb +2 -1
  47. data/lib/ruby-next/language/rewriters/numbered_params.rb +1 -0
  48. data/lib/ruby-next/language/rewriters/pattern_matching.rb +105 -13
  49. data/lib/ruby-next/language/rewriters/right_hand_assignment.rb +2 -1
  50. data/lib/ruby-next/language/rewriters/runtime.rb +6 -0
  51. data/lib/ruby-next/language/rewriters/runtime/dir.rb +32 -0
  52. data/lib/ruby-next/language/rewriters/safe_navigation.rb +87 -0
  53. data/lib/ruby-next/language/rewriters/shorthand_hash.rb +47 -0
  54. data/lib/ruby-next/language/rewriters/squiggly_heredoc.rb +36 -0
  55. data/lib/ruby-next/language/runtime.rb +3 -2
  56. data/lib/ruby-next/logging.rb +1 -1
  57. data/lib/ruby-next/rubocop.rb +15 -9
  58. data/lib/ruby-next/setup_self.rb +22 -0
  59. data/lib/ruby-next/utils.rb +30 -0
  60. data/lib/ruby-next/version.rb +1 -1
  61. data/lib/uby-next.rb +8 -4
  62. metadata +22 -7
@@ -4,8 +4,9 @@ module RubyNext
4
4
  module Language
5
5
  module Rewriters
6
6
  class RightHandAssignment < Base
7
+ NAME = "right-hand-assignment"
7
8
  SYNTAX_PROBE = "1 + 2 => a"
8
- MIN_SUPPORTED_VERSION = Gem::Version.new("2.8.0")
9
+ MIN_SUPPORTED_VERSION = Gem::Version.new("3.0.0")
9
10
 
10
11
  def on_rasgn(node)
11
12
  context.track! self
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Load rewriters only required for runtime transpiling
4
+
5
+ require "ruby-next/language/rewriters/runtime/dir"
6
+ RubyNext::Language.rewriters << RubyNext::Language::Rewriters::Dir
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyNext
4
+ module Language
5
+ module Rewriters
6
+ # Special rewriter for Ruby <=2.3, which doesn't support __dir__ in iseq.eval
7
+ class Dir < Base
8
+ SYNTAX_PROBE = "defined?(RubyVM::InstructionSequence) && RubyVM::InstructionSequence.compile('raise SyntaxError if __dir__.nil?', 'test.rb').eval"
9
+ MIN_SUPPORTED_VERSION = Gem::Version.new("2.4.0")
10
+
11
+ def on_send(node)
12
+ return super(node) unless node.children[1] == :__dir__
13
+
14
+ context.track! self
15
+
16
+ replace(node.loc.expression, "File.dirname(__FILE__)")
17
+
18
+ process(
19
+ node.updated(
20
+ nil,
21
+ [
22
+ s(:const, nil, :File),
23
+ :dirname,
24
+ s(:send, nil, "__FILE__")
25
+ ]
26
+ )
27
+ )
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,87 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyNext
4
+ module Language
5
+ module Rewriters
6
+ class SafeNavigation < Base
7
+ NAME = "safe-navigation"
8
+ SYNTAX_PROBE = "nil&.x&.nil?"
9
+ MIN_SUPPORTED_VERSION = Gem::Version.new("2.3.0")
10
+
11
+ def on_csend(node)
12
+ node = super(node)
13
+
14
+ context.track! self
15
+
16
+ receiver, *args = *node
17
+
18
+ new_node = node.updated(
19
+ :and,
20
+ [
21
+ process(safe_navigation(receiver)),
22
+ s(:send, decsendize(receiver), *args)
23
+ ]
24
+ )
25
+
26
+ replace(node.loc.expression, new_node)
27
+
28
+ new_node
29
+ end
30
+
31
+ def on_block(node)
32
+ return super(node) unless node.children[0].type == :csend
33
+
34
+ context.track!(self)
35
+
36
+ new_node = super(node.updated(
37
+ :and,
38
+ [
39
+ process(safe_navigation(node.children[0].children[0])),
40
+ process(node.updated(nil, node.children.map(&method(:decsendize))))
41
+ ]
42
+ ))
43
+
44
+ replace(node.loc.expression, new_node)
45
+
46
+ new_node
47
+ end
48
+
49
+ def on_op_asgn(node)
50
+ return super(node) unless node.children[0].type == :csend
51
+
52
+ context.track!(self)
53
+
54
+ new_node = super(node.updated(
55
+ :and,
56
+ [
57
+ process(safe_navigation(node.children[0].children[0])),
58
+ process(node.updated(nil, node.children.map(&method(:decsendize))))
59
+ ]
60
+ ))
61
+
62
+ replace(node.loc.expression, new_node)
63
+
64
+ new_node
65
+ end
66
+
67
+ private
68
+
69
+ def decsendize(node)
70
+ return node unless node.is_a?(::Parser::AST::Node) && node.type == :csend
71
+
72
+ node.updated(:send, node.children.map(&method(:decsendize)))
73
+ end
74
+
75
+ # Transform: x&.y -> (!x.nil? && x.y) || nil
76
+ # This allows us to handle `false&.to_s == "false"`
77
+ def safe_navigation(node)
78
+ s(:or,
79
+ s(:send,
80
+ s(:send, node, :nil?),
81
+ :!),
82
+ s(:nil))
83
+ end
84
+ end
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyNext
4
+ module Language
5
+ module Rewriters
6
+ class ShorthandHash < Base
7
+ NAME = "shorthand-hash"
8
+ SYNTAX_PROBE = "data = {x}"
9
+ MIN_SUPPORTED_VERSION = Gem::Version.new("3.0.0")
10
+
11
+ def on_ipair(node)
12
+ context.track! self
13
+
14
+ ident, = *node.children
15
+
16
+ key = key_from_ident(ident)
17
+
18
+ replace(
19
+ node.loc.expression,
20
+ "#{key}: #{key}"
21
+ )
22
+
23
+ node.updated(
24
+ :pair,
25
+ [
26
+ s(:sym, key),
27
+ ident
28
+ ]
29
+ )
30
+ end
31
+
32
+ private
33
+
34
+ def key_from_ident(node)
35
+ case node.type
36
+ when :send
37
+ node.children[1]
38
+ when :lvar
39
+ node.children[0]
40
+ else
41
+ raise ArgumentError, "Unsupport ipair node: #{node}"
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyNext
4
+ module Language
5
+ module Rewriters
6
+ class SquigglyHeredoc < Base
7
+ NAME = "squiggly-heredoc"
8
+ SYNTAX_PROBE = "txt = <<~TXT\n bla\n TXT"
9
+ MIN_SUPPORTED_VERSION = Gem::Version.new("2.3.0")
10
+
11
+ def on_str(node)
12
+ node = super(node) if defined?(super_method)
13
+ return node unless node.loc.respond_to?(:heredoc_body) && node.loc.expression.source.include?("<<~")
14
+
15
+ context.track! self
16
+
17
+ replace(node.loc.expression, node.loc.expression.source.tr("~", "-"))
18
+
19
+ heredoc_loc = node.loc.heredoc_body.join(node.loc.heredoc_end)
20
+ heredoc_source, heredoc_end = heredoc_loc.source.split(/\n([^\n]+)\z/)
21
+
22
+ indent = heredoc_source.lines.map { |line| line.match(/^\s*/)[0].size }.min
23
+
24
+ new_source = heredoc_source.gsub!(%r{^\s{#{indent}}}, "")
25
+
26
+ replace(heredoc_loc, [new_source, heredoc_end].join("\n"))
27
+
28
+ node
29
+ end
30
+
31
+ alias on_dstr on_str
32
+ alias on_xstr on_str
33
+ end
34
+ end
35
+ end
36
+ end
@@ -42,7 +42,7 @@ module RubyNext
42
42
  path
43
43
  end
44
44
 
45
- if defined?(JRUBY_VERSION)
45
+ if defined?(JRUBY_VERSION) || defined?(TruffleRuby)
46
46
  def evaluate(code, filepath)
47
47
  new_toplevel.eval(code, filepath)
48
48
  end
@@ -89,7 +89,8 @@ module Kernel
89
89
 
90
90
  alias_method :require_relative_without_ruby_next, :require_relative
91
91
  def require_relative(path)
92
- from = caller_locations(1..1).first.absolute_path || File.join(Dir.pwd, "main")
92
+ loc = caller_locations(1..1).first
93
+ from = loc.absolute_path || loc.path || File.join(Dir.pwd, "main")
93
94
  realpath = File.absolute_path(
94
95
  File.join(
95
96
  File.dirname(File.absolute_path(from)),
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "utils"
3
+ require "ruby-next/utils"
4
4
 
5
5
  module RubyNext
6
6
  class << self
@@ -46,23 +46,25 @@ module RuboCop
46
46
  end
47
47
  end
48
48
 
49
+ # Let's make this file Ruby 2.2 compatible to avoid transpiling
50
+ # rubocop:disable Layout/HeredocIndentation
49
51
  module RuboCop
50
52
  module AST
51
53
  module Traversal
52
54
  # Fixed in https://github.com/rubocop-hq/rubocop/pull/7786
53
- unless defined?(::RuboCop::AST::CaseMatchNode)
54
- %i[case_match in_pattern].each do |type|
55
- module_eval(<<~RUBY, __FILE__, __LINE__ + 1)
56
- def on_#{type}(node)
57
- node.children.each { |child| send(:"on_\#{child.type}", child) if child }
58
- nil
59
- end
60
- RUBY
61
- end
55
+ %i[case_match in_pattern find_pattern].each do |type|
56
+ next if method_defined?(:"on_#{type}")
57
+ module_eval(<<-RUBY, __FILE__, __LINE__ + 1)
58
+ def on_#{type}(node)
59
+ node.children.each { |child| send(:"on_\#{child.type}", child) if child }
60
+ nil
61
+ end
62
+ RUBY
62
63
  end
63
64
  end
64
65
  end
65
66
  end
67
+ # rubocop:enable Layout/HeredocIndentation
66
68
 
67
69
  module RuboCop
68
70
  module Cop
@@ -73,6 +75,10 @@ module RuboCop
73
75
  trigger_responding_cops(:on_meth_ref, node)
74
76
  end
75
77
 
78
+ def on_ipair(node)
79
+ trigger_responding_cops(:on_ipair, node)
80
+ end
81
+
76
82
  unless method_defined?(:on_numblock)
77
83
  def on_numblock(node)
78
84
  children = node.children
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This file setup LOAD_PATH to load Ruby Next own transpiled paths
4
+ # (we cannot use language/setup here, 'cause it requires Core to be loaded)
5
+
6
+ version = RubyNext.next_version
7
+ next_dirname = File.join(__dir__, "..", ".rbnext")
8
+ lib_path = File.realpath(File.join(__dir__, ".."))
9
+ current_index = $LOAD_PATH.index(lib_path)
10
+
11
+ loop do
12
+ break unless version
13
+
14
+ version_dir = File.join(next_dirname, version.segments[0..1].join("."))
15
+
16
+ if File.exist?(version_dir)
17
+ $LOAD_PATH.insert current_index, version_dir
18
+ current_index += 1
19
+ end
20
+
21
+ version = RubyNext.next_version(version)
22
+ end
@@ -33,5 +33,35 @@ module RubyNext
33
33
  lines.unshift " 0: # source: #{path}"
34
34
  end
35
35
  end
36
+
37
+ # Returns true if modules refinement is supported in current version
38
+ def refine_modules?
39
+ @refine_modules ||=
40
+ begin
41
+ # Make sure that including modules within refinements works
42
+ # See https://github.com/oracle/truffleruby/issues/2026
43
+ eval <<~RUBY, TOPLEVEL_BINDING, __FILE__, __LINE__ + 1
44
+ module RubyNext::Utils::A; end
45
+ class RubyNext::Utils::B
46
+ include RubyNext::Utils::A
47
+ end
48
+
49
+ using(Module.new do
50
+ refine RubyNext::Utils::A do
51
+ include(Module.new do
52
+ def i_am_refinement
53
+ "yes, you are!"
54
+ end
55
+ end)
56
+ end
57
+ end)
58
+
59
+ RubyNext::Utils::B.new.i_am_refinement
60
+ RUBY
61
+ true
62
+ rescue TypeError, NoMethodError
63
+ false
64
+ end
65
+ end
36
66
  end
37
67
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module RubyNext
4
- VERSION = "0.8.0"
4
+ VERSION = "0.10.0"
5
5
  end
@@ -43,11 +43,14 @@ at_exit do
43
43
  end
44
44
 
45
45
  if $0 == "-e" && e_script.nil?
46
- `ps axw`.split("\n").find { |ps| ps[/\A\s*#{$$}/] }.then do |command|
46
+ if File.file?("/proc/self/cmdline")
47
+ File.read("/proc/self/cmdline")
48
+ else
49
+ `ps axw`.split("\n").find { |ps| ps[/\A\s*#{$$}/] }
50
+ end.then do |command|
47
51
  next unless command
48
- command.tr! '\012', "\n"
49
- command.tr! "\\", "\n"
50
- command.match(/\-e(.*)/m)
52
+ command.gsub!(/(\\012|\u0000)/, "\n")
53
+ command.match(/-e(.*)/m)
51
54
  end.then do |matches|
52
55
  next unless matches
53
56
 
@@ -63,6 +66,7 @@ at_exit do
63
66
 
64
67
  if e_script
65
68
  new_e_script = RubyNext::Language::Runtime.transform(e_script)
69
+ RubyNext.debug_source new_e_script, $0
66
70
  TOPLEVEL_BINDING.eval(new_e_script, $0)
67
71
  exit!(0)
68
72
  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.8.0
4
+ version: 0.10.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-05-01 00:00:00.000000000 Z
11
+ date: 2020-09-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ruby-next-parser
@@ -16,28 +16,28 @@ dependencies:
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: 2.8.0.4
19
+ version: 3.0.0.0
20
20
  type: :development
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: 2.8.0.4
26
+ version: 3.0.0.0
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: unparser
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: 0.4.7
33
+ version: 0.4.8
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - ">="
39
39
  - !ruby/object:Gem::Version
40
- version: 0.4.7
40
+ version: 0.4.8
41
41
  description: "\n Ruby Next Core is a zero deps version of Ruby Next meant to be
42
42
  used\n as as dependency in your gems.\n\n It contains all the polyfills and
43
43
  utility files but doesn't require transpiler\n dependencies to be install.\n
@@ -55,6 +55,13 @@ files:
55
55
  - bin/parse
56
56
  - bin/ruby-next
57
57
  - bin/transform
58
+ - lib/.rbnext/2.3/ruby-next/commands/core_ext.rb
59
+ - lib/.rbnext/2.3/ruby-next/commands/nextify.rb
60
+ - lib/.rbnext/2.3/ruby-next/language/eval.rb
61
+ - lib/.rbnext/2.3/ruby-next/language/rewriters/base.rb
62
+ - lib/.rbnext/2.3/ruby-next/language/rewriters/endless_range.rb
63
+ - lib/.rbnext/2.3/ruby-next/language/rewriters/pattern_matching.rb
64
+ - lib/.rbnext/2.3/ruby-next/utils.rb
58
65
  - lib/ruby-next.rb
59
66
  - lib/ruby-next/cli.rb
60
67
  - lib/ruby-next/commands/base.rb
@@ -69,6 +76,7 @@ files:
69
76
  - lib/ruby-next/core/enumerable/tally.rb
70
77
  - lib/ruby-next/core/enumerator/produce.rb
71
78
  - lib/ruby-next/core/hash/deconstruct_keys.rb
79
+ - lib/ruby-next/core/hash/except.rb
72
80
  - lib/ruby-next/core/hash/merge.rb
73
81
  - lib/ruby-next/core/kernel/then.rb
74
82
  - lib/ruby-next/core/proc/compose.rb
@@ -92,15 +100,22 @@ files:
92
100
  - lib/ruby-next/language/rewriters/base.rb
93
101
  - lib/ruby-next/language/rewriters/endless_method.rb
94
102
  - lib/ruby-next/language/rewriters/endless_range.rb
103
+ - lib/ruby-next/language/rewriters/find_pattern.rb
95
104
  - lib/ruby-next/language/rewriters/method_reference.rb
96
105
  - lib/ruby-next/language/rewriters/numbered_params.rb
97
106
  - lib/ruby-next/language/rewriters/pattern_matching.rb
98
107
  - lib/ruby-next/language/rewriters/right_hand_assignment.rb
108
+ - lib/ruby-next/language/rewriters/runtime.rb
109
+ - lib/ruby-next/language/rewriters/runtime/dir.rb
110
+ - lib/ruby-next/language/rewriters/safe_navigation.rb
111
+ - lib/ruby-next/language/rewriters/shorthand_hash.rb
112
+ - lib/ruby-next/language/rewriters/squiggly_heredoc.rb
99
113
  - lib/ruby-next/language/runtime.rb
100
114
  - lib/ruby-next/language/setup.rb
101
115
  - lib/ruby-next/language/unparser.rb
102
116
  - lib/ruby-next/logging.rb
103
117
  - lib/ruby-next/rubocop.rb
118
+ - lib/ruby-next/setup_self.rb
104
119
  - lib/ruby-next/utils.rb
105
120
  - lib/ruby-next/version.rb
106
121
  - lib/uby-next.rb
@@ -121,7 +136,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
121
136
  requirements:
122
137
  - - ">="
123
138
  - !ruby/object:Gem::Version
124
- version: 2.5.0
139
+ version: 2.2.0
125
140
  required_rubygems_version: !ruby/object:Gem::Requirement
126
141
  requirements:
127
142
  - - ">="