使用include,让模块中定义的方法分别插入类方法与实例方法


# =============================
# 目标1:
# 1、类扩展:使用include,让模块中定义的方法分别插入类方法与实例方法中
# 2、obj实例对象调用extend,则模块中定义的方法为?
# 3、在模块中定义的实例变量能否被包含它的类的实例对象看到
# =============================
# 结论
# 1、通过重定义横块中的self.included方法,并对参数(receiver),使用关键字extend/include,分别向包含它的类中插入了
#    类方法(定义在ClassMethods模块中的方法)和实例方法(定义在InstanceMethod模块中)
# 2、obj实例对象调用extend,则模块中定义的方法为这个obj的单例方法,可以通过把方法定义在module中,让实例对象调用extend
#    来方便快速的增加自身的单例方法
# 3、可以。在模块中定义的实例变量可以被包含它的类的实例对象看到,因为被include的模块相当于当前类的父类,当前对象的
#    实例变量对其所有实例方法可见
# 4、extend方法的实质就是把module中定义的方法插入到对象的单件类中
# 5、调用MyClass.instance_methods(false)可以发现,在它的实例方法中并不包含实例方法instance_method,而MyClass
#    的实例对象可以调用这个方法,这正说明了类中include的模块(被代理类封装)充当这个类的父类。也验证了结论4
# =============================
lambda {
  module M
    module ClassMethods
      def class_method
        "i am a class method"
      end
    end

    module InstanceMethods
      def instance_method(from)
        @instance_variate = "i am a instance variate in M"
        "i am a instance method from:#{from}"
      end
    end

    def self.included(receiver)
      receiver.extend         ClassMethods
      receiver.send :include, InstanceMethods
    end
  end

  #<!-- more -->
  class MyClass
    include M

    def get_instance_variate_from_module(from)
      "#{@instance_variate} from: #{from}"
    end
  end

  obj = Object.new
  obj.extend M::InstanceMethods
  my = MyClass.new

  puts "================test1 OUTPUT================"
  puts MyClass.class_method
  puts my.instance_method("MyClass.new obj")
  puts my.get_instance_variate_from_module("MyClass.new")
  puts obj.instance_method("Object.new")
  puts obj.instance_eval("@instance_variate")
  puts "MyClass.instance_methods:"+MyClass.instance_methods(false).to_s
  puts "================test1 OUTPUT================"

  # ================test1 OUTPUT================
  # i am a class method
  # i am a instance method from:MyClass.new obj
  # i am a instance variate in M from: MyClass.new
  # i am a instance method from:Object.new
  # i am a instance variate in M
  # MyClass.instance_methods:[:get_instance_variate_from_module]
  # ================test1 OUTPUT================

}.call