- xml - AJAX/Jquery XML 解析
- 具有多重继承的 XML 模式
- .net - 枚举序列化 Json 与 XML
- XML 简单类型、简单内容、复杂类型、复杂内容
在阅读了下面 jvans 的回答并多看了几次源代码之后,我现在明白了:)。如果有人仍然想知道 Rails 委托(delegate)的工作原理。 Rails 所做的只是在您运行委托(delegate)方法的文件/类中使用 (module_eval) 创建一个新方法。
例如:
class A
delegate :hello, :to => :b
end
class B
def hello
p hello
end
end
当委托(delegate)被调用时,rails 将在类 A 中创建一个带有 (*args, &block) 的 hello 方法(从技术上讲,在类 A 写入的文件中),在该方法中,rails 所做的一切都是使用“:到”值(它应该是一个对象或一个已经在类A中定义的类)并将其分配给一个局部变量_,然后调用该对象或传递参数的类的方法。
因此,为了让委托(delegate)在不引发异常的情况下工作……使用我们之前的示例。 A 的实例必须已经有一个实例变量引用类 B 的实例。
class A
attr_accessor :b
def b
@b ||= B.new
end
delegate :hello, :to => :b
end
class B
def hello
p hello
end
end
这不是关于“如何在 rails 中使用委托(delegate)方法”的问题,我已经知道了。我想知道“委托(delegate)”到底是如何委托(delegate)方法的:D。在 Rails 4 源代码中,委托(delegate)在核心 Ruby 模块类中定义,这使得它可以在所有 Rails 应用程序中作为类方法使用。
实际上我的第一个问题是 Ruby 的 Module 类是如何包含的?我的意思是每个 Ruby 类都有 > Object > Kernel > BasicObject 的祖先,而 ruby 中的任何模块都有相同的祖先。那么当有人重新打开 Module 类时,ruby 到底是如何向所有 ruby 类/模块添加方法的呢?
我的第二个问题是..我知道 rails 中的委托(delegate)方法使用 module_eval 进行实际委托(delegate),但我并不真正理解 module_eval 是如何工作的。
def delegate(*methods)
options = methods.pop
unless options.is_a?(Hash) && to = options[:to]
raise ArgumentError, 'Delegation needs a target. Supply an options hash with a :to key as the last argument (e.g. delegate :hello, to: :greeter).'
end
prefix, allow_nil = options.values_at(:prefix, :allow_nil)
if prefix == true && to =~ /^[^a-z_]/
raise ArgumentError, 'Can only automatically set the delegation prefix when delegating to a method.'
end
method_prefix = \
if prefix
"#{prefix == true ? to : prefix}_"
else
''
end
file, line = caller.first.split(':', 2)
line = line.to_i
to = to.to_s
to = 'self.class' if to == 'class'
methods.each do |method|
# Attribute writer methods only accept one argument. Makes sure []=
# methods still accept two arguments.
definition = (method =~ /[^\]]=$/) ? 'arg' : '*args, &block'
# The following generated methods call the target exactly once, storing
# the returned value in a dummy variable.
#
# Reason is twofold: On one hand doing less calls is in general better.
# On the other hand it could be that the target has side-effects,
# whereas conceptually, from the user point of view, the delegator should
# be doing one call.
if allow_nil
module_eval(<<-EOS, file, line - 3)
def #{method_prefix}#{method}(#{definition}) # def customer_name(*args, &block)
_ = #{to} # _ = client
if !_.nil? || nil.respond_to?(:#{method}) # if !_.nil? || nil.respond_to?(:name)
_.#{method}(#{definition}) # _.name(*args, &block)
end # end
end # end
EOS
else
exception = %(raise DelegationError, "#{self}##{method_prefix}#{method} delegated to #{to}.#{method}, but #{to} is nil: \#{self.inspect}")
module_eval(<<-EOS, file, line - 2)
def #{method_prefix}#{method}(#{definition}) # def customer_name(*args, &block)
_ = #{to} # _ = client
_.#{method}(#{definition}) # _.name(*args, &block)
rescue NoMethodError => e # rescue NoMethodError => e
if _.nil? && e.name == :#{method} # if _.nil? && e.name == :name
#{exception} # # add helpful message to the exception
else # else
raise # raise
end # end
end # end
EOS
end
end
结束
最佳答案
Ruby 不会在这里重新打开模块类。在 ruby 中,类 Module 和类 Class 几乎相同。
Class.instance_methods - Module.instance_methods #=> [:allocate, :new, :superclass]
主要区别在于您不能“新建”模块。模块是多重继承的 ruby 版本,所以当你这样做时:
module A
end
module B
end
class C
include A
include B
end
在幕后,ruby 实际上正在创建一种叫做匿名类的东西。所以上面实际上等同于:
class A
end
class B < A
end
class C < B
end
module_eval 这里有点骗人。您正在查看的代码中没有任何内容与模块打交道。 class_eval 和 module_eval 是同一件事,它们只是重新打开它们被调用的类,所以如果你想向类 C 添加方法,你可以这样做:
C.class_eval do
def my_new_method
end
end
或
C.module_eval do
def my_new_method
end
end
两者都相当于手动重新打开类并定义方法
class C
end
class C
def my_new_method
end
end
所以当他们在上面的源代码中调用 module_eval 时,他们只是重新打开当前正在调用它的类并动态定义您要委托(delegate)的方法
我认为这会更好地回答您的问题:
Class.ancestors #=> [Module, Object, PP::ObjectMixin, Kernel, BasicObject]
因为 ruby 中的一切都是一个类,方法查找链将遍历所有这些对象,直到找到它要查找的内容。通过重新操作模块,您可以为所有内容添加行为。这里的祖先链有点欺骗性,因为 BasicObject.class #=> Class 和 Module 在 Class 的查找层次结构中,即使 BasicObject 也继承了重复模块的行为。在此处重新打开 Module 相对于 Class 的优势在于,您现在可以从模块内以及类内调用此方法!非常酷,我自己在这里学到了一些东西。
关于ruby - Rails 委托(delegate)方法如何工作?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20873591/
sanitize 是什么意思在 Rails 中是什么意思? 我正在阅读 CanCanCan 的文档.它说: When using strong_parameters or Rails 4+, you
在过去的几个月里,我感觉自己对 Ruby on Rails (RoR) 开发的了解达到了极限。我为大/小客户和 friend /爱好项目开发了大大小小的应用程序。我知道如何开发这些应用程序,但开始感觉
我昨天参加了一个关于扩展 Rails 的聚会,其中一个主题是 Hexagonal Rails。然而,我只做了一年的 Rails,对 MVC 结构非常满意(也许太舒服了),所以我不太了解适配器和消息队列
我使用多个 Rails 应用程序,一些在 Rails 3.2/Ruby 2.0 上,一些在 Rails 2.3/Ruby 1.8.7 上。 他们的共同点是,随着他们的成长和添加更多的依赖项/ gem
这个问题在这里已经有了答案: Using Rails-UJS in JS modules (Rails 6 with webpacker) (5 个答案) 关闭 3 年前。 我正在尝试使用 UJS
我正在开发一个当前使用 Rails 1.2 的 Rails 应用程序,所以我现在离最新的稳定版本(Rails 2.3)还有很长的路要走。 我应该如何进行迁移到更新版本的 Rails 的过程? 我应该一
尝试按照 Ryan Bates Backbone.js 教程构建抽奖应用程序,但我已经遇到了第一段代码的问题。在 application.js 的 init 函数中,他初始化了 Raffler 路由的
我正在使用 Rails 3.2 并且我有一个数据库表,我想在其中找到符合以下条件的所有行: a = true and b = true and ( 0 true, :b =>
我有一个用户类和一个联系人,其中联系人是用户的子类。这两个类都存储在用户表中。 我的联系人可能有也可能没有电子邮件地址,而我的用户需要一个电子邮件地址(我的用户模型定义中有 validates_pre
我正在编写一个教程,我在其中演示了一些 rails 命令。在我的机器上 rails和 script/rails两者都同样有效。有“首选”形式吗?两者中哪一个更普遍? 最佳答案 当您运行 rails 时
我正在寻找有关通过我的应用程序前进的最佳方式的建议,这是我首次开始集成Elasticsearch。我是一名初学者,但是热衷于深入研究,以便原谅任何明显的错误! 我遵循了http://www.sitep
我刚刚用 Rails new 启动了一个新的 Rails 应用程序,将默认数据库设置更改为 PostgresSQL。我用 bin/rails s 启动服务器,结果很奇怪 2016-04-21 05:0
我收到一个参数并希望它是这样的字符串: "abc,efg" 或者像这样的数组 ["abc","efg"] 在第一种情况下,我想将它转换成一个数组,什么是好的方法? 这是我的想法 if params[:
我刚刚用 Rails new 启动了一个新的 Rails 应用程序,将默认数据库设置更改为 PostgresSQL。我用 bin/rails s 启动服务器,结果很奇怪 2016-04-21 05:0
我收到一个参数并希望它是这样的字符串: "abc,efg" 或者像这样的数组 ["abc","efg"] 在第一种情况下,我想将它转换成一个数组,什么是好的方法? 这是我的想法 if params[:
我有 Rails 4,这是我的默认版本(我仍然希望它是)。但我不想在我的电脑上添加 rails 3.2。在以下命令中:gem install rails -v 3.2.16 我有这个警告: railt
您好,我想使用 Sheevaplug 构建一个“Rails Brick”来自 Marvell(操作系统是开箱即用的 Ubuntu,但您可以在其上安装其他发行版)。它将成为家庭服务器和静音、低成本(99
我需要能够从 Rails 控制台发送我的 Rails 应用程序的 Postgres 数据库中所有未接受的邀请。 (我有一个名为 Invitations 的表,其中包含一个名为 accepted 的 b
validate :cannot_modify_if_locked, on: :update def cannot_modify_if_locked if self.locked erro
我正在学习教程(学习 Rails 播客),需要更改以下路由语法,以便它与 Rails 3.0 兼容。谁能帮忙? map.view_page ':name', :controller => 'viewe
我是一名优秀的程序员,十分优秀!