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会先调用。

有理数和复数字面量

我们已经有了整数(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} 

细粒度方法缓存

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>'

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/


阅读更多

扫码向博主提问

大熊猫侯佩

博客专家

iOS以及ROR、Swift、ObjC
  • 擅长领域:
  • iOS开发
  • ROR开发
  • Swift
  • C及汇编语言
  • 框架设计
去开通我的Chat快问
版权声明:大熊猫猪·侯佩原创或翻译作品.谢绝转载! hopy https://blog.csdn.net/mydo/article/details/41679297
文章标签: ruby2 新特性
个人分类: 极客 ruby
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭
关闭