Class: Hyperloop::Autoloader

Inherits:
Object
  • Object
show all
Defined in:
lib/hyperloop/autoloader.rb

Class Method Summary collapse

Class Method Details

.const_missing(const_name, mod) ⇒ Object



38
39
40
41
42
# File 'lib/hyperloop/autoloader.rb', line 38

def self.const_missing(const_name, mod)
  # name.nil? is testing for anonymous
  from_mod = mod.name.nil? ? guess_for_anonymous(const_name) : mod
  load_missing_constant(from_mod, const_name)
end

.guess_for_anonymous(const_name) ⇒ Object



44
45
46
47
48
49
50
# File 'lib/hyperloop/autoloader.rb', line 44

def self.guess_for_anonymous(const_name)
  if Object.const_defined?(const_name)
    raise NameError.new "#{const_name} cannot be autoloaded from an anonymous class or module", const_name
  else
    Object
  end
end

.historyObject



9
10
11
# File 'lib/hyperloop/autoloader.rb', line 9

def self.history
  @@history
end

.history=(a) ⇒ Object

All files ever loaded.



6
7
8
# File 'lib/hyperloop/autoloader.rb', line 6

def self.history=(a)
  @@history = a
end

.load_missing_constant(from_mod, const_name) ⇒ Object



52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
# File 'lib/hyperloop/autoloader.rb', line 52

def self.load_missing_constant(from_mod, const_name)
  # see active_support/dependencies.rb in case of reloading on how to handle
  qualified_name = qualified_name_for(from_mod, const_name)
  qualified_path = underscore(qualified_name)

  module_path = search_for_module(qualified_path)
  if module_path
    if loading.include?(module_path)
      raise "Circular dependency detected while autoloading constant #{qualified_name}"
    else
      require_or_load(from_mod, module_path)
      raise LoadError, "Unable to autoload constant #{qualified_name}, expected #{module_path} to define it" unless from_mod.const_defined?(const_name, false)
      return from_mod.const_get(const_name)
    end
  elsif (parent = from_mod.parent) && parent != from_mod &&
        ! from_mod.parents.any? { |p| p.const_defined?(const_name, false) }
    begin
      return parent.const_missing(const_name)
    rescue NameError => e
      raise unless missing_name?(e, qualified_name_for(parent, const_name))
    end
  end
end

.load_pathsObject



17
18
19
# File 'lib/hyperloop/autoloader.rb', line 17

def self.load_paths
  @@load_paths
end

.load_paths=(a) ⇒ Object



14
15
16
# File 'lib/hyperloop/autoloader.rb', line 14

def self.load_paths=(a)
  @@load_paths = a
end

.loadedObject



25
26
27
# File 'lib/hyperloop/autoloader.rb', line 25

def self.loaded
  @@loaded
end

.loaded=(a) ⇒ Object



22
23
24
# File 'lib/hyperloop/autoloader.rb', line 22

def self.loaded=(a)
  @@loaded = a
end

.loadingObject



33
34
35
# File 'lib/hyperloop/autoloader.rb', line 33

def self.loading
  @@loading
end

.loading=(a) ⇒ Object



30
31
32
# File 'lib/hyperloop/autoloader.rb', line 30

def self.loading=(a)
  @@loading = a
end

.missing_name?(e, name) ⇒ Boolean

Returns:

  • (Boolean)


76
77
78
79
80
81
# File 'lib/hyperloop/autoloader.rb', line 76

def self.missing_name?(e, name)
  mn = if /undefined/ !~ e.message
         $1 if /((::)?([A-Z]\w*)(::[A-Z]\w*)*)$/ =~ e.message
       end
  mn == name
end

.qualified_name_for(mod, name) ⇒ Object

Returns the constant path for the provided parent and constant name.



84
85
86
87
# File 'lib/hyperloop/autoloader.rb', line 84

def self.qualified_name_for(mod, name)
  mod_name = to_constant_name(mod)
  mod_name == 'Object' ? name.to_s : "#{mod_name}::#{name}"
end

.require_or_load(from_mod, module_path) ⇒ Object



89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
# File 'lib/hyperloop/autoloader.rb', line 89

def self.require_or_load(from_mod, module_path)
  return if loaded.include?(module_path)
  loaded << module_path
  loading << module_path

  begin
    result = require module_path
  rescue Exception
    loaded.delete module_path
    raise LoadError, "Unable to autoload: require_or_load #{module_path} failed"
  ensure
    loading.pop
  end

  # Record history *after* loading so first load gets warnings.
  history << module_path
  result
  # end
end

.search_for_module(path) ⇒ Object



109
110
111
112
113
114
115
116
117
118
119
# File 'lib/hyperloop/autoloader.rb', line 109

def self.search_for_module(path)
  # oh my! imagine Bart Simpson, writing on the board:
  # "javascript is not ruby, javascript is not ruby, javascript is not ruby, ..."
  # then running home, starting irb, on the fly developing a chat client and opening a session with Homer at his workplace: "Hi Dad ..."
  load_paths.each do |load_path|
    mod_path = load_path + '/' + path
    return mod_path if `Opal.modules.hasOwnProperty(#{mod_path})`
  end
  return path if `Opal.modules.hasOwnProperty(#{path})`
  nil # Gee, I sure wish we had first_match ;-)
end

.to_constant_name(desc) ⇒ Object

Convert the provided const desc to a qualified constant name (as a string). A module, class, symbol, or string may be provided.



123
124
125
126
127
128
129
130
131
132
# File 'lib/hyperloop/autoloader.rb', line 123

def self.to_constant_name(desc) #:nodoc:
  case desc
  when String then desc.sub(/^::/, '')
  when Symbol then desc.to_s
  when Module
    desc.name ||
      raise(ArgumentError, 'Anonymous modules have no name to be referenced by')
  else raise TypeError, "Not a valid constant descriptor: #{desc.inspect}"
  end
end

.underscore(string) ⇒ Object



134
135
136
# File 'lib/hyperloop/autoloader.rb', line 134

def self.underscore(string)
  string.gsub(/::/, '/').gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').gsub(/([a-z\d])([A-Z])/,'\1_\2').tr("-", "_").downcase
end