extending.rb 1.6 KB
Newer Older
1 2
require 'active_support/core_ext/class/removal'

3 4 5 6
class Class
  # Rubinius
  if defined?(Class.__subclasses__)
    def descendents
7
      subclasses = []
8
      __subclasses__.each {|k| subclasses << k; subclasses.concat k.descendents }
9
      subclasses
10
    end
11 12 13 14
  else
    # MRI
    begin
      ObjectSpace.each_object(Class.new) {}
15

16 17 18 19 20 21 22 23 24 25 26
      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 = []
27
        ObjectSpace.each_object(Class) do |k|
28
          subclasses << k if k < self
29 30
        end
        subclasses.uniq!
31
        subclasses
32 33
      end
    end
34
  end
35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
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
53

54
  def extended_by #:nodoc:
55 56 57
    ancestors = class << self; ancestors end
    ancestors.select { |mod| mod.class == Module } - [ Object, Kernel ]
  end
58

59
  def extend_with_included_modules_from(object) #:nodoc:
60 61
    object.extended_by.each { |mod| extend mod }
  end
62
end