1
2
3
4
5
6
7
8
9
10
11
12
13
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
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
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
|
require File.dirname(__FILE__) + '/module_attribute_accessors'
module Dependencies
extend self
@@loaded = [ ]
mattr_accessor :loaded
@@mechanism = :load
mattr_accessor :mechanism
def load?
mechanism == :load
end
def depend_on(file_name, swallow_load_errors = false)
if !loaded.include?(file_name)
loaded << file_name
begin
require_or_load(file_name)
rescue LoadError
raise unless swallow_load_errors
rescue Object => e
raise ScriptError, "#{e.message}"
end
end
end
def associate_with(file_name)
depend_on(file_name, true)
end
def clear
self.loaded = [ ]
end
def require_or_load(file_name)
load? ? load("#{file_name}.rb") : require(file_name)
end
def remove_subclasses_for(*classes)
classes.each { |klass| klass.remove_subclasses }
end
# LoadingModules implement namespace-safe dynamic loading.
# They support automatic loading via const_missing, allowing contained items to be automatically
# loaded when required. No extra syntax is required, as expressions such as Controller::Admin::UserController
# load the relavent files automatically.
#
# Ruby-style modules are supported, as a folder named 'submodule' will load 'submodule.rb' when available.
class LoadingModule < Module
attr_reader :path
def initialize(filesystem_root, path=[])
@path = path
@filesystem_root = filesystem_root
end
# The path to this module in the filesystem.
# Any subpath provided is taken to be composed of filesystem names.
def filesystem_path(subpath=[])
File.join(@filesystem_root, self.path, subpath)
end
# Load missing constants if possible.
def const_missing(name)
return const_get(name) if const_defined?(name) == false && const_load!(name)
super(name)
end
# Load the controller class or a parent module.
def const_load!(name)
name = name.to_s if name.kind_of? Symbol
if File.directory? filesystem_path(name.underscore)
# Is it a submodule? If so, create a new LoadingModule *before* loading it.
# This ensures that subitems will be loadable
new_module = LoadingModule.new(@filesystem_root, self.path + [name.underscore])
const_set(name, new_module)
Object.const_set(name, new_module) if @path.empty?
end
source_file = filesystem_path("#{(name == 'ApplicationController' ? 'Application' : name).underscore}.rb")
self.load_file(source_file) if File.file?(source_file)
self.const_defined?(name.camelize)
end
# Is this name present or loadable?
# This method is used by Routes to find valid controllers.
def const_available?(name)
name = name.to_s unless name.kind_of? String
File.directory?(filesystem_path(name.underscore)) || File.file?(filesystem_path("#{name.underscore}.rb"))
end
def clear
constants.each do |name|
Object.send(:remove_const, name) if Object.const_defined?(name) && @path.empty?
self.send(:remove_const, name)
end
end
def load_file(file_path)
Controllers.module_eval(IO.read(file_path), file_path, 1) # Hard coded Controller line here!!!
end
end
end
Object.send(:define_method, :require_or_load) { |file_name| Dependencies.require_or_load(file_name) } unless Object.respond_to?(:require_or_load)
Object.send(:define_method, :require_dependency) { |file_name| Dependencies.depend_on(file_name) } unless Object.respond_to?(:require_dependency)
Object.send(:define_method, :require_association) { |file_name| Dependencies.associate_with(file_name) } unless Object.respond_to?(:require_association)
class Object #:nodoc:
class << self
# Use const_missing to autoload associations so we don't have to
# require_association when using single-table inheritance.
def const_missing(class_id)
if Object.const_defined?(:Controllers) and Object::Controllers.const_available?(class_id)
return Object::Controllers.const_get(class_id)
end
begin
require_or_load(class_id.to_s.demodulize.underscore)
if Object.const_defined?(class_id) then return Object.const_get(class_id) else raise LoadError end
rescue LoadError
raise NameError, "uninitialized constant #{class_id}"
end
end
end
end
|