class_loader 0.4.2 → 0.4.3
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 +1 -1
- data/lib/class_loader.rb +3 -0
- data/lib/class_loader/chained_adapter.rb +35 -37
- data/lib/class_loader/class_loader.rb +29 -7
- data/lib/class_loader/file_system_adapter.rb +117 -119
- data/lib/class_loader/file_system_adapter/camel_case_translator.rb +14 -16
- data/lib/class_loader/file_system_adapter/underscored_translator.rb +14 -16
- data/lib/class_loader/tasks.rb +8 -0
- data/readme.md +1 -1
- metadata +3 -2
data/Rakefile
CHANGED
data/lib/class_loader.rb
CHANGED
@@ -1,44 +1,42 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
attr_accessor :adapters
|
1
|
+
class ClassLoader::ChainedAdapter
|
2
|
+
attr_accessor :adapters
|
4
3
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
end
|
21
|
-
nil
|
4
|
+
def initialize
|
5
|
+
@adapters = []
|
6
|
+
end
|
7
|
+
|
8
|
+
%w(
|
9
|
+
exist?
|
10
|
+
read
|
11
|
+
to_file_path
|
12
|
+
to_class_name
|
13
|
+
).each do |method|
|
14
|
+
define_method method do |*args|
|
15
|
+
catch :found do
|
16
|
+
adapters.each do |a|
|
17
|
+
value = a.send method, *args
|
18
|
+
throw :found, value if value
|
22
19
|
end
|
20
|
+
nil
|
23
21
|
end
|
24
22
|
end
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
23
|
+
end
|
24
|
+
|
25
|
+
def each_changed_class &block
|
26
|
+
adapters.each{|a| a.each_changed_class &block}
|
27
|
+
end
|
28
|
+
|
29
|
+
def each_class &block
|
30
|
+
adapters.each{|a| a.each_class &block}
|
31
|
+
end
|
32
|
+
|
33
|
+
def clear
|
34
|
+
adapters.each{|a| a.clear}
|
35
|
+
end
|
36
|
+
|
37
|
+
def add_path *args
|
38
|
+
adapters.each do |a|
|
39
|
+
a.add_path *args if a.respond_to? :add_path
|
42
40
|
end
|
43
41
|
end
|
44
42
|
end
|
@@ -1,13 +1,15 @@
|
|
1
1
|
require 'monitor'
|
2
2
|
|
3
|
+
warn 'ClassLoader: working in slow, debug mode with explicit tmp file generation!' if defined?(CLASS_LOADER_GENERATE_TMP_FILES)
|
4
|
+
|
3
5
|
module ClassLoader
|
4
6
|
@observers = []
|
5
7
|
SYNC = Monitor.new
|
6
8
|
|
7
9
|
class << self
|
8
|
-
def loaded_classes; @loaded_classes ||= {} end
|
10
|
+
def loaded_classes; @loaded_classes ||= {} end
|
9
11
|
|
10
|
-
def load_class namespace, const, reload = false
|
12
|
+
def load_class namespace, const, reload = false
|
11
13
|
SYNC.synchronize do
|
12
14
|
original_namespace = namespace
|
13
15
|
namespace = nil if namespace == Object or namespace == Module
|
@@ -52,16 +54,16 @@ module ClassLoader
|
|
52
54
|
end
|
53
55
|
end
|
54
56
|
|
55
|
-
def reload_class class_name
|
57
|
+
def reload_class class_name
|
56
58
|
SYNC.synchronize do
|
57
59
|
class_name = class_name.sub(/^::/, "")
|
58
60
|
namespace = Module.namespace_for(class_name)
|
59
61
|
name = class_name.sub(/^#{namespace}::/, "")
|
60
|
-
|
62
|
+
|
61
63
|
# removing old class
|
62
64
|
# class_container = (namespace || Object)
|
63
65
|
# class_container.send :remove_const, name if class_container.const_defined? name
|
64
|
-
|
66
|
+
|
65
67
|
return load_class namespace, name, true
|
66
68
|
end
|
67
69
|
end
|
@@ -131,6 +133,9 @@ module ClassLoader
|
|
131
133
|
#
|
132
134
|
attr_accessor :watch_interval
|
133
135
|
def start_watching!
|
136
|
+
# reloading doesn works in debug mode, because we by ourself are generating tmp source files
|
137
|
+
return if defined?(CLASS_LOADER_GENERATE_TMP_FILES)
|
138
|
+
|
134
139
|
unless @watching_thread
|
135
140
|
@watching_thread = Thread.new do
|
136
141
|
while true
|
@@ -169,8 +174,25 @@ module ClassLoader
|
|
169
174
|
def load class_name, const
|
170
175
|
script = adapter.read class_name
|
171
176
|
script = wrap_inside_namespace Module.namespace_for(class_name), script
|
172
|
-
file_path = adapter.to_file_path(class_name)
|
173
|
-
|
177
|
+
file_path = adapter.to_file_path(class_name)
|
178
|
+
|
179
|
+
# sometimes we need to generate file explicitly
|
180
|
+
# for example evaluated code will not be shown in Ruby coverage tool
|
181
|
+
unless defined?(CLASS_LOADER_GENERATE_TMP_FILES)
|
182
|
+
eval script, TOPLEVEL_BINDING, file_path
|
183
|
+
else
|
184
|
+
if file_path =~ /\.rb$/
|
185
|
+
tmp_file_path = file_path.sub /\.rb$/, '.cltmp.rb'
|
186
|
+
begin
|
187
|
+
File.open(tmp_file_path, "w"){|f| f.write(script)}
|
188
|
+
Kernel.load tmp_file_path
|
189
|
+
ensure
|
190
|
+
File.delete tmp_file_path if defined?(CLASS_LOADER_CLEAN) and ::File.exist?(tmp_file_path)
|
191
|
+
end
|
192
|
+
else
|
193
|
+
eval script, TOPLEVEL_BINDING, file_path
|
194
|
+
end
|
195
|
+
end
|
174
196
|
end
|
175
197
|
|
176
198
|
def raise_without_self exception, message
|
@@ -1,141 +1,139 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
return nil unless file_path
|
19
|
-
|
20
|
-
if file_path =~ /\.rb$/
|
21
|
-
File.open(file_path){|f| f.read}
|
22
|
-
else
|
23
|
-
"module #{class_name}; end;"
|
24
|
-
end
|
25
|
-
end
|
1
|
+
class ClassLoader::FileSystemAdapter
|
2
|
+
attr_reader :translator
|
3
|
+
|
4
|
+
def initialize class_name_translator
|
5
|
+
@translator = class_name_translator
|
6
|
+
@paths, @watched_paths, @file_name_cache = [], [], {}
|
7
|
+
@watched_files, @first_check = {}, true
|
8
|
+
end
|
9
|
+
|
10
|
+
def exist? class_name
|
11
|
+
!!to_file_path(class_name)
|
12
|
+
end
|
13
|
+
alias_method :exists?, :exist?
|
14
|
+
|
15
|
+
def read class_name
|
16
|
+
file_path = to_file_path class_name
|
17
|
+
return nil unless file_path
|
26
18
|
|
27
|
-
|
28
|
-
file_path
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
throw :found, try
|
45
|
-
end
|
19
|
+
if file_path =~ /\.rb$/
|
20
|
+
File.open(file_path){|f| f.read}
|
21
|
+
else
|
22
|
+
"module #{class_name}; end;"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def to_file_path class_name
|
27
|
+
file_path, exist = @file_name_cache[class_name] || []
|
28
|
+
unless exist
|
29
|
+
normalized_name = translator.to_file_path class_name
|
30
|
+
file_path = catch :found do
|
31
|
+
# files
|
32
|
+
paths.each do |base|
|
33
|
+
try = "#{base}/#{normalized_name}.rb"
|
34
|
+
if File.exist? try
|
35
|
+
throw :found, try
|
46
36
|
end
|
47
|
-
|
48
|
-
nil
|
49
37
|
end
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
raise "Internal error, file_name should be absolute path (#{normalized_path})!" unless normalized_path =~ /^\//
|
57
|
-
raise "Internal error, file_name should be without .rb suffix (#{normalized_path})!" if normalized_path =~ /\.rb$/
|
58
|
-
|
59
|
-
paths.each do |base_path|
|
60
|
-
if normalized_path.start_with? base_path
|
61
|
-
normalized_name = normalized_path.sub(base_path + '/', '')
|
62
|
-
if translator.is_it_class? normalized_name
|
63
|
-
return translator.to_class_name(normalized_name)
|
38
|
+
|
39
|
+
# dirs
|
40
|
+
paths.each do |base|
|
41
|
+
try = "#{base}/#{normalized_name}"
|
42
|
+
if File.exist? try
|
43
|
+
throw :found, try
|
64
44
|
end
|
65
45
|
end
|
46
|
+
|
47
|
+
nil
|
66
48
|
end
|
67
|
-
|
49
|
+
@file_name_cache[class_name] = [file_path, true]
|
68
50
|
end
|
51
|
+
file_path
|
52
|
+
end
|
53
|
+
|
54
|
+
def to_class_name normalized_path
|
55
|
+
raise "Internal error, file_name should be absolute path (#{normalized_path})!" unless normalized_path =~ /^\//
|
56
|
+
raise "Internal error, file_name should be without .rb suffix (#{normalized_path})!" if normalized_path =~ /\.rb$/
|
69
57
|
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
58
|
+
paths.each do |base_path|
|
59
|
+
if normalized_path.start_with? base_path
|
60
|
+
normalized_name = normalized_path.sub(base_path + '/', '')
|
61
|
+
if translator.is_it_class? normalized_name
|
62
|
+
return translator.to_class_name(normalized_name)
|
63
|
+
end
|
76
64
|
end
|
77
65
|
end
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
each_watched_file{|file_path, file_name| remember_file file_path}
|
88
|
-
else
|
89
|
-
each_watched_file do |file_path, file_name|
|
90
|
-
if file_changed? file_path
|
91
|
-
remember_file file_path
|
92
|
-
|
93
|
-
normalized_name = file_name.sub(/\.rb$/, "")
|
94
|
-
block.call translator.to_class_name(normalized_name)
|
95
|
-
end
|
96
|
-
end
|
97
|
-
end
|
66
|
+
nil
|
67
|
+
end
|
68
|
+
|
69
|
+
def add_path base_path, watch = false
|
70
|
+
base_path = File.expand_path(base_path)
|
71
|
+
# raise "#{base_path} already added!" if paths.include? base_path
|
72
|
+
unless paths.include? base_path
|
73
|
+
paths << base_path
|
74
|
+
watched_paths << base_path if watch
|
98
75
|
end
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
76
|
+
end
|
77
|
+
|
78
|
+
def clear
|
79
|
+
@paths, @watched_paths, @file_name_cache = [], [], {}
|
80
|
+
@watched_files, @first_check = {}, true
|
81
|
+
end
|
82
|
+
|
83
|
+
def each_changed_class &block
|
84
|
+
unless @first_check == @watched_paths
|
85
|
+
@first_check = @watched_paths.clone
|
86
|
+
each_watched_file{|file_path, file_name| remember_file file_path}
|
87
|
+
else
|
88
|
+
each_watched_file do |file_path, file_name|
|
89
|
+
if file_changed? file_path
|
90
|
+
remember_file file_path
|
104
91
|
|
105
|
-
normalized_name =
|
106
|
-
|
107
|
-
block.call class_name
|
92
|
+
normalized_name = file_name.sub(/\.rb$/, "")
|
93
|
+
block.call translator.to_class_name(normalized_name)
|
108
94
|
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def each_class &block
|
100
|
+
@paths.each do |base_path|
|
101
|
+
Dir.glob("#{base_path}/**/*.rb").each do |file_path|
|
102
|
+
normalized_path = file_path.sub(/\.rb$/, "")
|
103
|
+
|
104
|
+
normalized_name = normalized_path.sub(base_path + "/", '')
|
105
|
+
class_name = translator.to_class_name(normalized_name)
|
106
|
+
block.call class_name
|
109
107
|
end
|
110
108
|
end
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
109
|
+
end
|
110
|
+
|
111
|
+
def each_watched_file &block
|
112
|
+
@watched_paths.each do |base_path|
|
113
|
+
Dir.glob("#{base_path}/**/*.rb").each do |file_path|
|
114
|
+
file_name = file_path.sub(base_path + '/', '')
|
116
115
|
|
117
|
-
|
118
|
-
|
119
|
-
end
|
116
|
+
if translator.is_it_class? file_name
|
117
|
+
block.call file_path, file_name
|
120
118
|
end
|
121
119
|
end
|
122
120
|
end
|
121
|
+
end
|
122
|
+
|
123
|
+
def inspect
|
124
|
+
"FileSystemAdapter (#{@paths.join(', ')})"
|
125
|
+
end
|
126
|
+
|
127
|
+
protected
|
128
|
+
attr_reader :paths, :watched_paths, :watcher, :watched_files
|
123
129
|
|
124
|
-
def
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
protected
|
129
|
-
attr_reader :paths, :watched_paths, :watcher, :watched_files
|
130
|
-
|
131
|
-
def file_changed? file_path
|
132
|
-
old_time = watched_files[file_path]
|
133
|
-
old_time == nil or old_time != File.mtime(file_path)
|
134
|
-
end
|
130
|
+
def file_changed? file_path
|
131
|
+
old_time = watched_files[file_path]
|
132
|
+
old_time == nil or old_time != File.mtime(file_path)
|
133
|
+
end
|
135
134
|
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
end
|
135
|
+
def remember_file file_path
|
136
|
+
watched_files[file_path] = File.mtime(file_path)
|
137
|
+
end
|
138
|
+
|
141
139
|
end
|
@@ -1,18 +1,16 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
normalized_file_name[0..0] =~ /[A-Z]/
|
16
|
-
end
|
1
|
+
class ClassLoader::CamelCaseTranslator
|
2
|
+
def self.to_class_name normalized_file_name
|
3
|
+
raise "internall error, invalid format for #{normalized_file_name}!" if normalized_file_name =~ /^\//
|
4
|
+
normalized_file_name.gsub('/', '::')
|
5
|
+
end
|
6
|
+
|
7
|
+
def self.to_file_path class_name
|
8
|
+
raise "internall error, invalid format for #{class_name}!" if class_name =~ /^::/
|
9
|
+
class_name.gsub('::', '/')
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.is_it_class? normalized_file_name
|
13
|
+
raise "internall error, invalid format for #{normalized_file_name}!" if normalized_file_name =~ /^\//
|
14
|
+
normalized_file_name[0..0] =~ /[A-Z]/
|
17
15
|
end
|
18
16
|
end
|
@@ -1,18 +1,16 @@
|
|
1
|
-
module ClassLoader
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
normalized_file_name[0..0] =~ /[a-z]/
|
16
|
-
end
|
1
|
+
module ClassLoader::UnderscoredTranslator
|
2
|
+
def self.to_class_name normalized_file_name
|
3
|
+
raise "internall error, invalid format for #{normalized_file_name}!" if normalized_file_name =~ /^\//
|
4
|
+
normalized_file_name.camelize
|
5
|
+
end
|
6
|
+
|
7
|
+
def self.to_file_path class_name
|
8
|
+
raise "internall error, invalid format for #{class_name}!" if class_name =~ /^::/
|
9
|
+
class_name.underscore
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.is_it_class? normalized_file_name
|
13
|
+
raise "internall error, invalid format for #{normalized_file_name}!" if normalized_file_name =~ /^\//
|
14
|
+
normalized_file_name[0..0] =~ /[a-z]/
|
17
15
|
end
|
18
16
|
end
|
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) Alexey Petrushin http://4ire.net, released under the MIT license.
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: class_loader
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.4.
|
4
|
+
version: 0.4.3
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2011-
|
12
|
+
date: 2011-07-02 00:00:00.000000000 +04:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
description:
|
@@ -26,6 +26,7 @@ files:
|
|
26
26
|
- lib/class_loader/file_system_adapter/underscored_translator.rb
|
27
27
|
- lib/class_loader/file_system_adapter.rb
|
28
28
|
- lib/class_loader/support.rb
|
29
|
+
- lib/class_loader/tasks.rb
|
29
30
|
- lib/class_loader.rb
|
30
31
|
- spec/class_loader_spec/anonymous_class/AnonymousSpec/ClassInsideOfAnonymousClass.rb
|
31
32
|
- spec/class_loader_spec/another_namespace/AnotherNamespace/NamespaceA.rb
|