eigenclass - Changes in Ruby 1.9

来源:百度文库 编辑:神马文学网 时间:2024/09/21 17:51:59
MAIN Index Search Changes PageRank Login
Changes in Ruby 1.9
Last major update on 2007-02-07.
I have scanned over 25000 lines of Changelogs to extract the changes between the stable branch and HEAD. These include important syntax additions, lots of modifications in the behavior of Procs and lambdas, new Enumerator and Enumerable goodies, convenient methods to interact with the OS, new IO stuff...
This is not Ruby 2.0!
Keep in mind that Ruby HEAD is being used to trywild and weird ideas. It should by no means be understood as a final say on what Ruby 2.0 will be like. A few decisions are firm and were labelled as Ruby2 in the Changelogs by matz. The below list also includes many crazy ideas (marked as EXPERIMENTAL in the Changelogs and here) which will probably be dropped in short.
Preliminary notes
this is, by necessity, work in progress, as Ruby 1.9 keeps evolving; I‘ll try to keep it up-to-date. the snippets which include the resulting value in a comment were evaluated using myXMP filter, under ruby 1.9.0 unless otherwise stated. The 1.8 interpreter used were either ruby 1.8.4 or 1.8.5.
Table of contents
Last major update on 2007-02-07.
This is not Ruby 2.0!Preliminary notes
Table of contentsNew syntax and semanticsNew constant lookup rulesNew literal hash syntax [Ruby2]Block local variables [EXPERIMENTAL]Block arguments are always localNew syntax for lambdas [VERY EXPERIMENTAL].() and calling Procs without #call/#[] [EXPERIMENTAL]Block argumentsMethod used for splat arguments: #to_splatMultiple splats allowedMandatory arguments after optional arguments allowedc semanticsArguments to #[]printf-style formatted strings (%)Newlines allowed before ternary colon
Kernel and ObjectBasicObject#instance_execsend doesn‘t always call private methods anymore (#__send, #__send!, #funcall)Kernel#requireObject#=~Object#tapKernel#instance_variable_defined?Kernel#define_singleton_methodKernel#singleton_methods, Kernel#methods
Class and ModuleModule#instance_methods, #private_instance_methods, #public_instance_methodsModule#const_defined?, #const_get and #method_defined?Module#class_variable_defined?#class_variable_{set,get}Module#attr is an alias of attr_readerClass of singleton classesClass variablesClass variables are not inherited
#module_execExtra subclassing check when binding UnboundMethods
Binding#evalBlocks and ProcsProc#yieldArity of blocks without argumentsPassing blocks to #[]proc is now a synonym of Proc.new
ExceptionsNameErrorEquality of exceptionsSystemStackErrorRemoved Exception#to_str [Ruby2]
Enumerable and EnumeratorEnumerable#first(n)Enumerable#group_byEnumerable#find_indexEnumerator#eachEnumerable methods called without a blockEnumerable#countEnumerator#with_index [EXPERIMENTAL]Added #min_by, #max_by
Regexp#match, String#matchArrayArray#nitemsArray#[m,n] = nil places nil in the array.Block argument to Array#index, Array#rindex [Ruby2]Array#pop, Array#shiftArray#to_s is equivalent to Array#inspect
HashHash#to_s is equivalent to Hash#inspectHash#_compare_by_identity and Hash#compare_by_identity?
IntegerInteger(nil) raises TypeErrorInteger#odd?, #even?Integer#pred
MethodMethod#receiverMethod#nameMethod#owner
NumericNumeric#upto, #downto, #times, #stepNumeric#scalar?, Complex#scalar?Numeric#div
RangeRange#cover?Range#include?Range#min, Range#max
StringNo longer an EnumerableString#clear"One-char-wide" semantics for String#[] and String#[]= [Ruby2]String#ordString#partition, #rpartitionString#linesString#bytesString#start_with?, #end_with?String#unpack with a blockString#hashZero-length symbols allowed
StructStruct#inspect
MathMath#log and Math#log2
File and Dir operations#to_path in File.path, File.chmod, File.lchmod, File.chown, File.lchown, File.utime, File.unlink... [Ruby2]Dir.[], Dir.globDir.exist?New methods
IO operationsNon-blocking IOIO#getcKernel#open [Ruby2]IO#initialize now accepts an IO argumentStringIO#readpartialIO#linesIO#bytesLimit input in IO#gets, IO#readline, IO#readlines, IO#each_line, IO#lines, IO.foreach, IO.readlines, StringIO#gets, StringIO#readline, StringIO#each, StringIO#readlines
TimeNew format in Time#to_sTimezone information preserved on Marshal.dump/load
ProcessProcess.setrlimitProcess.daemonProcess.exec
Symbols: restriction on literal symbols$SAFE and bound methodsMisc. new methodsGC.stress, GC.stress=Method#hash, Proc#hash__method__ and __callee__Symbol#to_proc
DeprecationVERSION and friendsStringScannerKernel.to_aObject#typeFile.exists?Hash#indexENV.indexSymbol#to_intRemoved Array and Hash #indices, #indexes
New syntax and semantics
New constant lookup rules
Now constants are looked up in the following order:
current class super classes except Object lexically enclosing classes/modules Object
The new rules entail differences in dynamic constant lookups too:
class ABAR = 1def foo(&b); instance_eval(&b) endenda = A.newa.foo { BAR } # => 1
vs. 1.8:
class ABAR = 1def foo(&b); instance_eval(&b) endenda = A.newa.foo { BAR } # =># ~> -:7: uninitialized constant BAR (NameError)# ~> from -:3:in `foo‘# ~> from -:7
See alsoruby-talk:181646.
New literal hash syntax [Ruby2]
{a: "foo"} # => {:a=>"foo"}Block local variables [EXPERIMENTAL]
Used as follows:
# {normal args; local variables}d = 2a = lambda{|;d| d = 1}a.call()d # => 2
When a variable is shadowed, ruby1.9 issues a warning:
-:2: warning: shadowing outer local variable - dBlock arguments are always local
a = 110.times{|a| } # !> shadowing outer local variable - aa # => 1New syntax for lambdas [VERY EXPERIMENTAL]
a = ->(b,c){ b + c }a.call(1,2) # => 3
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:
-> { }.call # => nil-> a, b { a + b }.call(1,2) # => 3c = 1; -> a, b; c { c = a + b }.call(1,2); c # => 1
It can get very tricky though:
c = 2; -> ;c { c = 1 }.call; c # => 2
or even
c = 2; -> *d ; c { d }.call(1,2,3) # => [1, 2, 3]c = 2; -> ; c { c = 1 }.call; c # => 2.() and calling Procs without #call/#[] [EXPERIMENTAL]
You can now do:
a = lambda{|*b| b}a.(1,2) # => [1, 2]
Note that you need the period:
a = lambda{|*b| b}a(1,2) # =># (eval):2: syntax error...# (a)(1,2)... ~> -:2: undefined method `a‘ for main:Object (NoMethodError)
You can use any expression inside the parentheses:
(lambda{|a,b| a + b}).(1,2) # => 3
.() will try to use #call no matter the receiver:
"foo".(1,2) # ~> undefined method `call‘ for "foo":String (NoMethodError)Block arguments
Blocks can take &block arguments:
define_method(:foo){|&b| b.call(bar)}
ruby-dev:23533
Method used for splat arguments: #to_splat
to_splat is used instead of #to_a.
nil.to_splat returns [].
Multiple splats allowed
As suggested by Audrey Tang, 1.9 allows multiple splat operators when calling a method:
def foo(*a)aendfoo(1, *[2,3], 4, *[5,6]) # => [1, 2, 3, 4, 5, 6]Mandatory arguments after optional arguments allowed
(ruby-dev:29014)
def m(a, b=nil, *c, d)[a,b,c,d]endm(1,2) # => [1, nil, [], 2]c semantics
a now returns a single character string instead of an integer:
a # => "a"Arguments to #[]
You can use splats, "assocs" (hashes without braces) and block arguments with #[]:
RUBY_VERSION # => "1.9.0"RUBY_RELEASE_DATE # => "2006-06-11"class Foo; def [](*a, &block); block.call(a) end enda = (0..3).to_aFoo.new[*a, :op => :+]{|x| x } # => [0, 1, 2, 3, {:op=>:+}]printf-style formatted strings (%)
%c can print a one character String (as returned e.g. by ?c).
Newlines allowed before ternary colon
p 1 == 2 ?0:1# >> 1
ruby-dev:29189
Kernel and Object
BasicObject
BasicObject is a top level BlankSlate class:
BasicObject.instance_methods# => ["__send__", "funcall", "__id__", "==", "send", "respond_to?", "equal?", "object_id"]Object.ancestors # => [Object, Kernel, BasicObject]#instance_exec
Allows to evaluate a block with a given self, while passing arguments:
def magic(obj); def obj.foo(&block); instance_exec(self, a, b, &block) end endo = Struct.new(:a,:b).new(1,2)magic(o)o.foo{|myself,x,y| x + y } # => 3send doesn‘t always call private methods anymore (#__send, #__send!, #funcall)
ruby-talk:153672 It is still possible to call them with the newly introduced #__send! and funcall methods.
class Foo; private; def foo; end; endFoo.new.funcall(:foo) # => nilFoo.new.send(:foo) # ~> in `BasicObject#send‘: private method `foo‘ called for # (NoMethodError)
Note that send(meth) (with no explicit receiver) can still call private methods:
class Klassdef hello(*args)"Hello " + args.join(‘ ‘)endendk = Klass.newk.send :hello, "gentle", "readers" #=> "Hello gentle readers"send(:puts, "foo") # prints "foo"1.send(:puts, "foo") # NoMethodError exception >> foo ~> -:10:in `BasicObject#send‘: private method `puts‘ called for 1:Fixnum (NoMethodError) ~> from -:10
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.
1 =~ 1 # => nil
ruby-core:05391.
Object#tap
Passes the object to the block and returns it (meant to be used for call chaining).
"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?
a = "foo"a.instance_variable_defined? :@a # => falsea.instance_variable_set(:@a, 1)a.instance_variable_defined? :@a # => trueKernel#define_singleton_method
a = ""a.define_singleton_method(:foo){|x| x + 1}a.__send!(:foo, 2) # => 3
The new singleton method will be private:
a = ""a.define_singleton_method(:foo){|x| x + 1}a.foo(2) # ~> private method `foo‘ called for "":String (NoMethodError)Kernel#singleton_methods, Kernel#methods
They now return an array of symbols (instead of strings):
a = ""class << a; def foo; end enda.singleton_methods # => [:foo]
Class and Module
Module#instance_methods, #private_instance_methods, #public_instance_methods
They now return an array of symbols (instead of strings):
class X; def foo; end endX.instance_methods(false) # => [:foo]
vs. (1.8.5)
class X; def foo; end endX.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 (seeruby-talk:175899):
module A; X = 1; def foo; end endmodule Binclude Aconst_defined? "X" # => truemethod_defined? :foo # => truemethod_defined? :foo, false # => falseconst_get "X" # => 1end
vs. (1.8)
module A; X = 1; def foo; end endmodule Binclude Aconst_defined? "X" # => falsemethod_defined? :foo # => trueconst_get "X" # => 1endModule#class_variable_defined?
class X; endX.class_variable_defined? :@@a # => falseclass X; @@a = 1 endX.class_variable_defined? :@@a # => true#class_variable_{set,get}
They are public in 1.9, private in 1.8:
class B; self end.class_variable_set(:@@a, "foo") # => "foo"Module#attr is an alias of attr_reader
Use
attr :foo=
to create a read/write accessor. (RCR#331)
Class of singleton classes
singleton class inherits Class rather than its object‘s class
class X;end; x=X.new; class << x; self < X; end # => true
vs. (1.8)
class X;end; x=X.new; class << x; self < X; end # => nil
[ruby-dev:23690]
Class variables<%