Skip to content

Commit

Permalink
Extract descendents a bit so it can take advantage of Rubinius' __sub…
Browse files Browse the repository at this point in the history
…classes__.
  • Loading branch information
Yehuda Katz authored and Yehuda Katz committed Dec 13, 2009
1 parent 25bb301 commit 0f7f90d
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 34 deletions.
6 changes: 5 additions & 1 deletion activesupport/lib/active_support/core_ext/class/removal.rb
Expand Up @@ -2,7 +2,11 @@
require 'active_support/core_ext/module/introspection' require 'active_support/core_ext/module/introspection'


class Class #:nodoc: class Class #:nodoc:


def reachable?
eval("defined?(::#{self}) && ::#{self}.equal?(self)")
end

# Unassociates the class with its subclasses and removes the subclasses # Unassociates the class with its subclasses and removes the subclasses
# themselves. # themselves.
# #
Expand Down
73 changes: 40 additions & 33 deletions activesupport/lib/active_support/core_ext/object/extending.rb
@@ -1,46 +1,53 @@
class Object class Class
def remove_subclasses_of(*superclasses) #:nodoc: # Rubinius
Class.remove_class(*subclasses_of(*superclasses)) if defined?(Class.__subclasses__)
end def descendents

begin
ObjectSpace.each_object(Class.new) {}

# Exclude this class unless it's a subclass of our supers and is defined.
# We check defined? in case we find a removed class that has yet to be
# garbage collected. This also fails for anonymous classes -- please
# submit a patch if you have a workaround.
def subclasses_of(*superclasses) #:nodoc:
subclasses = [] subclasses = []

__subclasses__.each {|k| subclasses << k; subclasses.concat k.descendents }
superclasses.each do |sup|
ObjectSpace.each_object(class << sup; self; end) do |k|
if k != sup && (k.name.blank? || eval("defined?(::#{k}) && ::#{k}.object_id == k.object_id"))
subclasses << k
end
end
end

subclasses subclasses
end end
rescue RuntimeError else
# JRuby and any implementations which cannot handle the objectspace traversal # MRI
# above fall back to this implementation begin
def subclasses_of(*superclasses) #:nodoc: ObjectSpace.each_object(Class.new) {}
subclasses = []


superclasses.each do |sup| def descendents
subclasses = []
ObjectSpace.each_object(class << self; self; end) do |k|
subclasses << k unless k == self
end
subclasses
end
# JRuby
rescue StandardError
def descendents
subclasses = []
ObjectSpace.each_object(Class) do |k| ObjectSpace.each_object(Class) do |k|
if superclasses.any? { |superclass| k < superclass } && subclasses << k if k < self
(k.name.blank? || eval("defined?(::#{k}) && ::#{k}.object_id == k.object_id"))
subclasses << k
end
end end
subclasses.uniq! subclasses.uniq!
subclasses
end end
subclasses
end end
end end
end

class Object
def remove_subclasses_of(*superclasses) #:nodoc:
Class.remove_class(*subclasses_of(*superclasses))
end

# Exclude this class unless it's a subclass of our supers and is defined.
# We check defined? in case we find a removed class that has yet to be
# garbage collected. This also fails for anonymous classes -- please
# submit a patch if you have a workaround.
def subclasses_of(*superclasses) #:nodoc:
subclasses = []
superclasses.each do |klass|
subclasses.concat klass.descendents.select {|k| k.name.blank? || k.reachable?}
end
subclasses
end


def extended_by #:nodoc: def extended_by #:nodoc:
ancestors = class << self; ancestors end ancestors = class << self; ancestors end
Expand Down

0 comments on commit 0f7f90d

Please sign in to comment.