But, I've grown tired of this debate. No one ever wins, instead people just get tired of listening so they stop interacting. If you want to define methods of a module in a loop that later gets included in 3 classes that have nothing else in common, you have the right to do that. In fact, I'm excited about helping you.
Here's how DRY your code could be.
# what's the sense in writing the class name?
# you already wrote it once when you named the file
C do
# attr_accessor clearly has 12 too many characters
a :first_name, :last_name, :favorite_color
# include is short, but i is good enough
i Enumerable
# ctor defines a constructor
ctor {|*args| s.first_name, s.last_name = *args }
# d allows you to define any method by calling it from d.
# you can also chain the calls together to if you have several methods that are similar.
d.complete_info? { first_name && last_name && true }
d.white?.red?.blue?.black? {|color| self.favorite_color.to_s == color.to_s.chomp("?") }
end
That's some DRY code, perhaps even Extremely DRY (EDRY). Code isn't any good unless it runs.
Foo < Enumerable # => true
f = Foo.new("Mike", "Ward") # => #<Foo:0x1e6f4 @first_name="Mike", @last_name="Ward">
f.first_name # => "Mike"
f.last_name # => "Ward"
f.complete_info? # => true
f.red? # => false
f.favorite_color = :red # => :red
f.red? # => true
It runs without problem. Dying for the implementation? No worries, here it is.
name = File.basename(eval("__FILE__", block.binding),".rb")
klass = eval "class ; end; ", binding, __FILE__, __LINE__
klass.class_eval(&block)
end
self
end
end
define_method :initialize, &block
end
include mod
end
DefineHelper.new(self)
end
attr_accessor(*args)
end
end
@klass = klass
end
@method_stack ||= []
end
method_stack << sym
if block_given?
method_stack.each do |meth|
@klass.class_eval do
define_method meth do
instance_exec meth, &block
end
end
end
end
self
end
end
# http://eigenclass.org/hiki.rb?instance_exec
mname = "__instance_exec_ _"
Object.class_eval{ define_method(mname, &block) }
begin
ret = send(mname, *args)
ensure
Object.class_eval{ undef_method(mname) } rescue nil
end
ret
end
end
Of course, any EDRY code will be write only. It would be painful to try to actually read code written in this way, but that's already true of the 150 modules that each contain only one method definition. The difference is generally it's not immediately obvious when you first look at a codebase that has been DRYed up for the sake of keystroke savings. If the implementer instead chose to utilize EDRY, I'd know what I was getting into from the first file opened.
I don't like 'C', 'a', 'i', etc.
ReplyDeleteWe code Ruby, not C !
However 'class' without name it's a great idea... but it must be a convention, not a restriction !
In an other hand, writing one time the name of the class is not really a problem, it can't be compared to a database definition...
Fun post, with some good points, but short names are not a part of DRY, so the "C", "i", etc., are a strawman.
ReplyDeleteYou know, as someone who is now writing APL for a living... I can really appreciate this post.
ReplyDeleteBut I've got to tell you: Nothing will stop people from being more terse than is beneficial.
I agree with Jeem. This post totally missed the point.
ReplyDeleteAs Jeem pointed out the post was supposed to be fun. I couldn't agree more that DRY is not about short names or typing less. If anything, it was meant to point out that typing less is a silly way to see DRY.
ReplyDeleteWhenever I see code in a post of yours, it invariably gets pushed around by the Google ad, like so:
ReplyDeletebad formatting
And you probably want it to look more like so:
good formatting
Just so you know.
I'd actually argue that you're not taking it far enough. What's the point of comments? Good code should be self-documenting and intuitive to anyone within 5 seconds of looking at it.
ReplyDeleteIt really frustrates me to see great programmers get bogged down by comments and documentation efforts. If we wanted to be technical writers, we'd have majored in English, not CS!
Also, your implementation is too long - more semi-colons, please!
...
;)