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 nil
s 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 & 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 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.
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 }
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.
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.
Can you supply arguments to the map(&:method) syntax in Ruby?
You can create a simple patch on Symbol
like this:
class Symbol
def with(*args, &block)
->(caller, *rest) { caller.send(self, *rest, *args, &block) }
end
end
Which will enable you to do not only this:
a = [1,3,5,7,9]
a.map(&:+.with(2))
# => [3, 5, 7, 9, 11]
But also a lot of other cool stuff, like passing multiple parameters:
arr = ["abc", "babc", "great", "fruit"]
arr.map(&:center.with(20, '*'))
# => ["********abc*********", "********babc********", "*******great********", "*******fruit********"]
arr.map(&:[].with(1, 3))
# => ["bc", "abc", "rea", "rui"]
arr.map(&:[].with(/a(.*)/))
# => ["abc", "abc", "at", nil]
arr.map(&:[].with(/a(.*)/, 1))
# => ["bc", "bc", "t", nil]
And even work with inject
, which passes two arguments to the block:
%w(abecd ab cd).inject(&:gsub.with('cde'))
# => "cdeeecde"
Or something super cool as passing [shorthand] blocks to the shorthand block:
[['0', '1'], ['2', '3']].map(&:map.with(&:to_i))
# => [[0, 1], [2, 3]]
[%w(a b), %w(c d)].map(&:inject.with(&:+))
# => ["ab", "cd"]
[(1..5), (6..10)].map(&:map.with(&:*.with(2)))
# => [[2, 4, 6, 8, 10], [12, 14, 16, 18, 20]]
Here is a conversation I had with @ArupRakshit explaining it further:
Can you supply arguments to the map(&:method) syntax in Ruby?
As @amcaplan suggested in the comment below, you could create a shorter syntax, if you rename the with
method to call
. In this case, ruby has a built in shortcut for this special method .()
.
So you could use the above like this:
class Symbol
def call(*args, &block)
->(caller, *rest) { caller.send(self, *rest, *args, &block) }
end
end
a = [1,3,5,7,9]
a.map(&:+.(2))
# => [3, 5, 7, 9, 11]
[(1..5), (6..10)].map(&:map.(&:*.(2)))
# => [[2, 4, 6, 8, 10], [12, 14, 16, 18, 20]]
Here is a version using Refinements (which is less hacky than globally monkey patching Symbol
):
module AmpWithArguments
refine Symbol do
def call(*args, &block)
->(caller, *rest) { caller.send(self, *rest, *args, &block) }
end
end
end
using AmpWithArguments
a = [1,3,5,7,9]
a.map(&:+.(2))
# => [3, 5, 7, 9, 11]
[(1..5), (6..10)].map(&:map.(&:*.(2)))
# => [[2, 4, 6, 8, 10], [12, 14, 16, 18, 20]]
How do I pass an argument to array.map short cut?
You can't do it like this. The &
operator is for turning symbols into procs.
a = [1, 2, 3, 4, 5]
puts a.map(&:to_s) # prints array of strings
puts a.map(&:to_s2) # error, no such method `to_s2`.
&
is a shorthand for to_proc
:
def to_proc
proc { |obj, *args| obj.send(self, *args) }
end
It creates and returns new proc. As you see, you can't pass any parameters to this method. You can only call the generated proc.
Related Topics
Elasticsearch & Tire: Using Mapping and To_Indexed_JSON
Generate an HTML Table from an Array of Hashes in Ruby
Redirect User After Log in Only If It's on Root_Path
How to Get the Last SQL Query Performed by Activerecord in Ruby on Rails
Force Browser to Download File Instead of Opening It
Which Ruby Version am I Really Running
Ruby Timeouts and System Commands
How to Calculate How Many Years Passed Since a Given Date in Ruby
How to Test 'Rand()' with Rspec
How to Get Past "Http://Gems.Rubyforge.Org/ Does Not Appear to Be a Repository" Error Message
Ruby Gets/Puts Only for Strings
How to Have Rspec Test for My Default Scope
How to Find Each Instance of a Class in Ruby
Ruby Cannot Load Such File - Active_Support/Core_Ext/Object/Blank