I am trying to stub a method that returns multiple values. For example:
class Foo
def foo(a,b)
return a + 1, b + 2
end
end
I want to stub it but I'm having trouble with and_return with 2 value returns
f = Foo.new
f.stub!(:foo).and_return(3,56)
doesn't work. It basically returns 3 the first time it's called and 56 the second time. Does anyone know what the syntax would be to have it return 3,56 the first time it's called? Is this even possible with rspec?
thanks in advance...
jd
Multiple-value returns are arrays:
> def f; return 1, 2; end
> f.class
=> Array
So return an array:
f.stub!(:foo).and_return([3, 56])
Related
I got a sample code that turns a block into an object using Proc.new so that it can be executed independently. There are two puts at the end to print the result, in this example, the array is brought into the block for execution. At this point, I have something that I don't understand.
In the following code, why is .iterate!(square) valid? They are the method defined in the class and the name of a separate block object. Why can they be written together?
Second, what is the working process of def iterate!(code)? Why is the value being carried into (code)? And what are self and code.call here?
square = Proc.new do |n|
n ** 2
end
class Array
def iterate!(code)
self.map {|n| code.call(n)}
end
end
puts [1, 2, 3].iterate!(square)
puts [4, 5, 6].iterate!(square)
I'm a beginner, please explain as detailed as possible, thank you.
square = Proc.new do |n|
n ** 2
end
This is a simple proc, which expect an integer argument, and return square of the argument.
eg:
square.call(5) => 25
square.(5) => 25
Now, You have opened Array class and added iterate! method which takes an argument. and the method just work on self (self here refers to same array on which you are calling the iterate method. here self = [1,2,3] in your first case and [4,5,6] in you second case.
in the iterate! method definition, you are mapping/looping the array elements and you are calling the square proc with each element as arguments.
So it is more like
square.call(1) => 1
square.call(2) => 4
square.call(3) => 9
I know when writing a function that takes a string, it looks like:
def function("string")
but how do I write one that takes an array? should I first define an empty array e.g. s=[] and then when writing the function, just use s as the input?
Please try this.
#here argument name can be anything. It not compulsory to use array as argument name, it can be anything like `string`, `xyz` etc
def function(array)
p array
end
function([1,2,3,4,5])
This is really a question about Ruby than Rails. Ruby is a dynamic typing language, which in method definition, means you don't declare the argument types:
def add_three ( x, y , z)
x + y + z
end
add_three(1, 2, 3) # 6
add_three('a', 'b', 'c') # 'abc'
add_three([2], [3], [4], # [2, 3, 4]
add_three(Date.new(2017,3,4), 1, 1), # new date 2017.3.6
What matters is that x has a method + that accepts y, and the result from x + y has a method + that accepts z. This is called duck typing. What's important here is not which class the object is, but what message it can respond to.
As Ruby is dynamic language and it supports Duck Typing we never declare the data type of the variables or arguments of the method. So you could pass the array in any method, ruby just cares about the methods you can use on that argument which is an object for it. So to be sure about the array methods you are using will execute on array only you can do like this:
def doSomething(value)
if (value.is_a?(Array))
value.any_array_method # For eg: value.include?('a')
else
raise "Expected array value"
end
end
And you can call it like:
doSomething(['a', 'b', 'c'])
and if you call it with any other argument than array then it will give:
RuntimeError: Expected array value
You can pass an error message too instead of raising an exception that depends on you.
Hope this helps.
You can do it by doing
def my_function(arr=[], s)
puts arr.inspect
puts s.inspect
end
you can call the method with
my_function([1,3,4], "string")
...
begin
last = Folder.where(name: #folders.last, user_id: #user_id)
prev = Folder.where(name: #folders[count], user_id: #user_id)
for z in 0..last.count
for x in 0..prev.count
valid = Folder.exists?(name: last[z].name, parent_id: prev[x].id)
case valid
when true
#test += valid.to_s
#ids << Folder.find_by(id: prev[x].id).id
##ids = #ids[0].id
else
end
end
end
#test += 'MSG'
rescue Exception => e
#test = e.message
valid = false
else
end
This is a portion of code, everything working fine except the code after loops which displays message #test += 'MSG'. There is an exception in rescue block, which says undefined method `id' for nil:NilClass but the method returns the id, so its working. What is the issue, please help? Why the code after two loops will not working
The loop should be 0..(last.count-1) and 0..(prev.count-1), to account for 0 index.
Or a more readable excluded end range (as suggested by Neil Slater)
0...last.count and 0...prev.count
EDIT
Lets say last has 3 items in it. Then looping through 0..3 will go through
last[0], last[1], last[2], last[3] #(4 items) Which will result in error
So instead, you should loop through 0..2 or 0...3 (three dots means exclude last num)
Your problem is that your iterators x and z get too large and reference empty array indexes. But your code does not actually need them, as you only use x and z to index into the separate arrays.
It is quite rare in Ruby to use for loops to iterate through an Array. The core Array class has many methods that give ways to iterate through and process lists of objects, and it is usually possible to find one that does more precisely what you want, simplifying your code and improving readability.
Your code could be re-written using Array#each:
last = Folder.where(name: #folders.last, user_id: #user_id)
prev = Folder.where(name: #folders[count], user_id: #user_id)
last.each do |last_folder|
prev.each do |prev_folder|
valid = Folder.exists?(name: last_folder.name, parent_id: prev_folder.id)
case valid
when true
#test += valid.to_s
#ids << Folder.find_by(id: prev_folder.id).id
else
end
end
end
#test += 'MSG'
... etc
This question already has answers here:
what is the point of return in Ruby?
(7 answers)
Closed 8 years ago.
When inside of a method in Ruby, what is the difference between print and return?
def squared_number(num)
return (num**2)
end
and
def squared_number(num)
print (num**2)
end
return ends current method returning passed parameter as a result. Example:
def add(a, b)
return a + b
end
c = add(1, 2)
In Ruby last statement returns value automatically. So we can define our add method like this
def add(a, b)
a + b
end
But return is very useful, if you want to end a method execution prior to the last line. For example:
def specialAdd(a, b)
if a < 0
return -1
end
a + b
end
This method returns always -1 if the first argument is negative. In all other cases it works just like add method.
On the other hand the print method outputs the passed parameter to the standard output (console) returning nil as a result. We can see it using irb - interactive ruby console:
$ irb
irb(main):002:0> print "Hello World\n"
Hello World
=> nil
irb(main):003:0>
Here we see "Hello World" plus newline printed. The returned value of the print method is nil.
A lot.
print will output the number without a newline on the end.
return will return the number from the method.
I have some code like below. comment method is called whenever some comment occurs in the html. Then, I am doing a regexp match, I want to count the number of matches within the parsed comments. Its printing like below
1
2
3
4
5
what I want is to just print 5 because thats the total number of matches. can someone help pls.
class PlainTextExtractor < Nokogiri::XML::SAX::Document
def comment(string)
# I am defining some regexp here
m = Regexp.new(re, Regexp::IGNORECASE);
if m.match(string)
$count += 1
puts $count
end
end
end
parser = Nokogiri::HTML::SAX::Parser.new(PlainTextExtractor.new)
parser.parse_memory(html)
Just move your puts $count out of the loop. You can put it at the end, after you call the parser.
If you are only interested in the number of matches you can do
m = Regexp.new(re, Regexp::IGNORECASE);
puts string.scan(m).length
One way is to make your class count the number of matches internally in an instance variable, eg #count. Then use attr_reader to create a method allowing you to read its value at the end. Also you don't need a global variable. Example (not tested):
class PlainTextExtractor < Nokogiri::XML::SAX::Document
attr_reader :count
def comment(string)
# I am defining some regexp here
m = Regexp.new(re, Regexp::IGNORECASE);
if m.match(string)
#count += 1
end
end
end
pt_extractor = PlainTextExtractor.new
parser = Nokogiri::HTML::SAX::Parser.new(pt_extractor)
parser.parse_memory(html)
puts pt_extractor.count