On Mar 18, 12:59 pm, “Sean O’Halpin” [email protected] 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.