From: Trans Date: 2007-01-02T10:34:04+09:00 Subject: Re: Little Things Gregory Seidman wrote: > The only way in which a class and a module differ is that you can create an > instance of a class. Current Ruby 1.8.5 will not let you call #new on a > singleton class, so one could argue that it's more a module than a class, > remembering that Class subclasses Module. It is, > however, at least a module. It is very important that it can be treated as > a module, i.e. responds to various methods defined in Module. I'd claim > that #include and #define_method are the two most important of those. Boy, I wish it were a module. That would make something a hek of a lot easier. Personally I never cared for the distiction between Class and Module. I feel it is rather arbitrary and I spend too much time wonder which one I should use for a give case. > If I hadn't had occasion to do significant metaprogramming and was looking > at this, I'd agree with you that this is nice. As it is, there are really > only four things I do to interact with the singleton class, in order of > frequency of use: > > 1) include a module > 2) define a method > 3) alias a method > 4) remove a method > > Now, #1 is served by Object#extend and doesn't require explicit access to > the singleton class at all. With #2, 99% of the time I use #define_method, > and the only time I don't is when I need to define a block-accepting > method. (Actually, I use send(:define_method, ...) because #define_method > is private. Could we make #define_method public for all singleton classes, > please? How about a SingletonClass subclass of Class, or possibly module, > that makes it public?) I actually need #3 and #4 vanishingly rarely, and > most of the time it makes more sense to do it in a module anyway which can > be included with extend. I'd put #2 before #1 and often 'def obj.meth' serves the purpose. > I just realized I forgot attr_accessor and friends, but I'd be inclined to > use #send (or #funcall) with that as well. What I'm saying, though, is that > if I had #customize and #customization (and #define_method were public for > singleton classes), I'd still do something like this (note: contrived > example): > > def setup_hashed_attributes(obj, hash) > if attrs = obj.instance_variable_get(:@hashed_attributes) > attrs.merge(hash) > else > obj.instance_variable_set(:@hashed_attributes, hash.dup) > end > singleton = obj.customization > singleton.send(:attr_reader, :hashed_attributes) > hash.keys.each { |k| > singleton.define_method(k) { @hashed_attributes[k] } > singleton.define_method("#{k}=") { |v| @hashed_attributes[k] = v } > } > end I don't know. If you're going to go to all that trouble why bother with the assignment? Just do: def setup_hashed_attributes(obj, hash) if attrs = obj.instance_variable_get(:@hashed_attributes) attrs.merge(hash) else obj.instance_variable_set(:@hashed_attributes, hash.dup) end obj.customization.send(:attr_reader, :hashed_attributes) hash.keys.each { |k| obj.customization.define_method(k) { @hashed_attributes[k] } obj.customization.define_method("#{k}=") { |v| @hashed_attributes[k] = v } } end That reads better IMO. You could alwasy add #define_custom_method too of course. T.