What is the counterpart for expression `?value1:value2` in ruby? - ruby

I want to know what the counterpart is in Ruby for this kind of expression:
var status=false;
var xx=new Obj(xx,status?"0":"1",status?"2":"3");
I tried the same in Ruby, but it seems that the syntax:
status?"23":nil
does not work.

Method names can end with question marks, so use more spaces:
status ? "23" : nil
Equivalently you could write:
("23" if status)

Put a space between status and ?. Seems that it might get parsed as a method name status?. Also, don't terminate your sentences with semicolons. And don't use var.
x = status ? "0" : "1"

Related

ruby: workarounds for nested string interpolation

In the string
"#{x ? (x.to_s + ' is ') : ''}ok", Rubocop's Style/StringConcatenation suggests avoiding the +.
But that requires a nested string interpolation
"#{x ? '#{x.to_s} is ' : ''}ok)",
which at least in Ruby 2.7 is not expanded: #{x.to_s} is treated like any other literal.
Is the + version alright because it's on the fringes of what a style guide could cover, or must one introduce a temporary variable?
tmp = x ? '#{x.to_s} is ' : ''
"#{tmp}ok"
Context: the string is sent to a logfile. ok is actually a long list of details. x is worth logging, but only when it exists.
Yes, a variable will make this more readable (imo):
prefix = "#{x} is " if x
"#{prefix}ok"
(this relies on the fact that nil#to_s == '')
Given that "ok" is actually:(according to the comments)
"...a long string that has even more interpolations. Duplicating that string isn't DRY".
I would go with
ok = generate_some_long_string()
ok.prepend("#{x} is ") if x
ok
This does mutate ok but based on my understanding of the question this may actually be desirable.
Nesting Interpolation
As an aside and I would not recommend it (because it is difficult to read) but nesting interpolation is completely valid ruby e.g.
x="val"
"#{x ? "#{x} is " : ""}ok"
#=> "val is ok"
This works because what is inside the interpolation closure is treated like any other ruby code. The inner double quotes open and close a new String rather than closing the first and opening another because the interpolation closure is waiting for a closing curly brace. You could technically do this at any depth.
"#{x ? "#{"the #{y = x}ue of"} #{x} is " : ""}#{y.inspect}"
#=> "the value of val is \"val\""

Interpolation with conditionals

I want to insert data into a string via interpolation. I want to check if #call.transferred_from is nil, and if so, output #call.transfer_from_other; else output #call.transferred_from.try(:facility_name) along with #call.transferred_from.try(:facility_address).
Here is my code example:
"#{if #call.transferred_from.nil? #call.transfer_from_other else #call.transferred_from.try(:facility_name) #call.transferred_from.try(:facility_address) end}"
Doing this gives me the following error:
syntax error, unexpected keyword_else, expecting keyword_then or ';' or '\n'
I'm not sure where to go. Any help would be appreciated.
Update: 08/04/14
I moved the conditional into a private controller method as follows:
def transfer_from_address
if #call.transferred_from.nil?
#call.transfer_from_other
else
#call.transferred_from.try(:facility_name) + ' ' + #call.transferred_from.try(:facility_address)
end
end
Then I call the following using string interpolation.
#{transfer_from_address}
This seems to work, but I'm not sure that it's proper Ruby.
I know this is not really answering your question, but I'd caution about putting this much logic in an interpolation. While its totally doable, it makes your code very hard to understand.
The fundamental issue I see with your particular issue is you're trying to return 2 things somehow, yet you're just putting both of them next to eachother which is not valid ruby.
Assuming this is in an interpolation you'd want to somehow return them together ..
#{
#call.transferred_from.nil? ?
#call.transfer_from_other :
#call.transferred_from.try(:facility_name) + ' ' + #call.transferred_from.try(:facility_address)
}
I'd really suggest you move this into a variable or a method tho .. and just reference it in the interpolation.
This could look something like:
facility_name_and_address = #call.transferred_from.nil? ? #call.transfer_from_other : #call.transferred_from.try(:facility_name) + ' ' + #call.transferred_from.try(:facility_address)
{
:body => facility_name_and_address
}
If I understand what you are trying to do, I would suggest adding a method to #call which does the job:
class Call
def transfer_text
return transfer_from_other if transferred_from.nil?
"#{transferred_from.try(:facility_name)} #{transferred_from.try(:facility_address)}"
end
end
Then simply calling #call.transfer_text should provide the needed text.
If you want to be more sophisticated, and you don't want trailing white-space in case facility_name or facility_address are nil, you can create a list of them, and join them with white space:
[transferred_from.try(:facility_name), transferred_from.try(:facility_address)].compact.join(' ')
This will make sure spaces will be only between to non-nil elements. If both are nil, and empty string will be the result (rather than a space), and if one is nil, it won't have a leading/trailing space.
why not using
:body => "#{#call.transferred_from.nil? ? #call.transfer_from_other : #call.transferred_from.try(:facility_name) #call.transferred_from.try(:facility_address)"
but anyway I would not use this compact syntax for better maintainability
You just need to put either a semicolon or then right after the condition.
if #call.transferred_from.nil?; #call.transfer_from_other ...
But in your case, there is not much point in putting the entire condition inside a string interpolation. It is better to do the condition outside the string.
By the way, if you fix your first error, then you might encounter the next error:
#call.transferred_from.try(:facility_name) #call.transferred_from.try(:facility_address)
To fix that as well, I think you should do
#call.transferred_from.instance_eval{|e| e.nil? ?
#call.transfer_from_other.to_s :
"#{e.try(:facility_name)} #{e.try(:facility_address)}"
}

Ruby gsub / regex with several arguments [duplicate]

This question already has answers here:
Match a string against multiple patterns
(2 answers)
Closed 8 years ago.
I'm new to ruby and I'm trying to solve a problem.
I'm parsing through several text field where I want to remove the header which has different values. It works fine when the header always is the same:
variable = variable.gsub(/(^Header_1:$)/, '')
But when I put in several arguments it doesn't work:
variable = variable.gsub(/(^Header_1$)/ || /(^Header_2$)/ || /(^Header_3$)/ || /(^Header_4$)/ || /^:$/, '')
You can use Regexp.union:
regex = Regexp.union(
/^Header_1/,
/^Header_2/,
/^Header_3/,
/^Header_4/,
/^:$/
)
variable.gsub(regex, '')
Please note that ^something$ will not work on strings containing something more than something :)
Cause ^ is for matching beginning of string and $ is for end of string.
So i intentionally removed $.
Also you do not need brackets when you only need to remove the matched string.
You can also use it like this:
headers = %w[Header_1 Header_2 Header_3]
regex = Regexp.union(*headers.map{|s| /^#{s}/}, /^\:$/, /etc/)
variable.gsub(regex, '')
And of course you can remove headers without explicitly define them.
Most likely there are a white space after headers?
If so, you can do it as simple as:
variable = "Header_1 something else"
puts variable.gsub(/(^Header[^\s]*)?(.*)/, '\2')
#=> something else
variable = "Header_BLAH something else"
puts variable.gsub(/(^Header[^\s]*)?(.*)/, '\2')
#=> something else
Just use a proper regexp:
variable.gsub(/^(Header_1|Header_2|Header_3|Header_4|:)$/, '')
If the header is always the same format of Header_n, where n is some integer value, then you can simplify your regex greatly:
/Header_\d+/
will find every one of these:
%w[Header_1 Header_2 Header_3].grep(/Header_\d+/)
[
[0] "Header_1",
[1] "Header_2",
[2] "Header_3"
]
Tweaking it to handle finding words, not substrings:
/^Header_\d+$/
or:
/\bHeader_\d+\b/
As mentioned, using Regexp.union is a good start, but, used blindly, can result in very slow or inefficient patterns, so think ahead and help out the engine by giving it useful sub-patterns to work with:
values = %w[foo bar]
/Header_(?:\d+|#{ values.join('|') })/
=> /Header_(?:\d+|foo|bar)/
Unfortunately, Ruby doesn't have the equivalent to Perl's Regexp::Assemble module, which can build highly optimized patterns from big lists of words. Search here on Stack Overflow for examples of what it can do. For instance:
use Regexp::Assemble;
my #values = ('Header_1', 'Header_2', 'foo', 'bar', 'Header_3');
my $ra = Regexp::Assemble->new;
foreach (#values) {
$ra->add($_);
}
print $ra->re, "\n";
=> (?-xism:(?:Header_[123]|bar|foo))

Using regex to find an exact pattern match in Ruby

How would I go about testing for an exact match using regex.
"car".match(/[ca]+/) returns true.
How would I get the above statement to return false since the regex pattern doesn't contain an "r"? Any string that contains any characters other than "c" and "a" should return false.
"acacaccc" should return true
"acacacxcc" should return false
Add some anchors to it:
/^[ca]+$/
You just need anchors.
"car".match(/^[ca]+$/)
This'll force the entire string to be composed of "c" or "a", since the "^" and "$" mean "start" and "end" of the string. Without them, the regex will succeed as long as it matches any portion of the string.
Turn your logic around and look for bad things:
string.match(/[^ca]/)
string.index(/[^ca]/)
If either of the above are non-nil, then you have a bad string. If you just want to test and don't care about where it matches then:
if string.index(/[^ca]/).nil?
# You have a good string
else
# You have a bad string
For example:
>> "car".index(/[^ca]/).nil?
=> false
>> "caaaacaac".index(/[^ca]/).nil?
=> true
try this
"car".match /^(a|c)+$/
Try this:
"car".match(/^(?:c|a)$/)

gsub! On an argument doesn't work

I am making a function that turns the first argument into a PHP var (useless, I know), and set it equal to the second argument. I'm trying to gsub! it to get rid of all the characters that can't be used in a PHP var. Here is what I have:
dvar = "$" + name.gsub!(/.?\/!#\#{}$%^&*()`~/, "") { |match| puts match }
I have the puts match there to make sure some of the characters were removed. name is a variable passed into a method in which this is its purpose. I am getting this error:
TypeError: can't convert nil into String
cVar at ./Web.rb:31
(root) at C:\Users\Andrew\Documents\NetBeansProjects\Web\lib\main.rb:13
Web.rb is the file this line is in, and main.rb is the file calling this method. How can I fix this?
EDIT: If I remove the ! in gsub!, it goes through, but the characters aren't removed.
Short answer
Use dvar = "$" + name.tr(".?\/!#\#{}$%^&*()``~", '')
Long answer
The problem you are facing is that the gsub! call is returning nil. You can't concatenate (+) a String with a nil.
That's happening because you have a malformed Regexp. You aren't escaping the special regex symbols, like $, * and ., just for a start. Also, the way it is now, gsub will only match if your string contains all that symbols in sequence. You should use the pipe (|) operator to make an OR like operation.
gsub! will also return nil if no substitutions happened.
See the documentation for gsub and gsub! here: http://ruby-doc.org/core/classes/String.html#M001186
I think you should replace gsub! with gsub. Do you really need name to change?
Example:
name = "m$var.name$$"
dvar = "$" + name.gsub!(/\$|\.|\*/, "") # $ or . or *
# dvar now contains $mvarname and name is mvarname
Your line, corrected:
dvar = "$" + name.gsub(/\.|\?|\/|\!|\#|\\|\#|\{|\}|\$|\%|\^|\&|\*|\(|\)|\`|\~/, "")
# some things shouldn't (or aren't needed to) be escaped, I don't remember them all right now
As J-_-L appointed, you could also use a character class ([]), that makes it a little clearer, I guess. Well, it's hard to mentally parse anyway.
dvar = "$" + name.gsub(/[\.\?\/\!\#\\\#\{\}\$\%\^\&\*\(\)\`\~]/, "")
But because what you are doing is simple character replacement, the best method is tr (again reminded by J-_-L!):
dvar = "$" + name.tr(".?\/!#\#{}$%^&*()`~", '')
Way easier to read and make modifications.
You cannot apply a second parameter
and a block to gsub (the block is ignored)
The regex is wrong, you forgot the
square brackets:
/[.?\/!#\#{}$%^&*()~]/`
Because your regex is wrong, it
didn't match anything and because
gsub! returns nil if nothing was
replaced, you get this strange nil no
method error
btw: you should use gsub not gsub! in
this case, because you are using the
return value (and not name itself) --
and the error would not have happened
i dont see what the block is for
just do
name = 'hello.?\/!##$%^&*()`~hello'
dvar = "$" + name.gsub(/\.|\?|\\|\/|\!|\#|\#|\{|\}|\$|\%|\^|\&|\*|\(|\)|\`|\~/, "")
puts dvar # => "$hellohello"
or use [] to denote OR
dvar = "$" + name.gsub(/[\.\?\\\/\!\#\\\#\{\}\$\%\^\&\*\(\)\`\~]/, "")
you have to escape the special characters and then OR them so it will remove them individually not just if they are all found together
also there is really no need to use gsub! to modify the string in place use the non mutator gsub() since you assign it to a new variable,
gsub! returns nil for which the operator + is not defined for stings, which gives you the no method error mentioned
It seems as the 'name' object is nil, you may be calling gsub! on nil which usually complains with a NoMethodError: private method gusb! called for nilNilClass, since I don't know the version of ruby you are using I am not sure if the error would be the same, but it's a good place to start looking at.

Resources