Ruby problems edit (Category edit)
Ruby / Problems edit (Category edit)
Solution: Never assume an array is an array; check to make sure. Unless you're 100% sure that something will (still?) be an Array/Hash by the time it gets to where you call [] on it, always do a check for nilness.
Solution 1: Use Ruby's && operator to your advantage: rely on the fact that it will be short-circuited at the first component that is nil (or false), and that it will return the last non-nil value (not true like in other languages).
So for each dimension of the array that your accessing, add it to the list of and-ed conditions that you check. An example:
Don't do this:
@required_fields[object][field]
Not only could @required_fields be nil, but @required_fields[object] could also be nil. So we add a check for both of them, like this:
@required_fields && @required_fields[object] && @required_fields[object][field]
This will never throw a NoMethodError -- ever.
The problem with this method is that it's really verbose.
Here is a conciser way:
a=@required_fields && a=a[object] && a[field]
Still kinda ugly, but a little better, in my opinion.
(Rails code:)
params[:verify][:username]
will fail if params[:verify] is not set.
You have a nil object when you didn't expect it! You might have expected an instance of Array. The error occured while evaluating nil.[]
You can add a check for the nil case, but that gets verbose quickly (what if you had a 3-dimensional hash?!):
params[:verify][:username] unless params[:verify].nil? (params[:verify][:username] unless params[:verify].nil?) || session[:username]
Have I already said yuck? Otherwise, I think now would be a good time.
Anyway, what if it's the test expression for an if statement? How do you specify a default value for the nil case? Ternary operator??
Solution 2 (ternary operator):
params[:verify].nil? ? ' ' : params[:verify][:username]
Yuck.
Solution 3 (unless):
Or, if you're fine with a nil default, you could stick with the unless:
params = Hash.new
=> {}
irb(main):003:0> params[:verify][:password] unless params[:verify].nil?
=> nil
This is ugly...
if authenticate((params[:verify][:username] unless params[:verify].nil?), (params[:verify][:password] unless params[:verify].nil?)) ... end
I guess what I'm really saying is... I expected Ruby to have a better way! Something like this, perhaps...
(params[:verify][:username] || nil) or dont_complain_if_its_not_a_hash(params[:verify][:username])
Solution 4:
Actually, I discovered there is a way to do essentially just that: It's the compact form of rescue:
(params[:verify][:username] rescue nil)
I guess that's fine if you are 100% sure there will be no other exceptions that could be raised (that we wouldn't want to silently rescue) by that block of code.
I guess we could overload NilClass with a [] operator! ... right?? ... have it return something sane, like Hash.new?
session[:registration_params] = ((params[:register] || {}).merge((params[:user] || {}))) || {}
Can't do this:
if params[object][field_name].blank?
Do this instead:
if params[object] && params[object][field_name].blank?
class NilClass
def to_arr
[]
end
def to_hash
{}
end
end
Call one of those whenever you are expecting a hash or array but know there is a chance that you'll get a Nil instead!
That's okay for custom methods -- you shouldn't be able to call them on nil -- but common checks like empty? should require that you also check nil? first!
For example, it seems silly that you have to do this:
(var and !var.empty?)
instead of just
!var.empty?
but you can get away with doing this
var == 'bob'
intead of
(var and var == 'bob')
I'm so sick of writing that all the time!
require File.dirname(__FILE__) + "/../whatever"
When is require_relative going to be part of core already?!
include the Enumerable moduleSo it appears that some methods from Enumerable that you'd expect to be there in Array also -- like enum_with_index, ... -- simply aren't there!
I can apparently do this:
irb -> ['a', 'b', 'c'].each_with_index{|value, index| "doesn't matter"}
=> ["a", "b", "c"]
but not this:
irb -> ['a', 'b', 'c'].enum_with_index.map {|value, index| [index, value]}
NoMethodError: undefined method `enum_with_index' for ["a", "b", "c"]:Array
from (irb):1
Oops. Correction: I guess that works, but only if you make sure Enumerable::Enumerator is defined first:
irb -> require 'enumerator'
=> true
irb -> ['a', 'b', 'c'].enum_with_index.map {|value, index| [index, value]}
=> [[0, "a"], [1, "b"], [2, "c"]]
Also, if you extend Enumerable, I guess those changes wouldn't appear in Array; you'd have to mix in your changes into Array specifically.
I think this might be the same problem with Hash.
So you can't add an /*inline comment*/ about an argument unless you break the arguments across several lines.
Recommendation: Use #- for inline comments -#
For example, this doesn't work...
rdoc.options \
<< '--line-numbers' \ # Include line numbers in the source code
<< '--inline-source' \ # Causes "Show source" link to display source inline rather than as a popup
<< '--all' \ # Include private methods
<< '--diagram' \ # Include diagrams showing modules and classes.
<< '--extension' << 'rake=rb' # Treat .rake files as files that contain Ruby code
/home/tyler/svn/code/plugins/shared_rake_tasks/tasks/base.rake:44: syntax error, unexpected $undefined, expecting kEND
<< '--line-numbers' \ # Include line numbers in the source code
Nor does this, because the \ is just treated as part of the comment.
rdoc.options \
<< '--line-numbers' # Include line numbers in the source code \
<< '--inline-source' # Causes "Show source" link to display source inline rather than as a popup \
<< '--all' # Include private methods \
<< '--diagram' # Include diagrams showing modules and classes. \
<< '--extension' << 'rake=rb' # Treat .rake files as files that contain Ruby code
/home/tyler/svn/code/plugins/shared_rake_tasks/tasks/base.rake:45: syntax error, unexpected tLSHFT, expecting kEND
<< '--inline-source' # Causes "Show source" link to display source inline rather than as a popup \
^
I would use inline comments (/* */ in many languages), but sadly, Ruby doesn't have any kind of inline comment.
So I'm forced to put some kind of operator at the end of the line to hint to Ruby that the next line is a continuation.
rdoc.options <<
'--line-numbers' << # Include line numbers in the source code
'--inline-source' << # Causes "Show source" link to display source inline rather than as a popup
'--all' # Include private methods
'--diagram' << # Include diagrams showing modules and classes.
'--extension' << 'rake=rb' # Treat .rake files as files that contain Ruby code
Currently they look something like this: http://www.ruby-doc.org/core/classes/Date.html#M000480
I propose that they be changed to the more intuitive: http://www.ruby-doc.org/core/classes/Date.html#new
Reason: This type of link would be less likely to break as the API evolves. If a method were deleted/added, the current link to new, #M000480, would probably change its number. This wouldn't happen if the anchor were named after the name of the method!!!
Confusing having so many incompatible choices.
Just today, I wanted to build an array of dates from start_date to end_date. I was overjoyed when I found that Date responds to up_to. It also provided a nic Date.today as a starting point for my range. My joy turned to frustration, however, when I learned that it doesn't have a tomorrow.
Rails (which I was using) implements a Time.tomorrow in ActiveSupport::CoreExtensions::Time::Calculations (which is mixed into Time). That got me to be hopeful again. But since it didn't provide Date.tomorrow, I had to do a conversion. And the resulting code, I think you'll agree is uglier than it needs to be:
@dates = []
Date.today.upto(Time.today.tomorrow.to_date) do |date|
@dates << date
end
(Time#today is a class method, Time.tomorrow is an instance method, which requires me to call Time#today first in order to get an instance. This doesn't work either: Date.today.tomorrow, nor does Date.tomorrow.)
Should be responds_to?. You're asking an object if it (singular) responds (singular) to a certain message.
http://pezra.barelyenough.org/blog/2005/04/ruby-backtraces/
I miss debug_print_back_trace() from PHP.
With all the effort Ruby put into making different prefixes for different scopes (@ = instance variables, @@ = class variables, $ = global variables), you would have thought they wouldn't leave it so ambiguous in this case:
def my_method params = nil end
Did I just set a local variable 'params' or call the params=() method of my class??
include? -- includes? would be more intuitive, IMHO
assert_raise? -> assert_raises?
File.exist? -> File.exists?
assert (Test::Unit::Assertions) assert_block (Test::Unit::Assertions) assert_equal (Test::Unit::Assertions) # Good. "assert that this two objects *are equal*" assert_in_delta (Test::Unit::Assertions) assert_instance_of (Test::Unit::Assertions) # Good. assert_kind_of (Test::Unit::Assertions) assert_match (Test::Unit::Assertions) # Bad. "assert that this *matches* this pattern" assert_nil (Test::Unit::Assertions) assert_no_match (Test::Unit::Assertions) assert_not_equal (Test::Unit::Assertions) assert_not_nil (Test::Unit::Assertions) assert_not_same (Test::Unit::Assertions) assert_nothing_raised (Test::Unit::Assertions) assert_nothing_thrown (Test::Unit::Assertions) assert_operator (Test::Unit::Assertions) assert_raise (Test::Unit::Assertions) # Bad. assert_raises (Test::Unit::Assertions) # Good. "assert that this block raises this exception." Unfortunately, it's deprecated. Why? assert_respond_to (Test::Unit::Assertions) # Bad. "assert that this object (singular) *responds* (singular) to this message. assert_same (Test::Unit::Assertions) assert_send (Test::Unit::Assertions) # Bed. assert_throws (Test::Unit::Assertions) # Good.
There is a way around this... but it's more work than I want it to be.
You can do this...
# examples/ruby/accessing_original_method_after_overriding.rb
# Let's say this is how it appears in the library
class Klass
def calculate(x)
x + 1
end
end
puts Klass.new.calculate(1)
# => 2
# Now, in our code, we want to reopen the class and override the method, but still make use of it...
# That is, we want to make a wrapper method for the original method but still let it have the same name!!
class Klass
alias_method :orig_calculate, :calculate
def calculate(x)
2 * orig_calculate(x)
end
end
puts Klass.new.calculate(1)
# => 4
I would like to be able to just do this:
class Klass
def calculate(x)
2 * original_method(x)
end
end
puts Klass.new.calculate(1)
# => 4
When a method is overriden, Ruby could automatically do the alias_method :original_mtehod, :method thing in the background.
Then from our overriden method we could jut call original_method(), which would look at the name of the method we're calling from (in this case :calculate), prepend that symbol with "original_" and then return that original method (as a symbol?? after invoking it? I'm not sure how best to pass around methods ... as a Proc??).
Seems like there ought to be a better idiom for doing this...
array = %w{c d e}
# Want to get this:
"... |a|, |b|, |c|, |d|, |e| ..."
# This works, but is long:
"... |a|, |b|, #{array.collect{|a| "|" + a + "|"}.join(", ")} ..."
# I thought this would work, but I guess you can't have a #{} within a #{}.
"... |a|, |b|, #{array.collect{|a| "|#{a}|"}.join(", ")})} ..."
# Would like to do it like so:
"... |a|, |b|, #{array.wrap_each_in('|', '|'}.join(", ")} ..."
# I guess I could write my own method to do that...
When you override a superclass's method in your subclass, then you still have access to the superclass's method via the keyword super.
I'd like to see the same thing with methods that have been overridden by re-opening the class (not subclassing it) and redefining a method within that class.
Proposal:
Questions: What happens when you subclass a class that already had overriden methods? Do you still have access to all the overridden methods of the superclass? ... Should you? Would you want to?
Occasionally it may make sense to have it return the ASCII value of the character as a Fixnum....
But most of the time, though, I want to get substrings out of the string. Consider this example:
irb -> "abcde"[0..2] # Greate! Intuitive!
=> "abc"
irb -> "abcde"[0] # Not what I would have intuitively expected!
=> 97
irb -> "abcde"[0..0] # More syntax than I really want to use to get at a single character... but at least it's possible!
=> "a"
Sometimes extra flexibility comes at the cost of extra confusion.
For example, the flexibility to use "." or "::" as a scope resolution operator is, in my opinion, unneeded and unwanted flexibility. And it necessitates this crazy, obscure language rule:
"The only difference between these two forms occurs if the method name starts wth an uppercase letter. In this case, Ruby will assume that a receiver::Thing method call is actually an attempt to access a constant call Thing in the receiver unless the method invokation has a parameter list between parentheses." (Pickaxe 2nd Ed., p. 349)
Wouldn't it have been simpler just to say "use . for method calls, :: for references to constants"?
All right, I'll admit it... I prefer to use the :: version when making class method calls... Maybe just a habit picked up from PHP or other languages (called static methods in other languages). It's nice, although tnot necessary, to have class method calls look different from instance method calls. But again, I wish that if we're allowed to call class methods like that that we should always have to call them like that. Consintency.
And I still don't like having a syntax rule that has an exception and then an exception to the exception.
[see example on main Ruby page with strings inside of strings...]
For example, I may start with something simple, like this:
node.additional_markup_adjustment = -1000
but as soon as I need to make the name of the method being called dynamic (I need to add a prefix to the method name and the prefix isn't known till run-time), I have to change the syntax to something else, because a method call technically can't be an l-value:
node.send("#{prefix}additional_markup_adjustment=", -1000)
Not as pretty to read, is it? That's typical of meta-programming...get used to it.
You can't catch as many things at compile time. You have to wait for them to happen at run-time. On the other hand, perhaps that's also its greatest strength: dynamic typing offers many benefits that seem to outweight the drawbacks. (Read http://www.journalhome.com/codecraft/9003/) And you could explicitly check the types of arguments being passed in if you really wanted to (if object.class != ExpectedClass...).
ARGV is a synonym for $*, why not call it $argv then? If it's a global variable, why not use the conventional $ ?? We have $stdin ...
{ Array.size and Array.length }, { $* or ARGV }, etc.
This can be considered a good thing or a bad thing.
Good because symbols are more concise than word.
Bad because when you see a bunch of symbols together it can (?) decrease readibility and make you have to sit there and parse for a minute before you understand. (Maybe not, though, I haven't checked.) I just don't want to end up with another APL!
An example of some perfectly valid code containing 6 symbols and 0 letters/words:
"#{$!}"
So, for example, you may want AbstractRequest to be your abstract base class / interface that describes which methods *must* be implemented by subclasses.
And then have CgiRequest and TestRequest extend it.
But there's nothing stopping AbstractRequest (and CgiRequest) from specifying a method that TestRequest doesn't implement ... is there??
Maybe I just haven't seen it yet.
To define your own constructor to a class, it would make the most sense (to me at least) to define a method named new (since that's what you call when you instantiate an object). But you actually have to define a method called initialize.
To further confuse things, the RDoc docs that are generated apparently list the initialize method you created as new rather than initialize.
class String
def is_integer?
self == self.to_i.to_s
end
end
It's easy to make this mistake. I've made it many times and I've seen others make it.
You copy and paste and existing method to get you started. You start modifying your new method... Only problem is, it still has the same name as the old method, so it just silently overrides the old method.
Usually you will notice this as soon as you try calling the method with the name that the new method is supposed to have (but doesn't, so it will have a NoMethodError).
Sometimes, it's a lot more subtle, however. For example, in tests, you never explicitly call the test methods -- they are found and executed through introspection. So if you accidentally have two methods named test_1, only the second one will ever get executed... and you may never find out about your problem because it won't throw any errors.
This problem is common to most OOP languages though.
Sometimes you actually want to see errors that are getting raised (imagine that) but for some reason, you don't see them. What is rescuing them?? And why?
This can be very hard to track down, but here is one strategy I have used...
At the place where you are raising an error that seems to be getting inexplicably rescued, put this:
require 'pp'; raise 'error' rescue pp $!.backtrace
The rescue must be in one of the files listed... start checking!
Can't do method names like:
That's tolerable, at least. Just change 's into _s.
What's really annoying, though, is that when you alias operator methods, you have to represent the operators (which originally used special punctuation characters) with a plain-jane alphanumeric name.
So you see things like this (which I think is kind of ugly):
alias :original_reader :[]
alias :[] :hierarchical_reader
alias :original_writer :[]=
alias :[]= :hierarchical_writer
I don't like this limitation, but I can see how it could make the parsing ambiguous if such symbols were allowed in method names. Then would original_[] mean send(:original_[]) or send(:original_).send(:[])?
obj.send(:attribute=, new_value) behaves differently from obj.attribute = new_valueI would have expected them to behave identically, but they don't.
obj.send(:attribute=, new_value) : returns the return value given in the attribute=() method.obj.attribute = new_value== : returns new_value, irrespective of the return value given in the attribute=() method.Proof:
> class Object; def foo=(new_value); puts 'Got here'; 'bogus'; end; end > o = Object.new > v = o.send(:foo=, 'new value'); v Got here => "bogus" > v = (o.foo = 'new value'); v Got here => "new value"
This isn't a huge problem, since one hardly ever calls a setter method by way of __send__. Still, it doesn't seem right that it would ignore the return value of the setter method. Or if it does choose to ignore it, then it should ignore it consistently. It can be very disconcerting to a programmer to get two different values from (what they thought was) two identical calls to the same method.
I bet the Ruby interpret just takes a shortcut ... whenever it sees an "assignment", it thinks that you always want the right-hand value returned... which may be true, actually! But if that is the behavior for an "assignment", then a obj.send(:attribute=, new_value) ought to behave identically (return the same return value), IMHO.
For example, who knew that if you override the built-in method method for an object, then you can't use pp to pretty print the object.
Ruby / Problems / If you override method, pp will break edit
Contrived example:
irb -> 'foo'.method(:inspect)
=> #<Method: String#inspect>
irb -> class String; def method; rand<0.5 ? 'get' : 'post'; end; end
=> nil
irb -> 'foo'.method
=> "get"
irb -> 'foo'.method
=> "post"
irb -> pp 'foo'
ArgumentError: wrong number of arguments (1 for 0)
from /usr/lib/ruby/1.8/pp.rb:258:in `method'
from /usr/lib/ruby/1.8/pp.rb:258:in `pretty_print'
from /usr/lib/ruby/1.8/pp.rb:140:in `pp'
from /usr/lib/ruby/1.8/prettyprint.rb:201:in `group'
from /usr/lib/ruby/1.8/prettyprint.rb:227:in `nest'
from /usr/lib/ruby/1.8/prettyprint.rb:200:in `group'
from /usr/lib/ruby/1.8/prettyprint.rb:212:in `group_sub'
from /usr/lib/ruby/1.8/prettyprint.rb:199:in `group'
from /usr/lib/ruby/1.8/pp.rb:140:in `pp'
from /usr/lib/ruby/1.8/pp.rb:77:in `pp'
from /usr/lib/ruby/1.8/pp.rb:119:in `guard_inspect_key'
from /usr/lib/ruby/1.8/pp.rb:77:in `pp'
from /usr/lib/ruby/1.8/pp.rb:60:in `pp'
from /usr/lib/ruby/1.8/pp.rb:59:in `each'
from /usr/lib/ruby/1.8/pp.rb:59:in `pp'
from (irb):14
That's because pretty_print is defined thusly in /usr/lib/ruby/1.8/pp.rb :
def pretty_print(q)
if /\(Kernel\)#/ !~ method(:inspect).inspect
q.text self.inspect
elsif /\(Kernel\)#/ !~ method(:to_s).inspect && instance_variables.empty?
q.text self.to_s
else
q.pp_object(self)
end
end
That happened to me in real life in a Rails application when I tried to do this from a controller:
pp request
Because, of course, ActionController::AbstractRequest defines the method method in terms of an HTTP request (get, post, delete, etc.).
This seems to me a bit too dangerous, that we're allowed to casually and easily override method only to run into an unusual run-time error later on due to the redefined method method!
Once a method is overridden, can you still access the original method? No, not unless you've explicitly created an alias to the method before redefining it (and who has the foresight to do that??).
It would be nice if you always had access to every version of a method that an object has ever had. Maybe you could look it up by module/class name. For example, if I wanted my Request object to use the "original" version of method during the portion of my code in which I called pp, then I could do something like this:
request.use_method_version(:method, from = Kernel) do
pp request
end
That's not currently possible. [Correction: it is.]
Maybe one could remove_method the method, re-mix-in the original module (Kernel), call the method that needs the original method, and then remove_method the method again and re-mix-in the last module?? Even if that would work (and I kind of doubt it), it would be very messy.
Or maybe all built-in/core methods could have a shadow method, like _method or _inspect, that is always available. The main problem with that is that you'd have to make sure that everywhere that wants the original implementation is calling the shadow method and not the normal method -- something that's nearly impossible to ensure.
Wow! I just discovered how to do it ... by looking at the source for PP, of all the unlikely places! PP defines this interesting method:
def PP.mcall(obj, mod, meth, *args, &block)
mod.instance_method(meth).bind(obj).call(*args, &block)
end
When I saw that, I was like "Wait a second! That does exactly what I'm trying to do here!" It calls the method implementation from the module of your choice on the object of your choice.
So all I had to do was change this line:
if /\(Kernel\)#/ !~ method(:inspect).inspect
to this line:
if /\(Kernel\)#/ !~ Kernel.instance_method(:method).bind(self).call(:inspect).inspect
and my test case (pp 'foo') started working!
Kind of ironic that the authors of PP knew about this trick but they didn't think to use it in their implementation of pretty_print.
This is the final version of the patched method (2 lines were changed) [Patches (category)]:
/usr/lib/ruby/1.8/pp.rb
def pretty_print(q)
if /\(Kernel\)#/ !~ Kernel.instance_method(:method).bind(self).call(:inspect).inspect
q.text self.inspect
elsif /\(Kernel\)#/ !~ Kernel.instance_method(:method).bind(self).call(:to_s).inspect && instance_variables.empty?
q.text self.to_s
else
q.pp_object(self)
end
end
(Also, for reference (in case you wonder what that regexp comparison is all about):
irb -> 'foo'.method(:inspect)
=> #<Method: String#inspect>
irb -> Kernel.method(:inspect)
=> #<Method: Module(Kernel)#inspect>
irb -> Class.method(:inspect)
=> #<Method: Class(Kernel)#inspect>
irb -> Array.method(:inspect)
=> #<Method: Class(Kernel)#inspect>
irb -> puts String.instance_methods.sort.map { |m| 'foo'.method(m) }.select { |m| m.inspect =~ /Kernel/ }
#<Method: String(Kernel)#===>
#<Method: String(Kernel)#__id__>
#<Method: String(Kernel)#__send__>
#<Method: String(Kernel)#class>
#<Method: String(Kernel)#clone>
#<Method: String(Kernel)#display>
#<Method: String(Kernel)#dup>
#<Method: String(Kernel)#equal?>
#<Method: String(Kernel)#extend>
#<Method: String(Kernel)#freeze>
#<Method: String(Kernel)#frozen?>
#<Method: String(Kernel)#gem>
#<Method: String(Kernel)#id>
#<Method: String(Kernel)#instance_eval>
#<Method: String(Kernel)#instance_of?>
#<Method: String(Kernel)#instance_variable_get>
#<Method: String(Kernel)#instance_variable_set>
#<Method: String(Kernel)#instance_variables>
#<Method: String(Kernel)#is_a?>
#<Method: String(Kernel)#kind_of?>
#<Method: String(Kernel)#method>
#<Method: String(Kernel)#methods>
#<Method: String(Kernel)#nil?>
#<Method: String(Kernel)#object_id>
#<Method: String(Kernel)#pretty_inspect>
#<Method: String(Kernel)#private_methods>
#<Method: String(Kernel)#protected_methods>
#<Method: String(Kernel)#public_methods>
#<Method: String(Kernel)#require>
#<Method: String(Kernel)#require_gem>
#<Method: String(Kernel)#respond_to?>
#<Method: String(Kernel)#send>
#<Method: String(Kernel)#singleton_methods>
#<Method: String(Kernel)#taint>
#<Method: String(Kernel)#tainted?>
#<Method: String(Kernel)#type>
#<Method: String(Kernel)#untaint>
)
Aliases: Ruby / Problems, Ruby / Problems with Ruby, Ruby / Complaints about Ruby, Ruby / Complaints