# Ruby1.9与Ruby1.8的不兼容处

1. formal argument cannot be an instance variable:
In ruby1.8 it’s possible to use an instance variable as a block argument:
class Foo  attr_accessor :bar  def test     [1,2,3].each {|@bar| }     # @bar will be 3 here  endend

This no longer works in ruby1.9, you as it always creates a new local variable block argument. The equivalent in ruby1.9:

class Foo  attr_accessor :bar  def test     [1,2,3].each {|bar| @bar=bar }     # @bar will be 3 here  endend
2. warning: shadowing outer local variable:
In ruby1.9 the block arguments are always local to block, in ruby1.8 if there’s an existing variable with the same name, the block parameter will use that one:
i = 0[1,2,3].each {|i| }puts i

This will print 0 in ruby1.9, as the variables named i inside/outside the block are different, and 3 in ruby1.8, as here the block reuses the outside variable i.

As with most warning, this warning doesn’t means that your code is incorrect, only that it might be incorrect.
For example the code bellow works the same in ruby1.9 and 1.8:

options = options.inject({}) do |options,pair|  options[pair.first.to_sym] = pair.last.to_sym; optionsend

It still makes sense to rewrite the above code just to supress warnings.

Note: You should set RUBYOPT to -w, or start your program with ruby -w, for this warning to show up

3. syntax error, unexpected ‘,’, expecting tASSOC
ruby1.8 supports , in hash definition, in 1.9 you have to use =>.

So the following valid ruby1.8:

{"a","b"}

has to be rewritten in ruby1.9:

{"a" => "b"}
4. invalid multibyte char:
the default encoding in ruby 1.9 for files is US-ASCII, if you have a non ASCII character in your text file you have to specify the encoding of the source code. You can do it by adding the following line to your ruby file:
# coding:utf-8
5. NoMethodError: undefined method to_a’ for “…”:String:
In Ruby1.8 the String class has a to_a method, so in ruby1.8 you can write:
lines = string.to_a

The equivalent in ruby1.9 is:

lines = string.lines.to_a# chars = string.chars.to_a # to get array of chars# bytes = string.bytes.to_a # to get array of bytes

The issue with this solution, is that the ruby1.9 solution is not compatible with ruby1.8.

Some ideas for a ruby1.9 and ruby1.8 compatible solution:

The first one is to add a lines method to the String, so you can use the ruby1.9 syntax:

unless String.method_defined?(:lines) then  class String    def lines      to_a    end  endendif

The downside is that this lines method is not 100% compatible with ruby1.9 String#lines – for example string.lines(”/n/r”) won’t work.

The second one is to check at each call whether it has the lines method:

if str.respond_to?(:lines) then  lines = string.lines.to_aelse  lines = string.to_aend
6. unexpected:’, expecting keyword_then or ‘,’ or ‘;’ or ‘/n’:
case or if with : instead of then

Ruby1.8 allows the use of : shortcut instead of then in if and case expressions. In Ruby1.9 this is no more allowed.

case 'test'  when 'test': print 'OK'end

In ruby1.9 you’ll get a syntax error, so you have to replace the ‘:’ with ‘then’

case 'test'  when 'test' then print 'OK'end
7. no such file to load — base64:
require "base64": ruby 1.9 ships without base64. You should use Array#pack, unpack
require 'base64' enc = Base64.encode64('Send reinforcements') plain = Base64.decode64(enc)

In ruby1.9 you can write:

enc = ['Send reinforcements'].pack( 'm' )plain = enc.unpack( 'm' )[0]
8. ’struct RString’ has no member named ‘ptr’
’struct RString’ has no member named ‘len’:
In ruby1.9 for the RString in C extensions was changed because of optimization, you should use the RSTRING_LEN, RSTRING_PTR macros instead of directly accessing the len, ptr members.
len = RSTRING(foo)->lenptr = RSTRING(foo)->ptr

Should be changed to

len = RSTRING_LEN(foo);ptr = RSTRING_PTR(foo);
9. .methods changed from Strings to Symbols
The contents of the methods array was changed from String to Symbol, so if you were doing something like this in ruby1.8:
Object.methods.include?("to_s")

The ruby1.9 version is:

Object.methods.include?(:to_s)

And the following works in ruby1.8 and 1.9:

object.respond_to?(:some_method)
10. TypeError: cannot assign nil; use Hash#delete instead
In ruby1.8 you can remove an environment variable by setting it to nil.
In ruby1.9 use the delete method instead:
ENV.delete('MY_ENV_VARIABLE')

Someone recently emailed the ruby-core mailing list asking "Is there some list of 'bullet points' on the major differences between the syntax of Ruby 1.8 and Ruby 1.9 available somewhere?" The response, of course was a link to the definitive list of changes in Ruby 1.9.

But that is an exhaustive list instead of just highlighting the major changes. So, the following is my somewhat more digested list of the important changes, as I understand them. Additions, corrections, clarifications, and so forth are welcome in the comments.

## Text

• Characters are represented by single-character strings, rather than integers:
• ?A returns "A" instead of 65
• "HELLO"[1] returns "E" instead of 69. s[x] is now the same as s[x,1]
• Use ord method of String to get character encoding. It returns the encoding of the first character of the string
• Strings are no longer Enumerable, and the each method has been removed. Use each_line and each_byte to iterate lines and bytes. Both of these methods can return enumerators (see below), which are Enumerable.
• Ruby 1.9 adopts the Oniguruma regexp engine, which adds advanced new features for regular expression wizards.
• Additional changes are expected to Ruby's Unicode and multi-byte string support, but Matz has not unveiled them yet. Strings may have an encoding method for querying or setting their encoding.

## Ranges

• member? and include? work differently if the endpoints of a range are not numbers: they actually iterate with succ to test membership in that case.
• The new method covers? does what member? and include? did in 1.8

## Hashes

• New hash syntax. When the keys of a hash are symbols, you can move the colon from the beginning of the symbol to the end (no space allowed) and omit the =>. So this hash {:a=>1,:b=>2} turns into {a:1,b:2}. The Ruby 1.8 syntax is still supported, of course.

## Parallel Assignment

• Any number of splat operators may appear on the right-hand side of a parallel assignment in Ruby 1.9. Previously only the last rvalue could have a splat.
• The left-hand side of a parallel assignment may have only one splat operator, as always, but it is no longer required to be on the last lvalue. In Ruby 1.9 a splat may appear before any one lvalue.
• Remember that the rules of parallel assignment apply to block invocation as well: the arguments to yield are rvalues, and the block parameters are lvalues. So these splat changes apply to blocks as well.
• In Ruby 1.8, the value of a parallel assignment expression was an array of the lvalues. For efficiency, Ruby 1.9 evaluates all parallel assignments to true.

## Enumerators

• The iterator methods of core classes and modules like String, Fixnum, Array, Hash and Enumerable now return an enumerator object when invoked with no block. An enumerator is an Enumerable object. The enumerator return by each of these iterator methods uses that underlying iterator in place of the each method normally used by the Enumerable mixin. So we can write things like:

counter = (1..10).each  # returns an enumerator
counter.each_with_index { |n,i| puts n,i }

• Ruby makes Enumerable::Enumerator core, so you no longer have to require "enumerator" to get methods like enum_for

## Blocks

• Block parameters are always local to their blocks, even when the enclosing scope includes a variable by the same name. Use -w to get a warning when this will change the behavior of your code.
• Block parameters must be local variables in Ruby 1.9. No more assigning to instance variables or global variables as a side-effect of block invocation
• You can declare block-local variables in Ruby 1.9. Just follow the ordinary list of block parameters with a semi-colon and follow it with a comma-separated list of variable names:

hash.each { |k,v; x,y,z| ... }

With this block declaration, x, y, and z will be local to the block, even if they are already defined in the enclosing scope.
• As per the parallel-assignment changes described above a block parameter list may a splat operator before any one parameter. It is no longer required to be the last one.
• The last block parameter may be prefixed with an ampersand to make it receive a block, just as you can do with methods. This is typically only useful when the block is being turned into a proc or lambda

## Procs and Lambdas

• Kernel.proc is now a synonym for Proc.new: proc now creates a proc and lambda creates a lambda. (Both procs and lambdas are still instances of Proc, of course.)
• The Symbol.to_proc method is now built-in to Ruby.
• Ruby 1.9 supports a (strange at first) new syntax for defining lambdas:

->(x,y) { x + y }  # same as lambda {|x,y| x + y}

• Parentheses are optional in this new syntax:

->x,y { x + y }  # same as lambda {|x,y| x + y}

• The new lambda syntax supports block-local variable declarations following a semicolon just as the regular block syntax does.
• The new lambda syntax allows argument defaults using the same syntax as method declarations:

sale_price = ->(price,discount=.25) { (1.0-discount)*price }

• Procs and lambdas can be invoked with parentheses preceded by a period. Given a lambda sum, the following three lines are synonyms:

sum.call(1,2)
sum[1,2]
sum.(1,2)

• Procs now have a yield method that is an alternative to call. yield uses yield semantics rather than method calling semantics to invoke the proc. This means that it is more relaxed about arity mis-matches and behaves like parallel assignment when the argument is a single array.

## Bindings

• Binding objects have an eval method to evaluate in that binding. This is an alternative to passing the binding as the second argument to Kernel.eval.
• Proc.binding is now a private method. It is not clear if this is a bug or if that method will no longer be available.

## Continuations

• Continuations are not supported in Ruby 1.9

## Private Methods

• The method name resolution algorithm has changed or may be changing to alter the way private methods are looked up. The details are still unclear (to me, at least).

## Class Variables

• Class variables are no longer shared by a class and its subclasses. A subclass can read the values of class variables defined by its superclass. But if it sets the value of such a variable, it simply creates its own local copy of the variable, and no longer alters the value seen by the superclass.

## Math

• Math.log2` computes base-2 log
• Math.log(x,y) computes the log base-y of x