Remove quotes from string built from an array - ruby-on-rails

I have user controller input like so (the length and # of items may change):
str = "['honda', 'toyota', 'lexus']"
I would like to convert this into an array, but I'm struggling to find the best way to do so. eval() does exactly what I need, but it is not very elegant and is dangerous in this case, since it's user controller input.
Another way is:
str[1..-2].split(',').collect { |car| car.strip.tr("'", '') }
=> ["honda", "toyota", "lexus"]
But this is also not very elegant. Any suggestions that are more 'Rubyish'?

You could use a regular expression:
# match (in a non-greedy way) characters up to a comma or `]`
# capture each word as a group, and don't capture `,` or `]`
str.scan(/'(.+?)'(?:,|\])/).flatten
Or JSON.parse (but accounting for the fact that single quotes are in fact technically not allowed in JSON):
JSON.parse( str.tr("'", '"') )
JSON.parse probably has a small edge over the regexp in terms of performance, but if you're expecting your users to do single quote escaping, then that tr is going to mess things up. In this case, I'd stick with the regexp.

The JSON.parse looks more correct, but here is another alternative:
str.split(/[[:punct:] ]+/).drop(1)

Related

Have anyone found beautiful way to replace "smth if smth.present?"?

Often I'm facing lines like
result = 'Some text'
result += some_text_variable if some_text_variable.present?
And every time I want to replace that with something more accurate but I don't know how
Any ideas plz?
result += some_text_variable.to_s
It will work if some_text_variable is nil or empty string for example
But it always will concat empty string to original string
You can also use
result += some_text_variable.presence.to_s
It will work for all presence cases (for example for " " string)
You could "compact" and join an array, e.g.
['Some text', some_text_variable].select(&:present?).join
I realise this is a longhand form, just offering as an alternative to mutating strings.
This can look a bit nicer, if you have a large number of variables to munge together, or you want to join them in some other way e.g.
[
var_1,
var_2,
var_3,
var_4
].select(&:present?).join("\n")
Again, nothing gets mutated - which may or may not suit your coding style.

Apply modification only to substring in Ruby

I have a string of the form "award.x_initial_value.currency" and I would like to camelize everything except the leading "x_" so that I get a result of the form: "award.x_initialValue.currency".
My current implementation is:
a = "award.x_initial_value.currency".split(".")
b = a.map{|s| s.slice!("x_")}
a.map!{|s| s.camelize(:lower)}
a.zip(b).map!{|x, y| x.prepend(y.to_s)}
I am not very happy with it since it's neither fast nor elegant and performance is key since this will be applied to large amounts of data.
I also googled it but couldn't find anything.
Is there a faster/better way of achieving this?
Since "performance is key" you could skip the overhead of ActiveSupport::Inflector and use a regular expression to perform the "camelization" yourself:
a = "award.x_initial_value.currency"
a.gsub(/(?<!\bx)_(\w)/) { $1.capitalize }
#=> "award.x_initialValue.currency"
▶ "award.x_initial_value.x_currency".split('.').map do |s|
"#{s[/\Ax_/]}#{s[/(\Ax_)?(.*)\z/, 2].camelize(:lower)}"
end.join('.')
#⇒ "award.x_initialValue.x_currency"
or, with one gsub iteration:
▶ "award.x_initial_value.x_currency".gsub(/(?<=\.|\A)(x_)?(.*?)(?=\.|\z)/) do |m|
"#{$~[1]}" << $~[2].camelize(:lower)
end
#⇒ "award.x_initialValue.x_currency"
In the latter version we use global substitution:
$~ is a short-hand to a global, storing the last regexp match occured;
$~[1] is the first matched entity, corresponding (x_)?, because of ? it might be either matched string, or nil; that’s why we use string extrapolation, in case of nil "#{nil}" will result in an empty string;
after all, we append the camelized second match to the string, discussed above;
NB Instead of $~ for the last match, one might use Regexp::last_match
Could you try solmething like this:
'award.x_initial_value.currency'.gsub(/(\.|\A)x_/,'\1#').camelize(:lower).gsub('#','x_')
# => award.x_initialValue.currency
NOTE: for # char can be used any of unused char for current name/char space.

Rails: Given a String, check if an Array (of strings) contains a substring of String

Is there a more Railsy way to do this (without explicit regex, perhaps?):
array_o_strings = ["some strings", "I'd like", "to parse"]
string = "like to parse"
re = Regexp.union(array_o_strings.map { |i| Regexp.new(i) })
string =~ re
Just pining for magical Rails methods.
There's really nothing wrong with using a regular expression here if that's your intent. It's generally more efficient to use one of those than to go through the trouble of comparing arrays.
It's worth noting you don't have to do that much work to get this:
re = Regexp.union(array)
That should handle automatically escaping those strings and compiling them into a singular regular expression. Test with strings containing * and ? to be sure.
One note to add on style is that the =~ operator is a hold-over from Perl. It's preferable to use string.match(re) to make it clear what's going on there.
How big is the array? It may be worth comparing the speed using a regex vs checking each element. If the array is sorted shortest to longest that would help when checking one by one as you're more likely to find a match first.
In any event, this is one way:
array_o_strings.any?{|e| string.index(e) }

Rails strip all except numbers commas and decimal points

Hi I've been struggling with this for the last hour and am no closer. How exactly do I strip everything except numbers, commas and decimal points from a rails string? The closest I have so far is:-
rate = rate.gsub!(/[^0-9]/i, '')
This strips everything but the numbers. When I try add commas to the expression, everything is getting stripped. I got the aboves from somewhere else and as far as I can gather:
^ = not
Everything to the left of the comma gets replaced by what's in the '' on the right
No idea what the /i does
I'm very new to gsub. Does anyone know of a good tutorial on building expressions?
Thanks
Try:
rate = rate.gsub(/[^0-9,\.]/, '')
Basically, you know the ^ means not when inside the character class brackets [] which you are using, and then you can just add the comma to the list. The decimal needs to be escaped with a backslash because in regular expressions they are a special character that means "match anything".
Also, be aware of whether you are using gsub or gsub!
gsub! has the bang, so it edits the instance of the string you're passing in, rather than returning another one.
So if using gsub! it would be:
rate.gsub!(/[^0-9,\.]/, '')
And rate would be altered.
If you do not want to alter the original variable, then you can use the version without the bang (and assign it to a different var):
cleaned_rate = rate.gsub!(/[^0-9,\.]/, '')
I'd just google for tutorials. I haven't used one. Regexes are a LOT of time and trial and error (and table-flipping).
This is a cool tool to use with a mini cheat-sheet on it for ruby that allows you to quickly edit and test your expression:
http://rubular.com/
You can just add the comma and period in the square-bracketed expression:
rate.gsub(/[^0-9,.]/, '')
You don't need the i for case-insensitivity for numbers and symbols.
There's lots of info on regular expressions, regex, etc. Maybe search for those instead of gsub.
You can use this:
rate = rate.gsub!(/[^0-9\.\,]/g,'')
Also check this out to learn more about regular expressions:
http://www.regexr.com/

regex basic url expression

Hi I'm creating a regular expression (ruby) to test the beginning and end of string. I have both parts but can't join them.
Beginning of string
\A(http:\/\/+)
End of string
(.pdf)\z
How to join?
Bonus if it could validate in-between and accept anything (to avoid http://.pdf)
By the way, rubular http://rubular.com is a neat place to validate expressions
Use .+ to match any character except \n one or more times.
\A(http:\/\/+).+(\.pdf)\z
Should match http://www.stackoverflow.com/bestbook.pdf but not http://.pdf

Resources