7

Is there something like this in ruby?

send(+, 1, 2)

I want to make this piece of code seem less redundant

if op == "+"
  return arg1 + arg2
elsif op == "-"
  return arg1 - arg2
elsif op == "*"
  return arg1 * arg2
elsif op == "/"
  return arg1 / arg2
user513951
  • 12,445
  • 7
  • 65
  • 82
MxLDevs
  • 19,048
  • 36
  • 123
  • 194

2 Answers2

17

Yup, simply use send (or, better yet, public_send) like so:

arg1.public_send(op, arg2)

This works because most operators in Ruby (including +, -, *, /, and more) simply call methods. So 1 + 2 is the same as 1.+(2).

You may also want to whitelist op if it’s user input, e.g. %w[+ - * /].include?(op), as otherwise the user will be able to call arbitrary methods (which is a potential security vulnerability).

Andrew Marshall
  • 95,083
  • 20
  • 220
  • 214
  • 1
    What is that `%w` notation? Or is it just cleaner than `["+", "-", ... ].include?(op)` – MxLDevs Oct 25 '12 at 01:40
  • 2
    `%w[a b c]` is equivalent to `['a', 'b', 'c']` - it's just a shorthand for an array of strings (elements separated by whitespace). – Scott Olson Oct 25 '12 at 02:16
  • is there are solution that would allow for += operators to work as well? – rposborne Apr 26 '14 at 01:34
  • 1
    @burningpony You can’t `send` operators, only methods, so no. But there’s no reason not just do an explicit assignment using the return value of `send`. – Andrew Marshall Apr 26 '14 at 02:47
1

As an other option, if your operator and operands happen to be in string format, say from a gets method, you can also use eval:

For example:

a = '1'; b = '2'; o = '+'

eval a+o+b

becomes

eval '1+2'

which returns 3

frank
  • 295
  • 3
  • 8