From cd1c83ba437f69bc759e7837b812c25509f09b6f Mon Sep 17 00:00:00 2001 From: Hilary Holz Date: Sat, 22 Apr 2017 14:47:59 -0700 Subject: [PATCH 1/6] add base class ExerciseCase converted: - hamming - ocr-numbers - luhn - pig-latin to use it --- README.md | 44 +++++++++++------------ exercises/hamming/example.tt | 10 +++--- exercises/hamming/hamming_test.rb | 9 +++-- exercises/ocr-numbers/ocr_numbers_test.rb | 34 +++++++++--------- lib/exercise_cases.rb | 28 +++++++++++++++ lib/hamming_cases.rb | 21 +++++------ lib/luhn_cases.rb | 18 ++-------- lib/ocr_numbers_cases.rb | 16 +++------ lib/pig_latin_cases.rb | 12 ++----- 9 files changed, 93 insertions(+), 99 deletions(-) diff --git a/README.md b/README.md index f2c3a04fad..8a9a883b4e 100644 --- a/README.md +++ b/README.md @@ -114,54 +114,50 @@ the exercise, which lives in the x-common repository. This change will need to be submitted as a pull request to the x-common repository. This pull request needs to be merged before you can regenerate the exercise. -Changes that don't have to do directly with the test inputs and outputs, will either need to be -made to `exercises/$PROBLEM/example.tt` or `lib/$PROBLEM_cases.rb`. Then you can regenerate the -exercise with `bin/generate $PROBLEM`. +Changes that don't have to do directly with the test inputs and outputs, will +most likely be made to `lib/$PROBLEM_cases.rb` but may also be made to +`exercises/$PROBLEM/example.tt`. Then you can regenerate the exercise with +`bin/generate $PROBLEM`. #### Implementing a Generator -You will need to implement three files to create a generator: +You will need to implement two files and a directory to create a generator: -1. `exercises/$PROBLEM/example.tt` - the Erb template for the test file, `$PROBLEM_test.rb`. -1. `exercises/$PROBLEM/.meta/.version` - used to keep track of the version of the test files as the data changes. 1. `lib/$PROBLEM_cases.rb` - the logic for turning the data into tests. +1. `exercises/$PROBLEM/example.tt` - the Erb template for the test file, `$PROBLEM_test.rb`. +1. `exercises/$PROBLEM/.meta/` - metadata directory, currently contains version file You will not need to touch the top-level script, `bin/generate`. The `bin/generate` command relies on some common logic implemented in `lib/generator.rb`. You probably won't need to touch that, either. -The `lib/$PROBLEM_cases.rb` file should contain a small class that wraps the JSON for a single test case: +`lib/$PROBLEM_cases.rb` contains a derived class of `ExerciseCase` (in `lib/exercise_cases.rb`) +which wraps the JSON for a single test case. The default version looks something like this: ``` require 'exercise_cases' -class ProblemNameCase < OpenStruct - def name - 'test_%s' % description.gsub(/[ -]/, '_') - end +class ProblemNameCase < ExerciseCase def workload # Example workload: - "assert #{expected.inspect}, Problem.call(#{input.inspect})" + "#{assert_or_refute} Problem.call(#{input.inspect})" end - def skipped - index.zero? ? '# skip' : 'skip' - end end ``` -Instead of `ProblemName` use the name of the actual problem. This is important, since +Instead of `ProblemName` use the CamelCased name of the actual problem. This is important, since the generator script will infer the name of the class from the argument that is passed. -This class must implement the following methods: - -- `name` - Returns the name of the test (i.e `test_one_equals_one`) -- `workload` - Returns the main syntax for the test. This includes the assertion and any setup required for the test. This will vary depending on the test generator and its underlying implementation -- `skipped` - Returns skip syntax (i.e. `skip` or `# skip`) +This class must provide the methods used by `example.tt`. The base class provides methods +for the default template for everything except `workload`. -Beyond that, you can implement any helper methods that you need. +`workload` generates the code for the body of a test, including the assertion +and any setup required. The base class provides a variety of assertion and +helper methods. Beyond that, you can implement any helper methods that you need +as private methods in your derived class. Below this class, implement a small loop that will generate all the test cases by reading the `canonical-data.json` file, and looping through the test cases. @@ -198,7 +194,8 @@ end Finally, you need to create a text template, `example.tt`, as the bases for the test suite. -Start with the following boilerplate, and adjust as necessary: +Start with the following boilerplate, and adjust as necessary. Remember, however, to strive +to keep logic out of views. ``` #!/usr/bin/env ruby @@ -216,6 +213,7 @@ class ProblemNameTest < Minitest::Test <% end %> <%= IO.read(XRUBY_LIB + '/bookkeeping.md') %> + def test_bookkeeping skip assert_equal <%= version %>, BookKeeping::VERSION diff --git a/exercises/hamming/example.tt b/exercises/hamming/example.tt index eae5e6209a..2b477261f1 100644 --- a/exercises/hamming/example.tt +++ b/exercises/hamming/example.tt @@ -4,14 +4,16 @@ require 'minitest/autorun' require_relative 'hamming' # Common test data version: <%= abbreviated_commit_hash %> -class HammingTest < Minitest::Test<% test_cases.each do |test_case| %> +class HammingTest < Minitest::Test +<% test_cases.each do |test_case| %> def <%= test_case.name %> - <%= test_case.skipped %><% if test_case.raises_error? %> - assert_raises(ArgumentError) { <%= test_case.workload %> }<% else %> - assert_equal <%= test_case.expected %>, <%= test_case.workload %><% end %> + <%= test_case.skipped %> + <%= test_case.workload %> end + <% end %> <%= IO.read(XRUBY_LIB + '/bookkeeping.md') %> + def test_bookkeeping skip assert_equal <%= version %>, BookKeeping::VERSION diff --git a/exercises/hamming/hamming_test.rb b/exercises/hamming/hamming_test.rb index 06d9fead88..7053e045ec 100755 --- a/exercises/hamming/hamming_test.rb +++ b/exercises/hamming/hamming_test.rb @@ -3,9 +3,7 @@ require 'minitest/autorun' require_relative 'hamming' -# Test data version: -# deb225e Implement canonical dataset for scrabble-score problem (#255) - +# Common test data version: bb56dc7 class HammingTest < Minitest::Test def test_identical_strands # skip @@ -88,8 +86,9 @@ def test_disallow_second_strand_longer # not your solution. # # Define a constant named VERSION inside of the top level BookKeeping - # module. - # In your file, it will look like this: + # 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. diff --git a/exercises/ocr-numbers/ocr_numbers_test.rb b/exercises/ocr-numbers/ocr_numbers_test.rb index f1c19ef83b..8cdb7338f3 100755 --- a/exercises/ocr-numbers/ocr_numbers_test.rb +++ b/exercises/ocr-numbers/ocr_numbers_test.rb @@ -5,87 +5,87 @@ # Common test data version: 80782b6 class OcrNumbersTest < Minitest::Test - def test_recognizes_0 + def test_Recognizes_0 # skip assert_equal "0", OcrNumbers.convert(" _ \n| |\n|_|\n ") end - def test_recognizes_1 + def test_Recognizes_1 skip assert_equal "1", OcrNumbers.convert(" \n |\n |\n ") end - def test_unreadable_but_correctly_sized_inputs_return_? + def test_Unreadable_but_correctly_sized_inputs_return_? skip assert_equal "?", OcrNumbers.convert(" \n _\n |\n ") end - def test_input_with_a_number_of_lines_that_is_not_a_multiple_of_four_raises_an_error + def test_Input_with_a_number_of_lines_that_is_not_a_multiple_of_four_raises_an_error skip assert_raises(ArgumentError) { OcrNumbers.convert(" _ \n| |\n ") } end - def test_input_with_a_number_of_columns_that_is_not_a_multiple_of_three_raises_an_error + def test_Input_with_a_number_of_columns_that_is_not_a_multiple_of_three_raises_an_error skip assert_raises(ArgumentError) { OcrNumbers.convert(" \n |\n |\n ") } end - def test_recognizes_110101100 + def test_Recognizes_110101100 skip assert_equal "110101100", OcrNumbers.convert(" _ _ _ _ \n | || | || | | || || |\n | ||_| ||_| | ||_||_|\n ") end - def test_garbled_numbers_in_a_string_are_replaced_with_? + def test_Garbled_numbers_in_a_string_are_replaced_with_? skip assert_equal "11?10?1?0", OcrNumbers.convert(" _ _ _ \n | || | || | || || |\n | | _| ||_| | ||_||_|\n ") end - def test_recognizes_2 + def test_Recognizes_2 skip assert_equal "2", OcrNumbers.convert(" _ \n _|\n|_ \n ") end - def test_recognizes_3 + def test_Recognizes_3 skip assert_equal "3", OcrNumbers.convert(" _ \n _|\n _|\n ") end - def test_recognizes_4 + def test_Recognizes_4 skip assert_equal "4", OcrNumbers.convert(" \n|_|\n |\n ") end - def test_recognizes_5 + def test_Recognizes_5 skip assert_equal "5", OcrNumbers.convert(" _ \n|_ \n _|\n ") end - def test_recognizes_6 + def test_Recognizes_6 skip assert_equal "6", OcrNumbers.convert(" _ \n|_ \n|_|\n ") end - def test_recognizes_7 + def test_Recognizes_7 skip assert_equal "7", OcrNumbers.convert(" _ \n |\n |\n ") end - def test_recognizes_8 + def test_Recognizes_8 skip assert_equal "8", OcrNumbers.convert(" _ \n|_|\n|_|\n ") end - def test_recognizes_9 + def test_Recognizes_9 skip assert_equal "9", OcrNumbers.convert(" _ \n|_|\n _|\n ") end - def test_recognizes_string_of_decimal_numbers + def test_Recognizes_string_of_decimal_numbers skip assert_equal "1234567890", OcrNumbers.convert(" _ _ _ _ _ _ _ _ \n | _| _||_||_ |_ ||_||_|| |\n ||_ _| | _||_| ||_| _||_|\n ") end - def test_numbers_separated_by_empty_lines_are_recognized__lines_are_joined_by_commas_ + def test_Numbers_separated_by_empty_lines_are_recognized_Lines_are_joined_by_commas skip assert_equal "123,456,789", OcrNumbers.convert(" _ _ \n | _| _|\n ||_ _|\n \n _ _ \n|_||_ |_ \n | _||_|\n \n _ _ _ \n ||_||_|\n ||_| _|\n ") end diff --git a/lib/exercise_cases.rb b/lib/exercise_cases.rb index 2bf9289798..ba8794897c 100644 --- a/lib/exercise_cases.rb +++ b/lib/exercise_cases.rb @@ -1,2 +1,30 @@ require 'ostruct' require 'json' + +class ExerciseCase < OpenStruct + def name + 'test_%s' % description.gsub(/[^\w- ?!]/, '').gsub(/[- ]/, '_') + end + + def skipped + index.zero? ? '# skip' : 'skip' + end + + protected + + def raises_error? + expected.to_i == -1 + end + + def assert_or_refute + expected ? 'assert' : 'refute' + end + + def assert_equal + "assert_equal #{expected.inspect}, #{yield}" + end + + def assert_raises(error) + "assert_raises(#{error}) { #{yield} }" + end +end diff --git a/lib/hamming_cases.rb b/lib/hamming_cases.rb index 1ad4f69cca..aaa0db6017 100644 --- a/lib/hamming_cases.rb +++ b/lib/hamming_cases.rb @@ -1,21 +1,18 @@ require 'exercise_cases' -class HammingCase < OpenStruct - def name - 'test_%s' % description.gsub(/[ -]/, '_') - end - +class HammingCase < ExerciseCase def workload - "Hamming.compute('#{strand1}', '#{strand2}')" + if raises_error? + assert_raises(ArgumentError) { test_case } + else + assert_equal { test_case } + end end - def raises_error? - expected.to_i == -1 - end + private - def skipped - index.zero? && '# skip' || - 'skip' + def test_case + "Hamming.compute('#{strand1}', '#{strand2}')" end end diff --git a/lib/luhn_cases.rb b/lib/luhn_cases.rb index df608b4e23..8c439c8cc1 100644 --- a/lib/luhn_cases.rb +++ b/lib/luhn_cases.rb @@ -1,22 +1,8 @@ require 'exercise_cases' -class LuhnCase < OpenStruct - def name - 'test_%s' % description.tr('- ', '__') - end - +class LuhnCase < ExerciseCase def workload - %Q(#{assertion} Luhn.valid?(#{input.inspect})) - end - - def skipped - index.zero? ? '# skip' : 'skip' - end - - private - - def assertion - expected ? 'assert' : 'refute' + %Q(#{assert_or_refute} Luhn.valid?(#{input.inspect})) end end diff --git a/lib/ocr_numbers_cases.rb b/lib/ocr_numbers_cases.rb index 4fc94dd98c..9110fe4477 100644 --- a/lib/ocr_numbers_cases.rb +++ b/lib/ocr_numbers_cases.rb @@ -1,22 +1,14 @@ require 'exercise_cases' -class OcrNumbersCase < OpenStruct - def name - 'test_%s' % description.downcase.tr('- .', '_') - end - +class OcrNumbersCase < ExerciseCase def workload - if expected == -1 - "assert_raises(ArgumentError) { #{test_case} }" + if raises_error? + assert_raises(ArgumentError) { test_case } else - "assert_equal #{expected.inspect}, #{test_case}" + assert_equal { test_case } end end - def skipped - index.zero? ? '# skip' : 'skip' - end - private def test_case diff --git a/lib/pig_latin_cases.rb b/lib/pig_latin_cases.rb index e256dfdefe..cf212b079b 100644 --- a/lib/pig_latin_cases.rb +++ b/lib/pig_latin_cases.rb @@ -1,16 +1,8 @@ require 'exercise_cases' -class PigLatinCase < OpenStruct - def name - 'test_%s' % description.tr('- ', '__') - end - +class PigLatinCase < ExerciseCase def workload - %Q(assert_equal #{expected.inspect}, PigLatin.translate(#{input.inspect})) - end - - def skipped - index.zero? ? '# skip' : 'skip' + assert_equal { "PigLatin.translate(#{input.inspect})" } end end From 33e60263f1af7f222c00ff9f528a8a205119f025 Mon Sep 17 00:00:00 2001 From: Hilary Holz Date: Sat, 22 Apr 2017 14:54:23 -0700 Subject: [PATCH 2/6] fix regex for cleaning test names --- lib/exercise_cases.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/exercise_cases.rb b/lib/exercise_cases.rb index ba8794897c..764c787844 100644 --- a/lib/exercise_cases.rb +++ b/lib/exercise_cases.rb @@ -3,7 +3,7 @@ class ExerciseCase < OpenStruct def name - 'test_%s' % description.gsub(/[^\w- ?!]/, '').gsub(/[- ]/, '_') + 'test_%s' % description.gsub(/[^\w ?!]/, '').gsub(/[- ]/, '_') end def skipped From fd10aa8c36afbe69a2546b3e77bbef175bdae84f Mon Sep 17 00:00:00 2001 From: Hilary Holz Date: Sun, 23 Apr 2017 14:35:53 -0700 Subject: [PATCH 3/6] add underscore refinement --- exercises/luhn/luhn_test.rb | 10 +++--- exercises/ocr-numbers/ocr_numbers_test.rb | 34 +++++++++--------- lib/exercise_cases.rb | 28 --------------- lib/generator/exercise_cases.rb | 43 +++++++++++++++++++++++ lib/generator/string/underscore.rb | 7 ++++ lib/hamming_cases.rb | 2 -- lib/luhn_cases.rb | 4 +-- lib/ocr_numbers_cases.rb | 2 -- lib/pig_latin_cases.rb | 2 -- test/generator/string/underscore_test.rb | 14 ++++++++ 10 files changed, 87 insertions(+), 59 deletions(-) create mode 100644 lib/generator/exercise_cases.rb create mode 100644 lib/generator/string/underscore.rb create mode 100644 test/generator/string/underscore_test.rb diff --git a/exercises/luhn/luhn_test.rb b/exercises/luhn/luhn_test.rb index 1b7828f669..40d3348d29 100755 --- a/exercises/luhn/luhn_test.rb +++ b/exercises/luhn/luhn_test.rb @@ -10,27 +10,27 @@ def test_single_digit_strings_can_not_be_valid refute Luhn.valid?("1") end - def test_A_single_zero_is_invalid + def test_a_single_zero_is_invalid skip refute Luhn.valid?("0") end - def test_a_simple_valid_SIN_that_remains_valid_if_reversed + def test_a_simple_valid_sin_that_remains_valid_if_reversed skip assert Luhn.valid?("059") end - def test_a_simple_valid_SIN_that_becomes_invalid_if_reversed + def test_a_simple_valid_sin_that_becomes_invalid_if_reversed skip assert Luhn.valid?("59") end - def test_a_valid_Canadian_SIN + def test_a_valid_canadian_sin skip assert Luhn.valid?("055 444 285") end - def test_invalid_Canadian_SIN + def test_invalid_canadian_sin skip refute Luhn.valid?("055 444 286") end diff --git a/exercises/ocr-numbers/ocr_numbers_test.rb b/exercises/ocr-numbers/ocr_numbers_test.rb index 8cdb7338f3..c0e1e6f2ca 100755 --- a/exercises/ocr-numbers/ocr_numbers_test.rb +++ b/exercises/ocr-numbers/ocr_numbers_test.rb @@ -5,87 +5,87 @@ # Common test data version: 80782b6 class OcrNumbersTest < Minitest::Test - def test_Recognizes_0 + def test_recognizes_0 # skip assert_equal "0", OcrNumbers.convert(" _ \n| |\n|_|\n ") end - def test_Recognizes_1 + def test_recognizes_1 skip assert_equal "1", OcrNumbers.convert(" \n |\n |\n ") end - def test_Unreadable_but_correctly_sized_inputs_return_? + def test_unreadable_but_correctly_sized_inputs_return_ skip assert_equal "?", OcrNumbers.convert(" \n _\n |\n ") end - def test_Input_with_a_number_of_lines_that_is_not_a_multiple_of_four_raises_an_error + def test_input_with_a_number_of_lines_that_is_not_a_multiple_of_four_raises_an_error skip assert_raises(ArgumentError) { OcrNumbers.convert(" _ \n| |\n ") } end - def test_Input_with_a_number_of_columns_that_is_not_a_multiple_of_three_raises_an_error + def test_input_with_a_number_of_columns_that_is_not_a_multiple_of_three_raises_an_error skip assert_raises(ArgumentError) { OcrNumbers.convert(" \n |\n |\n ") } end - def test_Recognizes_110101100 + def test_recognizes_110101100 skip assert_equal "110101100", OcrNumbers.convert(" _ _ _ _ \n | || | || | | || || |\n | ||_| ||_| | ||_||_|\n ") end - def test_Garbled_numbers_in_a_string_are_replaced_with_? + def test_garbled_numbers_in_a_string_are_replaced_with_ skip assert_equal "11?10?1?0", OcrNumbers.convert(" _ _ _ \n | || | || | || || |\n | | _| ||_| | ||_||_|\n ") end - def test_Recognizes_2 + def test_recognizes_2 skip assert_equal "2", OcrNumbers.convert(" _ \n _|\n|_ \n ") end - def test_Recognizes_3 + def test_recognizes_3 skip assert_equal "3", OcrNumbers.convert(" _ \n _|\n _|\n ") end - def test_Recognizes_4 + def test_recognizes_4 skip assert_equal "4", OcrNumbers.convert(" \n|_|\n |\n ") end - def test_Recognizes_5 + def test_recognizes_5 skip assert_equal "5", OcrNumbers.convert(" _ \n|_ \n _|\n ") end - def test_Recognizes_6 + def test_recognizes_6 skip assert_equal "6", OcrNumbers.convert(" _ \n|_ \n|_|\n ") end - def test_Recognizes_7 + def test_recognizes_7 skip assert_equal "7", OcrNumbers.convert(" _ \n |\n |\n ") end - def test_Recognizes_8 + def test_recognizes_8 skip assert_equal "8", OcrNumbers.convert(" _ \n|_|\n|_|\n ") end - def test_Recognizes_9 + def test_recognizes_9 skip assert_equal "9", OcrNumbers.convert(" _ \n|_|\n _|\n ") end - def test_Recognizes_string_of_decimal_numbers + def test_recognizes_string_of_decimal_numbers skip assert_equal "1234567890", OcrNumbers.convert(" _ _ _ _ _ _ _ _ \n | _| _||_||_ |_ ||_||_|| |\n ||_ _| | _||_| ||_| _||_|\n ") end - def test_Numbers_separated_by_empty_lines_are_recognized_Lines_are_joined_by_commas + def test_numbers_separated_by_empty_lines_are_recognized_lines_are_joined_by_commas skip assert_equal "123,456,789", OcrNumbers.convert(" _ _ \n | _| _|\n ||_ _|\n \n _ _ \n|_||_ |_ \n | _||_|\n \n _ _ _ \n ||_||_|\n ||_| _|\n ") end diff --git a/lib/exercise_cases.rb b/lib/exercise_cases.rb index 764c787844..2bf9289798 100644 --- a/lib/exercise_cases.rb +++ b/lib/exercise_cases.rb @@ -1,30 +1,2 @@ require 'ostruct' require 'json' - -class ExerciseCase < OpenStruct - def name - 'test_%s' % description.gsub(/[^\w ?!]/, '').gsub(/[- ]/, '_') - end - - def skipped - index.zero? ? '# skip' : 'skip' - end - - protected - - def raises_error? - expected.to_i == -1 - end - - def assert_or_refute - expected ? 'assert' : 'refute' - end - - def assert_equal - "assert_equal #{expected.inspect}, #{yield}" - end - - def assert_raises(error) - "assert_raises(#{error}) { #{yield} }" - end -end diff --git a/lib/generator/exercise_cases.rb b/lib/generator/exercise_cases.rb new file mode 100644 index 0000000000..8db0ae4c1c --- /dev/null +++ b/lib/generator/exercise_cases.rb @@ -0,0 +1,43 @@ +require 'ostruct' +require 'json' + +class ExerciseCase < OpenStruct + using Underscore + + def name + 'test_%s' % description.underscore + end + + def skipped + index.zero? ? '# skip' : 'skip' + end + + protected + + # used in workload, for example, as + # "#{assert} Luhn.valid?(#{input.inspect})" + def assert + expected ? 'assert' : 'refute' + end + + # used in workload, for example, as + # assert_equal { "PigLatin.translate(#{input.inspect})" } + def assert_equal + "assert_equal #{expected.inspect}, #{yield}" + end + + # used in workload, for example, as + # if raises_error? + # assert_raises(ArgumentError) { test_case } + # else + # assert_equal { test_case } + # end + + def raises_error? + expected.to_i == -1 + end + + def assert_raises(error) + "assert_raises(#{error}) { #{yield} }" + end +end diff --git a/lib/generator/string/underscore.rb b/lib/generator/string/underscore.rb new file mode 100644 index 0000000000..c2ffc1405b --- /dev/null +++ b/lib/generator/string/underscore.rb @@ -0,0 +1,7 @@ +module Underscore + refine String do + def underscore + downcase.gsub(/[- ]/, '_').gsub(/\W/, '') + end + end +end diff --git a/lib/hamming_cases.rb b/lib/hamming_cases.rb index aaa0db6017..d6d8832831 100644 --- a/lib/hamming_cases.rb +++ b/lib/hamming_cases.rb @@ -1,5 +1,3 @@ -require 'exercise_cases' - class HammingCase < ExerciseCase def workload if raises_error? diff --git a/lib/luhn_cases.rb b/lib/luhn_cases.rb index 8c439c8cc1..377519f199 100644 --- a/lib/luhn_cases.rb +++ b/lib/luhn_cases.rb @@ -1,8 +1,6 @@ -require 'exercise_cases' - class LuhnCase < ExerciseCase def workload - %Q(#{assert_or_refute} Luhn.valid?(#{input.inspect})) + "#{assert} Luhn.valid?(#{input.inspect})" end end diff --git a/lib/ocr_numbers_cases.rb b/lib/ocr_numbers_cases.rb index 9110fe4477..fea8e4f2e8 100644 --- a/lib/ocr_numbers_cases.rb +++ b/lib/ocr_numbers_cases.rb @@ -1,5 +1,3 @@ -require 'exercise_cases' - class OcrNumbersCase < ExerciseCase def workload if raises_error? diff --git a/lib/pig_latin_cases.rb b/lib/pig_latin_cases.rb index cf212b079b..c6b9b701f6 100644 --- a/lib/pig_latin_cases.rb +++ b/lib/pig_latin_cases.rb @@ -1,5 +1,3 @@ -require 'exercise_cases' - class PigLatinCase < ExerciseCase def workload assert_equal { "PigLatin.translate(#{input.inspect})" } diff --git a/test/generator/string/underscore_test.rb b/test/generator/string/underscore_test.rb new file mode 100644 index 0000000000..d9c8b6081e --- /dev/null +++ b/test/generator/string/underscore_test.rb @@ -0,0 +1,14 @@ +require_relative '../../test_helper' + +class UnderscoreTest < MiniTest::Test + using Underscore + + # at present, we're downcasing everything, including TLAs + def test_mixed_case + assert_equal 'A string with TLA'.underscore, 'a_string_with_tla' + end + + def hyphenated_text + assert_equal 'large distance in off-by-one strand'.underscore, 'large_distance_in_off_by_one_strand' + end +end From 9297e0a3813275ae0f7e8e3290a5e0f8c676b466 Mon Sep 17 00:00:00 2001 From: Hilary Holz Date: Sun, 23 Apr 2017 15:11:00 -0700 Subject: [PATCH 4/6] namespace underscore refinement --- exercises/ocr-numbers/ocr_numbers_test.rb | 4 ++-- lib/generator/exercise_cases.rb | 2 +- lib/generator/string/underscore.rb | 10 +++++---- test/generator/string/underscore_test.rb | 25 +++++++++++++++-------- 4 files changed, 26 insertions(+), 15 deletions(-) diff --git a/exercises/ocr-numbers/ocr_numbers_test.rb b/exercises/ocr-numbers/ocr_numbers_test.rb index c0e1e6f2ca..67bec5b61d 100755 --- a/exercises/ocr-numbers/ocr_numbers_test.rb +++ b/exercises/ocr-numbers/ocr_numbers_test.rb @@ -15,7 +15,7 @@ def test_recognizes_1 assert_equal "1", OcrNumbers.convert(" \n |\n |\n ") end - def test_unreadable_but_correctly_sized_inputs_return_ + def test_unreadable_but_correctly_sized_inputs_return_? skip assert_equal "?", OcrNumbers.convert(" \n _\n |\n ") end @@ -35,7 +35,7 @@ def test_recognizes_110101100 assert_equal "110101100", OcrNumbers.convert(" _ _ _ _ \n | || | || | | || || |\n | ||_| ||_| | ||_||_|\n ") end - def test_garbled_numbers_in_a_string_are_replaced_with_ + def test_garbled_numbers_in_a_string_are_replaced_with_? skip assert_equal "11?10?1?0", OcrNumbers.convert(" _ _ _ \n | || | || | || || |\n | | _| ||_| | ||_||_|\n ") end diff --git a/lib/generator/exercise_cases.rb b/lib/generator/exercise_cases.rb index 8db0ae4c1c..f1f7271b25 100644 --- a/lib/generator/exercise_cases.rb +++ b/lib/generator/exercise_cases.rb @@ -2,7 +2,7 @@ require 'json' class ExerciseCase < OpenStruct - using Underscore + using Generator::Underscore def name 'test_%s' % description.underscore diff --git a/lib/generator/string/underscore.rb b/lib/generator/string/underscore.rb index c2ffc1405b..46d5a94559 100644 --- a/lib/generator/string/underscore.rb +++ b/lib/generator/string/underscore.rb @@ -1,7 +1,9 @@ -module Underscore - refine String do - def underscore - downcase.gsub(/[- ]/, '_').gsub(/\W/, '') +module Generator + module Underscore + refine String do + def underscore + downcase.gsub(/[- ]/, '_').gsub(/[^\w?]/, '') + end end end end diff --git a/test/generator/string/underscore_test.rb b/test/generator/string/underscore_test.rb index d9c8b6081e..4e70ce6151 100644 --- a/test/generator/string/underscore_test.rb +++ b/test/generator/string/underscore_test.rb @@ -1,14 +1,23 @@ require_relative '../../test_helper' -class UnderscoreTest < MiniTest::Test - using Underscore +module Generator + class UnderscoreTest < MiniTest::Test + using Underscore - # at present, we're downcasing everything, including TLAs - def test_mixed_case - assert_equal 'A string with TLA'.underscore, 'a_string_with_tla' - end + # at present, we're downcasing everything, including TLAs + def test_mixed_case + assert_equal 'A string with TLA'.underscore, 'a_string_with_tla' + end + + def test_hyphenated_text + assert_equal 'large distance in off-by-one strand'.underscore, 'large_distance_in_off_by_one_strand' + end - def hyphenated_text - assert_equal 'large distance in off-by-one strand'.underscore, 'large_distance_in_off_by_one_strand' + def test_question_mark + assert_equal( + 'Unreadable but correctly sized inputs return ?'.underscore, + 'unreadable_but_correctly_sized_inputs_return_?' + ) + end end end From f2cb3bb72bfc00d80c3d8f2113402296487d090a Mon Sep 17 00:00:00 2001 From: Hilary Holz Date: Sun, 23 Apr 2017 15:25:49 -0700 Subject: [PATCH 5/6] update README (doh!) --- README.md | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 8a9a883b4e..3a2a391bd7 100644 --- a/README.md +++ b/README.md @@ -132,17 +132,15 @@ You will not need to touch the top-level script, `bin/generate`. The `bin/generate` command relies on some common logic implemented in `lib/generator.rb`. You probably won't need to touch that, either. -`lib/$PROBLEM_cases.rb` contains a derived class of `ExerciseCase` (in `lib/exercise_cases.rb`) +`lib/$PROBLEM_cases.rb` contains a derived class of `ExerciseCase` (in `lib/generator/exercise_cases.rb`) which wraps the JSON for a single test case. The default version looks something like this: ``` -require 'exercise_cases' - class ProblemNameCase < ExerciseCase def workload # Example workload: - "#{assert_or_refute} Problem.call(#{input.inspect})" + "#{assert} Problem.call(#{input.inspect})" end end From b028f22cef3cc2df6be6ddd2f3d8ce3ef323849c Mon Sep 17 00:00:00 2001 From: Hilary Holz Date: Sun, 23 Apr 2017 15:44:28 -0700 Subject: [PATCH 6/6] move underscore to lib/generator/ --- lib/generator/{string => }/underscore.rb | 0 test/generator/{string => }/underscore_test.rb | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename lib/generator/{string => }/underscore.rb (100%) rename test/generator/{string => }/underscore_test.rb (94%) diff --git a/lib/generator/string/underscore.rb b/lib/generator/underscore.rb similarity index 100% rename from lib/generator/string/underscore.rb rename to lib/generator/underscore.rb diff --git a/test/generator/string/underscore_test.rb b/test/generator/underscore_test.rb similarity index 94% rename from test/generator/string/underscore_test.rb rename to test/generator/underscore_test.rb index 4e70ce6151..f5a753ea6e 100644 --- a/test/generator/string/underscore_test.rb +++ b/test/generator/underscore_test.rb @@ -1,4 +1,4 @@ -require_relative '../../test_helper' +require_relative '../test_helper' module Generator class UnderscoreTest < MiniTest::Test