Is there a possibility to include methods of a class?

B

Bernd

Hi all,
first of all: this list and you rock! I know that there is no multiple
inheritance, but you can use the concept of mixin.
However, I want to inherit my class another and "mixin" methods from
another class.
To be more precise,
I have a class that inherits another one (that comes from a library and
I do not want to change) and I want the methods of ActiveRecord::Base in
my class. Is there a way to do that (without copying and paste the whole
ActiveRecord::Base class and changing it to a module)?

Thanks in advance!
 
M

Mariusz Pietrzyk

Bernd pisze:
Hi all,
first of all: this list and you rock! I know that there is no multiple
inheritance, but you can use the concept of mixin.
However, I want to inherit my class another and "mixin" methods from
another class.
To be more precise,
I have a class that inherits another one (that comes from a library and
I do not want to change) and I want the methods of ActiveRecord::Base in
my class. Is there a way to do that (without copying and paste the whole
ActiveRecord::Base class and changing it to a module)?

Thanks in advance!
Yes, You can use evil ruby http://rubyforge.org/projects/evil
like this:
class Bar
include Array.as_module
end

b = Bar.new
b.push(1,2,3)
p b # => [1,2,3]

but this is bad resolve of your problem.
 
B

Brian Candler

Hi all,
first of all: this list and you rock! I know that there is no multiple
inheritance, but you can use the concept of mixin.
However, I want to inherit my class another and "mixin" methods from
another class.
To be more precise,
I have a class that inherits another one (that comes from a library and
I do not want to change) and I want the methods of ActiveRecord::Base in
my class. Is there a way to do that (without copying and paste the whole
ActiveRecord::Base class and changing it to a module)?

I would use delegation for one class or the other.

That is: define your class as

class Foo < ActiveRecord::Base
..
def initialize
@other = Library::Bar.new
end
end

Or vice versa, whichever makes more sense. And if you can't choose, then
delegate to both.

class FooDB < ActiveRecord::Base
.. more stuff
end

class Foo
def initialize(id)
@db = FooDB.find(id)
@lib = Library::Bar.new
end
end

Then the interface that Foo exposes to the world can pass some calls to @db,
some to @lib, or (the best news) can combine behaviours from both in
whichever way it likes.
 
E

Enrique Comba Riepenhausen

I would use delegation for one class or the other.

That is: define your class as

class Foo < ActiveRecord::Base
..
def initialize
@other = Library::Bar.new
end
end

Or vice versa, whichever makes more sense. And if you can't choose,
then
delegate to both.

class FooDB < ActiveRecord::Base
.. more stuff
end

class Foo
def initialize(id)
@db = FooDB.find(id)
@lib = Library::Bar.new
end
end

Then the interface that Foo exposes to the world can pass some
calls to @db,
some to @lib, or (the best news) can combine behaviours from both in
whichever way it likes.
That would actually be a so called Bridge Design Pattern... I like it
I think I will use it for Ruby Patterns ;)

Thanks Brian!
 
B

Bernd Burnt

Brian said:
I would use delegation for one class or the other.

That is: define your class as

class Foo < ActiveRecord::Base
..
def initialize
@other = Library::Bar.new
end
end

Or vice versa, whichever makes more sense. And if you can't choose, then
delegate to both.

class FooDB < ActiveRecord::Base
.. more stuff
end

class Foo
def initialize(id)
@db = FooDB.find(id)
@lib = Library::Bar.new
end
end

Then the interface that Foo exposes to the world can pass some calls to
@db,
some to @lib, or (the best news) can combine behaviours from both in
whichever way it likes.

This is the workaround I just had so far, and now I want to get rid of
it.

I have two classes:
class Myclass < ActiveRecord::Base
def self.find(number)
Anotherclass.find(number)
end

class Anotherclass < SAP4Rails::Base
def self.find(number)
do something
end

But this solution to me seems to be so un-ruby!

As SAP4Rails::Base does not have an explicit superclass, I wondered, if
there is some way to inject it dynamically a super class, because I need
some other methods from ActiveRecord in another application
I know that I could just alter the SAP4Rails class, but I want it in the
way, that you just need ActiveRecord, SAP4RAils and my piece of code.
 
B

Bernd Burnt

Mariusz said:
Bernd pisze:
Thanks in advance!
Yes, You can use evil ruby http://rubyforge.org/projects/evil
like this:
class Bar
include Array.as_module
end

b = Bar.new
b.push(1,2,3)
p b # => [1,2,3]

but this is bad resolve of your problem.

I think that would be the ruby way, following the principle of least
surprise. Unfortunately, neither Array nor ActiveRecord::Base do have an
"as_module" method :-(
 
B

Brian Candler

You seem to be doing something very strange in the above code. You are
replacing one of ActiveRecord::Base's most fundamental operations - load
from database by ID - with something which does something completely
different.

Are you also going to overwrite the save and update methods? In which case,
what functionality from ActiveRecord::Base do you actually want to keep?

I am guessing that SAP4Rails is some sort of remote-procedure call wrapper.
That is, an instance of SAP4Rails::Base represents an object on some remote
SAP server. If that's true, I don't see how it makes sense to try to mix
that with another object which represents a row in a local SQL database.

If Myclass represents something which may exist in the local database and/or
in the remote SAP system, then I'd very much go for delegation.

class MyDb < ActiveRecord::Base; end
class MySap < SAP4Rails::Base; end

class Myclass
def self.find(number)
@rec = MyDb.find(number)
@sap = MySap.find(number)
end
end

Then you are making it explicit that you are talking about two different
things, and you can implement useful operations (such as copy data from one
to the other)

P.S. Something which may be relevant as an example is ActiveResource.

This is a REST XML client library, which presents an API very similar to
ActiveRecord: e.g.

class Foo < ActiveResource::Base
self.site = "http://localhost:3000"
end

foo = Foo.find(2) # performs GET /foo/2.xml
foos = Foo.find:)all) # performs GET /foo.xml

But this doesn't re-use *any* of ActiveRecord. Whilst the interface is
similar in some ways, the underlying operations are very different.

ActiveRecord is very much a wrapper around a SQL database. Almost all the
operations you can perform ultimately get translated into calls on the
database connection for SELECT, UPDATE etc.

The other useful bits of ActiveRecord, like validations, are already mixins
in their own right. That is, they come pre-mixed into ActiveRecord::Base,
but you could mix them into your own class independently.

Regards,

Brian.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,756
Messages
2,569,540
Members
45,025
Latest member
KetoRushACVFitness

Latest Threads

Top