Is there a possibility to include methods of a class?

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!

···

--
Posted via http://www.ruby-forum.com/.

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.

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.

···

On Fri, May 11, 2007 at 10:29:01PM +0900, Bernd wrote:

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)?

Mariusz Pietrzyk wrote:

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 just thought, if there is a possibility to do dynamic inheritance like

def some_method
Some_class < ActiveRecord::Base
end

···

--
Posted via http://www.ruby-forum.com/\.

That would actually be a so called Bridge Design Pattern... I like it I think I will use it for Ruby Patterns :wink:

Thanks Brian!

···

On 11 May 2007, at 17:14, Brian Candler wrote:

On Fri, May 11, 2007 at 10:29:01PM +0900, Bernd wrote:

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.

Brian Candler wrote:

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.

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.

···

On Fri, May 11, 2007 at 10:29:01PM +0900, Bernd wrote:

--
Posted via http://www.ruby-forum.com/\.

Mariusz Pietrzyk wrote:

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 :frowning:

···

--
Posted via http://www.ruby-forum.com/\.

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)

Regards,

Brian.

···

On Sat, May 12, 2007 at 12:30:00AM +0900, Bernd Burnt wrote:

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!

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.

···

On Sat, May 12, 2007 at 01:19:26AM +0900, Brian Candler wrote:

On Sat, May 12, 2007 at 12:30:00AM +0900, Bernd Burnt wrote:
> 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!

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)