diff --git a/exercises/triangle/.version b/exercises/triangle/.version new file mode 100644 index 0000000000..56a6051ca2 --- /dev/null +++ b/exercises/triangle/.version @@ -0,0 +1 @@ +1 \ No newline at end of file diff --git a/exercises/triangle/example.rb b/exercises/triangle/example.rb index c14012360b..65cf463f08 100644 --- a/exercises/triangle/example.rb +++ b/exercises/triangle/example.rb @@ -1,44 +1,37 @@ -class TriangleError < RuntimeError +module BookKeeping + VERSION = 1 end class Triangle - attr_reader :a, :b, :c - def initialize(a, b, c) - @a = a - @b = b - @c = c - end + attr_reader :sides - def kind - fail TriangleError if illegal? - if equilateral? - :equilateral - elsif isosceles? - :isosceles - else - :scalene + def initialize(sides) + @sides = sides + if illegal? + @sides = [] end end - private - - def sides - @sides ||= [a, b, c] - end - def equilateral? sides.uniq.size == 1 end def isosceles? - sides.uniq.size == 2 + sides.uniq.size.between?(1, 2) end + def scalene? + sides.uniq.size == 3 + end + + private + def illegal? impossible_length_side? || violates_inequality? end def violates_inequality? + a, b, c = sides a + b <= c || a + c <= b || b + c <= a end diff --git a/exercises/triangle/example.tt b/exercises/triangle/example.tt new file mode 100644 index 0000000000..7a4cac18a9 --- /dev/null +++ b/exercises/triangle/example.tt @@ -0,0 +1,20 @@ +#!/usr/bin/env ruby +gem 'minitest', '>= 5.0.0' +require 'minitest/autorun' +require_relative 'triangle' + +# Test data version: +# <%= sha1 %> +class TriangleTest < Minitest::Test<% test_cases.each do |test_case| %> + def <%= test_case.test_name %> + <%= test_case.skipped %> + <%= test_case.workload %> + end +<% end %> +<%= IO.read(XRUBY_LIB + '/bookkeeping.md') %> + def test_bookkeeping + skip + assert_equal <%= version.next %>, BookKeeping::VERSION + end +end + diff --git a/exercises/triangle/triangle_test.rb b/exercises/triangle/triangle_test.rb index 41ce62ec24..b5277fe085 100755 --- a/exercises/triangle/triangle_test.rb +++ b/exercises/triangle/triangle_test.rb @@ -3,91 +3,131 @@ require 'minitest/autorun' require_relative 'triangle' +# Test data version: +# b806246 class TriangleTest < Minitest::Test - def test_equilateral_triangles_have_equal_sides - assert_equal :equilateral, Triangle.new(2, 2, 2).kind + def test_triangle_is_equilateral_if_all_sides_are_equal + # skip + triangle = Triangle.new([2, 2, 2]) + assert triangle.equilateral?, "Expected 'true', triangle is equilateral." end - def test_larger_equilateral_triangles_also_have_equal_sides + def test_triangle_is_not_equilateral_if_any_side_is_unequal skip - assert_equal :equilateral, Triangle.new(10, 10, 10).kind + triangle = Triangle.new([2, 3, 2]) + refute triangle.equilateral?, "Expected 'false', triangle is not equilateral." end - def test_isosceles_triangles_have_last_two_sides_equal + def test_triangle_is_not_equilateral_if_no_sides_are_equal skip - assert_equal :isosceles, Triangle.new(3, 4, 4).kind + triangle = Triangle.new([5, 4, 6]) + refute triangle.equilateral?, "Expected 'false', triangle is not equilateral." end - def test_isosceles_triangles_have_first_and_last_sides_equal + def test_all_zero_sides_are_illegal_so_the_triangle_is_not_equilateral skip - assert_equal :isosceles, Triangle.new(4, 3, 4).kind + triangle = Triangle.new([0, 0, 0]) + refute triangle.equilateral?, "Expected 'false', triangle is not equilateral." end - def test_isosceles_triangles_have_two_first_sides_equal + def test_equilateral_triangle_sides_may_be_floats skip - assert_equal :isosceles, Triangle.new(4, 4, 3).kind + triangle = Triangle.new([0.5, 0.5, 0.5]) + assert triangle.equilateral?, "Expected 'true', triangle is equilateral." end - def test_isosceles_triangles_have_in_fact_exactly_two_sides_equal + def test_triangle_is_isosceles_if_last_two_sides_are_equal skip - assert_equal :isosceles, Triangle.new(10, 10, 2).kind + triangle = Triangle.new([3, 4, 4]) + assert triangle.isosceles?, "Expected 'true', triangle is isosceles." end - def test_isosceles_triangles_have_unequal_side_larger_than_equal_sides + def test_triangle_is_isosceles_if_first_two_sides_are_equal skip - assert_equal :isosceles, Triangle.new(4, 7, 4).kind + triangle = Triangle.new([4, 4, 3]) + assert triangle.isosceles?, "Expected 'true', triangle is isosceles." end - def test_scalene_triangles_have_no_equal_sides + def test_triangle_is_isosceles_if_first_and_last_sides_are_equal skip - assert_equal :scalene, Triangle.new(3, 4, 5).kind + triangle = Triangle.new([4, 3, 4]) + assert triangle.isosceles?, "Expected 'true', triangle is isosceles." end - def test_2a_equals_b_plus_c_looks_like_equilateral_but_is_not + def test_equilateral_triangles_are_also_isosceles skip - assert_equal :scalene, Triangle.new(5, 4, 6).kind + triangle = Triangle.new([4, 4, 4]) + assert triangle.isosceles?, "Expected 'true', triangle is isosceles." end - def test_scalene_triangles_have_no_equal_sides_at_a_larger_scale_too + def test_triangle_is_not_isosceles_if_no_sides_are_equal skip - assert_equal :scalene, Triangle.new(10, 11, 12).kind + triangle = Triangle.new([2, 3, 4]) + refute triangle.isosceles?, "Expected 'false', triangle is not isosceles." end - def test_scalene_triangles_have_no_equal_sides_in_descending_order_either + def test_sides_that_violate_triangle_inequality_are_not_isosceles_even_if_two_are_equal skip - assert_equal :scalene, Triangle.new(5, 4, 2).kind + triangle = Triangle.new([1, 1, 3]) + refute triangle.isosceles?, "Expected 'false', triangle is not isosceles." end - def test_very_small_triangles_are_legal + def test_isosceles_triangle_sides_may_be_floats skip - assert_equal :scalene, Triangle.new(0.4, 0.6, 0.3).kind + triangle = Triangle.new([0.5, 0.4, 0.5]) + assert triangle.isosceles?, "Expected 'true', triangle is isosceles." end - def test_triangles_with_no_size_are_illegal + def test_triangle_is_scalene_if_no_sides_are_equal skip - assert_raises(TriangleError) do - Triangle.new(0, 0, 0).kind - end + triangle = Triangle.new([5, 4, 6]) + assert triangle.scalene?, "Expected 'true', triangle is scalene." end - def test_triangles_violating_triangle_inequality_are_illegal + def test_triangle_is_not_scalene_if_all_sides_are_equal skip - assert_raises(TriangleError) do - Triangle.new(1, 1, 3).kind - end + triangle = Triangle.new([4, 4, 4]) + refute triangle.scalene?, "Expected 'false', triangle is not scalene." end - def test_triangles_violating_triangle_inequality_are_illegal_2 + def test_triangle_is_not_scalene_if_two_sides_are_equal skip - assert_raises(TriangleError) do - Triangle.new(7, 3, 2).kind - end + triangle = Triangle.new([4, 4, 3]) + refute triangle.scalene?, "Expected 'false', triangle is not scalene." end - def test_triangles_violating_triangle_inequality_are_illegal_3 + def test_sides_that_violate_triangle_inequality_are_not_scalene_even_if_they_are_all_different skip - assert_raises(TriangleError) do - Triangle.new(1, 3, 1).kind - end + triangle = Triangle.new([7, 3, 2]) + refute triangle.scalene?, "Expected 'false', triangle is not scalene." + end + + def test_scalene_triangle_sides_may_be_floats + skip + triangle = Triangle.new([0.5, 0.4, 0.6]) + assert triangle.scalene?, "Expected 'true', triangle is scalene." + 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/triangle_cases.rb b/lib/triangle_cases.rb new file mode 100644 index 0000000000..09afe6a307 --- /dev/null +++ b/lib/triangle_cases.rb @@ -0,0 +1,51 @@ +class TriangleCase < OpenStruct + def test_name + initial = description.downcase + replaced = initial.gsub(/(true|false)/, expected_type) + if initial.eql?(replaced) && !initial.include?(triangle) + replaced = triangle + ' triangle ' + initial + end + 'test_%s' % replaced.tr_s(', -', '_') + end + + def workload + [ + "triangle = Triangle.new(#{sides})", + indent("#{assert_or_refute} triangle.#{triangle}?, #{failure_message}") + ].join("\n") + end + + def indent(line) + ' ' * 4 + line + end + + def assert_or_refute + expected ? 'assert' : 'refute' + end + + def failure_message + %Q("Expected '#{expected}', #{expected_type}.") + end + + def expected_type + "triangle is #{expected ? '' : 'not '}#{triangle}" + end + + def skipped + index.zero? ? '# skip' : 'skip' + end +end + +TriangleCases = proc do |data| + i = 0 + cases = [] + data = JSON.parse(data).select { |key, value| key.to_s.match(/[^#]+/) } + data.keys.each do |triangle| + data[triangle]['cases'].each do |row| + row = row.merge(row.merge('index' => i, 'triangle' => triangle)) + cases << TriangleCase.new(row) + i += 1 + end + end + cases +end