0

I'm working on a bit of metaprogramming using send methods quite a bit. I've been successful so far because the methods I'm sending to only take one argument.

Example:

client is an API client

@command is a method on client taken as an option to a CLI utility

@verb is a method on command taken as another option in the CLI

def command_keys
  case @command
  when "something"
    self.command_options.slice(:some, :keys)
  end
end

Then I call the API client like this:

client.send(@command).send(@verb, command_keys)

This works since the methods all take a Hash as their argument. The problem I've run into is when I need to send more than 1 parameter in command_keys. What I'm wondering is the best way to handle the command_keys method returning more than 1 value. Example:

def command_keys
  case @command
  when "something"
    return self.command_options[:some], self.command_options[:keys]
  end
end

In this case, command_keys returns an Array as expected, but when I try to pass that in the send(@verb, command_options) call, it passes it as an Array (which is obviously expected). So, to make a long story short, is there some easy way to make this condition be handled easily?

I know send(@verb, argument1, argument2) would get me the result I want, but I would like to be able to not have to give my script any more implementation logic than it needs, that is to say I would like it to remain as abstracted as possible.

2
  • Yes, I know the title of this post sucks, I just couldn't think of a better way to word it. Commented Oct 8, 2013 at 2:09
  • 1
    If your only intent in using send is for metaprogramming and not bypassing access control to protected/private methods, consider using public_send instead to more clearly indicate that intent. Commented Oct 8, 2013 at 3:00

1 Answer 1

1

Use splat. You might have to rethink the code a bit, but something like:

client.send(@command).send(@verb, *all_the_args)
Sign up to request clarification or add additional context in comments.

4 Comments

I half suspected splat was the solution, I'm just not sure how to get the list of arguments back from that method into something I can actually splat
You could just always return an array from the method, but it should actually work even with non array values, I believe. send(:foo, *[bar]) === send(:foo, *bar)
The send(:foo, *[bar]) syntax is invalid, it sends the elements as the array, not its values. The send(:foo, *bar) syntax works, but it breaks all of the instances where command_keys returns a hash, since it breaks the hash into its key/value pairs as an array. I tried adding some logic around whether or not the returned value was an Array and then splatting if necessary, but it very much did not like that without removing the DRYness from the code.
At this point, the dryness of the code is of little concern, this solution worked well enough. Thanks!

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.