Ruby method with few or zero parameters - how to do it? - ruby

I have two methods in Ruby:
def reverse(first,second)
#items[first..second]=#items[first..second].reverse
end
And:
def reverse
#items.reverse!
end
Can I combine these into one function and use an if first.nil? && second.nil? condition, or it is better to keep it like it is?

First option is to use default valued parameters:
def reverse(first = nil, second = nil)
if first && second
#items[first..second]=#items[first..second].reverse
else
#items.reverse!
end
end
The second option is to use variable number of args:
def reverse(*args)
if args.length == 2
#items[args.first..args.last]=#items[args.first..args.last].reverse
else
#items.reverse!
end
end

Related

How to refactor two loops to use one method in Ruby

I have the following code, and would like the loop to only exist once, but my return statements are different for each:
def valid?
patterns.each do |pattern|
match_data = text.match(pattern)
if match_data
return true
end
end
false
end
def pattern_matched
patterns.each do |pattern|
match_data = text.match(pattern)
if match_data
return pattern.source
end
end
nil
end
I don't want to store anything in state as I want these functions to be pure and independent of each other.
How can I write a helper function that runs the loop but returns either true/false OR pattern/nil?
How about:
def valid?
!pattern_matched.nil?
end
def pattern_matched
patterns.detect { |pattern| text.match(pattern) }&.source
end
I also replaced each loop as for finding first matching element detect seems like a better choice.

Undefined method in console?

Here comes another Codecademy question:
The following challenge has been presented.
Define two methods in the editor:
A greeter method that takes a single string parameter, name, and
returns a string greeting that person. (Make sure to use return and
don't use print or puts.)
A by_three? method that takes a single integer parameter, number, and
returns true if that number is evenly divisible by three and false if
not. Remember, it's a Ruby best practice to end method names that
produce boolean values with a question mark.
The code I put in re: was..
def greeter(name)
return "Greet #{name}"
end
def by_three?(x)
if x % 3==0
returns true
else
return false
end
greeter("Brant")
by_three?(6)
The console then gives me the following error:
Did you define your greeter method?
It seems like I have. Am I wrong?
this would be it:
def greeter(name)
"Greet #{name}"
end
def by_three?(x)
x % 3 == 0
end
greeter("Brant") # => "Greet Brant"
by_three?(6) # => true
It looks like you did not add "end" after your else statement. Here you go.
#For the greeter method, i decided to use this format
def greeter(name)
return name
end
greeter("Hello Jane, good morning")
def by_three?(number)
if number % 3 != 1
return true
else
return false
end #Add end here to end your statement
end
by_three?(5)

Use of yield and return in Ruby

Can anyone help me to figure out the the use of yield and return in Ruby. I'm a Ruby beginner, so simple examples are highly appreciated.
Thank you in advance!
The return statement works the same way that it works on other similar programming languages, it just returns from the method it is used on.
You can skip the call to return, since all methods in ruby always return the last statement. So you might find method like this:
def method
"hey there"
end
That's actually the same as doing something like:
def method
return "hey there"
end
The yield on the other hand, excecutes the block given as a parameter to the method. So you can have a method like this:
def method
puts "do somthing..."
yield
end
And then use it like this:
method do
puts "doing something"
end
The result of that, would be printing on screen the following 2 lines:
"do somthing..."
"doing something"
Hope that clears it up a bit. For more info on blocks, you can check out this link.
yield is used to call the block associated with the method. You do this by placing the block (basically just code in curly braces) after the method and its parameters, like so:
[1, 2, 3].each {|elem| puts elem}
return exits from the current method, and uses its "argument" as the return value, like so:
def hello
return :hello if some_test
puts "If it some_test returns false, then this message will be printed."
end
But note that you don't have to use the return keyword in any methods; Ruby will return the last statement evaluated if it encounters no returns. Thus these two are equivelent:
def explicit_return
# ...
return true
end
def implicit_return
# ...
true
end
Here's an example for yield:
# A simple iterator that operates on an array
def each_in(ary)
i = 0
until i >= ary.size
# Calls the block associated with this method and sends the arguments as block parameters.
# Automatically raises LocalJumpError if there is no block, so to make it safe, you can use block_given?
yield(ary[i])
i += 1
end
end
# Reverses an array
result = [] # This block is "tied" to the method
# | | |
# v v v
each_in([:duck, :duck, :duck, :GOOSE]) {|elem| result.insert(0, elem)}
result # => [:GOOSE, :duck, :duck, :duck]
And an example for return, which I will use to implement a method to see if a number is happy:
class Numeric
# Not the real meat of the program
def sum_of_squares
(to_s.split("").collect {|s| s.to_i ** 2}).inject(0) {|sum, i| sum + i}
end
def happy?(cache=[])
# If the number reaches 1, then it is happy.
return true if self == 1
# Can't be happy because we're starting to loop
return false if cache.include?(self)
# Ask the next number if it's happy, with self added to the list of seen numbers
# You don't actually need the return (it works without it); I just add it for symmetry
return sum_of_squares.happy?(cache << self)
end
end
24.happy? # => false
19.happy? # => true
2.happy? # => false
1.happy? # => true
# ... and so on ...
Hope this helps! :)
def cool
return yield
end
p cool {"yes!"}
The yield keyword instructs Ruby to execute the code in the block. In this example, the block returns the string "yes!". An explicit return statement was used in the cool() method, but this could have been implicit as well.

How to decide whether an optional argument was given or not in a ruby method

I have a method with an optional argument. How can I decide whether the Argument was given or not?
I came up with the following solutions. I am asking this question since I am not entirely satisfied with any of them. Exists there a better one?
nil as default value
def m(a= nil)
if a.nil?
...
end
end
The drawback with this one is, that it cannot be decided whether no argument or nil was given.
custom NoArgument as default value
class NoArgument
end
def m(a= NoArgument.new)
if NoArgument === a
...
end
end
Whether nil was given can be decided, but the same problem exists for instances of NoArgument.
Evaluating the size of an ellipsis
def m(*a)
raise ArgumentError if m.size > 1
if m.size == 1
...
end
end
In this variant it can be always decided whether the optional argument was given.
However the Proc#arity of this method has changed from 1 to -1 (not true, see the comment). It still has the disadvantage of beeing worse to document and needing to manually raise the ArgumentError.
Jorg W Mittag has the following code snippet that can do what you want:
def foo(bar = (bar_set = true; :baz))
if bar_set
# optional argument was supplied
end
end
How about
NO_ARGUMENT = Object.new
def m(a = NO_ARGUMENT)
if a.equal?(NO_ARGUMENT)
#no argument given
end
end

Refactoring respond_to? call in if-elsif-else condition

I have the following method and want to make it more readable:
def value_format(value)
if value.respond_to? :to_actor
value.to_actor
elsif value.respond_to? :to_subject
value.to_subject
elsif value.respond_to? :to_json
value.to_json
elsif value.respond_to? :to_hash
value.to_hash
else
value.inspect
end
end
This is my solution. What do you think?
def value_format(value)
methods = [:to_actor, :to_subject, :to_json, :to_hash, :inspect]
value.send(methods.find_all { |m| m if value.respond_to? m }.first)
end
Your solution looks fine, but you might as well use find instead of find_all:
METHODS = [:to_actor, :to_subject, :to_json, :to_hash, :inspect]
def value_format(value)
value.send(METHODS.find { |m| value.respond_to? m })
end
Using a constant has the advantage of not creating a new array every time value_format is ran.
Seems there's a pretty simple optimization to your solution:
def value_format(value)
methods = [:to_actor, :to_subject, :to_json, :to_hash]
value.send(methods.find(:inspect) { |m| value.respond_to? m })
end
The facets gem provides an elegant solution (I think) to this problem. It combines the two steps of checking if an object responds to a method and actually calling that method into a single step.
So your example could be rewritten as this:
require 'facets/kernel/respond'
def value_format(v)
v.respond.to_actor || v.respond.to_subject || v.respond.to_json || v.respond.to_hash || v.respond.inspect
end
Note that this method only works if it is safe to assume that none of these methods are going to return nil or false (because respond returns nil if the object doesn't respond, that is what allows us to chain it together with a bunch of ors).
Since all of the methods you listed should return strings, I believe this approach would work fine in your example.
Documentation:
# Like #respond_to? but returns the result of the call
# if it does indeed respond.
#
# class RespondExample
# def f; "f"; end
# end
#
# x = RespondExample.new
# x.respond(:f) #=> "f"
# x.respond(:g) #=> nil
#
# or
#
# x.respond.f #=> "f"
# x.respond.g #=> nil

Resources