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.
70
71
72
|
# File 'lib/ruby-next/language.rb', line 70
def exclude_patterns
@exclude_patterns
end
|
.include_patterns ⇒ Object
Returns the value of attribute include_patterns.
69
70
71
|
# File 'lib/ruby-next/language.rb', line 69
def include_patterns
@include_patterns
end
|
.mode ⇒ Object
Returns the value of attribute mode.
83
84
85
|
# File 'lib/ruby-next/language.rb', line 83
def mode
@mode
end
|
.parser_class ⇒ Object
Returns the value of attribute parser_class.
38
39
40
|
# File 'lib/ruby-next/language/parser.rb', line 38
def parser_class
@parser_class
end
|
.parser_syntax_errors ⇒ Object
Returns the value of attribute parser_syntax_errors.
38
39
40
|
# File 'lib/ruby-next/language/parser.rb', line 38
def parser_syntax_errors
@parser_syntax_errors
end
|
.rewriters ⇒ Object
Returns the value of attribute rewriters.
77
78
79
|
# File 'lib/ruby-next/language.rb', line 77
def rewriters
@rewriters
end
|
.strategy ⇒ Object
Returns the value of attribute strategy.
79
80
81
|
# File 'lib/ruby-next/language.rb', line 79
def strategy
@strategy
end
|
.watch_dirs ⇒ Object
72
73
74
75
|
# File 'lib/ruby-next/language.rb', line 72
def watch_dirs
warn "[DEPRECATED] Use `RubyNext::Language.include_patterns` instead of `RubyNext::Language.watch_dirs`"
@watch_dirs
end
|
Class Method Details
.ast? ⇒ Boolean
94
95
96
|
# File 'lib/ruby-next/language.rb', line 94
def ast?
mode == :ast
end
|
.current_rewriters ⇒ Object
Rewriters required for the current version
150
151
152
|
# File 'lib/ruby-next/language.rb', line 150
def current_rewriters
@current_rewriters ||= rewriters.select(&:unsupported_syntax?)
end
|
.parse(source, file = "(string)") ⇒ Object
48
49
50
51
52
53
54
55
56
|
# File 'lib/ruby-next/language/parser.rb', line 48
def parse(source, file = "(string)")
buffer = ::Parser::Source::Buffer.new(file).tap do |buffer|
buffer.source = source
end
parser.parse(buffer)
rescue *parser_syntax_errors => e
raise ::SyntaxError, e.message, e.backtrace
end
|
58
59
60
61
62
63
64
65
66
|
# File 'lib/ruby-next/language/parser.rb', line 58
def (source, file = "(string)")
buffer = ::Parser::Source::Buffer.new(file).tap do |buffer|
buffer.source = source
end
parser.(buffer)
rescue *parser_syntax_errors => e
raise ::SyntaxError, e.message, e.backtrace
end
|
.parser ⇒ Object
40
41
42
43
44
45
46
|
# File 'lib/ruby-next/language/parser.rb', line 40
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
90
91
92
|
# File 'lib/ruby-next/language.rb', line 90
def rewrite?
mode == :rewrite?
end
|
.runtime! ⇒ Object
98
99
100
101
102
|
# File 'lib/ruby-next/language.rb', line 98
def runtime!
require "ruby-next/language/rewriters/runtime"
@runtime = true
end
|
.runtime? ⇒ Boolean
104
105
106
|
# File 'lib/ruby-next/language.rb', line 104
def runtime?
@runtime
end
|
.select_rewriters(*names) ⇒ Object
This method guarantees that rewriters will be returned in order they defined in Language module
155
156
157
158
159
160
161
162
|
# File 'lib/ruby-next/language.rb', line 155
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
136
137
138
139
140
141
142
|
# File 'lib/ruby-next/language.rb', line 136
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
|
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
|
# File 'lib/ruby-next/language.rb', line 108
def transform(source, rewriters: self.rewriters, using: RubyNext::Core.refine?, path: nil, context: TransformContext.new(path: path))
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
|
144
145
146
147
|
# File 'lib/ruby-next/language.rb', line 144
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
|