在类体中声明的Ruby方法调用

Are*_*ian 59 ruby ruby-on-rails

我刚开始在rails上学习ruby,我遇到过如下代码:

class Post < ActiveRecord::Base
 validates_presence_of   :title
 belongs_to :user
end
Run Code Online (Sandbox Code Playgroud)

类体内有两个方法调用.我很难找到任何描述如何在类的主体内(但在任何方法之外)进行方法调用的ruby文档.我拥有的所有书籍,仅描述了如何定义类和实例方法以及如何从其他方法中调用它们.

我的问题是:如何以及何时调用这些方法?他们是如何定义的?它们是否在某些活动记录模块中定义了mixins?

Chu*_*uck 35

类定义的主体是代码的执行上下文,就像任何其他代码一样.代码在类的上下文中执行(意思self是类对象,它是Class的一个实例).您可以拥有本地变量和实例变量(它们将属于类对象本身而不是类的实例),您可以调用类对象响应的任何方法.类定义块完成后运行代码.

在这种情况下,ActiveRecord :: Base定义了类方法validates_presence_ofbelongs_to.


Joh*_*ley 18

Yehuda Katz在他的博客上对此有一个很好的解释.见第4点:类体不是特殊的.


Lar*_*y K 12

Re:如何以及何时调用这些方法?

[他们在班级加载时被调用.您可以在其中一个方法中放置一个断点,并看到它是作为rails项目启动的一部分调用的.]

他们是如何定义的?

[他们是阶级方法.由于这是红宝石,它们可以通过多种方式定义.]

它们是否在某些活动记录模块中定义了mixins?

[在这种情况下,

validates_presence_of在vendor/rails/activerecord/lib/active_record/validations.rb中定义.

belongs_to在vendor/rails/activerecord/lib/active_record/associations.rb中定义

ActiveRecord是一个很大的系统,包括许多mixins,模块等.

注意,要查看方法的定义,我使用http://www.gotapi.com/rubyrails 作为每种方法,请参阅定义底部的"显示源"链接.

]


Cor*_*ook 11

这些是类方法或"单例"方法.您应该熟悉的是attr_accessor.我们可以在测试类中实现类似的东西.

class Klass
  def self.add_getter_and_setter(symbol)
    module_eval "def #{symbol}; @#{symbol}; end"
    module_eval "def #{symbol}=(val); @#{symbol} = val; end"
  end
end

class Person < Klass
  add_getter_and_setter :name
  add_getter_and_setter :phone
end

person = Person.new
person.name = 'John Smith'
person.phone = '555-2344'
person # returns <Person:0x28744 @name="John Smith", @phone="555-2344">
Run Code Online (Sandbox Code Playgroud)

在上面的例子中,我们使用'def self.add_getter_and_setter'创建了类方法,但这不是唯一的方法.

class Klass
  class << self # opens the singleton class
    def add_getter_and_setter(symbol)  # note we dont specify self as it is already within the context of the singleton class
      ..
    end
  end
end
Run Code Online (Sandbox Code Playgroud)

使用扩展.Module#extend是一个使用类方法扩展类的方法,同样方法Module #include包含一个带有实例方法的类.

class Klass
  extend(Module.new do
    def add_getter_and_setter(symbol)
      ..
    end
  end)
end
Run Code Online (Sandbox Code Playgroud)

如果已经定义了Klass,我们可以重新打开它来添加类方法

class Klass
end

def Klass.add_getter_and_setter(symbol)
  ..
end

# or 

class << Klass
  def add_getter_and_setter(symbol)
    ..
  end
end
Run Code Online (Sandbox Code Playgroud)

那些是我知道如何做到这一点的几种方式,所以如果你看到不同的语法只是意识到它都在做同样的事情.

注意:在rails中,我们都使用的常见类方法是"find".它直接在Model类之外运行.

person = Person.find(1) # finds a person with id:1
Run Code Online (Sandbox Code Playgroud)


Cod*_*lan 3

您所看到的是 ActiveRecord 对象的类级方法。要编写您自己的方法来执行类似的操作,您可以将它们编写为插件,然后通过重新打开类定义将它们包含到 ActiveRecord 中。创建插件的 Ruby on Rails 指南:

http://guides.rubyonrails.org/plugins.html

涵盖如何编写这样的插件/类级方法。这是一个很好的文档,介绍了如何理解这些方法的含义以及它们如何与实例交互。