EDRY, meet CoC

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
Get In Touch