Class: Myco::CodeLoader

Inherits:
Object
  • Object
show all
Defined in:
lib/myco/code_loader.rb

Defined Under Namespace

Classes: AbstractLoader, BytecodeLoader, MycoLoader, RubyLoader

Class Attribute Summary collapse

Class Method Summary collapse

Class Attribute Details

.emit_rbObject

Whether to cache generated ruby code to disk.



7
8
9
# File 'lib/myco/code_loader.rb', line 7

def emit_rb
  @emit_rb
end

.emit_rbcObject

Whether to cache rubinius bytecode to disk.



8
9
10
# File 'lib/myco/code_loader.rb', line 8

def emit_rbc
  @emit_rbc
end

.precedenceObject

Order of precedence for file types.



9
10
11
# File 'lib/myco/code_loader.rb', line 9

def precedence
  @precedence
end

Class Method Details

.load(path, load_paths, kwargs = {}) ⇒ Object

Load from the given path and load_paths and call under the given ConstantScope, VariableScope, and receiver. If cscope or vscope or receiver are nil, they are pulled from the given call_depth, corresponding to one of the calling frames.

TODO: fix rubinius JIT issue and use “call_depth:1, **kwargs” here



89
90
91
92
93
94
95
96
97
98
99
100
101
# File 'lib/myco/code_loader.rb', line 89

def self.load path, load_paths, kwargs={}
  kwargs[:call_depth] ||= 1
  begin
    loader = loader_for_file(path, load_paths)
    loader.bind_to(kwargs.merge(call_depth: kwargs[:call_depth] + 1))
    loader.compile
    loader.emit_rb!  if self.emit_rb
    loader.emit_rbc! if self.emit_rbc
    loader.load
  rescue Rubinius::InvalidRBC
    retry
  end
end

.loader_for(type, *args) ⇒ Object

Return a loader of the given type with the given arguments



74
75
76
77
78
79
80
81
# File 'lib/myco/code_loader.rb', line 74

def self.loader_for type, *args
  case type
  when :myco; MycoLoader.new(*args)
  when :rbc;  BytecodeLoader.new(*args)
  when :rb;   RubyLoader.new(*args)
  else;       raise NotImplementedError
  end
end

.loader_for_file(path, load_paths = []) ⇒ Object

Select a loader and file path for the given path, considering the currently selected order of precedence for file types.

Raises:

  • (ArgumentError)


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
# File 'lib/myco/code_loader.rb', line 35

def self.loader_for_file path, load_paths=[]
  use_path = resolve_file(path, load_paths)
  
  # TODO: This logic could be refactored to look cleaner
  if use_path && defined? Myco::ToolSet
    # Try to find an implementation with higher precedence than :myco
    # With a file that has been modified at least as recently as
    # the resolved file in use_path.
    ref_mtime = File.mtime(use_path)
    precedence.each { |type|
      begin
        if type==:myco
          return loader_for(type, use_path)
        else
          alt_path = use_path + ".#{type}"
          if File.file?(alt_path) && (File.mtime(alt_path) >= ref_mtime)
            return loader_for(type, alt_path)
          end
        end
      rescue NotImplementedError # Skip loader if not implemented
      end
    }
  else
    # Try to find any implementation other than :myco, in precedence order.
    precedence.each { |type|
      if type != :myco
        alt_path = resolve_file(path + ".#{type}", load_paths)
        if alt_path && File.file?(alt_path)
          return loader_for(type, alt_path)
        end
      end
    }
  end
  
  raise ArgumentError, "Couldn't resolve file: #{path.inspect} \n" \
                       "in load_paths: #{load_paths.inspect}" \
end

.resolve_file(path, load_paths = []) ⇒ Object

Try to resolve the given file path in the current working directory or in the given load paths.



21
22
23
24
25
26
27
28
29
30
31
# File 'lib/myco/code_loader.rb', line 21

def self.resolve_file path, load_paths=[]
  tmp_path = File.expand_path(path)
  use_path = File.file?(tmp_path) && tmp_path
  load_paths.each { |load_path|
    break if use_path
    tmp_path = File.expand_path(path, load_path)
    use_path = File.file?(tmp_path) && tmp_path
  }
  
  use_path
end