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.
69
70
71
|
# File 'lib/ruby-next/language.rb', line 69
def exclude_patterns
@exclude_patterns
end
|
.include_patterns ⇒ Object
Returns the value of attribute include_patterns.
68
69
70
|
# File 'lib/ruby-next/language.rb', line 68
def include_patterns
@include_patterns
end
|
.mode ⇒ Object
Returns the value of attribute mode.
82
83
84
|
# File 'lib/ruby-next/language.rb', line 82
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
|
.parser_syntax_errors ⇒ Object
Returns the value of attribute parser_syntax_errors.
37
38
39
|
# File 'lib/ruby-next/language/parser.rb', line 37
def parser_syntax_errors
@parser_syntax_errors
end
|
.rewriters ⇒ Object
Returns the value of attribute rewriters.
76
77
78
|
# File 'lib/ruby-next/language.rb', line 76
def rewriters
@rewriters
end
|
.strategy ⇒ Object
Returns the value of attribute strategy.
78
79
80
|
# File 'lib/ruby-next/language.rb', line 78
def strategy
@strategy
end
|
.watch_dirs ⇒ Object
71
72
73
74
|
# File 'lib/ruby-next/language.rb', line 71
def watch_dirs
warn "[DEPRECATED] Use `RubyNext::Language.include_patterns` instead of `RubyNext::Language.watch_dirs`"
@watch_dirs
end
|
Class Method Details
.ast? ⇒ Boolean
93
94
95
|
# File 'lib/ruby-next/language.rb', line 93
def ast?
mode == :ast
end
|
.current_rewriters ⇒ Object
Rewriters required for the current version
149
150
151
|
# File 'lib/ruby-next/language.rb', line 149
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_syntax_errors => e
raise ::SyntaxError, e.message, e.backtrace
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_syntax_errors => e
raise ::SyntaxError, e.message, e.backtrace
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
89
90
91
|
# File 'lib/ruby-next/language.rb', line 89
def rewrite?
mode == :rewrite?
end
|
.runtime! ⇒ Object
97
98
99
100
101
|
# File 'lib/ruby-next/language.rb', line 97
def runtime!
require "ruby-next/language/rewriters/runtime"
@runtime = true
end
|
.runtime? ⇒ Boolean
103
104
105
|
# File 'lib/ruby-next/language.rb', line 103
def runtime?
@runtime
end
|
.select_rewriters(*names) ⇒ Object
This method guarantees that rewriters will be returned in order they defined in Language module
154
155
156
157
158
159
160
161
|
# File 'lib/ruby-next/language.rb', line 154
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
135
136
137
138
139
140
141
|
# File 'lib/ruby-next/language.rb', line 135
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
|
107
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
|
# File 'lib/ruby-next/language.rb', line 107
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
|
143
144
145
146
|
# File 'lib/ruby-next/language.rb', line 143
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
|