我的红宝石之旅:挂钩

我才刚刚开始Ruby / Rails之旅(工作了不到一年),有一天我遇到了这样的事情。

 类产品 
actions_as_paranoid
actions_as_taggable
has_paper_trail
获利:price_cents
结束

我知道它们来自宝石,但我认为它看起来非常酷,并且对它们的工作方式非常好奇,因此我退后一步,解决了问题并逐一解决。

我在这里发现的几件事:

  • 它们只是普通的类方法
  • 当您在类中放置方法名称时,每次您创建该方法的新实例时都会调用该方法。

例如:

 类示例 
放置“每次启动#{self}实例时都会调用此函数”
endExample.new#=>“每次启动Example实例时都会调用此方法

因此,既然我知道它们只是类方法,我决定下一步应该写类似的东西。 可重用的类方法 ! (我现在还不想了解Rails如何自动加载它)

因此,我开始了自己的旅程,然后下一个障碍!

(剧透:是的,你可以,我一开始不知道! 😛)

起初,我认为这将是一个简单的“ include Module”,因为这就是告诉我可重用方法的工作方式,所以我在这里天真地尝试在模块上定义一个类方法,然后将其包含在类中,但是不起作用!

例如:

 可重用模块 
def self.awesome?
表示“太棒了!”
结束
结束类AwesomeObject
包括可重用
endAwesomeObject.awesome? #=>未定义的方法“太棒了” 对于AwesomeObject:Class(NoMethodError)

经过一番挖掘,我发现这样做的原因是因为Ruby的include不包括类方法。

但是,有一个通过extend的解决方案 ,包括鲜为人知的兄弟姐妹(另一个是prepend )。

完整的解释超出了本文的讨论范围,因此在这里我将不做深入探讨,但是,如果您想了解更多信息,那是由于Ruby中有一个名为Singleton Class的东西。 这也是我下一篇博客文章的主题,请继续关注!

由于include是扩展和前置的更受欢迎的兄弟,因此我决心确保最终用户只需记住要包含一个模块,而不必考虑-

“我要扩展此范围, 包括此范围还是在其前面 ?”

还希望避免出现包含模块的情况,然后花一整天的时间弄清楚为什么类方法不起作用。

实际上,事后看来,告诉开发人员盲目地扩展方法并不是一个坏主意。 但是话又说回来,如果我放弃了,那么现在就不会有博客了 。

经过大量研究,我发现Ruby具有一个包含的 , 扩展的和前置的钩子供我们使用(您猜对了)。

  • 来源: https : //ruby-doc.org/core-2.2.0/Module.html

这些挂钩使我们能够在包含 , 扩展或前置模块时执行代码,并猜测我们将要做什么?

当 包含 模块时, 我们将对其进行 扩展 (起初对我来说听起来很有趣)

让我们看一下钩子如何工作的一个小例子:

例如:

 模块HookedModule 
def self.included(base)
将“#{self}包含在#{base}中”
结束
结束类BaseObject
包括HookedModule
endBaseObject.new#=> HookedModule已包含在BaseObject中

这里需要注意的几件事:

  • 包含的内容必须是类方法,因为它是Module类的方法。 如果不将其声明为类方法,则该钩子将不起作用。
  • 传递给include的基本参数是您要从中包含模块的类,在本例中为BaseObject 。

现在,我对Rubys的钩子如何工作有了更好的了解,让我们回顾一下我的目标是:

  • 包含模块时 扩展 模块

太棒了! 让我们尝试在那里扩展类方法! ( 当需求完全告诉您您需要做什么时,您是否就喜欢它?)

 模块HookedModule 
def self.included(base)
base.extend ClassMethods
endmodule ClassMethods
def很棒吗?
写道:“是的,#{self}很棒,别问了。”
结束
结束
结束类BaseObject
包括HookedModule
endBaseObject.awesome? #=>“是的,BaseObject很棒,请停止询问。

进行这项工作的原因是,当我们第一次连接到include时,便可以通过base获得对BaseObject的访问权限。 然后,我们可以在BaseObject类上调用extend (一个类方法),其工作原理与我们刚才做的完全相同:

  BaseObject类 
扩展HookedModule
结束

首先,这似乎需要做很多工作,但是如果您想重用实例方法和类方法,那么必须同时包含和扩展YourModule毫无意义。

因此,我从这篇文章开始试图弄清楚这些gem如何提供魔术方法-我仍然不完全了解如何在不显式包含或排除模块的情况下(例如,另一篇博客文章的主题!)如何加载这些方法,但是我发现它们都是普通的类方法,我可以将其与Module一起使用以使我的类方法可重用。

我的经验:

  • 您可以在类初始化时运行方法。
  • 包括模块不包括类方法。
  • 模块具有挂钩,我们可以将其挂钩以简化API。

这是我写过的第一篇博客文章! 可能不是确切的最高级文章或撰写得最好的文章,但我仍在学习,因此,如果您有任何反馈意见,请务必发表评论,我将非常感谢他们!

就是这样了! 我的第一个Ruby Journey即将结束。 我喜欢在这里和那里探索Ruby的小技巧,因此希望以后再写一些博客文章。 在此之前,请安全穿越自己的Ruby土地!