Lets say I create a Calculator class that works by manipulating elements in an array - within this class I define several methods: add, subtract, multiply, divide. I want each method to raise the same error if there exist only 1 or fewer elements in the array, something like:
class Calculator
# ...
def add
if @array.length < 2
raise 'Not Enough Elements'
else
@array << @array.pop + @array.pop
end
end
# ...
end
I could write a condition to raise the error into each method, but that seems very tedious and un-Ruby. Would there be a way to apply the raised error to all the methods that would need it that would save all that typing?
One of the options would be moving the length checking logic into it's own method and using it where needed:
class Calculator
def add
check_array_length
# rest of the method
end
private
def check_array_length
raise 'Not Enough Elements' if @array.length < 2
end
end
If you are setting @array
in the initialize
method, you could raise on the early stage, saying that you can't proceed because of too less elements in the @array
:
class Calculator
def initialize(array)
raise 'Not Enough Elements' if array.length < 2
@array = array
end
end
Here's a possible structure :
module Validator
[:add, :substract, :multiply, :divide].each do |method|
define_method(method) do
validate_array_length(2)
super()
end
end
private
def validate_array_length(min,max=min)
raise 'Not Enough Elements' if @array.length < min
raise 'Too Many Elements' if @array.length > max
end
end
class Calculator
prepend Validator
def initialize(*values)
@array = values
end
def add
@array << @array.pop + @array.pop
end
# def substract ....
end
c = Calculator.new(3,2)
c.add
c.add
# => calculator.rb:12:in `validate_array_length': Not Enough Elements (RuntimeError)
class Calculator
def initialize(arr)
@arr = arr
end
def add; binary(:+); end
def subtract; binary(:-); end
def multiply; binary(:*); end
def divide; binary(:/); end
def power; binary(:**); end
def modulo; binary(:%); end
# ... (others)
def negate; unary(:-@); end
def odd?; unary(:odd?); end
def even?; unary(:even?); end
def to_f; unary(:to_f); end
# ... (others)
private
def binary(op)
raise ArgumentError, 'Too few elements' if @arr.length < 2
@arr.pop.send(op, @arr.pop)
end
def unary(op)
raise ArgumentError, 'Too few elements' if @arr.length.zero?
@arr.pop.send(op)
end
end
# add neg mod pow div mult sub add
calc = Calculator.new [ 1, 5, 2,3, 4,5, 6,7, 8,9, 10,11, 12,13]
#=> #<Calculator:0x007fa192030968 @arr=[1, 5, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]>
calc.add #=> 25 (13+12)
calc.subtract #=> 1 (11-10)
calc.multiply #=> 72 (8*9)
calc.divide #=> 1 (7/6)
calc.power #=> 625 (5**4)
calc.modulo #=> 1 (3%2)
calc.negate #=> -5 (5)
calc.add #=> ArgumentError: Too few elements
It appears that you are constructing an RPN calculator. If so, you probably want to push the result of each calculation back onto the stack. For binary operators you could change the method binary
as follows:
def binary(op)
raise ArgumentError, 'Too few elements' if @arr.length < 2
@arr << @arr.pop.send(op, @arr.pop)
@arr[-1]
end
@arr[-1]
, the result of the calculation, is the return value. The modification of unary
is similar.
You may wish to add some stack manipulation methods, such as
def pop
@arr.pop
end
def push(n)
@arr << n
end
def swap
@arr[-1], @arr[-2] = @arr[-2], @arr[-1]
end
def rotate
@arr.rotate
end
Lastly, you might find it it clearer to make the beginning (rather than end) of @arr
the top of the stack, in which you would use unshift/shift
rather than push/pop
.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.