Search code examples
rubysyntaxoperator-precedence

No implicit conversion of Enumerator into Array


I have:

qs = ["all=true", "limit=-1"]
value = ["agent", "service", "token"]

This code:

qs.concat value.map do |val|
  "#{field}=#{val}"
end

ends up with the following error:

`concat': no implicit conversion of Enumerator into Array (TypeError)`

whereas this code:

values = value.map do |val|
  "field=#{val}"
end
qs.concat values

does not.

What is the difference between them?


Solution

  • Your issue is caused by the different precedences when providing blocks to chained method calls. In your case you use the following code:

    qs.concat value.map do |val|
      "#{field}=#{val}"
    end
    

    Ruby assumes here that you mean the following:

    qs.concat(value.map) do |val|
      "#{field}=#{val}"
    end
    

    That is, Ruby passes the block to the first method (i.e qs.concat) which ignores the block. Since Array#map returns an Enumerator if you don't pass a block, you get your error you saw.

    To solve this, you can use the braces form of passing the block, i.e.:

    qs.concat value.map { |val|
      "#{field}=#{val}"
    }
    

    In this form, the block is always passed to the "last" method, u.e. your map.

    In any case, if there is any doubt about operator precedence, it is always a good idea to use explicit parenthesis or intermediate variables to make it clear both to human readers as well as the Ruby interpreter how your code is supposed to work.