Ruby 魔法 学习笔记之一_ruby专题

一、向对象显示的发送消息
我们可以向对象直接发送消息:
Ruby代码

复制代码 代码如下:

class HelloWorld
def say(name)
print "Hello, ", name
end
end
hw = HelloWorld.new
hw.send(:say,"world")

我们通常使用hw.say("world"),但send可以对private的方法起作用。
不光如此send可以使程序更加动态,下面我们看看一个例子:
我们定义了一个类Person,我们希望一个包含Person对象的数组能够按
照Person的任意成员数据来排序:
Ruby代码

复制代码 代码如下:

class Person
attr_reader :name,:age,:height
def initialize(name,age,height)
@name,@age,@height = name,age,height
end
def inspect
"#@name #@age #@height"
end
end

在ruby中任何一个类都可以随时打开的,这样可以写出像2.days_ago这样优美
的code,我们打开Array,并定义一个sort_by方法:
Ruby代码
class Array
def sort_by(sysm)
self.sort{|x,y| x.send(sym) <=> y.send(sym)}
end
end
我们看看运行结果:
Ruby代码
people = []
people << Person.new("Hansel",35,69)
people << Person.new("Gretel",32,64)
people << Person.new("Ted",36,68)
people << Person.new("Alice", 33, 63)
p1 = people.sort_by(:name)
p2 = people.sort_by(:age)
p3 = people.sort_by(:height)
p p1 # [Alice 33 63, Gretel 32 64, Hansel 35 69, Ted 36 68]
p p2 # [Gretel 32 64, Alice 33 63, Hansel 35 69, Ted 36 68]
p p3 # [Alice 33 63, Gretel 32 64, Ted 36 68, Hansel 35 69]
这个结果是如何得到的呢?
其实除了send外还有一个地方应该注意attr_reader,attr_reader相当于定义了name,
age,heigh三个方法,而Array里的sort方法只需要提供一个比较方法:
x.send(sym) <=> y.send(sym) 通过send得到person的属性值,然后在使用<=>比较
二、定制一个object
<< object
ruby不仅可以打开一个类,而且可以打开一个对象,给这个对象添加或定制功能,而不影响
其他对象:
Ruby代码
a = "hello"
b = "goodbye"
def b.upcase
gsub(/(.)(.)/)($1.upcase + $2)
end
puts a.upcase #HELLO
puts b.upcase #GoOdBye
我们发现b.upcase方法被定制成我们自己的了
如果想给一个对象添加或定制多个功能,我们不想多个def b.method1 def b.method2这么做
我们可以有更模块化的方式:
Ruby代码
b = "goodbye"
class << b
def upcase # create single method
gsub(/(.)(.)/) { $1.upcase + $2 }
end
def upcase!
gsub!(/(.)(.)/) { $1.upcase + $2 }
end
end
puts b.upcase # GoOdBye
puts b # goodbye
b.upcase!
puts b # GoOdBye
这个class被叫做singleton class,因为这个class是针对b这个对象的。
和设计模式singleton object类似,只会发生一次的东东我们叫singleton.
<< self 给你定义的class添加行为
Ruby代码
class TheClass
class << self
def hello
puts "hello!"
end
end
end
TheClass.hello #hello!
<<self修改了你定义class的class,这是个很有用的技术,他可以定义class级别
的helper方法,然后在这个class的其他的定义中使用。下面一个列子定义了访问
函数,我们希望访问的时候把成员数据都转化成string,我们可以通过这个技术来
定义一个Class-Level的方法accessor_string:
Ruby代码
class MyClass
class << self
def accessor_string(*names)
names.each do |name|
class_eval <<-EOF
def #{name}
@#{name}.to_s
end
EOF
end
end
end
def initialize
@a = [ 1, 2, 3 ]
@b = Time.now
end
accessor_string :a, :b
end
o = MyClass.new
puts o.a # 123
puts o.b # Fri Nov 21 09:50:51 +0800 2008
通过extend module给你的对象添加行为,module里面的方法变成了对象里面的
实例方法:
Ruby代码
module Quantifier
def any?
self.each { |x| return true if yield x }
false
end
def all?
self.each { |x| return false if not yield x }
true
end
end
list = [1, 2, 3, 4, 5]
list.extend(Quantifier)
flag1 = list.any? {|x| x > 5 } # false
flag2 = list.any? {|x| x >= 5 } # true
flag3 = list.all? {|x| x <= 10 } # true
flag4 = list.all? {|x| x % 2 == 0 } # false
三、创建一个可参数化的类:
如果我们要创建很多类,这些类只有类成员的初始值不同,我们很容易想起:
Ruby代码
class IntelligentLife # Wrong way to do this!
@@home_planet = nil
def IntelligentLife.home_planet
@@home_planet
end
def IntelligentLife.home_planet=(x)
@@home_planet = x
end
#...
end
class Terran < IntelligentLife
@@home_planet = "Earth"
#...
end
class Martian < IntelligentLife
@@home_planet = "Mars"
#...
end
这种方式是错误的,实际上Ruby中的类成员不仅在这个类中被所有对象共享,
实际上会被整个继承体系共享,所以我们调用Terran.home_planet,会输出
“Mars”,而我们期望的是Earth
一个可行的方法:
我们可以通过class_eval在运行时延迟求值来达到目标:
Ruby代码
class IntelligentLife
def IntelligentLife.home_planet
class_eval("@@home_planet")
end
def IntelligentLife.home_planet=(x)
class_eval("@@home_planet = #{x}")
end
#...
end
class Terran < IntelligentLife
@@home_planet = "Earth"
#...
end
class Martian < IntelligentLife
@@home_planet = "Mars"
#...
end
puts Terran.home_planet # Earth
puts Martian.home_planet # Mars
最好的方法:
我们不使用类变量,而是使用类实例变量:
Ruby代码
class IntelligentLife
class << self
attr_accessor :home_planet
end
#...
end
class Terran < IntelligentLife
self.home_planet = "Earth"
#...
end
class Martian < IntelligentLife
self.home_planet = "Mars"
#...
end
puts Terran.home_planet # Earth
puts Martian.home_planet # Mars
四、Ruby中的Continuations:
Continuations恐怕是Ruby中最难理解的概念了,它可以处理非局部的跳转,
它保存了返回地址和执行的环境,和c中的setjmp和longjump类似,但它保存
了更多的信息:
axgle举的曹操的例子很形象,我们拿过来看看:
来自[http://www.javaeye.com/topic/44271]
曹操(caocao)被誉为“古代轻功最好的人 ”,是因为“说曹操,曹操到”这句名言。
在ruby中,曹操的这种轻功被称为callcc.
Ruby代码
callcc{|caocao|
for say in ["曹操","诸葛亮","周瑜"]
caocao.call if say=="曹操"
puts say #不会输出,因为曹操已经飞出去了
end
}#“曹操”飞到这里来了(跳出了callcc的block,紧跟在这个block后面,继续执行下面的ruby代码)
puts "到"
callcc里的caocao是个"延续"(Continuation)对象.这个对象只有名叫“call"的这样一个方法。
当执行了caocao.call后,caocao就会飞到callcc的块(block)后面,让ruby继续执行其下面的代码。
我上面给出的是一个从块里头”飞“到块外面的例子;下面是Programming Ruby给出的从代码后面”飞“到代码前面的例子:
Ruby代码
arr = [ "Freddie", "Herbie", "Ron", "Max", "Ringo" ]
callcc{|$cc|}#下面的$cc.call如果被执行,就会飞回到这里(callcc的块之后)。
puts(message = arr.shift)
$cc.call unless message =~ /Max/
例子大多来自<<The ruby way>>

时间: 2024-10-13 20:31:59

Ruby 魔法 学习笔记之一_ruby专题的相关文章

ruby语言学习笔记2

ruby学习笔记2  (摘自<ruby程序设计语言教程(中文版)>.pdf,全书25页) 1.同一个问题ruby有多个解决方案,途径 ruby之父:松本行弘(Matz),1993年创立 ruby的偶数发行版为稳定版 圆括号在方法调用中是可选的.即无论函数定义还是调用函数,括号都随意的 vim为ruby配置一个插件才好用:vim_ruby:在vimrc中添加<map> <F7> :!ruby -Ku % <CR>      表示用F7键运行  -Ku表示utf

Ruby简洁学习笔记(一):字符串、数字、类和对象_ruby专题

为了证明Ruby真的好用,hello world也能写的如此简洁: 复制代码 代码如下: puts 'hello world' 1.输入/输出 复制代码 代码如下: print('Enter your name') name=gets() puts("Hello #{name}") 注:Ruby是区分大小写的 2.String类 puts("Hello #{name}")中的变量 name是内嵌在整个String里的,通过 #{ } 包裹进行内嵌求值,并用双引号&q

Ruby简洁学习笔记(二):类继承、属性、类变量_ruby专题

1.如何声明一个子类 复制代码 代码如下: class Treasure < Thing 这样Thing类中的属性name,description都被Treasure继承 2.以下三种方式传入父类initialize方法的参数分别是什么? 复制代码 代码如下: # This passes a, b, c to the superclass def initialize( a, b, c, d, e, f ) super( a, b, c ) end # This passes a, b, c t

Luhn算法学习及其Ruby版实现代码示例_ruby专题

关于LUHN算法LUHN算法,主要用来计算信用卡等证件号码的合法性. 1.从卡号最后一位数字开始,偶数位乘以2,如果乘以2的结果是两位数,将两个位上数字相加保存. 2.把所有数字相加,得到总和. 3.如果信用卡号码是合法的,总和可以被10整除. Luhn 算法或是Luhn 公式,也被称作"模10算法".它是一种简单的校验公式,一般会被用于身份证号码,IMEI号码,美国供应商识别号码,或是加拿大的社会保险号码的验证.该算法是由IBM的科学家Hans Peter Luhn所创造,于1954

Ruby的安装与运行_ruby专题

Ruby的安装 注意点 OSX或linux较好 不同版本的实现:c++.C.java 本次C Ruby 安装方法 linux或OSX都有预装 包管理器(apt.yum.brew),并非最新 版本控制系统:rvm(rvm.io).rbenv rvm 查看ruby版本 rvm list known 安装 rvm install 2.2.1 帮助 rvm --help 用户手册 : man rvm rbenv OSX下用brew安装 windows下安装通过rubyInstaller 学习资料 工具

深入理解Ruby中的block概念_ruby专题

Ruby 里的 block一般翻译成代码块,block 刚开始看上去有点奇怪,因为很多语言里面没有这样的东西.事实上它还不错.First-class function and Higher-order function First-class function 和 Higher-order function 是函数式编程语言里面的概念,听起来好像很高端的样子,其实很很简单的. First-class functions 是指在某些语言里,函数是一等公民,可以把函数当做参数传递, 可以返回一个函数

win7安装ruby on rails开发环境_ruby专题

前言 看到很多文章都说ruby环境在windows上是非常难搭建,会出现各种各样的怪问题,所以都推荐到linux和mac上安装开发.但是我按照教程搭了下,问题也不算太多.总过大概花费了2个半小时左右就完成了.所以大家不要被吓尿了,下面就把安装的步骤及具体的版本记录了一下供大家参考. 安装步骤:    开发机环境:我使用的开发机:win7 旗舰版 - 64位 (cpu是i5). 1 安装 rubyinstaller-2.0.0-p481.exe    1 选择安装目录:(如:D:\server\R

Ruby多线程编程初步入门_ruby专题

 传统程序有一个单独的线程执行,包含该程序的语句或指令顺序执行直到程序终止. 一个多线程的程序有多个线程的执行.在每个线程是按顺序执行的,但是在多核CPU机器上线程可能并行地执行.例如,通常情况下在单一CPU的机器,多个线程实际上不是并行执行的,而是模拟并行交叉的线程的执行. Ruby的可以使用 Thread 类很容易地编写多线程程序. Ruby线程是一个轻量级的和高效的在代码中实现并行性.创建Ruby线程: 要启动一个新线程,关联一个块通过调用Thread.new.将创建一个新的线程执行的代码

详解Ruby中的方法概念_ruby专题

 Ruby方法跟其他编程语言中的函数非常相似, Ruby方法用于捆绑到一个单元中的一个或多个重复的语句. 方法名称应以小写字母开始.如果一个方法的名称以大写字母开始,Ruby可能会认为这是一个常数,因此可以正确解析调用. 方法应该定义Ruby的之前调用他们,否则会引发一个异常未定义的方法调用. 语法: def method_name [( [arg [= default]]...[, * arg [, &expr ]])] expr.. end 所以,可以定义一个简单的方法如下: def met