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
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.
} > 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 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!
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
} > 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?
Thx
Robert
} T.
--Greg
class Module
···
On 4/10/06, Gregory Seidman <gsslist+ruby@anthropohedron.net> wrote:
On Mon, Apr 10, 2006 at 11:58:43PM +0900, TRANS wrote:
def cattr( *names )
names.map{ |name| name.to_s }.each do
>name>
eval <<-EOEval
def self.#{name}; @#{name}; end
def self.#{name}=(x); @#{name}=x; end
EOEval
define_method( name ){ self.class.send( name ) }
define_method( name + "="){ |v| self.class.send(
name + "=", v ) }
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.
} > 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
···
On Tue, Apr 11, 2006 at 06:19:23AM +0900, TRANS 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 Tue, Apr 11, 2006 at 02:19:30AM +0900, Robert Dober wrote:
} On 4/10/06, Gregory Seidman <gsslist+ruby@anthropohedron.net> 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.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
···
On 4/10/06, Gregory Seidman <gsslist+ruby@anthropohedron.net> wrote:
On Tue, Apr 11, 2006 at 02:19:30AM +0900, Robert Dober wrote:
} On 4/10/06, Gregory Seidman <gsslist+ruby@anthropohedron.net> wrote:
--
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.