How do I make an operator be evaluated before methods? - ruby

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.

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

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.

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!

Related

Ruby - when I should use parenthesis or not when calling a function/method

Is there a clear standard or guide to use or not use parenthesis when calling a function/method?
For example, the following code:
class List < Jets::Stack
sqs_queue(:dead_letter)
end
Should I or shouldn't I use parenthesis? Other example:
class ExampleJob < ApplicationJob
def sqs_event ref(:dead_letter)
end
end
vs.
class ExampleJob < ApplicationJob
def sqs_event ref :dead_letter
end
end
Is there a official guideline I can follow?
There isn't an official standard for Ruby code best practices. However, a set of preferred styles has evolved in the Ruby community. It's a good idea to follow those preferred styles, just because it makes your code more easily readable by other Ruby programmers.
Nick Roz has given you a link to the style guide. I would also recommend that you consider installing and using rubocop. It will give you feedback on when and when not to parenthesize arguments, many other formatting matters such as proper indenting, and which of the often several different syntax options to choose in a particular situation.
To answer your specific question about whether or not to use parentheses for method arguments, the answer is yes, in general. Exceptions are, as the guide says, "methods that have 'keyword' status in Ruby." An example is puts (actually the Kernel.puts method). Most people don't use parentheses here, but the guide states that they are optional.
Another example, as Nick has said (although "methods with keyword arguments" isn't quite correct; in that case the arguments are symbols that represent methods rather than keywords), is attr_accessor, which is actually Module.attr_accessor.
So, as a general rule, if it looks like a "command" (a "keyword," if you will), but is actually a method, omit the parentheses. Otherwise, use them. And if you're not sure of the difference, get in the habit of using rubocop.
In Ruby it is usually optional.
Ruby tends towards minimalism so they are often avoided.
Sometimes they are required such as in rspec expect where
expect a.to be true
has to be
expect(a).to be true
Using no parens or empty parens when calling a method that has a parameter results in ArgumentError unless you a default for the param, i.e.
def a(x=1)
The other consideration is when you want to call a method on the result of something, when you'll need want that method to clearly be on the final result, i.e.
"br" + "own".upcase
brOWN
However
("br" + "own").upcase
BROWN
Finally, as I'm talking about clarity, sometimes it may be better to have them, even when not strictly needed. This is generally in compound expressions, rather than relying on operator precedence, etc. Or if you want an expression that specifically does not get executed by standard operator precedence and you want your own grouping and order of operations, for example:
irb(main):007:0> 5 + 6 * 2
=> 17
irb(main):008:0> (5 + 6) * 2
=> 22
As Nick indicated, the one complication is super where super or super() pass on parms but super(a,b) calls super with... a,b as params
Yes there is
I suppose you are looking for community guidelines since there is not style guides from Ruby core team.
Well, whenever you call a method you should use parenthesis, otherwise it becomes unclear
# bad
x = Math.sin y
# good
x = Math.sin(y)
# bad
array.delete e
# good
array.delete(e)
# bad
temperance = Person.new 'Temperance', 30
# good
temperance = Person.new('Temperance', 30)
However it is recommended to skip them when there is no arguments.
Be careful with super and super() they are different. super without brackets passes all the parameters implicitly. super() with empty brackets omits all the parameters
The only exception that comes to my mind is some kind of custom DSL, there must be some rules or preferences for DSL itself e.g.
validates :name, presence: true
It is also true for methods with keyword arguments:
attr_reader :name, :age
According to Matz:
If arguments are given to a method, they are generally surrounded by
parentheses,
object.method(arg1, arg2)
but they can be omitted if doing so does not cause ambiguity.
object.method arg1, arg2

Provide alias for Ruby's built-in keyword

For example, I want to make Object#rescue another name so I can use in my code like:
def dangerous
something_dangerous!
dont_worry # instead of rescue here
false
end
I tried
class ::Object
alias :dont_worry :rescue
end
But cannot find the rescue method on Object:
`<class:Object>': undefined method `rescue' for class `Object' (NameError)
Another example is I would like to have when in the language to replace:
if cond
# eval when cond is truthy
end
to
when cond
# eval when cond is truthy
end
Is it possible to give a Ruby keyword alias done in Ruby?
Or I need to hack on Ruby C source code?
Thanks!
This is not possible without some deep changes to the Ruby language itself. The things you describe are not methods but keywords of the language, i.e. the actual core of what is Ruby. As such, these things are not user-changeable at all.
If you still want to change the names of the keywords, you would at least have to adapt the language parser. If you don't change semantics at all, this might do it as is. But if you want to change what these keywords represent, things get messy really quick.
Also note that Ruby in itself is sometimes quite ambiguous (e.g. with regards to parenthesis, dots, spacing) and goes to great length to resolve this in a mostly consistent way. If you change keywords, you would have to ensure that things won't get any more ambiguous. This could e.g. happen with your change of if to when. when is used as a keywords is case statements already and would thus could be a source of ambiguity when used as an if.

Ruby operator and method invoking

Assume that we have a class
class Foo
def + (element); end
def add (element); end
end
Now we can invoke these two methods like:
foo = Foo.new
foo.+('bar')
foo.add('bar')
And that's resonable. This is the right way of invoking methods.
My question is: Why we can do something like:
foo + 'bar'
but not:
foo add 'bar'
Does Ruby distinguish if method name is actually operator overloading? How does it work?
This is one of the things many people refer to as Ruby's syntax sugar. The language recognizes these mathematical operators as well as other ASCII symbol operators, such as the << insertion operator, and allows them to be called with white space and without the method dot. This allows for a more natural usage of the method.
Your #add method is not recognized by Ruby to be a standard operator and so this syntax help is not performed.
Ruby treats specific method names called also as a (subset of) operators differently. They can be invoked without a dot ., can be prepended to an owning object (do not require an argument, ie. unary operators) and have different precedence order then standard methods.
Here is a fixed list of concrete `operator' methods which are not keywords and can be defined or overloaded (marked with Y).

Defining a new logical operator in Ruby

Very much an idle day-dream this but is it possible with some neat meta-programming trick to define a new logical operator in Ruby? I'd like to define a but operator.
For example, if I want to do something if x but not y is true I have to write something like:
if x and not y
But I would like to write
if x but not y
It should work exactly the same as and but would be down to the programmer to use sensibly to increase the legibility of code.
Without editing the Ruby parser and sources and compiling a new version of Ruby, you can't. If you want, you can use this ugly syntax:
class Object
def but(other)
self and other
end
end
x.but (not y)
Note that you can't remove the parentheses or the space in this snippet. It will also shadow the functionality of the code to someone else reading your code. Don't do it.
If you really want to do this, try editing parse.y and recompiling Ruby. That's where Ruby's syntax is defined.
As others have already pointed out, you cannot define your own operators in Ruby. The set of operators is predefined and fixed. All you can do is influence the semantics of some of the existing operators (namely the ones that get translated into message sends) by responding to the appropriate messages.
But of course, you can implement a but method quite easily:
class Object
def but
self && yield
end
end
Object.new.but { not true }

Idiomatic use of parentheses in Ruby

array.include? 'foo' or array.include? 'bar'
is a syntax error (unexpected keyword_or). Parentheses solve the problem, but as I'm new to Ruby I've no idea which of the following is considered more idiomatic:
Option 1
array.include?('foo') or array.include?('bar')
Option 2
(array.include? 'foo') or (array.include? 'bar')
Does this come down to personal preference, or is one approach considered more "correct"?
I'd suggest you take a look at the community-driven Ruby coding style guide, here particularly the section on Syntax.
Omit parentheses around parameters for methods that are part of an internal DSL (e.g. Rake, Rails, RSpec), methods that are with "keyword" status in Ruby (e.g. attr_reader, puts) and attribute access methods. Use parentheses around the arguments of all other method invocations. - excerpt from the guide
class Person
attr_reader :name, :age
# omitted
end
temperance = Person.new('Temperance', 30)
temperance.name
puts temperance.age
x = Math.sin(y)
array.delete(e)
Are you sure that is failing? Your initial example works fine for me.
ruby-1.9.2-p290 :002 > array = ['bar']
=> ["bar"]
ruby-1.9.2-p290 :003 > array.include? 'foo' or array.include? 'bar'
=> true
As a matter of fact, if anything could be considered idiomatic it would be that one. The low precedence of or allows this to work when you leave the parens off. This characteristic is something that should make it idiomatic to Ruby (and even Perl, which or is a hold over from).
Option 1 is super clear, but considering you included the parens you really have no need to use or. It's probably better to use ||, which has a high precedence like other operators and is just more common. I think using or for the sake of it looking like english is not a great practice. It has a semantic meaning within the language and is probably best used for those qualities.
Option 2 is silly of course. If you're going to include parens, you might as well use them for the method signature.
Hope this helps.
Avdi Grimm reckons you shouldn't use and or or for boolean logic. You should only and or or for control flow (analogous to if or unless)
According to his recommendation, you should use || instead:
array.include?('foo') || array.include?('bar')
Option 1 is preferred since it's common to other languages as well. Option 2 looks like LISP, which is not popular nowadays.

Resources