From 4f44249edf6becb34fd1d0ac633967cd4509da35 Mon Sep 17 00:00:00 2001 From: Hilary Holz Date: Thu, 20 Apr 2017 17:02:01 -0700 Subject: [PATCH 1/5] initial skeleton --- exercises/luhn/.meta/.version | 1 + exercises/luhn/example.tt | 18 ++++++++++++++++++ lib/luhn_cases.rb | 11 +++++++++++ 3 files changed, 30 insertions(+) create mode 100644 exercises/luhn/.meta/.version create mode 100644 exercises/luhn/example.tt create mode 100644 lib/luhn_cases.rb diff --git a/exercises/luhn/.meta/.version b/exercises/luhn/.meta/.version new file mode 100644 index 0000000000..56a6051ca2 --- /dev/null +++ b/exercises/luhn/.meta/.version @@ -0,0 +1 @@ +1 \ No newline at end of file diff --git a/exercises/luhn/example.tt b/exercises/luhn/example.tt new file mode 100644 index 0000000000..469bb4eb34 --- /dev/null +++ b/exercises/luhn/example.tt @@ -0,0 +1,18 @@ +#!/usr/bin/env ruby +gem 'minitest', '>= 5.0.0' +require 'minitest/autorun' +require_relative 'luhn' + +# Common test data version: <%= abbreviated_commit_hash %> +class LuhnTest < Minitest::Test<% test_cases.each do |test_case| %> + def <%= test_case.name %> + <%= test_case.skipped %> + assert_equal <%= test_case.expected %>, <%= test_case.work_load %> + end +<% end %> +<%= IO.read(XRUBY_LIB + '/bookkeeping.md') %> + def test_bookkeeping + skip + assert_equal <%= version %>, BookKeeping::VERSION + end +end diff --git a/lib/luhn_cases.rb b/lib/luhn_cases.rb new file mode 100644 index 0000000000..88ba7da1dc --- /dev/null +++ b/lib/luhn_cases.rb @@ -0,0 +1,11 @@ +require 'exercise_cases' + +class LuhnCase < OpenStruct + def name + 'test_%s' % description.tr(' ', '_') + end + + def skipped + index.zero? ? '# skip' : 'skip' + end +end From b5bbc00ca20b940fd3ea8650794c4ca18e1723cc Mon Sep 17 00:00:00 2001 From: Hilary J Holz Date: Thu, 20 Apr 2017 22:08:25 -0400 Subject: [PATCH 2/5] Generator for Luhn, with example solution Cases and template seem to be very simple, and may be used in documenting this process. --- exercises/luhn/.meta/.version | 2 +- exercises/luhn/example.rb | 45 +++++++++--------- exercises/luhn/example.tt | 2 +- exercises/luhn/luhn_test.rb | 87 ++++++++++++++++++++++++----------- lib/luhn_cases.rb | 16 ++++++- 5 files changed, 99 insertions(+), 53 deletions(-) diff --git a/exercises/luhn/.meta/.version b/exercises/luhn/.meta/.version index 56a6051ca2..d00491fd7e 100644 --- a/exercises/luhn/.meta/.version +++ b/exercises/luhn/.meta/.version @@ -1 +1 @@ -1 \ No newline at end of file +1 diff --git a/exercises/luhn/example.rb b/exercises/luhn/example.rb index 58e1242245..1405165d47 100644 --- a/exercises/luhn/example.rb +++ b/exercises/luhn/example.rb @@ -1,35 +1,34 @@ class Luhn - def self.create(number) - test_number = number * 10 - luhn = Luhn.new(test_number) - return test_number if luhn.valid? - test_number + 10 - (luhn.checksum % 10) - end + DOUBLE = [0, 2, 4, 6, 8, 1, 3, 5, 7, 9] + DOUBLE.freeze - attr_reader :number - def initialize(number) - @number = number + def self.valid?(string) + Luhn.new(string).valid? end - def addends - numbers = [] - number.to_s.reverse.split('').map(&:to_i).each_with_index do |n, i| - if i % 2 == 0 - numbers << n - else - value = n * 2 - value -= 9 if value > 9 - numbers << value - end - end - numbers.reverse + def initialize(string) + @string = string.tr(' ', '') end def checksum - addends.inject(0, :+) + @string. + reverse.each_char.with_index. + sum {|c, i| i.odd? ? DOUBLE[c.to_i] : c.to_i } end def valid? - checksum % 10 == 0 + clean? && checksum_mod_10.zero? + end + + def clean? + @string.match(/^\d{2,}$/) end + + def checksum_mod_10 + checksum % 10 + end +end +module BookKeeping + VERSION = 1 end + diff --git a/exercises/luhn/example.tt b/exercises/luhn/example.tt index 469bb4eb34..b46731eae5 100644 --- a/exercises/luhn/example.tt +++ b/exercises/luhn/example.tt @@ -7,7 +7,7 @@ require_relative 'luhn' class LuhnTest < Minitest::Test<% test_cases.each do |test_case| %> def <%= test_case.name %> <%= test_case.skipped %> - assert_equal <%= test_case.expected %>, <%= test_case.work_load %> + <%= test_case.assertion %> <%= test_case.work_load %> end <% end %> <%= IO.read(XRUBY_LIB + '/bookkeeping.md') %> diff --git a/exercises/luhn/luhn_test.rb b/exercises/luhn/luhn_test.rb index 52d5538cc1..1b7828f669 100755 --- a/exercises/luhn/luhn_test.rb +++ b/exercises/luhn/luhn_test.rb @@ -3,57 +3,90 @@ require 'minitest/autorun' require_relative 'luhn' +# Common test data version: c826372 class LuhnTest < Minitest::Test - def test_addends - luhn = Luhn.new(12_121) - assert_equal [1, 4, 1, 4, 1], luhn.addends + def test_single_digit_strings_can_not_be_valid + # skip + refute Luhn.valid?("1") end - def test_too_large_addend + def test_A_single_zero_is_invalid skip - luhn = Luhn.new(8631) - assert_equal [7, 6, 6, 1], luhn.addends + refute Luhn.valid?("0") end - def test_checksum + def test_a_simple_valid_SIN_that_remains_valid_if_reversed skip - luhn = Luhn.new(4913) - assert_equal 22, luhn.checksum + assert Luhn.valid?("059") end - def test_checksum_again + def test_a_simple_valid_SIN_that_becomes_invalid_if_reversed skip - luhn = Luhn.new(201_773) - assert_equal 21, luhn.checksum + assert Luhn.valid?("59") end - def test_invalid_number + def test_a_valid_Canadian_SIN skip - luhn = Luhn.new(738) - refute luhn.valid? + assert Luhn.valid?("055 444 285") end - def test_valid_number + def test_invalid_Canadian_SIN skip - luhn = Luhn.new(8_739_567) - assert luhn.valid? + refute Luhn.valid?("055 444 286") end - def test_create_valid_number + def test_invalid_credit_card skip - number = Luhn.create(123) - assert_equal 1230, number + refute Luhn.valid?("8273 1232 7352 0569") end - def test_create_other_valid_number + def test_valid_strings_with_a_non_digit_included_become_invalid skip - number = Luhn.create(873_956) - assert_equal 8_739_567, number + refute Luhn.valid?("055a 444 285") end - def test_create_yet_another_valid_number + def test_valid_strings_with_punctuation_included_become_invalid skip - number = Luhn.create(837_263_756) - assert_equal 8_372_637_564, number + refute Luhn.valid?("055-444-285") + end + + def test_valid_strings_with_symbols_included_become_invalid + skip + refute Luhn.valid?("055£ 444$ 285") + end + + def test_single_zero_with_space_is_invalid + skip + refute Luhn.valid?(" 0") + end + + def test_more_than_a_single_zero_is_valid + skip + assert Luhn.valid?("0000 0") + end + + def test_input_digit_9_is_correctly_converted_to_output_digit_9 + skip + assert Luhn.valid?("091") + end + # Problems in exercism evolve over time, as we find better ways to ask + # questions. + # The version number refers to the version of the problem you solved, + # not your solution. + # + # Define a constant named VERSION inside of the top level BookKeeping + # module, which may be placed near the end of your file. + # + # In your file, it will look like this: + # + # module BookKeeping + # VERSION = 1 # Where the version number matches the one in the test. + # end + # + # If you are curious, read more about constants on RubyDoc: + # http://ruby-doc.org/docs/ruby-doc-bundle/UsersGuide/rg/constants.html + def test_bookkeeping + skip + assert_equal 1, BookKeeping::VERSION end end diff --git a/lib/luhn_cases.rb b/lib/luhn_cases.rb index 88ba7da1dc..20915aad25 100644 --- a/lib/luhn_cases.rb +++ b/lib/luhn_cases.rb @@ -2,10 +2,24 @@ class LuhnCase < OpenStruct def name - 'test_%s' % description.tr(' ', '_') + 'test_%s' % description.tr('- ', '__') + end + + def work_load + %Q(Luhn.valid?("#{input}")) end def skipped index.zero? ? '# skip' : 'skip' end + + def assertion + expected ? 'assert' : 'refute' + end +end + +LuhnCases = proc do |data| + JSON.parse(data)['cases'].map.with_index do |row, i| + LuhnCase.new(row.merge('index' => i)) + end end From 45e2de53427e6d7837bc8dc34ccca440db77f4da Mon Sep 17 00:00:00 2001 From: Hilary Holz Date: Thu, 20 Apr 2017 23:30:09 -0700 Subject: [PATCH 3/5] update example.rb for ruby 2.1.2 --- exercises/luhn/example.rb | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/exercises/luhn/example.rb b/exercises/luhn/example.rb index 1405165d47..f53ac38d01 100644 --- a/exercises/luhn/example.rb +++ b/exercises/luhn/example.rb @@ -13,22 +13,18 @@ def initialize(string) def checksum @string. reverse.each_char.with_index. - sum {|c, i| i.odd? ? DOUBLE[c.to_i] : c.to_i } + reduce(0) {|sum, (c, i)| sum + (i.odd? ? DOUBLE[c.to_i] : c.to_i) } end def valid? - clean? && checksum_mod_10.zero? + clean? && (checksum % 10).zero? end def clean? @string.match(/^\d{2,}$/) end - - def checksum_mod_10 - checksum % 10 - end end + module BookKeeping VERSION = 1 end - From 38f37161aa7f4ba45dfd674b8299334565d63296 Mon Sep 17 00:00:00 2001 From: Hilary Holz Date: Thu, 20 Apr 2017 23:57:11 -0700 Subject: [PATCH 4/5] simplify example.tt and luhn_cases.rb api --- exercises/luhn/example.tt | 2 +- lib/luhn_cases.rb | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/exercises/luhn/example.tt b/exercises/luhn/example.tt index b46731eae5..9a761d5d99 100644 --- a/exercises/luhn/example.tt +++ b/exercises/luhn/example.tt @@ -7,7 +7,7 @@ require_relative 'luhn' class LuhnTest < Minitest::Test<% test_cases.each do |test_case| %> def <%= test_case.name %> <%= test_case.skipped %> - <%= test_case.assertion %> <%= test_case.work_load %> + <%= test_case.work_load %> end <% end %> <%= IO.read(XRUBY_LIB + '/bookkeeping.md') %> diff --git a/lib/luhn_cases.rb b/lib/luhn_cases.rb index 20915aad25..991d08d2a7 100644 --- a/lib/luhn_cases.rb +++ b/lib/luhn_cases.rb @@ -6,13 +6,15 @@ def name end def work_load - %Q(Luhn.valid?("#{input}")) + %Q(#{assertion} Luhn.valid?("#{input}")) end def skipped index.zero? ? '# skip' : 'skip' end + private + def assertion expected ? 'assert' : 'refute' end From 9d8f722fe0b561de5c233996c96b10e4dfca7b14 Mon Sep 17 00:00:00 2001 From: Hilary Holz Date: Fri, 21 Apr 2017 00:25:32 -0700 Subject: [PATCH 5/5] requested changes --- exercises/luhn/example.tt | 2 +- lib/luhn_cases.rb | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/exercises/luhn/example.tt b/exercises/luhn/example.tt index 9a761d5d99..0770a41b04 100644 --- a/exercises/luhn/example.tt +++ b/exercises/luhn/example.tt @@ -7,7 +7,7 @@ require_relative 'luhn' class LuhnTest < Minitest::Test<% test_cases.each do |test_case| %> def <%= test_case.name %> <%= test_case.skipped %> - <%= test_case.work_load %> + <%= test_case.workload %> end <% end %> <%= IO.read(XRUBY_LIB + '/bookkeeping.md') %> diff --git a/lib/luhn_cases.rb b/lib/luhn_cases.rb index 991d08d2a7..df608b4e23 100644 --- a/lib/luhn_cases.rb +++ b/lib/luhn_cases.rb @@ -5,8 +5,8 @@ def name 'test_%s' % description.tr('- ', '__') end - def work_load - %Q(#{assertion} Luhn.valid?("#{input}")) + def workload + %Q(#{assertion} Luhn.valid?(#{input.inspect})) end def skipped