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/
ruby 2.x.x之新特性散谈的更多相关文章
- [C#]6.0新特性浅谈
原文:[C#]6.0新特性浅谈 C#6.0出来也有很长一段时间了,虽然新的特性和语法趋于稳定,但是对于大多数程序猿来说,想在工作中用上C#6.0估计还得等上不短的一段时间.所以现在再来聊一聊新版本带来 ...
- JDK各版本新特性浅谈
JDK 5.0 自动拆装箱 枚举 可变参数 泛型 For -each 内省 静态导入 JDK 6.0 console开发控制台程序 轻量级HTTP ServerAPI 支持脚本语言 使用Compile ...
- 前端进阶系列(三):HTML5新特性
HTML5 是对 HTML 标准的第五次修订.其主要的目标是将互联网语义化,以便更好地被人类和机器阅读,并同时提供更好地支持各种媒体的嵌入.HTML5 的语法是向后兼容的.现在国内普遍说的 H5 是包 ...
- PHP5.3、PHP5.4、PHP5.5、PHP5.6的新特性
1. PHP5.3中的新特性 1.1 支持命名空间(namespace) 毫无疑问,命名空间是PHP5.3所带来的最重要的新特性. 在PHP5.3中,可以用命名空间防止代码的冲突,命名空间的分隔符为 ...
- php7 新特性整理
PHP7 已经出来1年了,PHP7.1也即将和大家见面,这么多好的特性,好的方法,为什么不使用呢,也希望PHP越来越好. 在这里整理 PHP 5.1 ,PHP5.2,PHP5.3,PHP5.4,PHP ...
- 一文带你看遍 JDK9~14 的重要新特性!
Java9 发布于 2017 年 9 月 21 日 .作为 Java8 之后 3 年半才发布的新版本,Java 9 带 来了很多重大的变化其中最重要的改动是 Java 平台模块系统的引入,其他还有诸如 ...
- PHP的学习--新特性
最近做的项目使用了 php7,但感觉有很多新特性没有用起来.就想总结一下,一些可能会用到的新特性.之前使用的环境是 php5.4,所有也会有 php5.5 和 php5.6 的特性总结进来,这里只列出 ...
- JDK1.5/1.6/1.7之新特性总结(转载)
原文地址:http://www.cnblogs.com/yezhenhan/archive/2011/08/16/2141510.html 如果原作者看到不想让我转载请私信我! 开发过程中接触到了从j ...
- HTML5和CSS3新特性一览
HTML5 1.HTML5 新元素 HTML5提供了新的元素来创建更好的页面结构: 标签 描述 <article> 定义页面独立的内容区域. <aside> 定义页面的侧边栏内 ...
随机推荐
- 插件开发之360 DroidPlugin源码分析(四)Activity预注册占坑
请尊重分享成果,转载请注明出处: http://blog.csdn.net/hejjunlin/article/details/52258434 在了解系统的activity,service,broa ...
- 从嵌入式linux到android应用开发
时间过得很快,转眼之间已经到新公司一个月了.虽然学到了一些移动开发的知识,但是觉得离我的目标还很远,完全没能达到我想要的水平.以前产品都是自己主导的,需要完成什么,计划什么也是自己主导,现在得从头 ...
- 最详细的制作正式版10.11 OS X El Capitan 安装U盘的方法
原帖地址:http://bbs.feng.com/read-htm-tid-10036487.html 一.准备工作: 1.准备一个 8GB 或以上容量的 U 盘,确保里面的数据已经妥善备份好(该过程 ...
- Win 10 下 android studio显示 Intel haxm无法安装,以及VT-X和hyper-x的冲突问题
我 的电脑是神舟战神k650c i7 D4,处理器是Intel core i7 4710-MQ,系统是win 10的 我心血来潮想学习一下安卓开发,就首先安装了android s ...
- python类:描述器Descriptors和元类MetaClasses
http://blog.csdn.net/pipisorry/article/details/50444769 描述器(Descriptors) 描述器决定了对象属性是如何被访问的.描述器的作用是定制 ...
- 程序员修炼之道中所有tips总结
1 关心你的技艺 如果你不在乎能否漂亮地开发出软件,你又为何要耗费生命去开发软件呢? 2 思考!你的工作 关掉自动驾驶仪,接管操作.不断地批评和评估你的工作. 3 ...
- 1017. Queueing at Bank (25) - priority_queuet
题目如下: Suppose a bank has K windows open for service. There is a yellow line in front of the windows ...
- gcov 统计 inline 函数
gcov 统计 inline 函数 (金庆的专栏) gcov可以统计 inline 函数,可是实际使用中碰到统计次数总是为0的现象. 假设类A的头文件为 A.h, 实现文件为 A.cpp. A 有几 ...
- H5学习之旅-H5的元素属性(3)
1.标签可以拥有属性,为标签提供更多的信息 2.属性以键值对的形式呈现例如:href = "www.baidu.com" 3.常用标签属性 :align对其方式 ,对齐方式,包括上 ...
- Java集合之Collection
Java集合是java提供的工具包,包含了常用的数据结构:集合.链表.队列.栈.数组.映射等.Java集合工具包位置是java.util.* Java集合主要可以划分为4个部分:List列表.Set集 ...