Class: Ibex::Frontend::SourceLoader

Inherits:
Object
  • Object
show all
Defined in:
lib/ibex/frontend/source_loader.rb

Overview

Resolves canonical grammar paths and reads either open-buffer overlays or disk.

Instance Method Summary collapse

Constructor Details

#initialize(overlays: {}, record_reads: false) ⇒ SourceLoader

Returns a new instance of SourceLoader.



30
31
32
33
34
35
36
37
# File 'lib/ibex/frontend/source_loader.rb', line 30

def initialize(overlays: {}, record_reads: false)
  @overlays = {} #: Hash[String, String]
  @aliases = {} #: Hash[String, String]
  @read_records = {} #: Hash[String, GenerationInput]
  @record_reads = record_reads
  @access_paths = {} #: Hash[String, Array[String]]
  overlays.each { |path, source| set_overlay(path, source) }
end

Instance Method Details

#canonical_path(path, base: Dir.pwd, allow_missing: false) ⇒ Object

Canonicalize an existing file, or a missing path explicitly allowed by an open overlay.



41
42
43
44
45
46
47
48
49
50
51
52
53
54
# File 'lib/ibex/frontend/source_loader.rb', line 41

def canonical_path(path, base: Dir.pwd, allow_missing: false)
  expanded = File.expand_path(path, base)
  aliased = @aliases[expanded]
  return aliased if aliased

  begin
    File.realpath(expanded)
  rescue Errno::ENOENT
    canonical = canonical_missing_path(expanded)
    return canonical if allow_missing || @overlays.key?(canonical)

    raise
  end
end

#delete_overlay(path) ⇒ Object

Remove an editor buffer and return its canonical path.



100
101
102
103
104
105
106
# File 'lib/ibex/frontend/source_loader.rb', line 100

def delete_overlay(path)
  expanded = File.expand_path(path)
  canonical = @aliases.delete(expanded) || canonical_path(expanded, allow_missing: true)
  @aliases.delete_if { |_alias_path, target| target == canonical }
  @overlays.delete(canonical)
  canonical
end

#disk_file?(path) ⇒ Boolean

Returns:

  • (Boolean)


115
116
117
118
119
# File 'lib/ibex/frontend/source_loader.rb', line 115

def disk_file?(path)
  File.file?(disk_path(path))
rescue SystemCallError
  false
end

#disk_path(path) ⇒ Object

Resolve the current disk target without consulting overlay aliases.



123
124
125
# File 'lib/ibex/frontend/source_loader.rb', line 123

def disk_path(path)
  File.realpath(File.expand_path(path))
end

#disk_source(path) ⇒ Object

Read disk while deliberately bypassing an open overlay.



110
111
112
# File 'lib/ibex/frontend/source_loader.rb', line 110

def disk_source(path)
  File.binread(disk_path(path))
end

#file?(path) ⇒ Boolean

Returns:

  • (Boolean)


71
72
73
74
75
76
# File 'lib/ibex/frontend/source_loader.rb', line 71

def file?(path)
  canonical = canonical_path(path, allow_missing: true)
  @overlays.key?(canonical) || File.file?(canonical)
rescue SystemCallError
  false
end

#overlay?(path) ⇒ Boolean

Returns:

  • (Boolean)


79
80
81
82
83
84
# File 'lib/ibex/frontend/source_loader.rb', line 79

def overlay?(path)
  canonical = canonical_path(path, allow_missing: true)
  @overlays.key?(canonical)
rescue SystemCallError
  false
end

#read(path) ⇒ Object



57
58
59
60
61
62
63
64
65
66
67
68
# File 'lib/ibex/frontend/source_loader.rb', line 57

def read(path)
  canonical = canonical_path(path, allow_missing: true)
  overlay = @overlays[canonical]
  source = overlay || File.binread(canonical)
  if @record_reads
    record = GenerationInput.new(canonical, source)
    (@access_paths[canonical] || []).each { |access| record.add_access_path(access) }
    @read_records[canonical] = record
  end

  source
end

#read_recordsObject



16
17
18
# File 'lib/ibex/frontend/source_loader.rb', line 16

def read_records
  @read_records.values
end

#record_access(canonical, access_path) ⇒ Object

Associate the lexical path used by a resolver with its canonical source.



22
23
24
25
26
27
# File 'lib/ibex/frontend/source_loader.rb', line 22

def record_access(canonical, access_path)
  paths = (@access_paths[canonical] ||= [])
  expanded = File.expand_path(access_path)
  paths << expanded unless paths.include?(expanded)
  @read_records[canonical]&.add_access_path(expanded)
end

#set_overlay(path, source) ⇒ Object

Install or replace an editor buffer without writing it to disk.

Raises:

  • (ArgumentError)


88
89
90
91
92
93
94
95
96
# File 'lib/ibex/frontend/source_loader.rb', line 88

def set_overlay(path, source)
  expanded = File.expand_path(path)
  canonical = canonical_path(expanded, allow_missing: true)
  raise ArgumentError, "overlay path must not be a directory" if File.directory?(canonical)

  @aliases[expanded] = canonical
  @overlays[canonical] = source.dup.freeze
  canonical
end