Jay Fields has envisioned a beautiful future for software development with his EDRY dialect of Ruby. But what is Enhanced DRY without better CoC (Convention over Configuration)?
I have modified Jay's code to rely more on convention. Why have a distinct vocabulary for fields vs. mixins, when the right thing to do can be inferred from the types involved? The result is some really tight code:
C Enumerable , :first_name , :last_name , :favorite_color do
d . complete_info? { nd ( first_name , last_name ) }
d . white? . red? . blue? . black? { | color | favorite_color . to_s == color . to_s . chop }
end
I am including the full source at the bottom of this entry. Can you make it even DRYer and more convention-driven?
class Object
def C ( * args , & block )
attrs = args . find_all { | arg | Symbol === arg }
includes = args . find_all { | inc | inc . instance_of? ( Module )}
name = File . basename ( eval ( "__FILE__" , block . binding ), ".rb" )
klass = Struct . new ( name . capitalize , * attrs )
Kernel . const_set ( name . capitalize , klass )
klass . class_eval ( & block )
klass . send :include , * includes
end
def s
self
end
end
class Class
def ctor ( & block )
define_method :initialize , & block
end
def i ( mod )
include mod
end
def d
DefineHelper . new ( self )
end
def a ( * args )
attr_accessor ( * args )
end
end
class DefineHelper
def initialize ( klass )
@klass = klass
end
def method_stack
@method_stack ||= []
end
def method_missing ( sym , * args , & block )
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
module Kernel
def instance_exec ( * args , & block )
mname = "__instance_exec_ #{ Thread . current . object_id . abs } _ #{ object_id . abs } "
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
def nd ( * args )
args . each { | x | return false unless x }
true
end
# convention: symbols are attributes, modules are to be included
C Enumerable , :first_name , :last_name , :favorite_color do
d . complete_info? { nd ( first_name , last_name ) }
d . white? . red? . blue? . black? { | color | favorite_color . to_s == color . to_s . chop }
end