用于定义类方法:b,b=,b?
三种用法:
set :b, 'a symbol named b'
set :b {'a symbol named b'}
set b: 'a symbol named b', c: 'a symbol named c'


def set(option, value = (not_set = true), ignore_setter = false, &block)
  # 如果有block,又有value,则报错
  raise ArgumentError if block and !not_set

  # 如有block,则value赋值为block
  value, not_set = block, false if block

  # 如无block也无value,则option需为hash
  if not_set
    raise ArgumentError unless option.respond_to?(:each)
    option.each { |k,v| set(k, v) }
    return self
  end

  # 如已有对应setter,且真的想用该setter(无设ignore_setter的话),则调用它
  if respond_to?("#{option}=") and not ignore_setter
    return __send__("#{option}=", value)
  end

  # setter还是调用set,但传ignore_setter = true,以作赋值而非重定义setter
  setter = proc { |val| set option, val, true }
  getter = proc { value }

  case value
  when Proc
    getter = value
  # define_singleton会将字符串包装成def...来eval
  when Symbol, Fixnum, FalseClass, TrueClass, NilClass
    getter = value.inspect
  # 若value是Hash,则以后每次赋值都是merge
  when Hash
    setter = proc do |val|
      val = value.merge val if Hash === val
      set option, val, true
    end
  end

  # if setter/getter似乎没有意义,因它们肯定存在
  define_singleton("#{option}=", setter) if setter
  define_singleton(option, getter) if getter
  define_singleton("#{option}?", "!!#{option}") unless method_defined? "#{option}?"
  self
end

def define_singleton(name, content = Proc.new)
  singleton_class.class_eval do
    undef_method(name) if method_defined? name
    String === content ? class_eval("def #{name}() #{content}; end") : define_method(name, &content)
  end
end