1

There is a class Commerce and its constructor will initialize an object named commerce. LineItem is a class with in the Commerce class. LineItem class has a method named "ssm". when this method "ssm" is invoked it will initialize an object of another class named SSM. In our problem, we need pass to the "ssm" method as a function argument in another Test class.

 def autoUpdate(docNum, type, varName, value)
   type = method(Commerce::LineItem:ssm)
  commerce.line_item.type(varName).set(value)
end

In the place of the function parameter 'type', it should be replaced by different method names from the class LineItem. However the above function autoUpdate throws an error. How to pass child class methods as function parameters in another class.

2 Answers2

2

I think what you're doing is probably a mistake and a terrible design, but for your specific question if you actually want a method object, I think you want:

type_method = Commerce::LineItem.instance_method(:ssm)

You could then call it by:

bound_type_method = comerce.line_item.bind(type_method).call(varName).set(value)

But this doesn't make a lot of sense. You could also just pass the symbol, method_name = :ssm, and later call commerce.line_item.type.send(method_name, varName).set(value)

That's still kind of a mess though, this is scary code.

Also there appear to be 'child classes' involved here.

jrochkind
  • 22,799
  • 12
  • 59
  • 74
  • thank you Jrochkind. I am very new to ruby and trying to explore different things. Thanks a lot for the answer. i am not sure why it is scary? – techLearner Feb 28 '15 at 17:22
1

Passing methods as arguments and changing their receivers is not as easy to do in Ruby as it is in, say, Javascript, nor is it as conventional. Instead, usually when this sort of thing needs to be done, the Ruby convention is to use blocks. E.g. if you defined your auto_update method like this

def auto_update(doc_num, var_name, value)
  raise ArgumentError, "Block is required." unless block_given?

  line_item = yield var_name
  line_item.set(value)
end

Then you might call it like this

auto_update(doc_num, var_name, value) do |var_name|
  commerce.line_item.ssm(var_name)
end

Granted that looks pretty silly, for a number of reasons (for instance, why not just call the contents of the block first and then pass in the result as an argument for auto_update). If you describe your design a bit more, in particular from where this auto_update method is being called and how the value for type is determined, that might help.

alexcavalli
  • 526
  • 6
  • 10
  • Hi Alex, thanks a lot the answer. the auto_update method is a user defined method written by a tester in the Testcase class. the value for "type" is a function parameter in auto_update method. the values for "type" must be replaced by all the method/function names written in another class called LineItem . LineItem is a class within Commerce class. – techLearner Feb 28 '15 at 17:46
  • So, is the goal to have a single method that can be used to test multiple methods in the LineItem class? If that's the case I think a block (or maybe a Proc) is still your best bet. As I mentioned in my answer, passing a "function parameter" which will then be called on a new receiver is a bit hairy in Ruby. I'd suggest you look at some of these answers for more info: http://stackoverflow.com/q/522720/4280232 – alexcavalli Feb 28 '15 at 18:04