I'm trying to get this RSpec test pasted below to pass, but I'm lost on how I should call multiply_by
. I believe that I have to store multiply_by
as a proc so that it can be called on the expect
line, but how do I get access to the multiply_by
method if I don't instantiate the NumProcessor
class? Maybe I'm not supposed to make NumProcessor
a class, but I need to use .
operator so I can do NumProcessor.multiply_by
, so I'm unclear on that. There is something I'm missing about how procs work in ruby, I believe. Any guidance would be much appreciated.
# First attempt
class NumProcessor
def multiply_by(num)
multiply_by = Proc.new { |num| num * 2}
end
end
# Trying to write code to make this test pass without changing it
describe 'NumProcessor#multiply_by' do
it 'should double' do
double = NumProcessor.multiply_by(2)
expect(double.call(4)).to eq(8)
end
end
Updated Tests
class NumProcessor
def self.multiply_by(factor)
Proc.new { |num| num * factor}
end
end
# Trying to write code to make this test pass without changing it
describe 'NumProcessor#multiply_by' do
it 'should double' do
double = NumProcessor.multiply_by(2)
expect(double.call(2)).to eq(4)
end
it 'should triple' do
triple = NumProcessor.multiply_by(3)
expect(triple.call(2)).to eq(6)
end
end
Got them working!
CodePudding user response:
I need to use
.
operator so I can doNumProcessor.multiply_by
In order to call the method on the class itself, you have to define a so-called class method, e.g. by prefixing it with self.
: (see Methods – Scope)
class NumProcessor
def self.multiply_by(number)
# ...
end
end
You can now call it via:
NumProcessor.multiply_by(4)
#=> #<Proc:...>
If you are not going to create instances of NumProcessor
, you can make it a module:
module NumProcessor
def self.multiply_by(number)
# ...
end
end
Last not least there's module_function
– it turns a public instance method (one without self.
) into both, a class method and a private instance method:
module NumProcessor
def multiply_by(number)
# ...
end
module_function :multiply_by
end
This is how the built-in Math
module is implemented. The method can be called as a class method:
NumProcessor.multiply_by(4)
#=> #<Proc:...>
But you can also include the module into another class in order to call its methods without explicit receiver:
class Foo
include NumProcessor
def bar
multiply_by(4)
end
end
while not exposing it to the outside:
foo = Foo.new
foo.bar
#=> #<Proc:...>
foo.multiply_by(4)
# NoMethodError: private method `multiply_by' called
Regarding your implementation:
- the
multiply_by =
assignment is superfluous, because themultiply_by
variable isn't used afterwards - the
number
argument isn't used - despite its name,
multiply_by(number)
always multiplies by 2 (instead of multiplying bynumber
)
To fix it, I'd implement it as: (see the docs for Proc
which uses the very same implementation as an example)
def multiply_by(factor)
Proc.new { |n| n * factor }
end
A corresponding test could look like this:
describe 'NumProcessor' do
describe '.multiply_by' do
let(:multplier) { NumProcessor.multiply_by(factor) }
context 'with a factor of 2' do
let(:factor) { 2 }
it 'should double' do
expect(multiplier.call(4)).to eq(8)
end
end
context 'with a factor of 3' do
let(:factor) { 3 }
it 'should triple' do
expect(multiplier.call(4)).to eq(12)
end
end
end
end
CodePudding user response:
Change multiply_by
to a class method by adding self.
in the start of the method name.
class NumProcessor
def self.multiply_by(number)
multiply_by = Proc.new { |num| num * 2}
end
end
This will allow a call like NumProcessor.multiply_by(4)