I am new to ruby on rails and started a tutorial and found out the following function
def string_shuffle(s)
>> s.split('').?.?
>> end
=> nil
>> string_shuffle("foobar")
What does s.split('').?.? do? I know the split method but i have no idea what the two question marks are for. I saw "? used in boolean methods, but i couldnt understand how this one works. I tried to google it but, I couldnt find it at all.
To quote the tutorial in question:
By replacing the question marks in Listing 4.10 with the appropriate
methods, combine split, shuffle, and join to write a function that
shuffles the letters in a given string.
Listing 4.10 is an exercise where the two question marks are meant to be replaced with actual method calls.
This code is not valid
You can see split returns an array :
http://www.ruby-doc.org/core-1.9.3/String.html#method-i-split
And there is no method called ? in Array :
http://www.ruby-doc.org/core-1.9.3/Array.html
Related
I'm looking for some help understanding why I get an error (no implicit conversion of nil into String) when attempting to use a for-loop to search through an array of letters (and add them to a resulting string, which seems to be the real problem), but not when I use a while-loop or 'each' for the same purposes. I've looked through a lot of documentation, but haven't been able to find an answer as to why this is happening. I understand that I could just use the "each" method and call it a day, but I'd prefer to comprehend the cause as well as the effect (and hopefully avoid this problem in the future).
The following method works as desired: printing "result" which is the original string, only with "!" in place of any vowels.
s="helloHELLO"
result=""
vowels=["a","e","i","o","u","A","E","I","O","U"]
string_array=s.split("")
string_array.each do |i|
if vowels.include?(i)
result+="!"
else
result+=i
end
end
puts result
However, my initial attempt (posted below) raises the error mentioned above: "no implicit conversion of nil into String" citing lines 5 and 9.
s="helloHELLO"
result=""
vowels=["a","e","i","o","u","A","E","I","O","U"]
string_array=s.split("")
for i in 0..string_array.length
if vowels.include?(string_array[i])
result+= "!"
else
result+=string_array[i]
end
end
puts result
Through experimentation, I managed to get it working; and I determined--through printing to screen rather than storing in "result"--that the problem occurs during concatenation of the target letter to the string "result". But why is "string_array[i]" (line #9) seen as NIL rather than as a String? I feel like I'm missing something very obvious.
If it matters: This is just a kata on CodeWars that lead me to a fundamental question about data types and the mechanics of the for..in loop. This seemed very relevant, but not 100% on the mark for my question: "for" vs "each" in Ruby.
Thanks in advance for the help.
EDIT:
Okay, I think I figured it out. I'd still love some answers though, to confirm, clarify, or downright refute.
I realized that if I wanted to use the for-loop, I should use the array itself as the "range" rather than "0..array.length", like so:
s="helloHELLO"
result=""
vowels=["a","e","i","o","u","A","E","I","O","U"]
string_array=s.split("")
for i in string_array
if vowels.include?(i)
result+= "!"
else
result+=i
end
end
puts result
So, is it that since the "each" method variable (in this case, "i") doesn't exist outside the scope of the main block, its datatype become nil after evaluating whether it's included in the 'vowels' array?
You got beaten by the classical error when iterating an array starting with index 0, instead of length as end position it should be length-1.
But it seems like you come from some other programming language, your code is not Rubyesque, a 'For' for example is seldom used.
Ruby is a higher language than most others, it has many solutions build in, we call it 'sugared' because Ruby is meant to make us programmers happy. What you try to achieve can be done in just one line.
"helloHELLO".scan(/[aeoui]/i).count
Some explanation: the literal array "hello HELLO" is a String, meaning an object of the String class and as such has a lot of methods you can use, like scan, which scans the string for the regular expression /[aeoui]/ which means any of the characters enclosed in the [], the i at the end makes it case insentitive so you don't have to add AEOUI. The scan returns an array with the matching characters, an object of the Array class has the method count, which gives us the ... Yeah once you get the drift it's easy, you can string together methods which act upon each other.
Your for loop:
for i in 0..string_array.length
loops from 0 to 10.
But string[10] #=> nil because there is no element at index 10. And then on line 9 you try to add nil to result
result = result + string_array[i] #expanded
You can't add nil to a string like this, you have to convert nil to a string explicitly thus the error. The best way to fix this issue is to change your for loop to:
for i in 0..string_array.length-1
Then your loop will finish at the last element, string[9].
I have a JSON file full of regex keys with responses based on the message sent (eg. Hello, Dragnflier!). The file contains values like this:
{
"/hello/i" : "Why hello there!",
"/how are you.*dragnflier/i" : "I'm good thank you! How are you?"
}
I load these into a hash at the start of my ruby program. Is there a more efficient way to see if the message matches any of the regular expressions in my hash than just running a loop over it with all of the keys? I want to get the value that the key returns, not a list of keys or a boolean value.
The solution ended up being, based on other answers for the opposite case:
val = myhash.keys.select {|key| message.to_s.match(key)}
Yes, there is more efficient way:
hash = {
/hello/i => "Why hello there!",
/how are you.*dragnflier/i => "I'm good thank you! How are you?"
}
message =~ Regexp.union(hash.keys)
You stated that the goal is to check “if the message matches any of the regular expressions in my hash.” The above is way more efficient than the solution you came up with.
After this preliminary check is done, one might do whatever she wants to detect the respective key (this claim appeared in the questions after I have it answered.) This approach will be more efficient than just bruteforce detect on keys.
Please note, that the answer you have provided is not correct, since
Regexp.new '/foo/i'
becomes
#⇒ /\/foo\/i/i
and not
#⇒ /foo/i
as you probably expected.
So I am trying to make the transition from PHP to ruby(finally). I am attempting to complete the rubymonk challenges but I am stuck on the third challenge.
The challenge itself is easy and I've already found a solution, but I cant figure out what type of data I'm looking at or how to process it properly.
The challenge simply wants you create a method that takes a array containing some strings, and return a count of each string in that same position. so ["I","suck","at","ruby"] == ["1","4","2","4"].
That part is Ez-pz, but I cant for the life of me figure out how to process the input properly.
It gives you a shell of method and tells you to complete it
def lenght_finder(input_array)
#I added the print input_array
print input_array #=> ["I","am","genius"]["things","are","","awesome"]
end
Is this a multidimensional array?
I've tried to replicate this in IRB with
input_array = ["I","am","genius"]["things","are","","awesome"]
but it returns and error
input_array = [["I","am","genius"],["things","are","","awesome"]]
works, but that is clearly not that same.
Because of this I am struggling to traverse the array to process that data properly.
I can't get anything like input_array.flatten to work, or input_array[0] which returns "Ithings".
This is confusing me. Am I looking at a single array? a multidimensional array? Clearly it cant be a string. Why does it skip "am" when accessing input_array[0]?
Ha, like Justin Ko suggested in his comment above, what you're seeing is the stdout of running the function twice.
Since you used print, there's no newline. Use puts instead.
This should help you see it more clearly:
def length_finder(input_array)
puts '*** '+input_array.inspect
return 0
end
I am working on a quoting mechanism in my app, where it should be possible to simply type #26, for example, in the comment form in order to quote comment 26 of that topic.
To check if a user wants to quote one or more comments in the first place, I put an if condition after my current_user.comments.build and before #comment.save.
But, just to make my question a bit more general and easier to adapt:
if #comment.content.include?(/\A[\w+\-.]+#[a-z\d\-.]+\.[a-z]+\z/i)
I want something like this. That example was for checking if the comment's content includes emails. But logically I get an "can't convert regexp to string" error.
How can you do the include? method in rails with an regexp? So, to check whether a text includes a string of a certain regex format?
Or is the controller the wrong place for such regex actions?
I do ruby regex'es this way:
stringObj.match(/regex/)
There's also
if #comment.content =~ /regex/
If you had an array of all previous comments #prev_comments and wanted to replace them all in one shot, you could:
pattern = /#(\d+)/
#comment.content.gsub(pattern) do
cur_match = Regexp.last_match
idx = cur_match[1].to_i - 1
#prev_comments[idx]
end
Trick is using Regexp.last_match to get the current match, which made me wonder if it was thread safe. It is, apparently.
adapted (stolen) from the below more general String extension
class String
def js_replace(pattern, &block)
gsub(pattern) do |_|
md = Regexp.last_match
args = [md.to_s, md.captures, md.begin(0), self].flatten
block.call(*args)
end
end
end
Source: http://vemod.net/string-js_replace
To match the nature of .include?
stringObj.match(/regex/).present?
Would give similar true/false outcomes if you're using Rails (or ActiveSupport)
I dont understand how #{...} construct is used in Ruby.
I've seen in used in the regexp example on http://www.ruby-doc.org/core-1.9.3/Regexp.html
place = "tokyo"
/#{place}/.match("Go to tokyo")
#=> #<MatchData "tokyo">
What exactly is this #{...} feature called and does anyone know of some good working examples of this.
Really appreciate the help.
Thanks!
Here's an example that's a bit simpler:
place = "Tokyo"
puts "Go to #{place}"
What the #{...} construct does is to execute the ruby code that it contains, and return a string representation of the result, which then is embedded in the string where the construct appears.
Another example:
place = "Tokyo"
puts "#{place} is a #{place.class} of #{place.length} characters"
In other words, your example is equivalent to:
/tokyo/.match("Go to tokyo")
Hope this helps.
Is called interpolation, and allows you to convert placeholders to the value they represent...
http://kconrails.com/2010/12/08/ruby-string-interpolation/
The #{...} is especially useful and used quite a lot in metaprogramming. It helps you to dispatch methods dynamically without knowing the name of these methods before run time.
if conf.rc and File.exists?( conf.rc )
YAML.load_file(conf.rc).each do |k,v|
conf.send("#{k}=" , v)
end
end
As you can see, until run time we do not know which methods are going to be dispatched. Through .send and #{...}, we can dynamically dispatch methods. For example, in above code depending on the values in conf.rc different methods can be dispatched.
Example is taken from Metaprogramming Ruby.