From 31097ac9336c4d83eccc42e3972b3265beaef935 Mon Sep 17 00:00:00 2001 From: Harshal LADHE Date: Sun, 26 Nov 2023 20:13:45 +0530 Subject: [PATCH 1/3] feat: added support to define numeric extension methods for units --- lib/unit_measurements/base.rb | 2 + .../extras/numeric_methods.rb | 81 +++++++++++++++++++ lib/unit_measurements/measurement.rb | 3 + .../extras/numeric_methods_spec.rb | 33 ++++++++ 4 files changed, 119 insertions(+) create mode 100644 lib/unit_measurements/extras/numeric_methods.rb create mode 100644 spec/unit_measurements/extras/numeric_methods_spec.rb diff --git a/lib/unit_measurements/base.rb b/lib/unit_measurements/base.rb index bf3cff6..81859b2 100644 --- a/lib/unit_measurements/base.rb +++ b/lib/unit_measurements/base.rb @@ -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" diff --git a/lib/unit_measurements/extras/numeric_methods.rb b/lib/unit_measurements/extras/numeric_methods.rb new file mode 100644 index 0000000..991cf9f --- /dev/null +++ b/lib/unit_measurements/extras/numeric_methods.rb @@ -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] 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] 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) + 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 diff --git a/lib/unit_measurements/measurement.rb b/lib/unit_measurements/measurement.rb index 016920c..9cf5c10 100644 --- a/lib/unit_measurements/measurement.rb +++ b/lib/unit_measurements/measurement.rb @@ -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 @@ -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/] diff --git a/spec/unit_measurements/extras/numeric_methods_spec.rb b/spec/unit_measurements/extras/numeric_methods_spec.rb new file mode 100644 index 0000000..506a367 --- /dev/null +++ b/spec/unit_measurements/extras/numeric_methods_spec.rb @@ -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 From b0ad5f746960ea71d8a38c65e95ae0ecb4683b8d Mon Sep 17 00:00:00 2001 From: Harshal LADHE Date: Sun, 26 Nov 2023 21:34:30 +0530 Subject: [PATCH 2/3] Updated changelog and readme --- CHANGELOG.md | 8 ++++++++ README.md | 25 +++++++++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 11206a7..06164f8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 diff --git a/README.md b/README.md index 3ddee5b..f8f225e 100644 --- a/README.md +++ b/README.md @@ -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 From eba1eb0d1151663be6b21cd552f3f4e228436454 Mon Sep 17 00:00:00 2001 From: Harshal LADHE Date: Sun, 26 Nov 2023 21:34:50 +0530 Subject: [PATCH 3/3] Bump version to `5.14.0` --- Gemfile.lock | 2 +- lib/unit_measurements/version.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 50031c6..4704e43 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,7 +1,7 @@ PATH remote: . specs: - unit_measurements (5.13.0) + unit_measurements (5.14.0) activesupport (~> 7.0) GEM diff --git a/lib/unit_measurements/version.rb b/lib/unit_measurements/version.rb index c8f5bf1..9138ba0 100644 --- a/lib/unit_measurements/version.rb +++ b/lib/unit_measurements/version.rb @@ -4,5 +4,5 @@ module UnitMeasurements # Current stable version. - VERSION = "5.13.0" + VERSION = "5.14.0" end