DRYing argument checks - ruby

There's a method that's usually called with named arguments and it looks like this
def foo(x = nil, y = nil)
fail ArgumentError, "x must be present" unless x
fail ArgumentError, "y must be present" unless y
# do stuff with x and y
end
I want to rewrite as something like
def foo(x = nil, y = nil)
required_arguments :x, :y
# do stuff with x and y
end
or
class Foo
required_arguments :bar, :x, :y
def bar(x = nil, y = nil)
end
end
I've tried to implement second approach with alias_method_chain but the problem is that __method__ is evaluated in the context of my utility module so I can't access the parameters of the method I need to check. Any ideas?

If you use ruby 2.0 you can use keyword arguments:
def foo(x: (fail ArgumentError), y: (fail ArgumentError))
# do stuff with x and y
end
And in ruby 2.1 you have proper required arguments:
def foo(x:, y:)
# do stuff with x and y
end
This way you do actually have named parameters (you called them named parameters in your question, but that's a bit confusing imho), so you have to call the method like this:
foo(x: 1, y: 2)

The value of such run-time assertions is limited, but they do have their use. I have incorporated them in YSupport. Type gem install y_support in your command line, and use it as follows
require 'y_support/typing'
def foo x=nil, y=nil
x.aT; y.aT
# do stuff with x and y
end
Mnemonic: In aT, a means "assert" and T means TypeError – raise TypeError if the assertion fails. If #aT method is called without parameters, it simply enforces that the receiver must be truey. If a block is supplied, any assertion can be written. For example, the following call enforces that the receiver be divisible by 3:
6.aT { |n| n % 3 == 0 } #=> 6
7.aT { |n| n % 3 == 0 } #=> TypeError: 7:fixnum fails its check!
In case of checking the method arguments, ArgumentError is appropriate when there is wrong number of arguments and similar problems. When the arguments are of wrong type, I prefer to raise TypeError. Error message of #aT method can be customized with two string arguments. The first one describes what the receiver, the second one describes the block assertion. For example:
7.aT "number of apples", "be divisible by three" do |n| n % 3 == 0 end
#=> TypeError: Number of apples fails to be divisible by three!
The #aT method, if it passes, returns back its receiver, so the assertions can be chained:
81.aT( "no. of apples", "divisible by 3 ) { |n|
n % 3 == 0
}.aT( "no. of apples", "be a square" ) { |n|
root = n ** 0.5; root == root.floor
} ** 0.5 #=> 9.0
Other, more specialized runtime assertions are available in YSupport, such as:
[ 1, 2, 3 ].aT_kind_of Enumerable #=> [ 1, 2, 3 ]
:foobar.aT_respond_to :each
#=> TypeError: Foobar:symbol does not respond to method 'each'!
:foobar.aT_respond_to :each, "object returned from the black box"
#=> TypeError: Object returned from the black box does not respond to method 'each'!
7.aT_equal 8
#=> TypeError: 7:fixnum must be equal to the prescribed value (8:fixnum)!
You can look up more of those methods by yourself in YSupport, and if you miss something, you are welcome to contribute it.
As a post scriptum to this post, if you are accustomed to ActiveSupport's #present? method, the runtime assertion for it in YSupport is:
[].aT_present "supplied array"
#=> TypeError: Supplied array not present!

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

Dynamically created "method_missing" containing a closure and supporting a passed block

I would like to dynamically create method_missing on an object, while still allowing it to accept blocks. At the same time, I need to use a closure in the dynamically created method_missing. Here's the problem:
To create the closure, I need to use define_singleton_method to create method_missing, passing it a block to create the closure.
Blocks cannot themselves accept blocks, so the newly created method_missing can't accept a block.
Simple demo, for clarification only (ie, I care about solving the general case, not this specific problem):
close_over_me = "99"
o = Object.new
o.define_singleton_method(:method_missing) do |*all_args|
meth, *args = all_args
"The args passed to #{meth}: #{args}. Special code: #{close_over_me}"
end
p o.hi(42) #=> "The args passed to hi: [42]. Special code: 99"
Now let's say I wanted to pass in a block, which changed the special code somehow, eg, by doubling it. That is, I'd like to write:
p o.hi(42) {|x| 2*x}
Keep in mind I want to achieve all of the following:
It will work with any method name.
method_missing must create a closure when it's dynamically defined. Hence cannot do def o.method_missing...
It must work with any number of arguments, and we don't know the number of arguments in advance. The arguments could be of any type.
Is there any metaprogramming magic that can achieve all these at once?
With the define_method family of methods, the parameter list of the block passed to define_method becomes the parameter list of the method defined by define_method, so all you need to do to take a block parameter is to add a block parameter to the block's parameter list:
close_over_me = "99"
o = Object.new
o.define_singleton_method(:method_missing) do |meth, *args, &blk|
blk ||= -> x { x }
"The args passed to #{meth}: #{args}. Special code: #{blk.(close_over_me)}"
end
p o.hi(42) {|x| x*2 } #=> "The args passed to hi: [42]. Special code: 9999"
Though it is definitely possible:
close_over_me = "99"
o = Object.new
o.define_singleton_method(:method_missing) do |*all_args, &cb|
meth, *args = all_args
yielded = cb.call(13) if cb
"Args #{meth}: #{args}. Code: #{close_over_me}. Yielded: #{yielded}."
end
p o.hi(42)
#=> "The args passed to hi: [42]. Special code: 99. Block yielded:."
p o.hi(42) { |x| 2 * x }
#=> "The args passed to hi: [42]. Special code: 99, Block yielded: 26."
I can not get how it is supposed to work with any amount of arguments, since inside the singleton we should call it explicitly.
It seems to me you are misdesigning things.
Here is modified code - you can expect a block along with all_args.
Block presence has to be validated before issuing a call to it.
Also note that since close_over_me is a string, so doubling it by multiplying by 2 results in "9999".
close_over_me = "99"
o = Object.new
o.define_singleton_method(:method_missing) do |*all_args, &block|
meth, *args = all_args
"The args passed to #{meth}: #{args}. Special code: #{block ? block.call(close_over_me) : close_over_me}"
end
p o.hi(42) {|x| x * 2}
#=> "The args passed to hi: [42]. Special code: 9999"
p o.hi(42)
#=> "The args passed to hi: [42]. Special code: 99"

What do c == self and yield do?

Can you help me understand what this class does and how we can make use of it?
class Integer
def myt
c=0
until c == self
yield(c)
c+=1
end
self
end
end
Thank you.
x = Integer.new
x.myt
I tried to test it but it doesn't work. Error is: "no block given (yield)"
Also, in my book it says to test like this:
5.myt (|| puts "I'm on iteration #{i}! "} but it also gives an error - not sure why or what this line of code means.
allonhadaya and PNY did a good job explaining the purpose (enumeration) of the myt method.
Regarding your two questions mentioned in the title:
1.) What does 'c == self' do?
The '==' operator checks whether the integer c and Integer object you instantiate, are equal in value. If they are, the expression evaluates to true.
2.) What does 'yield' do?
The 'yield' statement passes control from the current method to a block which has been provided to the method. Blocks are ruby's implementation of a closure which, simple put, means that a method can be "extended" by calling the method with a block of additional code as long as the method supports a block (ie. incorporates yield statements)
The method seems to be a times implementation.
Basically 5.times { |i| puts i } and 5.myt { |i| puts i } will do exactly the same thing.
First, it sets a counter to 0, c = 0. Then you have a conditional where it checks if c is equal with self which will always be the integer attached to the method myt. It, then yields the counter and return self when is done.
Looks like it enumerates the values between zero inclusively and self exclusively.
allon#ahadaya:~$ irb
irb(main):001:0> class Integer
irb(main):002:1> def myt
irb(main):003:2> c=0
irb(main):004:2> until c == self
irb(main):005:3> yield(c)
irb(main):006:3> c+=1
irb(main):007:3> end
irb(main):008:2> self
irb(main):009:2> end
irb(main):010:1> end
=> nil
irb(main):011:0> 5.myt { |i| puts i }
0
1
2
3
4
=> 5
irb(main):012:0>
Using the example your book gave --
5.myt {|i| puts "I'm on iteration #{i}! "}
#You were missing an object in the pipes and a curly bracket before the pipes (not parentheses)
Allows you to see the internal workings of your myt method. Initializing variable c with a value of 0 the method executes an until look until the condition "c == self" is satisfied. Self references the object, here 5, which the method is acting on.
Therefore ...
def myt
until c == 5 #Until this is true
yield(c) #Do this .. here yield will do whatever the block specified
c+=1 #Increment on each iteration the value of variable c by 1
end #closing the until loop
self #return self
end
The yield within the method passes control from your method to the parameter, a block, back to the method.
Yield therefore allows you to build methods which can have similar patterns but with block you customize it to do your particular need.
If instead of putting each number maybe all you want to do is put the odd integers between 0 and the integer you call the method on --
5.myt {|i| puts i if i.odd?} # returns I am odd: 1 and I am odd: 3
I would suggest that you write your own blocks here to see how yield works and how you can keep the same method but pass in different blocks and create different method outputs!

how do i pass a block to a method whose name ends with equals sign?

this sounds weird doesn't it?
class Dummy
def foo=(value); end
end
Dummy.new.foo = 1 { |x| x } # => syntax error
Dummy.new.foo=(1) { |x| x } # => syntax error
i tried every permutation of blanks, parenthesis, commas; no luck. i'm puzzled. i never suspected methods ending with '=' were special. is it a bug? is it intended? if intended, why? is it documented? where? please share insight.
thanks
ps. ruby is 1.9.2p290 (2011-07-09 revision 32553) [x86_64-darwin11.0.1]
The syntax sugar for methods ending in = does make it special. You can still do things like pass multiple arguments to that method, or pass a block, but not in any pretty or convenient manner:
class Foo
def bar=(a,b=nil)
p [a,b]
if block_given?
yield "hi"
else
puts "No block"
end
end
end
f = Foo.new
f.bar = 42
#=> [42, nil]
#=> No block
f.bar = 42, 17
#=> [[42,17], nil]
#=> No block
f.send(:bar=,42,17) do |x|
puts "x is #{x.inspect}"
end
#=> [42, 17]
#=> x is "hi"
Another way in which these methods are special is that when called with the syntax sugar they evaluate to the right hand value, not the return value of the method:
class Foo
def bar=(a)
return 17 # really explicit
end
end
f = Foo.new
x = (f.bar = 42)
p x
#=> 42
x = f.send(:bar=,42)
p x
#=> 17
It's not so much that the methods themselves are special, but more to do with how Ruby deals with assignments (like foo = bar). First the right hand side is evalulated, then the left hand side is evaluated and the appropriate action is taken. If the left hand side is an object attribute, then the appropriate setter method is called.
So in your example:
Dummy.new.foo = 1 { |x| x }
First ruby tries to evalulate 1 { |x| x }, which is what causes the syntax error.
Dummy.new.foo=something doesn't actually mean "call the method named foo=", but actually means something more like "evalualate something, and then determine what `Dummy.new.foo is, and if it looks like an object attribute, add = to the name and call that method". This is why Dummy.new.foo= and Dummy.new.foo = both work the same way.
You can call these methods using send, and can pass a block with this:
Dummy.new.send "foo=", 2 do
puts "HI"
end
This is because with send you can explicitly name the method you want to call.
Of course the end result is that methods ending in = seem to have some "special" behaviour you need to be aware of, but it might be useful to understand what's actually going on.

Resources