How to dynamically alter inheritance in Ruby
Joshua has already given you a great list of alternatives, but to answer your question: You can't change the superclass of a class after the class has been created in ruby. That's simply not possible.
Ruby How to inherit from object given in constructor
You probably wish to use Decorator pattern, when all methods are proxied to given model:
class TestClass
def initialize(object)
@object = object
end
def method_missing(method, *args, &block)
@object.send(method, *args, &block)
end
end
v = TestClass.new([1,2,3,4,5,6,7,8,9])
v.each { |number| print number}
Dynamically create a class inherited from ActiveRecord?
Nailed it:
def create_arec(table_name, &block)
klass = Class.new(ActiveRecord::Base){self.table_name = table_name}
klass.class_eval &block
klass
end
thanks @phoet
How to dynamically declare subclass in Ruby?
When you refer to something
in Ruby, it first look up something
in local bindings, if it fails, it then look up self.something
. self
represents a context of the evaluation, and this context changes on class definition class C; self; end
, method definition class C; def m; self; end; end
, however, it won't change on block definition. The block captures the current self
at the point of block definition.
module Command
define :quit do
foo "bar" # self is Command, calls Command.foo by default
end
end
If you want to modify the self
context inside a block, you can use BasicObject.instance_eval
(or instance_exec
, class_eval
, class_exec
).
For your example, the block passed to define
should be evaluated under the self
context of an instance of the concrete command.
Here is an example. I added some mock method definition in class Command::Command
:
module Command
class Command
# remove this accessor if you want to make `name` readonly
attr_accessor :name
def exec(&block)
@exec = block
end
def foo(msg)
puts "FOO => #{msg}"
end
def run
@exec.call if @exec
end
end
def self.define(name, &block)
klass = Class.new(Command) do
define_method(:initialize) do
method(:name=).call(name) # it would be better to make it readonly
instance_eval(&block)
end
# readonly
# define_method(:name) { name }
end
::Command.const_set("Command_#{name}", klass)
end
define :quit do
foo "bar"
exec do
puts "EXEC => #{name}"
end
end
end
quit = Command::Command_quit.new #=> FOO => bar
quit.run #=> EXEC => quit
puts quit.class #=> Command::Command_quit
Ruby: How to dynamically create a subclass of an existing class?
Class.new
accepts a parameter, which will be the superclass.
Documentation: Class.new.
Ruby exception inheritance with dynamically generated classes
Ok, I'll try to help here :
First a module is not a class, it allows you to mix behaviour in a class. second see the following example :
module A
module B
module Error
def foobar
puts "foo"
end
end
end
end
class StandardError
include A::B::Error
end
StandardError.new.kind_of?(A::B::Error)
StandardError.new.kind_of?(A::B)
StandardError.included_modules #=> [A::B::Error,Kernel]
kind_of? tells you that yes, Error does possess All of A::B::Error behaviour (which is normal since it includes A::B::Error) however it does not include all the behaviour from A::B and therefore is not of the A::B kind. (duck typing)
Now there is a very good chance that ruby-aws reopens one of the superclass of NameError and includes Amazon::AWS:Error in there. (monkey patching)
You can find out programatically where the module is included in the hierarchy with the following :
class Class
def has_module?(module_ref)
if self.included_modules.include?(module_ref) and not self.superclass.included_modules.include?(module_ref)
puts self.name+" has module "+ module_ref.name
else
self.superclass.nil? ? false : self.superclass.has_module?(module_ref)
end
end
end
StandardError.has_module?(A::B::Error)
NameError.has_module?(A::B::Error)
Regarding your second question I can't see anything better than
begin
#do AWS error prone stuff
rescue Exception => e
if Amazon::AWS::Error.constants.include?(e.class.name)
#awsError
else
whatever
end
end
(edit -- above code doesn't work as is : name includes module prefix which is not the case of the constants arrays. You should definitely contact the lib maintainer the AWSError class looks more like a factory class to me :/ )
I don't have ruby-aws here and the caliban site is blocked by the company's firewall so I can't test much further.
Regarding the include : that might be the thing doing the monkey patching on the StandardError hierarchy. I am not sure anymore but most likely doing it at the root of a file outside every context is including the module on Object or on the Object metaclass. (this is what would happen in IRB, where the default context is Object, not sure about in a file)
from the pickaxe on modules :
A couple of points about the include statement before we go on. First, it has nothing to do with files. C programmers use a preprocessor directive called #include to insert the contents of one file into another during compilation. The Ruby include statement simply makes a reference to a named module. If that module is in a separate file, you must use require to drag that file in before using include.
(edit -- I can't seem to be able to comment using this browser :/ yay for locked in platforms)
Using dynamically created classes in a Single Table Inheritance mechanism
Your error message stands that 'FooObject' class cannot be located.
In your code, the dynamic generated class name shoudl be 'FooDynObject'.
Just check you don't have old test records in your database before loading DynObject.
@edit:
Another thing is also to know on which class you affect the dynamic class name.
class DynObject < ActiveRecord::Base
const_set 'FooDynObject', Class.new(DynObject)
end
Will result in DynObject::FooDynObject, and ActiveRecord won't be able to load it when it will see 'FooDynObject' type.
Personnally, I would do someting like
class DynObject < ActiveRecord::Base
Object.const_set 'FooDynObject', Class.new(DynObject)
end
Can you change the default inheritance of classes in Ruby?
Sure you could do this by modifying the relevant part of the Ruby source and recompiling Ruby:
VALUE
rb_define_class_id(ID id, VALUE super)
{
VALUE klass;
if (!super) super = rb_cObject; // <-- where the default is set
klass = rb_class_new(super);
// ...
But that’s a huge hassle and requires patching and running a custom Ruby and probably has a lot of gotchas and things that are hard-coded to assume Object
is the default.
And, on top of that, what’s the point? If you replace Object
with something else as the default superclass, every class—including those in Ruby core—will now inherit from this new default superclass. You could get the same effect (just without the different name) far more easily and without needing a custom Ruby by just changing Object
itself. That’s the beauty of being able to reopen classes! For example:
class Object
def foo
'bar!'
end
end
class A; end
A.new.foo #=> 'bar!'
If you wanted to be kind you might even just put all the relevant methods in an Entity
module instead of a class and then include
it into Object
.
Related Topics
In Rails - Is There a Rails Method to Convert Newlines to <Br>
Finding the Element of a Ruby Array with the Maximum Value for a Particular Attribute
Error: Failed to Build Gem Native Extension When Installing Rails on MAC Mountian Lion Os
Get Single Char from Console Immediately
Looping Through an Array with Step
Ruby 1.9 + Sinatra Incompatible Character Encodings: Ascii-8Bit and Utf-8
Why Do People Say That Ruby Is Slow
How to Sort an Array of Hashes by a Value in the Hash
How to Get the Current Time as 13-Digit Integer in Ruby
How to Make Instance Variables Private in Ruby
How to Check to See If My Array Includes an Object
Ruby Net::Http - Following 301 Redirects
Is There an Expect Equivalent Gem for Ruby
Irb History Not Working with Ruby 2.3.0