Module: ClassLoader

Defined in:
lib/class_loader/class_loader.rb,
lib/class_loader/chained_adapter.rb,
lib/class_loader/file_system_adapter.rb,
lib/class_loader/file_system_adapter/camel_case_translator.rb,
lib/class_loader/file_system_adapter/underscored_translator.rb

Defined Under Namespace

Classes: CamelCaseTranslator, ChainedAdapter, FileSystemAdapter, UnderscoredTranslator

Constant Summary collapse

SYNC =
Monitor.new

Class Attribute Summary collapse

Class Method Summary collapse

Class Attribute Details

.adapterObject



125
126
127
# File 'lib/class_loader/class_loader.rb', line 125

def adapter
  @adapter ||= default_adapter
end

.error_on_defined_constantObject

Class loading logic



11
12
13
# File 'lib/class_loader/class_loader.rb', line 11

def error_on_defined_constant
  @error_on_defined_constant
end

.observersObject

Returns the value of attribute observers.



106
107
108
# File 'lib/class_loader/class_loader.rb', line 106

def observers
  @observers
end

.watch_intervalObject

Watcher thread



133
134
135
# File 'lib/class_loader/class_loader.rb', line 133

def watch_interval
  @watch_interval
end

Class Method Details

.add_observer(&block) ⇒ Object



107
# File 'lib/class_loader/class_loader.rb', line 107

def add_observer &block; observers << block end

.autoload_dir(path, watch = false, start_watch_thread = true) ⇒ Object

Utilities



94
95
96
97
98
# File 'lib/class_loader/class_loader.rb', line 94

def autoload_dir path, watch = false, start_watch_thread = true
  hook!
  start_watching! if watch and start_watch_thread
  adapter.add_path path, watch
end

.clearObject



100
101
102
103
104
# File 'lib/class_loader/class_loader.rb', line 100

def clear
  self.adapter = nil
  self.observers = []
  self.error_on_defined_constant = false
end

.hook!Object



112
113
114
115
116
117
118
119
120
121
122
# File 'lib/class_loader/class_loader.rb', line 112

def hook!
  return if @hooked

  ::Module.class_eval do
    alias_method :const_missing_without_cl, :const_missing
    def const_missing const
      return ClassLoader.load_class self, const.to_s
    end
  end
  @hooked = true
end

.load_class(namespace, const, reload = false) ⇒ Object



14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
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
# File 'lib/class_loader/class_loader.rb', line 14

def load_class namespace, const, reload = false            
  SYNC.synchronize do
    namespace = nil if namespace == Object or namespace == Module
    target_namespace = namespace
  
    # Name hack (for anonymous classes)
    namespace = eval "#{name_hack(namespace)}" if namespace
  
    class_name = namespace ? "#{namespace.name}::#{const}" : const
    simple_also_tried = false
    begin
      simple_also_tried = (namespace == nil)
    
      if try_load(class_name, const)
        defined_in_home_scope = namespace ? namespace.const_defined?(const) : Object.const_defined?(const)            
      
        unless defined_in_home_scope
          msg = "Class Name '#{class_name}' doesn't correspond to File Name '#{adapter.to_file_path(class_name)}'!"
          raise_without_self NameError, msg
        end
                    
        unless reload
          if loaded_classes.include? class_name
            if error_on_defined_constant  
              raise_without_self NameError, "Class '#{class_name}' is not defined in the '#{target_namespace}' Namespace!"
            else
              warn "Warn: Class '#{class_name}' is not defined in the '#{target_namespace}' Namespace!"
              puts caller
            end
          end
        end
        
        result = namespace ? namespace.const_get(const) : Object.const_get(const)
      
        loaded_classes[class_name] = target_namespace
        notify_observers result
        return result
      elsif namespace
        namespace = Module.namespace_for(namespace.name)
        class_name = namespace ? "#{namespace.name}::#{const}" : const
      end
    end until simple_also_tried
    
    raise_without_self NameError, "uninitialized constant '#{class_name}'!"
  end
end

.loaded_classesObject



12
# File 'lib/class_loader/class_loader.rb', line 12

def loaded_classes; @loaded_classes ||= {} end

.notify_observers(o) ⇒ Object



108
109
110
# File 'lib/class_loader/class_loader.rb', line 108

def notify_observers o
  observers.each{|obs| obs.call o}
end

.preload!Object



155
156
157
158
159
# File 'lib/class_loader/class_loader.rb', line 155

def preload!
  adapter.each_class do |class_name|
    reload_class class_name
  end
end

.reload_class(class_name) ⇒ Object



61
62
63
64
65
66
67
68
69
70
71
72
73
# File 'lib/class_loader/class_loader.rb', line 61

def reload_class class_name
  SYNC.synchronize do
    class_name = class_name.sub(/^::/, "")
    namespace = Module.namespace_for(class_name)
    name = class_name.sub(/^#{namespace}::/, "")      
    
    # removing old class
    class_container = (namespace || Object)
    class_container.send :remove_const, name if class_container.const_defined? name
    
    return load_class namespace, name, true
  end
end

.start_watching!Object



134
135
136
137
138
139
140
141
142
143
144
145
146
# File 'lib/class_loader/class_loader.rb', line 134

def start_watching!
  unless watching_thread      
    self.watching_thread = Thread.new do        
      while true
        sleep(watch_interval || 2)
        adapter.each_changed_class do |class_name|
          puts "reloading #{class_name}"
          reload_class class_name              
        end
      end
    end
  end
end

.stop_watching!Object



148
149
150
151
152
153
# File 'lib/class_loader/class_loader.rb', line 148

def stop_watching!
  if watching_thread
    watching_thread.kill
    self.watching_thread = nil
  end
end

.wrap_inside_namespace(namespace, script) ⇒ Object



75
76
77
78
79
80
81
82
83
84
85
86
87
88
# File 'lib/class_loader/class_loader.rb', line 75

def wrap_inside_namespace namespace, script
  nesting = []
  if namespace
    current_scope = ""
    namespace.name.split("::").each do |level|
      current_scope += "::#{level}"
      type = eval current_scope, TOPLEVEL_BINDING, __FILE__, __LINE__
      nesting << [level, (type.class == Module ? "module" : "class")]
    end
  end
  begining = nesting.collect{|l, t| "#{t} #{l};"}.join(' ')
  ending = nesting.collect{"end"}.join('; ')
  return "#{begining}#{script} \n#{ending}"
end