composite_unit_measurements 0.1.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7e212c20da9787a853fef2791d5f95d0004e5e45225c3809088205a1375b600c
4
- data.tar.gz: 8b2c03cfdfba50cc0e13088bbfb8910afd249b98ec4048280441131f47a310f5
3
+ metadata.gz: cd67813e0e00bce4c907e7076ec4a62994570585875da38dfa72bc968b3c0c20
4
+ data.tar.gz: c9de7ccfd6e0ede94d8cd5976174a1a60ed4f4cf3566bc613349a211ea9e4309
5
5
  SHA512:
6
- metadata.gz: c1a6c264037d7db78d70676137d60a1085bb7126034674c6156de7806ef9c76263a8acd8bd4125fa3655d1c6c64c1ccec3bdd04d004dcc93dbd0e4ad6e056c86
7
- data.tar.gz: 394309d1a68c9eed5548f446fe3816ae467c7f2f6c4e66428d9957ae1ca5ed376659e4c7ff4fe1adc731cee85a8ea340577d120c65038b312398cf8f10dde6af
6
+ metadata.gz: 7291bb98bb1e404be485f5f89de9f7594a7093f89cb98c4fd27310051804bfd22ea891acdfffed137ed466b0d9e778d6034439561dffe5e1e5b8b354093044b0
7
+ data.tar.gz: d86f50e73b9044cd8248bf49454c8c036a99b0bd2577fe21554b2c52ff14d1951bf19a11c388b9c0ddfed1670a1d315b054cda0d191909b1ae29cdc8793bf1e9
data/CHANGELOG.md CHANGED
@@ -1,3 +1,25 @@
1
+ ## [0.3.0](https://github.com/shivam091/composite_unit_measurements/compare/v0.2.0...v0.3.0) - 2023-11-27
2
+
3
+ ### What's new
4
+
5
+ - Added ability to parse `kilometre-metre` and `metre-centimetre` length measurements.
6
+ - Added ability to parse `hour-minute` time measurement.
7
+ - Added ability to parse `kilogramme-gramme` weight measurement.
8
+
9
+ -----------
10
+
11
+ ## [0.2.0](https://github.com/shivam091/composite_unit_measurements/compare/v0.1.0...v0.2.0) - 2023-11-17
12
+
13
+ ### What's new
14
+
15
+ - Added ability to parse composite measurements containing `real`, `scientific`,
16
+ `rational`, and `complex` numbers.
17
+ - Added ability to parse `foot-inch` length measurement.
18
+ - Added ability to parse `duration`.
19
+ - Added ability to parse `pound-ounce` and `stone-pound` weight measurement.
20
+
21
+ -----------
22
+
1
23
  ## 0.1.0 - 2023-11-09
2
24
 
3
25
  ### Initial release
data/Gemfile.lock CHANGED
@@ -1,14 +1,14 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- composite_unit_measurements (0.1.0)
4
+ composite_unit_measurements (0.3.0)
5
5
  activesupport (~> 7.0)
6
6
  unit_measurements (~> 5)
7
7
 
8
8
  GEM
9
9
  remote: https://rubygems.org/
10
10
  specs:
11
- activesupport (7.1.1)
11
+ activesupport (7.1.2)
12
12
  base64
13
13
  bigdecimal
14
14
  concurrent-ruby (~> 1.0, >= 1.0.2)
@@ -54,7 +54,7 @@ GEM
54
54
  simplecov_json_formatter (0.1.4)
55
55
  tzinfo (2.0.6)
56
56
  concurrent-ruby (~> 1.0)
57
- unit_measurements (5.8.0)
57
+ unit_measurements (5.11.1)
58
58
  activesupport (~> 7.0)
59
59
 
60
60
  PLATFORMS
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Composite Unit Measurements
2
2
 
3
- A set of specialized parsers for dealing with composite measurement strings.
3
+ A collection of specialized parsers designed for handling composite measurement strings.
4
4
 
5
5
  [![Ruby](https://github.com/shivam091/composite_unit_measurements/actions/workflows/main.yml/badge.svg)](https://github.com/shivam091/composite_unit_measurements/actions/workflows/main.yml)
6
6
  [![Gem Version](https://badge.fury.io/rb/composite_unit_measurements.svg)](https://badge.fury.io/rb/composite_unit_measurements)
@@ -13,17 +13,18 @@ A set of specialized parsers for dealing with composite measurement strings.
13
13
 
14
14
  ## Introduction
15
15
 
16
- The `CompositeUnitMeasurements` gem is a versatile solution tailored for parsing
17
- composite measurement strings. By harnessing the capabilities of the `unit_measurements`
18
- gem, it empowers you to seamlessly handle composite measurements in various units.
16
+ The `CompositeUnitMeasurements` gem offers versatile parsers for efficiently parsing
17
+ composite measurement strings. Leveraging the power of the `unit_measurements` gem,
18
+ it enables smooth handling of composite measurements in various units.
19
19
 
20
20
  ## Minimum Requirements
21
21
 
22
- * Ruby 3.2.2+ (https://www.ruby-lang.org/en/downloads/branches/)
22
+ * Ruby 3.2.2+ ([Download Ruby](https://www.ruby-lang.org/en/downloads/branches/))
23
23
 
24
24
  ## Installation
25
25
 
26
- If using bundler, first add this line to your application's Gemfile:
26
+ To use `composite_unit_measurements-rails` in your Rails application, add the
27
+ following line to your Gemfile:
27
28
 
28
29
  ```ruby
29
30
  gem "composite_unit_measurements"
@@ -37,13 +38,106 @@ Or otherwise simply install it yourself as:
37
38
 
38
39
  `$ gem install composite_unit_measurements`
39
40
 
41
+ ## Usage
42
+
43
+ Each packaged parser includes the `#parse` method to parse composite measurements.
44
+ You can use an appropriate parser to parse measurements. The final result of `#parse`
45
+ is returned in the leftmost unit of your measurement.
46
+
47
+ This gem internally uses [`unit_measurements`](https://github.com/shivam091/unit_measurements)
48
+ to perform conversions and arithmetic operations. You can build supported composite measurements
49
+ using any [unit alias](https://github.com/shivam091/unit_measurements/blob/main/units.md).
50
+
51
+ ### Examples
52
+
53
+ **Parsing length measurements:**
54
+
55
+ ```ruby
56
+ CompositeUnitMeasurements::Length.parse("5 ft 6 in")
57
+ #=> 5.5 ft
58
+ CompositeUnitMeasurements::Length.parse("6 m 50 cm")
59
+ #=> 6.5 m
60
+ CompositeUnitMeasurements::Length.parse("5 km 500 m")
61
+ #=> 5.5 km
62
+ ```
63
+
64
+ **Parsing weight measurements:**
65
+
66
+ ```ruby
67
+ CompositeUnitMeasurements::Weight.parse("8 lb 12 oz")
68
+ #=> 8.75 lb
69
+ CompositeUnitMeasurements::Weight.parse("2 st 6 lb")
70
+ #=> 2.428571428571429 st
71
+ CompositeUnitMeasurements::Weight.parse("2 st 6 lb")
72
+ # 4.5 kg
73
+ ```
74
+
75
+ **Parsing time measurements:**
76
+
77
+ ```ruby
78
+ CompositeUnitMeasurements::Time.parse("3 h 45 min")
79
+ #=> 3.75 hx
80
+ CompositeUnitMeasurements::Time.parse("12:60:3600,360000000")
81
+ #=> 14.1 h
82
+ ```
83
+
84
+ ### Support for numeric types
85
+
86
+ Each parser can handle various numeric types, including scientific notation, rational numbers, and complex numbers.
87
+
88
+ ```ruby
89
+ CompositeUnitMeasurements::Length.parse("1+2i ft 12 in")
90
+ #=> 2.0+2.0i ft
91
+ CompositeUnitMeasurements::Length.parse("1.5 ft 12e2 in")
92
+ #=> 101.5 ft
93
+ CompositeUnitMeasurements::Length.parse("1 1/2 ft 1+2i in")
94
+ #=> 1.5833333333333333+0.16666666666666669i ft
95
+ CompositeUnitMeasurements::Length.parse("2 ft 1+2i in")
96
+ #=> 2.0833333333333335+0.16666666666666669i ft
97
+ CompositeUnitMeasurements::Length.parse("1e-2 ft 1+2i in")
98
+ #=> 0.09333333333333334+0.16666666666666669i ft
99
+ ```
100
+
101
+ ## Packaged parsers & supported composite measurements
102
+
103
+ The `composite_unit_measurements` gem supports parsing various composite measurements, including:
104
+
105
+ **1. CompositeUnitMeasurements::Length**
106
+ - foot-inch (5 ft 6 in)
107
+ - metre-centimetre (6 m 50 cm)
108
+ - kilometre-metre (5 km 500 m)
109
+
110
+ **2. CompositeUnitMeasurements::Weight**
111
+ - pound-ounce (8 lb 12 oz)
112
+ - stone-pound (2 st 6 lb)
113
+ - kilogramme-gramme (4 kg 500 g)
114
+
115
+ **3. CompositeUnitMeasurements::Time**
116
+ - hour-minute (3 h 45 min)
117
+ - hour-minute-second-microsecond (12:60,3600:360000000)
118
+
119
+ ### Specifing parsers
120
+
121
+ By default, `composite_unit_measurements` includes all packaged parsers automatically
122
+ when required in your application. However, you can opt to use specific parsers as
123
+ needed:
124
+
125
+ ```ruby
126
+ require "composite_unit_measurements/base"
127
+
128
+ require "composite_unit_measurements/length"
129
+ require "composite_unit_measurements/weight"
130
+ ```
131
+
40
132
  ## Contributing
41
133
 
42
- 1. Fork it
43
- 2. Create your feature branch (`git checkout -b my-new-feature`)
134
+ Contributions to this project are welcomed! To contribute:
135
+
136
+ 1. Fork this repository
137
+ 2. Create a new branch (`git checkout -b my-new-feature`)
44
138
  3. Commit your changes (`git commit -am "Add some feature"`)
45
- 4. Push to the branch (`git push origin my-new-feature`)
46
- 5. Create new Pull Request
139
+ 4. Push the changes to your branch (`git push origin my-new-feature`)
140
+ 5. Create new **Pull Request**
47
141
 
48
142
  ## License
49
143
 
@@ -5,3 +5,53 @@
5
5
  require "unit_measurements/base"
6
6
 
7
7
  require "composite_unit_measurements/version"
8
+
9
+ module CompositeUnitMeasurements
10
+ # Matches real numbers in the form of 31, +72, or -12.
11
+ REAL_NUMBER = /
12
+ (?: # Start of non-capturing group
13
+ [+-]? # Optional plus (+) or minus (-) sign
14
+ \d+ # One or more digits
15
+ ) # End of non-capturing group
16
+ /x.freeze
17
+
18
+ # Matches a rational number in the form of a/b (fractional) or a b/c (mixed fractional).
19
+ RATIONAL_NUMBER = /
20
+ (?: # Start of optional non-capturing group
21
+ [+-]? # Optional plus (+) or minus (-) sign
22
+ \d+ # One or more digits
23
+ \s+ # One or more whitespace
24
+ )? # End of optional non-capturing group
25
+ ( # Start of capturing group for the fraction
26
+ (\d+) # Capture the numerator (one or more digits)
27
+ \/ # Match the forward slash, indicating division
28
+ (\d+) # Capture the denominator (one or more digits)
29
+ ) # End of capturing group for the fraction
30
+ /x.freeze
31
+
32
+ # Matches a scientific number in various formats like 1.23E+4 or -5.67e-8.
33
+ SCIENTIFIC_NUMBER = /
34
+ (?: # Start of non-capturing group
35
+ [+-]? # Optional plus (+) or minus (-) sign
36
+ \d* # Zero or more digits (integer part)
37
+ \.? # Optional decimal point
38
+ \d+ # One or more digits (fractional part)
39
+ (?: # Start of non-capturing group for exponent part
40
+ [Ee] # Match 'E' or 'e' for exponentiation
41
+ [+-]? # Optional plus (+) or minus (-) sign for exponent
42
+ \d+ # One or more digits (exponent value)
43
+ )? # End of non-capturing group of exponent part (optional)
44
+ ) # End of non-capturing group
45
+ /x.freeze
46
+
47
+ # Matches complex numbers in the form of a+bi, where both 'a' and 'b' can be
48
+ # in scientific notation. It captures the real and imaginary parts.
49
+ COMPLEX_NUMBER = /
50
+ #{SCIENTIFIC_NUMBER} # Pattern for scientific number
51
+ #{SCIENTIFIC_NUMBER} # Pattern for scientific number
52
+ i # Match the letter 'i' (the imaginary unit)
53
+ /x.freeze
54
+
55
+ # Matches any number, including scientific, complex, rational, and real numbers.
56
+ ANY_NUMBER = /(?<number>#{SCIENTIFIC_NUMBER}|#{COMPLEX_NUMBER}|#{RATIONAL_NUMBER}|#{REAL_NUMBER})/.freeze
57
+ end
@@ -0,0 +1,145 @@
1
+ # -*- encoding: utf-8 -*-
2
+ # -*- frozen_string_literal: true -*-
3
+ # -*- warn_indent: true -*-
4
+
5
+ require "unit_measurements/unit_groups/length"
6
+
7
+ module CompositeUnitMeasurements
8
+ # A parser handling +length+ measurements, particularly for composite units
9
+ # like +foot-inch+, +kilometre-metre+, +mile-yard+, etc.
10
+ #
11
+ # @author {Harshal V. Ladhe}[https://shivam091.github.io/]
12
+ # @since 0.2.0
13
+ class Length
14
+ class << self
15
+ # Parses a given +string+ into a +UnitMeasurements::Length+ object.
16
+ #
17
+ # @param [String] string The string to parse for length measurement.
18
+ # @return [UnitMeasurements::Length]
19
+ # Returns a UnitMeasurements::Length object if parsing is successful.
20
+ #
21
+ # @raise [UnitMeasurements::ParseError]
22
+ # If the string does not match any known format.
23
+ #
24
+ # @author {Harshal V. Ladhe}[https://shivam091.github.io/]
25
+ # @since 0.2.0
26
+ def parse(string)
27
+ case string
28
+ when FOOT_INCH then parse_foot_inch(string)
29
+ when KILOMETRE_METRE then parse_kilometre_metre(string)
30
+ when METRE_CENTIMETRE then parse_metre_centimetre(string)
31
+ else raise UnitMeasurements::ParseError, string
32
+ end
33
+ end
34
+
35
+ private
36
+
37
+ # @private
38
+ # Parses a +string+ representing a length in the format of +foot-inch+.
39
+ #
40
+ # @param [String] string
41
+ # The string representing length measurement in the format of *foot-inch*.
42
+ # @return [UnitMeasurements::Length]
43
+ # Returns a UnitMeasurements::Length object if parsing is successful.
44
+ #
45
+ # @see FOOT_INCH
46
+ # @author {Harshal V. Ladhe}[https://shivam091.github.io/]
47
+ # @since 0.2.0
48
+ def parse_foot_inch(string)
49
+ foot, inch = string.match(FOOT_INCH)&.captures
50
+
51
+ if foot && inch
52
+ UnitMeasurements::Length.new(foot, "ft") + UnitMeasurements::Length.new(inch, "in")
53
+ end
54
+ end
55
+
56
+ # @private
57
+ # Parses a +string+ representing a length in the format of +metre-centimetre+.
58
+ #
59
+ # @param [String] string
60
+ # The string representing length measurement in the format of *metre-centimetre*.
61
+ # @return [UnitMeasurements::Length]
62
+ # Returns a UnitMeasurements::Length object if parsing is successful.
63
+ #
64
+ # @see METRE_CENTIMETRE
65
+ # @author {Harshal V. Ladhe}[https://shivam091.github.io/]
66
+ # @since 0.3.0
67
+ def parse_metre_centimetre(string)
68
+ metre, centimetre = string.match(METRE_CENTIMETRE)&.captures
69
+
70
+ if metre && centimetre
71
+ UnitMeasurements::Length.new(metre, "m") + UnitMeasurements::Length.new(centimetre, "cm")
72
+ end
73
+ end
74
+
75
+ # @private
76
+ # Parses a +string+ representing a length in the format of +kilometre-metre+.
77
+ #
78
+ # @param [String] string
79
+ # The string representing length measurement in the format of *kilometre-metre*.
80
+ # @return [UnitMeasurements::Length]
81
+ # Returns a UnitMeasurements::Length object if parsing is successful.
82
+ #
83
+ # @see KILOMETRE_METRE
84
+ # @author {Harshal V. Ladhe}[https://shivam091.github.io/]
85
+ # @since 0.3.0
86
+ def parse_kilometre_metre(string)
87
+ kilometre, metre = string.match(KILOMETRE_METRE)&.captures
88
+
89
+ if kilometre && metre
90
+ UnitMeasurements::Length.new(kilometre, "km") + UnitMeasurements::Length.new(metre, "m")
91
+ end
92
+ end
93
+ end
94
+
95
+ private
96
+
97
+ # Regex pattern for aliases of +foot+ unit.
98
+ #
99
+ # @author {Harshal V. Ladhe}[https://shivam091.github.io/]
100
+ # @since 0.2.0
101
+ FOOT_ALIASES = /(?:'|ft|foot|feet)/.freeze
102
+
103
+ # Regex pattern for aliases of +inch+ unit.
104
+ #
105
+ # @author {Harshal V. Ladhe}[https://shivam091.github.io/]
106
+ # @since 0.2.0
107
+ INCH_ALIASES = /(?:"|in|inch(?:es)?)/.freeze
108
+
109
+ # Regex pattern for aliases of +metre+ unit.
110
+ #
111
+ # @author {Harshal V. Ladhe}[https://shivam091.github.io/]
112
+ # @since 0.3.0
113
+ METRE_ALIASES = /(?:m|meter(?:s)?|metre(?:s)?)/.freeze
114
+
115
+ # Regex pattern for aliases of +centimetre+ unit.
116
+ #
117
+ # @author {Harshal V. Ladhe}[https://shivam091.github.io/]
118
+ # @since 0.3.0
119
+ CENTIMETRE_ALIASES = /(?:cm|centimeter(?:s)?|centimetre(?:s)?)/.freeze
120
+
121
+ # Regex pattern for aliases of +kilometre+ unit.
122
+ #
123
+ # @author {Harshal V. Ladhe}[https://shivam091.github.io/]
124
+ # @since 0.3.0
125
+ KILOMETRE_ALIASES = /(?:km|kilometer(?:s)?|kilometre(?:s)?)/.freeze
126
+
127
+ # Regex pattern for parsing a length measurement in the format of +foot-inch+.
128
+ #
129
+ # @author {Harshal V. Ladhe}[https://shivam091.github.io/]
130
+ # @since 0.2.0
131
+ FOOT_INCH = /\A#{ANY_NUMBER}\s*#{FOOT_ALIASES}\s*#{ANY_NUMBER}\s*#{INCH_ALIASES}\z/.freeze
132
+
133
+ # Regex pattern for parsing a length measurement in the format of +metre-centimetre+.
134
+ #
135
+ # @author {Harshal V. Ladhe}[https://shivam091.github.io/]
136
+ # @since 0.3.0
137
+ METRE_CENTIMETRE = /\A#{ANY_NUMBER}\s*#{METRE_ALIASES}\s*#{ANY_NUMBER}\s*#{CENTIMETRE_ALIASES}\z/.freeze
138
+
139
+ # Regex pattern for parsing a length measurement in the format of +kilometre-metre+.
140
+ #
141
+ # @author {Harshal V. Ladhe}[https://shivam091.github.io/]
142
+ # @since 0.3.0
143
+ KILOMETRE_METRE = /\A#{ANY_NUMBER}\s*#{KILOMETRE_ALIASES}\s*#{ANY_NUMBER}\s*#{METRE_ALIASES}\z/.freeze
144
+ end
145
+ end
@@ -0,0 +1,105 @@
1
+ # -*- encoding: utf-8 -*-
2
+ # -*- frozen_string_literal: true -*-
3
+ # -*- warn_indent: true -*-
4
+
5
+ require "unit_measurements/unit_groups/time"
6
+
7
+ module CompositeUnitMeasurements
8
+ # A parser handling +time+ measurements, particularly for composite units
9
+ # like +hour:minute:second,microsecond+, +minute-second+, +hour-minute+, etc.
10
+ #
11
+ # @author {Harshal V. Ladhe}[https://shivam091.github.io/]
12
+ # @since 0.2.0
13
+ class Time
14
+ class << self
15
+ # Parses a given +string+ into a +UnitMeasurements::Time+ object.
16
+ #
17
+ # @param [String] string The string to parse for time measurement.
18
+ # @return [UnitMeasurements::Time]
19
+ # Returns a UnitMeasurements::Time object if parsing is successful.
20
+ # @raise [UnitMeasurements::ParseError]
21
+ # If the string does not match any known format.
22
+ #
23
+ # @author {Harshal V. Ladhe}[https://shivam091.github.io/]
24
+ # @since 0.2.0
25
+ def parse(string)
26
+ case string
27
+ when HOUR_MINUTE then parse_hour_minute(string)
28
+ when DURATION then parse_duration(string)
29
+ else raise UnitMeasurements::ParseError, string
30
+ end
31
+ end
32
+
33
+ private
34
+
35
+ # @private
36
+ # Parses a +string+ representing a time in the format of +hour-minute+.
37
+ #
38
+ # @param [String] string
39
+ # The string representing time measurement in the format of *hour-minute*.
40
+ # @return [UnitMeasurements::Time]
41
+ # Returns a UnitMeasurements::Time object if parsing is successful.
42
+ #
43
+ # @see HOUR_MINUTE
44
+ # @author {Harshal V. Ladhe}[https://shivam091.github.io/]
45
+ # @since 0.3.0
46
+ def parse_hour_minute(string)
47
+ hour, minute = string.match(HOUR_MINUTE)&.captures
48
+
49
+ if hour && minute
50
+ UnitMeasurements::Time.new(hour, "h") + UnitMeasurements::Time.new(minute, "min")
51
+ end
52
+ end
53
+
54
+ # @private
55
+ # Parses a +string+ representing time duration in the format of
56
+ # +hour:minute:second,microsecond+ or +hour:minute:second+.
57
+ #
58
+ # @param [String] string The string representing time duration.
59
+ # @return [UnitMeasurements::Time]
60
+ # Returns a UnitMeasurements::Time object if parsing is successful.
61
+ # @raise [ArgumentError]
62
+ # Raises an ArgumentError for an invalid duration format.
63
+ #
64
+ # @see DURATION
65
+ # @author {Harshal V. Ladhe}[https://shivam091.github.io/]
66
+ # @since 0.2.0
67
+ def parse_duration(string)
68
+ hour, minute, second, microsecond = string.match(DURATION)&.captures
69
+ raise ArgumentError, "Invalid Duration" if [hour, minute, second, microsecond].all?(&:nil?)
70
+
71
+ UnitMeasurements::Time.new((hour || 0), :h) +
72
+ UnitMeasurements::Time.new((minute || 0), :min) +
73
+ UnitMeasurements::Time.new((second || 0), :s) +
74
+ UnitMeasurements::Time.new((microsecond || 0), :μs)
75
+ end
76
+ end
77
+
78
+ private
79
+
80
+ # Regex pattern for aliases of +hour+ unit.
81
+ #
82
+ # @author {Harshal V. Ladhe}[https://shivam091.github.io/]
83
+ # @since 0.3.0
84
+ HOUR_ALIASES = /(?:h|hr|hour(?:s)?)/.freeze
85
+
86
+ # Regex pattern for aliases of +minute+ unit.
87
+ #
88
+ # @author {Harshal V. Ladhe}[https://shivam091.github.io/]
89
+ # @since 0.3.0
90
+ MINUTE_ALIASES = /(?:min|minute(?:s)?)/.freeze
91
+
92
+ # Regex pattern for parsing a time measurement in the format of +hour-minute+.
93
+ #
94
+ # @author {Harshal V. Ladhe}[https://shivam091.github.io/]
95
+ # @since 0.3.0
96
+ HOUR_MINUTE = /\A#{ANY_NUMBER}\s*#{HOUR_ALIASES}\s*#{ANY_NUMBER}\s*#{MINUTE_ALIASES}\z/.freeze
97
+
98
+ # Regex pattern for parsing duration in the format of +hour:minute:second+ or
99
+ # +hour:minute:second,microsecond+.
100
+ #
101
+ # @author {Harshal V. Ladhe}[https://shivam091.github.io/]
102
+ # @since 0.2.0
103
+ DURATION = /\A(?<hour>#{REAL_NUMBER}):(?<min>#{REAL_NUMBER}):(?:(?<sec>#{REAL_NUMBER}))?(?:,(?<msec>#{REAL_NUMBER}))?\z/.freeze
104
+ end
105
+ end
@@ -2,6 +2,28 @@
2
2
  # -*- frozen_string_literal: true -*-
3
3
  # -*- warn_indent: true -*-
4
4
 
5
+ # This module provides parsers and utilities for handling composite unit measurements.
6
+ # It allows parsing and manipulation of various composite measurements for units of
7
+ # +length+, +weight+, +time+ etc.
8
+ #
9
+ # @note
10
+ # This module serves as a namespace for classes and utilities related to composite
11
+ # unit measurements. To parse such measurements, refer to individual classes like
12
+ # {Length}, {Weight}, {Time}, etc. within this module.
13
+ #
14
+ # @example
15
+ # CompositeUnitMeasurements::Length.parse("5 feet 12 inches")
16
+ # => 6.0 ft
17
+ #
18
+ # CompositeUnitMeasurements::Weight.parse("8 lb 12 oz")
19
+ # => 8.75 lb
20
+ #
21
+ # CompositeUnitMeasurements::Time.parse("3 h 45 min")
22
+ # => 3.75 h
23
+ #
24
+ # @author {Harshal V. Ladhe}[https://shivam091.github.io/]
25
+ # @since 0.1.0
5
26
  module CompositeUnitMeasurements
6
- VERSION = "0.1.0"
27
+ # Current stable version
28
+ VERSION = "0.3.0"
7
29
  end
@@ -0,0 +1,144 @@
1
+ # -*- encoding: utf-8 -*-
2
+ # -*- frozen_string_literal: true -*-
3
+ # -*- warn_indent: true -*-
4
+
5
+ require "unit_measurements/unit_groups/weight"
6
+
7
+ module CompositeUnitMeasurements
8
+ # A parser handling +weight+ measurements, particularly for composite units
9
+ # like +pound-ounce+, +stone-pound+, +kilogramme-gramme+, etc.
10
+ #
11
+ # @author {Harshal V. Ladhe}[https://shivam091.github.io/]
12
+ # @since 0.2.0
13
+ class Weight
14
+ class << self
15
+ # Parses a given +string+ into a +UnitMeasurements::Weight+ object.
16
+ #
17
+ # @param [String] string The string to parse for weight measurement.
18
+ # @return [UnitMeasurements::Weight]
19
+ # Returns a UnitMeasurements::Weight object if parsing is successful.
20
+ # @raise [UnitMeasurements::ParseError]
21
+ # If the string does not match any known format.
22
+ #
23
+ # @author {Harshal V. Ladhe}[https://shivam091.github.io/]
24
+ # @since 0.2.0
25
+ def parse(string)
26
+ case string
27
+ when POUND_OUNCE then parse_pound_ounce(string)
28
+ when STONE_POUND then parse_stone_pound(string)
29
+ when KILOGRAMME_GRAMME then parse_kilogramme_gramme(string)
30
+ else raise UnitMeasurements::ParseError, string
31
+ end
32
+ end
33
+
34
+ private
35
+
36
+ # @private
37
+ # Parses a +string+ representing a weight in the format of +pound-ounce+.
38
+ #
39
+ # @param [String] string
40
+ # The string representing weight measurement in the format of *pound-ounce*.
41
+ # @return [UnitMeasurements::Weight]
42
+ # Returns a UnitMeasurements::Weight object if parsing is successful.
43
+ #
44
+ # @see POUND_OUNCE
45
+ # @author {Harshal V. Ladhe}[https://shivam091.github.io/]
46
+ # @since 0.2.0
47
+ def parse_pound_ounce(string)
48
+ pound, ounce = string.match(POUND_OUNCE)&.captures
49
+
50
+ if pound && ounce
51
+ UnitMeasurements::Weight.new(pound, "lb") + UnitMeasurements::Weight.new(ounce, "oz")
52
+ end
53
+ end
54
+
55
+ # @private
56
+ # Parses a +string+ representing a weight in the format of +stone-pound+.
57
+ #
58
+ # @param [String] string
59
+ # The string representing weight measurement in the format of *stone-pound*.
60
+ # @return [UnitMeasurements::Weight]
61
+ # Returns a UnitMeasurements::Weight object if parsing is successful.
62
+ #
63
+ # @see STONE_POUND
64
+ # @author {Harshal V. Ladhe}[https://shivam091.github.io/]
65
+ # @since 0.2.0
66
+ def parse_stone_pound(string)
67
+ stone, pound = string.match(STONE_POUND)&.captures
68
+
69
+ if stone && pound
70
+ UnitMeasurements::Weight.new(stone, "st") + UnitMeasurements::Weight.new(pound, "lb")
71
+ end
72
+ end
73
+
74
+ # @private
75
+ # Parses a +string+ representing a weight in the format of +kilogramme-gramme+.
76
+ #
77
+ # @param [String] string
78
+ # The string representing weight measurement in the format of *kilogramme-gramme*.
79
+ # @return [UnitMeasurements::Weight]
80
+ # Returns a UnitMeasurements::Weight object if parsing is successful.
81
+ #
82
+ # @see KILOGRAMME_GRAMME
83
+ # @author {Harshal V. Ladhe}[https://shivam091.github.io/]
84
+ # @since 0.3.0
85
+ def parse_kilogramme_gramme(string)
86
+ kilogramme, gramme = string.match(KILOGRAMME_GRAMME)&.captures
87
+
88
+ if kilogramme && gramme
89
+ UnitMeasurements::Weight.new(kilogramme, "kg") + UnitMeasurements::Weight.new(gramme, "g")
90
+ end
91
+ end
92
+ end
93
+
94
+ private
95
+
96
+ # Regex pattern for aliases of +pound+ unit.
97
+ #
98
+ # @author {Harshal V. Ladhe}[https://shivam091.github.io/]
99
+ # @since 0.2.0
100
+ POUND_ALIASES = /(?:#|lb|lbs|lbm|pound-mass|pound(?:s)?)/.freeze
101
+
102
+ # Regex pattern for aliases of +ounce+ unit.
103
+ #
104
+ # @author {Harshal V. Ladhe}[https://shivam091.github.io/]
105
+ # @since 0.2.0
106
+ OUNCE_ALIASES = /(?:oz|ounce(?:s)?)/.freeze
107
+
108
+ # Regex pattern for aliases of +stone+ unit.
109
+ #
110
+ # @author {Harshal V. Ladhe}[https://shivam091.github.io/]
111
+ # @since 0.2.0
112
+ STONE_ALIASES = /(?:st|stone(?:s)?)/.freeze
113
+
114
+ # Regex pattern for aliases of +gramme+ unit.
115
+ #
116
+ # @author {Harshal V. Ladhe}[https://shivam091.github.io/]
117
+ # @since 0.3.0
118
+ GRAMME_ALIASES = /(?:g|gram(?:s)?|gramme(?:s)?)/.freeze
119
+
120
+ # Regex pattern for aliases of +kilogramme+ unit.
121
+ #
122
+ # @author {Harshal V. Ladhe}[https://shivam091.github.io/]
123
+ # @since 0.3.0
124
+ KILOGRAMME_ALIASES = /(?:kg|kilogram(?:s)?|kilogramme(?:s)?)/.freeze
125
+
126
+ # Regex pattern for parsing a weight measurement in the format of +pound-ounce+.
127
+ #
128
+ # @author {Harshal V. Ladhe}[https://shivam091.github.io/]
129
+ # @since 0.2.0
130
+ POUND_OUNCE = /\A#{ANY_NUMBER}\s*#{POUND_ALIASES}\s*#{ANY_NUMBER}\s*#{OUNCE_ALIASES}\z/.freeze
131
+
132
+ # Regex pattern for parsing a weight measurement in the format of +stone-pound+.
133
+ #
134
+ # @author {Harshal V. Ladhe}[https://shivam091.github.io/]
135
+ # @since 0.2.0
136
+ STONE_POUND = /\A#{ANY_NUMBER}\s*#{STONE_ALIASES}\s*#{ANY_NUMBER}\s*#{POUND_ALIASES}\z/.freeze
137
+
138
+ # Regex pattern for parsing a weight measurement in the format of +kilogramme-gramme+.
139
+ #
140
+ # @author {Harshal V. Ladhe}[https://shivam091.github.io/]
141
+ # @since 0.3.0
142
+ KILOGRAMME_GRAMME = /\A#{ANY_NUMBER}\s*#{KILOGRAMME_ALIASES}\s*#{ANY_NUMBER}\s*#{GRAMME_ALIASES}\z/.freeze
143
+ end
144
+ end
@@ -2,8 +2,8 @@
2
2
  # -*- frozen_string_literal: true -*-
3
3
  # -*- warn_indent: true -*-
4
4
 
5
- require "composite_unit_measurements/version"
5
+ require "composite_unit_measurements/base"
6
6
 
7
- module CompositeUnitMeasurements
8
- class Error < StandardError; end
9
- end
7
+ require "composite_unit_measurements/length"
8
+ require "composite_unit_measurements/time"
9
+ require "composite_unit_measurements/weight"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: composite_unit_measurements
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Harshal LADHE
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-11-09 00:00:00.000000000 Z
11
+ date: 2023-11-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -121,7 +121,10 @@ files:
121
121
  - composite_unit_measurements.gemspec
122
122
  - lib/composite_unit_measurements.rb
123
123
  - lib/composite_unit_measurements/base.rb
124
+ - lib/composite_unit_measurements/length.rb
125
+ - lib/composite_unit_measurements/time.rb
124
126
  - lib/composite_unit_measurements/version.rb
127
+ - lib/composite_unit_measurements/weight.rb
125
128
  homepage: https://github.com/shivam091/composite_unit_measurements
126
129
  licenses:
127
130
  - MIT