The & to_proc chain on the character

It is well known that Rubyist &will call a to_procsymbol, therefore

[:a, :b, :c].map(&:to_s)

equivalently

[:a, :b, :c].map { |e| e.to_s } # => ["a", "b", "c"]

Let's say I want to call another method right after to_s, these two implementations will work:

[:a, :b, :c].map { |e| e.to_s.upcase }
[:a, :b, :c].map(&:to_s).map(&:upcase)

My question is, is there a way to bind a call with & Symbol#to_procone parameter? Sort of:

[:a, :b, :c].map(&:to_s:upcase)

Thanks!

+4
source share
5 answers

If you only do:

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

then just use the block and do more important things. If you are really executing an Enumerable call chain and find the blocks too visually noisy:

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

then you can toss your logic into a lambda to help clear the look:

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...

, ( &:symbol ), . to_s.upcase , , .

+5

- , . :

class Symbol
  def * other
    ->x{x.send(self).send(other)}
  end
end

[:a, :b, :c].map(&:to_s * :upcase)
[:a, :b, :c].map(&:to_s * :capitalize)
...

* .

, , :

class Proc
  def * other
    ->x{call(x).send(other)}
  end
end
+5

, ( , , ), Symbol ( Symbol#chain),

class Symbol
  def proc_chain(*args)
    args.inject(self.to_proc) do |memo,meth|
      meth, *passable_args = [meth].flatten
      passable_block = passable_args.pop if passable_args.last.is_a?(Proc)
      Proc.new do |obj|
        memo.call(obj).__send__(meth,*passable_args,&passable_block)
      end
    end
  end
  alias_method :chain, :proc_chain
end

:

[:a, :b, :c].map(&:to_s.chain(:upcase))
#=> ["A","B","C"]
# Or with Arguments & blocks
[1,2,3,4,5].map(&:itself.chain([:to_s,2],:chars,[:map,->(e){ "#{e}!!!!"}]))
#=>  => [["1!!!!"], ["1!!!!", "0!!!!"], ["1!!!!", "1!!!!"],
#        ["1!!!!","0!!!!", "0!!!!"], ["1!!!!", "0!!!!", "1!!!!"]]

It can be used even as stand-alone

p = :to_s.chain([:split,'.'])
p.call(123.45)
#=> ["123","45"]
# Or even 
[123.45,76.75].map(&p)
#=> => [["123", "45"], ["76", "75"]]
+2
source

There is no way to bind a character to proc.

However, you can decapitate the patch to a class method that you map that will do both, and then call it.

class Symbol
  def to_upcase_str
    self.to_s.upcase
  end
end

[:a, :b, :c].map(&:to_upcase_str)
+1
source

While we are playing with the syntax, how about an array with a monkey patch using a method to_proc?

class Array
  def to_proc
    return :itself.to_proc if empty?
    ->(obj) { drop(1).to_proc.call(first.to_proc.call(obj)) }
  end
end

["foo", "bar", "baz"].map(&[:capitalize, :swapcase, :chars, ->a{ a.join("-") }])
# => ["f-O-O", "b-A-R", "b-A-Z"]

Take a look at repl.it: https://repl.it/JS4B/1

+1
source

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


All Articles