Call Method on object if Object Exists - ruby

Is there a more elegant way of writing this?
#on_connection_callback.call() if #on_connection_callback
It's having to reference #on_connection_callback twice that's irking me.

you may write this as
#on_connection_callback.call() rescue nil

I like things like the "andand" gem which allows:
#on_connection_callback.andand.call()
There are other options, like various try implementations.

#on_connection_callback.call() if #on_connection_callback
is fine, and is actually the fastest way to test. I recently did a benchmark test here proving that the above is slightly faster than:
#on_connection_callback && #on_connection_callback.call()

Use this little gem:
tryit { #on_connection_callback.call() }

#on_connection_callback.instance_eval{call if self}
Or
->p{p.call if p}.call(#on_connection_callback)

Related

Is there no convenience method for !nil?

I think I would see my code better if I would ask myself object.not_nil? vs !object.nil?. So my question: Is there really no convenience method for !nil? to sugar things up? Is it in front of my eyes and I cannot see it or am I just missing an important point?
How about this?
not object.nil?
But the easier thing to do would be to check for the "truthiness" of by testing the variable itself. Since nil is implicitly false you can just check object.
You can introduce the sugar at an upper level. Instead of:
if not object.nil?
you can write:
unless object.nil?
What about this ?
if object
# sth
end
It is not the same as it will not be executed if object is false but depending on you code, it could be better.
Another solution (which is not the same either), as you tagged your question with ruby-on-rails-3 : using present? which will not execute the block for [] or {} unlike !object.nil?.
Again another one depending of the case : using unless which won't be really nice if your condition is more complex (with && and/or ||).
If your condition is of this form :
if !object.nil? && object.something?
# sth
end
You can use try, as you are using Rails, like this :
if object.try(:something?)
# sth
end
In all the other cases, !object.nil? or not object.nil? stays the best solution I guess.
When convenience around #nil? is discussed, Activesupport's methods #blank? and #present? shouldn't be forgotten either.
Not that you'd necessarily want to, but you can introduce not_nil? yourself:
class Object
def not_nil?
!self.nil?
end
end
then you can do things like:
nil.not_nil?
==> false
3.not_nil?
==> true
a = []
a.not_nil?
==> true

Call Ruby method with parameters separated by space

Not sure if this is possible but can I call a method from an irb shell with spaces between parameters rather than commas (don't ask) ? Lets say I have a method
def start_band(member1, member2, member3, member4)
#do something
end
And then I call it like the following:
irb>> start_band "John" "Paul" "George" "Ringo"
EDIT: Would it be possible to detect every keypress instead?
No, you can't do that. Not with strings anyway.
No.
You could use something like treetop to write a really simple DSL, or just play monkey-parsing games, but that won't solve your exact question.
The other obvious answer is this, which also fails:
irb>> start_band %W(John Paul George Ringo)
Creating an irb-like CLI isn't difficult, and may be adequate, depending on what your actual requirements are.
There is actually a very easy way to get rid of the commas. You can even get rid of the quotes, too:
def start_band(members)
#members is an array
end
start_band %w(John Paul George Ringo)
The limitation is that you can't use spaces inside your strings, and you still need start-end terminations (can use other characters instead of parenthesis though).
Durr! I really approached this the wrong way. I simply needed to run
#members = gets
to allow the input as required. Thanks for the responses nonetheless.

Rspec: Should be (this or that)

What would be the best way to write the rspec in a situation where either of two (or more) outcomes are acceptable?
Here's an example of what I want to do. This is obviously wrong (I think), but it should give you the gist of what I'm trying to accomplish:
it "should be heads or tails" do
h="heads"
t="tails"
flip_coin.should be(h || t)
end
And yes, I'm aware I could write my own rspec matcher "should_be_one_or_the_other(option1,option2)", but that seems a bit much - I was hoping for a better solution.
ActiveSupport provides Object#in? method. You can combine it with RSpec and simply use the following:
flip_coin.should be_in(["heads", "tails"])
Or with new Rspec 3 syntax:
expect(flip_coin).to be_in(["heads", "tails"])
I know this is old but in I ran into this on RSpec 3.4, there is an or method now. So this is valid:
expect(flip_coin).to eq('heads').or(eq('tails'))
I'd probably write something like this:
it "should be heads or tails" do
["heads", "tails"].should include flip_coin
end
Another way of writing it with the expectation on the right of the should:
it 'should be heads or tails' do
flip_coin.should satisfy{|s| ['heads', 'tails'].include?(s)}
end
if applied or with be matcher
expect(flip_coin).to eq('heads').or(be == 'tails')
You can solve this by flipping the comparison:
expect(['head','tails']).to include(flip_coin)

How do I suppress string interpolation issues in ruby

I have the following code:
address = "#{(article/"div.address").inner_html.strip_html.squish}"
(using Hpricot)
And in some instances...
address = "#{(article/"div.address").inner_html.strip_html.squish}"
...is nil
I would like the script to keep chugging along, possibly replacing nil with an empty string.
Any tips?
Edit
I have traced the problem better to:
puts "#{link[0].to_s}\n" unless link.empty?
(.backtrace points to this particular line in the source.)
So the revised question is: why doesn't that line just not get parsed? Why does it throw an error? I thought that using unless will just skip it...
Use :to_s method:
nil.to_s == ''
Is try what you are looking for? http://api.rubyonrails.org/classes/Object.html#method-i-try
Thank you all for the support and helpful tips, in the end it was a matter of using the proper method, I ended up solving my problem by using:
unless uri.query.nil?
But I did come to make use of both .to_s and try in my source, and I wish I could pick two answers as the right one!

Why is "#{String}" a common idiom in Ruby

A Ruby dev I know asked this; my answer is below... Are there other, better reasons?
Why do so many Ruby programmers do
"#{string}"
rather than
string
since the second form is simpler and more efficient?
Is this a common idiom for Ruby developers? I don't see it that much.
Smaller changes when you later need to do more than simply get the value of the string, but also prepend/append to it at the point of use seems to be the best motivation I can find for that idiom.
There is only one case where this is a recommended idiom :
fname = 'john'
lname = 'doe'
name = "#{fname} #{lname}"
The code above is more efficient than :
name = fname + ' ' + lname
or
name = [fname, lname].join(' ')
What's the broader context of some of the usages? The only thing I can come up with beyond what's already been mentioned is as a loose attempt at type safety; that is, you may receive anything as an argument, and this could ensure that whatever you pass in walks like a duck..or, well, a string (though string.to_s would arguably be clearer).
In general though, this is probably a code smell that someone along the way thought was Best Practices.
I use this kind of code, so that I can pass nil as string and it still will work on a string, rather than seeing some exceptions flying:
def short(string = nil)
"#{string}"[0..7]
end
And it's easier/faster to append some debug code, if it's already in quotes.
So in short: It's more convenient.
Interesting answers, everyone. I'm the developer who asked the original question. To give some more context, I see this occasionally at my current job, and also sometimes in sample code on the Rails list, with variables that are known in advance to contain strings. I could sort of understand it as a substitute for to_s, but I don't think that's what's going on here; I think people just forget that you don't need the interpolation syntax if you're just passing a string variable.
If anyone tried to tell me this was a best practice, I'd run away at top speed.
maybe it is easy way to convert any to string? Because it is the same as call to_s method. But it is quite strange way :).
a = [1,2,3]
"#{a}"
#=> "123"
a.to_s
#=> "123"
I could image this being useful in cases where the object being interpolated is not always a String, as the interpolation implicitly calls #to_s:
"#{'bla'}" => "bla"
"#{%r([a-z])}" => "(?-mix:[a-z])"
"#{{:bla => :blub}}" => "blablub"
May make sense when logging something, where you don't care so much about the output format, but never want an error because of a wrong argument type.

Resources