Ruby 1.8とRuby 1.9の変更点の生成を半自動化
http://eigenclass.org/hiki/mechanically-verified-ruby19-changelog
クリスマスリリースされるであろうRuby 1.9はかなり久々の大きなバージョンアップだ。Ruby 1.8時代がかつてないほどに長かった。これからは1.8、1.9が共存していく。安定を望む人はこれまで通り1.8を使えばいいし、よりパワーアップしたRubyを使いたければ1.9を使えばいい。
Ruby 1.9では新しい文法やいろいろな非互換性がある。進化する上で非互換性は仕方ない。変更点がどうなったのか気になっている人は多いだろう。eigenclass.orgの中の人は今まで時間をかけて変更点のチェックしていた。しかし、1.9開発中にはいろいろな機能ができては消えてきた。だから手作業でチェックしていたら内容の信憑性が怪しい。そこで、彼は変更点を自動生成することにした。比較コード、ドキュメント、動作検証用コード(assertion)をひとつのRubyスクリプトに詰め込んだ。そのRubyスクリプトを実行することで変更点が半自動的に生成されるというわけだ。比較コードはxmpfilterによりRuby 1.8、Ruby 1.9の双方で結果が出てくる。もし、assertionがコケたら、「Invalid change descriptions(変更点ドキュメントの誤り)」として出力されるから、ドキュメントを修正すればいい。ナイスアイデア!かっこいいなぁ…
さて、検証するにはdarcsでリポジトリを得る必要がある。ruby18-19.rbの引数にはRuby 1.8とRuby 1.9の実行ファイル名を指定する。
ちなみに、ruby-changelogのソースコードはおもしろいDSLになっているので、読んでみると勉強になる。
追記
リリース版に変更してみた。
$ cd ~/src $ darcs get http://eigenclass.org/repos/ruby-changelog $ cd ruby-changelog $ ruby ruby18-19.rb ruby18 ruby19 About this document ------------------- This document was generated semi-automatically by a Ruby program that annotates the code snippets and checks the assertions attached to the descriptions. The annotations are generated by xmpfilter (see http://eigenclass.org/hiki/rcodetools). This is the notation used in the snippets below: expr # => the value expr evaluates to whatever # !> a warning issued by ruby puts "stuff output to stdout" # >> stuff output to stdout These are the versions of the interpreters used to evaluate the examples: ruby 1.9.0: RUBY_VERSION # => "1.9.0" RUBY_PATCHLEVEL # => 0 RUBY_RELEASE_DATE # => "2007-12-25" ruby 1.8.6: RUBY_VERSION # => "1.8.6" RUBY_PATCHLEVEL # => 111 RUBY_RELEASE_DATE # => "2007-09-24" Syntax ====== New hash literal ---------------- ruby 1.9.0: { a: "foo" } # => {:a=>"foo"} Block local variables --------------------- You can declare block local variables with this syntax: {|normal args; local variables| ...} When a variable is shadowed, ruby1.9 issues a warning. ruby 1.9.0: d = 2 a = lambda{|;d| d = 1} # !> shadowing outer local variable - d a.call() p d # >> 2 Block arguments are always local -------------------------------- ruby 1.9.0: a = 1 10.times{|a| } # !> shadowing outer local variable - a p a # >> 1 ruby 1.8.6: a = 1 10.times{|a| } p a # >> 9 New syntax for lambdas (VERY EXPERIMENTAL) ------------------------------------------ Note that this does not replace the traditional block syntax. Matz has already said the latter is here to stay, forever. The new syntax allows to specify default values for block arguments, since {|a,b=1| ... } is said to be impossible with Ruby's current LALR(1) parser, built with bison. You can use the new syntax without parenthesis for the arguments. ruby 1.9.0: a = ->(b,c){ b + c } a.call(1,2) # => 3 --- -> { }.call # => nil -> a, b { a + b }.call(1,2) # => 3 c = 1; -> a, b; c { c = a + b }.call(1,2); c # => 1 # !> shadowing outer local variable - c --- # things get tricky... c = 2; -> ;c { c = 1 }.call; c # => 2 # !> shadowing outer local variable - c --- # or even... c = 2; -> *d ; c { d }.call(1,2,3) # => [1, 2, 3] # !> shadowing outer local variable - c c = 2; -> ; c { c = 1 }.call; c # => 2 # !> shadowing outer local variable - c .() and calling procs without call/[] (EXPERIMENTAL) ---------------------------------------------------- You can call a proc with .() (the period is needed). ruby 1.9.0: a = lambda{|*b| b} a.(1,2) # => [1, 2] --- a = lambda{|*b| b} a(1,2) # => # ~> -:2:in `<main>': undefined method `a' for main:Object (NoMethodError) Block arguments passed to blocks -------------------------------- Blocks can take &block arguments ([[ruby-dev:23533]]). ruby 1.9.0: /tmp/ruby-changelog.20784.21:2: warning: multiple values for a block parameter (2 for 1) from /tmp/ruby-changelog.20784.21:1 define_method(:foo){|&b| b.call(bar)} # ~> -:1:in `<main>': undefined method `define_method' for main:Object (NoMethodError) Block argument assignment ------------------------- |v| now works like the former |v,|: ruby 1.9.0: def m; yield 1, 2; end p m{|v| v} # >> 1 ruby 1.8.6: def m; yield 1, 2; end p m{|v| v} # !> multiple values for a block parameter (2 for 1) # >> [1, 2] Multiple splats allowed ----------------------- As suggested by Audrey Tang, 1.9 allows multiple splat operators when calling a method. Multiple splats are also allowed in array expressions. ruby 1.9.0: def foo(*a) a end p foo(1, *[2,3], 4, *[5,6]) # >> [1, 2, 3, 4, 5, 6] --- a = [1,2,3] b = [4,5,6] p [*a, *b] # >> [1, 2, 3, 4, 5, 6] Mandatory arguments after optional ones allowed ----------------------------------------------- See [[ruby-dev:29014]]. ruby 1.9.0: def m(a, b=nil, *c, d) [a,b,c,d] end p m(1,2) # >> [1, nil, [], 2] ?c semantics ------------ ?a now returns a single character string instead of an integer. ruby 1.9.0: ?a # => "a" ruby 1.8.6: ?a # => 97 Arguments to [] --------------- You can use splats and "assocs" (hashes without braces) with []. ruby 1.9.0: class Foo; def [](*a); a end end a = (0..3).to_a p Foo.new[*a, :op => :+] # >> [0, 1, 2, 3, {:op=>:+}] Newlines before the ternary color --------------------------------- See [[ruby-dev:29189]]. ruby 1.9.0: p 1 == 2 ? 0 : 1 # >> 1 defined? and local variables ---------------------------- ruby 1.9.0: a = 0 defined? a # => "local-variable" 1.times do |i| defined? i # => "local-variable" end ruby 1.8.6: a = 0 defined? a # => "local-variable" 1.times do |i| defined? i # => "local-variable(in-block)" end Kernel and object ================= BasicObject ----------- BasicObject is a top level "BlankSlate" class. ruby 1.9.0: BasicObject.instance_methods # => [:==, :equal?, :"!", :"!=", :__send__] Object.ancestors # => [Object, Kernel, BasicObject] Kernel#instance_exec -------------------- Allows to evaluate a block with a given ''self'', while passing arguments ruby 1.9.0: def magic(obj); def obj.foo(&block); instance_exec(self, a, b, &block) end end o = Struct.new(:a,:b).new(1,2) magic(o) o.foo{|myself,x,y| x + y } # => 3 Kernel#public_send ------------------ public_send only calls public methods. You can call private methods (as usual) using send. ruby 1.9.0: class Foo; private; def foo; end; end Foo.new.send(:foo) # => nil Foo.new.public_send(:foo) # ~> -:3:in `public_send': private method `foo' called for #<Foo:0xb7b831e0> (NoMethodError) # ~> from -:3:in `<main>' --- class Klass def hello(*args) "Hello " + args.join(' ') end end k = Klass.new k.send :hello, "gentle", "readers" #=> "Hello gentle readers" send(:puts, "foo") # prints "foo" 1.public_send(:puts, "foo") # NoMethodError exception # ~> -:10:in `public_send': private method `puts' called for 1:Fixnum (NoMethodError) # ~> from -:10:in `<main>' # >> foo Kernel#require -------------- The value stored in ''$"'' when requiring a file contains the full path, i.e. it works like $" << File.expand_path(loaded_file) [[ruby-dev:26079]] Object#=~ --------- Now returns nil instead of false. [[ruby-core:05391]] ruby 1.9.0: 1 =~ 1 # => nil Object#tap ---------- Passes the object to the block and returns it (meant to be used for call chaining). ruby 1.9.0: "F".tap{|x| x.upcase!}[0] # => "F" # Note that "F".upcase![0] would fail since upcase! would return nil in this # case. Kernel#instance_variable_defined? --------------------------------- ruby 1.9.0: a = "foo" a.instance_variable_defined? :@a # => false a.instance_variable_set(:@a, 1) p a.instance_variable_defined?(:@a) # >> true define_singleton_method ----------------------- ruby 1.9.0: a = "" a.define_singleton_method(:foo){|x| x + 1} a.send(:foo, 2) # => 3 # the method is private a = "" a.define_singleton_method(:foo){|x| x + 1} a.foo(2) Kernel#singleton_methods, methods --------------------------------- They now return an array of symbols (instead of strings). ruby 1.9.0: a = "" class << a; def foo; end end p a.singleton_methods # => [:foo] # >> [:foo] Class and Module ================ Module#instance_methods, #private_instance_methods, #public_instance_methods ---------------------------------------------------------------------------- They now return an array of symbols (instead of strings). ruby 1.9.0: class X; def foo; end end p X.instance_methods(false) # >> [:foo] ruby 1.8.6: class X; def foo; end end p X.instance_methods(false) # >> ["foo"] Module#const_defined?, #const_get and #method_defined? ------------------------------------------------------ These methods now accept a flag specifying whether ancestors will be included in the chain, which defaults to true. See [[ruby-talk:175899]]. ruby 1.9.0: module A; X = 1; def foo; end end module B include A const_defined? "X" # => true method_defined? :foo # => true method_defined? :foo, false # => const_get "X" # => end # ~> -:6:in `method_defined?': wrong number of arguments(2 for 1) (ArgumentError) # ~> from -:6:in `<module:B>' # ~> from -:2:in `<main>' ruby 1.8.6: module A; X = 1; def foo; end end module B include A const_defined? "X" # => false method_defined? :foo # => true const_get "X" /tmp/ruby-changelog.20784.9:4: warning: parenthesize argument(s) for future version # => 1 end Module#class_variable_set, get ------------------------------ They are public in 1.9, private in 1.8: ruby 1.9.0: class B; self end.class_variable_set(:@@a, "foo") # => "foo" ruby 1.8.6: class B; self end.class_variable_set(:@@a, "foo") # => # ~> -:1: private method `class_variable_set' called for B:Class (NoMethodError) Module#attr ----------- Use attr :foo= to create a read/write accessor. (RCR#331) Class of singleton classes -------------------------- Singleton classes inherits from Class rather than from the class of its object. See [[ruby-dev:23690]]. ruby 1.9.0: class X; end x = X.new class << x; p(self < X); end # >> true ruby 1.8.6: class X; end x = X.new class << x; p(self < X); end # >> nil Module#module_exec ------------------ Similar to Object#instance_exec. Extra subclassing check when binding UnboundMethods --------------------------------------------------- The check is performed at definition ti/tmp/ruby-changelog.20784.19:2: private method `eval' called for #<Binding:0xb7dfaab8> (NoMethodError) me, not when the method is executed. See [[ruby-dev:23410]]. ruby 1.9.0: class Foo; def foo; "Foo#foo" end end module Bar define_method(:foo, Foo.instance_method(:foo)) end a = "1" a.extend Bar a.foo # => # ~> -:3:in `define_method': bind argument must be a subclass of Foo (TypeError) # ~> from -:3:in `<module:Bar>' # ~> from -:2:in `<main>' ruby 1.8.6: class Foo; def foo; "Foo#foo" end end module Bar define_method(:foo, Foo.instance_method(:foo)) end a = "1" a.extend Bar a.foo # => # ~> -:7:in `foo': bind argument must be an instance of Foo (TypeError) # ~> from -:7 Binding#eval ------------ RCR 251 ruby 1.9.0: a = 1 p binding.eval("a") # >> 1 ruby 1.8.6: a = 1 p binding.eval("a") # ~> -:2: private method `eval' called for #<Binding:0xb7e13acc> (NoMethodError) Blocks and Procs ================ Proc#yield ---------- Invokes the block, setting the block's parameters /tmp/ruby-changelog.20784.28:4: syntax error, unexpected tLBRACE_ARG, expecting $end s[/d/]{|x| digits << x; sum += x.to_i } ^ to the values in params in the same manner the yield statement does. NilClass#yield raises a LocalJumpError so you can use it on &block. ruby 1.9.0: a_proc = Proc.new {|a, *b| b.collect {|i| i*a }} a_proc.yield(9, 1, 2, 3) #=> [9, 18, 27] a_proc.yield([9, 1, 2, 3]) #=> [9, 18, 27] a_proc = Proc.new {|a,b| a} p a_proc.yield(1,2,3) # >> 1 Arity of blocks without arguments --------------------------------- Arity is now defined as number of parameters that would not be ignored. See [[ruby-talk:120253]] and http://rcrchive.net/rcr/show/227. ruby 1.9.0: lambda{}.arity # => 0 lambda{}.call(1) # ~> -:2:in `call': wrong number of arguments (1 for 0) (ArgumentError) # ~> from -:2:in `<main>' ruby 1.8.6: lambda{}.arity # => -1 lambda{}.call(1) proc is now a synonym of Proc.new --------------------------------- proc is an alias of Proc.new, so it receives its arguments with multiple-assignment (block) semantics, instead of lambda ones as in 1.8, where proc and lambda where synonyms. ruby 1.9.0: Proc.new{|a,b|}.arity # => 2 Proc.new{|a,b|}.call(1) # = nil proc{|a,b|}.arity # => 2 proc{|a,b|}.call(1) # => nil ruby 1.8.6: Proc.new{|a,b|}.arity # => 2 Proc.new{|a,b|}.call(1) # = nil proc{|a,b|}.arity # => 2 proc{|a,b|}.call(1) # => # ~> -:4: wrong number of arguments (1 for 2) (ArgumentError) # ~> from -:4:in `call' # ~> from -:4 Proc#lambda? ------------ Returns whether the Proc has got "lambda semantics" or "block semantics". Exceptions ========== Equality of exceptions ---------------------- They are now considered equal if they have the same class, message and backtrace ([[ruby-talk:110354]]). ruby 1.9.0: def method raise 'foobar' end errors = [] 2.times do Thread.new do begin method rescue => e errors << e end end.join end errors[-2] == errors[-1] # => true ruby 1.8.6: def method raise 'foobar' end errors = [] 2.times do Thread.new do begin method rescue => e errors << e end end.join end errors[-2] == errors[-1] # => false SystemStackError ---------------- SystemStackError is no longer a StandardError. See [[ruby-talk:89782]]. ruby 1.9.0: SystemStackError.ancestors # => [SystemStackError, Exception, Object, Kernel, BasicObject] ruby 1.8.6: SystemStackError.ancestors # => [SystemStackError, StandardError, Exception, Object, Kernel] Exception#to_str removed [Ruby2] -------------------------------- ruby 1.9.0: p begin raise "foo" rescue $!.to_str end # ~> -:4:in `rescue in <main>': undefined method `to_str' for #<RuntimeError: foo> (NoMethodError) # ~> from -:1:in `<main>' ruby 1.8.6: p begin raise "foo" rescue $!.to_str end # >> "foo" Enumerable and Enumerator ========================= Enumerator available by default ------------------------------- Enumerator is now integrated in the core and need not be required. Enumerable#cycle ---------------- Calls the given block for each element of the enumerable in a never-ending cycle: a = ["a", "b", "c"] a.cycle {|x| puts x } # print, a, b, c, a, b, c,.. forever. Enumerable#cycle can be described in Ruby as follows (modulo the enumerator magic): def cycle a = [] each{|x| a << x; yield x} loop{ a.each{|x| yield x} } end The elements contained in the enumerable are saved in an internal array, so the #each method is only called once. Enumerable#each_with_index -------------------------- Now forwards arguments to #each. ruby 1.9.0: class X include Enumerable def each(*args); yield args.inspect end end z = nil X.new.each_with_index(42){|x| z = x} z # => "[42]" ruby 1.8.6: class X include Enumerable def each(*args); yield args.inspect end end z = nil X.new.each_with_index(42){|x| z = x} z # => # ~> -:7:in `each_with_index': wrong number of arguments (1 for 0) (ArgumentError) # ~> from -:7 Enumerable#first(n) ------------------- Gets the first n elements from an enumerable object. ruby 1.9.0: a = {1 => "foo", 2 => "bar", 3 => "babar"} a.first(2) # => [[1, "foo"], [2, "bar"]] Enumerable#group_by ------------------- Groups the values in the enumerable according to the value returned by the block. ruby 1.9.0: (1..10).group_by{|x| x % 3} # => {1=>[1, 4, 7, 10], 2=>[2, 5, 8], 0=>[3, 6, 9]} Enumerable#find_index --------------------- Similar to #find but returns the index of the first matching element ([[ruby-talk:178495]]). ruby 1.9.0: (1..10).find_index{|x| x % 5 == 0} # => 4 (1..10).find_index{|x| x % 25 == 0} # => nil Enumerable#take --------------- Returns either the first n elements from the enumeration or all elements until the given block returns false ([[ruby-dev:30407]]). ruby 1.9.0: a = [1, 2, 3, 4, 5] a.take(3) # => [1, 2, 3] a.take {|i| i < 3 } # => # ~> -:4:in `take': wrong number of arguments(0 for 1) (ArgumentError) # ~> from -:4:in `<main>' Enumerable#drop --------------- Without a block, returns an array with all but the first n elements from the enumeration. Otherwise drops elements while the block returns true (and returns all the elements after it returns a false value) ([[ruby-dev:30407]]). ruby 1.9.0: a = [1, 2, 3, 4, 5] a.drop(3) # => [4, 5] a.drop {|i| i < 3 } # => # ~> -:4:in `drop': wrong number of arguments(0 for 1) (ArgumentError) # ~> from -:4:in `<main>' Enumerable#each --------------- Returns self if no block is given ruby 1.9.0: a = 4.times a = a.each a.inject{|s,x| s+x} # => 6 Enumerable methods called without a block ----------------------------------------- If no block is given to the methods in Enumerable (and those in Array, Dir, Hash, IO, Range, String or Struct that serve the same purposes), an Enumerator will be generated. ruby 1.9.0: [1,2,3].map # => #<Enumerable::Enumerator:0xb7b58b20> [1,2,3].map.each{|x| p x} # => [1, 2, 3] # >> 1 # >> 2 # >> 3 Enumerable#inject (#reduce) without a block ------------------------------------------- If no block is given, the first argument to #inject is the name of a two-argument method that will be called; the optional second argument is the initial value. ruby 1.9.0: (1..10).reduce(:+) # => 55 Enumerable#count ---------------- It could be defined in Ruby as def count(*a) inject(0) do |c, e| if a.size == 1 # suspect, but this is how it works (a[0] == e) ? c + 1 : c else yield(e) ? c + 1 : c end end end See [[ruby-dev:26895]]. ruby 1.9.0: ["bar", 1, "foo", 2].count(1) # => 1 ["bar", 1, "foo", 2].count{|x| x.to_i != 0} # => 2 Enumerable#reduce ----------------- An alias for #inject. Enumerator#with_index [EXPERIMENTAL] ------------------------------------ You can turn an Enumerator into another that provides the index when iterating. See [[ruby-talk:147728]]. ruby 1.9.0: [1,2,3,4,5,6].map.with_index{|x,i|[2,5].include?(i) ? x : x*2} # => [2, 4, 3, 8, 10, 6] Enumerable#min_by, #max_by -------------------------- ruby 1.9.0: %w[1 3 5 7 6 4 2].min_by{|x| 10 - x.to_i} # => "7" %w[1 3 5 7 6 4 2].max_by{|x| 10 - x.to_i} # => "1" Enumerable#zip -------------- Doesn't convert the arguments to arrays; enumerators are used instead. Second argument to Regexp#match, String#match --------------------------------------------- Second argument to #match to specify the starting position of the matching attempt. See [[ruby-core:03203]] and [[ruby-core:03205]]. ruby 1.9.0: "foo bar".match(/S+/,3)[0] # => /S+/.match("foo bar",3)[0] # => # ~> -:1:in `<main>': undefined method `[]' for nil:NilClass (NoMethodError) Block passed to Regexp#match, String#match ------------------------------------------ If a block is given, it will only be evaluated and given the matchdata if there is a match. Enumerable#minmax and minmax_by ------------------------------- Returns both the minimun and the maximum at once as a two-element array. Enumerator#rewind ----------------- Rewinds the enumeration sequence. Fiber: coroutines/micro-threads =============================== Fiber ----- Think of Fibers are threads without preemption. Fiber#yield can be used to force a change of context amongst micro-threads. The API is being refined. (To be expanded). Array Array#nitems ------------ It is equivalent to selecting the elements that satisfy a condition and obtaining the size of the resulting array. See [[ruby-talk:134083]]. ruby 1.9.0: %w[1 2 3 4 5 6].nitems{|x| x.to_i > 3} # => 3 %w[1 2 3 4 5 6].nitems{|x| x.to_i > 3} # => 3 ruby 1.8.6: %w[1 2 3 4 5 6].nitems{|x| x.to_i > 3} # => 6 %w[1 2 3 4 5 6].nitems{|x| x.to_i > 3} # => 6 Array#[m,n] = nil doesn't delete elements ----------------------------------------- It used to delete the selected elements in 1.8. ruby 1.9.0: a = %w[a b c d] a[1,2] = nil a # => ["a", nil, "d"] ruby 1.8.6: a = %w[a b c d] a[1,2] = nil a # => ["a", "d"] Block argument to Array#index, Array#rindex [Ruby2] --------------------------------------------------- They can now take a block to make them work like ''#select''. http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/113069 ruby 1.9.0: ['a','b','c'].index{|e| e == 'b'} # => 1 ['a','b','c'].index{|e| e == 'c'} # => 2 ['a','a','a'].rindex{|e| e == 'a'} # => 2 ['a','a','a'].index{|e| e == 'b'} # => nil Array#combination ----------------- ary.combination(n){|c| ...} yields all the combinations of length n of the elements in the array to the given block. If no block is passed, it returns an enumerator instead. The order of the combinations is unspecified. See [[ruby-list:42671]]. ruby 1.9.0: a = [1, 2, 3, 4] a.combination(1).to_a #=> [[1],[2],[3],[4]] a.combination(2).to_a #=> [[1,2],[1,3],[1,4],[2,3],[2,4],[3,4]] a.combination(3).to_a #=> [[1,2,3],[1,2,4],[1,3,4],[2,3,4]] a.combination(4).to_a #=> [[1,2,3,4]] a.combination(0).to_a #=> [[]]: one combination of length 0 a.combination(5).to_a #=> [] : no combinations of length 5 Array#permutation ----------------- Operates like #combination, but with permutations of length n. ruby 1.9.0: a = [1, 2, 3] a.permutation(1).to_a #=> [[1],[2],[3]] a.permutation(2).to_a #=> [[1,2],[1,3],[2,1],[2,3],[3,1],[3,2]] a.permutation(3).to_a #=> [[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]] a.permutation(0).to_a #=> [[]]: one permutation of length 0 a.permutation(4).to_a #=> [] : no permutations of length 4 Array#product ------------- Returns the cartesian product of the receiver and the arrays given as arguments. ruby 1.9.0: [1,2,3].product([4,5]) # => [[1, 4], [1, 5], [2, 4], [2, 5], [3, 4], [3, 5]] [1,2].product([1,2]) # => [[1, 1], [1, 2], [2, 1], [2, 2]] [1,2].product([3,4],[5,6]) # => [[1, 3, 5], [1, 3, 6], [1, 4, 5], [1, 4, 6], [2, 3, 5], [2, 3, 6], [2, 4, 5], [2, 4, 6]] # [2,3,5],[2,3,6],[2,4,5],[2,4,6]] [1,2].product() # => [[1], [2]] [1,2].product([]) # => [] Argument to Array#pop, Array#shift ---------------------------------- They can take an argument to specify how many objects to return: ruby 1.9.0: %w[a b c d].pop(2) # => ["c", "d"] Array#to_s is equivalent to Array#inspect ----------------------------------------- ruby 1.9.0: [1,2,3,4].to_s # => "[1, 2, 3, 4]" ruby 1.8.6: [1,2,3,4].to_s # => "1234" Array.try_convert ----------------- Returns either the converted value, as returned by to_ary, or nil if the object cannot be converted for any reason. Hash Hash preserves insertion order ------------------------------ ruby 1.9.0: h={:a=>1, :b=>2, :c=>3, :d=>4} # => {:a=>1, :b=>2, :c=>3, :d=>4} h[:e]=5 h # => {:a=>1, :b=>2, :c=>3, :d=>4, :e=>5} h.keys # => [:a, :b, :c, :d, :e] h.values # => [1, 2, 3, 4, 5] h.to_a # => [[:a, 1], [:b, 2], [:c, 3], [:d, 4], [:e, 5]] ruby 1.8.6: h={:a=>1, :b=>2, :c=>3, :d=>4} # => {:a=>1, :b=>2, :c=>3, :d=>4} h[:e]=5 h # => {:a=>1, :e=>5, :b=>2, :c=>3, :d=>4} h.keys # => [:a, :e, :b, :c, :d] h.values # => [1, 5, 2, 3, 4] h.to_a # => [[:a, 1], [:e, 5], [:b, 2], [:c, 3], [:d, 4]] Hash#to_s is equivalent to Hash#inspect --------------------------------------- ruby 1.9.0: {1,2,3,4}.to_s # => # ~> -:1: syntax error, unexpected ',', expecting tASSOC # ~> ..._1198679089_21175_571841 = ({1,2,3,4}.to_s ... # ~> ... ^ ruby 1.8.6: {1,2,3,4}.to_s # => "1234" Hash#compare_by_identity and Hash#compare_by_identity? ------------------------------------------------------ Hash#compare_by_identity lets the hash compare its keys by their identity (using equal? instead of eql?). ruby 1.9.0: "a".eql? "a" # => true "a".equal? "a" # => false h1 = { "a" => 100, "b" => 200, :c => "c" } h1["a"] # => 100 h1.compare_by_identity h1.compare_by_identity? # => true # different objects. h1["a"] # => nil # same symbols are all the same. h1[:c] # => "c" Arguments yielded by Hash#each and Hash#each_pair ------------------------------------------------- #each_pair passes two arguments to the block, #each passes a two-element array to the block. Keep in mind that |x| is equivalent to |x,|. ruby 1.9.0: {1 => 2}.each{|x| p x} {1 => 2}.each_pair{|x| p x} # >> [1, 2] # >> [1, 2] ruby 1.8.6: {1 => 2}.each{|x| p x} {1 => 2}.each_pair{|x| p x} # !> multiple values for a block parameter (2 for 1) # >> [1, 2] # >> [1, 2] Return value of Hash#select --------------------------- Returns a hash instead of an association array ([[ruby-core:11504]]): ruby 1.9.0: {'foo'=>'bar','baz'=>'qux'}.select{|k,v| k=='baz' } # => {"baz"=>"qux"} ruby 1.8.6: {'foo'=>'bar','baz'=>'qux'}.select{|k,v| k=='baz' } # => [["baz", "qux"]] Hash#try_convert ---------------- Returns either the converted value, as returned by to_hash, or nil if the object cannot be converted for any reason. Integer ======= Integer(nil) raises TypeError ----------------------------- See [[ruby-talk::210205]]. Integer#odd?, #even? -------------------- ruby 1.9.0: 1.odd? # => true 2.odd? # => false Integer#pred ------------ The opposite of Integer#succ. Method ====== Method#receiver --------------- Returns the receiver of a Method object. ruby 1.9.0: class A; def foo; end end a = A.new a.method(:foo).receiver # => #<A:0xb7bb14a0> Method#name ----------- Returns the method name. Method#owner ------------ Returns the class or module where the method was defined. ruby 1.9.0: class A; def foo; end end a = A.new a.method(:foo).owner # => A Numeric ======= Numeric#upto, #downto, #times, #step ------------------------------------ These methods return an enumerator if no block is given: ruby 1.9.0: a = 10.times a.inject{|s,x| s+x } # => 45 a = [] b = 10.downto(5) b.each{|x| a << x} a # => [10, 9, 8, 7, 6, 5] Numeric#scalar?, Complex#scalar? -------------------------------- Returns true for non-complex values. See [[ruby-dev:27936]]. ruby 1.9.0: 3.scalar? # => true 3.3.scalar? # => true require 'complex' Complex.new(0,1).scalar? # => false Numeric#div ----------- Now uses #floor instead of the previous special cased integer conversion. This leads to less surprising behavior at times. See [[ruby-dev:27674]]. ruby 1.9.0: -10.0.div(3) # => -4 -10.div(3) # => -4 ruby 1.8.6: -10.0.div(3) # => -4 -10.div(3) # => -4 Numeric#fdiv ------------ An alias for quo ([[ruby-dev:30771]]). Range Range#cover? ------------ range.cover?(value) compares value to the begin and end values of the range, returning true if it is comprised between them, honoring #exclude_end?. See http://www.rubyist.net/~matz/20051210.html#c08 and [[ruby-talk:167182]]. ruby 1.9.0: ("a".."z").cover?("c") # => true ("a".."z").cover?("5") # => false Range#include? -------------- When the begin and end values are Numeric types, range.include?(value) will compare value to them, thus behaving like range.cover?(value). "Discrete" membership is used for other values: ruby 1.9.0: class A < Struct.new(:v) def <=>(o); v <=> o.v end def succ; puts v; A.new(v+1) end end (A.new(0)...A.new(2)).include? A.new(2) # => false puts "----" (A.new(0)...A.new(2)).include? A.new(1) # => true # >> 0 # >> 1 # >> ---- # >> 0 ruby 1.8.6: class A < Struct.new(:v) def <=>(o); v <=> o.v end def succ; puts v; A.new(v+1) end end (A.new(0)...A.new(2)).include? A.new(2) # => false puts "----" (A.new(0)...A.new(2)).include? A.new(1) # => true # >> ---- Range#min, Range#max -------------------- The operation is now defined in terms of #<=>, instead of iterating through the members. However, if the range excludes the end value, the iterative test will be used unless the latter is an Integer. See [[ruby-talk:167420]]. ruby 1.9.0: class A < Struct.new(:v) def <=>(o); v <=> o.v end def succ; puts v; A.new(v+1) end end (A.new(0)...A.new(2)).min # => #<struct A v=0> puts "----" (A.new(0)..A.new(2)).max # => #<struct A v=2> puts "----" (A.new(0)...A.new(2)).max # => #<struct A v=1> # >> 1 # >> ---- # >> ---- # >> 0 # >> 1 ruby 1.8.6: class A < Struct.new(:v) def <=>(o); v <=> o.v end def succ; puts v; A.new(v+1) end end (A.new(0)...A.new(2)).min # => #<struct A v=0> puts "----" (A.new(0)..A.new(2)).max # => #<struct A v=2> puts "----" (A.new(0)...A.new(2)).max # => #<struct A v=1> # >> 1 # >> 0 # >> 1 # >> ---- # >> 0 # >> 1 # >> ---- # >> 0 # >> 1 Regexp ====== Regexp#=== matches symbols -------------------------- ruby 1.9.0: sym = :foo # ... x = case sym when /bar/; 1 when /foo/; 2 end x # => 2 ruby 1.8.6: sym = :foo # ... x = case sym when /bar/; 1 when /foo/; 2 end x # => nil Regexp.try_convert ------------------ Returns either the converted value, as returned by to_regexp, or nil if the object cannot be converted for any reason. String ====== String is no longer Enumerable ------------------------------ String is not Enumerable anymore. Use #each_line instead of #each, and #lines (see below) to iterate over the lines. Encoding-awareness of Strings ----------------------------- String methods operate on chars and are thus encoding-aware. These are some of the affected methods: * == * [] []= * each_line, each_char * hash * inspect * length * ljust, rjust, center * reverse * split * strip!, strip, lstrip, rstrip * succ * upcase, downcase, capitalize, swapcase The length field in the format specifier for printf-like methods also operates on a character basis. String#clear ------------ ruby 1.9.0: a = "foo" a.clear a # => "" ruby 1.8.6: a = "foo" a.clear a # => # ~> -:2: undefined method `clear' for "foo":String (NoMethodError) One-char-wide semantics for String#[] and String#[]= [Ruby2] ------------------------------------------------------------ Indexing a String with an integer doesn't return a byte value, but a one-character String. String#[]= changed accordingly: ruby 1.9.0: "a"[0] # => "a" foo = "foo" foo[0] = ?a foo # => "aoo" ruby 1.8.6: "a"[0] # => 97 foo = "foo" foo[0] = ?a foo # => "aoo" String#each_char ---------------- Passes each character (not byte!) to the given block. String#ord ---------- The new String#ord allows you to get your friendly Fixnum out of the String returned by String#[], so 'a'[0].ord # => 97 is equivalent the 'a'[0] in 1.8. String#partition, #rpartition ----------------------------- str.partition(sep) returns an array with * the text before the first occurrence of sep in str * the separator * the text after the separator If sep cannot be found in str, it will return [str, "", ""]. sep can be a String or a Regexp. rpartition is similar to #partition but the text is cut at the last occurrence of the separator in the string. ruby 1.9.0: "hello".partition("l") # => ["he", "l", "lo"] "hello".rpartition("l") # => ["hel", "l", "o"] "abcdedcbabcdcba".partition(/cd/) # => ["ab", "cd", "edcbabcdcba"] "abcdedcbabcdcba".rpartition(/cd/) # => ["abcdedcbab", "cd", "cba"] String#lines ------------ Returns an enumerator that will yield each line in the string. String#lines accepts an extra argument to indicate the line separator. If given a block, #lines behaves like #each_line ([[ruby-core:9218]]). ruby 1.9.0: "foo\nbar".lines.sort # => ["bar", "foo\n"] String#bytes ------------ Returns an enumerator that will yield each byte in the string: ruby 1.9.0: "hello".bytes.to_a # => [104, 101, 108, 108, 111] String#encoding --------------- Returns the encoding of the string. String#force_encoding --------------------- Changes the encoding of the string to the given one and returns self. String#start_with?, #end_with? ------------------------------ string.start_with?(str) returns true if str is a prefix (suffix) of string. String#unpack with a block -------------------------- If given a block, String#unpack will call it with the unpacked values instead of creating an array. ruby 1.9.0: s = (0..4).to_a.pack("V*") a = [] s.unpack("V*"){|x| a << x} a # => [0, 1, 2, 3, 4] ruby 1.8.6: s = (0..4).to_a.pack("V*") a = [] s.unpack("V*"){|x| a << x} a # => [] String#hash ----------- Now uses Bob Jenkins' hash. String#upto ----------- Takes an optional second array specifying whether the to exclude the final value (by default, it is included). String.try_convert ------------------ Returns either the converted value, as returned by to_string, or nil if the object cannot be converted for any reason. Zero-length symbols allowed --------------------------- ruby 1.9.0: "".intern # => :"" # ~> empty symbol literal # !> useless use of nil in void context # ~> -:2: empty symbol literal # ~> :"" # ~> empty symbol literal # ~> ^ ruby 1.8.6: "".intern # => :"" # ~> empty symbol literal # ~> -:2: empty symbol literal # ~> :"" # ~> empty symbol literal # ~> ^ Struct ====== Struct#inspect -------------- Does not show the class name for anonymous structs: ruby 1.9.0: Struct.new(:a).new("") # => #<struct a=""> ruby 1.8.6: Struct.new(:a).new("") # => #<struct #<Class:0xb7dbd334> a=""> Symbol ====== Symbol#=== matches strings -------------------------- ruby 1.9.0: :a === "a" # => true ruby 1.8.6: :a === "a" # => false Symbol#intern ------------- Returns self. Symbol#encoding --------------- Returns the encoding of the symbol. Symbol methods similar to those in String ----------------------------------------- Now Symbols respond to many methods that resemble those in String: * [] * <=>, casecmp, =~, === * empty? * encoding * length, size * match * slice * succ, next * upcase, downcase, capitalize, swapcase Math Math#log and Math#log2 ---------------------- Math#log accepts an optional base argument ([[ruby-talk:191308]]). The new method Math#log2 ([[ruby-talk:191237]]) computes the base 2 logarithm. File and Dir operations ======================= to_path called in file operations [Ruby2] ----------------------------------------- The to_path method will be called for for non-String arguments in File.path, File.chmod, File.lchmod, File.chown, File.lchown, File.utime, File.unlink... ruby 1.9.0: File.path(Struct.new(:path){ def to_path; path end }.new("foo")) # => "foo" ruby 1.8.6: File.path(Struct.new(:path){ def to_path; path end }.new("foo")) # => # ~> -:1: undefined method `path' for File:Class (NoMethodError) Dir.[], Dir.glob ---------------- * ''['' is no longer considered a normal char ([[ruby-dev:23291]]): * handling of escaped '{', '}' and ',' ([[ruby-dev:23376]]): ruby 1.9.0: File.open("/tmp/[", "w"){|f| f.puts "hi"} Dir["/tmp/["] # => [] --- File.open("/tmp/,", "w"){|f| f.puts "hi"} Dir.glob('/tmp/{\,}') # => ["/tmp/,"] ruby 1.8.6: File.open("/tmp/[", "w"){|f| f.puts "hi"} Dir["/tmp/["] # => [] --- File.open("/tmp/,", "w"){|f| f.puts "hi"} Dir.glob('/tmp/{\,}') # => ["/tmp/,"] Dir.exist? ---------- Equivalent to File.directory?. Dir#inspect ----------- File::world_readable? --------------------- File::world_writable? --------------------- Pathname#world_readable? ------------------------ Pathname#world_writable? ------------------------ File::Stat#world_readable? -------------------------- File::Stat#world_writable? -------------------------- FileUtils.copy_entry -------------------- IO operations ============= Non-blocking IO --------------- Lots of new methods for non-blocking IO: IO#read_nonblock, IO#write_nonblock, Socket#connect_nonblock, Socket#accept_nonblock, Socket#revcfrom_nonblock [[ruby-core:7917]], IPSocket#recvfrm_nonblock, UNIXSocket#recvfrom_nonblock, TCPServer#accept_nonblock, UNIXServer#accept_nonblock. IO#getc ------- Now returns a single-char String instead of an Integer. IO#getbyte, IO#readbyte, StringIO#getbyte, StringIO#readbyte ------------------------------------------------------------ getbyte returns either a Fixnum or nil on EOF. readbyte returns a Fixnum or raises EOFError. Kernel#open [Ruby2] ------------------- Uses #to_open if the first argument responds to it. ruby 1.9.0: require 'stringio' sio = StringIO.new("fooooo") s = Struct.new(:io){ def to_open; io end }.new(sio) open(s){|io| io.gets } # => "fooooo" IO#initialize now accepts an IO argument ---------------------------------------- See [[ruby-dev:22195]]. ruby 1.9.0: IO.new(STDOUT).fileno # => 1 StringIO#readpartial -------------------- It is an alias for ''StringIO#sysread''. ruby 1.9.0: require 'stringio' StringIO.new("foo").readpartial(2) # => "fo" IO#lines -------- Returns an enumerator that will return each line in the IO (similar to String#lines). IO#bytes -------- Returns an enumerator that will return each byte in the IO (similar to String#bytes). IO.try_convert -------------- Returns either the converted value, as returned by to_io, or nil if the object cannot be converted for any reason. Limit input in IO and StringIO operations ----------------------------------------- IO#gets, IO#readline, IO#readlines, IO#each_line, IO#lines, IO.foreach, IO.readlines, StringIO#gets, StringIO#readline, StringIO#each and StringIO#readlines accept an optional integer argument to specify the maximum amount of data to be read. The limit is specified either as the (optional) second argument, or by passing a single integer argument (i.e. the first argument is interpreted as the limit if it's an integer, as a line separator otherwise). IO#ungetc, StringIO#ungetc -------------------------- They allow to push back an arbitrarily large character. Time Time#monday?...sunday? ---------------------- Seven predicate methods where added for the weekdays ([[ruby-list:41340]]). ruby 1.9.0: Time.now # => 2007-12-26 23:24:51 +0900 Time.now.sunday? # => false New format in Time#to_s ----------------------- ruby 1.9.0: Time.new.to_s # => "2007-12-26 23:24:51 +0900" ruby 1.8.6: Time.new.to_s # => "Wed Dec 26 23:24:51 +0900 2007" Timezone information preserved on Marshal.dump/load --------------------------------------------------- See [[ruby-talk:100213]]. ruby 1.9.0: class Object def deep_copy Marshal.load(Marshal.dump(self)) end end fmt = "%m-%d-%Y %H:%M" original = Time.gm(2004, 04, 25, 22, 56) # => 2004-04-25 22:56:00 UTC copy = original.deep_copy # => 2004-04-25 22:56:00 UTC ruby 1.8.6: class Object def deep_copy Marshal.load(Marshal.dump(self)) end end fmt = "%m-%d-%Y %H:%M" original = Time.gm(2004, 04, 25, 22, 56) # => Sun Apr 25 22:56:00 UTC 2004 copy = original.deep_copy # => Mon Apr 26 07:56:00 +0900 2004 Process ======= Process.setrlimit ----------------- Used as Process.setrlimit(resource, cur_limit, max_limit) The resources are OS-dependent, but SuSv3 defines a number of them, allowing to set stack size, file descriptor, core size, data segment size, CPU time limits... See [[ruby-dev:24834]]. The third argument is optional. Process.daemon -------------- Process.daemon() => fixnum Process.daemon(nochdir=nil,noclose=nil) => fixnum Detach the process from controlling terminal and run in the background as system daemon. Unless the argument nochdir is true (i.e. non false), it changes the current working directory to the root ("/"). Unless the argument noclose is true, daemon() will redirect standard input, standard output and standard error to /dev/null. Process.exec ------------ It is to Process.fork what execv(3) is to fork(2). [[ruby-dev:28107]] Symbols ======= Symbols: restriction on literal symbols --------------------------------------- See [[ruby-core:02518]]. Symbols for invalid global variable (e.g. `:$-)`) aren't allowed. :$-) # => # !> useless use of a literal in void context # ~> -:1: syntax error, unexpected ')', expecting $end # ~> :$-) # => # ~> ^ however "$-)".to_sym # => :"$-)" $SAFE $SAFE and bound methods ----------------------- $SAFE isn't set for methods defined from Proc. See http://www.rubyist.net/~nobu/t/20040611.html and [[ruby-dev:23697]]. Miscellaneous new methods ========================= GC.stress, GC.stress= -/tmp/ruby-changelog.20784.17:1:in `<main>': undefined method `to_a' for 1:Fixnum (NoMethodError) -------------------- GC is done on every memory allocation when GC.stress = true This is useful to debug Ruby extensions (such as Syck). Method#hash, Proc#hash ---------------------- See [[ruby-talk:93968]] ruby 1.9.0: lambda{}.hash; # => 1068450039 lambda{}.hash; # => 1068447431 method(:object_id).hash # => 162308 method(:object_id).hash # => 162308 Symbol#to_proc -------------- The infamous &:proc trick. ruby 1.9.0: %w[dsf fgdg fg].map(&:capitalize) # => ["Dsf", "Fgdg", "Fg"] Deprecation =========== VERSION and friends ------------------- Use RUBY_VERSION, RUBY_RELEASE_DATE... instead. StringScanner#peep, empty, clear -------------------------------- The StringScanner methods #peep, #empty, #clear and #getbyte have been renamed to #peek, #eos?, #terminate and #get_byte. Kernel.to_a ----------- ruby 1.9.0: 1.to_a # => nil.to_a # => # ~> -:1:in `<main>': undefined method `to_a' for 1:Fixnum (NoMethodError) ruby 1.8.6: 1.to_a # => [1] # !> default `to_a' will be obsolete nil.to_a # => [] Kernel#getc ----------- Replaced by STDIN.getc. Object#type ----------- Gone for good, see [[ruby-core:04335]]. ruby 1.9.0: "".type # => # ~> -:1:in `<main>': undefined method `type' for "":String (NoMethodError) ruby 1.8.6: "".type # => String # !> Object#type is deprecated; use Object#class File.exists? ------------ Use File.exist? instead. Hash#index ---------- Use Hash#key. ruby 1.9.0: p({a: 1, b: 2}.key(2)) # >> :b ENV.index --------- ENV replicates Hash's behaviour. See [[ruby-dev:25974]]. ruby 1.9.0: ENV["foo"] = "someuniqueval" ENV.index("someuniqueval") # => "foo" # !> ENV.index is deprecated; use ENV.key ruby 1.8.6: ENV["foo"] = "someuniqueval" ENV.index("someuniqueval") # => "foo" Symbol#to_int ------------- ruby 1.9.0: :foo.to_int # => # ~> -:1:in `< Invalid change descriptions =========================== Module#class_variable_defined? ------------------------------ Expected something different from true Passing blocks to [] -------------------- Expected ["3445", 16], got nil. NameError --------- Expected false, got true. __method__ and __callee__ ------------------------- Expected [:foo, :bar], got [:foo, :foo]. main>': undefined method `to_int' for :foo:Symbol (NoMethodError) ruby 1.8.6: :foo.to_int # => 10529 # !> treating Symbol as an integer Array and Hash indices, indexes -------------------------------