Is it possible to add class attributes (cattr_accessor) using a module?
If so could you give an example?
There is no “Ruby Way” to do this b/c Ruby’s module methods aren’t
inherited by classes that include them. Though I’ve asked for a way
man times now!
It might seem easy to glaze by this, thinking nothing of
cattr_accessor, a seemingly esoteric method since it’s not included in
core Ruby, but you will find it in both Rail’s Active Support and Ruby
Facets. And in fact, you’ve brought up a nice example of how this play
out b/c cattr_accessor and it’s ilk really don’t do anything very
esoteric under the hood. I’m going to layout what cattr_accessor
essentially does* so all can see this for what it is and what happens
when you try to REUSE structures of this nature.
For a class, it is simply:
class C
def self.m ; @m ; end
def self.m=(x) ; @m=x ; end
def m ; self.class.m ; end
def m=(x) ; self.class.m=x ; end
end
Hence
C.m = 10
C.m #=> 10
c = C.new
c.m #=> 10
c.m = 20
c.m #=> 20
C.m #=> 20
While you can subclass C with this functionality readily, eg ‘class N
< C’ works as you’d expect, try MODULARIZING this functionality. The
cooresponding
module M
def self.m ; @m ; end
def self.m=(x) ; @m=x ; end
def m ; self.class.m ; end
def m=(x) ; self.class.m=x ; end
end
does not work at all. You can’t include it in a class, you can’t
extend a class with it, nor both --it completely bombs. Feel free to
maniputlate the code as well --shame as that is, while you can get
closer, nothing completely works --there’s alwasy something wrong.
Only ugly meta-programming hacks will give the sought behavior --and
even then their are corner-case complications.
T.
- I’m using an instance var in this case rather than a class var for
simplicity sake, but it makes no difference to the problem itself.
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
TRANS wrote:
core Ruby, but you will find it in both Rail’s Active Support and Ruby
def self.m=(x) ; @m=x ; end
c.m = 20
c.m #=> 20
C.m #=> 20
On a total side note, why do you have cattr_* methods affecting instance
methods as well ?
class C
cattr_accessor :m
end
C.m = 10
c = C.new
puts c.m
=> 10
I would expect it to work for “C.m” and “C.m=” but not for “c.m” I would
expect:
NoMethodError: undefined method m' for #<C:0xb7d3103c> from /home/zdennis/.irbrc:4:in
method_missing’
from (irb):5
from :0
Perhaps I have wrong expectation of cattr_* . I am just asking at this
point though to better understand thought behind it.
Zach
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.1 (GNU/Linux)
Comment: Using GnuPG with Thunderbird - http://enigmail.mozdev.org
iD8DBQFEOoKXMyx0fW1d8G0RAmiHAJ9KTcVR3wogDAWDEkvYEYtBJAJKFACcC/9T
Rxg1qQquejXwvmS6hH57aB0=
=Eq3D
-----END PGP SIGNATURE-----
On Mon, Apr 10, 2006 at 11:58:43PM +0900, TRANS wrote:
} > Is it possible to add class attributes (cattr_accessor) using a
module?
} > If so could you give an example?
}
} There is no “Ruby Way” to do this b/c Ruby’s module methods aren’t
} inherited by classes that include them. Though I’ve asked for a way
} man times now!
[…]
} Only ugly meta-programming hacks will give the sought behavior --and
} even then their are corner-case complications.
Does this count as ugly meta-programming?
module M
def self.included(klass)
class << klass
attr_accessor :m
end
end
end
} T.
–Greg
On 4/10/06, Gregory S. [email protected] wrote:
} Only ugly meta-programming hacks will give the sought behavior --and
end
It is much prettier than the following ugly meta-programming, but I have
no
clue how it works !!!
Could you explain please?
Thx
Robert
} T.
–Greg
class Module
end
end
end
–
Deux choses sont infinies : l’univers et la bêtise humaine ; en ce qui
concerne l’univers, je n’en ai pas acquis la certitude absolue.
On Tue, Apr 11, 2006 at 02:19:30AM +0900, Robert D. wrote:
} On 4/10/06, Gregory S. [email protected] wrote:
} >
} > On Mon, Apr 10, 2006 at 11:58:43PM +0900, TRANS wrote:
} > } > Is it possible to add class attributes (cattr_accessor) using a
} > module?
} > } > If so could you give an example?
} > }
} > } There is no “Ruby Way” to do this b/c Ruby’s module methods aren’t
} > } inherited by classes that include them. Though I’ve asked for a
way
} > } man times now!
} > […]
} > } Only ugly meta-programming hacks will give the sought behavior
–and
} > } even then their are corner-case complications.
} >
} > Does this count as ugly meta-programming?
} >
} > module M
} > def self.included(klass)
} > class << klass
} > attr_accessor :m
} > end
} > end
} > end
}
} It is much prettier than the following ugly meta-programming, but I
have no
} clue how it works !!!
} Could you explain please?
The first thing to understand is that when you define a class, e.g.
class
Foo; … end, you are just setting a constant (Object::Foo, in this
case)
to a new instance of a Class. Just as you can add new methods to an
instance of any other kind of object with class << obj; … end, you can
add new methods to Foo. When a module is included, its self.included
method
is called with the Class instance it is being included into as an
argument.
I am defining self.included to add an attribute accessor to that Class
instance.
} Thx
} Robert
[…]
–Greg
On 4/10/06, Gregory S. [email protected] wrote:
} > } inherited by classes that include them. Though I’ve asked for a way
} > attr_accessor :m
Foo; … end, you are just setting a constant (Object::Foo, in this case)
to a new instance of a Class. Just as you can add new methods to an
instance of any other kind of object with class << obj; … end, you can
add new methods to Foo. When a module is included, its self.includedmethod
is called with the Class instance it is being included into as an
argument.
I see thank you about the explanation of that hook.
I am defining self.included to add an attribute accessor to that Class
instance.
No of course not, because it is equivalent to
class <<self
attr_accessor
end
which does not work.
} Thx
} Robert
[…]
–Greg
Robert
–
Deux choses sont infinies : l’univers et la bêtise humaine ; en ce qui
concerne l’univers, je n’en ai pas acquis la certitude absolue.
Does this count as ugly meta-programming?
module M
def self.included(klass)
class << klass
attr_accessor :m
end
end
end
Yep. That’s Ugly Hack #1. What wrong with Ugly Hack #1, you ask?
module N
include M
end
class C
include N
end
C.m
NoMethodError: undefined method `m’ for C:Class
T.
On Tue, Apr 11, 2006 at 06:19:23AM +0900, TRANS wrote:
} > Does this count as ugly meta-programming?
} >
} > module M
} > def self.included(klass)
} > class << klass
} > attr_accessor :m
} > end
} > end
} > end
}
} Yep. That’s Ugly Hack #1. What wrong with Ugly Hack #1, you ask?
}
} module N
} include M
} end
}
} class C
} include N
} end
}
} C.m
} NoMethodError: undefined method `m’ for C:Class
Yep, that’s an issue. Well, you can do this:
module M
OnIncludeProc = lambda do |klass|
if klass.class == Module
def klass.included(k)
OnIncludeProc.call(k)
end
else
class << klass
attr_accessor :m
end
end
end
OnIncludeProc.call(self)
end
Yes, it’s uglier. Yes, it conflicts with other #included tricks with
modules
that include the module. It does work, though.
} T.
–Greg