Instantly share code, notes, and snippets.

Embed
What would you like to do?
test, and the code that makes the test pass, to understand whole values and exceptional values, from Avdi Grim's https://avdi.codes/courses/moom/
class Object
def exceptional?
false
end
end
Course = Struct.new(:name, :duration) do
def duration=(new_duration)
self[:duration] = Duration(new_duration)
end
end
class Duration
def self.[](magnitude)
new(magnitude)
end
attr_reader :magnitude
def initialize(magnitude)
@magnitude = magnitude
freeze
end
def to_s
"#{self.magnitude} #{self.class.name.downcase}"
end
def inspect
"#{self.class}[#{self.magnitude}]"
end
alias_method :to_i, :magnitude
end
class Days < Duration; end
class Weeks < Duration; end
class Months < Duration; end
class ExceptionalValue
attr_reader :raw_value, :reason
def initialize(raw_value, reason: "Unspecified")
@raw_value = raw_value
@reason = reason
end
def exceptional?
true
end
def to_s
@raw_value.to_s
end
end
# helper methods
def render_course_info(course)
"#{course.name} (#{render_value(course.duration)})"
end
def render_value(value)
case value
when Months
"#{value.to_i} gruling months"
when Weeks
"#{value.to_i} delightful weeks"
when Days
"a paultry #{value.to_i} days"
end
end
# in the video, this method was capitalized, I don't know why but I imagine
# it was for a good reason
def Duration(raw_value)
case raw_value
when Duration
raw_value
when /\A(\d+)\s+months\z/i
Months[$1.to_i]
when /\A(\d+)\s+weeks\z/i
Weeks[$1.to_i]
when /\A(\d+)\s+days\z/i
Days[$1.to_i]
else
ExceptionalValue.new(raw_value, reason: "unrecognized format")
end
end
require_relative './exceptional_values'
gem 'minitest'
require 'minitest/autorun'
class DurationTest < MiniTest::Test
def setup
@math = Course.new("Math", Months[4])
@grammar = Course.new("Grammar", Days[50])
@skrying = Course.new("Skrying", Weeks[7])
end
def test_create_new_duration
assert @math
assert_equal "Math", @math.name
end
def test_duration_has_magnitude
assert_equal 4, @math.duration.magnitude
end
def test_duration_is_months_object
assert_instance_of Months, @math.duration
end
def test_duration_formatting_is_not_string
refute_equal String, @math.duration.class
end
def test_duration_to_i_is_aliased_to_magnitude
assert_equal 4, @math.duration.to_i
end
def test_duration_to_string
assert_equal "4 months", @math.duration.to_s
end
def test_duration_inspect
assert_equal "Months[4]", @math.duration.inspect
end
def test_duration_can_change
@math.duration = Weeks[3]
assert_instance_of Weeks, @math.duration
end
def test_duration_can_be_denominated_in_days
assert_instance_of Days, @grammar.duration
assert_equal 50, @grammar.duration.magnitude
end
def test_duration_can_be_denominated_in_weeks
assert_instance_of Weeks, @skrying.duration
assert_equal 7, @skrying.duration.magnitude
end
def test_duration_can_be_denominated_in_months
potions = Course.new("Potions", Months[3])
assert_instance_of Months, potions.duration
assert_equal 3, potions.duration.magnitude
end
# test helper methods
def test_render_months_class
results = render_value(@math.duration)
assert_equal "4 gruling months", results
end
def test_render_weeks_class
results = render_value(@skrying.duration)
assert_equal "7 delightful weeks", results
end
def test_render_days_class
results = render_value(@grammar.duration)
assert_equal "a paultry 50 days", results
end
def test_render_course_info_returns_nicely_formatted_strings
assert_equal "Math (4 gruling months)", render_course_info(@math)
assert_equal "Grammar (a paultry 50 days)", render_course_info(@grammar)
assert_equal "Skrying (7 delightful weeks)", render_course_info(@skrying)
end
def test_freeze_magnitude_in_initialize
skip
# not sure what I can assert to make sure value is frozen
# https://blog.honeybadger.io/when-to-use-freeze-and-frozen-in-ruby/
end
# testing exceptional values
def test_Duration_converts_months_string_to_duration_object
math = Course.new("Math")
math.duration = "4 months"
assert_equal Months, math.duration.class
assert_equal 4, math.duration.magnitude
end
def test_Duration_convert_weeks_string_to_duration_object
math = Course.new("Math")
math.duration = "7 days"
assert_equal Days, math.duration.class
assert_equal 7, math.duration.magnitude
end
def test_convert_weeks_string_to_duration
math = Course.new("Math")
math.duration = "3 weeks"
assert_instance_of Weeks, math.duration
assert_equal 3, math.duration.magnitude
end
def test_exceptional_values
math = Course.new("Math")
math.duration = "a blink of an eye"
assert_instance_of ExceptionalValue, math.duration
assert_equal "a blink of an eye", math.duration.to_s
end
def test_exceptional_values_know_they_are_exceptional
math = Course.new("Math")
math.duration = "a blink of an eye"
assert math.duration.exceptional?
refute math.name.exceptional?
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment