Class: Audition::Static::SourceFile
- Inherits:
-
Object
- Object
- Audition::Static::SourceFile
- Defined in:
- lib/audition/static/source_file.rb
Overview
A parsed Ruby file plus the magic comments that change Ractor semantics.
Instance Attribute Summary collapse
-
#parse_result ⇒ Object
readonly
Returns the value of attribute parse_result.
-
#path ⇒ Object
readonly
Returns the value of attribute path.
-
#source ⇒ Object
readonly
Returns the value of attribute source.
Class Method Summary collapse
Instance Method Summary collapse
-
#boot_insertion ⇒ Object
Where a hoisted
requireline can be inserted: right after the last existing top-level require, or after the leading comment block (shebang and magic comments), or at the top. -
#frozen_string_literal? ⇒ Boolean
String literals in this file are frozen (and therefore shareable when they contain no interpolation).
-
#initialize(source:, path:) ⇒ SourceFile
constructor
A new instance of SourceFile.
- #leading_comments_end ⇒ Object
- #line_at(number) ⇒ Object
- #magic_comment(key) ⇒ Object
-
#magic_insertion_offset ⇒ Object
Where a new magic comment can go: after the shebang and any existing magic comments, before code.
- #root ⇒ Object
-
#shareable_constants? ⇒ Boolean
# shareable_constant_value: literal|experimental_everything| experimental_copymakes constant values deeply frozen and shareable at parse time, so constant checks are moot. - #syntax_errors ⇒ Object
-
#top_level_requires ⇒ Object
Literal feature strings required by top-level statements.
- #valid_syntax? ⇒ Boolean
Constructor Details
#initialize(source:, path:) ⇒ SourceFile
Returns a new instance of SourceFile.
16 17 18 19 20 |
# File 'lib/audition/static/source_file.rb', line 16 def initialize(source:, path:) @source = source @path = path @parse_result = Prism.parse(source) end |
Instance Attribute Details
#parse_result ⇒ Object (readonly)
Returns the value of attribute parse_result.
10 11 12 |
# File 'lib/audition/static/source_file.rb', line 10 def parse_result @parse_result end |
#path ⇒ Object (readonly)
Returns the value of attribute path.
10 11 12 |
# File 'lib/audition/static/source_file.rb', line 10 def path @path end |
#source ⇒ Object (readonly)
Returns the value of attribute source.
10 11 12 |
# File 'lib/audition/static/source_file.rb', line 10 def source @source end |
Class Method Details
.read(path) ⇒ Object
12 13 14 |
# File 'lib/audition/static/source_file.rb', line 12 def self.read(path) new(source: File.read(path), path: path) end |
Instance Method Details
#boot_insertion ⇒ Object
Where a hoisted require line can be inserted: right after
the last existing top-level require, or after the leading
comment block (shebang and magic comments), or at the top.
69 70 71 72 73 74 75 76 77 78 79 80 81 |
# File 'lib/audition/static/source_file.rb', line 69 def boot_insertion last_require = root.statements.body.rfind do |s| s.is_a?(Prism::CallNode) && s.receiver.nil? && %i[require require_relative].include?(s.name) end if last_require newline = source.index("\n", last_require.location.end_offset) offset = newline ? newline + 1 : source.bytesize {offset: offset, after_require: true} else {offset: leading_comments_end, after_require: false} end end |
#frozen_string_literal? ⇒ Boolean
String literals in this file are frozen (and therefore shareable when they contain no interpolation).
37 38 39 |
# File 'lib/audition/static/source_file.rb', line 37 def frozen_string_literal? magic_comment("frozen_string_literal") == "true" end |
#leading_comments_end ⇒ Object
98 99 100 101 102 103 104 105 106 |
# File 'lib/audition/static/source_file.rb', line 98 def leading_comments_end offset = 0 source.each_line do |line| break unless line.start_with?("#") offset += line.bytesize end offset end |
#line_at(number) ⇒ Object
50 51 52 53 |
# File 'lib/audition/static/source_file.rb', line 50 def line_at(number) @lines ||= source.lines @lines[number - 1]&.strip end |
#magic_comment(key) ⇒ Object
28 29 30 31 32 33 |
# File 'lib/audition/static/source_file.rb', line 28 def magic_comment(key) comment = parse_result.magic_comments.find do |mc| mc.key_loc.slice == key end comment&.value_loc&.slice end |
#magic_insertion_offset ⇒ Object
Where a new magic comment can go: after the shebang and any existing magic comments, before code.
85 86 87 88 89 90 91 92 93 94 95 96 |
# File 'lib/audition/static/source_file.rb', line 85 def magic_insertion_offset offset = 0 if source.start_with?("#!") newline = source.index("\n") offset = newline ? newline + 1 : source.bytesize end after_magic = parse_result.magic_comments.map do |mc| newline = source.index("\n", mc.value_loc.end_offset) newline ? newline + 1 : source.bytesize end.max [offset, after_magic || 0].max end |
#root ⇒ Object
26 |
# File 'lib/audition/static/source_file.rb', line 26 def root = parse_result.value |
#shareable_constants? ⇒ Boolean
# shareable_constant_value: literal|experimental_everything| experimental_copy makes constant values deeply frozen and
shareable at parse time, so constant checks are moot.
(v1 treats the comment as file-wide.)
45 46 47 48 |
# File 'lib/audition/static/source_file.rb', line 45 def shareable_constants? value = magic_comment("shareable_constant_value") !value.nil? && value != "none" end |
#syntax_errors ⇒ Object
24 |
# File 'lib/audition/static/source_file.rb', line 24 def syntax_errors = parse_result.errors |
#top_level_requires ⇒ Object
Literal feature strings required by top-level statements.
56 57 58 59 60 61 62 63 64 |
# File 'lib/audition/static/source_file.rb', line 56 def top_level_requires @top_level_requires ||= root.statements.body.filter_map do |s| next unless s.is_a?(Prism::CallNode) && s.receiver.nil? next unless %i[require require_relative].include?(s.name) arg = s.arguments&.arguments&.first arg.unescaped if arg.is_a?(Prism::StringNode) end end |
#valid_syntax? ⇒ Boolean
22 |
# File 'lib/audition/static/source_file.rb', line 22 def valid_syntax? = parse_result.success? |