美文网首页
译:Ruby动态方法

译:Ruby动态方法

作者: 李小西033 | 来源:发表于2017-01-14 16:10 被阅读36次

通常情况下,我们使用关键字def来定义方法。
但是当有一系列方法具有相同的结构和逻辑时,继续这样做未免显得有些重复并且违反了DRY原则。
Ruby,作为一个动态语言,允许你在运行时定义方法。
那么,这是什么意思呢?
来看一个最简单的例子:

class A
  define_method :a do
    puts "hello"
  end
  define_method :greeting do |message|
    puts message
  end
end

A.new.a #=> hello
A.new.greeting 'Ram ram' #=> Ram ram

define_method 用来定义实例方法,下面的例子展示更加贴合实际的使用场景。

  class User
    ACTIVE = 0
    INACTIVE = 1
    PENDING = 2
    attr_accessor :status

    def active?
      status == ACTIVE
    end

    def inactive?
      status == User::INACTIVE
    end

    def pending?
      status == User::PENDING
    end
  end

  user = User.new
  user.status = 1

  user.inactive?
  #=> true
  user.active?
  #=> false

使用动态方法定义重构:

  class User
    ACTIVE = 0
    INACTIVE = 1
    PENDING = 2
    attr_accessor :status

    [:active, :inactive, :pending].each do |method|
      define_method “#{method}?” do
        status == User.const_get(method.upcase)
      end
    end
  end

  user = User.new
  user.status = 1

  user.inactive?
  #=> true
  user.active?
  #=> false

我们使用了define_method来动态的定义方法。

我们也可以使用类方法来定义实例方法,利用这一点我们可以暴露一个用来生成实例方法的类方法。COOL!
例如:

  class User
    ACTIVE = 0
    INACTIVE = 1
    PENDING = 2
    attr_accessor :status

    def self.states(*args)
      args.each do |arg|
        define_method “#{arg}?” do
          self.status == User.const_get(arg.upcase)
        end
      end
    end

    states :active, :inactive, :pending
  end

定义类方法最简单的方式则为:

class A
  class << self
    define_method method_name do
      #...
    end
  end
end

也可以使用 instance_evalclass_eval来动态定义方法。这些方法允许运行特定类或方法中的任意代码。这些方法有时候很让人迷惑,你可以看看 stackoverflow上的讨论或者读读博客来理解它们的用法。

stackoverflow上的讨论我们可以总结如下:

  Foo = Class.new
  Foo.class_eval do
    def class_bar
      “class_bar”
    end
  end
  Foo.instance_eval do
    def instance_bar
      “instance_bar”
    end
  end
  Foo.class_bar       #=> undefined method ‘class_bar’ for Foo:Class
  Foo.new.class_bar   #=> “class_bar”
  Foo.instance_bar       #=> “instance_bar”
  Foo.new.instance_bar   #=> undefined method ‘instance_bar’ for #<Foo:0x7dce8>

注意,我们没有在_eval中使用define_method*,因为如下例所示,不管在class_eval还是instance_eval内使用define_method方法,它最终定义的都是实例方法。

  Foo = Class.new
  Foo.class_eval do
    define_method “class_bar” do
      “class_bar”
    end
  end
  Foo.instance_eval do
    define_method “instance_bar” do
      “instance_bar”
    end
  end

  Foo.class_bar #=> undefined
  Foo.new.class_bar #=> “class_bar”
  Foo.instance_bar #=> undefined
  Foo.new.instance_bar #=> “instance_bar”

接下来,我们来看看方法的动态调用。Ruby中一个动态调用方法的方式是向对象发送消息。我们可以向类或类定义本身发送消息发送消息,或者只是发送给类对象。这些都可以通过调用send方法完成。
最简单的例子如下:

  s= “hi man”

  p s.length #=> 6
  p s.include? “hi” #=> true

  p s.send(:length) #=> 6
  p s.send(:include?,”hi”) #=> true

这个方法在什么时候有用呢?
来看看下面这段代码(取例自:http://www.funonrails.com/2011/12/dynamic-methods-inside-ruby-classes.html)

  class ApplicationController < ActionController::Base
    protect_from_forgery
    helper_method :current_staff, :current_employee, current_admin

    def authenticate_staff!(opts={})
      current_staff || not_authorized
    end

    def current_staff
      current_user if current_user.is_a? Staff
    end

    def authenticate_employee!(opts={})
      current_employee || not_authorized
    end

    def current_employee
      current_user if current_user.is_a? Employee
    end

    def authenticate_admin!(opts={})
      current_admin || not_authorized
    end

    def current_admin
      current_user if current_user.is_a? Admin
    end
  end

使用send方法重构:

  %w(Staff Employee Admin).each do |k|
    define_method “current_#{k.underscore}” do
      current_user if current_user.is_a?(k.constantize)
    end

    define_method “authenticate_#{k.underscore}!” do |opts={}|
      send(“current_#{k.underscore}”) || not_authorized
    end
  end

动态方法定义能够减少方法定义的错误,减少重复并且简化代码
享受元编程吧~
原文:http://rohitrox.github.io/2013/07/02/ruby-dynamic-methods/

相关文章

  • 译:Ruby动态方法

    通常情况下,我们使用关键字def来定义方法。但是当有一系列方法具有相同的结构和逻辑时,继续这样做未免显得有些重复并...

  • 我眼中的元编程-方法篇

    Ruby是一门动态语言,动态创建与调用方法是其中一个体现。 动态方法 动态调用方法(动态派发) 动态调用方法,是指...

  • Ruby动态方法初探

    1.方法的动态调用 为何Ruby如此先进,为何它元编程能力这么强大,得益于它能够运行时生成需要的代码,或者调用相应...

  • Ruby中的动态方法

    一、什么是动态方法?这就要从静态语言和动态语言的区别说起,静态语言比如Java,在编译阶段就需要运行对象调用的所有...

  • Ruby元编程笔记 - 方法

    Dynamic Method 通过send()去动态调用方法: 在Ruby2.2.2中,send()依然可以调用私...

  • Ruby的动态特性

    Ruby动态特性的体现 动态执行字符串形式的代码。 动态获取模块或类中的常量和变量值 动态为类或者对象添加方法 对...

  • Ruby 语言进阶

    Intro to Ruby (Ruby 基础) 什么是ruby?ruby是动态的(没有固定的类型),反射性的,面向...

  • 任务301 Ruby 基础

    1、Ruby 简介 Ruby 是一种面向对象、命令式、函数式、动态的通用编程语言。详细介绍请看:Ruby 2、Ru...

  • From Objective-C to Ruby(4)-类和模块

    类 定义类 OC: ruby: 初始化方法 OC: ruby: 实例变量和属性 OC: ruby: 类方法和对象方...

  • Go编写Ruby扩展

    本文将会介绍,使用Go语言编写 Ruby的扩展程序 Ruby-FFI Ruby-FFI 是一个以编程的方式加载动态...

网友评论

      本文标题:译:Ruby动态方法

      本文链接:https://www.haomeiwen.com/subject/nsiebttx.html