2

I want to extend the Proc class so that its constructor can also take a hash of arguments with will be converted into methods with some meta programming construct. Something to the effect of:

p = Proc.new(this: 100, that: 200, yes: 1, no: 2) { |arg| arg.even? }
p.call(1) # => false
p.this # => 100
p.yes # => 1

I want to know the ruby way of doing something like this.

3 Answers 3

3
class Proc
  def initialize h; @h = h end
  def method_missing k; @h[k] end
  def respond_to_missing?; true end
end

p = Proc.new(this: 100, that: 200, yes: 1, no: 2) { |arg| arg.even? }
p.call(1) # => false
p.this # => 100
p.yes # => 1
Sign up to request clarification or add additional context in comments.

2 Comments

I might want to use def method_missing(k,*args); @h.fetch(k){super}; end instead.
Always best to also implement respond_to_missing? when defining method_missing.
3

You can (and probably should in this case) avoid monkey patching altogether by having your own class behave like a Proc by implementing to_proc and call. For example, you could start from an OpenStruct:

require 'ostruct'
class MyFunkyClass < OpenStruct
  def initialize(h, &block)
    @block = block
    super
  end

  def to_proc
    @block
  end

  def call(*args)
    @block.call(*args)
  end
end

f = MyFunkyClass.new(this: 100, that: 200, yes: 1, no: 2) { |arg| arg.even? }
f.that # => 200
f.call(42) # => true
[1,2,3,4].select(&f) # => [2, 4]

2 Comments

+1 For getting the block right and the (for me) jaw-dropping last example.
The last example works for the same reason that &:even? works; check Symbol#to_proc
2

Without metaprogramming:

require 'ostruct'

r = OpenStruct.new(this: 100, that: 200, yes: 1, no: 2)
def r.call(n)
  n.even?
end

p r.this # 100
p r.call(1) # false

Edit: @Marc-André Lafortune had the same idea about Openstruct; his implementation is way better.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.