Chaining & To_Proc on Symbol

Chaining & to_proc on symbol

If you're only doing:

%i[a b c].map { |e| e.to_s.upcase }

then just use the block and get on with more important things. If you're really doing a chain of Enumerable calls and find the blocks too visually noisy:

%i[a b c].map { |e| e.to_s.upcase }.some_chain_of_enumerable_calls...

then you could toss your logic into a lambda to help clean up the appearance:

to_s_upcase = lambda { |e| e.to_s.upcase }
%i[a b c].map(&to_s_upcase).some_chain_of_enumerable_calls...

or throw it in a method and say:

%i[a b c].map(&method(:to_s_upcase)).some_chain_of_enumerable_calls...

Either way, you're giving your little bit of logic a name (which is pretty much all &:symbol is doing for you) to make the code more readable and easier to understand. In the specific case of to_s.upcase, this is all a bit pointless but these approaches are quite useful when the block gets bigger.

Chaining methods using Symbol#to_proc shorthand in Ruby?

No, there's no shorthand for that. You could define a method:

def really_empty?(x)
x.strip.empty?
end

and use method:

array.reject(&method(:really_empty?))

or use a lambda:

really_empty = ->(x) { x.strip.empty? }
array.reject(&really_empty)

but I wouldn't call either of those better unless you have a use for really_empty? in enough places that splitting up the logic makes sense.

However, since you're using Rails, you could just use blank? instead of .strip.empty?:

array.reject(&:blank?)

Note that nil.blank? is true whereas nil.strip.empty? just hands you an exception so they're not quite equivalent; however, you probably want to reject nils as well so using blank? might be better anyway. blank? also returns true for false, {}, and [] but you probably don't have those in your array of strings.

Chaining block passing in ruby

Because :any?(&:zero?) is not an appropriate symbol literal. You can make it a symbol by doing :"any?(&:zero?)", but still, there is no such method.

Is it possible to use &: (ampersand colon) notation with a parameter or with chaining in Ruby?

:to_s is a symbol,not a method. So you can't pass any argument to it like :to_s(2). If you do so,you will get error.That's how your code wouldn't work.So [1, 2, 3].map(&:to_s(2)) is not possible,where as [1, 2, 3].map(&:to_s) possible.&:to_s means you are calling #to_proc method on the symbol. Now in your case &:to_s(2) means :to_s(2).to_proc. Error will be happened before the call to the method #to_proc.

:to_s.to_proc # => #<Proc:0x20e4178>
:to_s(2).to_proc # if you try and the error as below

syntax error, unexpected '(', expecting $end
p :to_s(2).to_proc
^

Now try your one and compare the error with above explanation :

[1, 2, 3].map(&:to_s(2))

syntax error, unexpected '(', expecting ')'
[1, 2, 3].map(&:to_s(2))
^

calling slice! with map / symbol_to_proc syntax

As far as I know that is the simplest way to do it without monkey patching as indicated in the link you gave. You really aren't saving much time by using a more compact format. If you want to compact it more, you can move the map into it's own method. then do something like

def map_slice!(arr, *fields)
arr.map {|i| i.slice!(*fields) }
end

map_slice!(arr, :sort, :suppress)

# Not much shorter than just using below
# Which is why it probably wasn't implemented.
arr.map {|i| i.slice!(:sort, :suppress) }

Explicitly yielding n values to Symbol#to_proc

Here's how you can do it:

class Enumerator
def explicitly
each { |e| yield(*e) }
end
end

I executed your tests against this and the proper results are returned.

UPDATE: Changed to not capture the block explicitly.

How do i invoke a method chain using map method, in ruby?

You can pass a block to map and put your expression within the block. Each member of the enumerable will be yielded in succession to the block.

category_ids = categories.map {|c| c._id.to_s }

doing ampersand for multiple fields does not work in ruby

Symbol#to_proc is useful as shorthand for the basic case of calling one method. If you want something more complicated just move to the longhand

['Hi', 'Yo'].map { |word| [word.upcase, word.downcase] }

which would return [['HI', 'hi'], ['YO', 'yo']] - which you could then call flatten on if what you want is ['HI', 'hi', 'YO', 'yo'] instead.

UPDATE: Since you actually want [['HI','YO'], ['hi', 'yo']] you can call transpose on the results

['Hi', 'Yo'].map { |w| [w.upcase, w.downcase] }.transpose

Note: The following is a terrible idea and no one should implement it in real code because the meaning of Array#to_proc would be completely non-obvious (does it call all and return an array, does it chain, does it pass parameters to a method, etc), but since you've asked for it you can do something like

class Array
def to_proc
lambda { |o| map { |m| o.send(m) } }
end
end

which would allow

['Hi', 'Yo'].map(&[:upcase, :downcase]).transpose

to produce the answer you're asking for. It does save a couple of characters but it's not worth the ambiguity it adds to the code.



Related Topics



Leave a reply



Submit