Skip to content

Instantly share code, notes, and snippets.

@josh-works
Last active February 10, 2021 18:07
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save josh-works/6eb437670b66a67675c23352c787e66d to your computer and use it in GitHub Desktop.
Save josh-works/6eb437670b66a67675c23352c787e66d to your computer and use it in GitHub Desktop.
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/, based on https://josh.works/primative-obsession-and-exceptional-values
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