ruby中容易犯的错误
• First and foremost, run your scripts with warnings enabled (the -w command-line
option).
• If you happen to forget a “,” in an argument list—especially to print—you can
produce some very odd error messages.
• A parse error at the last line of the source often indicates a missing end keyword,
sometimes quite a bit earlier.
• An attribute setter is not being called. Within a class definition, Ruby will parse
setter= as an assignment to a local variable, not as a method call. Use the form
self.setter= to indicate the method call.
class Incorrect
attr_accessor :one, :two
def initialize
one = 1 # incorrect - sets local variable
self.two = 2
end
end
obj = Incorrect.new
obj.one → nil
obj.two →2
• Objects that don’t appear to be properly set up may have been victims of an incor-
rectly spelled initialize method.
class Incorrect
attr_reader :answer
def initialise # < < < spelling error
@answer = 42
end
end
ultimate = Incorrect.new
ultimate.answer → nil
The same kind of thing can happen if you misspell the instance variable name.
class Incorrect
attr_reader :answer
def initialize
@anwser = 42 #<« spelling error
end
end
ultimate = Incorrect.new
ultimate.answer → nil
• Block parameters are in the same scope as local variables. If an existing local
variable with the same name as a block parameter exists when the block executes,
that variable will be modified by the call to the block. This may or may not be a
Good Thing.
c = "carbon"
i = "iodine"
elements = [ c, i ]
elements.each_with_index do |element, i|
# do some chemistry
end
c → "carbon"
i →1
• Watch out for precedence issues, especially when using {} instead of do/end.
def one(arg)
if block_given?
"block given to 'one' returns #{yield}"
else
arg
end
end
def two
if block_given?
"block given to 'two' returns #{yield}"
end
end
result1 = one two {
"three"
}
result2 = one two do
"three"
end
puts "With braces, result = #{result1}"
puts "With do/end, result = #{result2}"
produces:
With braces, result = block given to 'two' returns three
With do/end, result = block given to 'one' returns three
• Output written to a terminal may be buffered. This means you may not see a mes-
sage you write immediately. In addition, if you write messages to both $stdout
and $stderr, the output may not appear in the order you were expecting. Always
use nonbuffered I/O (set sync=true) for debug messages.
• If numbers don’t come out right, perhaps they’re strings. Text read from a file will
be a String and will not be automatically converted to a number by Ruby. A call
to Integer will work wonders (and will throw an exception if the input isn’t a
well-formed integer). A common mistake Perl programmers make is
while line = gets
num1, num2 = line.split(/,/)
# ...
end
You can rewrite this as
while line = gets
num1, num2 = line.split(/,/)
num1 = Integer(num1)
num2 = Integer(num2)
# ...
end
Or, you could convert all the strings using map.
while line = gets
num1, num2 = line.split(/,/).map {|val| Integer(val) }
# ...
end
• Unintended aliasing—if you are using an object as the key of a hash, make sure it
doesn’t change its hash value (or arrange to call Hash#rehash if it does).
arr = [1, 2]
hash = { arr => "value" }
hash[arr] → "value"
arr[0] = 99
hash[arr] nil
→
hash.rehash {[99, 2]=>"value"}
→
hash[arr] "value"
→
• Make sure the class of the object you are using is what you think it is. If in doubt,
use puts my_obj.class.
• Make sure your method names start with a lowercase letter and class and constant
names start with an uppercase letter.
• If method calls aren’t doing what you’d expect, make sure you’ve put parentheses
around the arguments.
• Make sure the open parenthesis of a method’s parameter list butts up against the
end of the method name with no intervening spaces.
• Use irb and the debugger.
• Use Object#freeze. If you suspect that some unknown portion of code is setting
a variable to a bogus value, try freezing the variable. The culprit will then be
caught during the attempt to modify the variable.
option).
• If you happen to forget a “,” in an argument list—especially to print—you can
produce some very odd error messages.
• A parse error at the last line of the source often indicates a missing end keyword,
sometimes quite a bit earlier.
• An attribute setter is not being called. Within a class definition, Ruby will parse
setter= as an assignment to a local variable, not as a method call. Use the form
self.setter= to indicate the method call.
class Incorrect
attr_accessor :one, :two
def initialize
one = 1 # incorrect - sets local variable
self.two = 2
end
end
obj = Incorrect.new
obj.one → nil
obj.two →2
• Objects that don’t appear to be properly set up may have been victims of an incor-
rectly spelled initialize method.
class Incorrect
attr_reader :answer
def initialise # < < < spelling error
@answer = 42
end
end
ultimate = Incorrect.new
ultimate.answer → nil
The same kind of thing can happen if you misspell the instance variable name.
class Incorrect
attr_reader :answer
def initialize
@anwser = 42 #<« spelling error
end
end
ultimate = Incorrect.new
ultimate.answer → nil
• Block parameters are in the same scope as local variables. If an existing local
variable with the same name as a block parameter exists when the block executes,
that variable will be modified by the call to the block. This may or may not be a
Good Thing.
c = "carbon"
i = "iodine"
elements = [ c, i ]
elements.each_with_index do |element, i|
# do some chemistry
end
c → "carbon"
i →1
• Watch out for precedence issues, especially when using {} instead of do/end.
def one(arg)
if block_given?
"block given to 'one' returns #{yield}"
else
arg
end
end
def two
if block_given?
"block given to 'two' returns #{yield}"
end
end
result1 = one two {
"three"
}
result2 = one two do
"three"
end
puts "With braces, result = #{result1}"
puts "With do/end, result = #{result2}"
produces:
With braces, result = block given to 'two' returns three
With do/end, result = block given to 'one' returns three
• Output written to a terminal may be buffered. This means you may not see a mes-
sage you write immediately. In addition, if you write messages to both $stdout
and $stderr, the output may not appear in the order you were expecting. Always
use nonbuffered I/O (set sync=true) for debug messages.
• If numbers don’t come out right, perhaps they’re strings. Text read from a file will
be a String and will not be automatically converted to a number by Ruby. A call
to Integer will work wonders (and will throw an exception if the input isn’t a
well-formed integer). A common mistake Perl programmers make is
while line = gets
num1, num2 = line.split(/,/)
# ...
end
You can rewrite this as
while line = gets
num1, num2 = line.split(/,/)
num1 = Integer(num1)
num2 = Integer(num2)
# ...
end
Or, you could convert all the strings using map.
while line = gets
num1, num2 = line.split(/,/).map {|val| Integer(val) }
# ...
end
• Unintended aliasing—if you are using an object as the key of a hash, make sure it
doesn’t change its hash value (or arrange to call Hash#rehash if it does).
arr = [1, 2]
hash = { arr => "value" }
hash[arr] → "value"
arr[0] = 99
hash[arr] nil
→
hash.rehash {[99, 2]=>"value"}
→
hash[arr] "value"
→
• Make sure the class of the object you are using is what you think it is. If in doubt,
use puts my_obj.class.
• Make sure your method names start with a lowercase letter and class and constant
names start with an uppercase letter.
• If method calls aren’t doing what you’d expect, make sure you’ve put parentheses
around the arguments.
• Make sure the open parenthesis of a method’s parameter list butts up against the
end of the method name with no intervening spaces.
• Use irb and the debugger.
• Use Object#freeze. If you suspect that some unknown portion of code is setting
a variable to a bogus value, try freezing the variable. The culprit will then be
caught during the attempt to modify the variable.