I assume you are doing this for the challenge / learning expience…
That, and it’s nice to have an implementation that fits with the
interface we have pretty much agreed on (well, matz has).
end
Thanks for the feedback, here’s the updated version.
class Module
def class_extension(&block) @class_extension ||= Module.new do
def self.append_features(mod); end
end @class_extension.module_eval(&block) if block_given? @class_extension
end
def append_features(mod)
mod.extend(class_extension)
if mod.instance_of? Module and mod.respond_to? :class_extension
mod.send(:class_extension).send(:include, class_extension)
end
end
end
class Class
undef_method :class_extension
end
#class_extension should probably be private, right?
def included(mod)
mod.extend(class_extension)
if mod.instance_of? Module and mod.respond_to? :class_extension
mod.send(:class_extension).send(:include, class_extension)
end
end
end
The code might need a change if we decide to make #class_extension private.
Daniel,
I assume you are doing this for the challenge / learning expience…
#included is not the best method to use since it is a callback. While
you could override #include itself, probably the most appropriate
method to use is #append_features. This is the method include calls to
do it’s “magic”.
Also, after defining the class_extension method for Module, you’ll want
to undefine it for Class, since it has no relevance there:
In message “Re: Why the lack of mixing-in support for Class methods?”
on Thu, 15 Jun 2006 23:38:24 +0900, Daniel S. [email protected] writes:
|That, and it’s nice to have an implementation that fits with the
|interface we have pretty much agreed on (well, matz has).
Yes, and there’s something that only working code can prove.
|#class_extension should probably be private, right?
I think so. Besides, I am thinking of class/module separation in the
future (both of them will become subclass of Object), so that users
won’t confuse modules with classes.
In message “Re: Why the lack of mixing-in support for Class methods?”
on Thu, 15 Jun 2006 23:38:24 +0900, Daniel S. [email protected] writes:
|That, and it’s nice to have an implementation that fits with the
|interface we have pretty much agreed on (well, matz has).
Yes, and there’s something that only working code can prove.
do you think this is important?
harp:~ > cat b.rb
require 'class_extension'
module M
class_extension do
p const_get(:File) # File
p File # File
class File
def self.inspect() 'my_file' end
end
p const_get(:File) # File
p File # my_file
end
end
p M::File # my_file
p M::const_get(:File) # my_file
p M::class_extension::const_get(:File) # File
p M::class_extension::File # exception!
harp:~ > ruby b.rb
File
File
File
my_file
my_file
my_file
File
b.rb:18: uninitialized constant #<Module:0xb75cdf08>::File
(NameError)
i am in the minority, but it bothers me. don’t get me wrong, i like the
interface - but the semantics seem odd.
#class_extension is now private, the magic has been moved to #append_features, and #class_extension has been undefined in Class, per
T’s request.
class Module
alias_method :append_features, :append_features
def class_extension(&block)
@class_extension ||= Module.new do
def self.append_features(mod)
__append_features__(mod)
end
end
@class_extension.module_eval(&block) if block_given?
@class_extension
end
private :class_extension
def append_features(mod)
__append_features__(mod)
mod.extend(class_extension)
if mod.instance_of? Module
mod.send(:class_extension).send(:include, class_extension)
end
end
end
class Class
undef_method :class_extension
end
#send must of course be replaced with #funcall in 1.9 – has there been
any progress with the naming of that? I checked the archives, but
couldn’t find anything never than August '05… it sounds like a “fun
call”, if you know what I mean… hopefully you don’t.
#send must of course be replaced with #funcall in 1.9 – has there been any
progress with the naming of that? I checked the archives, but couldn’t find
anything never than August '05… it sounds like a “fun call”, if you know
what I mean… hopefully you don’t.
Daniel
hi daniel-
is this by design?
harp:~ > cat b.rb
require ‘class_extension’
module M
class_extension{ attr_accessor ‘a’ }
end
M.a # exception!
#send must of course be replaced with #funcall in 1.9 – has there been
any progress with the naming of that? I checked the archives, but
couldn’t find anything never than August '05… it sounds like a “fun
call”, if you know what I mean… hopefully you don’t.
In message “Re: Why the lack of mixing-in support for Class methods?”
on Fri, 16 Jun 2006 00:50:43 +0900, [email protected] writes:
| p M::class_extension::const_get(:File) # File
| p M::class_extension::File # exception!
The difference here is caused because a class statement with in
module_eval defines a constant in the innermost surrounding class /
module (M, this case) in 1.8, and const_get looks ancestors for
constants by default, where double colons do not.
In 1.9, a class statement in module_eval defines a constant in the
target module (anonymous class_extension module in this case). So
that it gives:
i lost track of whether the module should respond to this or not… (the
thread
is looooong).
Hi,
Yes, it’s by design. Originally I extended the class that defined the
class extension, but per the request of some, I removed it again. This
should sort it out
module M
class_extension{ attr_accessor :a, :b }
extend class_extension
end
In message “Re: Why the lack of mixing-in support for Class methods?”
on Fri, 16 Jun 2006 01:16:08 +0900, [email protected] writes:
|> #send must of course be replaced with #funcall in 1.9 – has there been
|> any progress with the naming of that? I checked the archives, but
|> couldn’t find anything never than August '05… it sounds like a “fun
|> call”, if you know what I mean… hopefully you don’t.
I don’t. Luckily or not. For your information, ‘funcall’ is a lisp
function name that has its own history.
module (M, this case) in 1.8, and const_get looks ancestors for
/tmp/c.rb:42: warning: toplevel constant File referenced by M::File
File
File
my_file
my_file
for 1.9 that means the new File class is defined under anonymous
class_extension module. It seems more consistent and simple.
yes it does. that makes me feel better. thanks for the explanation.
I don’t. Luckily or not. For your information, ‘funcall’ is a lisp
function name that has its own history.
|Isn’t #funcall now called #instance_exec?
No, they are different.
I see. I wouldn’t otherwise have a problem with the name ‘funcall’ but
it’s a meta-programming method and as such it’s something important to
always have available. I have BasicObject class (basically the same as
BlankSlate) which clears out the Kernel methods. But some methods are
too important to remove. Thankfully all the important ones (except #dup
and #clone) start with either ‘__’ or ‘instance_’ (eg. send). But #funcall will add another exception. It would be nicer to see a
consistant pattern in the naming of these meta-methods.
i am in the minority, but it bothers me. don’t get me wrong, i like the
interface - but the semantics seem odd.
Well, I agree with you on both counts - I like your semantics and
Daniel’s interface. I certainly think you’re right to raise the
scoping issues of this implementation in 1.8.
Luckily, it seems we can have our cake and eat it with ruby 1.9!
And if people use Daniel’s implementation as a shim for 1.8, we now
have a clear explanation of the differences between this and what will
eventually be the official behaviour.
And if people use Daniel’s implementation as a shim for 1.8, we now
have a clear explanation of the differences between this and what will
eventually be the official behaviour.
Right on. I and the Nitro project have been despretely needing a
standardized approach to this. I’ll be providing a distribution of
Daniel’s implementation in Facets until it makes its way into Ruby.
Thanks Matz, Daniel, Ara, Sean and everyone that participated in this
thread! Oh and Alder G. for starting it! (Did you get your answer?
BTW Is this possibly the longest ruby-talk thread in history? Sheesh!