`
andyhu1007
  • 浏览: 199767 次
  • 性别: Icon_minigender_1
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

Rails每周一题(十六): Evaluation in Ruby

阅读更多

Ruby的evaluation是一个很重要的功能,它可以eval一个字符串或者一个block。在一些适宜的情况下使用它会得到一些“意外”的效果。

 

常用的eval

 

Ruby常用的evaluation有:class_eval (module_eval),instance_evaleval

 

这三种evaluation方法可以在不同的情况下使用:

 

1. class_eval

 

class_eval和module_eval是相同的,class_eval是module_eval的一个alias。

 

class_eval可以在一个mod的上下文中eval一个字符串或者一个block,常用于给一个类添加方法(实例方法):

 

class Thing
end
   
a = %q{def hello() "Hello there!" end}
Thing.module_eval(a)
puts Thing.new.hello()  #=> "Hello there!"
 

2. instance_eval

 

instance_eval可以在一个实例的上下文中eval一个字符串或者一个block:

 

class Klass
  def initialize
    @secret = 99
  end
end

k = Klass.new
k.instance_eval { @secret }   #=> 99

 

3. eval

 

eval是在当前上下文中eval一个字符串,如果指定一个binding,则在binding的上下文中eval。

 

def getBinding(str)
  return binding
end
str = "hello"
eval "str + ' Fred'"                      #=> "hello Fred"
eval "str + ' Fred'", getBinding("bye")   #=> "bye Fred"
 

class_eval和instance_eval的不同

 

首先注意到class_eval和instance_eval的不同主要在于执行上下文(context)的不同。class_eval在一个mod的上下文中执行,而instance_eval在一个实例的上下文中执行。

 

其次,他们的常用场景不同。class_eval的应用场景一般是“打开一个类”来做一些事情,比如增加方法,或者是include一个module。

 

String.class_eval do
  include ExtraMethods

  def another_method
    ....
  end
end
 

而instance_eval主要关注于一个实例。

 

class Paginator
  def initialize total_entires
    @total_entries = total_entires
    @page_index = 0
  end

  def next
    @page_index += 1
  end
end
paginator = Paginator.new(100)
paginator.next
paginator.instance_eval "@page_index" #=> 1
paginator.instance_eval { @page_index } #=> 1
 

当然,我们也同样可以通过class_eval给Paginator类增加一个方法来获取page_index。

 

在我们了解instance_eval和class_eval之前,很可能会误用它们,比如通过下面的方法给Paginator增加一个实例方法:

 

Paginator.instance_eval do
  def baz
    "baz"
  end
end
 

结果:

 

Paginator.new.baz   #=> undefined method ‘baz’ for #<Foo:0x7dce8>

 

但我们偶然发现:

 

Paginator.baz   #=> "baz"
 

其实,如果我们了解ruby的对象模型,对这个结果并不会意外。我刚才已经说过:instance_eval关注于一个实例,它是在一个实例的上下文中执行的。Paginator类本身就是一个Class类的实例,所以Paginator.instance_eval做的就是给这个Class实例--Paginator--增加一个方法,也就是Paginator的类方法。

 

同样,我们可以通过instance_eval给任意类的实例增加方法,比如:

 

"good".instance_eval do 
  def opposite
     "bad"
  end
end

"good".opposite #=> "bad"
 

这个opposite方法就是"good"实例的一个singleton method。

 

instance_eval和DSL

 

DSL的一个主要特点是可以在不同的上下文中执行,下面就是一个例子(窃取自Jay Field举的例子):

 

 class SqlGenerator
   class << self
     def evaluate(&script)
       self.new.instance_eval(&script)
     end
   end

   def multiply(arg)
     "select #{arg}"
   end

   def two(arg=nil)
     "2#{arg}"
   end

   def times(arg)
     " * #{arg}"
   end
 end

 SqlGenerator.evaluate { multiply two times two }
 #=> "select 2 * 2"

 class Calculator
   class << self
     def evaluate(&script)
       self.new.instance_eval(&script)
     end
   end

   def multiply(arg)
     eval arg
   end

   def two(arg=nil)
     "2#{arg}"
   end

   def times(arg)
     " * #{arg}"
   end
 end

 Calculator.evaluate { multiply two times two }
 #=> 4
  
 

简单得介绍了一下ruby的evaluation,要了解更多,可以看下面这两篇文章:

 

http://www.infoq.com/articles/eval-options-in-ruby

 

http://blog.jayfields.com/2007/03/ruby-instanceeval-and-classeval-method.html

分享到:
评论
7 楼 ray_linn 2010-05-18  
eval的速度也是慢得可以
6 楼 orcl_zhang 2010-05-18  
>> Thing.my_class_eval do
?>  def say_hi
>>   puts 'hi---'
>>  end
>> end
=> nil
>> Thing.say_hi
hi---

为哈子我的还是public的呢?
>> "good".instance_eval do 
?>   def opposite
>>      "bad"
>>   end
>> end
=> nil
>> 
?> "good".opposite #=> "bad"
NoMethodError: undefined method `opposite' for "good":String
	from (irb):51
>> a='good'
=> "good"
>> a.instance_eval do 
?>  def ss
>>   'ss'
>>  end
>> end
=> nil
>> a.ss
=> "ss"

1.87下跑的。结果不太一样。
5 楼 night_stalker 2009-08-04  
在 Thing 里头加一个 public 就行了 ……
Thing;  public;end


public、private 会传播是个陷阱 …… def 之前最好标一标

ps:class 和 module 会返回块内最后一条语句的值。
class T;  @@a = 3;end
a = class T;@@a;end #=> 3
4 楼 Hooopo 2009-08-03  
我觉得class_eval和instance_eval这两个名字起的有些晦涩,还有module_eval和class_eval是一个意思这也让人难以理解。。。
我觉得class_eval如果这样比较合理些:


class Thing
  
end

class Module
  def my_class_eval(*args)
    if block_given?
      yield
    else
      eval *args
    end
  end

end
str = %q{
  def hello
    puts "hello"
  end
}

Thing.my_class_eval(str)
Thing.my_class_eval do
  def say_hi
    puts "Hi~~"
  end
end
Thing.hello # => hello
Thing.send(:say_hi) # => Hi~~
#不知道为什么用block后成了private方法,只好用send了。。

3 楼 night_stalker 2009-08-03  
Hooopo 写道
原来
SqlGenerator.evaluate { multiply two times two }  

SqlGenerator.evaluate { multiply(two(times(two))) }  

的意思啊 ,看起来好神秘。。


可以把空格理解为右结合的运算符 ~


ruby 1.9 还有一种 eval 方法
is = RubyVM::InstructionSequence.compile('1+1')
is.eval


这个东西还能用来看 YARV 字节码:
pp is.to_a
puts is.disasm
2 楼 Hooopo 2009-08-03  
原来
SqlGenerator.evaluate { multiply two times two }  

SqlGenerator.evaluate { multiply(two(times(two))) }  

的意思啊 ,看起来好神秘。。
1 楼 jinleileiking 2009-08-03  
ruby for rails 这本书里介绍得比较详细

相关推荐

    Ruby on Rails入门经典代码

    Ruby on Rails,简称Rails,是基于Ruby语言的一个开源Web应用程序框架,它遵循MVC(Model-View-Controller)架构模式,旨在使Web开发过程更加高效、简洁。本压缩包中的"Ruby on Rails入门经典代码"提供了新手学习...

    Ruby on Rails入门例子

    Ruby on Rails,简称Rails,是一种基于Ruby语言的开源Web应用程序框架,它遵循MVC(Model-View-Controller)架构模式,旨在使Web开发过程更加高效、简洁。本篇将通过一个入门实例,深入探讨Rails的基本概念和核心...

    SOA系列:开源框架Ruby on Rails

    **Ruby on Rails (RoR 或 Rails)** 是一个使用 Ruby 语言编写的开源 Web 应用框架,该框架自诞生以来就以其简单易用著称,并且严格遵循 MVC(Model-View-Controller)设计模式。Rails 的设计理念之一是减少开发过程...

    Ruby on Rails Guides v2 - Ruby on Rails 4.2.5

    ### Ruby on Rails Guides v2 - Ruby on Rails 4.2.5 #### 一、重要概念及基础假设 - **重要概念**:本指南旨在帮助读者深入理解Ruby on Rails(以下简称Rails)4.2.5版本的核心功能与最佳实践。 - **基础假设**:...

    NetBeans Ruby and Rails IDE with JRuby 2009

    总结来说,《NetBeans Ruby and Rails IDE with JRuby 2009》是一本详尽介绍了如何使用NetBeans作为Ruby和Rails开发工具的指南。它不仅覆盖了从安装到日常开发的所有方面,还深入探讨了如何利用NetBeans的各种高级...

    ruby安装升级及命令自行编译安装非APTGET方式安装升级的办法

    作为Ruby应用开发中的主流框架之一,Rails可以通过RubyGems轻松安装。执行命令`gem install rails -y`即可一键安装Rails及其所有依赖包。例如: ```bash gem install rails -y ``` 安装完成后,可以使用`gem list`...

    ruby on rails 101

    《Ruby on Rails 101》是一本介绍Ruby on Rails(简称RoR或ROR)的基础书籍,旨在为初学者提供一个全面而深入的学习框架。本书由Peter Marklund编写,包含了五天课程的演示文稿和相关资料,覆盖了从安装到实际应用...

    Ruby+for+Rails

    **Ruby for Rails** Ruby是一种面向对象的动态编程语言,它以其简洁、优雅的语法和强大的元编程能力而闻名。在Web开发领域,Ruby与Rails框架的结合,即Ruby on Rails(RoR),开创了Web应用的新纪元。Ruby on Rails...

    ruby on rails 开发环境包(ruby1.8.7,rails2.2.3)

    Ruby on Rails,简称Rails,是由David Heinemeier Hansson创建的一种基于Ruby语言的开源Web应用程序框架,它遵循MVC(模型-视图-控制器)架构模式,旨在提高开发效率和可读性。在这个开发环境包中,我们拥有Ruby ...

    rails-docker-compose:Ruby on Rails的Docker开发环境

    使用Docker开发Ruby on Rails的配置文件 docker-compose up 利润! 你得到什么 一线开发环境的设置和启动: docker-compose up 。 一个易于安装的依赖关系可在新计算机上进行编码:Docker。 (与使用Vagrant时的两...

    ruby on rails最新版

    Ruby on Rails,简称Rails,是基于Ruby编程语言的一个开源Web应用程序框架,它遵循MVC(模型-视图-控制器)架构模式,旨在提高开发效率和代码的可读性。Rails以其“约定优于配置”(Convention over Configuration)...

    Ruby on Rails实践

    Ruby on Rails,简称Rails,是由David Heinemeier Hansson基于Ruby语言开发的一个开源Web应用程序框架。这个框架遵循“约定优于配置”(Convention over Configuration)的原则,致力于简化Web应用的开发流程,提高...

    Ruby on Rails安装包全集(Linux)

    Ruby on Rails是一款基于Ruby语言的开源Web开发框架,它遵循MVC(模型-视图-控制器)架构模式,简化了Web应用的开发流程。在Linux环境下安装Ruby on Rails需要一系列的依赖包和步骤,本资源包提供了所需的所有组件,...

    ruby rails demo

    ruby rails demo, rails 简单demo。 (1)到ruby官网:http://www.ruby-lang.org/en/下载window安装包,并安装, ruby版本: ruby -v (2)安装Rails3 gem install rails (3)安装sqlite3 gem install sqlite3-ruby 安装...

    Web开发:Ruby on Rails.pdf

    Web开发:Ruby on Rails.pdf

    Ruby - Ruby for Rails

    ### 一、Ruby/Rails 景观 #### 1.1 如何理解 Ruby 的工作原理 - **基础概念**:介绍 Ruby 作为一种动态类型的面向对象编程语言的基础知识。 - **解释器与虚拟机**:讲解 Ruby 是如何通过解释器或虚拟机运行的。 - *...

    Ruby On Rails中文教材(PDF)

    Ruby on Rails,简称Rails,是一款基于Ruby语言的开源Web应用框架,它遵循MVC(Model-View-Controller)架构模式,旨在简化Web应用程序的开发。Rails由David Heinemeier Hansson于2004年创建,它提倡“约定优于配置...

    rails2.3.8 && ruby1.8.7

    Ruby on Rails(通常简称为Rails)是一个基于Ruby语言的开源Web应用程序框架,它遵循模型-视图-控制器(MVC)架构模式,用于简化Web应用的开发。Ruby 1.8.7是这个框架运行所依赖的特定版本的Ruby解释器。 描述中...

    Ruby on Rails教程:学习使用Rails进行Web开发Ruby on Rails Tutorial: Learn Web Development with Rails

    本书教您如何使用Ruby on Rails开发和部署真正的,具有工业实力的Web应用程序,Ruby on Rails是为诸如Twitter,Hulu,GitHub和Yellow Pages等顶级网站提供支持的开源Web框架。

Global site tag (gtag.js) - Google Analytics