activesupport 1.2.5 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of activesupport might be problematic. Click here for more details.

Files changed (63) hide show
  1. data/CHANGELOG +163 -4
  2. data/lib/active_support.rb +8 -3
  3. data/lib/active_support/breakpoint.rb +1 -1
  4. data/lib/active_support/caching_tools.rb +62 -0
  5. data/lib/active_support/clean_logger.rb +3 -1
  6. data/lib/active_support/core_ext/array.rb +16 -0
  7. data/lib/active_support/core_ext/array/conversions.rb +18 -2
  8. data/lib/active_support/core_ext/blank.rb +14 -2
  9. data/lib/active_support/core_ext/class.rb +3 -0
  10. data/lib/active_support/core_ext/class/attribute_accessors.rb +44 -0
  11. data/lib/active_support/{class_inheritable_attributes.rb → core_ext/class/inheritable_attributes.rb} +2 -4
  12. data/lib/active_support/core_ext/class/removal.rb +24 -0
  13. data/lib/active_support/core_ext/date/conversions.rb +2 -0
  14. data/lib/active_support/core_ext/enumerable.rb +23 -1
  15. data/lib/active_support/core_ext/exception.rb +0 -1
  16. data/lib/active_support/core_ext/hash.rb +4 -0
  17. data/lib/active_support/core_ext/hash/conversions.rb +44 -0
  18. data/lib/active_support/core_ext/hash/diff.rb +11 -0
  19. data/lib/active_support/core_ext/hash/indifferent_access.rb +23 -4
  20. data/lib/active_support/core_ext/integer/inflections.rb +1 -1
  21. data/lib/active_support/core_ext/kernel.rb +4 -79
  22. data/lib/active_support/core_ext/kernel/agnostics.rb +11 -0
  23. data/lib/active_support/core_ext/kernel/daemonizing.rb +15 -0
  24. data/lib/active_support/core_ext/kernel/reporting.rb +51 -0
  25. data/lib/active_support/core_ext/kernel/requires.rb +24 -0
  26. data/lib/active_support/core_ext/logger.rb +16 -0
  27. data/lib/active_support/core_ext/module.rb +5 -0
  28. data/lib/active_support/core_ext/module/attribute_accessors.rb +44 -0
  29. data/lib/active_support/core_ext/module/delegation.rb +16 -0
  30. data/lib/active_support/core_ext/module/inclusion.rb +11 -0
  31. data/lib/active_support/core_ext/module/introspection.rb +21 -0
  32. data/lib/active_support/core_ext/module/loading.rb +13 -0
  33. data/lib/active_support/core_ext/numeric/time.rb +14 -1
  34. data/lib/active_support/core_ext/object.rb +2 -0
  35. data/lib/active_support/core_ext/object/extending.rb +47 -0
  36. data/lib/active_support/core_ext/object/misc.rb +34 -0
  37. data/lib/active_support/core_ext/proc.rb +12 -0
  38. data/lib/active_support/core_ext/string.rb +2 -0
  39. data/lib/active_support/core_ext/string/access.rb +2 -2
  40. data/lib/active_support/core_ext/string/inflections.rb +10 -3
  41. data/lib/active_support/core_ext/string/iterators.rb +17 -0
  42. data/lib/active_support/core_ext/symbol.rb +5 -0
  43. data/lib/active_support/core_ext/time/calculations.rb +15 -0
  44. data/lib/active_support/core_ext/time/conversions.rb +1 -0
  45. data/lib/active_support/dependencies.rb +81 -159
  46. data/lib/active_support/inflections.rb +48 -48
  47. data/lib/active_support/inflector.rb +17 -5
  48. data/lib/active_support/json.rb +37 -0
  49. data/lib/active_support/json/encoders.rb +25 -0
  50. data/lib/active_support/json/encoders/core.rb +65 -0
  51. data/lib/active_support/option_merger.rb +25 -0
  52. data/lib/active_support/ordered_options.rb +23 -11
  53. data/lib/active_support/reloadable.rb +30 -0
  54. data/lib/active_support/vendor/builder.rb +13 -0
  55. data/lib/active_support/vendor/builder/blankslate.rb +53 -0
  56. data/lib/active_support/vendor/builder/xmlbase.rb +143 -0
  57. data/lib/active_support/vendor/builder/xmlevents.rb +63 -0
  58. data/lib/active_support/vendor/builder/xmlmarkup.rb +308 -0
  59. data/lib/active_support/version.rb +2 -2
  60. metadata +113 -69
  61. data/lib/active_support/class_attribute_accessors.rb +0 -57
  62. data/lib/active_support/core_ext/object_and_class.rb +0 -44
  63. data/lib/active_support/module_attribute_accessors.rb +0 -57
@@ -0,0 +1,11 @@
1
+ class Module
2
+ def included_in_classes
3
+ classes = []
4
+ ObjectSpace.each_object(Class) { |k| classes << k if k.included_modules.include?(self) }
5
+
6
+ classes.reverse.inject([]) do |unique_classes, klass|
7
+ unique_classes << klass unless unique_classes.collect { |k| k.to_s }.include?(klass.to_s)
8
+ unique_classes
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,21 @@
1
+ class Module
2
+ # Return the module which contains this one; if this is a root module, such as
3
+ # +::MyModule+, then Object is returned.
4
+ def parent
5
+ parent_name = name.split('::')[0..-2] * '::'
6
+ parent_name.empty? ? Object : parent_name.constantize
7
+ end
8
+
9
+ # Return all the parents of this module, ordered from nested outwards. The
10
+ # receiver is not contained within the result.
11
+ def parents
12
+ parents = []
13
+ parts = name.split('::')[0..-2]
14
+ until parts.empty?
15
+ parents << (parts * '::').constantize
16
+ parts.pop
17
+ end
18
+ parents << Object unless parents.include? Object
19
+ parents
20
+ end
21
+ end
@@ -0,0 +1,13 @@
1
+ class Module
2
+ def as_load_path
3
+ if self == Object || self == Kernel
4
+ ''
5
+ elsif is_a? Class
6
+ parent == self ? '' : parent.as_load_path
7
+ else
8
+ name.split('::').collect do |word|
9
+ word.underscore
10
+ end * '/'
11
+ end
12
+ end
13
+ end
@@ -1,8 +1,21 @@
1
1
  module ActiveSupport #:nodoc:
2
2
  module CoreExtensions #:nodoc:
3
3
  module Numeric #:nodoc:
4
- # Enables the use of time calculations and declarations, like 45.minutes + 2.hours + 4.years
4
+ # Enables the use of time calculations and declarations, like 45.minutes + 2.hours + 4.years.
5
+ #
6
+ # If you need precise date calculations that doesn't just treat months as 30 days, then have
7
+ # a look at Time#advance.
8
+ #
9
+ # Some of these methods are approximations, Ruby's core
10
+ # Date[http://stdlib.rubyonrails.org/libdoc/date/rdoc/index.html] and
11
+ # Time[http://stdlib.rubyonrails.org/libdoc/time/rdoc/index.html] should be used for precision
12
+ # date and time arithmetic
5
13
  module Time
14
+ def seconds
15
+ self
16
+ end
17
+ alias :second :seconds
18
+
6
19
  def minutes
7
20
  self * 60
8
21
  end
@@ -0,0 +1,2 @@
1
+ require File.dirname(__FILE__) + '/object/extending'
2
+ require File.dirname(__FILE__) + '/object/misc'
@@ -0,0 +1,47 @@
1
+ class Object #:nodoc:
2
+ def remove_subclasses_of(*superclasses)
3
+ Class.remove_class(*subclasses_of(*superclasses))
4
+ end
5
+
6
+ def subclasses_of(*superclasses)
7
+ subclasses = []
8
+ ObjectSpace.each_object(Class) do |k|
9
+ next if # Exclude this class if
10
+ (k.ancestors & superclasses).empty? || # It's not a subclass of our supers
11
+ superclasses.include?(k) || # It *is* one of the supers
12
+ eval("! defined?(::#{k})") || # It's not defined.
13
+ eval("::#{k}").object_id != k.object_id
14
+ subclasses << k
15
+ end
16
+ subclasses
17
+ end
18
+
19
+ def extended_by
20
+ ancestors = class << self; ancestors end
21
+ ancestors.select { |mod| mod.class == Module } - [ Object, Kernel ]
22
+ end
23
+
24
+ def copy_instance_variables_from(object, exclude = [])
25
+ exclude += object.protected_instance_variables if object.respond_to? :protected_instance_variables
26
+
27
+ instance_variables = object.instance_variables - exclude.map { |name| name.to_s }
28
+ instance_variables.each { |name| instance_variable_set(name, object.instance_variable_get(name)) }
29
+ end
30
+
31
+ def extend_with_included_modules_from(object)
32
+ object.extended_by.each { |mod| extend mod }
33
+ end
34
+
35
+ def instance_values
36
+ instance_variables.inject({}) do |values, name|
37
+ values[name[1..-1]] = instance_variable_get(name)
38
+ values
39
+ end
40
+ end
41
+
42
+ unless defined? instance_exec # 1.9
43
+ def instance_exec(*arguments, &block)
44
+ block.bind(self)[*arguments]
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,34 @@
1
+ class Object #:nodoc:
2
+ # A Ruby-ized realization of the K combinator, courtesy of Mikael Brockman.
3
+ #
4
+ # def foo
5
+ # returning values = [] do
6
+ # values << 'bar'
7
+ # values << 'baz'
8
+ # end
9
+ # end
10
+ #
11
+ # foo # => ['bar', 'baz']
12
+ #
13
+ # def foo
14
+ # returning [] do |values|
15
+ # values << 'bar'
16
+ # values << 'baz'
17
+ # end
18
+ # end
19
+ #
20
+ # foo # => ['bar', 'baz']
21
+ #
22
+ def returning(value)
23
+ yield(value)
24
+ value
25
+ end
26
+
27
+ def with_options(options)
28
+ yield ActiveSupport::OptionMerger.new(self, options)
29
+ end
30
+
31
+ def to_json
32
+ ActiveSupport::JSON.encode(self)
33
+ end
34
+ end
@@ -0,0 +1,12 @@
1
+ class Proc #:nodoc:
2
+ def bind(object)
3
+ block, time = self, Time.now
4
+ (class << object; self end).class_eval do
5
+ method_name = "__bind_#{time.to_i}_#{time.usec}"
6
+ define_method(method_name, &block)
7
+ method = instance_method(method_name)
8
+ remove_method(method_name)
9
+ method
10
+ end.bind(object)
11
+ end
12
+ end
@@ -2,10 +2,12 @@ require File.dirname(__FILE__) + '/string/inflections'
2
2
  require File.dirname(__FILE__) + '/string/conversions'
3
3
  require File.dirname(__FILE__) + '/string/access'
4
4
  require File.dirname(__FILE__) + '/string/starts_ends_with'
5
+ require File.dirname(__FILE__) + '/string/iterators'
5
6
 
6
7
  class String #:nodoc:
7
8
  include ActiveSupport::CoreExtensions::String::Access
8
9
  include ActiveSupport::CoreExtensions::String::Conversions
9
10
  include ActiveSupport::CoreExtensions::String::Inflections
10
11
  include ActiveSupport::CoreExtensions::String::StartsEndsWith
12
+ include ActiveSupport::CoreExtensions::String::Iterators
11
13
  end
@@ -50,9 +50,9 @@ module ActiveSupport #:nodoc:
50
50
  # "hello".last(2) # => "lo"
51
51
  # "hello".last(10) # => "hello"
52
52
  def last(limit = 1)
53
- self[(-limit)..-1]
53
+ self[(-limit)..-1] || self
54
54
  end
55
55
  end
56
56
  end
57
57
  end
58
- end
58
+ end
@@ -1,4 +1,4 @@
1
- require File.dirname(__FILE__) + '/../../inflector'
1
+ require File.dirname(__FILE__) + '/../../inflector' unless defined? Inflector
2
2
  module ActiveSupport #:nodoc:
3
3
  module CoreExtensions #:nodoc:
4
4
  module String #:nodoc:
@@ -12,8 +12,11 @@ module ActiveSupport #:nodoc:
12
12
  Inflector.singularize(self)
13
13
  end
14
14
 
15
- def camelize
16
- Inflector.camelize(self)
15
+ def camelize(first_letter = :upper)
16
+ case first_letter
17
+ when :upper then Inflector.camelize(self, true)
18
+ when :lower then Inflector.camelize(self, false)
19
+ end
17
20
  end
18
21
  alias_method :camelcase, :camelize
19
22
 
@@ -26,6 +29,10 @@ module ActiveSupport #:nodoc:
26
29
  Inflector.underscore(self)
27
30
  end
28
31
 
32
+ def dasherize
33
+ Inflector.dasherize(self)
34
+ end
35
+
29
36
  def demodulize
30
37
  Inflector.demodulize(self)
31
38
  end
@@ -0,0 +1,17 @@
1
+ require 'strscan'
2
+
3
+ module ActiveSupport #:nodoc:
4
+ module CoreExtensions #:nodoc:
5
+ module String #:nodoc:
6
+ # Custom string iterators
7
+ module Iterators
8
+ # Yields a single-character string for each character in the string.
9
+ # When $KCODE = 'UTF8', multi-byte characters are yielded appropriately.
10
+ def each_char
11
+ scanner, char = StringScanner.new(self), /./mu
12
+ loop { yield(scanner.scan(char) || break) }
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,5 @@
1
+ class Symbol #:nodoc:
2
+ def to_proc
3
+ Proc.new { |obj, *args| obj.send(self, *args) }
4
+ end
5
+ end
@@ -44,6 +44,15 @@ module ActiveSupport #:nodoc:
44
44
  options[:usec] || ((options[:hour] || options[:min] || options[:sec]) ? 0 : self.usec)
45
45
  )
46
46
  end
47
+
48
+ # Uses Date to provide precise Time calculations for years, months, and days. The +options+ parameter takes a hash with
49
+ # any of these keys: :months, :days, :years.
50
+ def advance(options)
51
+ d = ::Date.new(year + (options.delete(:years) || 0), month, day)
52
+ d = d >> options.delete(:months) if options[:months]
53
+ d = d + options.delete(:days) if options[:days]
54
+ change(options.merge(:year => d.year, :month => d.month, :mday => d.day))
55
+ end
47
56
 
48
57
  # Returns a new Time representing the time a number of seconds ago, this is basically a wrapper around the Numeric extension
49
58
  # Do not use this method in combination with x.months, use months_ago instead!
@@ -152,6 +161,12 @@ module ActiveSupport #:nodoc:
152
161
  change(:mday => last_day,:hour => 0, :min => 0, :sec => 0, :usec => 0)
153
162
  end
154
163
  alias :at_end_of_month :end_of_month
164
+
165
+ # Returns a new Time representing the start of the quarter (1st of january, april, july, october, 0:00)
166
+ def beginning_of_quarter
167
+ beginning_of_month.change(:month => [10, 7, 4, 1].detect { |m| m <= self.month })
168
+ end
169
+ alias :at_beginning_of_quarter :beginning_of_quarter
155
170
 
156
171
  # Returns a new Time representing the start of the year (1st of january, 0:00)
157
172
  def beginning_of_year
@@ -1,4 +1,5 @@
1
1
  require 'date'
2
+ require 'time'
2
3
 
3
4
  module ActiveSupport #:nodoc:
4
5
  module CoreExtensions #:nodoc:
@@ -1,176 +1,72 @@
1
- require File.dirname(__FILE__) + '/module_attribute_accessors'
1
+ require 'set'
2
+ require File.dirname(__FILE__) + '/core_ext/module/attribute_accessors'
2
3
  require File.dirname(__FILE__) + '/core_ext/load_error'
4
+ require File.dirname(__FILE__) + '/core_ext/kernel'
3
5
 
4
6
  module Dependencies #:nodoc:
5
7
  extend self
6
8
 
7
- @@loaded = [ ]
9
+ # Should we turn on Ruby warnings on the first load of dependent files?
10
+ mattr_accessor :warnings_on_first_load
11
+ self.warnings_on_first_load = false
12
+
13
+ # All files ever loaded.
14
+ mattr_accessor :history
15
+ self.history = Set.new
16
+
17
+ # All files currently loaded.
8
18
  mattr_accessor :loaded
19
+ self.loaded = Set.new
9
20
 
10
- @@mechanism = :load
21
+ # Should we load files or require them?
11
22
  mattr_accessor :mechanism
12
-
23
+ self.mechanism = :load
24
+
13
25
  def load?
14
26
  mechanism == :load
15
27
  end
16
-
17
- def depend_on(file_name, swallow_load_errors = false)
18
- unless loaded.include?(file_name)
19
- loaded << file_name
20
28
 
21
- begin
22
- require_or_load(file_name)
23
- rescue LoadError
24
- raise unless swallow_load_errors
25
- end
26
- end
29
+ def depend_on(file_name, swallow_load_errors = false)
30
+ require_or_load(file_name)
31
+ rescue LoadError
32
+ raise unless swallow_load_errors
27
33
  end
28
34
 
29
35
  def associate_with(file_name)
30
36
  depend_on(file_name, true)
31
37
  end
32
-
38
+
33
39
  def clear
34
- self.loaded = [ ]
40
+ loaded.clear
35
41
  end
36
-
37
- def require_or_load(file_name)
38
- file_name = "#{file_name}.rb" unless ! load? || file_name[-3..-1] == '.rb'
39
- load? ? load(file_name) : require(file_name)
40
- end
41
-
42
- def remove_subclasses_for(*classes)
43
- Object.remove_subclasses_of(*classes)
44
- end
45
-
46
- # LoadingModules implement namespace-safe dynamic loading.
47
- # They support automatic loading via const_missing, allowing contained items to be automatically
48
- # loaded when required. No extra syntax is required, as expressions such as Controller::Admin::UserController
49
- # load the relavent files automatically.
50
- #
51
- # Ruby-style modules are supported, as a folder named 'submodule' will load 'submodule.rb' when available.
52
- class LoadingModule < Module #:nodoc:
53
- attr_reader :path
54
- attr_reader :root
55
-
56
- class << self
57
- def root(*load_paths)
58
- RootLoadingModule.new(*load_paths)
59
- end
60
- end
61
-
62
- def initialize(root, path=[])
63
- @path = path.clone.freeze
64
- @root = root
65
- end
66
-
67
- def root?() self.root == self end
68
- def load_paths() self.root.load_paths end
69
-
70
- # Load missing constants if possible.
71
- def const_missing(name)
72
- const_load!(name) ? const_get(name) : super(name)
73
- end
74
-
75
- # Load the controller class or a parent module.
76
- def const_load!(name, file_name = nil)
77
- file_name ||= 'application' if root? && name.to_s == 'ApplicationController'
78
- path = self.path + [file_name || name]
79
-
80
- load_paths.each do |load_path|
81
- fs_path = load_path.filesystem_path(path)
82
- next unless fs_path
83
-
84
- case
85
- when File.directory?(fs_path)
86
- new_module = LoadingModule.new(self.root, self.path + [name])
87
- self.const_set name, new_module
88
- if self.root?
89
- if Object.const_defined?(name)
90
- msg = "Cannot load module #{name}: Object::#{name} is set to #{Object.const_get(name).inspect}"
91
- raise NameError, msg
92
- end
93
- Object.const_set(name, new_module)
94
- end
95
- break
96
- when File.file?(fs_path)
97
- loaded_file = self.root.load_file!(fs_path)
98
-
99
- # Import the loaded constant from Object provided we are the root node.
100
- self.const_set(name, Object.const_get(name)) if self.root? && Object.const_defined?(name)
101
-
102
- # Throw an error if we load the file but we don't find the Object we expect
103
- if loaded_file and not self.const_defined?(name)
104
- msg = "Already loaded file '#{fs_path}' but '#{name.to_s}' was not set, perhaps you need to rename '#{fs_path}'?"
105
- raise LoadError, msg
106
- end
107
- break
108
- end
109
- end
110
-
111
- self.const_defined?(name)
112
- end
113
-
114
- # Is this name present or loadable?
115
- # This method is used by Routes to find valid controllers.
116
- def const_available?(name)
117
- self.const_defined?(name) || load_paths.any? {|lp| lp.filesystem_path(path + [name])}
118
- end
119
- end
120
-
121
- class RootLoadingModule < LoadingModule #:nodoc:
122
- attr_reader :load_paths
123
42
 
124
- def initialize(*paths)
125
- @load_paths = paths.flatten.collect {|p| p.kind_of?(ConstantLoadPath) ? p : ConstantLoadPath.new(p)}
126
- end
127
-
128
- def root() self end
43
+ def require_or_load(file_name)
44
+ file_name = $1 if file_name =~ /^(.*)\.rb$/
45
+ return if loaded.include?(file_name)
129
46
 
130
- def path() [] end
131
-
132
- # Load the source file at the given file path
133
- def load_file!(file_path)
134
- require_dependency(file_path)
135
- end
47
+ # Record that we've seen this file *before* loading it to avoid an
48
+ # infinite loop with mutual dependencies.
49
+ loaded << file_name
136
50
 
137
- # Erase all items in this module
138
- def clear!
139
- constants.each do |name|
140
- Object.send(:remove_const, name) if Object.const_defined?(name) && Object.const_get(name).object_id == self.const_get(name).object_id
141
- self.send(:remove_const, name)
142
- end
143
- end
144
- end
145
-
146
- # This object defines a path from which Constants can be loaded.
147
- class ConstantLoadPath #:nodoc:
148
- # Create a new load path with the filesystem path
149
- def initialize(root) @root = root end
150
-
151
- # Return nil if the path does not exist, or the path to a directory
152
- # if the path leads to a module, or the path to a file if it leads to an object.
153
- def filesystem_path(path, allow_module=true)
154
- fs_path = [@root]
155
- fs_path += path[0..-2].map {|name| const_name_to_module_name name}
156
-
157
- if allow_module
158
- result = File.join(fs_path, const_name_to_module_name(path.last))
159
- return result if File.directory? result # Return the module path if one exists
51
+ if load?
52
+ begin
53
+ # Enable warnings iff this file has not been loaded before and
54
+ # warnings_on_first_load is set.
55
+ if !warnings_on_first_load or history.include?(file_name)
56
+ load "#{file_name}.rb"
57
+ else
58
+ enable_warnings { load "#{file_name}.rb" }
59
+ end
60
+ rescue
61
+ loaded.delete file_name
62
+ raise
160
63
  end
161
-
162
- result = File.join(fs_path, const_name_to_file_name(path.last))
163
-
164
- File.file?(result) ? result : nil
165
- end
166
-
167
- def const_name_to_file_name(name)
168
- name.to_s.underscore + '.rb'
64
+ else
65
+ require file_name
169
66
  end
170
67
 
171
- def const_name_to_module_name(name)
172
- name.to_s.underscore
173
- end
68
+ # Record history *after* loading so first load gets warnings.
69
+ history << file_name
174
70
  end
175
71
  end
176
72
 
@@ -181,27 +77,53 @@ Object.send(:define_method, :require_association) { |file_name| Dependencies.ass
181
77
  class Module #:nodoc:
182
78
  # Rename the original handler so we can chain it to the new one
183
79
  alias :rails_original_const_missing :const_missing
184
-
80
+
185
81
  # Use const_missing to autoload associations so we don't have to
186
82
  # require_association when using single-table inheritance.
187
83
  def const_missing(class_id)
188
- if Object.const_defined?(:Controllers) and Object::Controllers.const_available?(class_id)
189
- return Object::Controllers.const_get(class_id)
190
- end
191
-
192
84
  file_name = class_id.to_s.demodulize.underscore
85
+ file_path = as_load_path.empty? ? file_name : "#{as_load_path}/#{file_name}"
193
86
  begin
194
- require_dependency(file_name)
195
- raise NameError.new("uninitialized constant #{class_id}") unless Object.const_defined?(class_id)
196
- return Object.const_get(class_id)
87
+ require_dependency(file_path)
88
+ brief_name = self == Object ? '' : "#{name}::"
89
+ raise NameError.new("uninitialized constant #{brief_name}#{class_id}") unless const_defined?(class_id)
90
+ return const_get(class_id)
197
91
  rescue MissingSourceFile => e
198
- # Convert the exception to a NameError only if the file we are looking for is the missing one.
199
- raise unless e.is_missing? file_name
92
+ # Re-raise the error if it does not concern the file we were trying to load.
93
+ raise unless e.is_missing? file_path
94
+
95
+ # Look for a directory in the load path that we ought to load.
96
+ if $LOAD_PATH.any? { |base| File.directory? "#{base}/#{file_path}" }
97
+ mod = Module.new
98
+ const_set class_id, mod # Create the new module
99
+ return mod
100
+ end
101
+
102
+ # Attempt to access the name from the parent, unless we don't have a valid
103
+ # parent, or the constant is already defined in the parent. If the latter
104
+ # is the case, then we are being queried via self::class_id, and we should
105
+ # avoid returning the constant from the parent if possible.
106
+ if parent && parent != self && ! parents.any? { |p| p.const_defined?(class_id) }
107
+ suppress(NameError) do
108
+ return parent.send(:const_missing, class_id)
109
+ end
110
+ end
111
+
200
112
  raise NameError.new("uninitialized constant #{class_id}").copy_blame!(e)
201
113
  end
202
114
  end
203
115
  end
204
116
 
117
+ class Class
118
+ def const_missing(class_id)
119
+ if [Object, Kernel].include?(self) || parent == self
120
+ super
121
+ else
122
+ parent.send :const_missing, class_id
123
+ end
124
+ end
125
+ end
126
+
205
127
  class Object #:nodoc:
206
128
  def load(file, *extras)
207
129
  super(file, *extras)
@@ -237,4 +159,4 @@ class Exception #:nodoc:
237
159
  @blamed_files = exc.blamed_files.clone
238
160
  self
239
161
  end
240
- end
162
+ end