Module: ClassLoader
- Defined in:
- lib/class_loader/class_loader.rb
Defined Under Namespace
Classes: Watcher
Constant Summary collapse
- SKIP =
Sometimes other libraries try to load some const to check if it exist, and we don’t want ClassLoader automatically load it.
%w(Test RSpec)
Class Attribute Summary collapse
-
.after_callbacks ⇒ Object
readonly
Returns the value of attribute after_callbacks.
-
.loaded_classes ⇒ Object
readonly
Returns the value of attribute loaded_classes.
-
.monitor ⇒ Object
readonly
Returns the value of attribute monitor.
Class Method Summary collapse
- .after(class_name, &block) ⇒ Object
- .filter_backtrace(backtrace) ⇒ Object
-
.load(namespace, const) ⇒ Object
Hierarchically searching for class file, according to modules hierarchy.
-
.preload(*paths) ⇒ Object
Eagerly load all classes in paths.
-
.watch(*paths) ⇒ Object
Watch and reload files.
- .watcher ⇒ Object
Class Attribute Details
.after_callbacks ⇒ Object (readonly)
Returns the value of attribute after_callbacks.
12 13 14 |
# File 'lib/class_loader/class_loader.rb', line 12 def after_callbacks @after_callbacks end |
.loaded_classes ⇒ Object (readonly)
Returns the value of attribute loaded_classes.
12 13 14 |
# File 'lib/class_loader/class_loader.rb', line 12 def loaded_classes @loaded_classes end |
.monitor ⇒ Object (readonly)
Returns the value of attribute monitor.
12 13 14 |
# File 'lib/class_loader/class_loader.rb', line 12 def monitor @monitor end |
Class Method Details
.after(class_name, &block) ⇒ Object
121 122 123 124 125 126 127 128 129 130 131 |
# File 'lib/class_loader/class_loader.rb', line 121 def after class_name, &block (@after_callbacks[class_name] ||= []) << block # Firing it immediatelly if class has been already loaded. # Checking if constant exist without loading it. names = class_name.gsub(/^::/, '').split('::') const_defined = names.inject Object do |current, const| current = current && current.const_defined?(const) && current.const_get(const) end block.call if const_defined end |
.filter_backtrace(backtrace) ⇒ Object
133 134 135 |
# File 'lib/class_loader/class_loader.rb', line 133 def filter_backtrace backtrace backtrace.reject{|path| path.include?("/lib/class_loader") or path.include?('monitor.rb')} end |
.load(namespace, const) ⇒ Object
Hierarchically searching for class file, according to modules hierarchy.
For example, let’s suppose that ‘C` class defined in ’/lib/a/c.rb’ file, and we referencing it in the ‘A::B` namespace, like this - `A::B::C`, the following files will be checked:
-
‘/lib/a/b/c.rb’ - there’s nothing, moving up in hierarchy.
-
‘/lib/a/c.rb’ - got and load it.
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 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 |
# File 'lib/class_loader/class_loader.rb', line 21 def load namespace, const monitor.synchronize do original_namespace = namespace namespace = nil if namespace == Object or namespace == Module target_namespace = namespace # Need this hack to work with anonymous classes. namespace = eval "#{name_hack(namespace)}" if namespace # Hierarchically searching for class name. hierarchy = {} begin class_name = namespace ? "#{namespace.name}::#{const}" : const.to_s class_file_name = get_file_name class_name binding = namespace || Object hierarchy[class_file_name] = binding # Skip some constants. return nil if SKIP.any?{|c| class_name == c or class_name.include?("#{c}::")} # Trying to load class file, if its exist. loaded = begin require class_file_name true rescue LoadError => e # Not the best way - hardcoding error messages, but it's the fastest way # to check existence of file & load it. unless e. =~ /no such file.*#{Regexp.escape(class_file_name)}/ raise e.class, e., filter_backtrace(e.backtrace) end false end if loaded # Checking that class hasn't been loaded previously, sometimes it may be caused by # weird class definition code. if loaded_classes.include? class_name msg = "something wrong with '#{const}' referenced from '#{original_namespace}' scope!" raise NameError, msg, filter_backtrace(caller) end # Checking that class defined in correct namespace, not the another one. unless binding.const_defined? const, false msg = "class name #{class_name} doesn't correspond to file name '#{class_file_name}'!" raise NameError, msg, filter_backtrace(caller) end # Getting the class itself. klass = binding.const_get const, false # Firing after callbacks. if callbacks = after_callbacks[klass.name] then callbacks.each{|c| c.call klass} end loaded_classes[class_name] = klass return klass end # Moving to higher namespace. global_also_tried = namespace == nil namespace = Module.namespace_for namespace.name if namespace end until global_also_tried # If file not found trying to find directory and evaluate it as a module. hierarchy.each do |path, binding| $LOAD_PATH.each do |base| next unless File.directory? File.join(base, path) amodule = Module.new binding.const_set const, amodule return amodule end end return nil end end |
.preload(*paths) ⇒ Object
Eagerly load all classes in paths.
99 100 101 102 103 104 105 106 107 108 |
# File 'lib/class_loader/class_loader.rb', line 99 def preload *paths monitor.synchronize do paths.each do |path| Dir.glob("#{path}/**/*.rb").each do |class_path| class_file_name = class_path.sub("#{path}/", '').sub(/\.rb$/, '') require class_file_name end end end end |
.watch(*paths) ⇒ Object
Watch and reload files.
111 112 113 114 |
# File 'lib/class_loader/class_loader.rb', line 111 def watch *paths paths.each{|path| watcher.paths << path unless watcher.paths.include? path} watcher.start end |
.watcher ⇒ Object
116 117 118 119 |
# File 'lib/class_loader/class_loader.rb', line 116 def watcher require 'class_loader/watcher' @watcher ||= ClassLoader::Watcher.new monitor end |