一个简单的测试 1 2 3 4 5 6 7 8 9 10 11 12 def to_word(s) s.gsub(/\d/, '' ) end require 'test/unit' class ToWordTest < Test::Unit ::TestCase def test1 assert_equal 'hello world ', to_word ('234234he345345l345345lo345345 wo345r4353ld ') end end
在 class String 上添加方法 1 2 3 4 5 6 7 8 9 10 11 12 13 class String def to_word self .gsub(/\d/ , '' ) end end require 'test/unit' class ToWordTest < Test::Unit::TestCase def test1 assert_equal 'hello world' , '234234he345345l345345lo345345 wo345r4353ld' .to_word end end
Class 重复的 class 1 2 3 4 5 3. times do class C p 'hello ' end end
验证只是 class 可以重复声明且会自动合并
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 class C def x p 'x' end end class C def y p 'y' end end z = C.new z.x z.y
自定义一个 class 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 class MyClass def initialize @v = 1 end def add @v += 1 end end obj = MyClass .new p obj.class p obj.add p obj.instance_variables p MyClass .instance_variables p obj.methods p MyClass .instance_methods p obj.methods.grep(/add/ )
证明,一个对象的实例变量储存在自身,一个对象的实例方法存储在其类身上
superclass (类似于 JS 的原型链) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 p p String .superclass # Object p Object .superclass # BasicObject p BasicObject.superclass # nil p String .is_a? Class p p Array.superclass # Object p Array.is_a? Class class MyClass ; end p MyClass .superclass # Object p MyClass .is_a? Class p p Class .is_a? Class p Class .superclass # Module # 模块是低配版的类,类是高配版的模块
模块是低配版的类,类是高配版的模块
常量 1 2 3 4 5 6 7 8 9 10 11 12 Const1 = 'root const' module MyModule Const1 = 'outer const' class MyClass Const1 = 'inner const ' p ::Const1 # 'root const ' end end p Const1 # 'root const 'p MyModule::Const1 # 'outer const 'p MyModule::MyClass ::Const1 # 'inner const '
使用 ::
打印出内部的常量,直接使用 ::
可以打印出根的常量
1 2 p '------------' p MyModule.constants
使用 MyModule.constants 得到 MyModule 的内部的所有一级常量
1 2 3 4 5 6 7 8 9 Const1 = 'root const' module MyModule Const1 = 'outer const' class MyClass Const1 = 'inner const' p 'Module.nesting' p Module .nesting end end
使用 Module.nesting 得到 当前作用域的层级结构
祖先链 1 2 3 4 5 6 7 8 9 10 11 12 13 14 class MyClass def my_class 'my_class' end end class MySubClass < MyClass end obj = MySubClass .new p obj.my_class p MySubClass .ancestors
module
模块和类非常非常像,只是模块不能继承
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 module M1 def my_methods 'M1#my_methods' end end class C1 include M1 end class A1 < C1 end p A1 .ancestors
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 module M1 def my_methods 'M1#my_methods' end end class C1 prepend M1 end class A1 < C1 end p A1 .ancestors
使用 include (上面增加)和 prepend(下面增加) 可以在类中引入模块,用来改变方法查找顺序,使得继承组合更加多样化
self (method 的查找方法) self 是当前对象 1 2 3 4 5 6 7 8 9 10 11 12 13 class MyClass def test_self @var = 10 me_method self end def me_method @var += 1 end end obj = MyClass .new p obj.test_self
可以看到 @var 已经是 11 了, 注意:这里执行到 me_method 的时候,不是像js一样直接往下在当前对象上找到 me_method 这个方法,而是这样的执行顺序: 先找 obj 上的 test_self, 在MyClass 上找到,执行该方法,该方法声明了 @var 并执行 me_method 方法(注意:这里的 me_method 会再次找 obj => MyClass => def me_method,再执行)注意调用该方法时,self已经变了,所以 me_method 才能给 @var 加一 ,最后返回 self
特殊:顶级的 self
p 出来的肯定是对象,为什么是 main,只需要改写其 to_s 和 inspect 方法即可,
1 2 3 4 5 6 7 8 9 10 11 12 13 o1 = {name: 'zch' } p o1 p self class Temp def to_s 'temp' end def inspect 'temp' end end p Temp .new
self 也可以是类 1 2 3 4 5 6 7 class MyClass2 p 'MyClass2 ' p self # self 是类 def my_method p self end end
私有方法 1 2 3 4 5 6 7 8 9 10 11 12 class MyClass def public_method 'MyClass::public_method ' end private def private_method1 'MyClass::private_method1 ' end def private_method2 'MyClass::private_method2 ' end end
使用 private 分隔私有方法,非常机智,private 以上都是不是私有的,下面都是私有的
1 2 3 4 obj = MyClass.new obj.public_method obj.private_methods1 # 报错 obj.private_methods2 # 报错
调用 private 方法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 class MyClass def public_method1 self .private_method1 end def public_method2 private_method1 end private def private_method1 'MyClass::private_method1' end def private_method2 'MyClass::private_method2' end end
私有方法调用必须满足如下情况
必须在对象所在的类中调用
不能再前面加 self 字样(只能隐式指定 self)
动态调用方法
调用方法有两种
obj.xx_method(‘hi’)
obj.send(:xx_method, ‘hi’)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 class Notification def notify (witch ) send "notify_#{witch} " end private def notify_wx p '通知到威信' end def notify_qq p '通知到qq' end def notify_phone p '通知到手机' end def notify_all notify_wx notify_qq notify_phone end end obj = Notification .new obj.notify('qq' )
注意 send 调用方法不分共、私有,上述可以直接 obj.send(:notify_qq, 'hi')
。(ruby 中的私有方法更像是一种君子协定:),另外你也可以使用 public_send,这样就不能调用私有方法了
动态定义方法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 class MyClass x = :methods1 define_method x do |n | n * 3 end end require 'test/unit' class MyClassTest < Test::Unit::TestCase def test_1 obj = MyClass .new assert_equal 6 , obj.methods1(2 ) end end
动态定义的好处:可以在运行时决定方法的名字,而不是写代码时 这在批量创建方法时非常有用
自定义未定义方法(狗头) 1 2 3 class MyClass ;end obj = MyClass .new obj.xxx
调用 obj.xxx
, 一般来说调用一个未定义的方法,其他语言会直接报错,但是 ruby 不会,obj 会一直向上查找,直到调用 BaseObject#method_missing
这个方法去报错 也就等同于 obj.send(:method_missing, :xxx)
,这两个报错一模一样,即可验证
所以我们就可以直接覆盖 method_mssing 1 2 3 4 5 6 7 8 9 10 class MyClass private def method_missing (method, *args ) p "method:#{method} ,参数:#{args} " p '找不到方法啊,大哥' end end obj = MyClass .new obj.xxx(1 ,2 ,3 )
这么做以后,就可以让一个对象响应任何一个方法 例如可以看看 hashie 的库,lib=>mash=>method_missing 定义了更好用的对象