Ruby 中的 module_function 和 extend self异同

在阅读开源的 Ruby 代码和编写可维护性的代码经常遇到这两者的使用,那么他们两者的共同点和区别是什么呢?

module_function

Ruby 的 module 是 method 和 constants 的集合。module 中的method 又可分为 instance method 和 module method, 当一个 module 被 include 进一个 class ,那么 module 中的 method (注:没有被 module_function 标记的 method)就是 class 中的 instance method, instance method 需要所在的 class 被实例化之后才能被调用;被 module_function 标记的 method(不管该 method 是 public 或者 private)就是 module method 且 instance method 也会变成 private method,对于被 include 所在的 class 来说是 private method,object.module_name 会出错。module method 都能被 module_name.method_name 调用,没有被 module_function 标记的 public method 不能被 module_name.method_name 调用。

module 中的 module_function 会把 module 中的 method 变成 module method 且对于被 include 所在的 class 来说,module method 在 module 中是 private method 故 module_name.module_method 能调用,而不能被 object.module_name 调用。

module 中的 public method 对于被 include 所在的 class 来说是 instance method,故 object.public_method_in_module 能调用。如果想要非 module method 能够被 module 调用(module_name.not_module_method) ,需要引入 extend self (下文会讨论 extend self)

# test.rb
module MyModule
 def public_meth
  p "a public method, if the module is included to a class , can be call as object.public_meth"
 end
 def module_method
  p "a module method,can be called as module_name.module_method. but can not be call as object.module_method"
 end
 private
 def private_method_to_module_function
  p "a private_method, but can be call as module_name.module_method, because it was assigned to module_function"
 end
 def private_method
  p "I am a private method"
 end
 module_function :module_method, :private_method_to_module_function
end

MyModule.module_method
MyModule.private_method_to_module_function
begin
 MyModule.public_meth
rescue
 p "public method can not be called by module_name.public_meth"
end
begin
 MyModule.private_method
rescue NoMethodError
 p "private method can not be called by module_name.module_method"
end

class MyClass
 include MyModule
end

obj = MyClass.new
obj.public_meth

begin
 obj.private_method
rescue NoMethodError
 p "private method in module can not be call by object.method_name"
end

begin
 obj.module_method
rescue NoMethodError
 p "module method can not be called by object.method_name, for object, module method is private instance method"
end

#调用
ruby test.rb
"a module method,can be called as module_name.module_method. but can not be call as object.module_method"
"a private_method, but can be call as module_name.module_method, because it was assigned to module_function"
"public method can not be called by module_name.public_meth"
"private method can not be called by module_name.module_method"
"a public method, if the module is included to a class , can be call as object.public_meth"
"private method in module can not be call by object.method_name"
"module method can not be called by object.method_name, for object, module method is private instance method"

总结就是

•The method will be copied to class' singleton class
•The instance method's visibility will become private

extend self

Include is for adding methods to an instance of a class and extend is for adding class methods

extend 本质是给 class 或者 module 添加 class method

extend self 让 module 中的 instance method 能够被 module_name.instance_method 调用,保留 module 中原本 method 的 public 或 private 属性,但又不像 module_function 一样把被标记的 method 变成 private 。

#!/usr/bin/env ruby
# encoding: utf-8
# test_extend.rb
module MyModule
 extend self
 def public_meth
  p "a public_method extended by self can be called by module_name.public_meth and object.public_meth, included by a class"
  private_method
 end
 private
 def private_method
  p "a private method, can be call in module internal"
 end
end

class MyClass
 include MyModule
end

MyModule.public_meth

begin
 MyModule.private_method
rescue NoMethodError
 p "private method in extend self module can not be called module_name.private_method"
end

obj = MyClass.new
obj.public_meth

begin
 obj.private_method
rescue NoMethodError
 p "private method can not be called by object.private_method"
end

# 调用 ruby test_extend.rb
"a public_method extended by self can be called by module_name.public_meth and object.public_meth, included by a class"
"a private method, can be call in module internal"
"private method in extend self module can not be called module_name.private_method"
"a public_method extended by self can be called by module_name.public_meth and object.public_meth, included by a class"
"a private method, can be call in module internal"
"private method can not be called by object.private_method"

总结就是:
•No method copying involved
•No changes to method visibility

总结

module_function 改变 module 内 原来 method 的 public/private 属性并把改 method 变成 module method ,能够被 module_name.module_method 调用。

extend self 就是在 module 自继承,不改变 module 中 method 的 public/private 属性,能够被 module_name.public_method

(0)

相关推荐

  • Ruby中require、load、include、extend的区别介绍

    require,load用于文件,如.rb等等结尾的文件.include,load则用于包含一个文件中的模块. require 一般情况下用于加载库文件,而load则用于加载配置文件. 1.require:加载一个库,并且只加载一次,如果多次加载会返回false.只有当要加载的库位于一个分离的文件中时才有必要使用require.使用时不需要加扩展名,一般放在文件的最前面: 复制代码 代码如下: require 'test_library' 2.load: load用来多次加载一个库,必须指定扩展

  • Ruby 中的 module_function 和 extend self异同

    在阅读开源的 Ruby 代码和编写可维护性的代码经常遇到这两者的使用,那么他们两者的共同点和区别是什么呢? module_function Ruby 的 module 是 method 和 constants 的集合.module 中的method 又可分为 instance method 和 module method, 当一个 module 被 include 进一个 class ,那么 module 中的 method (注:没有被 module_function 标记的 method)就

  • Ruby中编写类与模块的风格指南

    在 class 定义里使用一致的结构. class Person # extend and include go first extend SomeModule include AnotherModule # constants are next SOME_CONSTANT = 20 # afterwards we have attribute macros attr_reader :name # followed by other macros (if any) validates :name

  • Ruby中的钩子方法详解

    Ruby的哲学理念是基于一个基本的要素,那就是让程序员快乐.Ruby非常注重程序员的快乐,并且也提供了许多不同的方法来实现它. 它的元编程能力能够让程序员编写在运行时动态生成的代码.它的线程功能使得程序员有一种优雅的的方式编写多线程代码. 它的钩子方法能让程序员在程序运行时扩展它的行为. 上述的这些特性,以及一些其他很酷的语言方面,使得Ruby成为编写代码的优先选择之一. 本文将探讨Ruby中的一些重要的钩子方法.我们将从不同方面讨论钩子方法,如它们是什么,它们用于什么,以及我们如何使用它们来解

  • Ruby中的block、proc、lambda区别总结

    在规则引擎中,Ruby 的闭包使用特别频繁,而且有 block,Proc和 lambda 等后几种形式的用法,很让人困惑.为了深入理解代码,再次认真学习了一下 Ruby 的闭包,特别是 block,proc 和 lambda 几种用法的异同,这次的周记就和大家分享一下心得. 闭包是 Ruby 相对其它语言特别优势之一,很多语言有闭包,但是唯有 Ruby 把闭包的优势发挥得淋漓尽致.Ruby 的哲学之一:同一个问题现实中有多种解决方法,所以 Ruby 中也有多种解法,所以闭包的使用也有多种方法.

  • Java中比较抽象类与接口的异同

    目录 一.抽象类 (一)概念 (二)抽象类和抽象方法 (三)使用抽象类的意义 二.接口 (一)概念 (二)语法 三.比较抽象类与接口 Q: 为什么有了抽象类还要接口?  Q: 如何确定在什么情况下应该使用接口,什么情况下应该使用类呢? 一.抽象类 (一)概念       在继承的层次结构中,每个新的子类都使类变得更加明确和具体.如果从一个子类向父类追溯,类就会变得更通用.更加不明确.类的设计应该确保父类包含它的子类的共同特征.有时候,一个父类设计得非常抽象,以至于它都没有任何具体的实例.这样的类

  • ruby中并发并行与全局锁详解

    前言 本文主要给大家介绍了关于ruby并发并行和全局锁的相关内容,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍吧. 并发和并行 在开发时,我们经常会接触到两个概念: 并发和并行,几乎所有谈到并发和并行的文章都会提到一点: 并发并不等于并行.那么如何理解这句话呢? 并发: 厨师同时接收到了2个客人点了的菜单需要处理. 顺序执行: 如果只有一个厨师,那么他只能一个菜单接着一个菜单的去完成. 并行执行: 如果有两个厨师,那么就可以并行,两个人一起做菜. 将这个例子扩展到我们的web开发

  • Ruby中Hash哈希结构的基本操作方法小结

    关于哈希 先来了解一下Hash的基本思路: 设要存储对象的个数为num, 那么我们就用len个内存单元来存储它们(len>=num); 以每个对象ki的关键字为自变量,用一个函数h(ki)来映射出ki的内存地址,也就是ki的下标,将ki对象的元素内容全部存入这个地址中就行了.这个就是Hash的基本思路. 为什么要用一个函数来映射出它们的地址单元呢? 假设现在我要存储4个元素 13 7 14 11 显然,我们可以用数组来存.也就是:a[1] = 13; a[2] = 7; a[3] = 14; a

  • 详解Ruby中的单件方法和单件类

    单件方法 Ruby允许给单个对象增加方法,这种只针对单个对象生效的方法,称为单件方法 示例代码 str = "just a regular string" def str.title? self.upcase == self end str.title? # => false str.methods.grep(/title?/) # => [:title?] str.singleton_methods #=> [:title?] str.class # => S

  • Monkey Patch猴子补丁编程方式及其在Ruby中的运用

    何谓猴子补丁(Monkey Patch)?在动态语言中,不修改源代码而对功能进行追加和变更. 使用猴子补丁的目的: 1.追加功能 2.功能变更 3.修正程序错误 4.增加钩子,在执行某个方法的同时执行一些其他的处理,如打印日志,实现AOP等, 5.缓存,在计算量很大,结算之后的结果可以反复使用的情况下,在一次计算完成之后,对方法进行替换可以提高处理速度. Ruby的类都是开放类,即在类定义之后还可以任意添加内容, 这就使得在Ruby中使用猴子补丁变得特别容易了.另外,Ruby还提供了对方法.类和

  • Ruby中执行Linux shell命令的六种方法详解

    在Ruby中,执行shell命令是一件不奇怪的事情,Ruby提供了大概6种方法供开发者进行实现.这些方法都很简单,本文将具体介绍一下如何在Ruby脚本中进行调用终端命令. exec exec会将指定的命令替换掉当前进程中的操作,指定命令结束后,进程结束. 复制代码 代码如下: exec 'echo "hello world"' print 'abc' 执行上述的命令,结果如下,我们可以看到没有abc的输出,可以看出来,在执行echo "hello world"命令后

随机推荐