class_loader 3.0.0 → 3.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/Rakefile CHANGED
@@ -4,7 +4,7 @@ project(
4
4
  name: "class_loader",
5
5
  gem: true,
6
6
  summary: "Automatically find, load and reload classes",
7
- version: '3.0.0',
7
+ # version: '3.0.0',
8
8
 
9
9
  author: "Alexey Petrushin",
10
10
  homepage: "http://github.com/alexeypetrushin/class_loader"
@@ -1,9 +1,11 @@
1
1
  require 'class_loader/support'
2
+ require 'monitor'
2
3
 
3
4
  module ClassLoader
4
5
  @loaded_classes = {}
6
+ @monitor = Monitor.new
5
7
  class << self
6
- attr_reader :loaded_classes
8
+ attr_reader :loaded_classes, :monitor
7
9
 
8
10
  # Hierarchically searching for class file, according to modules hierarchy.
9
11
  #
@@ -13,65 +15,69 @@ module ClassLoader
13
15
  # - '/lib/a/b/c.rb' - there's nothing, moving up in hierarchy.
14
16
  # - '/lib/a/c.rb' - got and load it.
15
17
  def load namespace, const
16
- original_namespace = namespace
17
- namespace = nil if namespace == Object or namespace == Module
18
- target_namespace = namespace
18
+ monitor.synchronize do
19
+ original_namespace = namespace
20
+ namespace = nil if namespace == Object or namespace == Module
21
+ target_namespace = namespace
22
+
23
+ # Need this hack to work with anonymous classes.
24
+ namespace = eval "#{name_hack(namespace)}" if namespace
25
+
26
+ # Hierarchically searching for class name.
27
+ begin
28
+ class_name = namespace ? "#{namespace.name}::#{const}" : const.to_s
29
+ class_file_name = get_file_name class_name
30
+
31
+ # Trying to load class file, if its exist.
32
+ loaded = begin
33
+ require class_file_name
34
+ true
35
+ rescue LoadError => e
36
+ # Not the best way - hardcoding error messages, but it's the fastest way
37
+ # to check existence of file & load it.
38
+ raise e unless e.message =~ /no such file.*#{Regexp.escape(class_file_name)}/
39
+ false
40
+ end
19
41
 
20
- # Need this hack to work with anonymous classes.
21
- namespace = eval "#{name_hack(namespace)}" if namespace
42
+ if loaded
43
+ # Checking that class hasn't been loaded previously, sometimes it may be caused by
44
+ # weird class definition code.
45
+ if loaded_classes.include? class_name
46
+ raise_without_self NameError, \
47
+ "something wrong with '#{const}' referenced from '#{original_namespace}' scope!"
48
+ end
22
49
 
23
- # Hierarchically searching for class name.
24
- begin
25
- class_name = namespace ? "#{namespace.name}::#{const}" : const.to_s
26
- class_file_name = get_file_name class_name
50
+ # Checking that class defined in correct namespace, not the another one.
51
+ unless namespace ? namespace.const_defined?(const, false) : Object.const_defined?(const, false)
52
+ raise_without_self NameError, \
53
+ "class name '#{class_name}' doesn't correspond to file name '#{class_file_name}'!"
54
+ end
27
55
 
28
- # Trying to load class file, if its exist.
29
- loaded = begin
30
- require class_file_name
31
- true
32
- rescue LoadError => e
33
- # Not the best way - hardcoding error messages, but it's the fastest way
34
- # to check existence of file & load it.
35
- raise e unless e.message =~ /no such file.*#{Regexp.escape(class_file_name)}/
36
- false
37
- end
56
+ # Getting the class itself.
57
+ klass = namespace ? namespace.const_get(const, false) : Object.const_get(const, false)
38
58
 
39
- if loaded
40
- # Checking that class hasn't been loaded previously, sometimes it may be caused by
41
- # weird class definition code.
42
- if loaded_classes.include? class_name
43
- raise_without_self NameError, \
44
- "something wrong with '#{const}' referenced from '#{original_namespace}' scope!"
45
- end
59
+ loaded_classes[class_name] = klass
46
60
 
47
- # Checking that class defined in correct namespace, not the another one.
48
- unless namespace ? namespace.const_defined?(const, false) : Object.const_defined?(const, false)
49
- raise_without_self NameError, \
50
- "class name '#{class_name}' doesn't correspond to file name '#{class_file_name}'!"
61
+ return klass
51
62
  end
52
63
 
53
- # Getting the class itself.
54
- klass = namespace ? namespace.const_get(const, false) : Object.const_get(const, false)
55
-
56
- loaded_classes[class_name] = klass
64
+ # Moving to higher namespace.
65
+ global_also_tried = namespace == nil
66
+ namespace = Module.namespace_for namespace.name if namespace
67
+ end until global_also_tried
57
68
 
58
- return klass
59
- end
60
-
61
- # Moving to higher namespace.
62
- global_also_tried = namespace == nil
63
- namespace = Module.namespace_for namespace.name if namespace
64
- end until global_also_tried
65
-
66
- return nil
69
+ return nil
70
+ end
67
71
  end
68
72
 
69
73
  # Dynamic class loading is not thread safe (known Ruby bug), to workaround it
70
74
  # You can forcefully preload all Your classes in production when Your app starts.
71
75
  def preload path
72
- Dir.glob("#{path}/**/*.rb").each do |class_path|
73
- class_file_name = class_path.sub("#{path}/", '').sub(/\.rb$/, '')
74
- require class_file_name
76
+ monitor.synchronize do
77
+ Dir.glob("#{path}/**/*.rb").each do |class_path|
78
+ class_file_name = class_path.sub("#{path}/", '').sub(/\.rb$/, '')
79
+ require class_file_name
80
+ end
75
81
  end
76
82
  end
77
83
 
@@ -83,7 +89,7 @@ module ClassLoader
83
89
 
84
90
  def watcher
85
91
  require 'class_loader/watcher'
86
- @watcher ||= ClassLoader::Watcher.new
92
+ @watcher ||= ClassLoader::Watcher.new monitor
87
93
  end
88
94
 
89
95
  protected
@@ -1,7 +1,8 @@
1
1
  class ClassLoader::Watcher
2
2
  attr_accessor :paths, :interval
3
3
 
4
- def initialize
4
+ def initialize monitor
5
+ @monitor = monitor
5
6
  @paths, @files = [], {}
6
7
  @interval = 2
7
8
  end
@@ -23,22 +24,24 @@ class ClassLoader::Watcher
23
24
  end
24
25
 
25
26
  def check
26
- paths.each do |path|
27
- Dir.glob("#{path}/**/*.rb").each do |class_path|
28
- updated_at = File.mtime class_path
29
- if last_updated_at = files[class_path]
30
- if last_updated_at < updated_at
31
- class_file_name = class_path.sub "#{path}/", ''
32
- warn "reloading #{class_file_name}"
33
- load class_file_name
27
+ monitor.synchronize do
28
+ paths.each do |path|
29
+ Dir.glob("#{path}/**/*.rb").each do |class_path|
30
+ updated_at = File.mtime class_path
31
+ if last_updated_at = files[class_path]
32
+ if last_updated_at < updated_at
33
+ class_file_name = class_path.sub "#{path}/", ''
34
+ warn "reloading #{class_file_name}"
35
+ load class_file_name
36
+ end
37
+ else
38
+ files[class_path] = updated_at
34
39
  end
35
- else
36
- files[class_path] = updated_at
37
40
  end
38
41
  end
39
42
  end
40
43
  end
41
44
 
42
45
  protected
43
- attr_reader :files, :thread
46
+ attr_reader :files, :thread, :monitor
44
47
  end
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: 3.0.0
4
+ version: 3.0.1
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors: