Ruby if regex help needed - ruby

I am attempting to modify someone's script.
I have managed to modify everything but there is one problem left I am unable to solve:
disp_status("\tAnswer: #{convert_err(results["status"])}")
This produces various outputs as it is run, however, when the output is "ERROR", I want it to do an action. I am not sure how to limit it to "Error", as it appears to always run the method no matter the output.
What I tried was:
if #{convert_err(results["status"])} =~ /ERROR/
and a lot of similar iterations without any luck. Can anyone help?

In ruby interpolation doesn't work without double-quotes. But using interpolation here is an over kill, so just change the line in question from:
if #{convert_err(results["status"])} =~ /ERROR/
To
if convert_err(results["status"]) =~ /ERROR/
And should it should work! :-)

I think the .include? method might be helpful. You could do:
if "#{convert_err(results["status"])}".include?("ERROR")
Furthermore if convert_err returns a string you could just call:
if convert_err(results["status"]).include?("ERROR")
And another option would be to call .to_s which will convert the result of convert_err to a string. So that would look like:
if convert_err(results["status"]).to_s.include?("ERROR")
For further reference read: http://www.ruby-doc.org/core-2.1.4/String.html#method-i-include-3F

Related

Can I put an if/unless clause on the next line in Ruby?

In Perl, I often find myself using the following pattern:
croak "incompatible object given: $object"
unless $object->isa('ExampleObject') and $object->can('foo');
I tried to translate this into Ruby like this:
raise ArgumentError, "incompatible object given: #{object.inspect}"
unless object.is_a?(ExampleObject) and object.respond_to?(:foo)
But that does not work because Ruby interprets unless as the start of a new statement. As far as I understand, I can put a backslash at the end of the first line, but that looks ugly and feels wrong. I could also use a regular unless condition raise error end structure, but I like the style of the original form more. Is there a nice (and idiomatic) way to write this as a single statement in Ruby?
Can I put an if/unless clause on the next line in Ruby?
You can't. From page 107 (PDF page 127) of the final draft of ISO Ruby which usually isn't relevant, but basic things like this are and it also spares us from having to read parse.y:
unless-modifier-statement ::
statement [no line-terminator here] unless expression
This is pretty clear. It just doesn't get more similar to your Perl example than:
raise ArgumentError, "incompatible object given: #{object.inspect}" unless
object.is_a?(ExampleObject) and object.respond_to?(:foo)`
or:
raise ArgumentError, "incompatible object given: #{object.inspect}" \
unless object.is_a?(ExampleObject) and object.respond_to?(:foo)
Just as you feel wrong to put a backslash at the end to force a single line statement, it is wrong to use a single line statement when it extends beyond a single line.
This is not really a solution, I was sloppy when reading the question. The OP wants a solution without backslash.
You should be able to do this:
raise ArgumentError, "incompatible object given: #{object.inspect}" \
unless object.is_a?(ExampleObject) and object.respond_to?(:foo)
The \ characters tells ruby to keep reading as if there was no line break.
As far as I know there is no other way than a \, since otherwise, as you already said, Ruby thinks it's a new statement.
Keep in mind that style guides and conventions differ from language to language. In Ruby I'd not expect an if/unless statement in a line coming after it's code. In fact I even dislike putting if/unless at the end of a line, since it reverses the reading direction from If this, then that to that, if this (then what? Ah, I need to read back again), especially when the condition is more complex than raise 'foo' if bar.empty?.
In Perl and other languages though this might be different, since you have other conventions, style guides and this ;-thingy ;)

Ruby: "undefined method" error; how to use gsub more effectively?

So I'm trying to find a way to Donald Duck-ify statements inputed by users (judge me later).
This is my code so far:
puts "Wanna get Donald Duck-ified?"
print "Type some text here:"
user_input = gets.chomp
if user_input.gsub!(/s/,"th").gsub!(/ce/,"th").gsub!(/ci/,"th").gsub!(/cy/,"th")
puts "Boop - there go your s's and soft c's!"
else
puts "Dang, you didn't have any s's or soft c's!"
end
puts "#{user_input}"
Upon testing it with some input of my own ("square cycle caesar circle", specifically), I'm getting "undefined method `gsub!' for nil:NilClass" as an error.
How is gsub! undefined? If the code runs with user_input.gsub!(/s/,"th") on it own, without any other methods behind it, it works fine. Once a second method is added, the else code runs and only replacements for "s" are made. All four and I get the error above.
Does there happen to be another way of substituting multiple patterns (as named by the Ruby docs) with a single replacement? I've spent the last hours researching the problem and I still can't totally tell what the issue is.
New to Ruby. Encouraged and motivated.
Many thanks in advance.
Don't use #gsub! chained. (Actually, don't use #gsub! at all for most code.)
[gsub!] Performs the substitutions of String#gsub in place, returning str, or nil if no substitutions were performed.
Switch the code to #gsub which doesn't cause side-effects (yay!) and always returns a string (yay!) - simply compare the result with the original (unmodified) string.
Also, one could use the gsub form that accepts a hash (since Ruby 1.9.something). This has a subtle difference that replaced values will not be themselves replaced, although it doesn't matter here.
user_input.gsub(/s|ce|ci|cy/, { "s"=>"th", "ce"=>"th", "ci"=>"th", "cy"=>"th" })
# or since all are replaced with "th" (which I just noticed =^_^=) ..
user_input.gsub(/s|ce|ci|cy/, "th")
(I still recommend against gsub! because I find side effects upon strings disconcerting. However, it would work reliably when used with the non-chained forms above.)
Ruby's gsub! returns nil if it performs no substitutions. This means you can't reliably chain it like you do. If you want to verify that any of the gsubs have made any change, you can chain non-destructive gsubs (without the bang; return a new string instead of modifying the current one) instead:
input = gets.chomp
replaced = input.gsub(/s/,"th").gsub(/ce/,"th").gsub(/ci/,"th").gsub(/cy/,"th")
if input == replaced
...

Basic Help: Reading Ruby Script Case Syntax

I've never done a thing with ruby script before, and was hoping someone here would have a quick answer. I'm on a time sensitive project, and was hoping SO could provide some insight.
I've googled around here, and sought out some ruby script guides, and think I understand most of the following code, but there are a few things I wasn't able to figure out.
I have the following exceprt from a ruby script, and I just need to know what it's doing:
where docName and document_name are a string of a file path
case docName
when /^QRX/ then document_name = "/TRPRR/#{docName}"
when /^BVN/ then document_name = "/TRPRR/#{docName}"
....
There are a bunch of other cases, and I understand case statements. I don't understand the following:
Is the /^QRX/ some kind of regular expression or something? And what does the #{docName} do?
Yes, the /^QRX/, etc. performs a regular expression match against docName, and if it matches, it performs the code following.
The #{docName} is how ruby handles string interpolation:
docName = "foo"
puts "/TRPRR/#{docName}" # Outputs "/TRPRR/foo"

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.

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!

Resources