`

分析ActiveRecord使用method_missing和respond_to?实现动态方法

阅读更多
method_missing经常用来写Ruby的元编程。例如,如果你的UserModel有个email的属性,你就可以通过
User.find_by_email('joe@example.com')
来查找,这是如果User并没有定义这个方法,那么ActiveRecord::Base就会处理这样的请求。后面我们会具体分析这过程的逻辑和实现,并学习处理。

respond_to?在实现动态编程中也经常会用到,通常我们在使用respond之前判断是否有respond。
那么我们具体看看实现:
假设我们有Legislator类,我们将实现从find_by_first_name('John') 到find(:first_name => 'John')的动态逻辑
如下:
class Legislator
  # Pretend this is a real implementation
  def find(conditions = {})
  end
  
  # Define on self, since it's  a class method
  def self.method_missing(method_sym, *arguments, &block)
    # the first argument is a Symbol, so you need to_s it if you want to pattern match
    if method_sym.to_s =~ /^find_by_(.*)$/
      find($1.to_sym => arguments.first)
    else
      super
    end
  end
end


按照道理来说,这是通过样的逻辑,只是Legislator.respond_to?(:find_by_first_name)会返回false那么我们需要respond_to?来支持。

class Legislator
  # ommitted
  
  # It's important to know Object defines respond_to to take two parameters: the method to check, and whether to include private methods
  # http://www.ruby-doc.org/core/classes/Object.html#M000333
  def self.respond_to?(method_sym, include_private = false)
    if method_sym.to_s =~ /^find_by_(.*)$/
      true
    else
      super
    end
  end
end



那么现在有一个问题,就是我们的重复了。这就很不DRY。所以,我们可以和ActiveRecord的学习,看看是怎么处理重复的问题的。实际上ActiveRecord把逻辑封装在了ActiveRecord::DynamicFinderMatch以便不会在method_missing 和respond_to?重复代码

class LegislatorDynamicFinderMatch
  attr_accessor :attribute
  def initialize(method_sym)
    if method_sym.to_s =~ /^find_by_(.*)$/
      @attribute = $1.to_sym
    end
  end
  
  def match?
    @attribute != nil
  end
end

class Legislator
  def self.method_missing(method_sym, *arguments, &block)
    match = LegislatorDynamicFinderMatch.new(method_sym)
    if match.match?
      find(match.attribute => arguments.first)
    else
      super
    end
  end

  def self.respond_to?(method_sym, include_private = false)
    if LegislatorDynamicFinderMatch.new(method_sym).match?
      true
    else
      super
    end
  end
end



method_missing的缓冲

显然method missing效率不好,那么太多的method missing一定导致很慢。所以另外一个我们可以学习ActiveRecord的地方是我们可以在定义method missing的同时发送到正定义的方法,如下:
class Legislator    
  def self.method_missing(method_sym, *arguments, &block)
    match = LegislatorDynamicFinderMatch.new(method_sym)
    if match.match?
      define_dynamic_finder(method_sym, match.attribute)
      send(method_sym, arguments.first)
    else
      super
    end
  end
  
  protected
  
  def self.define_dynamic_finder(finder, attribute)
    class_eval <<-RUBY
      def self.#{finder}(#{attribute})        # def self.find_by_first_name(first_name)
        find(:#{attribute} => #{attribute})   #   find(:first_name => first_name)
      end                                     # end
    RUBY
  end
end


测试
创建LegislatorDynamicFinderMatch来测试逻辑,下面是RSpec的例子:

describe LegislatorDynamicFinderMatch do
  describe 'find_by_first_name' do
    before do
      @match = LegislatorDynamicFinderMatch.new(:find_by_first_name)
    end
      
    it 'should have attribute :first_name' do
      @match.attribute.should == :first_name
    end
    
    it 'should be a match' do
      @match.should be_a_match
    end
  end
  
  describe 'zomg' do
    before do
      @match = LegislatorDynamicFinderMatch(:zomg)
    end
    
    it 'should have nil attribute' do
      @match.attribute.should be_nil
    end
    
    it 'should not be a match' do
      @match.should_not be_a_match
    end
  end
end


当然,如果你的动态实习需要一些输入的话,很难免你需要用到RSpec,如下:
describe Legislator, 'dynamic find_by_first_name' do
  it 'should call find(:first_name => first_name)' do
    Legislator.should_receive(:find).with(:first_name => 'John')
    
    Legislator.find_by_first_name('John')
  end
end

总之,如果你正在写动态方法你应该考虑respond_to?
2
0
分享到:
评论

相关推荐

    ruby元编程之创建自己的动态方法

    本文将深入探讨如何利用`method_missing`和`respond_to?`来创建动态方法,这是一种在Ruby社区中广泛使用的技巧,尤其是在诸如Rails这样的框架中。 #### 二、`method_missing`详解 `method_missing`是Ruby中的一个...

    Ruby学习思维导图.pdf

    - **Object#respond_to?**:检查是否可以调用某个方法。 - **Object#method**:获取方法对象。 - **Object#class_eval**:在类的上下文中执行代码。 - **Object#instance_eval**:在对象的上下文中执行代码。 #### ...

    marlett_01_0109.pdf

    marlett_01_0109

    [AB PLC例程源码][MMS_040384]Winder Application.zip

    AB PLC例程代码项目案例 【备注】 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用!有问题请及时沟通交流。 2、适用人群:计算机相关专业(如计科、信息安全、数据科学与大数据技术、人工智能、通信、物联网、自动化、电子信息等)在校学生、专业老师或者企业员工下载使用。 3、用途:项目具有较高的学习借鉴价值,不仅适用于小白学习入门进阶。也可作为毕设项目、课程设计、大作业、初期项目立项演示等。 4、如果基础还行,或热爱钻研,亦可在此项目代码基础上进行修改添加,实现其他不同功能。 欢迎下载!欢迎交流学习!不清楚的可以私信问我!

    stassar_3cd_01_0716.pdf

    stassar_3cd_01_0716

    malpass_02_0907.pdf

    malpass_02_0907

    [AB PLC例程源码][MMS_046459]InView on EtherNet Add On Instruction.zip

    AB PLC例程代码项目案例 【备注】 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用!有问题请及时沟通交流。 2、适用人群:计算机相关专业(如计科、信息安全、数据科学与大数据技术、人工智能、通信、物联网、自动化、电子信息等)在校学生、专业老师或者企业员工下载使用。 3、用途:项目具有较高的学习借鉴价值,不仅适用于小白学习入门进阶。也可作为毕设项目、课程设计、大作业、初期项目立项演示等。 4、如果基础还行,或热爱钻研,亦可在此项目代码基础上进行修改添加,实现其他不同功能。 欢迎下载!欢迎交流学习!不清楚的可以私信问我!

    matlab程序代码项目案例:matlab程序代码项目案例文档+程序具有输出LC滤波器的三相逆变器的前馈神经网络模型预测控制.zip

    matlab程序代码项目案例 【备注】 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用!有问题请及时沟通交流。 2、适用人群:计算机相关专业(如计科、信息安全、数据科学与大数据技术、人工智能、通信、物联网、自动化、电子信息等)在校学生、专业老师或者企业员工下载使用。 3、用途:项目具有较高的学习借鉴价值,不仅适用于小白学习入门进阶。也可作为毕设项目、课程设计、大作业、初期项目立项演示等。 4、如果基础还行,或热爱钻研,亦可在此项目代码基础上进行修改添加,实现其他不同功能。 欢迎下载!欢迎交流学习!不清楚的可以私信问我!

    matlab程序代码项目案例:matlab程序代码项目案例基于运动学车辆模型的开放式驾驶MPC横向控制算法.zip

    matlab程序代码项目案例 【备注】 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用!有问题请及时沟通交流。 2、适用人群:计算机相关专业(如计科、信息安全、数据科学与大数据技术、人工智能、通信、物联网、自动化、电子信息等)在校学生、专业老师或者企业员工下载使用。 3、用途:项目具有较高的学习借鉴价值,不仅适用于小白学习入门进阶。也可作为毕设项目、课程设计、大作业、初期项目立项演示等。 4、如果基础还行,或热爱钻研,亦可在此项目代码基础上进行修改添加,实现其他不同功能。 欢迎下载!欢迎交流学习!不清楚的可以私信问我!

    matsumoto_01_1107.pdf

    matsumoto_01_1107

    [AB PLC例程源码][MMS_045719]Rotary Knife with SoftLogix.zip

    AB PLC例程代码项目案例 【备注】 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用!有问题请及时沟通交流。 2、适用人群:计算机相关专业(如计科、信息安全、数据科学与大数据技术、人工智能、通信、物联网、自动化、电子信息等)在校学生、专业老师或者企业员工下载使用。 3、用途:项目具有较高的学习借鉴价值,不仅适用于小白学习入门进阶。也可作为毕设项目、课程设计、大作业、初期项目立项演示等。 4、如果基础还行,或热爱钻研,亦可在此项目代码基础上进行修改添加,实现其他不同功能。 欢迎下载!欢迎交流学习!不清楚的可以私信问我!

    QT第五课-QT系统相关-文件

    代码

    大模型创业者手册-法务与产品合规篇.pdf

    大模型创业者手册-法务与产品合规篇.pdf

    [AB PLC例程源码][MMS_046456]ME Equipment Status Summary Faceplate for PowerFlex, Kinetix, E3 Plus,.zip

    AB PLC例程代码项目案例 【备注】 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用!有问题请及时沟通交流。 2、适用人群:计算机相关专业(如计科、信息安全、数据科学与大数据技术、人工智能、通信、物联网、自动化、电子信息等)在校学生、专业老师或者企业员工下载使用。 3、用途:项目具有较高的学习借鉴价值,不仅适用于小白学习入门进阶。也可作为毕设项目、课程设计、大作业、初期项目立项演示等。 4、如果基础还行,或热爱钻研,亦可在此项目代码基础上进行修改添加,实现其他不同功能。 欢迎下载!欢迎交流学习!不清楚的可以私信问我!

    指标体系数据开发.pptx

    指标体系数据开发

    半导体三极管β值测量仪的设计与制作

    半导体三极管β值测量仪的设计与制作

    [AB PLC例程源码][MMS_047416]ME Faceplates-AOIs for GuardLogix Safety Systems.zip

    AB PLC例程代码项目案例 【备注】 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用!有问题请及时沟通交流。 2、适用人群:计算机相关专业(如计科、信息安全、数据科学与大数据技术、人工智能、通信、物联网、自动化、电子信息等)在校学生、专业老师或者企业员工下载使用。 3、用途:项目具有较高的学习借鉴价值,不仅适用于小白学习入门进阶。也可作为毕设项目、课程设计、大作业、初期项目立项演示等。 4、如果基础还行,或热爱钻研,亦可在此项目代码基础上进行修改添加,实现其他不同功能。 欢迎下载!欢迎交流学习!不清楚的可以私信问我!

    [AB PLC例程源码][MMS_041473]Input Time Stamping.zip

    AB PLC例程代码项目案例 【备注】 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用!有问题请及时沟通交流。 2、适用人群:计算机相关专业(如计科、信息安全、数据科学与大数据技术、人工智能、通信、物联网、自动化、电子信息等)在校学生、专业老师或者企业员工下载使用。 3、用途:项目具有较高的学习借鉴价值,不仅适用于小白学习入门进阶。也可作为毕设项目、课程设计、大作业、初期项目立项演示等。 4、如果基础还行,或热爱钻研,亦可在此项目代码基础上进行修改添加,实现其他不同功能。 欢迎下载!欢迎交流学习!不清楚的可以私信问我!

    本文将带你深入了解如何使用OpenCV库实现图片拼接技术,打造令人惊叹的全景图像。通过清晰的步骤讲解和代码示例

    本文将带你深入了解如何使用OpenCV库实现图片拼接技术,打造令人惊叹的全景图像。通过清晰的步骤讲解和代码示例

    nicholl_01_0508.pdf

    nicholl_01_0508

Global site tag (gtag.js) - Google Analytics