I tried to write a private function that will take in a single token and return the given token without white space or punctuation, for example:
normalize_token(" cat.")
# => "cat"
I then defined an array of tokens that have punctuation and white space:
["a.", " b...."]
which I'd like to map over using my defined function. I expect a new object returned, which looks like:
["a", "b"]
Here is a small snippet of code:
private def normalize_token(token)
token.gsub(/\W/, ' ') # does the same thing as [^A-Za-z0-9_]
end
["a.", " b...."].map!(&:normalize_token)
I get:
map!': private method
normalize_token' called for "a.":String (NoMethodError)
Any help or even an explanation of what I'm doing wrong would be greatly appreciated.
Instead of passing the method reference, pass a block:
private def normalize_token(token)
token.gsub(/\W/, ' ') # does the same thing as [^A-Za-z0-9_]
end
["a.", " b...."].map! {|token| normalize_token token}
This will leave white space in your strings, so you might want to chomp!
them or change your gsub
to gsub(/\\w/, '')
Explanation
The first problem is that normalize_token
is private. You can get around that by making it public or by send
ing it as @alex mentioned.
The second problem however is more subtle.
By passing the method reference, you essentially have the following
["a.", " b...."].map! {|token| token.send :normalize_token }
Running this will result in the following error message:
ArgumentError (wrong number of arguments (given 0, expected 1))
map!
will not pass the mapped value to normalize_token
as an argument. (notice that the send
has your mapped value as a receiver but not as an argument .) Instead, by using a block with a variable declared, we can get around this by passing the mapped value as an argument explicitly in the block.
Quick note on &:
- it accomplishes the same thing as {|i| ...}
{|i| ...}
by using & to call to_proc on the :object, then passes it as a block to the method - so in order to use it, whatever follows &:
needs to be defined on whatever object is being passed to map!
.
Here's an example, cracking open the String
class to define it there:
class String
def normalize_token
self.gsub(/\W/, ' ')
end
end
Which will let you use your original ["a.", " b...."].map!(&:normalize_token)
. Not a great idea to do stuff like this in real life, since you'd probably want normalize_token to be defined in whatever class is responsible for generating these strings. But it should get you started.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.