Reputation: 417
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
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
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
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