Skip to content

Commit

Permalink
Merge pull request #68 from shivam091/5.15.0
Browse files Browse the repository at this point in the history
5.15.0
  • Loading branch information
shivam091 authored Nov 29, 2023
2 parents 12e56f5 + 6bf1009 commit 41c1618
Show file tree
Hide file tree
Showing 10 changed files with 210 additions and 44 deletions.
10 changes: 9 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,16 @@
## [5.15.0](https://github.com/shivam091/unit_measurements/compare/v5.14.0...v5.15.0) - 2023-12-01

### What's new

- Added `.define_conversion_methods` method to define conversion helper methods for units.

----------

## [5.14.0](https://github.com/shivam091/unit_measurements/compare/v5.13.0...v5.14.0) - 2023-11-29

### What's new

- Added `.define_numeric_methods` support to define numeric extension methods for units.
- Added `.define_numeric_methods` method to define numeric extension methods for units.

----------

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 (5.14.0)
unit_measurements (5.15.0)
activesupport (~> 7.0)

GEM
Expand Down
62 changes: 43 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,12 @@ Users are advised to cross-verify conversions for their specific use cases._

## Minimum Requirements

* Ruby 3.2.2+ (https://www.ruby-lang.org/en/downloads/branches/)
* Ruby 3.2.2+ ([Download Ruby](https://www.ruby-lang.org/en/downloads/branches/))

## Installation

If using bundler, first add this line to your application's Gemfile:
To use `unit_measurements` in your Rails application, add the
following line to your Gemfile:

```ruby
gem "unit_measurements"
Expand Down Expand Up @@ -269,8 +270,7 @@ UnitMeasurements::Length.units_for("metric")
**Finding units within the unit group:**

You can use `#unit_for` or `#unit_for!` (aliased as `#[]`) methods to find units
within the unit group. `#unit_for!` method returns an error if a unit is not present
in the unit group.
within the unit group. `#unit_for!` method returns an error if a unit system is not defined within the unit group.

```ruby
UnitMeasurements::Length.unit_for("m")
Expand Down Expand Up @@ -484,13 +484,12 @@ Volume = UnitMeasurements::Volume

## Extras

### Numeric extension methods
### Numeric methods

The `.define_numeric_methods` method allows you to instantiate measurements in a
manner similar to how `ActiveSupport::Duration` objects are created in Rails,
providing a familiar syntax and functionality.
The `.define_numeric_methods` method allows you to define numeric methods that help you to initialize measurements in a
manner similar to how `ActiveSupport::Duration` objects are created in Rails, providing a familiar syntax and functionality.

To define numeric extension methods for specific units within a unit group, use
To define numeric methods for specific units within the unit group, use
the following syntax:

```ruby
Expand All @@ -500,21 +499,46 @@ UnitMeasurements::Length.define_numeric_methods("metre", "foot", "inch")
This will enable the usage of these units as methods to instantiate and use measurements:

```ruby
1.m #=> Instantiate a measurement representing 1 metre.
5.feet #=> Instantiate a measurement representing 5 feet.
10.inches #=> Instantiate a measurement representing 10 inches.
1.foot == 12.inches #=> equality comparison between two measurements.
1.ft + 12.in #=> adds quantity of two measurements.
# Initialize a measurement
1.m #=> 1 m
5.feet #=> 5 ft
10.inches #=> 10 in

# Usage
## Equality comparison
1.foot == 12.inches #=> true
## Arithmetic operation
1.ft + 12.in #=> 2.0 ft
```

### Conversion methods

The `.define_conversion_methods` method allows you to define conversion methods that
help you to easily convert measurements to a different unit.

To define conversion methods for specific units within the unit group, use the following syntax:

```ruby
UnitMeasurements::Length.define_conversion_methods("metre", "foot", "inch")
```

This will enable you to convert units as:

```ruby
UnitMeasurements::Length.new(1, "ft").in_inches #=> 12.0 in
12.in.in_foot #=> 1.0 ft
```

## Contributing

1. Fork it
2. Create your feature branch (`git checkout -b my-new-feature`)
Contributions to this project are welcomed! To contribute:

1. Fork this repository
2. Create a new branch (`git checkout -b my-new-feature`)
3. Commit your changes (`git commit -am "Add some feature"`)
4. Push to the branch (`git push origin my-new-feature`)
5. Create new Pull Request
4. Push the changes to your branch (`git push origin my-new-feature`)
5. Create new **Pull Request**

## License

Copyright 2023 [Harshal V. LADHE]((https://shivam091.github.io)), Released under the [MIT License](http://opensource.org/licenses/MIT).
Copyright 2023 [Harshal V. LADHE](https://shivam091.github.io), Released under the [MIT License](http://opensource.org/licenses/MIT).
1 change: 1 addition & 0 deletions lib/unit_measurements/base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@ def configure

# The following requires load various components of the unit measurements library.
require "unit_measurements/extras/numeric_methods"
require "unit_measurements/extras/conversion_methods"

require "unit_measurements/configuration"
require "unit_measurements/cache"
Expand Down
87 changes: 87 additions & 0 deletions lib/unit_measurements/extras/conversion_methods.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
# -*- encoding: utf-8 -*-
# -*- frozen_string_literal: true -*-
# -*- warn_indent: true -*-

module UnitMeasurements
# This module provides functionality to define conversion methods for a list
# of units within a unit group. If units are empty, it defaults to defining
# methods for all units in the unit group. These methods allow easy conversion
# between different units within a given unit group.
#
# This module is included in the +Measurement+ class to allow defining conversion
# methods for specified units.
#
# @see Measurement
#
# @author {Harshal V. Ladhe}[https://shivam091.github.io/]
# @since 5.15.0
module ConversionMethods
# @scope class
# Defines conversion methods for specified +units+ within the unit group.
# If +units+ are empty, it defaults to defining methods for all units within
# the unit group.
#
# @example Define conversion methods for metres, centimetres, and millimetres:
# UnitMeasurements::Length.define_conversion_methods("metres", :cm, :mm)
#
# @example Define conversion methods for all units within the unit group:
# UnitMeasurements::Length.define_conversion_methods
#
# @param [Array<String|Symbol>, optional] units
# An array of units' names for which conversion methods need to be defined.
# If empty, methods will be defined for all units within the unit group.
#
# @return [Array<Unit>]
# An array of units for which the conversion methods were defined.
#
# @note
# This method defines a conversion methods specifically for units that contain
# alphabetic characters in their names.
#
# @see .define_conversion_method_for
# @author {Harshal V. Ladhe}[https://shivam091.github.io/]
# @since 5.15.0
def define_conversion_methods(*units)
unit_group = self
units = units.empty? ? unit_group.units : units

units.inject([]) do |units, unit|
units << define_conversion_method_for(unit, unit_group)
end
end

private

# @private
# @scope class
# Defines conversion methods for a specific +unit+ within a +unit_group+.
# These methods are defined dynamically using +define_method+.
#
# @param [String|Symbol|Unit] unit
# The unit (or its name) for which the conversion methods need to be defined.
# @param [UnitGroup] unit_group The unit group to which the unit belongs.
#
# @return [Unit]
# The unit instance for which the conversion methods were defined.
#
# @see .define_conversion_methods
# @author {Harshal V. Ladhe}[https://shivam091.github.io/]
# @since 5.15.0
def define_conversion_method_for(unit, unit_group)
unit = unit.is_a?(Unit) ? unit : unit_group.unit_for!(unit)

unit.names.each do |method_name|
# Check if the name contains alphabetic characters
next unless method_name =~ /^[a-zA-Z]+$/

define_method("in_#{method_name}") do |use_cache: false|
convert_to(unit, use_cache: use_cache)
end
alias_method "to_#{method_name}", "in_#{method_name}"
alias_method "as_#{method_name}", "in_#{method_name}"
end

unit
end
end
end
44 changes: 24 additions & 20 deletions lib/unit_measurements/extras/numeric_methods.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,36 +3,40 @@
# -*- warn_indent: true -*-

module UnitMeasurements
# This module provides methods to define +Numeric+ extension methods for a list
# of units within a unit group. If units are empty, it defaults to defining
# methods for all units in the unit group.
# This module provides methods to define +Numeric+ methods for a list of units
# within a unit group. If units are empty, it defaults to defining methods for
# all units in the unit group.
#
# This module is included in the +Measurement+ class to allow defining numeric
# extension methods for specified units.
# methods for specified units.
#
# @see Measurement
#
# @author {Harshal V. Ladhe}[https://shivam091.github.io/]
# @since 5.14.0
module NumericMethods
# @scope class
# Defines +Numeric+ extension methods for specified units within the unit
# group. If units are empty, it defaults to defining methods for all units
# within the unit group.
#
# @param [Array<String|Symbol>] units
# An array of units' names for which numeric methods need to be defined.
# If empty, methods will be defined for all units in the unit group.
#
# @return [Array<Unit>] An array of units for which methods are defined.
# Defines +Numeric+ methods for specified +units+ within the unit group. If
# +units+ are empty, it defaults to defining methods for all units within
# the unit group.
#
# @example Define numeric methods for metres, centimetres, and millimetres:
# UnitMeasurements::Length.define_numeric_methods("metres", :cm, :mm)
#
# @example Define numeric methods for all units in the unit group:
# @example Define numeric methods for all units within the unit group:
# UnitMeasurements::Length.define_numeric_methods
#
# @see #define_numeric_method_for
# @param [Array<String|Symbol>, optional] units
# An array of units' names for which numeric methods need to be defined.
# If empty, methods will be defined for all units within the unit group.
#
# @return [Array<Unit>] An array of units for which numeric methods were defined.
#
# @note
# This method defines a numeric methods specifically for units that contain
# alphabetic characters in their names.
#
# @see .define_numeric_method_for
#
# @author {Harshal V. Ladhe}[https://shivam091.github.io/]
# @since 5.14.0
Expand All @@ -49,17 +53,17 @@ def define_numeric_methods(*units)

# @private
# @scope class
# This method defines a numeric method for a specific unit within a unit group.
# The method is defined dynamically using +define_method+ and associates the
# unit with the numeric value.
# Defines a numeric method for a specific +unit+ within a +unit_group+. The
# method is defined dynamically using +define_method+ and associates the unit
# with the numeric value.
#
# @param [String|Symbol|Unit] unit
# The unit for which the numeric method is defined.
# The unit (or its name) for which the numeric method needs to be defined.
# @param [UnitGroup] unit_group The unit group to which the unit belongs.
#
# @return [Unit] The unit instance for which the method was defined.
#
# @see #define_numeric_methods
# @see .define_numeric_methods
#
# @author {Harshal V. Ladhe}[https://shivam091.github.io/]
# @since 5.14.0
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 @@ -34,6 +34,7 @@ class Measurement
include Math

extend NumericMethods
extend ConversionMethods

# Regular expression to match conversion strings.
#
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 @@ -4,5 +4,5 @@

module UnitMeasurements
# Current stable version.
VERSION = "5.14.0"
VERSION = "5.15.0"
end
41 changes: 41 additions & 0 deletions spec/unit_measurements/extras/conversion_methods_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# -*- encoding: utf-8 -*-
# -*- frozen_string_literal: true -*-
# -*- warn_indent: true -*-

# spec/unit_measurements/extras/conversion_methods_spec.rb

RSpec.describe UnitMeasurements::ConversionMethods do
let(:unit_group) { UnitMeasurements::Length }
let(:measurement) { unit_group.new(1, "ft") }

context "when units are specified" do
it "defines methods for specified units" do
unit_group.define_conversion_methods("m", "cm")

expect(unit_group.method_defined?("to_m")).to be_truthy
expect(unit_group.method_defined?("to_cm")).to be_truthy

expect(measurement).to respond_to(:to_m)
expect(measurement).to respond_to(:in_m)
expect(measurement).to respond_to(:as_m)

expect(measurement.to_m.to_s).to eq("0.3048 m")
end
end

context "when units are specified" do

it "defines methods for all units within the unit group" do
unit_group.define_conversion_methods

expect(unit_group.method_defined?("to_ft")).to be_truthy
expect(unit_group.method_defined?("to_in")).to be_truthy

expect(measurement).to respond_to(:to_in)
expect(measurement).to respond_to(:to_inch)
expect(measurement).to respond_to(:to_inches)

expect(measurement.to_in.to_s).to eq("12.0 in")
end
end
end
4 changes: 2 additions & 2 deletions spec/unit_measurements/extras/numeric_methods_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
let(:cm) { unit_group.unit_for!(:cm) }

context "when units are specified" do
it "defines extension methods for specified units" do
it "defines methods for specified units" do
unit_group.define_numeric_methods("m", "cm")

expect(Numeric.method_defined?("m")).to be_truthy
Expand All @@ -21,7 +21,7 @@
end

context "when units are specified" do
it "defines extension methods for all units within the unit group" do
it "defines methods for all units within the unit group" do
unit_group.define_numeric_methods

expect(Numeric.method_defined?("ft")).to be_truthy
Expand Down

0 comments on commit 41c1618

Please sign in to comment.