ruby-next-core 0.10.5 → 0.13.0

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.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +41 -0
  3. data/README.md +25 -16
  4. data/lib/.rbnext/2.1/ruby-next/core.rb +206 -0
  5. data/lib/.rbnext/2.1/ruby-next/language.rb +227 -0
  6. data/lib/.rbnext/2.3/ruby-next/commands/nextify.rb +2 -2
  7. data/lib/.rbnext/2.3/ruby-next/language/eval.rb +4 -4
  8. data/lib/.rbnext/2.3/ruby-next/language/rewriters/base.rb +23 -5
  9. data/lib/.rbnext/2.3/ruby-next/language/rewriters/endless_range.rb +1 -1
  10. data/lib/.rbnext/2.3/ruby-next/language/rewriters/pattern_matching.rb +20 -17
  11. data/lib/.rbnext/2.3/ruby-next/utils.rb +1 -1
  12. data/lib/.rbnext/2.7/ruby-next/core.rb +206 -0
  13. data/lib/ruby-next/commands/nextify.rb +1 -1
  14. data/lib/ruby-next/config.rb +50 -0
  15. data/lib/ruby-next/core/array/deconstruct.rb +1 -1
  16. data/lib/ruby-next/core/array/intersect.rb +9 -0
  17. data/lib/ruby-next/core/constants/frozen_error.rb +15 -0
  18. data/lib/ruby-next/core/constants/no_matching_pattern_error.rb +1 -1
  19. data/lib/ruby-next/core/enumerable/tally.rb +46 -7
  20. data/lib/ruby-next/core/hash/deconstruct_keys.rb +1 -1
  21. data/lib/ruby-next/core/struct/deconstruct_keys.rb +3 -3
  22. data/lib/ruby-next/core.rb +8 -4
  23. data/lib/ruby-next/core_ext.rb +3 -1
  24. data/lib/ruby-next/language/bootsnap.rb +1 -1
  25. data/lib/ruby-next/language/edge.rb +0 -6
  26. data/lib/ruby-next/language/eval.rb +3 -3
  27. data/lib/ruby-next/language/parser.rb +16 -0
  28. data/lib/ruby-next/language/rewriters/args_forward.rb +14 -6
  29. data/lib/ruby-next/language/rewriters/args_forward_leading.rb +75 -0
  30. data/lib/ruby-next/language/rewriters/base.rb +19 -1
  31. data/lib/ruby-next/language/rewriters/in_pattern.rb +56 -0
  32. data/lib/ruby-next/language/rewriters/method_reference.rb +1 -1
  33. data/lib/ruby-next/language/rewriters/numeric_literals.rb +41 -0
  34. data/lib/ruby-next/language/rewriters/pattern_matching.rb +18 -15
  35. data/lib/ruby-next/language/rewriters/required_kwargs.rb +39 -0
  36. data/lib/ruby-next/language/rewriters/safe_navigation.rb +42 -29
  37. data/lib/ruby-next/language/rewriters/shorthand_hash.rb +1 -1
  38. data/lib/ruby-next/language/setup.rb +7 -4
  39. data/lib/ruby-next/language/unparser.rb +5 -0
  40. data/lib/ruby-next/language.rb +62 -44
  41. data/lib/ruby-next/rubocop.rb +9 -18
  42. data/lib/ruby-next/setup_self.rb +5 -3
  43. data/lib/ruby-next/version.rb +1 -1
  44. data/lib/ruby-next.rb +5 -38
  45. metadata +20 -18
  46. data/lib/.rbnext/2.3/ruby-next/language/rewriters/right_hand_assignment.rb +0 -117
  47. data/lib/ruby-next/language/rewriters/right_hand_assignment.rb +0 -117
@@ -20,7 +20,7 @@ module RubyNext
20
20
  module InstanceEval # :nodoc:
21
21
  refine Object do
22
22
  def instance_eval(*args, &block)
23
- return super(*args, &block) if block_given?
23
+ return super(*args, &block) if block
24
24
 
25
25
  source = args.shift
26
26
  new_source = ::RubyNext::Language::Runtime.transform(source, using: false)
@@ -33,7 +33,7 @@ module RubyNext
33
33
  module ClassEval
34
34
  refine Module do
35
35
  def module_eval(*args, &block)
36
- return super(*args, &block) if block_given?
36
+ return super(*args, &block) if block
37
37
 
38
38
  source = args.shift
39
39
  new_source = ::RubyNext::Language::Runtime.transform(source, using: false)
@@ -42,7 +42,7 @@ module RubyNext
42
42
  end
43
43
 
44
44
  def class_eval(*args, &block)
45
- return super(*args, &block) if block_given?
45
+ return super(*args, &block) if block
46
46
 
47
47
  source = args.shift
48
48
  new_source = ::RubyNext::Language::Runtime.transform(source, using: false)
@@ -4,8 +4,24 @@ require "parser/rubynext"
4
4
 
5
5
  module RubyNext
6
6
  module Language
7
+ module BuilderExt
8
+ def match_pattern(lhs, match_t, rhs)
9
+ n(:match_pattern, [lhs, rhs],
10
+ binary_op_map(lhs, match_t, rhs))
11
+ end
12
+
13
+ def match_pattern_p(lhs, match_t, rhs)
14
+ n(:match_pattern_p, [lhs, rhs],
15
+ binary_op_map(lhs, match_t, rhs))
16
+ end
17
+ end
18
+
7
19
  class Builder < ::Parser::Builders::Default
8
20
  modernize
21
+
22
+ unless method_defined?(:match_pattern_p)
23
+ include BuilderExt
24
+ end
9
25
  end
10
26
 
11
27
  class << self
@@ -5,22 +5,26 @@ module RubyNext
5
5
  module Rewriters
6
6
  class ArgsForward < Base
7
7
  NAME = "args-forward"
8
- SYNTAX_PROBE = "obj = Object.new; def obj.foo(...) super(1, ...); end"
9
- MIN_SUPPORTED_VERSION = Gem::Version.new("3.0.0")
8
+ SYNTAX_PROBE = "obj = Object.new; def obj.foo(...) super(...); end"
9
+ MIN_SUPPORTED_VERSION = Gem::Version.new("2.7.0")
10
10
 
11
11
  REST = :__rest__
12
12
  BLOCK = :__block__
13
13
 
14
- def on_forward_arg(node)
14
+ def on_args(node)
15
+ farg = node.children.find { |child| child.is_a?(::Parser::AST::Node) && child.type == :forward_arg }
16
+ return unless farg
17
+
15
18
  context.track! self
16
19
 
17
20
  node = super(node)
18
21
 
19
- replace(node.loc.expression, "*#{REST}, &#{BLOCK}")
22
+ replace(farg.loc.expression, "*#{REST}, &#{BLOCK}")
20
23
 
21
24
  node.updated(
22
25
  :args,
23
26
  [
27
+ *node.children.slice(0, node.children.index(farg)),
24
28
  s(:restarg, REST),
25
29
  s(:blockarg, BLOCK)
26
30
  ]
@@ -28,14 +32,14 @@ module RubyNext
28
32
  end
29
33
 
30
34
  def on_send(node)
31
- fargs = node.children.find { |child| child.is_a?(::Parser::AST::Node) && child.type == :forwarded_args }
35
+ fargs = extract_fargs(node)
32
36
  return super(node) unless fargs
33
37
 
34
38
  process_fargs(node, fargs)
35
39
  end
36
40
 
37
41
  def on_super(node)
38
- fargs = node.children.find { |child| child.is_a?(::Parser::AST::Node) && child.type == :forwarded_args }
42
+ fargs = extract_fargs(node)
39
43
  return super(node) unless fargs
40
44
 
41
45
  process_fargs(node, fargs)
@@ -43,6 +47,10 @@ module RubyNext
43
47
 
44
48
  private
45
49
 
50
+ def extract_fargs(node)
51
+ node.children.find { |child| child.is_a?(::Parser::AST::Node) && child.type == :forwarded_args }
52
+ end
53
+
46
54
  def process_fargs(node, fargs)
47
55
  replace(fargs.loc.expression, "*#{REST}, &#{BLOCK}")
48
56
 
@@ -0,0 +1,75 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyNext
4
+ module Language
5
+ module Rewriters
6
+ class ArgsForwardLeading < ArgsForward
7
+ NAME = "args-forward-leading"
8
+ SYNTAX_PROBE = "obj = Object.new; def obj.foo(...) super(1, ...); end"
9
+ MIN_SUPPORTED_VERSION = Gem::Version.new("3.0.0")
10
+
11
+ attr_reader :leading_farg
12
+ alias leading_farg? leading_farg
13
+
14
+ def on_def(node)
15
+ @leading_farg = method_with_leading_arg(node)
16
+
17
+ super
18
+ end
19
+
20
+ def on_defs(node)
21
+ @leading_farg = method_with_leading_arg(node)
22
+
23
+ super
24
+ end
25
+
26
+ def on_args(node)
27
+ return super if leading_farg?
28
+
29
+ node
30
+ end
31
+
32
+ def on_send(node)
33
+ return super if leading_farg?
34
+
35
+ node
36
+ end
37
+
38
+ def on_super(node)
39
+ return super if leading_farg?
40
+
41
+ node
42
+ end
43
+
44
+ private
45
+
46
+ def send_with_leading_farg(node)
47
+ return false unless node.type == :send || node.type == :super
48
+
49
+ fargs = extract_fargs(node)
50
+
51
+ return false unless fargs
52
+
53
+ node.children.index(fargs) > (node.type == :send ? 2 : 0)
54
+ end
55
+
56
+ def method_with_leading_arg(node)
57
+ find_child(node) { |child| child.type == :forward_arg } &&
58
+ (
59
+ def_with_leading_farg(node) ||
60
+ find_child(node) { |child| send_with_leading_farg(child) }
61
+ )
62
+ end
63
+
64
+ def def_with_leading_farg(node)
65
+ args = node.type == :defs ? node.children[2] : node.children[1]
66
+ args = args.children
67
+
68
+ farg = args.detect { |child| child.type == :forward_arg }
69
+
70
+ args.index(farg) > 0
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end
@@ -61,7 +61,7 @@ module RubyNext
61
61
  eval_mid = Kernel.respond_to?(:eval_without_ruby_next) ? :eval_without_ruby_next : :eval
62
62
  Kernel.send eval_mid, self::SYNTAX_PROBE, nil, __FILE__, __LINE__
63
63
  false
64
- rescue SyntaxError, NameError
64
+ rescue SyntaxError, StandardError
65
65
  true
66
66
  ensure
67
67
  $VERBOSE = save_verbose
@@ -94,6 +94,24 @@ module RubyNext
94
94
 
95
95
  private
96
96
 
97
+ # BFS with predicate block
98
+ def find_child(node)
99
+ queue = [node]
100
+
101
+ loop do
102
+ break if queue.empty?
103
+
104
+ child = queue.shift
105
+ next unless child.is_a?(::Parser::AST::Node)
106
+
107
+ return child if yield child
108
+
109
+ queue.push(*child.children)
110
+ end
111
+
112
+ nil
113
+ end
114
+
97
115
  def replace(range, ast)
98
116
  @source_rewriter&.replace(range, unparse(ast))
99
117
  end
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "ruby-next/language/rewriters/pattern_matching"
4
+
5
+ module RubyNext
6
+ module Language
7
+ module Rewriters
8
+ using RubyNext
9
+
10
+ # Separate pattern matching rewriter for Ruby 2.7 to
11
+ # transpile only `in` patterns
12
+ class InPattern < PatternMatching
13
+ NAME = "pattern-matching-in"
14
+ SYNTAX_PROBE = "1 in 2"
15
+ MIN_SUPPORTED_VERSION = Gem::Version.new("3.0.0")
16
+
17
+ # Make case-match no-op
18
+ def on_case_match(node)
19
+ node
20
+ end
21
+
22
+ def on_match_pattern_p(node)
23
+ context.track! self
24
+
25
+ @deconstructed_keys = {}
26
+ @predicates = Predicates::Noop.new
27
+
28
+ matchee =
29
+ s(:begin, s(:lvasgn, MATCHEE, node.children[0]))
30
+
31
+ pattern =
32
+ locals.with(
33
+ matchee: MATCHEE,
34
+ arr: MATCHEE_ARR,
35
+ hash: MATCHEE_HASH
36
+ ) do
37
+ send(
38
+ :"#{node.children[1].type}_clause",
39
+ node.children[1]
40
+ )
41
+ end
42
+
43
+ node.updated(
44
+ :and,
45
+ [
46
+ matchee,
47
+ pattern
48
+ ]
49
+ ).tap do |new_node|
50
+ replace(node.loc.expression, inline_blocks(unparse(new_node)))
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
@@ -6,7 +6,7 @@ module RubyNext
6
6
  class MethodReference < Base
7
7
  NAME = "method-reference"
8
8
  SYNTAX_PROBE = "Language.:transform"
9
- MIN_SUPPORTED_VERSION = Gem::Version.new("3.0.0")
9
+ MIN_SUPPORTED_VERSION = Gem::Version.new(RubyNext::NEXT_VERSION)
10
10
 
11
11
  def on_meth_ref(node)
12
12
  context.track! self
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyNext
4
+ module Language
5
+ module Rewriters
6
+ class NumericLiterals < Base
7
+ using RubyNext
8
+
9
+ NAME = "numeric-literals"
10
+ SYNTAX_PROBE = "2i + 1/2r"
11
+ MIN_SUPPORTED_VERSION = Gem::Version.new("2.1.0")
12
+
13
+ def on_rational(node)
14
+ context.track! self
15
+
16
+ val = node.children.first
17
+
18
+ parts = [s(:int, val.numerator)]
19
+
20
+ parts << s(:int, val.denominator) unless val.denominator == 1
21
+
22
+ s(:send, nil, :Rational, *parts).tap do |new_node|
23
+ replace(node.loc.expression, new_node)
24
+ end
25
+ end
26
+
27
+ def on_complex(node)
28
+ context.track! self
29
+
30
+ val = node.children.first
31
+
32
+ s(:send, nil, :Complex,
33
+ s(:int, val.real),
34
+ s(:int, val.imaginary)).tap do |new_node|
35
+ replace(node.loc.expression, new_node)
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -13,12 +13,12 @@ module RubyNext
13
13
 
14
14
  # Useful to generate simple operation nodes
15
15
  # (e.g., 'a + b')
16
- def -(val)
17
- ::Parser::AST::Node.new(:send, [self, :-, val.to_ast_node])
16
+ def -(other)
17
+ ::Parser::AST::Node.new(:send, [self, :-, other.to_ast_node])
18
18
  end
19
19
 
20
- def +(val)
21
- ::Parser::AST::Node.new(:send, [self, :+, val.to_ast_node])
20
+ def +(other)
21
+ ::Parser::AST::Node.new(:send, [self, :+, other.to_ast_node])
22
22
  end
23
23
  end
24
24
 
@@ -218,9 +218,10 @@ module RubyNext
218
218
  predicate_clause(:respond_to_deconstruct_keys, node)
219
219
  end
220
220
 
221
- def hash_key(node, key)
222
- key = key.children.first if key.is_a?(::Parser::AST::Node)
223
- predicate_clause(:"hash_key_#{key}", node)
221
+ def hash_keys(node, keys)
222
+ keys = keys.map { |key| key.is_a?(::Parser::AST::Node) ? key.children.first : key }
223
+
224
+ predicate_clause(:"hash_keys_#{keys.join("_p_")}", node)
224
225
  end
225
226
  end
226
227
  end
@@ -266,7 +267,7 @@ module RubyNext
266
267
  )
267
268
  end
268
269
 
269
- def on_in_match(node)
270
+ def on_match_pattern(node)
270
271
  context.track! self
271
272
 
272
273
  @deconstructed_keys = {}
@@ -303,6 +304,8 @@ module RubyNext
303
304
  end
304
305
  end
305
306
 
307
+ alias on_in_match on_match_pattern
308
+
306
309
  private
307
310
 
308
311
  def rewrite_case_in!(node, matchee, new_node)
@@ -350,7 +353,7 @@ module RubyNext
350
353
 
351
354
  else_clause = (else_clause || no_matching_pattern).then do |node|
352
355
  next node unless node.type == :empty_else
353
- s(:empty)
356
+ nil
354
357
  end
355
358
 
356
359
  clauses << else_clause
@@ -883,14 +886,14 @@ module RubyNext
883
886
  end
884
887
 
885
888
  def having_hash_keys(keys, hash = s(:lvar, locals[:hash]))
886
- key = keys.shift
887
- node = predicates.hash_key(hash_has_key(key, hash), key)
889
+ keys.reduce(nil) do |acc, key|
890
+ pnode = hash_has_key(key, hash)
891
+ next pnode unless acc
888
892
 
889
- keys.reduce(node) do |res, key|
890
893
  s(:begin,
891
- s(:and,
892
- res,
893
- predicates.hash_key(hash_has_key(key, hash), key)))
894
+ s(:and, acc, pnode))
895
+ end.then do |node|
896
+ predicates.hash_keys(node, keys)
894
897
  end
895
898
  end
896
899
 
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyNext
4
+ module Language
5
+ module Rewriters
6
+ class RequiredKwargs < Base
7
+ using RubyNext
8
+
9
+ NAME = "required-kwargs"
10
+ SYNTAX_PROBE = "obj = Object.new; def obj.foo(x:, y: 1); end"
11
+ MIN_SUPPORTED_VERSION = Gem::Version.new("2.1.0")
12
+
13
+ def on_kwarg(node)
14
+ context.track! self
15
+
16
+ name = node.children[0]
17
+
18
+ new_node = node.updated(
19
+ :kwoptarg,
20
+ [name, raise_missing_keyword(name)]
21
+ )
22
+
23
+ replace(node.loc.expression, "#{name}: ::Kernel.raise(::ArgumentError, \"missing keyword: #{name}\")")
24
+
25
+ new_node
26
+ end
27
+
28
+ private
29
+
30
+ def raise_missing_keyword(name)
31
+ s(:send,
32
+ s(:const, s(:cbase), :Kernel), :raise,
33
+ s(:const, s(:cbase), :ArgumentError),
34
+ s(:str, "missing keyword: #{name}"))
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -8,6 +8,8 @@ module RubyNext
8
8
  SYNTAX_PROBE = "nil&.x&.nil?"
9
9
  MIN_SUPPORTED_VERSION = Gem::Version.new("2.3.0")
10
10
 
11
+ SAFE_LVAR = :__safe_lvar__
12
+
11
13
  def on_csend(node)
12
14
  node = super(node)
13
15
 
@@ -20,7 +22,7 @@ module RubyNext
20
22
  :and,
21
23
  [
22
24
  process(safe_navigation(receiver)),
23
- s(:send, decsendize(receiver), *args)
25
+ s(:send, safe_lvar, *args)
24
26
  ]
25
27
  ))
26
28
 
@@ -34,18 +36,15 @@ module RubyNext
34
36
 
35
37
  context.track!(self)
36
38
 
37
- new_node = s(:begin,
38
- super(node.updated(
39
- :and,
40
- [
41
- process(safe_navigation(node.children[0].children[0])),
42
- process(node.updated(nil, node.children.map(&method(:decsendize))))
43
- ]
44
- )))
39
+ super(decsendize(node))
40
+ end
45
41
 
46
- replace(node.loc.expression, new_node)
42
+ def on_numblock(node)
43
+ return super(node) unless node.children[0].type == :csend
47
44
 
48
- new_node
45
+ context.track!(self)
46
+
47
+ super(decsendize(node))
49
48
  end
50
49
 
51
50
  def on_op_asgn(node)
@@ -53,37 +52,51 @@ module RubyNext
53
52
 
54
53
  context.track!(self)
55
54
 
55
+ super(decsendize(node))
56
+ end
57
+
58
+ private
59
+
60
+ def decsendize(node)
61
+ csend, *children = node.children
62
+
63
+ receiver, *other = csend.children
64
+
65
+ new_csend = csend.updated(:send, [safe_lvar, *other])
66
+
56
67
  new_node = s(:begin,
57
- super(node.updated(
68
+ node.updated(
58
69
  :and,
59
70
  [
60
- process(safe_navigation(node.children[0].children[0])),
61
- process(node.updated(nil, node.children.map(&method(:decsendize))))
71
+ process(safe_navigation(receiver)),
72
+ process(node.updated(nil, [new_csend, *children]))
62
73
  ]
63
- )))
74
+ ))
64
75
 
65
76
  replace(node.loc.expression, new_node)
66
77
 
67
78
  new_node
68
79
  end
69
80
 
70
- private
71
-
72
- def decsendize(node)
73
- return node unless node.is_a?(::Parser::AST::Node) && node.type == :csend
74
-
75
- node.updated(:send, node.children.map(&method(:decsendize)))
76
- end
77
-
78
- # Transform: x&.y -> (!x.nil? && x.y) || nil
81
+ # Transform: x&.y -> ((_tmp_ = x) || true) && (!_tmp_.nil? || nil) && _tmp_.y
79
82
  # This allows us to handle `false&.to_s == "false"`
80
83
  def safe_navigation(node)
81
84
  s(:begin,
82
- s(:or,
83
- s(:send,
84
- s(:send, node, :nil?),
85
- :!),
86
- s(:nil)))
85
+ s(:and,
86
+ s(:begin,
87
+ s(:or,
88
+ s(:begin, s(:lvasgn, SAFE_LVAR, node)),
89
+ s(:true))),
90
+ s(:begin,
91
+ s(:or,
92
+ s(:send,
93
+ s(:send, safe_lvar, :nil?),
94
+ :!),
95
+ s(:nil)))))
96
+ end
97
+
98
+ def safe_lvar
99
+ s(:lvar, SAFE_LVAR)
87
100
  end
88
101
  end
89
102
  end
@@ -6,7 +6,7 @@ module RubyNext
6
6
  class ShorthandHash < Base
7
7
  NAME = "shorthand-hash"
8
8
  SYNTAX_PROBE = "data = {x}"
9
- MIN_SUPPORTED_VERSION = Gem::Version.new("3.0.0")
9
+ MIN_SUPPORTED_VERSION = Gem::Version.new(RubyNext::NEXT_VERSION)
10
10
 
11
11
  def on_ipair(node)
12
12
  context.track! self
@@ -2,6 +2,7 @@
2
2
 
3
3
  # Make sure Core is loaded
4
4
  require "ruby-next"
5
+ require "pathname"
5
6
 
6
7
  module RubyNext
7
8
  module Language
@@ -29,7 +30,7 @@ module RubyNext
29
30
 
30
31
  def setup_gem_load_path(lib_dir = "lib", rbnext_dir: RUBY_NEXT_DIR, transpile: false)
31
32
  called_from = caller_locations(1, 1).first.path
32
- dirname = File.dirname(called_from)
33
+ dirname = File.realpath(File.dirname(called_from))
33
34
 
34
35
  loop do
35
36
  basename = File.basename(dirname)
@@ -48,11 +49,13 @@ module RubyNext
48
49
 
49
50
  GemTranspiler.maybe_transpile(File.dirname(dirname), lib_dir, next_dirname) if transpile
50
51
 
51
- current_index = $LOAD_PATH.index(dirname)
52
+ current_index = $LOAD_PATH.find_index do |load_path|
53
+ Pathname.new(load_path).realpath.to_s == dirname
54
+ end
52
55
 
53
56
  raise "Gem's lib is not in the $LOAD_PATH: #{dirname}" if current_index.nil?
54
57
 
55
- version = RubyNext.next_version
58
+ version = RubyNext.next_ruby_version
56
59
 
57
60
  loop do
58
61
  break unless version
@@ -64,7 +67,7 @@ module RubyNext
64
67
  current_index += 1
65
68
  end
66
69
 
67
- version = RubyNext.next_version(version)
70
+ version = RubyNext.next_ruby_version(version)
68
71
  end
69
72
  end
70
73
  end
@@ -6,3 +6,8 @@ require "parser/current"
6
6
  $VERBOSE = save_verbose
7
7
 
8
8
  require "unparser"
9
+
10
+ # For backward compatibility with older Unparser
11
+ if RubyNext::Language::Builder.respond_to?(:emit_kwargs=) && !defined?(Unparser::Emitter::Kwargs)
12
+ RubyNext::Language::Builder.emit_kwargs = false
13
+ end