Skip to content

Commit

Permalink
Merge pull request #5 from shivam091/1.4.0
Browse files Browse the repository at this point in the history
1.4.0
  • Loading branch information
shivam091 authored Sep 17, 2023
2 parents 480a3ab + 438f8ff commit 2c21af5
Show file tree
Hide file tree
Showing 9 changed files with 218 additions and 4 deletions.
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
## [1.4.0](https://github.com/shivam091/unit_measurements/compare/v1.3.0...v1.4.0) - 2023-08-17

### What's new

- Added ability to perform `arithmetic` operations of measurements.

----------

## [1.3.0](https://github.com/shivam091/unit_measurements/compare/v1.2.0...v1.3.0) - 2023-08-16

### What's new
Expand Down
2 changes: 1 addition & 1 deletion Gemfile.lock
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
PATH
remote: .
specs:
unit_measurements (1.3.0)
unit_measurements (1.4.0)
activesupport (~> 7.0)

GEM
Expand Down
23 changes: 23 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,29 @@ UnitMeasurements::Weight.parse("1 kg") >= UnitMeasurements::Weight.parse("0.5 kg
#=> true
```

### Arithmetic

You have the ability to perform arithmetic operations on measurements with the same or
different units within the same unit group. You can perform arithmetic operations on
measurement by either other compatible measurement or number.

**Methods:**
1. `#+` - Adds the other measurement quantity or number to the measurement.
2. `#-` - Subtracts the other measurement quantity or number from the measurement.
3. `#*` - Multiplies the measurement quantity by other measurement quantity or number.
4. `#/` - Divides the measurement quantity by other measurement quantity or number.

```ruby
UnitMeasurements::Weight.new(1, :kg) + UnitMeasurements::Weight.new(1, :g)
#=> 1.001 kg
UnitMeasurements::Weight.new(2, :kg) - 1
#=> 1 kg
UnitMeasurements::Weight.new(2, :kg) * 2
#=> 4 kg
UnitMeasurements::Weight.new(4, :kg) / UnitMeasurements::Weight.new(2, :kg)
#=> 2 kg
```

## Units

The **`UnitMeasurements::Unit`** class is used to represent the units for a measurement.
Expand Down
74 changes: 74 additions & 0 deletions lib/unit_measurements/arithmetic.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# -*- encoding: utf-8 -*-
# -*- frozen_string_literal: true -*-
# -*- warn_indent: true -*-

module UnitMeasurements
module Arithmetic
# Adds the other measurement quantity or number to the measurement.
#
# @param [Numeric or Measurement] other
#
# @example
# UnitMeasurements::Weight.new(1, :kg) + UnitMeasurements::Weight.new(1, :g)
# => 1.001 kg
#
# @return [Measurement]
def +(other)
arithmetic_operation(other, :+)
end

# Subtracts the other measurement quantity or number from the measurement.
#
# @param [Numeric or Measurement] other
#
# @example
# UnitMeasurements::Weight.new(2, :kg) - 1
# => 1 kg
#
# @return [Measurement]
def -(other)
arithmetic_operation(other, :-)
end

# Multiplies the measurement quantity by other measurement quantity or number.
#
# @param [Numeric or Measurement] other
#
# @example
# UnitMeasurements::Weight.new(2, :kg) * 2
# => 4 kg
#
# @return [Measurement]
def *(other)
arithmetic_operation(other, :*)
end

# Divides the measurement quantity by other measurement quantity or number.
#
# @param [Numeric or Measurement] other
#
# @example
# UnitMeasurements::Weight.new(4, :kg) / UnitMeasurements::Weight.new(2, :kg)
# => 2 kg
#
# @return [Measurement]
def /(other)
arithmetic_operation(other, :/)
end

private

def coerce(other)
case other
when Numeric then [self.class.new(other, self.unit), self]
when self.class then [other, self]
else raise TypeError, "Cannot coerce #{other.class} to #{self.class}"
end
end

def arithmetic_operation(other, operator)
other, _ = coerce(other)
self.class.new(self.quantity.public_send(operator, other.convert_to(self.unit).quantity), self.unit)
end
end
end
3 changes: 2 additions & 1 deletion lib/unit_measurements/base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,11 @@ class << self
require "unit_measurements/unit_group_builder"
require "unit_measurements/unit"
require "unit_measurements/unit_group"
require "unit_measurements/arithmetic"
require "unit_measurements/comparison"
require "unit_measurements/normalizer"
require "unit_measurements/parser"
require "unit_measurements/formatter"
require "unit_measurements/comparison"
require "unit_measurements/measurement"

require "unit_measurements/errors/unit_error"
Expand Down
1 change: 1 addition & 0 deletions lib/unit_measurements/measurement.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ module UnitMeasurements
class Measurement
include Formatter
include Comparison
include Arithmetic

CONVERSION_STRING_REGEXP = /(.+?)\s?(?:\s+(?:in|to|as)\s+(.+)|\z)/i.freeze

Expand Down
2 changes: 1 addition & 1 deletion lib/unit_measurements/version.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@
# -*- warn_indent: true -*-

module UnitMeasurements
VERSION = "1.3.0"
VERSION = "1.4.0"
end
107 changes: 107 additions & 0 deletions spec/unit_measurements/arithmetic_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
# -*- encoding: utf-8 -*-
# -*- frozen_string_literal: true -*-
# -*- warn_indent: true -*-

# spec/unit_measurements/arithmetic_spec.rb

RSpec.describe UnitMeasurements::Arithmetic do
subject { UnitMeasurements::Length }
let(:m) { subject.unit_for!(:m) }
let(:cm) { subject.unit_for!(:cm) }

describe "#+" do
it "must add numbers" do
measurement = subject.new(3.5, :m) + 2
expect(measurement.quantity).to eq(5.5)
expect(measurement.unit).to eq(m)
end

it "must add similar units" do
measurement = (subject.new(3.5, :m) + subject.new(2, :m))
expect(measurement.quantity).to eq(5.5)
expect(measurement.unit).to eq(m)
end

it "must add unsimilar units" do
measurement = (subject.new(3.5, :cm) + subject.new(2, :m))
expect(measurement.quantity).to eq(203.5)
expect(measurement.unit).to eq(cm)
end
end

describe "#-" do
it "must subtract numbers" do
measurement = (subject.new(3.5, :m) - 2)
expect(measurement.quantity).to eq(1.5)
expect(measurement.unit).to eq(m)
end

it "must subtract unsimilar units" do
measurement = (subject.new(3.5, :m) - subject.new(2, :m))
expect(measurement.quantity).to eq(1.5)
expect(measurement.unit).to eq(m)
end

it "must subtract similar units" do
measurement = (subject.new(3.5, :m) - subject.new(2, :cm))
expect(measurement.quantity).to eq(3.48)
expect(measurement.unit).to eq(m)
end
end

describe "#*" do
it "must multiply by numbers" do
measurement = (subject.new(3.5, :m) * 2)
expect(measurement.quantity).to eq(7)
expect(measurement.unit).to eq(m)
end

it "must multiply by similar units" do
measurement = (subject.new(3.5, :m) * subject.new(2, :m))
expect(measurement.quantity).to eq(7)
expect(measurement.unit).to eq(m)
end

it "must multiply by unsimilar units" do
measurement = (subject.new(3.5, :m) * subject.new(2, :cm))
expect(measurement.quantity).to eq(0.07)
expect(measurement.unit).to eq(m)
end
end

describe "#/" do
it "must divide by numbers" do
measurement = (subject.new(4, :m) / 2)
expect(measurement.quantity).to eq(2)
expect(measurement.unit).to eq(m)
end

it "must divide by similar units" do
measurement = (subject.new(4, :m) / subject.new(2, :m))
expect(measurement.quantity).to eq(2)
expect(measurement.unit).to eq(m)
end

it "must divide by unsimilar units" do
measurement = (subject.new(36, :cm) / subject.new(2, :m))
expect(measurement.quantity).to eq(0.18)
expect(measurement.unit).to eq(cm)
end
end

describe "#coerce" do
let(:meter) { subject.new(1, :m) }

it "must coerce numbers" do
expect((meter * 5).quantity).to eq(5)
end

it "must coerce measurements" do
expect((meter * subject.new(1, :cm)).quantity).to eq(0.01)
end

it "should raise an error for other than numbers and measurement instance" do
expect { meter * "foo" }.to raise_error(TypeError)
end
end
end
2 changes: 1 addition & 1 deletion spec/unit_measurements_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@

RSpec.describe UnitMeasurements do
it "has a valid version number" do
expect(UnitMeasurements::VERSION).to eq("1.3.0")
expect(UnitMeasurements::VERSION).to eq("1.4.0")
end
end

0 comments on commit 2c21af5

Please sign in to comment.