it just ducks into the singleton class of whatever object you use it on. in
the case the object is a class and it just so happens that class methods are
singleton methods of classes so you end up defining class methods this way
Ok.
[...]
using this construct in classes just so happens to work nicely since singleton
methods of classes are also know as 'class methods' for instances of that
class.
Ok, just making sure.
there's no need really - but it allows you to do things like this that cannot
be done otherwise:
class C
class << self
attr 'a'
attr 'b'
alias c a
alias d b
end
attr 'a'
attr 'b'
end
so now we have instance method 'a' and 'b' and class methods 'a' and 'b' and
aliases for those two class methods 'c' and 'd' respectively. because the
'attr' and 'alias' calls are in class singleton scope here it works.
Yeah, that's what I'll be using, since it should work just fine for my
purposes, but I think it's a touch obfuscated. Of course, I've already
admitted to not fully grokking the 'class << self' syntax, so that
doesn't help.
if they don't it's doubtful that they are real subclasses. most OO theory
would suggest that any subclass (subtype) is a specialzation only of the
base class - eg it should only ADD new behaviour. be definition that means
any existing class vars should be inherited. if you aren't inheriting class
vars (and therefore clobbering them) you might want to look at other code
sharing methods like mixins since you may not have a true inheritence
hierarchy.
I agree, I probably don't have "valid" heirarchies. I would probably
describe most of my heirarchies with a type at the type, and then
instances of that type below it, and then instances of those instances
below that. For instance (similar to the other example I just sent):
class Type
class << self
attr_accessor :params
end
# class method
def self.each
unless defined? @params
raise "@params not defined for %s" % self
end
@params.each { |param| yield param }
end
def =(param,value)
@params[param] = value
end
def (param)
@params[param]
end
# instance method; notice this is a hash, not an array
def each
unless defined? @params
raise "@params not defined for %s" % self
end
@params.each { |param,value| yield param, value }
end
def initialize(hash)
@params = {}
self.class.each { |param|
if hash.include?(param)
self[param] = value
hash.delete(param)
else
raise "%s requires parameter %s" %
[self.class, param]
end
}
if hash.length > 0
raise "Unknown parameter(s) '%s'" % hash.keys.join(" ")
end
end
end
class Sub < Base
@params = [:name, :address]
end
instance = Sub.new(
:name => "Luke",
:address => "42 Earth"
)
I really feel like this is a type at the top, with an instance of the
Base class below that, and then an instance of the instance below that.
I expect that I'm being retarded here, and there's some significantly
better way of doing this, but it's working pretty darn well for me, so
I'm sticking with it unless someone else has a better idea.
of course most of my inheritence hierarchies aren't technically 'valid' either
Not that I'd know how to tell...
you have that already
class C
class << self
attr 'foo'
end
end
Yah, and that's what I'll be using now that I (basically) understand it,
but I still think it's pretty obfuscated.
> I'll check into 'traits', but I don't think I can use it for this
> project, since I have to mostly stick to libs that are part of the
> standard library.
it's pure ruby so you can always just cut and paste it.
The above is sufficient for now, but we'll see.
Thanks,
Luke
···
On Tue, 12 Jul 2005, Ara.T.Howard wrote:
--
Writing is not necessarily something to be ashamed of, but do it in
private and wash your hands afterwards. --Robert Heinlein
---------------------------------------------------------------------
Luke Kanies | http://reductivelabs.com | http://config.sage.org