From: Trans Date: 2008-03-19T06:54:05+09:00 Subject: Re: Parametric module or injecting code via class method? On Mar 18, 12:59 pm, "Sean O'Halpin" wrote: > > True enough. As I said, I'm only surmising what Trans is after. I'm > not criticising your response to the concrete example (after all, > it is both pragmatic and to the point). Rather, I'm taking the > question Trans posed as an opportunity to discuss what I consider best > practice in the more general case. I'd like to present another example --a simpler one in a sense, of direct extension vs. using modules. I will leave out most the code for brevity sakes but consider, but here is an example where I took code that was straight core extensions and "modulized" it: # -- random.rb # Can't modulize Kernel b/c of double module inclusion problem. module Kernel def maybe(chance = 0.5, &block) if block then yield if rand < chance else rand < chance end end ... end module Random def self.append_features(mod) if mod == ::Kernel # not needed mod.send(:include, Random::Kernel) elsif mod == ::Array mod.send(:include, Random::Array) elsif mod == ::Hash mod.send(:include, Random::Hash) elsif mod == ::String mod.send(:include, Random::String) else raise TypeError end end # module Array def at_rand self.at( rand( size ) ) end ... end # module Hash def rand_key keys.at( rand(keys.size) ) end ... end # module String def self.included(base) base.extend(Self) end module Self def random(max_length = 8, char_re = /[\w\d]/) # gmosx: this is a nice example of input parameter checking. # this is NOT a real time called method so we can add this # check. Congrats to the author. raise ArgumentError.new('char_re must be a regular expression!') unless char_re.is_a?(Regexp) string = "" while string.length < max_length ch = rand(255).chr string << ch if ch =~ char_re end return string end def rand_letter (rand(26) + (rand(2) == 0 ? 65 : 97) ).chr end end def at_rand( separator=// ) #separator = self.class.patterns( separator ) self.split(separator,-1).at_rand end ... end end class Array include Random end class Hash include Random end class String include Random end Other Ruby coder's might look at this and think, "clever". I look at it and think, "obfuscated". First off there is Kernel, b/c of the double module inclusion problem it can't participate in the whole "clever" affair. Then there is Self and the included callback hack to get the class-level methods in there. And on top of it all, there is the simple fact that I had to create and include a bunch of new modules and all the overhead that comes with them -- when all I want to do add a few methods to the core classes/modules. To throw in a little irony as well, the main reason I even bothered to do this, was not to help avoid method clash (a fairly unavoidable problem really), but to get better results for RDoc --and that fact really makes me sick. T.