class_loader 0.3.10 → 0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Rakefile +5 -5
- data/lib/class_loader/class_loader.rb +32 -36
- data/lib/class_loader/support.rb +3 -2
- data/readme.md +1 -1
- data/spec/class_loader_spec.rb +7 -6
- data/spec/file_system_adapter_spec.rb +2 -2
- metadata +20 -40
data/Rakefile
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
require 'rake_ext'
|
2
2
|
|
3
3
|
project(
|
4
|
-
:
|
5
|
-
:
|
6
|
-
:
|
4
|
+
name: "class_loader",
|
5
|
+
version: "0.4",
|
6
|
+
summary: "Automatically finds, loads and reloads Classes",
|
7
7
|
|
8
|
-
:
|
9
|
-
:
|
8
|
+
author: "Alexey Petrushin",
|
9
|
+
homepage: "http://github.com/alexeypetrushin/class_loader"
|
10
10
|
)
|
@@ -5,43 +5,38 @@ module ClassLoader
|
|
5
5
|
SYNC = Monitor.new
|
6
6
|
|
7
7
|
class << self
|
8
|
-
#
|
9
|
-
# Class loading logic
|
10
|
-
#
|
11
|
-
attr_accessor :error_on_defined_constant
|
12
8
|
def loaded_classes; @loaded_classes ||= {} end
|
13
9
|
|
14
|
-
def load_class namespace, const, reload = false
|
10
|
+
def load_class namespace, const, reload = false
|
15
11
|
SYNC.synchronize do
|
12
|
+
original_namespace = namespace
|
16
13
|
namespace = nil if namespace == Object or namespace == Module
|
17
14
|
target_namespace = namespace
|
18
15
|
|
19
16
|
# Name hack (for anonymous classes)
|
17
|
+
|
20
18
|
namespace = eval "#{name_hack(namespace)}" if namespace
|
21
|
-
|
19
|
+
|
22
20
|
class_name = namespace ? "#{namespace.name}::#{const}" : const
|
23
21
|
simple_also_tried = false
|
24
22
|
begin
|
25
23
|
simple_also_tried = (namespace == nil)
|
26
24
|
|
27
|
-
if
|
25
|
+
if adapter.exist? class_name
|
26
|
+
if loaded_classes.include?(class_name) and !reload
|
27
|
+
raise_without_self NameError, "something wrong with '#{const}' referenced from '#{original_namespace}' scope!"
|
28
|
+
end
|
29
|
+
|
30
|
+
load(class_name, const)
|
31
|
+
|
28
32
|
defined_in_home_scope = namespace ? namespace.const_defined?(const) : Object.const_defined?(const)
|
29
33
|
|
30
34
|
unless defined_in_home_scope
|
31
35
|
msg = "Class Name '#{class_name}' doesn't correspond to File Name '#{adapter.to_file_path(class_name)}'!"
|
32
|
-
|
36
|
+
raise msg
|
37
|
+
# raise_without_self NameError, msg
|
33
38
|
end
|
34
39
|
|
35
|
-
unless reload
|
36
|
-
if loaded_classes.include? class_name
|
37
|
-
if error_on_defined_constant
|
38
|
-
raise_without_self NameError, "Class '#{class_name}' is not defined in the '#{target_namespace}' Namespace!"
|
39
|
-
else
|
40
|
-
warn "Warn: Class '#{class_name}' is not defined in the '#{target_namespace}' Namespace!"
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
40
|
result = namespace ? namespace.const_get(const) : Object.const_get(const)
|
46
41
|
|
47
42
|
loaded_classes[class_name] = target_namespace
|
@@ -53,7 +48,7 @@ module ClassLoader
|
|
53
48
|
end
|
54
49
|
end until simple_also_tried
|
55
50
|
|
56
|
-
|
51
|
+
return false
|
57
52
|
end
|
58
53
|
end
|
59
54
|
|
@@ -99,7 +94,7 @@ module ClassLoader
|
|
99
94
|
def clear
|
100
95
|
self.adapter = nil
|
101
96
|
self.observers = []
|
102
|
-
self.error_on_defined_constant = false
|
97
|
+
# self.error_on_defined_constant = false
|
103
98
|
end
|
104
99
|
|
105
100
|
attr_accessor :observers
|
@@ -112,10 +107,15 @@ module ClassLoader
|
|
112
107
|
return if @hooked
|
113
108
|
|
114
109
|
::Module.class_eval do
|
115
|
-
alias_method :
|
110
|
+
alias_method :const_missing_without_class_loader, :const_missing
|
111
|
+
protected :const_missing_without_class_loader
|
116
112
|
def const_missing const
|
117
|
-
|
118
|
-
|
113
|
+
if klass = ClassLoader.load_class(self, const.to_s)
|
114
|
+
klass
|
115
|
+
else
|
116
|
+
const_missing_without_class_loader const
|
117
|
+
end
|
118
|
+
end
|
119
119
|
end
|
120
120
|
@hooked = true
|
121
121
|
end
|
@@ -166,25 +166,21 @@ module ClassLoader
|
|
166
166
|
adapter
|
167
167
|
end
|
168
168
|
|
169
|
-
def
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
eval script, TOPLEVEL_BINDING, file_path
|
175
|
-
else
|
176
|
-
return false
|
177
|
-
end
|
178
|
-
return true
|
169
|
+
def load class_name, const
|
170
|
+
script = adapter.read class_name
|
171
|
+
script = wrap_inside_namespace Module.namespace_for(class_name), script
|
172
|
+
file_path = adapter.to_file_path(class_name)
|
173
|
+
eval script, TOPLEVEL_BINDING, file_path
|
179
174
|
end
|
180
175
|
|
181
176
|
def raise_without_self exception, message
|
182
|
-
raise exception, message, caller.select{|path| path !~ /\/lib\/class_loader\//}
|
177
|
+
raise exception, message, caller.select{|path| path !~ /\/lib\/class_loader\// and path !~ /monitor\.rb/}
|
183
178
|
end
|
184
179
|
|
185
|
-
def name_hack namespace
|
180
|
+
def name_hack namespace
|
186
181
|
if namespace
|
187
|
-
namespace.to_s.gsub("#<Class:", "").gsub(">", "")
|
182
|
+
result = namespace.to_s.gsub("#<Class:", "").gsub(">", "")
|
183
|
+
result =~ /^\d/ ? "" : result
|
188
184
|
else
|
189
185
|
""
|
190
186
|
end
|
data/lib/class_loader/support.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
class String
|
2
|
-
unless
|
2
|
+
unless method_defined? :underscore
|
3
3
|
def underscore
|
4
4
|
word = self.dup
|
5
5
|
word.gsub!(/::/, '/')
|
@@ -11,7 +11,7 @@ class String
|
|
11
11
|
end
|
12
12
|
end
|
13
13
|
|
14
|
-
unless
|
14
|
+
unless method_defined? :camelize
|
15
15
|
def camelize first_letter_in_uppercase = true
|
16
16
|
if first_letter_in_uppercase
|
17
17
|
gsub(/\/(.?)/) { "::#{$1.upcase}" }.gsub(/(?:^|_)(.)/) { $1.upcase }
|
@@ -24,6 +24,7 @@ end
|
|
24
24
|
|
25
25
|
class Module
|
26
26
|
unless respond_to? :namespace_for
|
27
|
+
# TODO3 cache it?
|
27
28
|
def self.namespace_for class_name
|
28
29
|
list = class_name.split("::")
|
29
30
|
if list.size > 1
|
data/readme.md
CHANGED
@@ -42,4 +42,4 @@ There's currently a known bug in Ruby 1.8.x - class loading isn't thread safe, s
|
|
42
42
|
|
43
43
|
## Please let me know about bugs and your proposals, there's the 'Issues' tab at the top, feel free to submit.
|
44
44
|
|
45
|
-
Copyright (c)
|
45
|
+
Copyright (c) 2011 Alexey Petrushin http://4ire.net, released under the MIT license.
|
data/spec/class_loader_spec.rb
CHANGED
@@ -16,10 +16,10 @@ describe ClassLoader do
|
|
16
16
|
UnloadOldClass
|
17
17
|
PreloadingSpec
|
18
18
|
UnderscoredNamespace
|
19
|
-
)
|
19
|
+
)
|
20
20
|
end
|
21
21
|
|
22
|
-
after
|
22
|
+
after do
|
23
23
|
ClassLoader.clear
|
24
24
|
end
|
25
25
|
|
@@ -57,7 +57,7 @@ describe ClassLoader do
|
|
57
57
|
it "should recognize infinity loop" do
|
58
58
|
autoload_dir "#{spec_dir}/infinity_loop"
|
59
59
|
|
60
|
-
|
60
|
+
-> {InfinityLoop}.should raise_error(/Class Name .+ doesn't correspond to File Name/)
|
61
61
|
end
|
62
62
|
|
63
63
|
it "should correctly works inside of anonymous class" do
|
@@ -78,10 +78,11 @@ describe ClassLoader do
|
|
78
78
|
autoload_dir "#{spec_dir}/another_namespace"
|
79
79
|
|
80
80
|
AnotherNamespace::NamespaceA
|
81
|
-
ClassLoader.error_on_defined_constant = true
|
82
|
-
|
81
|
+
# ClassLoader.error_on_defined_constant = true
|
82
|
+
-> {
|
83
83
|
AnotherNamespace::NamespaceB
|
84
|
-
}.should raise_error(/
|
84
|
+
}.should raise_error(/something wrong with/)
|
85
|
+
# }.should raise_error(/Class '.+' is not defined in the '.+' Namespace!/)
|
85
86
|
end
|
86
87
|
|
87
88
|
describe "reloading" do
|
@@ -4,7 +4,7 @@ require "class_loader"
|
|
4
4
|
describe ClassLoader::FileSystemAdapter do
|
5
5
|
with_tmp_spec_dir
|
6
6
|
|
7
|
-
before
|
7
|
+
before do
|
8
8
|
@fs_adapter = ClassLoader::FileSystemAdapter.new(ClassLoader::CamelCaseTranslator)
|
9
9
|
|
10
10
|
# Actually we are testing both ChainedAdapter and FileSystemAdapter
|
@@ -83,7 +83,7 @@ describe ClassLoader::FileSystemAdapter do
|
|
83
83
|
end
|
84
84
|
|
85
85
|
describe "Underscored shouldn't mess with CamelCase" do
|
86
|
-
before
|
86
|
+
before do
|
87
87
|
@camel_case_adapter = ClassLoader::FileSystemAdapter.new(ClassLoader::CamelCaseTranslator)
|
88
88
|
@camel_case_adapter.add_path "#{spec_dir}/shouldnt_mess", true
|
89
89
|
@camel_case_file_path = "#{spec_dir}/shouldnt_mess/CamelCaseClass.rb"
|
metadata
CHANGED
@@ -1,33 +1,23 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: class_loader
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
|
5
|
-
prerelease:
|
6
|
-
segments:
|
7
|
-
- 0
|
8
|
-
- 3
|
9
|
-
- 10
|
10
|
-
version: 0.3.10
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: '0.4'
|
5
|
+
prerelease:
|
11
6
|
platform: ruby
|
12
|
-
authors:
|
7
|
+
authors:
|
13
8
|
- Alexey Petrushin
|
14
9
|
autorequire:
|
15
10
|
bindir: bin
|
16
11
|
cert_chain: []
|
17
|
-
|
18
|
-
date: 2010-12-13 00:00:00 +03:00
|
12
|
+
date: 2011-04-10 00:00:00.000000000 +04:00
|
19
13
|
default_executable:
|
20
14
|
dependencies: []
|
21
|
-
|
22
15
|
description:
|
23
16
|
email:
|
24
17
|
executables: []
|
25
|
-
|
26
18
|
extensions: []
|
27
|
-
|
28
19
|
extra_rdoc_files: []
|
29
|
-
|
30
|
-
files:
|
20
|
+
files:
|
31
21
|
- Rakefile
|
32
22
|
- readme.md
|
33
23
|
- lib/class_loader/chained_adapter.rb
|
@@ -61,36 +51,26 @@ files:
|
|
61
51
|
has_rdoc: true
|
62
52
|
homepage: http://github.com/alexeypetrushin/class_loader
|
63
53
|
licenses: []
|
64
|
-
|
65
54
|
post_install_message:
|
66
55
|
rdoc_options: []
|
67
|
-
|
68
|
-
require_paths:
|
56
|
+
require_paths:
|
69
57
|
- lib
|
70
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
58
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
71
59
|
none: false
|
72
|
-
requirements:
|
73
|
-
- -
|
74
|
-
- !ruby/object:Gem::Version
|
75
|
-
|
76
|
-
|
77
|
-
- 0
|
78
|
-
version: "0"
|
79
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
60
|
+
requirements:
|
61
|
+
- - ! '>='
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: '0'
|
64
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
80
65
|
none: false
|
81
|
-
requirements:
|
82
|
-
- -
|
83
|
-
- !ruby/object:Gem::Version
|
84
|
-
|
85
|
-
segments:
|
86
|
-
- 0
|
87
|
-
version: "0"
|
66
|
+
requirements:
|
67
|
+
- - ! '>='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
88
70
|
requirements: []
|
89
|
-
|
90
71
|
rubyforge_project:
|
91
|
-
rubygems_version: 1.
|
72
|
+
rubygems_version: 1.5.1
|
92
73
|
signing_key:
|
93
74
|
specification_version: 3
|
94
|
-
summary: Automatically finds and
|
75
|
+
summary: Automatically finds, loads and reloads Classes
|
95
76
|
test_files: []
|
96
|
-
|