Fork me on GitHub
Hoopla! - now with extra whiz-bang home

Ruby provides a handy shortcut for simple procs by letting you use a symbol:

    [1, 2, 3].map {|number| number.odd? }
    # => [true, false, true]
    [1, 2, 3].map(&:odd?)
    # => [true, false, true]
  

Despite a performance hit that occurs from converting the symbol to a proc it’s really useful and I use it in lots of production code when I only have to iterate through a loop a few times.

Today I was iterating through a few properties of an object and unconsciously used the inverse of the Symbol-to-Proc trick:

    [ :name,
      :type,
      :amount_in_cents, 
      :created_at,
      lambda {|record| record.class.superclass }
    ].map {|attribute| @item.send(attribute) }
  

Rather than specifying a symbol to perform a proc operation I felt like specifying a proc itself and just passing that into send. Surely that would get executed, right? Err… no. I know passing an eval-able string (e.g. @item.send(‘class.superclass’) ) doesn’t work, so I figured I’d throw that lambda in there to calculate the name of @item’s superclass. No dice. But there’s a pretty simple workaround:

    module ProcToSend
      def self.included(target)
        target.class_eval do
          def send_with_proc_to_symbol(*args)
            if args.first.is_a?(Proc)
              args.shift.call(self, *args)
            else
              send_without_proc_to_symbol *args
            end
          end
          alias_method_chain :send, :proc_to_symbol
        end
      end
    end

    Module.send :include, ProcToSend
    Object.send :include, ProcToSend
  

Now this works:

    Item.send Proc.new {|x| x.name }
    # => 'Item'
  

But, like all hacks, I need to go refactor away the need for this.

blog comments powered by Disqus