Skip to content

Instantly share code, notes, and snippets.

@pedrogimenez
Last active September 23, 2019 20:39
Show Gist options
  • Save pedrogimenez/6096235 to your computer and use it in GitHub Desktop.
Save pedrogimenez/6096235 to your computer and use it in GitHub Desktop.
string calculator
module StringCalculator
extend self
DELIMITERS = ["\n", ","]
DELIMITER_MARK = '//'
def add(string)
numbers = extract_numbers(string)
assert_not_negatives(numbers)
total(numbers)
end
private
def extract_numbers(string)
string.split(delimiters(string)).map(&:to_i)
end
def delimiters(string)
Regexp.union(delimiters_regexp(string))
end
def delimiters_regexp(string)
regexp = DELIMITERS.tap do |delimiters|
delimiters << string[DELIMITER_MARK.length] if string.start_with?(DELIMITER_MARK)
end
end
def assert_not_negatives(numbers)
negatives = numbers.select { |number| number < 0}
raise "negatives are not allowed: #{negatives.join(', ')}" if negatives.size > 0
end
def total(numbers)
numbers.inject(0, :+)
end
end
describe StringCalculator do
context 'empty string' do
it 'returns 0 for ""' do
subject.add('').should eq(0)
end
end
context 'simple number' do
it 'returns 1 for "1"' do
subject.add('1').should eq(1)
end
it 'returns 2 for "2"' do
subject.add('2').should eq(2)
end
end
context 'two numbers' do
it 'returns 3 for "1,2"' do
subject.add('1,2').should eq(3)
end
it 'returns 5 for "2,3"' do
subject.add('2,3').should eq(5)
end
it 'returns 12 for "10,2"' do
subject.add('10,2').should eq(12)
end
end
context 'three numbers' do
it 'returns 3 for "1,1,1"' do
subject.add('1,1,1').should eq(3)
end
end
context 'with line break' do
it 'returns 5 for "2\n3"' do
subject.add("2\n3").should eq(5)
end
it 'returns 9 for "3\n3,3"' do
subject.add("3\n3,3").should eq(9)
end
end
context 'with custom delimiter' do
it 'returns 10 for "//;\n5;5"' do
subject.add("//;\n5;5").should eq(10)
end
end
context 'with negative numbers' do
it 'throws error with the list of the negative numbers' do
expect { subject.add('-1,-2,-3') }.to raise_exception(
'negatives are not allowed: -1, -2, -3')
end
end
it 'integration' do
subject.add("//;\n5;5\n2,3,300\n1000").should eq(1315)
end
end
@juanxo
Copy link

juanxo commented Jul 27, 2013

Creo que no necesitamos guardar los delimiters en la clase Numbers, puesto que solo se usan en el initialize (que los tiene como parametro tambien) y en el parse, que es privado. Fijate que nunca llamamos al getter. Sería mejor pasarlo como parametro al parse.

Por otro lado, algo que he estado pensando es en el parse_numbers. numbers es redundante( la clase ya te lo dice) y ademas, no parsea, extrae.

@pedrogimenez
Copy link
Author

I did some improvements :-)

@gpg0
Copy link

gpg0 commented Jul 27, 2013

Couple of improvements and simplifications. https://gist.github.com/pasku/90f9138bdb37af5dc99b

@pedrogimenez
Copy link
Author

pedrogimenez commented Jul 27, 2013

@pasku I have applied some of your improvements here :-)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment