Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion exercises/practice/perfect-numbers/.meta/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@
"iHiD",
"Insti",
"kotp",
"tryantwit"
"tryantwit",
"themetar"
],
"files": {
"solution": [
Expand Down
35 changes: 18 additions & 17 deletions exercises/practice/perfect-numbers/.meta/example.rb
Original file line number Diff line number Diff line change
@@ -1,24 +1,25 @@
class PerfectNumber
def self.classify(num)
raise 'not a natural number' if num < 0
aliquot_sum = aliquot_sum(num)
aliquot_sum == num ? "perfect" : aliquot_sum < num ? "deficient" : 'abundant'
end
module PerfectNumber
def self.classify(number)
raise ArgumentError, 'Classification is only possible for positive integers.' unless number > 0

aliquot_sum = get_divisors(number).sum

def self.aliquot_sum(num)
get_divisors(num).reduce(:+)
if aliquot_sum == number
"perfect"
else
aliquot_sum < number ? "deficient" : 'abundant'
end
end

private
def self.get_divisors(number)
return [] if number == 1

(2..Math.sqrt(number)).each_with_object [1] do |n, divisors|
div, mod = number.divmod n
next unless mod.zero?

def self.get_divisors(num)
divisors = [0]
(1..Math.sqrt(num)).each do |n|
if num % n == 0
divisors << n
divisors << num/n unless (n == 1) || (num/n) == n
end
divisors << n
divisors << div unless div == n
end
divisors
end
end
18 changes: 18 additions & 0 deletions exercises/practice/perfect-numbers/.meta/test_template.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
require 'minitest/autorun'
require_relative 'perfect_numbers'

class PerfectNumberTest < Minitest::Test
<% json["cases"].each do |group| %>
<% group["cases"].each do |sub_case| %>
def test_<%= underscore(sub_case["description"]) %>
<%= skip? %>
<%- if sub_case["expected"].is_a?(Hash) && sub_case["expected"].key?("error") -%>
error = assert_raises(ArgumentError) { PerfectNumber.<%= underscore(sub_case["property"]) %>(<%= sub_case["input"]["number"] %>) }
assert_equal '<%= sub_case["expected"]["error"] %>', error.message
<%- else -%>
assert_equal '<%= sub_case["expected"] %>', PerfectNumber.<%= underscore(sub_case["property"]) %>(<%= sub_case["input"]["number"] %>)
<%- end -%>
end
<% end %>
<% end %>
end
67 changes: 58 additions & 9 deletions exercises/practice/perfect-numbers/perfect_numbers_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,70 @@
require_relative 'perfect_numbers'

class PerfectNumberTest < Minitest::Test
def test_initialize_perfect_number
assert_raises RuntimeError do
PerfectNumber.classify(-1)
end
def test_smallest_perfect_number_is_classified_correctly
# skip
assert_equal 'perfect', PerfectNumber.classify(6)
end

def test_classify_deficient
assert_equal 'deficient', PerfectNumber.classify(13)
def test_medium_perfect_number_is_classified_correctly
skip
assert_equal 'perfect', PerfectNumber.classify(28)
end

def test_classify_perfect
assert_equal 'perfect', PerfectNumber.classify(28)
def test_large_perfect_number_is_classified_correctly
skip
assert_equal 'perfect', PerfectNumber.classify(33_550_336)
end

def test_classify_abundant
def test_smallest_abundant_number_is_classified_correctly
skip
assert_equal 'abundant', PerfectNumber.classify(12)
end

def test_medium_abundant_number_is_classified_correctly
skip
assert_equal 'abundant', PerfectNumber.classify(30)
end

def test_large_abundant_number_is_classified_correctly
skip
assert_equal 'abundant', PerfectNumber.classify(33_550_335)
end

def test_smallest_prime_deficient_number_is_classified_correctly
skip
assert_equal 'deficient', PerfectNumber.classify(2)
end

def test_smallest_non_prime_deficient_number_is_classified_correctly
skip
assert_equal 'deficient', PerfectNumber.classify(4)
end

def test_medium_deficient_number_is_classified_correctly
skip
assert_equal 'deficient', PerfectNumber.classify(32)
end

def test_large_deficient_number_is_classified_correctly
skip
assert_equal 'deficient', PerfectNumber.classify(33_550_337)
end

def test_edge_case_no_factors_other_than_itself_is_classified_correctly
skip
assert_equal 'deficient', PerfectNumber.classify(1)
end

def test_zero_is_rejected_as_it_is_not_a_positive_integer
skip
error = assert_raises(ArgumentError) { PerfectNumber.classify(0) }
assert_equal 'Classification is only possible for positive integers.', error.message
end

def test_negative_integer_is_rejected_as_it_is_not_a_positive_integer
skip
error = assert_raises(ArgumentError) { PerfectNumber.classify(-1) }
assert_equal 'Classification is only possible for positive integers.', error.message
end
end