ruby 2.x.x之新特性散谈

    ruby入门看的是经典的《ruby编程语言》,可是那描述的是v1.9的老版本啊!下面聊一下ruby2.x.x的新特性,x是0-n都有可能啊。

1.关键字参数(Keyword arguments)

在1.9的时候为了模拟这个功能,我们需要传递散列:

2.1.3 :044 > def foo(n,others)

2.1.3 :045?>   puts n

2.1.3 :046?>   puts others[:name]

2.1.3 :047?>   puts others[:age]

2.1.3 :048?>   end

 => :foo 

2.1.3 :049 > foo(11,name:"ks",age:11)

11

ks

11

但是如果要有默认值怎么办?新的关键字参数特性正好满足这些功能:

2.1.3 :050 > def foo(n,name:"noname",age:11)

2.1.3 :051?>   puts [n,name,age]

2.1.3 :052?>   end

 => :foo 

2.1.3 :053 > foo 100

100

noname

11

对于不带默认值的参数如果在调用时省略会抛出异常的:

2.1.3 :054 > def foo(n,name:"noname",age:)

2.1.3 :055?>   puts [n,name,age]

2.1.3 :056?>   end

 => :foo 

2.1.3 :057 > foo 11

ArgumentError: missing keyword: age

from (irb):57

from /Users/apple/.rvm/rubies/ruby-2.1.3/bin/irb:11:in `<main>'

2.字符串的#freeze优化

ruby中的字符串总是易变的,就算是内容相同的字符串,这在大量调用时会产生内存的浪费。不过在使用freeze后,会在冻结字符串表中查找字符串,导致内容相同的字符串会重复利用:

2.1.3 :058 > def rept

2.1.3 :059?>   "hello"

2.1.3 :060?>   end

 => :rept 

2.1.3 :061 > 3.times {puts rept.object_id}

70098312821560

70098312821460

70098312821400

 => 3 

2.1.3 :062 > def rept;"hello".freeze end

 => :rept 

2.1.3 :063 > 3.times {puts rept.object_id}

70098312835340

70098312835340

70098312835340

 => 3 

3.def返回方法的名字作为标示符

以前的def定义最后返回的是nil,现在是返回方法名字:

2.1.3 :064 > x=def foo; end

 => :foo 

2.1.3 :065 > x

 => :foo 

顺面把原来的示例代码贴出来解释下:

module Around

  def around(method)

    prepend(Module.new do

      define_method(method) do |*args, &block|

        send(:"before_#{method}"if respond_to?(:"before_#{method}"true)

        result = super(*args, &block)

        send(:"after_#{method}"if respond_to?(:"after_#{method}"true)

        result

      end

    end)

    method

  end

end

 

class Example

  extend Around

 

  around def call

    puts "call"

  end

 

  def before_call

    puts "before"

  end

 

  def after_call

    puts "after"

  end

end

 

Example.new.call

这里用到了Module的prepend方法,和include和extend类似,prepend也是将模块插入到类或其他模块中,它扩展的是实例方法(这点和include更像),不过插入的位置不同:它会插入到被插入类的“前面”而不是“后面”,即是说,如果A中有方法foo,它被prepend到有同名方法的类B中,则A#foo会先调用。如果是include到类B中,则B#foo会先调用。

4 有理数和复数字面量

我们已经有了整数(1) 和浮点数(1.0) 字面量, 现在我们也有有理数(1r)和复数(1i)字面量了。

他们配合Ruby的类型转换机制可以轻松搞定数学操作,好比,一个数学上的有理数1/3可以在Ruby中写作1/3r。3i会生成复数0+3i。这意味着复数可以写成标准的标准的数学符号, 2+3i 生成复数2+3i!

5 数组枚举的#to_h方法

现在数组和任何包含枚举的类都有#to_h方法了,so可以这样写代码:

2.1.3 :067 > [[1,2],[3,4]].to_h

 => {1=>2, 3=>4} 

2.1.3 :068 > require "set"

 => true 

2.1.3 :069 > Set[[1,2],[3,4]].to_h

 => {1=>2, 3=>4} 

6 细粒度方法缓存

Ruby2.1之前使用一个全局方法缓存,当代码中任何一个地方定义一个方法,模块引入,模块对象拓展时,这一全局方法缓存都会失效。这使得一些类--如OpenStruct -- 以及一些技术 -- 如exception
tagging
 -- 出于性能原因而不可用。

现在不会有这个问题了, Ruby 2.1 使用基于类层次的方法缓存, 只有讨论中的类和任意子类才会失效缓存。

一个已经加入到 RubyVM 类的方法会返回一些方法缓存状态的调试信息。这个直接看示例代码吧:

class Foo
end

RubyVM.stat   #=> {:global_method_state=>133, :global_constant_state=>820,
                    :class_serial=>5689}

# setting constant increments :global_constant_state

Foo::Bar = "bar"

RubyVM.stat(:global_constant_state)   #=> 821

# defining instance method increments :class_serial

class Foo
  def foo
  end
end

RubyVM.stat(:class_serial)            #=> 5690

# defining global method increments :global_method_state

def foo
end

RubyVM.stat(:global_method_state)     #=> 134

7 Refinements

refine和using配合使用,它们可以在一个局部的作用域中扩展一个模块或类而不污染全局空间,比如:

2.1.3 :091 > module A

2.1.3 :092?>   refine String do

2.1.3 :093 >       def sh2

2.1.3 :094?>       self*2

2.1.3 :095?>       end

2.1.3 :096?>     end

2.1.3 :097?>   end

 => #<refinement:String@A> 

2.1.3 :098 > module B

2.1.3 :099?>   using A

2.1.3 :100?>   "a".sh2

2.1.3 :101?>   end

 => "aa" 

2.1.3 :102 > "a".sh2

NoMethodError: undefined method `sh2' for "a":String

from (irb):102

from /Users/apple/.rvm/rubies/ruby-2.1.3/bin/irb:11:in `<main>'

2.1.3 :103 > using A

 => main 

2.1.3 :104 > "a".sh2

NoMethodError: undefined method `sh2' for "a":String

from (irb):104

from /Users/apple/.rvm/rubies/ruby-2.1.3/bin/irb:11:in `<main>'

8 String#scrub

字符串增加scrub方法用来剔除无效的字符,这个可以参考下ri的结果:

= .scrub

(from ruby site)

=== Implementation from String

------------------------------------------------------------------------------

  str.scrub -> new_str

  str.scrub(repl) -> new_str

  str.scrub{|bytes|} -> new_str

------------------------------------------------------------------------------

If the string is invalid byte sequence then replace invalid bytes with given

replacement character, else returns self. If block is given, replace invalid

bytes with returned value of the block.

  "abc\u3042\x81".scrub #=> "abc\u3042\uFFFD"

  "abc\u3042\x81".scrub("*") #=> "abc\u3042*"

  "abc\u3042\xE3\x80".scrub{|bytes| '<'+bytes.unpack('H*')[0]+'>' } #=> "abc\u3042<e380>"

9 $SAFE级别4被移除

设置$SAFE = 4目的是将Ruby放入一个“沙箱”模型并且允许执行不受信任的代码。 然而这并不是十分有效, 因为这需要代码分散到整个Ruby中,并且这几乎从来没有被用到,所以就被移除了。

2.1.3 :114 > $SAFE=4

ArgumentError: $SAFE=4 is obsolete

from (irb):114

from /Users/apple/.rvm/rubies/ruby-2.1.3/bin/irb:11:in `<main>'

10 Process.clock_gettime

可以通过以上方法来访问系统的clock_gettime函数,从而获取不同种类的时间值,比如一般系统都支持以下3个:

Process::CLOCK_REALTIME将返回一个unix时间戳。这和Time.now.to_f返回值相同,但是因为它跳过创建时间实例,所以会更快一点。

Process::CLOCK_MONOTONIC用途是访问一个单调时钟,这个时钟总是向前移动,无论系统时钟如何调整。这对关键时序或者基准测试是完美的。

Process::CLOCK_PROCESS_CPUTIME_ID对基准测试是有用的,它的工作方式和单调时钟相似,总是向前移动,只有和另一个cpu time做参考时才有意义,但是它只有在CPU工作的情况下,时间才向前移动。

可以检查Process常量查询是否支持其他时钟,比如我的Mac OS 上有:

2.1.3 :118 > Process.constants

 => [:WNOHANG, :WUNTRACED, :Status, :PRIO_PROCESS, :PRIO_PGRP, :PRIO_USER, :RLIM_SAVED_MAX, :RLIM_INFINITY, :RLIM_SAVED_CUR, :RLIMIT_AS, :RLIMIT_CORE, :RLIMIT_CPU, :RLIMIT_DATA, :RLIMIT_FSIZE, :RLIMIT_MEMLOCK, :RLIMIT_NOFILE, :RLIMIT_NPROC, :RLIMIT_RSS, :RLIMIT_STACK,
:CLOCK_REALTIME, :CLOCK_MONOTONIC, :CLOCK_PROCESS_CPUTIME_ID, :Tms, :UID, :GID, :Sys] 

使用很简单:

2.1.3 :121 > Process.clock_gettime(Process::CLOCK_REALTIME)

 => 1417521526.4812741 

2.1.3 :122 > start = Process.clock_gettime(Process::CLOCK_MONOTONIC)

 => 30244.170570458 

2.1.3 :123 > sleep 1

 => 1 

2.1.3 :124 > Process.clock_gettime(Process::CLOCK_MONOTONIC) - start

 => 14.592389030996856 

2.1.3 :125 > start = Process.clock_gettime(Process::CLOCK_PROCESS_CPUTIME_ID)

 => 0.600038 

2.1.3 :126 > sleep 1

 => 1 

2.1.3 :127 > Process.clock_gettime(Process::CLOCK_PROCESS_CPUTIME_ID) - start 

 => 0.01080200000000009 

11 升级RubyGems

Ruby自带的RubyGems版本升级到2.2。基础的Gemfile支持已添加对Gemfile.lock的支持,并向着合入所有Bundler功能到RubyGems而努力。

gem install的--file(或者-g)选项不再要求依赖文件的文件名,它将自动检测Gemfile。如果文件不存在,gem install将产生Gemfile.lock,如果文件存在将遵循特定的版本。

?


1

2

3

4

5

6

7

8

ls

Gemfile

$ gem install -g

Fetching: going_postal-0.1.4.gem (100%)

Installing going_postal (0.1.4)

ls

Gemfile

Gemfile.lock

12 进程标题

添加新的方法Process.setproctitle用于设置进程的标题,不用再设置$0。还增加了相关的方法Process.argv0用于查看$0的初始值,如果$0被设置的话。

2.1.3 :129 > $0

 => "irb" 

2.1.3 :130 > $0= "irb_love"

 => "irb_love" 

2.1.3 :131 > $0

 => "irb_love" 

2.1.3 :132 > Process.argv0

 => "/Users/apple/.rvm/rubies/ruby-2.1.3/bin/irb" 

apple@kissAir: ruby_src$ps 

  PID TTY           TIME CMD

 1497 ttys000    0:00.11 -bash

  501 ttys001    0:00.38 -bash

  595 ttys002    0:00.18 -bash

 1251 ttys002    0:00.62 irb 

  633 ttys003    0:00.17 -bash

  775 ttys004    0:00.17 -bash

  794 ttys005    0:00.16 -bash

  856 ttys006    0:00.17 -bash

apple@kissAir: ruby_src$ps

  PID TTY           TIME CMD

 1497 ttys000    0:00.11 -bash

  501 ttys001    0:00.38 -bash

  595 ttys002    0:00.18 -bash

 1251 ttys002    0:00.63 irb_love 

  633 ttys003    0:00.17 -bash

  775 ttys004    0:00.17 -bash

  794 ttys005    0:00.16 -bash

  856 ttys006    0:00.17 -bash

13 修复了eval作用域解析错误

当eval, instance_eval 或者 module_eval 解析的字符串中含有不带参数的private,protected,public或module_function时,方法的可见作用域变成了它调用处的作用域,如下面这个例子 foo 将会是private的。

?


1

2

3

4

5

6

7

class Foo

  eval "private"

   

  def foo

    "foo"

  end

end

这种情况已经在2.1中得到了修正。所以,在这个例子中,foo应该是public的.

14 #untrusted?现在是#tainted?的别名

之前,Ruby有两套方法来标识/检查对象是否是untrusted,第一套是#tainted?,#taint和#untaint,另一套是#untrusted?,#untrust, 和#trust。这些方法行为都一样,但是分别设置了标识,所以一个对象可能是 untrusted,但不是tainted。

这些方法已经被统一成了对单个的标识设值或取值。#tainted?等是推荐的用法,而#untrusted?等会产生警告。

?


1

2

3

string = "foo"

string.untrust

string.tainted?   #=> true

产生的警告:

?


1

example.rb:2: warning: untrust is deprecated and its behavior is same as taint

不过在2.1.3上测试并没有发现警告

15 Lambda 中的return总是从Lambda返回

Lambdas 不同于内部使用了return的Lambda并从lambda返回的Procs/blocks,它不是封闭方法. 但是有一个例外,如果传给某个方法的lambda带有&并且被yield调用. 这一例外目前已经被移除了。

2.1.3 :155 > def call_lambda

2.1.3 :156?>   yield

2.1.3 :157?>   end

 => :call_lambda 

2.1.3 :158 > def foo

2.1.3 :159?>   call_lambda(&lambda {return "from lambda"})

2.1.3 :160?>   "from method"

2.1.3 :161?>   end

 => :foo 

2.1.3 :162 > foo

 => "from method" 

?

上面的例子在Ruby 2.0.0 之前的版本会返回"from lambda"。

16 获取网络接口地址

目前可以通过Socket.getifaddrs获取系统的网络接口详细信息。将返回Socket::Ifaddr对象数组。

2.1.3 :177 > info = Socket.getifaddrs.find do |ifaddr|

2.1.3 :178 >       (ifaddr.flags & Socket::IFF_BROADCAST).nonzero? &&

2.1.3 :179 >         ifaddr.addr.afamily == Socket::AF_INET

2.1.3 :180?>   end

 => #<Socket::Ifaddr en0 UP,BROADCAST,RUNNING,NOTRAILERS,MULTICAST,0x800 192.168.0.3 netmask=255.255.255.? (7 bytes for 16 bytes sockaddr_in) broadcast=192.168.0.255> 

2.1.3 :181 > info.addr.ip_address

 => "192.168.0.3" 

17 Queue,SizedQueue和ConditionVariable性能提升

Queue,SizedQueue和ConditionVariable已经在C语言中加速实现。

18 Set

Set 中加入了#intersect? 和 #disjoint? 方法。当接收者和参数两者之间至少有一个共同值的时候#intersect? 会返回true,反之,返回false。#disjoint? 则恰恰相反,如果集合之间没有相同的值,返回true,反之,返回false。

?


1

2

3

4

5

6

7

8

9

10

11

12

13

require "set"

 

a = Set[1,2,3]

b = Set[3,4,5]

c = Set[4,5,6]

 

a.intersect?(b)   #=> true

b.intersect?(c)   #=> true

a.intersect?(c)   #=> false

 

a.disjoint?(b)   #=> false

b.disjoint?(c)   #=> false

a.disjoint?(c)   #=> true

Set的另一个主要的变化是,调用一个 set 的 #to_set 会返回它自身,而不是它的拷贝。

?


1

2

3

4

5

require "set"

 

set = Set["foo""bar""baz"]

set.object_id          #=> 70286489985620

set.to_set.object_id   #=> 70286489985620


19 #include 和 #prepend 现在是public的了

Module 和 Class 中的 #include 和 #prepend 方法现在是public的了

2.1.3 :202 > module M

2.1.3 :203?>   def sh

2.1.3 :204?>     self*2

2.1.3 :205?>     end

2.1.3 :206?>   end

 => :sh 

2.1.3 :207 > String.include M

 => String 

2.1.3 :208 > "a".sh

 => "aa" 

2.1.3 :209 > Numeric.include M

 => Numeric 

2.1.3 :210 > 1.sh

 => 2 

20 Module/Class #singleton_class?

Module 和 Class 中引入了一个#singleton_class? 方法,用来返回接收器是否是一个单类。这个不用解释吧

?


1

2

3

4

5

6

class Example

  singleton_class?     #=> false

  class << self

    singleton_class?   #=> true

  end

end

21 Method#original_name

Method 和UnboundMethod 中添加了一个#original_name方法,来返回非别名。

?


1

2

3

4

5

6

7

8

9

10

11

class Example

  def foo

    "foo"

  end

  alias bar foo

end

 

example = Example.new

example.method(:foo).original_name            #=> :foo

example.method(:bar).original_name            #=> :foo

Example.instance_method(:bar).original_name   #=> :foo

22 整数/大数 #bit_length

调用integer的#bit_length方法会返回一个代表该数二进制数的位数的数字。

2.1.3 :218 > 15.bit_length

 => 4 

2.1.3 :219 > 12**12.bit_length

 => 20736 

2.1.3 :220 > 12**120.bit_length

 => 35831808 

2.1.3 :221 > 12**1200.bit_length

 => 743008370688 

23 pack/unpack 本机字节存储次序 long long

Array#pack和String#unpack中添加了使用Q_/Q!和_/q!指令来处理本机字节存储次序的能力.

?


1

2

3

4

5

6

7

8

# output may differ depending on the endianness of your system

unsigned_long_long_max = [2**64 1].pack("Q!")   #=> "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"

signed_long_long_min = [-2**63].pack("q!")        #=> "\x00\x00\x00\x00\x00\x00\x00\x80"

signed_long_long_max = [2**63 1].pack("q!")     #=> "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x7F"

 

unsigned_long_long_max.unpack("Q!")   #=> 18446744073709551615

signed_long_long_min.unpack("q!")     #=> -9223372036854775808

signed_long_long_max.unpack("q!")     #=> 9223372036854775807

24  tempfile.create

Tempfile 现在有了一个类似与new的create方法,不同的是,他并不是返回一个当对象被回收后使用finaliser来清理文件的Tempfile实例,而是得到一个块内的普通文件对象,并在块结束时清理该文件。

2.1.3 :225 > require 'tempfile'

 => true 

2.1.3 :226 > Tempfile.create("foo") do |f|

2.1.3 :227 >     puts f.path

2.1.3 :228?>   end

/var/folders/z2/n3vz292s0z7f995w0_bphm780000gn/T/foo20141202-1251-1hghnr0

 => nil 

2.1.3 :229 > File.exist? "/var/folders/z2/n3vz292s0z7f995w0_bphm780000gn/T/foo20141202-1251-1hghnr0

2.1.3 :230"> "

 => false 

25 curses 库被移除了

curses 已经被从标准库中移除了,现在需要单独下载gem了。

参考地址:http://www.oschina.net/translate/ruby-2-1-in-detail

原文地址:http://globaldev.co.uk/2014/05/ruby-2-1-in-detail/

时间: 2024-10-14 19:13:04

ruby 2.x.x之新特性散谈的相关文章

[C#]6.0新特性浅谈

原文:[C#]6.0新特性浅谈 C#6.0出来也有很长一段时间了,虽然新的特性和语法趋于稳定,但是对于大多数程序猿来说,想在工作中用上C#6.0估计还得等上不短的一段时间.所以现在再来聊一聊新版本带来的新特性可能也还不算晚吧? 一.nameof关键字 这绝对是整个新版本最让我期待的内容,它给代码重构带来了巨大的便利.先来看一下它是怎么使用的吧: string s; Console.WriteLine(nameof(s)); s = nameof(s.Length); Console.WriteL

Ruby on Rails 2.0的新特性介绍

万众瞩目的Ruby on Rails 2.0已经发布了,Rails框架在2004年诞生以来,一直保持着相当快的版本 升级速度:2005年发布了Rails1.0版本,2006年初发布Rails1.1版本,2007年初发布Rails1.2版本,而还 没有等到2008年,在2007年圣诞前夕的12月6日,Rails2.0已经发布. Rails框架每个大的版本升级都给我们带来了相当多的新功能,新惊喜.Rails1.0带给我们完善的单元 测试和集成测试:Rails1.1带给我们DataBase Migra

php5.3 PHP5.4 PHP5.5 php5.6 新特性/使用PHP5.5/PHP5.6要注意的

因为用到PHP新版本,一些新特性必须要了解,且有些可以在开发时就使用,如果不使用,那么何必升级PHP版本呢,显得有些得不偿失了! 所以整理了一下 一些特性,有可能不全,待添加 PHP7.0 和PHP7.1.X新特性请看 http://blog.csdn.net/fenglailea/article/details/52717364 1.PHP 5.3中的新特性  1.1 PHP 5.3中的新特性  1.1.1. 支持命名空间 (Namespace) 毫无疑问,命名空间是PHP5.3所带来的最重要

jQuery 1.4官方文档详细讲述新特性功能

为了庆祝jQuery的四周岁生日, jQuery的团队荣幸的发布了jQuery Javascript库的最新主要版本! 这个版本包含了大量的编程,测试,和记录文档的工作,我们为此感到很骄傲. 我要以个人的名义感谢 Brandon Aaron, Ben Alman, Louis-Rémi Babe, Ariel Flesler, Paul Irish, Robert Kati?, Yehuda Katz, Dave Methvin, Justin Meyer, Karl Swedberg, and

Java SE 6 新特性: HTTP 增强

2006 年底,Sun 公司发布了 Java Standard Edition 6(Java SE 6)的最终正式版,代号 Mustang(野马).跟 Tiger(Java SE 5)相比,Mustang 在性能方面有了不错的提升.与 Tiger 在 API 库方面的大幅度加强相比,虽然 Mustang 在 API 库方面的新特性显得不太多,但是也提供了许多实用和方便的功能:在脚本,WebService,XML,编译器 API,数据库,JMX,网络和 Instrumentation 方面都有不错

探索Eclipse V3.1的新特性

这份教程演示了 Eclipse 的最新发行版 V3.1 中的许多新特性.如果正考虑 从以前的发行版升级到 V3.1,或者正考虑从其他集成开发环境转到 Eclipse, 那么您会发现本教程非常有用.如果想修改代码,以利用 Java 语言的 最新一代 Java 2 Standard Edition V1.5(为 Java 编程语言添加了许多强大 的结构和便利),本教程也会给您带来很大的帮助. 预备知识 了解本教程的学习目标和最佳学习方式. 关于本教 程 本教程演示了 Eclipse 的最新发行版 V

Spring 2.0的新特性点评

Spring2.0的发布恐怕算得上2006年Java社区的一件大事了.在Spring2.0发布附带的文档里面对2.0新特性做了概要的介绍,2.0的新特性是自然是我们最关注的方面: 一.Spring的XML配置引入XML Schema语法简化配置 在Spring1.x系列中,bean的配置文件使用DTD,没有namespace的分隔.2.0的一个非常大的改进是引入了XML Schema的namespace,因而可以将bean的配置文件做大幅度的简化.这些简化包括了对bean属性的各种简化,AOP配

PHP7 新特性详细介绍_php技巧

PHP 的学习新特性 最近做的项目使用了 php7,但感觉有很多新特性没有用起来.就想总结一下,一些可能会用到的新特性.之前使用的环境是 php5.4,所有也会有 php5.5 和 php5.6 的特性总结进来,这里只列出我觉得在项目中可能用到的特性,主要内容来自 php手册的附录. Generators (PHP 5 >= 5.5.0, PHP 7) 通过添加 yield 关键字支持了 generators,Generators 提供了一个更简单的方法实现迭代器,不需要实现 Iterator

《Oracle达人修炼秘籍:Oracle 11g数据库管理与开发指南 》一2.4 Oracle 11g数据库的新特性

2.4 Oracle 11g数据库的新特性 2007年7月12日,Oracle公司在美国纽约宣布推出Oracle 11g数据库,这是迄今为止Oracle公司推出的所有产品中最具创新性和质量最高的软件.Oracle 11g数据库增强了Oracle数据库独特的数据库集群.数据中心自动化和工作量管理功能,可以在安全的.高度可用的.可扩展的.由低成本服务器和存储设备组成的网格上,满足最苛刻的交易处理.数据仓库和内容管理应用. 1.自助式管理和自动化能力 Oracle 11g的各项管理功能可用来帮助企业轻