Validating a string inside of a string - ruby

I'm starting a cucumber automation and I'm struggling to validate a simple string,
cucumber is telling me the following:
expected: "[The value '123456789' is not valid.]"
got: ["The value '123456789' is not valid."]
the code I wrote for that validation: expect(#response['errors']['id']).to eql "[The value '123456789' is not valid.]"
how can I make such validation? Thanks everyone.

AhmeDEV49's answer is already good, I just want to suggest using another matcher, include instead of eql, like this:
expect(#response['errors']['id']).to include "The value '123456789' is not valid."
Then you do not have to care about the array brackets at all.

Maybe there is a mistake in your assertion :
Just move double quote inside your array
eql "[The value '123456789' is not valid.]"
to
eql ["The value '123456789' is not valid."]

The response was a array of strings, so the following worked:
expect(#response['errors']['id']).to eql ["The value '123456789' is not valid."]

Related

Removing a character from string in Rspec

I am new to Rspec and I am facing a little issue.
text = page.find(:xpath,"some xpath").text
the code line above gets the value from a html element i.e. 15% or any other value under 100, I want to remove % sign from the value after and getting it to use for comparison. Can anybody help on this?
You can use String#sub to replace it:
'15%'.sub('%', '') #=> '15'
You can also use gsub in case there is more than one occurrence:
'15%%%'.gsub('%', '') #=> '15'

Detect if string has substring from array of possibilities

Is there a way to check whether a string contains any substring in an array?
Say I have bad_words = ['broccoli', 'cabbage', 'kale'], and my_string = "My shopping list features pizza, gummy bears, kale, and vodka." I want to check whether my_string has any of the bad_words items within it without using a loop/iterator. Is this possible?
It seems like people use Array#index to solve this problem, but I'm not sure how because, in my tests, it only returns true if the entire argument matches an entire item from the array: bad_words.index "kale" returns an index but bad_words.index "no kale" returns nil. So it's no good for substrings.
my_string =~ /\b#{Regexp.union(bad_words)}\b/
#=> 46
will do.

Is there a method to extract integers from a string?

It seems that String#to_i only works when numbers are leading in a string.
Works:
"123acb".to_i #=> 123
Doesn't work, but what I'm trying to accomplish:
"abc123def".to_i #=> 123
I've been looking for a built in method to do this but I haven't found one. Is my only option to use a regular expression?
EDIT -
Wow! Lots of good options! As an aside, was there any specific reason why to_i only deals with leading numbers?
What about doing something like this?
"abc123def".gsub(/\D/, '').to_i
# => 123
If you want to handle multiple numbers inside a big string, you can do
"a22bc123de4f004".split(/\D/).reject(&:empty?).map(&:to_i)
# => [22, 123, 4, 004]
Here's another approach, using scan rather than split:
>> "abc123def456ghi".scan(/\d+/).join.to_i
=> 123456
Note that scan keeps while split throws away....
To answer the actual question "is there a built-in method to do this?" you can see from the Ruby String class documentation that there isn't, unless you take scan, split, to_i, delete and friends as "close enough" to being built-in.
"abc123def"[/\d+/].to_i
# => 123
Another one using delete
"abc123def456ghi".delete("^0-9").to_i
# => 123456
How about the below using String#tr ?
"abc123def456ghi".tr('a-z','').to_i
# => 123456
"abc123def456ghiA".tr('A-z','').to_i
# => 123456

Regex parsing of iCalendar (Ruby regex)

I'm trying to parse iCalendar (RFC2445) input using a regex.
Here's a [simplified] example of what the input looks like:
BEGIN:VEVENT
abc:123
def:456
END:VEVENT
BEGIN:VEVENT
ghi:789
END:VEVENT
I'd like to get an array of matches: the "outer" match is each VEVENT block and the inner matches are each of the field:value pairs.
I've tried variants of this:
BEGIN:VEVENT\n((?<field>(?<name>\S+):\s*(?<value>\S+)\n)+?)END:VEVENT
But given the input above, the result seems to have only ONE field for each matching VEVENT, despite the +? on the capture group:
**Match 1**
field def:456
name def
value 456
**Match 2**
field ghi:789
name ghi
value 789
In the first match, I would have expected TWO fields: the abc:123 and the def:456 matches...
I'm sure this is a newbie mistake (since I seem to perpetually be a newbie when it comes to regex's...) - but maybe you can point me in the right direction?
Thanks!
You need to split your regex up into one matching a VEVENT and one matching the name/value pairs. You can then use nested scan to find all occurences, e. g.
str.scan(/BEGIN:VEVENT((?<vevent>.+?))END:VEVENT/m) do
$~[:vevent].scan(/(?<field>(?<name>\S+?):\s*(?<value>\S+?))/) do
p $~[:field], $~[:name], $~[:value]
end
end
where str is your input. This outputs:
"abc:1"
"abc"
"1"
"def:4"
"def"
"4"
"ghi:7"
"ghi"
"7"
If you want to make the code more readable, i suggest you require 'english' and replace $~ with $LAST_MATCH_INFO
Use the icalendar gem.
See the Parsing iCalendars section for more info.
You need a nested scan.
string.scan(/^BEGIN:VEVENT\n(.*?)\nEND:VEVENT$/m).each.with_index do |item, i|
puts
puts "**Match #{i+1}**"
item.first.scan(/^(.*?):(.*)$/) do |k, v|
puts "field".ljust(7)+"#{k}:#{v}"
puts "name".ljust(7)+"#{k}"
puts "value".ljust(7)+"#{v}"
end
end
will give:
**Match 1**
field abc:123
name abc
value 123
field def:456
name def
value 456
**Match 2**
field ghi:789
name ghi
value 789
I think the problem is that the ruby MatchData object, which is what the regexp returns its results in, doesn't have any provision for more than one value with the same name. So your second match overwrites the first one.
Ruby has a seldom used method called slice_before that fits this need well:
'BEGIN:VEVENT
abc:123
def:456
END:VEVENT
BEGIN:VEVENT
ghi:789
END:VEVENT'.split("\n").slice_before(/^BEGIN:VEVENT/).to_a
Results in:
[["BEGIN:VEVENT", "abc:123", "def:456", "END:VEVENT"],
["BEGIN:VEVENT", "ghi:789", "END:VEVENT"]]
From there it's simple to grab just the inner array elements:
'BEGIN:VEVENT
abc:123
def:456
END:VEVENT
BEGIN:VEVENT
ghi:789
END:VEVENT'.split("\n").slice_before(/^BEGIN:VEVENT/).map{ |a| a[1 .. -2] }
Which is:
[["abc:123", "def:456"], ["ghi:789"]]
And, from there it's trivial to break up each resulting string using map and split(':').
Don't be seduced by the siren call of regular expressions trying to do everything. They're very powerful and convenient in their particular place, but often there are simpler and easier to maintain solutions.

English Sentence to Camel-cased method name

I had to convert a series of sentences into camel-cased method names. I ended writing something for it. I am still curious if there's something simpler for it.
Given the string a = "This is a test." output thisIsATest
I used for following:
a.downcase.gsub(/\s\w/){|b| b[-1,1].upcase }
Not sure it's better as your solution but it should do the trick:
>> "This is a test.".titleize.split(" ").join.camelize(:lower)
=> "thisIsATest."
titleize: uppercase every first letter of each word
split(" ").join: create an array with each word and join to squeeze the spaces out
camelize(:lower): make the first letter lowercase
You can find some more fun functions in the Rails docs: http://api.rubyonrails.org/classes/ActiveSupport/CoreExtensions/String/Inflections.html
"active_record".camelize(:lower)
output : "activeRecord"
use these
"Some string for you".gsub(/\s+/,'_').camelize(:lower) #=> "someStringForYou"
gsub: Replace spaces by underscores
camelize: java-like method camelcase
You might try using the 'English' gem, available at http://english.rubyforge.org/
require 'english/case'
a = "This is a test."
a.camelcase().uncapitalize() # => 'thisIsATest

Resources