Ruby String to Operator

Ruby string to operator

Do as below using Object#public_send method :

operator = ['+', '-', '*', '/']
operator.map {|o| 2.public_send o,2 }
# => [4, 0, 4, 1]

One more way using Object#method and Method#call:

operator = ['+', '-', '*', '/']
operator.map {|o| 2.method(o).(2) }
# => [4, 0, 4, 1]

how to convert += to operator in ruby

2.send("-", 3) works, because - is a method and 2 responds to that method:

2.respond_to?('-') #=> true

= and += on the other hand are not methods:

2.respond_to?('=')  #=> false
2.respond_to?('+=') #=> false

And even if = was a valid method1, then

a = 2
a.send("=", 4)

would be equivalent to:

2.send("=", 4)

or simply:

2 = 4

In other words: it would redefine 2 as 4, something Ruby doesn't allow you to do.

This is because variables (like a above) are not objects. a.send doesn't send a message to the variable a, but to the object, a is referring to (2 in the example).

The same applies to abbreviated assignment like +=:

a = 2
a += 2

is equivalent to:

a = 2
a = a + 2

You can just rewrite it as:

a = 2
a = a.send("+", 2)

The assignment is not part of the method invocation.


1 you can actually define a method = via define_method:

class Foo
define_method('=') { |other| puts "`=' called with #{other}" }
end

But it is just an ordinary method. In particular, it does not and can not alter the variable the object was assigned-to or the object's identity:

 f = Foo.new
#=> #<Foo:0x007ff20c0eeda8>
f.send('=', 123)
# `=' called with 123
#=> nil
f
#=> #<Foo:0x007ff20c0eeda8>

String || comparison operator in Ruby

'X' || 'O' just says X or O. And since any string is truthy it always returns X. So any spot where you’ve said [('X' || 'O')], you’ve really just said ['X'].

Because of this, you’re only ever checking if a whole line of 3 is all X.

I don’t really understand how you’re trying to test this, but I feel like you’d be better off running the function twice first handing in X and then handing in O if it didn’t find X as a winner, as opposed to trying to check both as once.

Alternatively you could instead have the function return 'X', 'O', or nil and then you could have it only run the function once. The string returned would be who won and if it’s nil then no one won. I would also recommend making a loop for this. I find it easier to read.

Here's how I would solve the problem.

ROWS = [
[1,2,3],
[4,5,6],
[7,8,9],

[1,4,7],
[2,5,8],
[3,6,9],

[1,5,9],
[7,5,3],
]

def find_winner(board)
ROWS.each do |row|
# subtract 1 because the ROWS is 1-indexed (like a phone dial) but arrays are 0-indexed
row_values = row.map { |v| board[v - 1] }
return('X') if row_values.all?('X')
return('O') if row_values.all?('O')
end

return(nil)
end

test1 = [
'X', 'X', 'X',
'O', 'X', 'O',
'O', 'O', '',
]
puts "Winner of test1: #{find_winner(test1).inspect}"
"X"

test2 = [
'X', '', 'X',
'X', 'O', 'O',
'X', 'O', 'X',
]
puts "Winner of test2: #{find_winner(test2).inspect}"
"X"

test3 = [
'O', 'X', 'X',
'O', 'X', 'O',
'O', 'O', '',
]
puts "Winner of test3: #{find_winner(test3).inspect}"
"O"

test4 = [
'O', 'X', 'O',
'X', 'O', 'X',
'O', 'O', 'X',
]
puts "Winner of test4: #{find_winner(test4).inspect}"
"O"

test5 = [
'O', 'X', 'O',
'O', 'X', 'O',
'X', 'O', 'X',
]
puts "Winner of test5: #{find_winner(test5).inspect}"
nil

ruby coercing integer and string

Let's break down your example into something a little more simple:

num1 = 1
num2 = 2
op = '+'
result = num1 + op + num2

When you attempt to assign result, here's what's actually happening:

result = 1 + '+' + 2

Ruby reports String can't be coerced into Integer because it is attempting to add the string + to the integer 1 and Ruby can't add a string to an integer. You can read more about this at String can't be coerced into Fixnum (TypeError).

You can reproduce it with an even simpler example:

1 + '+'
TypeError: String can't be coerced into Integer

In your question you say it should perform the calculation using those variables so I am assuming that you expect result to be equal to 3. (because it should calculate 1 + 2 from the three variables) That's not what happens in your result = ... line for the reasons described above.

The proper way to do this is to use public_send as described in these other questions and answers here on Stack Overflow:

  • Can I dynamically call a math operator in Ruby?
  • Ruby string to operator
  • Ruby- How to covert a string into an operator

Thus the answer is:

num1.public_send(op, num2)
=> 3

And integrated into your example:

if operators.include?(op)
result = num1.public_send(op, num2)
else
puts "enter a valid operator"
end

What is the meaning of operator ==~ in Ruby?

The unary ~ operator has higher precedence than == or =~ so this:

string ==~ /^ABC/

is just a confusing way of writing:

string == (~/^ABC/)

But what does Regexp#~ do? The fine manual says:

~ rxp → integer or nil

Match—Matches rxp against the contents of $_. Equivalent to rxp =~ $_.

and $_ is "The last input line of string by gets or readline." That gives us:

string == (/^ABC/ =~ $_)

and that doesn't make any sense at all because the right hand side will be a number or nil and the left hand side is, presumably, a string. The condition will only be true if string.nil? and the regex match fails but there are better ways to doing that.

I think you have two problems:

  1. ==~ is a typo that should probably be =~.
  2. Your test suite has holes, possibly one hole that the entire code base fits in.

See also What is the !=~ comparison operator in ruby? for a similar question.

converting a string into a mathematical operation (ex: +2.days)

You could use eval, e.g.:

eval("Date.today+2.days")

...and then simply use string interpolation to put in the variables. Note, however, that you should only do this if you can be very certain that the values in your database are always what you want them to be; under no circumstances should users be able to change them, otherwise you'll have a major security issue which compromises your entire system.

Using more lengthy methods like the if statement you suggested (or a case statement) require you to write more code, but they are much more secure.

ruby operator =~

The =~ operator matches the regular expression against a string, and it returns either the offset of the match from the string if it is found, otherwise nil.

/mi/ =~ "hi mike" # => 3 
"hi mike" =~ /mi/ # => 3

"mike" =~ /ruby/ # => nil

You can place the string/regex on either side of the operator as you can see above.



Related Topics



Leave a reply



Submit