Skip to content

Commit

Permalink
Refactoring (#26)
Browse files Browse the repository at this point in the history
  • Loading branch information
marian13 committed Mar 5, 2020
1 parent 38758b4 commit d2a607c
Show file tree
Hide file tree
Showing 5 changed files with 230 additions and 162 deletions.
6 changes: 6 additions & 0 deletions .rubocop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,11 @@ AllCops:
Layout/LineLength:
Max: 110

Metrics/MethodLength:
Max: 15

Style/Lambda:
EnforcedStyle: literal

Style/RedundantSelf:
Enabled: No
2 changes: 1 addition & 1 deletion basic_temperature.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ Gem::Specification.new do |spec|
spec.add_development_dependency 'byebug', '~> 10.0'
spec.add_development_dependency 'coveralls'
spec.add_development_dependency 'rake', '~> 12.0'
spec.add_development_dependency 'reverse_coverage'
spec.add_development_dependency 'rspec', '~> 3.0'
spec.add_development_dependency 'rubocop', '~> 0.80.0'
spec.add_development_dependency 'simplecov'
spec.add_development_dependency 'reverse_coverage'
end
156 changes: 98 additions & 58 deletions lib/basic_temperature.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,7 @@ class BasicTemperature
class InitializationArgumentsError < StandardError; end
class InvalidDegreesError < StandardError; end
class InvalidScaleError < StandardError; end
class InvalidOtherError < StandardError; end
class CoersionError < StandardError; end
class InvalidNumericOrTemperatureError < StandardError; end

SCALES =
[
Expand All @@ -24,8 +23,7 @@ class CoersionError < StandardError; end
attr_reader :degrees, :scale

def initialize(*positional_arguments, **keyword_arguments)
raise_initialization_arguments_error if positional_arguments.any? && keyword_arguments.any?
raise_initialization_arguments_error if positional_arguments.none? && keyword_arguments.none?
assert_either_positional_arguments_or_keyword_arguments!(positional_arguments, keyword_arguments)

if keyword_arguments.any?
initialize_via_keywords_arguments(keyword_arguments)
Expand All @@ -47,85 +45,87 @@ def set_scale(scale)
# rubocop:enable Naming/AccessorMethodName

def to_scale(scale)
case cast_scale(scale)
casted_scale = cast_scale(scale)

assert_valid_scale!(casted_scale)

case casted_scale
when CELSIUS
to_celsius
when FAHRENHEIT
to_fahrenheit
when KELVIN
to_kelvin
else
raise_invalid_scale_error
end
end

def to_celsius
return @to_celsius unless @to_celsius.nil?

return @to_celsius = self if self.scale == CELSIUS

degrees =
case self.scale
when FAHRENHEIT
(self.degrees - 32) * (5 / 9r)
when KELVIN
self.degrees - 273.15
end

@to_celsius = BasicTemperature.new(degrees, CELSIUS)
memoized(:to_celsius) || memoize(:to_celsius, -> {
return self if self.scale == CELSIUS

degrees =
case self.scale
when FAHRENHEIT
(self.degrees - 32) * (5 / 9r)
when KELVIN
self.degrees - 273.15
end

BasicTemperature.new(degrees, CELSIUS)
})
end

def to_fahrenheit
return @to_fahrenheit unless @to_fahrenheit.nil?

return @to_fahrenheit = self if self.scale == FAHRENHEIT

degrees =
case self.scale
when CELSIUS
self.degrees * (9 / 5r) + 32
when KELVIN
self.degrees * (9 / 5r) - 459.67
end

@to_fahrenheit = BasicTemperature.new(degrees, FAHRENHEIT)
memoized(:to_fahrenheit) || memoize(:to_fahrenheit, -> {
return self if self.scale == FAHRENHEIT

degrees =
case self.scale
when CELSIUS
self.degrees * (9 / 5r) + 32
when KELVIN
self.degrees * (9 / 5r) - 459.67
end

BasicTemperature.new(degrees, FAHRENHEIT)
})
end

def to_kelvin
return @to_kelvin unless @to_kelvin.nil?

return @to_kelvin = self if self.scale == KELVIN

degrees =
case self.scale
when CELSIUS
self.degrees + 273.15
when FAHRENHEIT
(self.degrees + 459.67) * (5 / 9r)
end

@to_kelvin = BasicTemperature.new(degrees, KELVIN)
memoized(:to_kelvin) || memoize(:to_kelvin, -> {
return self if self.scale == KELVIN

degrees =
case self.scale
when CELSIUS
self.degrees + 273.15
when FAHRENHEIT
(self.degrees + 459.67) * (5 / 9r)
end

BasicTemperature.new(degrees, KELVIN)
})
end

def ==(other)
return false unless other.instance_of?(BasicTemperature)
return false unless assert_temperature(other)

if self.scale == other.scale
self.degrees == other.degrees
equal_degrees?(self.degrees, other.degrees)
else
self.to_scale(other.scale).degrees == other.degrees
equal_degrees?(self.to_scale(other.scale).degrees, other.degrees)
end
end

def +(other)
assert_numeric_or_temperature!(other)

degrees, scale =
case other
when Numeric
[self.degrees + other, self.scale]
when BasicTemperature
[self.to_scale(other.scale).degrees + other.degrees, other.scale]
else
raise_invalid_other_error(other)
end

BasicTemperature.new(degrees, scale)
Expand All @@ -150,13 +150,14 @@ def inspect
end

def <=>(other)
return unless other.instance_of?(BasicTemperature)
return unless assert_temperature(other)

self.to_scale(other.scale).degrees <=> other.degrees
compare_degrees(self.to_scale(other.scale).degrees, other.degrees)
end

private

# Initialization
def initialize_via_positional_arguments(positional_arguments)
degrees, scale = positional_arguments

Expand All @@ -179,10 +180,17 @@ def initialize_arguments(degrees, scale)
@scale = casted_scale
end

# Casting
def cast_scale(scale)
scale.to_s
end

# Assertions
def assert_either_positional_arguments_or_keyword_arguments!(positional_arguments, keyword_arguments)
raise_initialization_arguments_error if positional_arguments.any? && keyword_arguments.any?
raise_initialization_arguments_error if positional_arguments.none? && keyword_arguments.none?
end

def assert_valid_degrees!(degrees)
raise_invalid_degrees_error unless degrees.is_a?(Numeric)
end
Expand All @@ -194,13 +202,18 @@ def assert_valid_scale!(scale)
def assert_numeric_or_temperature!(numeric_or_temperature)
return if numeric_or_temperature.is_a?(Numeric) || numeric_or_temperature.instance_of?(BasicTemperature)

raise_coersion_error(numeric_or_temperature)
raise_invalid_numeric_or_temperature_error(numeric_or_temperature)
end

def assert_numeric!(numeric)
raise_invalid_numeric unless numeric.is_a?(Numeric)
end

def assert_temperature(temperature)
temperature.instance_of?(BasicTemperature)
end

# Raising errors
def raise_initialization_arguments_error
message =
'Positional and keyword arguments are mixed or ' \
Expand All @@ -221,12 +234,39 @@ def raise_invalid_scale_error
raise InvalidScaleError, message
end

def raise_invalid_other_error(other)
raise InvalidOtherError, "`#{other}` is neither Numeric nor Temperature."
def raise_invalid_numeric_or_temperature_error(numeric_or_temperature)
raise InvalidNumericOrTemperatureError, "`#{numeric_or_temperature}` is neither Numeric nor Temperature."
end

# Rounding
def equal_degrees?(first_degrees, second_degrees)
round_degrees(first_degrees) == round_degrees(second_degrees)
end

def round_degrees(degrees)
degrees.round(2)
end

def compare_degrees(first_degrees, second_degrees)
round_degrees(first_degrees) <=> round_degrees(second_degrees)
end

# Memoization
def memoized(key)
name = convert_to_variable_name(key)

return instance_variable_get(name) if instance_variable_defined?(name)
end

def memoize(key, proc)
name = convert_to_variable_name(key)
value = proc.call

instance_variable_set(name, value)
end

def raise_coersion_error(object)
raise CoersionError, "#{object} is neither Numeric nor Temperature."
def convert_to_variable_name(key)
"@#{key}"
end
end
# rubocop:enable Metrics/ClassLength
2 changes: 2 additions & 0 deletions lib/basic_temperature/temperature.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
# frozen_string_literal: true

require_relative '../basic_temperature'

Temperature = BasicTemperature
Loading

0 comments on commit d2a607c

Please sign in to comment.