Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

5.14.0 #67

Merged
merged 3 commits into from
Nov 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
## [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.

----------

## [5.13.0](https://github.com/shivam091/unit_measurements/compare/v5.12.0...v5.13.0) - 2023-11-27

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

GEM
Expand Down
25 changes: 25 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -482,6 +482,31 @@ Length = UnitMeasurements::Length
Volume = UnitMeasurements::Volume
```

## Extras

### Numeric extension 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.

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

```ruby
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.
```

## Contributing

1. Fork it
Expand Down
2 changes: 2 additions & 0 deletions lib/unit_measurements/base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,8 @@ def configure
end

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

require "unit_measurements/configuration"
require "unit_measurements/cache"
require "unit_measurements/unit_group_builder"
Expand Down
81 changes: 81 additions & 0 deletions lib/unit_measurements/extras/numeric_methods.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
# -*- encoding: utf-8 -*-
# -*- frozen_string_literal: true -*-
# -*- 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 is included in the +Measurement+ class to allow defining numeric
# extension 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.
#
# @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:
# UnitMeasurements::Length.define_numeric_methods
#
# @see #define_numeric_method_for
#
# @author {Harshal V. Ladhe}[https://shivam091.github.io/]
# @since 5.14.0
def define_numeric_methods(*units)
unit_group = self
units = units.empty? ? unit_group.units : units

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

private

# @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.
#
# @param [String|Symbol|Unit] unit
# The unit for which the numeric method is 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
#
# @author {Harshal V. Ladhe}[https://shivam091.github.io/]
# @since 5.14.0
def define_numeric_method_for(unit, unit_group)
shivam091 marked this conversation as resolved.
Show resolved Hide resolved
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]+$/

Numeric.define_method(method_name) do
unit_group.new(self, unit)
end
end

unit
end
end
end
3 changes: 3 additions & 0 deletions lib/unit_measurements/measurement.rb
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ module UnitMeasurements
# @see Conversion
# @see Formatter
# @see Math
# @see NumericMethods
# @author {Harshal V. Ladhe}[https://shivam091.github.io/]
# @since 1.0.0
class Measurement
Expand All @@ -32,6 +33,8 @@ class Measurement
include Formatter
include Math

extend NumericMethods

# Regular expression to match conversion strings.
#
# @author {Harshal V. Ladhe}[https://shivam091.github.io/]
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.13.0"
VERSION = "5.14.0"
end
33 changes: 33 additions & 0 deletions spec/unit_measurements/extras/numeric_methods_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# -*- encoding: utf-8 -*-
# -*- frozen_string_literal: true -*-
# -*- warn_indent: true -*-

# spec/unit_measurements/extras/numeric_methods_spec.rb

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

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

expect(Numeric.method_defined?("m")).to be_truthy
expect(Numeric.method_defined?("cm")).to be_truthy

expect(1.cm).to be_instance_of(unit_group)
end
end

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

expect(Numeric.method_defined?("ft")).to be_truthy
expect(Numeric.method_defined?("in")).to be_truthy

expect(1.ft).to be_instance_of(unit_group)
end
end
end