What does +# mean as a method in ruby - ruby

I was reading some code and I saw something along the lines of
module M
def +#
self
end
end
I was surprised that this was legal syntax, yet when I ran ruby -c on the file (to lint) it said it was valid. -# was also a legal method name yet when I tried *# or d# both of those were illegal. I was wondering what +# means and why is it legal?

Ruby contains a few unary operators, including +, -, !, ~, & and *. As with other operators you can also redefine these. For ~ and ! you can simply just say def ~ and def ! as they don't have a binary counterpart (e.g. you cannot say a!b).
However for - and + there is both a unary, and a binary version (e.g. a+b and +a are both valid), so if you want to redefine the unary version you have to use def +# and def -#.
Also note that there is a unary version of * and & as well, but they have special meanings. For * it is tied to splatting the array, and for & it is tied to converting the object to a proc, so if you want to use them you have to redefine to_a and to_proc respectively.
Here is a more complete example showing all kinds of the unary operators:
class SmileyString < String
def +#
SmileyString.new(self + " :)")
end
def -#
SmileyString.new(self + " :(")
end
def ~
SmileyString.new(self + " :~")
end
def !
SmileyString.new(self + " :!")
end
def to_proc
Proc.new { |a| SmileyString.new(self + " " + a) }
end
def to_a
[SmileyString.new(":("), self]
end
end
a = SmileyString.new("Hello")
p +a # => "Hello :)"
p ~a # => "Hello :~"
p *a # => [":(", "Hello"]
p !a # => "Hello :!"
p +~a # => "Hello :~ :)"
p *+!-~a # => [":(", "Hello :~ :( :! :)"]
p %w{:) :(}.map &a # => ["Hello :)", "Hello :("]
In your example the Module just simply defines an unary + operator, with a default value of not doing anything with the object (which is a common behaviour for the unary plus, 5 and +5 usually mean the same thing). Mixing in with any class would mean the class immediately gets support for using the unary plus operator, which would do nothing much.
For example (using ruby <=2.2):
module M
def +#
self
end
end
p +"Hello" # => NoMethodError: undefined method `+#' for "Hello":String
class String
include M
end
p +"Hello" # => "Hello"
Note that in this example you can clearly see from the error message that the +# method is missing from the class
Note that the above example will be different from Ruby 2.3, as the unary minus and plus are defined for Strings since that version, and they refer to returning a frozen and unfrozen string from the original.

The method names +# and -# are used to overload the unary operators + and - in Ruby (1.9+).
Unary operators are operators which only take a single value (e.g. value = -value).

Related

Splat parameters behave differently for attribute writers compared to regular method

I have the following two methods, which I believe should have the same behaviour disregarding their names:
def a=(*params)
params
end
def b(*params)
params
end
But when in fact I use them:
a=(1) # => 1
b(1) # => [1]
(a=1) == b(1) # => false
while interestingly:
(a=1,2) == b(1,2) # => true
Why isn't their behaviour the same?
Edit: forgot to wrap the above in a class / call with self. which accidentally produces the same behaviour but for a different reason. It has been pointed out in the answers.
It has nothing to do with splat. It's the assignment operator. In ruby, the assignment operator returns the value assigned. The return value from the method is ignored.
So a=1 return 1, not [1].
But, as mentioned by #mudasobwa, you're not even calling the method here. But if you were, that's what would happen (ignoring the return value).
class Foo
def a=(*params)
params
end
end
f = Foo.new
f.a = 1 # => 1
f.a = 1,2 # => [1, 2]
To not ignore the return value, call that setter without using assignment operator.
f.send 'a=', 1 # => [1]
The thing is that
a = 1
sets the local variable and does not call your method at all. Try with
def a=(*param)
puts "I AM HERE"
end
var= methods require an explicit receiver. To call your method, call it with an explicit receiver:
self.a = 1
It still won’t return anything but 1, because assignment methods return the value (the same way as initialize called through MyClass.new returns an instance, no matter what.) But you might check that splat works with:
def a=(*param)
puts param.inspect
end
self.a = 1
# [1]
#⇒ 1

How to convert any method to infix operator in ruby

In some language such as Haskell, it is possible to use any function taking two arguments as an infix operator.
I find this notation interesting and would like to achieve the same in ruby.
Given a imaginary method or_if_familiar
I'd like to be able to write something like "omg" or_if_familiar "oh!" instead of or_if_familiar("omg", "oh!")
How one would create such a notation in ruby (without modifying ruby itself)?
A bit late to the party but I've been toying around with it and you can use operator overloading to create Infix operators just like in python (but with a bit more work), the syntax becomes a |op| b, here's how:
First a quick and dirty copy-paste to play around with Infix:
class Infix def initialize*a,&b;raise'arguments size mismatch'if a.length<0||a.length>3;raise'both method and b passed'if a.length!=0&&b;raise'no arguments passed'if a.length==0&&!b;#m=a.length>0? a[0].class==Symbol ? method(a[0]):a[0]:b;if a.length==3;#c=a[1];#s=a[2]end end;def|o;if#c;o.class==Infix ? self:#m.(#s,o)else;raise'missing first operand'end end;def coerce o;[Infix.new(#m,true,o),self]end;def v o;Infix.new(#m,true,o)end end;[NilClass,FalseClass,TrueClass,Object,Array].each{|c|c.prepend Module.new{def|o;o.class==Infix ? o.v(self):super end}};def Infix*a,&b;Infix.new *a,&b end
#
Ok
Step 1: create the Infix class
class Infix
def initialize *args, &block
raise 'error: arguments size mismatch' if args.length < 0 or args.length > 3
raise 'error: both method and block passed' if args.length != 0 and block
raise 'error: no arguments passed' if args.length == 0 and not block
#method = args.length > 0 ? args[0].class == Symbol ? method(args[0]) : args[0] : block
if args.length == 3; #coerced = args[1]; #stored_operand = args[2] end
end
def | other
if #coerced
other.class == Infix ? self : #method.call(#stored_operand, other)
else
raise 'error: missing first operand'
end
end
def coerce other
[Infix.new(#method, true, other), self]
end
def convert other
Infix.new(#method, true, other)
end
end
Step 2: fix all the classes that don't have a | method and the three special cases (true, false, and nil) (note: you can add any class in here and it will probably work fine)
[ NilClass, FalseClass, TrueClass,
Float, Symbol, String, Rational,
Complex, Hash, Array, Range, Regexp
].each {|c| c.prepend Module.new {
def | other
other.class == Infix ? other.convert(self) : super
end}}
Step 3: define your operators in one of 5 ways
# Lambda
pow = Infix.new -> (x, y) {x ** y}
# Block
mod = Infix.new {|x, y| x % y}
# Proc
avg = Infix.new Proc.new {|x, y| (x + y) / 2.0}
# Defining a method on the spot (the method stays)
pick = Infix.new def pick_method x, y
[x, y][rand 2]
end
# Based on an existing method
def diff_method x, y
(x - y).abs
end
diff = Infix.new :diff_method
Step 4: use them (spacing doesn't matter):
2 |pow| 3 # => 8
9|mod|4 # => 1
3| avg |6 # => 4.5
0 | pick | 1 # => 0 or 1 (randomly chosen)
You can even kinda sorta curry:
(This only works with the first operand)
diff_from_3 = 3 |diff
diff_from_3| 2 # => 1
diff_from_3| 4 # => 1
diff_from_3| -3 # => 6
As a bonus, this little method allows you to define Infixes (or any object really) without using .new:
def Infix *args, &block
Infix.new *args, &block
end
pow = Infix -> (x, y) {x ** y} # and so on
All that's left to do is wrap it up in a module
Hope this helped
P.S. You can muck about with the operators to have something like a <<op>> b, a -op- b, a >op> b and a <op<b for directionality, a **op** b for precedence and any other combination you want but beware when using true, false and nil as the first operand with logical operators (|, &&, not, etc.) as they tend to return before the infix operator is called.
For example: false |equivalent_of_or| 5 # => true if you don't correct.
FINALLY, run this to check a bunch of cases of all the builtin classes as both the first and second operand:
# pp prints both inputs
pp = Infix -> (x, y) {"x: #{x}\ny: #{y}\n\n"}
[ true, false, nil, 0, 3, -5, 1.5, -3.7, :e, :'3%4s', 'to',
/no/, /(?: [^A-g7-9]\s)(\w{2,3})*?/,
Rational(3), Rational(-9.5), Complex(1), Complex(0.2, -4.6),
{}, {e: 4, :u => 'h', 12 => [2, 3]},
[], [5, 't', :o, 2.2, -Rational(3)], (1..2), (7...9)
].each {|i| puts i.class; puts i |pp| i}
In Ruby, whether the operator is prefix or infix is fixed by the parser. Operator precedence is also fixed. There is no way, short of modifying the parser, of changing these things.
But you can implement the built-in operators for your objects
Although you may not change the fix-ness or precedence of a built-in operator, you may implement operators for your objects by defining methods. That is because Ruby translates operators into method calls. For example, this expression:
a + b
is translated into:
a.+(b)
Therefore, you may implement the + operator for an arbitrary object by defining the + method:
def +(rhs)
...
end
The prefix operator - causes a call to method #-, so to implement prefix - you do this:
def #-
..
end
You may also use methods
You may implement your own infix operators as plain methods. This will require a slightly different syntax than what you want. You want:
"omg" or_if_familiar "oh!"
Which you cannot have. What you can have is:
"omg".or_if_familiar "oh!"
This works because, in Ruby, the parentheses on method arguments may often be omitted. The above is equivalent to:
"omg".or_if_familiar("oh!")
In this example, we would implement this by monkey-patching the String class:
class String
def or_ir_familiar(rhs)
...
end
end
Ruby does not have infix method syntax, except for a fixed and predefined set of operators. And Ruby does not allow user code to change the language syntax. Ergo, what you want is not possible.
Based on Wayne Conrad's answer, I can write the following code that would work for any method defined in ruby top-level:
class Object
def method_missing(method, *args)
return super if args.size != 1
# only work if "method" method is defined in ruby top level
self.send(method, self, *args)
end
end
which allows to write
def much_greater_than(a,b)
a >= b * 10
end
"A very long sentence that say nothing really but should be long enough".much_greater_than "blah"
# or
42.much_greater_than 2
Thanks Wayne!
Interesting reference on the same subject:
Defining a new logical operator in Ruby

What kinds of names are legal for Ruby methods?

In this article, it uses the following method.
h = {}
def h.[]=(k, v)
puts "Setting hash key #{k} with #{v.inspect}"
super
end
# 1. The standard ||= approach
h[:x] ||= 10
h[:x] ||= 20
...
I understand that this is a setter like this for =( ) part.
def noise=(noise)
#noise = noise
end
Q1. But I am not sure what .[] part is doing.
Q2. Can you use [] or other non-alphabets in a Ruby method name?
Q1. But I am not sure what .[] part is doing.
Almost everything is an object in Ruby, and we can define a method on anything that's an object. So []= is a method defined on the Hash class (an object) in Ruby, just like + and - are methods on numbers (also objects):
> 4 + 5
# => 9
> 4.+(5)
# => 9
> 10.-(3)
# => 7
Likewise, we can call the .[] or .[]= methods for objects that define it, like an Array:
> arr = ['hi', 'there', 'welcome', 'to', 'StackOverflow']
> arr.[](3)
# => "to"
or like your Hash:
> hash = {:name => 'Bob', :age => 27}
> hash[:name]
# => "Bob"
> hash[:name] = 'Steve'
# => "Steve"
Again, Ruby lets us put methods on anything that's an object, and (almost) everything is an object in Ruby. So we can define that .[] method on any class we like:
> class Foo
> def [](arg)
> arg
> end
> end
> Foo.new[456]
> # => 456
Since instances of objects are also objects, we can define that method to be only on specific instances:
> h = {} # a Hash instance
> def h.[](arg) # we're giving this instance a new method
> "received #{arg}"
> end
> h[123]
# => "received 123"
Other instances of the same class won't get that implementation:
> {:foo => :bar}[123] # other Hash instances don't have this method,
# so they're using the default Hash#[] method
# => nil
.[] is something of a special case in one respect, because we let you skip the parentheses and put the argument right inside the brackets:
> arr[3] == arr.[](3)
# => true
Q2. Can you use [] or other non-alphabets in a Ruby method name?
No, you can't use [] in the name of an arbitrary Ruby method. This is an operator (like + or - in the previous example).
You can only overload specific operators, namely (listed in order of precedence):
!, ~, + (unary)
**
- (unary)
*, /, %
+, - (binary)
<<, >>
&
|, ^
<, <=, =>, >
==, ===, !=, =~, !~, <=>
Otherwise, a Ruby method can contain any mixture of alphanumeric Unicode characters and underscores. (I'm using "alphanumeric" loosely here -- Ruby is very liberal in what it allows, and generally speaking any character that isn't otherwise reserved by the language to tokenize things will work.) It may optionally end with a single ! or ?, and it may not start with a number.
So these are valid method names:
present?
valid_user?
replace!
replace
更换 (but you probably should make your method names using the A-Z Latin alphabet so developers don't hate you)
❨╯°□°❩╯︵┻━┻
┬─┬ノ❨º_ºノ❩
replace_all
REPLACE_1
REPLACE_ALL
Note that while the last two are valid method names, by convention Rubyists usually reserve ALL-CAPS identifiers for constants, not methods.
In Ruby, [] and []= are just operators and they can be overloaded.
Here []= is being defined on the singleton class for h, in other words, it is being defined to work a certain way just for h.
So when you say h[something] = somethingelse the new method gets called.
You are right that this use is quite similar to the general use of setters.
To answer the second question, you can overload the operators shown in this table, but you can't just go ahead and create operators like <-*-> as you can in some languages.

Remove substring from the string

I am just wondering if there is any method to remove string from another string?
Something like this:
class String
def remove(s)
self[s.length, self.length - s.length]
end
end
You can use the slice method:
a = "foobar"
a.slice! "foo"
=> "foo"
a
=> "bar"
there is a non '!' version as well. More info can be seen in the documentation about other versions as well:
http://www.ruby-doc.org/core/classes/String.html#method-i-slice-21
How about str.gsub("subString", "")
Check out the Ruby Doc
If it is a the end of the string, you can also use chomp:
"hello".chomp("llo") #=> "he"
If you only have one occurrence of the target string you can use:
str[target] = ''
or
str.sub(target, '')
If you have multiple occurrences of target use:
str.gsub(target, '')
For instance:
asdf = 'foo bar'
asdf['bar'] = ''
asdf #=> "foo "
asdf = 'foo bar'
asdf.sub('bar', '') #=> "foo "
asdf = asdf + asdf #=> "foo barfoo bar"
asdf.gsub('bar', '') #=> "foo foo "
If you need to do in-place substitutions use the "!" versions of gsub! and sub!.
Ruby 2.5+
If your substring is at the beginning of in the end of a string, then Ruby 2.5 has introduced the methods for this:
delete_prefix for removing a substring from the beginning of the string
delete_suffix for removing a substring from the end of the string
If you are using Rails there's also remove.
E.g. "Testmessage".remove("message") yields "Test".
Warning: this method removes all occurrences
If you are using rails or at less activesupport you got String#remove and String#remove! method
def remove!(*patterns)
patterns.each do |pattern|
gsub! pattern, ""
end
self
end
source: http://api.rubyonrails.org/classes/String.html#method-i-remove
If I'm interpreting right, this question seems to ask for something like a minus (-) operation between strings, i.e. the opposite of the built-in plus (+) operation (concatenation).
Unlike the previous answers, I'm trying to define such an operation that must obey the property:
IF c = a + b THEN c - a = b AND c - b = a
We need only three built-in Ruby methods to achieve this:
'abracadabra'.partition('abra').values_at(0,2).join == 'cadabra'.
I won't explain how it works because it can be easily understood running one method at a time.
Here is a proof of concept code:
# minus_string.rb
class String
def -(str)
partition(str).values_at(0,2).join
end
end
# Add the following code and issue 'ruby minus_string.rb' in the console to test
require 'minitest/autorun'
class MinusString_Test < MiniTest::Test
A,B,C='abra','cadabra','abracadabra'
def test_C_eq_A_plus_B
assert C == A + B
end
def test_C_minus_A_eq_B
assert C - A == B
end
def test_C_minus_B_eq_A
assert C - B == A
end
end
One last word of advice if you're using a recent Ruby version (>= 2.0): use Refinements instead of monkey-patching String like in the previous example.
It is as easy as:
module MinusString
refine String do
def -(str)
partition(str).values_at(0,2).join
end
end
end
and add using MinusString before the blocks where you need it.
here's what I'd do
2.2.1 :015 > class String; def remove!(start_index, end_index) (end_index - start_index + 1).times{ self.slice! start_index }; self end; end;
2.2.1 :016 > "idliketodeleteHEREallthewaytoHEREplease".remove! 14, 32
=> "idliketodeleteplease"
2.2.1 :017 > ":)".remove! 1,1
=> ":"
2.2.1 :018 > "ohnoe!".remove! 2,4
=> "oh!"
Formatted on multiple lines:
class String
def remove!(start_index, end_index)
(end_index - start_index + 1).times{ self.slice! start_index }
self
end
end

What is "for" in Ruby

In Ruby:
for i in A do
# some code
end
is the same as:
A.each do |i|
# some code
end
for is not a kernel method:
What exactly is "for" in ruby
Is there a way to use other keywords to do similar things?
Something like:
total = sum i in I {x[i]}
mapping to:
total = I.sum {|i] x[i]}
It's almost syntax sugar. One difference is that, while for would use the scope of the code around it, each creates a separate scope within its block. Compare the following:
for i in (1..3)
x = i
end
p x # => 3
versus
(1..3).each do |i|
x = i
end
p x # => undefined local variable or method `x' for main:Object
for is just syntax sugar for the each method. This can be seen by running this code:
for i in 1 do
end
This results in the error:
NoMethodError: undefined method `each' for 1:Fixnum
For is just syntactic sugar.
From the pickaxe:
For ... In
Earlier we said that the only built-in Ruby looping primitives were while and until. What's this ``for'' thing, then? Well, for is almost a lump of syntactic sugar. When you write
for aSong in songList
aSong.play
end
Ruby translates it into something like:
songList.each do |aSong|
aSong.play
end
The only difference between the for loop and the each form is the scope of local variables that are defined in the body. This is discussed on page 87.
You can use for to iterate over any object that responds to the method each, such as an Array or a Range.
for i in ['fee', 'fi', 'fo', 'fum']
print i, " "
end
for i in 1..3
print i, " "
end
for i in File.open("ordinal").find_all { |l| l =~ /d$/}
print i.chomp, " "
end
produces:
fee fi fo fum 1 2 3 second third
As long as your class defines a sensible each method, you can use a for loop to traverse it.
class Periods
def each
yield "Classical"
yield "Jazz"
yield "Rock"
end
end
periods = Periods.new
for genre in periods
print genre, " "
end
produces:
Classical Jazz Rock
Ruby doesn't have other keywords for list comprehensions (like the sum example you made above). for isn't a terribly popular keyword, and the method syntax ( arr.each {} ) is generally preferred.

Resources