class Original
  CONST = :original
  @@class = :original

  def create_proc
    return Proc.new{
      p self
      p CONST
      p @@class

      def new_method_by_proc_at_method
      end
      # これは構文エラーになるのでコメント化
      # NEW_CONST_BY_PROC_AT_METHOD = :proc_at_method
      @@new_class_by_proc_at_method = :proc_at_method
    }
  end

  CONST = :modified
  @@class = :modified
end

class Other
  CONST = :other
  @@class = :other

  def call(code, method_name, const_name, classvar_name)
    case code
    when Proc
      self.instance_eval(&code)
    else
      self.instance_eval(code)
    end

    case
    when Original.method_defined?(method_name)
      p :original
    when Other.method_defined?(method_name)
      p :other
    when self.respond_to?(method_name)
      p :singleton
    else
      raise
    end

    case
    when Original.const_defined?(const_name)
      p :original
    when Other.const_defined?(const_name)
      p :other
    when (class << self; self end).const_defined?(const_name)
      p :singleton
    else
      p :not_defined
    end

    case
    when (Original.__send__(:class_variable_get, classvar_name) rescue false)
      p :original
    when (Other.__send__(:class_variable_get, classvar_name) rescue false)
      p :other
    when ((class << self; self end).__send__(:class_variable_get, classvar_name) rescue false)
      p :singleton
    else
      raise
    end
  end
end

orig = Original.new
proc_by_method = orig.create_proc

proc_by_class = class Original
  Proc.new {
    p self
    p CONST
    p @@class

    def new_method_by_proc_at_class
    end
    NEW_CONST_BY_PROC_AT_CLASS = :proc_at_class
    @@new_class_by_proc_at_class = :proc_at_class
  }
end

program = <<'EOS'
  p self
  p CONST
  p @@class

  def new_method_by_str
  end
  NEW_CONST_BY_STR = :str
  @@new_class_by_str = :str
EOS






other = Other.new
other.call(program, :new_method_by_str, :NEW_CONST_BY_STR, :@@new_class_by_str)
puts
other = Other.new
other.call(proc_by_method, :new_method_by_proc_at_method, :NEW_CONST_BY_PROC_AT_METHOD, :@@new_class_by_proc_at_method)
puts
other = Other.new
other.call(proc_by_class, :new_method_by_proc_at_class, :NEW_CONST_BY_PROC_AT_CLASS, :@@new_class_by_proc_at_class)



