Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Ruby > Mixin module with class variables and class methods

Reply
Thread Tools

Mixin module with class variables and class methods

 
 
John Lane
Guest
Posts: n/a
 
      02-09-2010
Hello,

I am trying to learn ruby and am experimenting with a Mixin.

I have the following test module: http://pastie.org/816001

On line 17, the class variable @@name gives an error:

uninitialized class variable @@name in TestMixin::ClassMethods

I understand it is because that's in a module within the TestMixin
module and that the @@name class variable is created in the including
class which is in a separate scope.

Can someone advise how this should be written so that a class method in
a mixin can access a class variable created by the mixin ?

Instance methods work fine.

Thanks in advance.
--
Posted via http://www.ruby-forum.com/.

 
Reply With Quote
 
 
 
 
Brian Candler
Guest
Posts: n/a
 
      02-09-2010
John Lane wrote:
> Can someone advise how this should be written so that a class method in
> a mixin can access a class variable created by the mixin ?


Class variables are a pain, for exactly this sort of reason. Instance
variables of a class are much easier to handle and understand.

module TestMixin

def self.included(base)
p "TextMixin included in #{base}"
base.class_eval {
@name = "foobar"
}
base.extend ClassMethods
end

module ClassMethods

def name
@name
end

def name=(x)
@name=(x)
end

def class_method(str)
$stderr.puts "this is a class method in TestMixin #{str}"
$stderr.puts "the class variable is #{name}"
end

end

def name
self.class.name
end

def name=(x)
self.class.name=(x)
end

def instance_method
$stderr.puts "this is an instance method in TextMixin"
$stderr.puts "the class variable is #{name}"
end

end

class Foo

include TestMixin
class_method "foo"
def initialize
instance_method
end
end

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

 
Reply With Quote
 
 
 
 
John Lane
Guest
Posts: n/a
 
      02-09-2010
Brian Candler wrote:
> Class variables are a pain, for exactly this sort of reason.


Yes, I'm getting that feeling! My example test was just a simplified
model to understand how it worked and, in the case of the example, I can
see instance variables provide a solution.

What I'm trying to do is end up with a module mixed into a number of
classes that will each call a mixed-in class method to add values to a
class variable that will be a hash. Other instance methods in the mixin
will then make use of the information in the class variable hash.

So I think I really need a class variable.

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

 
Reply With Quote
 
Marnen Laibow-Koser
Guest
Posts: n/a
 
      02-09-2010
John Lane wrote:
> Brian Candler wrote:
>> Class variables are a pain, for exactly this sort of reason.

>
> Yes, I'm getting that feeling! My example test was just a simplified
> model to understand how it worked and, in the case of the example, I can
> see instance variables provide a solution.
>
> What I'm trying to do is end up with a module mixed into a number of
> classes that will each call a mixed-in class method to add values to a
> class variable that will be a hash. Other instance methods in the mixin
> will then make use of the information in the class variable hash.
>
> So I think I really need a class variable.


But you're probably wrong. What you probably want is a class instance
variable -- a weird concept, to be sure, until you recall that in Ruby
classes are instances of class Class. So:

class MyClass
@@class_var = 'foo'
@class_ivar = 'bar'

def self.class_method
puts @@class_var
puts @class_ivar
end
end

puts MyClass.class_method # prints 'foo' and 'bar'

In other words, class @instance variables act just like @@class
variables but without the problems.

Best,
--*
Marnen Laibow-Koser
http://www.marnen.org
http://www.velocityreviews.com/forums/(E-Mail Removed)
--
Posted via http://www.ruby-forum.com/.

 
Reply With Quote
 
John Lane
Guest
Posts: n/a
 
      02-09-2010
Marnen Laibow-Koser wrote:

>> So I think I really need a class variable.

>
> But you're probably wrong. What you probably want is a class instance
> variable -- a weird concept, to be sure, until you recall that in Ruby
> classes are instances of class Class.


snip

> In other words, class @instance variables act just like @@class
> variables but without the problems.
>


Ok so I get that point. I've now got working code, well almost. I mix
the module into multiple classes and each gets their own instance of the
variable, which is not what I need.

Here's the code: http://pastie.org/816654

There are three classes, One, Two and Three. Classes One and Two both
mix in the module. Class Three is a subclass of class Two and therefore
does not directly mix in the module.

The output i get demonstrates that each class gets its own instance of
the variable that I want to be shared across all three. Here is the
output:

TestMixin included in One
b added for class One : a b
c added for class One : a b c
TestMixin included in Two
d added for class Two : a d
e added for class Two : a d e
f added for class Three : f
g added for class Three : f g
the list for class One is a b c
the list for class Two is a d e
the list for class Three is f g

What I want to get is this:

TestMixin included in One
b added for class One : a b
c added for class One : a b c
TestMixin included in Two
d added for class Two : a b c d
e added for class Two : a b c d e
f added for class Three : a b c d e f
g added for class Three : a b c d e f g
the list for class One is a b c d e f g
the list for class Two is a b e d e f g
the list for class Three is a b c d e f g






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

 
Reply With Quote
 
Brian Candler
Guest
Posts: n/a
 
      02-09-2010
John Lane wrote:
> Ok so I get that point. I've now got working code, well almost. I mix
> the module into multiple classes and each gets their own instance of the
> variable, which is not what I need.


If everything which mixes in this module shares the same state, then you
can use a module instance variable.

If you want each subtree of related classes to share state, then one
option is to use a class instance variable and use the class hierarchy
to find where the value is held. Along the lines of:

def name
defined?(@name) ? @name : super
end

Another option is for each class to have its own @name instance
variable, but for them all to refer to the same object (a Hash in your
case); in self.included you initialize @name to the same as @name in the
parent class, if it exists.

But in your case class One and Two are unrelated but you want them to
share state anyway, so I'd go with a module instance variable. This
passes your test:

module TestMixin

@list = "a"

def self.list
@list
end

def self.included(base)
puts "TestMixin included in #{base}"

base.extend ClassMethods
end

module ClassMethods

def list
TestMixin.list
end

def class_method(str)
self.list << " #{str}"
puts "#{str} added for class #{self} : #{list}"
end

end

def list
TestMixin.list
end

def instance_method
puts "the list for class #{self.class} is #{list}"
end

end

class One

include TestMixin

class_method 'b'
class_method 'c'

end

class Two

include TestMixin

class_method 'd'
class_method 'e'

end

class Three < Two

class_method 'f'
class_method 'g'

end

one = One.new

two = Two.new

three = Three.new

one.instance_method

two.instance_method

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

 
Reply With Quote
 
John Lane
Guest
Posts: n/a
 
      02-09-2010
Thank you Brian, that sure does what I need. I will now go away and try
it in a real application. Thank you all - there's some useful techniques
highlighted in these answers.
--
Posted via http://www.ruby-forum.com/.

 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Module Mixin & Class Variables JP Billaud Ruby 0 03-06-2011 11:15 PM
Overriding methods in a class using a mixin James Coglan Ruby 4 11-15-2008 05:01 PM
Is there a way to find the class methods of a class, just like'methods' finds the instance methods? Kenneth McDonald Ruby 5 09-26-2008 03:09 PM
Mixin of class methods? Michael Roth Ruby 8 09-26-2005 08:00 AM
Extract methods in a class to mixin? Florian Frank Ruby 0 09-10-2003 01:20 PM



Advertisments