Module: RubyNext::Language
- Defined in:
- lib/ruby-next/language.rb,
lib/ruby-next/language/eval.rb,
lib/ruby-next/language/setup.rb,
lib/ruby-next/language/parser.rb,
lib/ruby-next/language/runtime.rb,
lib/ruby-next/language/rewriters/base.rb,
lib/ruby-next/language/rewriters/2.4/dir.rb,
lib/ruby-next/language/rewriters/3.0/in_pattern.rb,
lib/ruby-next/language/rewriters/2.7/args_forward.rb,
lib/ruby-next/language/rewriters/3.0/find_pattern.rb,
lib/ruby-next/language/rewriters/2.6/endless_range.rb,
lib/ruby-next/language/rewriters/3.0/endless_method.rb,
lib/ruby-next/language/rewriters/3.1/shorthand_hash.rb,
lib/ruby-next/language/rewriters/2.1/required_kwargs.rb,
lib/ruby-next/language/rewriters/2.3/safe_navigation.rb,
lib/ruby-next/language/rewriters/2.7/numbered_params.rb,
lib/ruby-next/language/rewriters/3.1/anonymous_block.rb,
lib/ruby-next/language/rewriters/2.1/numeric_literals.rb,
lib/ruby-next/language/rewriters/2.3/squiggly_heredoc.rb,
lib/ruby-next/language/rewriters/2.7/pattern_matching.rb,
lib/ruby-next/language/rewriters/3.1/pin_vars_pattern.rb,
lib/ruby-next/language/rewriters/2.5/rescue_within_block.rb,
lib/ruby-next/language/rewriters/3.0/args_forward_leading.rb,
lib/ruby-next/language/rewriters/proposed/method_reference.rb,
lib/ruby-next/language/rewriters/3.1/endless_method_command.rb,
lib/ruby-next/language/rewriters/proposed/bind_vars_pattern.rb,
lib/ruby-next/language/rewriters/3.1/refinement_import_methods.rb,
lib/ruby-next/language/rewriters/3.1/oneline_pattern_parensless.rb
Overview
Language module contains tools to transpile newer Ruby syntax into an older one.
It works the following way:
- Takes a Ruby source code as input
- Generates the AST using the edge parser (via the `parser` gem)
- Pass this AST through the list of processors (one feature = one processor)
- Each processor may modify the AST
- Generates a transpiled source code from the transformed AST (via the `unparser` gem)
Defined Under Namespace
Modules: BuilderExt, ClassEval, Eval, GemTranspiler, InstanceEval, KernelEval, Rewriters, Runtime
Classes: Builder, TransformContext
Constant Summary
collapse
- RewriterNotFoundError =
Class.new(StandardError)
- MODES =
%i[rewrite ast].freeze
Class Attribute Summary collapse
Class Method Summary
collapse
Instance Method Summary
collapse
Class Attribute Details
.mode ⇒ Object
Returns the value of attribute mode.
72
73
74
|
# File 'lib/ruby-next/language.rb', line 72
def mode
@mode
end
|
.rewriters ⇒ Object
Returns the value of attribute rewriters.
65
66
67
|
# File 'lib/ruby-next/language.rb', line 65
def rewriters
@rewriters
end
|
.strategy ⇒ Object
Returns the value of attribute strategy.
68
69
70
|
# File 'lib/ruby-next/language.rb', line 68
def strategy
@strategy
end
|
.watch_dirs ⇒ Object
Returns the value of attribute watch_dirs.
66
67
68
|
# File 'lib/ruby-next/language.rb', line 66
def watch_dirs
@watch_dirs
end
|
Class Method Details
.ast? ⇒ Boolean
83
84
85
|
# File 'lib/ruby-next/language.rb', line 83
def ast?
mode == :ast
end
|
.current_rewriters ⇒ Object
Rewriters required for the current version
127
128
129
|
# File 'lib/ruby-next/language.rb', line 127
def current_rewriters
@current_rewriters ||= rewriters.select(&:unsupported_syntax?)
end
|
.parse(source, file = "(string)") ⇒ Object
36
37
38
39
40
41
42
43
44
|
# File 'lib/ruby-next/language/parser.rb', line 36
def parse(source, file = "(string)")
buffer = ::Parser::Source::Buffer.new(file).tap do |buffer|
buffer.source = source
end
parser.parse(buffer)
rescue ::Parser::SyntaxError => e
raise ::SyntaxError, e.message
end
|
46
47
48
49
50
51
52
53
54
|
# File 'lib/ruby-next/language/parser.rb', line 46
def (source, file = "(string)")
buffer = ::Parser::Source::Buffer.new(file).tap do |buffer|
buffer.source = source
end
parser.(buffer)
rescue ::Parser::SyntaxError => e
raise ::SyntaxError, e.message
end
|
.parser ⇒ Object
28
29
30
31
32
33
34
|
# File 'lib/ruby-next/language/parser.rb', line 28
def parser
::Parser::RubyNext.new(Builder.new).tap do |prs|
prs.diagnostics.tap do |diagnostics|
diagnostics.all_errors_are_fatal = true
end
end
end
|
.rewrite? ⇒ Boolean
79
80
81
|
# File 'lib/ruby-next/language.rb', line 79
def rewrite?
mode == :rewrite?
end
|
.runtime! ⇒ Object
87
88
89
90
91
|
# File 'lib/ruby-next/language.rb', line 87
def runtime!
require "ruby-next/language/rewriters/runtime"
@runtime = true
end
|
.runtime? ⇒ Boolean
93
94
95
|
# File 'lib/ruby-next/language.rb', line 93
def runtime?
@runtime
end
|
.select_rewriters(*names) ⇒ Object
This method guarantees that rewriters will be returned in order they defined in Language module
132
133
134
135
136
137
138
139
|
# File 'lib/ruby-next/language.rb', line 132
def select_rewriters(*names)
rewriters_delta = names - rewriters.map { |rewriter| rewriter::NAME }
if rewriters_delta.any?
raise RewriterNotFoundError, "Rewriters not found: #{rewriters_delta.join(",")}"
end
rewriters.select { |rewriter| names.include?(rewriter::NAME) }
end
|
.setup_gem_load_path(lib_dir = "lib", rbnext_dir: RUBY_NEXT_DIR, transpile: false) ⇒ Object
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
|
# File 'lib/ruby-next/language/setup.rb', line 31
def setup_gem_load_path(lib_dir = "lib", rbnext_dir: RUBY_NEXT_DIR, transpile: false)
called_from = caller_locations(1, 1).first.path
dirname = File.realpath(File.dirname(called_from))
loop do
basename = File.basename(dirname)
raise "Couldn't find gem's load dir: #{lib_dir}" if basename == dirname
break if basename == lib_dir
dirname = File.dirname(basename)
end
dirname = File.realpath(dirname)
return if Language.runtime? && Language.watch_dirs.include?(dirname)
next_dirname = File.join(dirname, rbnext_dir)
GemTranspiler.maybe_transpile(File.dirname(dirname), lib_dir, next_dirname) if transpile
current_index = $LOAD_PATH.find_index do |load_path|
pn = Pathname.new(load_path)
pn.exist? && pn.realpath.to_s == dirname
end
raise "Gem's lib is not in the $LOAD_PATH: #{dirname}" if current_index.nil?
version = RubyNext.next_ruby_version
loop do
break unless version
version_dir = File.join(next_dirname, version.segments[0..1].join("."))
if File.exist?(version_dir)
$LOAD_PATH.insert current_index, version_dir
current_index += 1
end
version = RubyNext.next_ruby_version(version)
end
end
|
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
|
# File 'lib/ruby-next/language.rb', line 97
def transform(source, rewriters: self.rewriters, using: RubyNext::Core.refine?, context: TransformContext.new)
retried = 0
new_source = nil
begin
new_source =
if mode == :rewrite
rewrite(source, rewriters: rewriters, using: using, context: context)
else
regenerate(source, rewriters: rewriters, using: using, context: context)
end
rescue Unparser::UnknownNodeError => err
RubyNext.warn "Ruby Next fallbacks to \"rewrite\" transpiling mode since the version of Unparser you use doesn't support some syntax yet: #{err.message}.\n" \
"Try upgrading the Unparser or set transpiling mode to \"rewrite\" in case you use some edge or experimental syntax."
self.mode = :rewrite
retried += 1
retry unless retried > 1
raise
end
return new_source unless RubyNext::Core.refine?
return new_source unless using && context.use_ruby_next?
Core.inject! new_source.dup
end
|
122
123
124
|
# File 'lib/ruby-next/language.rb', line 122
def transformable?(path)
watch_dirs.any? { |dir| path.start_with?(dir) }
end
|
Instance Method Details
#runtime? ⇒ Boolean
26
27
28
|
# File 'lib/ruby-next/language/setup.rb', line 26
def runtime?
false
end
|