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/text.rb,
lib/ruby-next/language/paco_parsers/base.rb,
lib/ruby-next/language/rewriters/2.4/dir.rb,
lib/ruby-next/language/rewriters/abstract.rb,
lib/ruby-next/language/paco_parsers/comments.rb,
lib/ruby-next/language/rewriters/edge/it_param.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/paco_parsers/string_literals.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/3.2/anonymous_restargs.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, PacoParsers, 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
.exclude_patterns ⇒ Object
Returns the value of attribute exclude_patterns.
66
67
68
|
# File 'lib/ruby-next/language.rb', line 66
def exclude_patterns
@exclude_patterns
end
|
.include_patterns ⇒ Object
Returns the value of attribute include_patterns.
65
66
67
|
# File 'lib/ruby-next/language.rb', line 65
def include_patterns
@include_patterns
end
|
.mode ⇒ Object
Returns the value of attribute mode.
79
80
81
|
# File 'lib/ruby-next/language.rb', line 79
def mode
@mode
end
|
.parser_class ⇒ Object
Returns the value of attribute parser_class.
37
38
39
|
# File 'lib/ruby-next/language/parser.rb', line 37
def parser_class
@parser_class
end
|
.rewriters ⇒ Object
Returns the value of attribute rewriters.
73
74
75
|
# File 'lib/ruby-next/language.rb', line 73
def rewriters
@rewriters
end
|
.strategy ⇒ Object
Returns the value of attribute strategy.
75
76
77
|
# File 'lib/ruby-next/language.rb', line 75
def strategy
@strategy
end
|
.watch_dirs ⇒ Object
68
69
70
71
|
# File 'lib/ruby-next/language.rb', line 68
def watch_dirs
warn "[DEPRECATED] Use `RubyNext::Language.include_patterns` instead of `RubyNext::Language.watch_dirs`"
@watch_dirs
end
|
Class Method Details
.ast? ⇒ Boolean
90
91
92
|
# File 'lib/ruby-next/language.rb', line 90
def ast?
mode == :ast
end
|
.current_rewriters ⇒ Object
Rewriters required for the current version
146
147
148
|
# File 'lib/ruby-next/language.rb', line 146
def current_rewriters
@current_rewriters ||= rewriters.select(&:unsupported_syntax?)
end
|
.parse(source, file = "(string)") ⇒ Object
47
48
49
50
51
52
53
54
55
|
# File 'lib/ruby-next/language/parser.rb', line 47
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
|
57
58
59
60
61
62
63
64
65
|
# File 'lib/ruby-next/language/parser.rb', line 57
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
39
40
41
42
43
44
45
|
# File 'lib/ruby-next/language/parser.rb', line 39
def parser
parser_class.new(Builder.new).tap do |prs|
prs.diagnostics.tap do |diagnostics|
diagnostics.all_errors_are_fatal = true
end
end
end
|
.rewrite? ⇒ Boolean
86
87
88
|
# File 'lib/ruby-next/language.rb', line 86
def rewrite?
mode == :rewrite?
end
|
.runtime! ⇒ Object
94
95
96
97
98
|
# File 'lib/ruby-next/language.rb', line 94
def runtime!
require "ruby-next/language/rewriters/runtime"
@runtime = true
end
|
.runtime? ⇒ Boolean
100
101
102
|
# File 'lib/ruby-next/language.rb', line 100
def runtime?
@runtime
end
|
.select_rewriters(*names) ⇒ Object
This method guarantees that rewriters will be returned in order they defined in Language module
151
152
153
154
155
156
157
158
|
# File 'lib/ruby-next/language.rb', line 151
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
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
74
75
76
|
# File 'lib/ruby-next/language/setup.rb', line 34
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.target_dir?(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
|
.target_dir?(dirname) ⇒ Boolean
132
133
134
135
136
137
138
|
# File 'lib/ruby-next/language.rb', line 132
def target_dir?(dirname)
fname = File.join(dirname, "x.rb")
include_patterns.any? { |pattern| File.fnmatch?(pattern, fname) } &&
exclude_patterns.none? { |pattern| File.fnmatch?(pattern, fname) }
end
|
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
|
# File 'lib/ruby-next/language.rb', line 104
def transform(source, rewriters: self.rewriters, using: RubyNext::Core.refine?, context: TransformContext.new)
text_rewriters, ast_rewriters = rewriters.partition(&:text?)
retried = 0
new_source = text_rewrite(source, rewriters: text_rewriters, using: using, context: context)
begin
new_source =
if mode == :rewrite
rewrite(new_source, rewriters: ast_rewriters, using: using, context: context)
else
regenerate(new_source, rewriters: ast_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
|
140
141
142
143
|
# File 'lib/ruby-next/language.rb', line 140
def transformable?(path)
include_patterns.any? { |pattern| File.fnmatch?(pattern, path) } &&
exclude_patterns.none? { |pattern| File.fnmatch?(pattern, path) }
end
|
Instance Method Details
#runtime? ⇒ Boolean
29
30
31
|
# File 'lib/ruby-next/language/setup.rb', line 29
def runtime?
false
end
|