Array () applied to hashes?

I recently came across " " Style Elements in Ruby # 3: make sure "is an array ...".

TL DR: the Array() method in Ruby converts everything you insert into an array and tries to guess what the correct result should be:

 Array(1) # => [1] Array([1,2]) # => [1,2] Array(nil) # => [] 

So what does Array({a: :b}) return? I would suggest that it returns an array with a hash as the value: [{a: :b}] .

However, the hash is converted directly to an array: [:a, :b] .

I do not just want to put the hash in an array ( [{a: :b}] ). I would like to have functionality that returns an array no matter what I insert. Array() already does this, but it converts the hash into an array in a way that I don't expect.

So basically the functionality should look like this:

 NewFancyArrayMethod({a: :b}) # => [{a: :b}] NewFancyArrayMethod([{a: :b}, {c: :d}]) # => [{a: :b}, {c: :d}] 

The second part is already done by Array() .

I know I can do something like values = [values] unless values.is_a? Array values = [values] unless values.is_a? Array , as the article points out. However, I would prefer to use a method that abstracts this transformation from me, as Array() already does. The only problem is that Array() treats the hash differently than any other "single" value (String, Integer, Object, etc.). I just do not want different processing for different cases.

+4
source share
4 answers

As Frederick Chung pointed out, the Array # wrap method does exactly what I want:

 Array.wrap({a: :b}) # => [{a: :b}] 

Unfortunately, this method is part of ActiveSupport, so it cannot be used in simple Ruby projects.

+1
source

So what does Array({a: :b}) return? I would suggest that it returns an array with a hash as the value: [{a: :b}] .

Your guess is wrong. Kernel#Array converts the arg argument, trying (in that order):

  • arg.to_ary
  • arg.to_a
  • and finally creates [arg]

<strong> Examples:

 Array(1) #=> [1] 

This is because of (3). There is no Fixnum#to_ary or Fixnum#to_a

 Array([1, 2]) #=> [1, 2] 

This does not return [[1, 2]] due to (1). Array#to_ary returns self

 Array(nil) #=> [] 

This does not return [nil] due to (2). There is no NilClass#to_ary , but there is NilClass#to_a : "Always returns an empty array."

 Array({a: :b}) #=> [[:a, :b]] 

Like Array(nil) , this does not return [{a: :b}] due to (2). There is no Hash#to_ary , but there Hash#to_a : "Converts hsh to a nested array of [key, value] arrays."

 Array(Time.now) #=> [33, 42, 17, 22, 8, 2013, 4, 234, true, "CEST"] 

This is Time#to_a return ... "ten-element array of time values"

Output:

Kernel#Array works as expected, Hash#to_a is the culprit. (or to_a in general)

I would like to have functionality that returns an array no matter what I insert.

Hash and Array are different objects. You can check the type ( Kernel#Array does this too):

 def hash_to_array(h) h.is_a?(Array) ? h : [h] end 

Or continue with Hash (or even Object ) and Array :

 class Hash # or Object def my_to_a [self] end end class Array def my_to_a self end end 

See comments for alternative implementations.

+7
source

Then run the monkey patch as shown below:

 class Hash def fancyarraymethod [self] end end class Array def fancyarraymethod self end end {a: :b}.fancyarraymethod # => [{a: :b}] [{a: :b}, {c: :d}].fancyarraymethod # => [{a: :b}, {c: :d}] 
+1
source

If you do not know that the array or hash you are working with, you can use flatten to prevent the array from being nested in case of the latter. Like this:

 [foo].flatten # Eg foo = [{:a => :b}, {:c => :d}] [foo] #=> [[{:a => :b}, {:c => :d}]] -- Nested, call flatten to fix that [foo].flatten #=> [{:a => :b}, {:c => :d}] foo = {:a => :b} [foo] #=> [{:a => :b}] -- Not nested, call flatten anyway just in case [foo].flatten #=> [{:a => :b}] 

This also works for strings, integers and objects:

 foo = 'bar' [foo].flatten #=> ['bar'] foo = 1 [foo].flatten #=> [1] foo = Object.new [foo].flatten #=> [#<Object:0x00000100a8daf8>] 

In any case, you get what you want.

+1
source

Source: https://habr.com/ru/post/1498385/


All Articles