Skip to content

Commit

Permalink
Enable equivalence and hash equality to Observer (#57)
Browse files Browse the repository at this point in the history
An observer can be seen as a value object. If all the characteristics of
an observer are equal to those of another, they can be considered as the
same.

This change implements `#==` (and its alias `#eql?`) and `#hash` to
implement value object behaviours.
  • Loading branch information
rhannequin authored Apr 11, 2024
1 parent 483cd35 commit c2869ad
Show file tree
Hide file tree
Showing 2 changed files with 111 additions and 8 deletions.
35 changes: 27 additions & 8 deletions lib/astronoby/observer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ class Observer
MOLAR_MASS_OF_AIR = 0.0289644
UNIVERSAL_GAS_CONSTANT = 8.31432

attr_reader :latitude, :longitude, :elevation, :temperature
attr_reader :latitude, :longitude, :elevation, :temperature, :pressure

# @param latitude [Angle] geographic latitude of the observer
# @param longitude [Angle] geographic longitude of the observer
Expand All @@ -31,19 +31,38 @@ def initialize(
@longitude = longitude
@elevation = elevation
@temperature = temperature
@pressure = pressure
@pressure = pressure || compute_pressure
end

# Compute an estimation of the atmospheric pressure based on the elevation
# and temperature
#
# @return [Float] the atmospheric pressure in millibars.
def pressure
@pressure ||= PRESSURE_AT_SEA_LEVEL * pressure_ratio
def ==(other)
return false unless other.is_a?(self.class)

@latitude == other.latitude &&
@longitude == other.longitude &&
@elevation == other.elevation &&
@temperature == other.temperature &&
@pressure == other.pressure
end
alias_method :eql?, :==

def hash
[
self.class,
@latitude,
@longitude,
@elevation,
@temperature,
@pressure
].hash
end

private

# @return [Float] the atmospheric pressure in millibars.
def compute_pressure
@pressure ||= PRESSURE_AT_SEA_LEVEL * pressure_ratio
end

# Source:
# Barometric formula
# https://en.wikipedia.org/wiki/Barometric_formula
Expand Down
84 changes: 84 additions & 0 deletions spec/astronoby/observer_spec.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,90 @@
# frozen_string_literal: true

require "set" # rubocop:disable Lint/RedundantRequireStatement

RSpec.describe Astronoby::Observer do
describe "equivalence (#==)" do
it "returns true when the observers are equivalent" do
observer1 = described_class.new(
latitude: Astronoby::Angle.from_degrees(45),
longitude: Astronoby::Angle.from_degrees(90),
elevation: 100,
temperature: 280,
pressure: 10
)
observer2 = described_class.new(
latitude: Astronoby::Angle.from_degrees(45),
longitude: Astronoby::Angle.from_degrees(90),
elevation: 100,
temperature: 280,
pressure: 10
)

expect(observer1).to eq observer2
end

it "returns true when the observers are not equivalent" do
observer1 = described_class.new(
latitude: Astronoby::Angle.from_degrees(45),
longitude: Astronoby::Angle.from_degrees(90),
elevation: 100,
temperature: 280,
pressure: 10
)
observer2 = described_class.new(
latitude: Astronoby::Angle.from_degrees(45),
longitude: Astronoby::Angle.from_degrees(90),
elevation: 100,
temperature: 280,
pressure: 15
)

expect(observer1).not_to eq observer2
end
end

describe "hash equality" do
it "makes an angle foundable as a Hash key" do
observer1 = described_class.new(
latitude: Astronoby::Angle.from_degrees(45),
longitude: Astronoby::Angle.from_degrees(90),
elevation: 100,
temperature: 280,
pressure: 10
)
observer2 = described_class.new(
latitude: Astronoby::Angle.from_degrees(45),
longitude: Astronoby::Angle.from_degrees(90),
elevation: 100,
temperature: 280,
pressure: 10
)
map = {observer1 => :observer}

expect(map[observer2]).to eq :observer
end

it "makes an angle foundable in a Set" do
observer1 = described_class.new(
latitude: Astronoby::Angle.from_degrees(45),
longitude: Astronoby::Angle.from_degrees(90),
elevation: 100,
temperature: 280,
pressure: 10
)
observer2 = described_class.new(
latitude: Astronoby::Angle.from_degrees(45),
longitude: Astronoby::Angle.from_degrees(90),
elevation: 100,
temperature: 280,
pressure: 10
)
set = Set.new([observer1])

expect(set.include?(observer2)).to be true
end
end

describe "#pressure" do
it "returns the computed pression in millibars" do
latitude = Astronoby::Angle.from_degrees(0)
Expand Down

0 comments on commit c2869ad

Please sign in to comment.