2

I'm trying to remove all the - from the strings in an array using map(&:gsub('-','')), but I'm having some difficulty to understand why it is not working:

2.2.2 (main)> my_array = [ 'a-b-c', 'd-e-f', 'g-h-i']
=> [
    [0] "a-b-c",
    [1] "d-e-f",
    [2] "g-h-i"
]
2.2.2 (main)> my_array.map(&:gsub('-',''))
SyntaxError: unexpected ',', expecting end-of-input
my_array.map(&:gsub('-',''))
                        ^

But, when I try these, they work

2.2.2 (main)> my_array.map!(&:upcase)
=> [
    [0] "A-B-C",
    [1] "D-E-F",
    [2] "G-H-I"
]

2.2.2 (main)> my_array.map!(&:downcase)
=> [
    [0] "a-b-c",
    [1] "d-e-f",
    [2] "g-h-i"
]

2.2.2 (main)> my_array.map(&:class)
=> [
    [0] String < Object,
    [1] String < Object,
    [2] String < Object
]

2.2.2 (main)> my_array.map{ | element | element.gsub("-", "") }
=> [
    [0] "abc",
    [1] "def",
    [2] "ghi"
]

Does anyone know why I'm getting this error with map(&:gsub( "-", ""))?

Matt Schuchard
  • 18,599
  • 3
  • 40
  • 57

2 Answers2

3

You can't pass a method that way. You should do the following:

my_array.map{ |a| a.gsub('-','') }

About a proper usage of ampersand you can read here: Ruby ampersand colon shortcut

Community
  • 1
  • 1
fl00r
  • 81,403
  • 31
  • 214
  • 233
  • 1
    So it doesn't work because the conversion from block to proc with method does not accept arguments to the method? – Matt Schuchard Nov 12 '16 at 19:48
  • 2
    Yes, you can't pass arguments. – fl00r Nov 12 '16 at 19:53
  • 1
    @MattSchuchard it's a conversion from symbol to proc. `:gsub` is the symbol, so putting parentheses after it like a method call is a syntax error. – Max Nov 13 '16 at 03:52
1

As fl00r has already pointed out, you can't pass arguments to the method through &:method like that. However, you can use a lambda if your logic is more than "call this method without any arguments". For example:

remove_hyphens = ->(s) { s.gsub('-', '') }
my_array.map(&remove_hyphens)

You could also use the method method if it makes sense to put the mapping logic in a separate non-String method:

def remove_hyphens(s)
  s.gsub('-', '')
end

my_array.map(&method(:remove_hyphens))

or even a method that returns a lambda:

def remove(char)
  ->(s) { s.gsub(char, '') }
end

my_array.map(&remove('-'))

There's not much point to all this extra machinery for a short one-off block but these are useful technique if the blocks are bigger or more complicated and you want to give it a name to better express your intent or if you want to use the same logic in multiple places. Giving each bit of logic a name is also useful if you're chaining several Enumerable methods together and you want to make the overall logic easier to read:

my_array.select(&the_ones_i_want)
        .map(&to_clean_values)
        .sort_by(&standard_accounting_practices)
        .take(11)
        ...
Community
  • 1
  • 1
mu is too short
  • 413,090
  • 67
  • 810
  • 771