user2251284
user2251284

Reputation: 417

How do I make an operator be evaluated before methods?

If I define an operator,

class Object
  def ~@
    self || ErrorlessNil.new
  end
end

how can I make it so that the ~ is evaluated first, instead of last? Right now, something like

~[1][100].undefined_method

will throw an error, while

(~[0][22]).randomsadfldsf

works fine. The goal is to define a tool that works like coffeescript's question mark. I could make a ?? method but I can't start with a ?, and _? works ok, but that is not fun.

Upvotes: 0

Views: 74

Answers (3)

Darek Nędza
Darek Nędza

Reputation: 1420

Obvious and easy answer is that, aside (), you cannot change operator precedence.

However you REALLY want, you can use eval* or/and you can build your Abstract syntax tree (AST)/SEXP.

str = "~[1,2,3].first"
def foo str
  if str[0] == '~'
    obj, meth = str[1..-1].split '.'
    eval "(~#{obj}).#{meth}"
  end
end
foo str

foo require that str is in this format:

"<~><object/literal without dot><method without dot>"

With more complex code, foo becomes more complex. You will end with some Regexp or with AST/SEXP.

Build-in Ruby Ripper can change source into sexp. There is gem named Sorcerer. It can change Sexp from the Ripper back to source. However it was tested with 1.9.3 and 2.0 only.

*eval may be insecure because it may run code that you don't want to. Check you string before evaling it!

Upvotes: 1

sawa
sawa

Reputation: 168101

Jörg W Mittag's answer provides one reason it will not work like you want, but there is another reason.

If ~ had stronger precedence than other method application, then

~[0][22].randomsadfldsf

would not be interpreted as

(~[0][22]).randomsadfldsf

but as

(~[0])[22].randomsadfldsf

Upvotes: 3

J&#246;rg W Mittag
J&#246;rg W Mittag

Reputation: 369458

You can't.

In Ruby, you can only override the behavior of existing operators. You cannot define new operators nor can you change their precedence, arity, associativity or fixity.

This is unlike, for example, Haskell or Fortress, which allow you to define your own operators with your own fixity (prefix, postfix, infix), associativity (left, right, none) and precedence. Ruby is like Python, C# and C++ in this regard.

Upvotes: 2

Related Questions