mirror of
https://github.com/mistergibson/gxg-web-client.git
synced 2026-08-15 03:26:00 -07:00
797 lines
20 KiB
Ruby
797 lines
20 KiB
Ruby
##
|
|
# Some terminology notes:
|
|
#
|
|
# [Encloser] The Class or Module inside which this one is defined or, in the
|
|
# event we are at top-level, Object.
|
|
#
|
|
# [Direct superclass] Whatever is next in the chain of superclass invocations.
|
|
# This may be either an included Module, a Class or nil.
|
|
#
|
|
# [Superclass] The real semantic superclass and thus only applies to Class
|
|
# objects.
|
|
|
|
class Module
|
|
|
|
attr_reader :constant_table
|
|
attr_writer :method_table
|
|
|
|
private :included
|
|
|
|
def self.nesting
|
|
scope = Rubinius::LexicalScope.of_sender
|
|
nesting = []
|
|
while scope and scope.module != Object
|
|
nesting << scope.module
|
|
scope = scope.parent
|
|
end
|
|
nesting
|
|
end
|
|
|
|
def initialize(&block)
|
|
# The method and constants tables are created and setup
|
|
# by Class and Module allocate.
|
|
module_eval(&block) if block
|
|
end
|
|
|
|
private :initialize
|
|
|
|
def deprecate_constant(*syms)
|
|
# no-op for now
|
|
end
|
|
|
|
def const_get(name, inherit=true)
|
|
Rubinius::Type.const_get self, name, inherit
|
|
end
|
|
|
|
def const_defined?(name, inherit=true)
|
|
c = Rubinius::Type.const_get self, name, inherit, false
|
|
return c.equal?(undefined) ? false : true
|
|
end
|
|
|
|
def attr(*attributes)
|
|
vis = Rubinius::VariableScope.of_sender.method_visibility
|
|
|
|
if attributes.size == 2 && (attributes.last.is_a?(TrueClass) || attributes.last.is_a?(FalseClass))
|
|
name = attributes.first
|
|
Rubinius.add_reader name, self, vis
|
|
Rubinius.add_writer name, self, vis if attributes.last
|
|
else
|
|
attributes.each do |name|
|
|
if name.is_a?(Symbol) || (name.respond_to?(:to_str) && name.to_str.is_a?(String) && !name.to_str.empty?)
|
|
Rubinius.add_reader(name, self, vis)
|
|
else
|
|
raise TypeError, "#{name.inspect} is not a symbol"
|
|
end
|
|
end
|
|
end
|
|
|
|
return nil
|
|
end
|
|
|
|
private :attr
|
|
|
|
# Install a new Autoload object into the constants table
|
|
# See core/autoload.rb
|
|
def autoload(name, path)
|
|
path = Rubinius::Type.coerce_to_path(path)
|
|
|
|
raise ArgumentError, "empty file name" if path.empty?
|
|
|
|
name = Rubinius::Type.coerce_to_constant_name name
|
|
|
|
Rubinius.check_frozen
|
|
|
|
if entry = @constant_table.lookup(name)
|
|
if entry.constant.kind_of? Autoload
|
|
# If there is already an Autoload here, just change the path to
|
|
# autoload!
|
|
entry.constant.set_path(path)
|
|
else
|
|
# Trying to register an autoload for a constant that already exists,
|
|
# ignore the request entirely.
|
|
end
|
|
|
|
return
|
|
end
|
|
|
|
autoload_constant = Autoload.new(name, self, path)
|
|
constant_table.store(name, autoload_constant, :public)
|
|
if self == Kernel
|
|
Object.singleton_class.constant_table.store(name, autoload_constant, :public)
|
|
end
|
|
|
|
Rubinius.inc_global_serial
|
|
return nil
|
|
end
|
|
|
|
def constants(all=undefined)
|
|
tbl = Rubinius::LookupTable.new
|
|
|
|
@constant_table.each do |name, constant, visibility|
|
|
tbl[name] = true unless visibility == :private
|
|
end
|
|
|
|
if all
|
|
current = self.direct_superclass
|
|
|
|
while current and current != Object
|
|
current.constant_table.each do |name, constant, visibility|
|
|
tbl[name] = true unless visibility == :private
|
|
end
|
|
|
|
current = current.direct_superclass
|
|
end
|
|
end
|
|
|
|
# special case: Module.constants returns Object's constants
|
|
if self.equal?(Module) && undefined.equal?(all)
|
|
Object.constant_table.each do |name, constant, visibility|
|
|
tbl[name] = true unless visibility == :private
|
|
end
|
|
end
|
|
|
|
tbl.keys
|
|
end
|
|
|
|
#--
|
|
# These have to be aliases, not methods that call instance eval, because we
|
|
# need to pull in the binding of the person that calls them, not the
|
|
# intermediate binding.
|
|
#++
|
|
|
|
def module_eval(string=undefined, filename="(eval)", line=1, &prc)
|
|
# we have a custom version with the prc, rather than using instance_exec
|
|
# so that we can setup the LexicalScope properly.
|
|
if prc
|
|
unless undefined.equal?(string)
|
|
raise ArgumentError, "cannot pass both string and proc"
|
|
end
|
|
|
|
# Return a copy of the BlockEnvironment with the receiver set to self
|
|
env = prc.block
|
|
lexical_scope = env.repoint_scope self
|
|
return env.call_under(self, lexical_scope, true, self)
|
|
elsif undefined.equal?(string)
|
|
raise ArgumentError, 'block not supplied'
|
|
end
|
|
|
|
string = StringValue(string)
|
|
filename = StringValue(filename)
|
|
|
|
# The constantscope of a module_eval CM is the receiver of module_eval
|
|
cs = Rubinius::LexicalScope.new self, Rubinius::LexicalScope.of_sender
|
|
|
|
binding = Binding.setup(Rubinius::VariableScope.of_sender,
|
|
Rubinius::CompiledCode.of_sender,
|
|
cs)
|
|
|
|
c = Rubinius::ToolSets::Runtime::Compiler
|
|
be = c.construct_block string, binding, filename, line
|
|
|
|
be.call_under self, cs, true, self
|
|
end
|
|
|
|
alias_method :class_eval, :module_eval
|
|
|
|
def private_constant(*names)
|
|
names = names.map(&:to_sym)
|
|
unknown_constants = names - @constant_table.keys
|
|
if unknown_constants.size > 0
|
|
raise NameError, "#{unknown_constants.size > 1 ? 'Constants' : 'Constant'} #{unknown_constants.map{|e| "#{name}::#{e}"}.join(', ')} undefined"
|
|
end
|
|
names.each do |name|
|
|
entry = @constant_table.lookup(name)
|
|
entry.visibility = :private
|
|
end
|
|
end
|
|
|
|
def public_constant(*names)
|
|
names = names.map(&:to_sym)
|
|
unknown_constants = names - @constant_table.keys
|
|
if unknown_constants.size > 0
|
|
raise NameError, "#{unknown_constants.size > 1 ? 'Constants' : 'Constant'} #{unknown_constants.map{|e| "#{name}::#{e}"}.join(', ')} undefined"
|
|
end
|
|
names.each do |name|
|
|
entry = @constant_table.lookup(name)
|
|
entry.visibility = :public
|
|
end
|
|
end
|
|
|
|
##
|
|
# Returns an UnboundMethod corresponding to the given name. The name will be
|
|
# searched for in this Module as well as any included Modules or
|
|
# superclasses. The UnboundMethod is populated with the method name and the
|
|
# Module that the method was located in.
|
|
#
|
|
# Raises a TypeError if the given name.to_sym fails and a NameError if the
|
|
# name cannot be located.
|
|
|
|
def instance_method(name)
|
|
name = Rubinius::Type.coerce_to_symbol name
|
|
|
|
mod = self
|
|
while mod
|
|
if mod == mod.origin && entry = mod.method_table.lookup(name)
|
|
break if entry.visibility == :undef
|
|
|
|
if meth = entry.get_method
|
|
if meth.kind_of? Rubinius::Alias
|
|
meth = meth.original_exec
|
|
end
|
|
|
|
mod = mod.module if mod.class == Rubinius::IncludedModule
|
|
|
|
return UnboundMethod.new(mod, meth, self, name)
|
|
end
|
|
end
|
|
|
|
mod = mod.direct_superclass
|
|
end
|
|
|
|
raise NameError.new("undefined method `#{name}' for #{self}", name)
|
|
end
|
|
|
|
def public_instance_method(name)
|
|
name = Rubinius::Type.coerce_to_symbol name
|
|
|
|
mod = self
|
|
while mod
|
|
if mod == mod.origin && entry = mod.method_table.lookup(name)
|
|
vis = entry.visibility
|
|
break if vis == :undef
|
|
|
|
if meth = entry.method
|
|
if meth.kind_of? Rubinius::Alias
|
|
meth = meth.original_exec
|
|
end
|
|
|
|
mod = mod.module if mod.class == Rubinius::IncludedModule
|
|
|
|
if vis == :public
|
|
return UnboundMethod.new(mod, meth, self, name)
|
|
else
|
|
raise NameError.new("method `#{name}' for module `#{self}' is #{vis}", name)
|
|
end
|
|
end
|
|
end
|
|
|
|
mod = mod.direct_superclass
|
|
end
|
|
|
|
raise NameError.new("undefined method `#{name}' for #{self}", name)
|
|
end
|
|
|
|
def visibility_for_aliased_method(new_name, current_name_visibility)
|
|
special_methods = [
|
|
:initialize,
|
|
:initialize_copy,
|
|
:initialize_clone,
|
|
:initialize_dup,
|
|
:respond_to_missing?
|
|
]
|
|
|
|
if special_methods.include?(new_name)
|
|
:private
|
|
else
|
|
current_name_visibility
|
|
end
|
|
end
|
|
private :visibility_for_aliased_method
|
|
|
|
def verify_class_variable_name(name)
|
|
if name.kind_of? Symbol
|
|
return name if name.is_cvar?
|
|
raise NameError, "#{name} is not an allowed class variable name"
|
|
end
|
|
|
|
name = StringValue(name).to_sym
|
|
unless name.is_cvar?
|
|
raise NameError, "#{name} is not an allowed class variable name"
|
|
end
|
|
name
|
|
end
|
|
private :verify_class_variable_name
|
|
|
|
def class_variable_set(name, val)
|
|
Rubinius.primitive :module_cvar_set
|
|
|
|
class_variable_set verify_class_variable_name(name), val
|
|
end
|
|
|
|
def class_variable_get(name)
|
|
Rubinius.primitive :module_cvar_get
|
|
|
|
class_variable_get verify_class_variable_name(name)
|
|
end
|
|
|
|
def class_variable_defined?(name)
|
|
Rubinius.primitive :module_cvar_defined
|
|
|
|
class_variable_defined? verify_class_variable_name(name)
|
|
end
|
|
|
|
def remove_class_variable(name)
|
|
Rubinius.primitive :module_cvar_remove
|
|
|
|
remove_class_variable verify_class_variable_name(name)
|
|
end
|
|
|
|
def __class_variables__
|
|
Rubinius.primitive :module_class_variables
|
|
|
|
raise PrimitiveFailure, "Module#__class_variables__ primitive failed"
|
|
end
|
|
alias_method :class_variables, :__class_variables__
|
|
|
|
def lookup_method(sym, check_object_too=true, trim_im=true)
|
|
mod = self
|
|
|
|
while mod
|
|
if mod == mod.origin && entry = mod.method_table.lookup(sym.to_sym)
|
|
mod = mod.module if trim_im and mod.kind_of? Rubinius::IncludedModule
|
|
return [mod, entry]
|
|
end
|
|
|
|
mod = mod.direct_superclass
|
|
end
|
|
|
|
# Optionally also search Object (and everything included in Object);
|
|
# this lets a module alias methods on Object or Kernel.
|
|
if check_object_too and instance_of?(Module)
|
|
return Object.lookup_method(sym, true, trim_im)
|
|
end
|
|
end
|
|
|
|
def ancestors
|
|
out = []
|
|
Rubinius::Type.each_ancestor(self) { |mod| out << mod }
|
|
return out
|
|
end
|
|
|
|
def public_method_defined?(sym)
|
|
sym = Rubinius::Type.coerce_to_reflection_name(sym)
|
|
mod, meth = lookup_method(sym, false)
|
|
meth ? meth.public? : false
|
|
end
|
|
|
|
def private_method_defined?(sym)
|
|
sym = Rubinius::Type.coerce_to_reflection_name(sym)
|
|
mod, meth = lookup_method(sym, false)
|
|
meth ? meth.private? : false
|
|
end
|
|
|
|
def protected_method_defined?(sym)
|
|
sym = Rubinius::Type.coerce_to_reflection_name(sym)
|
|
mod, meth = lookup_method(sym, false)
|
|
meth ? meth.protected? : false
|
|
end
|
|
|
|
def method_defined?(sym)
|
|
sym = Rubinius::Type.coerce_to_symbol(sym)
|
|
mod, meth = lookup_method(sym, false)
|
|
meth ? meth.public? || meth.protected? : false
|
|
end
|
|
|
|
def instance_methods(all=true)
|
|
ary = []
|
|
if all
|
|
table = Rubinius::LookupTable.new
|
|
|
|
mod = self
|
|
|
|
while mod
|
|
mod.method_table.each do |name, obj, vis|
|
|
unless table.key?(name)
|
|
table[name] = true
|
|
ary << name if vis == :public or vis == :protected
|
|
end
|
|
end
|
|
|
|
mod = mod.direct_superclass
|
|
end
|
|
else
|
|
method_table.each do |name, obj, vis|
|
|
ary << name if vis == :public or vis == :protected
|
|
end
|
|
end
|
|
|
|
ary
|
|
end
|
|
|
|
def public_instance_methods(all=true)
|
|
filter_methods(:public, all)
|
|
end
|
|
|
|
def private_instance_methods(all=true)
|
|
filter_methods(:private, all)
|
|
end
|
|
|
|
def protected_instance_methods(all=true)
|
|
filter_methods(:protected, all)
|
|
end
|
|
|
|
def filter_methods(filter, all)
|
|
ary = []
|
|
if all and self.direct_superclass
|
|
table = Rubinius::LookupTable.new
|
|
mod = self
|
|
|
|
while mod
|
|
mod.method_table.each do |name, obj, vis|
|
|
unless table.key?(name)
|
|
table[name] = true
|
|
ary << name if vis == filter
|
|
end
|
|
end
|
|
|
|
mod = mod.direct_superclass
|
|
end
|
|
else
|
|
method_table.each do |name, obj, vis|
|
|
ary << name if vis == filter
|
|
end
|
|
end
|
|
|
|
ary
|
|
end
|
|
|
|
private :filter_methods
|
|
|
|
def define_method(name, meth = undefined, &prc)
|
|
if undefined.equal?(meth) and !block_given?
|
|
raise ArgumentError, "tried to create Proc object without a block"
|
|
end
|
|
|
|
meth = prc if undefined.equal?(meth)
|
|
|
|
name = Rubinius::Type.coerce_to_symbol name
|
|
|
|
if meth.respond_to?(:for_define_method)
|
|
code, scope = meth.for_define_method(name, self.class)
|
|
else
|
|
raise TypeError, "wrong argument type #{meth.class} (expected Proc/Method)"
|
|
end
|
|
|
|
Rubinius.add_method name, code, self, scope, 0, :public
|
|
|
|
name
|
|
end
|
|
|
|
private :define_method
|
|
|
|
def thunk_method(name, value)
|
|
thunk = Rubinius::Thunk.new(value)
|
|
name = Rubinius::Type.coerce_to_symbol name
|
|
Rubinius.add_method name, thunk, self, nil, 0, :public
|
|
|
|
name
|
|
end
|
|
|
|
def extend_object(obj)
|
|
include_into Rubinius::Type.object_singleton_class(obj)
|
|
end
|
|
private :extend_object
|
|
|
|
def include?(mod)
|
|
if !mod.kind_of?(Module) or mod.kind_of?(Class)
|
|
raise TypeError, "wrong argument type #{mod.class} (expected Module)"
|
|
end
|
|
|
|
return false if self.equal?(mod)
|
|
|
|
Rubinius::Type.each_ancestor(self) { |m| return true if mod.equal?(m) }
|
|
|
|
false
|
|
end
|
|
|
|
def included_modules
|
|
out = []
|
|
sup = direct_superclass
|
|
|
|
while sup
|
|
if sup.class == Rubinius::IncludedModule
|
|
out << sup.module
|
|
end
|
|
|
|
sup = sup.direct_superclass
|
|
end
|
|
|
|
out
|
|
end
|
|
|
|
def set_visibility(meth, vis, where=nil)
|
|
name = Rubinius::Type.coerce_to_symbol(meth)
|
|
|
|
Rubinius::VM.reset_method_cache self, name
|
|
|
|
vis = vis.to_sym
|
|
|
|
if entry = @method_table.lookup(name)
|
|
entry.visibility = vis
|
|
elsif lookup_method(name)
|
|
@method_table.store name, nil, nil, nil, 0, vis
|
|
else
|
|
raise NameError.new("Unknown #{where}method '#{name}' to make #{vis.to_s} (#{self})", name)
|
|
end
|
|
|
|
return name
|
|
end
|
|
|
|
def set_class_visibility(meth, vis)
|
|
Rubinius::Type.object_singleton_class(self).set_visibility meth, vis, "class "
|
|
end
|
|
private :set_class_visibility
|
|
|
|
def module_exec(*args, &prc)
|
|
raise LocalJumpError, "Missing block" unless block_given?
|
|
|
|
env = prc.block
|
|
lexical_scope = env.repoint_scope self
|
|
return env.call_under(self, lexical_scope, true, *args)
|
|
end
|
|
alias_method :class_exec, :module_exec
|
|
|
|
##
|
|
# Return the named constant enclosed in this Module.
|
|
#
|
|
# Included Modules and, for Class objects, superclasses are also searched.
|
|
# Modules will in addition look in Object. The name is attempted to convert
|
|
# using #to_str. If the constant is not found, #const_missing is called
|
|
# with the name.
|
|
|
|
def const_missing(name)
|
|
unless self == Object
|
|
mod_name = "#{Rubinius::Type.module_name self}::"
|
|
end
|
|
case Rubinius.constant_missing_reason
|
|
when :private
|
|
msg = "Private constant: #{mod_name}#{name}"
|
|
else
|
|
msg = "Missing or uninitialized constant: #{mod_name}#{name}"
|
|
end
|
|
|
|
raise NameError.new(msg, name)
|
|
end
|
|
|
|
def <(other)
|
|
unless other.kind_of? Module
|
|
raise TypeError, "compared with non class/module"
|
|
end
|
|
|
|
# We're not an ancestor of ourself
|
|
return false if self.equal? other
|
|
|
|
Rubinius::Type.each_ancestor(self) { |mod| return true if mod.equal?(other) }
|
|
Rubinius::Type.each_ancestor(other) { |mod| return false if mod.equal?(self) }
|
|
|
|
nil
|
|
end
|
|
|
|
def <=(other)
|
|
equal?(other) || (self < other)
|
|
end
|
|
|
|
def >(other)
|
|
unless other.kind_of? Module
|
|
raise TypeError, "compared with non class/module"
|
|
end
|
|
other < self
|
|
end
|
|
|
|
def >=(other)
|
|
equal?(other) || (self > other)
|
|
end
|
|
|
|
def <=>(other)
|
|
return 0 if self.equal? other
|
|
return nil unless other.kind_of? Module
|
|
|
|
lt = self < other
|
|
return nil if lt.nil?
|
|
lt ? -1 : 1
|
|
end
|
|
|
|
def ===(inst)
|
|
Rubinius::Type.object_kind_of?(inst, self)
|
|
end
|
|
|
|
# Is an autoload trigger defined for the given path?
|
|
def autoload?(name)
|
|
name = name.to_sym
|
|
entry = constant_table.lookup(name)
|
|
return unless entry
|
|
trigger = entry.constant
|
|
return unless trigger && trigger.kind_of?(Autoload)
|
|
trigger.path
|
|
end
|
|
|
|
def remove_const(name)
|
|
unless name.kind_of? Symbol
|
|
name = StringValue name
|
|
|
|
unless Rubinius::CType.isupper name.getbyte(0)
|
|
raise NameError, "constant names must begin with a capital letter: #{name}"
|
|
end
|
|
end
|
|
|
|
sym = name.to_sym
|
|
unless constant_table.has_name?(sym)
|
|
mod_name = Rubinius::Type.module_name self
|
|
raise NameError, "Missing or uninitialized constant: #{mod_name}::#{name}"
|
|
end
|
|
|
|
val = constant_table.delete(sym)
|
|
Rubinius.inc_global_serial
|
|
|
|
# Silly API compact. Shield Autoload instances
|
|
return nil if Rubinius::Type.object_kind_of?(val, Autoload)
|
|
val
|
|
end
|
|
|
|
private :remove_const
|
|
|
|
def extended(name)
|
|
end
|
|
|
|
private :extended
|
|
|
|
def method_added(name)
|
|
end
|
|
|
|
private :method_added
|
|
|
|
def method_removed(name)
|
|
end
|
|
|
|
private :method_removed
|
|
|
|
def method_undefined(name)
|
|
end
|
|
|
|
private :method_undefined
|
|
|
|
def initialize_copy(other)
|
|
# If the method table is already different, we already
|
|
# initialized this module.
|
|
unless @method_table == other.method_table
|
|
raise TypeError, "already initialized module"
|
|
end
|
|
|
|
@method_table = other.method_table.dup
|
|
|
|
sc_s = Rubinius::Type.object_singleton_class self
|
|
sc_o = Rubinius::Type.object_singleton_class other
|
|
|
|
sc_s.method_table = sc_o.method_table.dup
|
|
sc_s.superclass = sc_o.direct_superclass
|
|
|
|
@constant_table = Rubinius::ConstantTable.new
|
|
|
|
other.constant_table.each do |name, val|
|
|
if val.kind_of? Autoload
|
|
val = Autoload.new(val.name, self, val.path)
|
|
end
|
|
|
|
@constant_table.store(name, val, :public)
|
|
end
|
|
|
|
if other == other.origin
|
|
@origin = self
|
|
else
|
|
@origin = other.origin.dup
|
|
end
|
|
|
|
self
|
|
end
|
|
|
|
private :initialize_copy
|
|
|
|
def add_ivars(code)
|
|
case code
|
|
when Rubinius::CompiledCode
|
|
new_ivars = code.literals.select { |l| l.kind_of?(Symbol) and l.is_ivar? }
|
|
return if new_ivars.empty?
|
|
|
|
if @seen_ivars
|
|
new_ivars.each do |x|
|
|
unless @seen_ivars.include?(x)
|
|
@seen_ivars << x
|
|
end
|
|
end
|
|
else
|
|
@seen_ivars = new_ivars
|
|
end
|
|
when Rubinius::AccessVariable
|
|
if @seen_ivars
|
|
unless @seen_ivars.include?(code.name)
|
|
@seen_ivars << code.name
|
|
end
|
|
else
|
|
@seen_ivars = [code.name]
|
|
end
|
|
else
|
|
raise "Unknown type of method to learn ivars - #{code.class}"
|
|
end
|
|
end
|
|
|
|
def dynamic_method(name, file="(dynamic)", line=1)
|
|
g = Rubinius::ToolSets::Runtime::Generator.new
|
|
g.name = name.to_sym
|
|
g.file = file.to_sym
|
|
g.set_line Integer(line)
|
|
|
|
yield g
|
|
|
|
g.close
|
|
|
|
g.use_detected
|
|
g.encode
|
|
|
|
code = g.package Rubinius::CompiledCode
|
|
|
|
scope = Rubinius::LexicalScope.new(self, Rubinius::LexicalScope.new(Object))
|
|
code.scope = scope
|
|
|
|
Rubinius.add_method name, code, self, scope, 0, :public
|
|
|
|
return code
|
|
end
|
|
|
|
def freeze
|
|
@method_table.freeze
|
|
@constant_table.freeze
|
|
super
|
|
end
|
|
|
|
def origin= origin
|
|
@origin = origin
|
|
end
|
|
|
|
def prepended(mod); end
|
|
private :prepended
|
|
|
|
def prepend(*modules)
|
|
modules.reverse_each do |mod|
|
|
if !mod.kind_of?(Module) or mod.kind_of?(Class)
|
|
raise TypeError, "wrong argument type #{mod.class} (expected Module)"
|
|
end
|
|
|
|
Rubinius.privately do
|
|
mod.prepend_features self
|
|
end
|
|
|
|
Rubinius.privately do
|
|
mod.prepended self
|
|
end
|
|
end
|
|
self
|
|
end
|
|
|
|
def prepend_features(klass)
|
|
unless klass.kind_of? Module
|
|
raise TypeError, "invalid argument class #{klass.class}, expected Module"
|
|
end
|
|
|
|
if kind_of? Class
|
|
raise TypeError, "invalid receiver class #{__class__}, expected Module"
|
|
end
|
|
|
|
if klass == klass.origin
|
|
im = Rubinius::IncludedModule.new(klass)
|
|
im.superclass = klass.direct_superclass
|
|
klass.superclass = im
|
|
klass.origin = im
|
|
klass.method_table.each do |meth, obj, vis|
|
|
Rubinius::VM.reset_method_cache klass, meth
|
|
end
|
|
end
|
|
Rubinius::Type.include_modules_from(self, klass)
|
|
Rubinius::Type.infect(klass, self)
|
|
self
|
|
end
|
|
private :prepend_features
|
|
|
|
def singleton_class?
|
|
!!Rubinius::Type.singleton_class_object(self)
|
|
end
|
|
end
|