Question

Before I start, I have tried fiddling with instance_eval and singleton methods to no avail. I am going to present my "best" attempt at the problem.

I am trying to do the following:

value = rule(condition: lambda {@something > 100})
value.act(120)

The above calls cannot change.

What can change is how rule is defined:

def rule(condition: nil)
    t = Object.new
    t.class.module_eval{
        attr_accessor :condition       

        def act(something)
            if(condition.call(something))
                return "SUCCESS"
            end
        end
    }
    t.condition = condition
    return t
end

I am unsure how to get the lambda code block to get the value of something. Any help or point in the right direction would be appreciated!

Was it helpful?

Solution

If these calls can not change:

value = rule(condition: lambda {@something > 100})
value.act(120)

Try instance_exec:

def rule(condition: nil)
  t = Object.new
  t.class.module_eval do
    attr_accessor :condition       

    def act(something)
      @something = something

      if(instance_exec &condition)
         "SUCCESS"
      else
        "FAILURE"
      end
    end
  end
  t.condition = condition
  t
end

It invokes the condition in t's context.

OTHER TIPS

You were close, your lambda needs to take a parameter.

def rule(condition: nil)
  t = Object.new
  t.class.module_eval do
    attr_accessor :condition       

    def act(something)
      if(condition.call(something))
         "SUCCESS"
      else
        "FAILURE"
      end
    end
  end
  t.condition = condition
  t
end

derp = rule(condition: lambda { |val| val > 100 })
puts derp.act(120)
puts derp.act(80)

Or even better, get stabby!

derp = rule(condition: ->(val) { val > 100 })

You are defining rule right, you are just defining your condition lambda wrong. Try using this instead:

value = rule(condition: lambda {|arg| arg > 100})

This tells Ruby that the lambda takes one argument. You are already passing the argument in your rule function.

If you need to keep your rule syntax the same, (I advise against this), you can change the definition to this:

def rule(condition: nil)
    t = Object.new
    t.class.module_eval{
        attr_accessor :condition       

        def act(something)
            argobj = Object.new
            argobj.instance_variable_set(:something, something)
            if(argobj.instance_eval(&(condition())))
                return "SUCCESS"
            end
        end
    }
    t.condition = condition
    return t
end
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top