composite_unit_measurements 0.1.0 → 0.2.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: e4450805d84ddd3b1cc972d152d187f44cbb1624d87dfece055c6db82ae70d20
4
+ data.tar.gz: 621ccd8a46402e7592dd93c8bf0683e414714e3f3fb67f1f4837cceabe96e5ab
5
5
  SHA512:
6
- metadata.gz: c1a6c264037d7db78d70676137d60a1085bb7126034674c6156de7806ef9c76263a8acd8bd4125fa3655d1c6c64c1ccec3bdd04d004dcc93dbd0e4ad6e056c86
7
- data.tar.gz: 394309d1a68c9eed5548f446fe3816ae467c7f2f6c4e66428d9957ae1ca5ed376659e4c7ff4fe1adc731cee85a8ea340577d120c65038b312398cf8f10dde6af
6
+ metadata.gz: 56937734d56198b02eb4c51c9b446558ec31a69bc123489ec371d8f36e7758efda6cf8d50ea85e947e57cf72f003e795a7897d850ff5a228f7505dc53b2aea36
7
+ data.tar.gz: d1e8a2129c276a186c8dd8bd7bf4cf5b29e2ff46c9dcff98b6928fba858b5d64441645c905ba273fd82bf547f43d14d1b0b25d2342d2219869d8d0a9b2a4d606
data/CHANGELOG.md CHANGED
@@ -1,3 +1,15 @@
1
+ ## 0.2.0 - 2023-11-17
2
+
3
+ ### What's new
4
+
5
+ - Added ability to parse composite measurements containing `real`, `scientific`,
6
+ `rational`, and `complex` numbers.
7
+ - Added ability to parse `foot-inch` length measurement.
8
+ - Added ability to parse `duration`.
9
+ - Added ability to parse `pound-ounce` and `stone-pound` weight measurement.
10
+
11
+ -----------
12
+
1
13
  ## 0.1.0 - 2023-11-09
2
14
 
3
15
  ### 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.2.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
@@ -37,6 +37,73 @@ Or otherwise simply install it yourself as:
37
37
 
38
38
  `$ gem install composite_unit_measurements`
39
39
 
40
+ ## Usage
41
+
42
+ Each packaged parser includes the `#parse` method to parse composite measurements.
43
+ You can use an appropriate parser to parse measurements. The final result of `#parse`
44
+ is returned in the leftmost unit of your measurement.
45
+
46
+ This gem internally uses [`unit_measurements`](https://github.com/shivam091/unit_measurements)
47
+ to perform conversions and arithmetic operations. You can use any
48
+ [alias of the units](https://github.com/shivam091/unit_measurements/blob/main/units.md)
49
+ to build a supported composite measurements.
50
+
51
+ ```ruby
52
+ CompositeUnitMeasurements::Length.parse("5 feet 6 inches")
53
+ #=> 5.5 ft
54
+ CompositeUnitMeasurements::Weight.parse("8 pound 12 ounce")
55
+ #=> 8.75 lb
56
+ CompositeUnitMeasurements::Time.parse("12:60:60,60")
57
+ #=> 13.0166666833333333666667 h
58
+ ```
59
+
60
+ Each parser has capability to parse `real`, `rational`, `scientific`, and `complex` numbers.
61
+
62
+ ```ruby
63
+ CompositeUnitMeasurements::Length.parse("1+2i ft 12 in")
64
+ #=> 2.0+2.0i ft
65
+ CompositeUnitMeasurements::Length.parse("1.5 ft 12e2 in")
66
+ #=> 101.5 ft
67
+ CompositeUnitMeasurements::Length.parse("1 1/2 ft 1+2i in")
68
+ #=> 1.5833333333333333+0.16666666666666669i ft
69
+ CompositeUnitMeasurements::Length.parse("2 ft 1+2i in")
70
+ #=> 2.0833333333333335+0.16666666666666669i ft
71
+ CompositeUnitMeasurements::Length.parse("1e-2 ft 1+2i in")
72
+ #=> 0.09333333333333334+0.16666666666666669i ft
73
+ ```
74
+
75
+ ## Packaged parsers & supported composite measurements
76
+
77
+ There are tons of composite measurements that are bundled with `composite_unit_measurements`.
78
+
79
+ **1. Unitify::CompositeMeasurements::Length**
80
+ - foot-inch (5 ft 6 in)
81
+
82
+ **2. Unitify::CompositeMeasurements::Weight**
83
+ - pound-ounce (8 lb 12 oz)
84
+ - stone-pound (2 st 6 lb)
85
+
86
+ **3. Unitify::CompositeMeasurements::Time**
87
+ - hour-minute-second-microsecond (12:60:60,60)
88
+
89
+ ### Specifing parsers
90
+
91
+ By default, `composite_unit_measurements` ships with all the packaged parsers and
92
+ this happens automatically when you require the gem in the following manner.
93
+
94
+ ```ruby
95
+ require "composite_unit_measurements"
96
+ ```
97
+
98
+ You can also use parsers in your application as per your need as:
99
+
100
+ ```ruby
101
+ require "composite_unit_measurements/base"
102
+
103
+ require "composite_unit_measurements/length"
104
+ require "composite_unit_measurements/weight"
105
+ ```
106
+
40
107
  ## Contributing
41
108
 
42
109
  1. Fork it
@@ -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,74 @@
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
+ # @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 FOOT_INCH then parse_foot_inch(string)
28
+ else raise UnitMeasurements::ParseError, string
29
+ end
30
+ end
31
+
32
+ private
33
+
34
+ # @private
35
+ # Parses a +string+ representing a length in the format of +foot-inch+.
36
+ #
37
+ # @param [String] string
38
+ # The string representing length measurement in the format of *foot-inch*.
39
+ # @return [UnitMeasurements::Length]
40
+ # Returns a UnitMeasurements::Length object if parsing is successful.
41
+ #
42
+ # @see FOOT_INCH
43
+ # @author {Harshal V. Ladhe}[https://shivam091.github.io/]
44
+ # @since 0.2.0
45
+ def parse_foot_inch(string)
46
+ foot, inch = string.match(FOOT_INCH)&.captures
47
+
48
+ if foot && inch
49
+ UnitMeasurements::Length.new(foot, :ft) + UnitMeasurements::Length.new(inch, :in)
50
+ end
51
+ end
52
+ end
53
+
54
+ private
55
+
56
+ # Regex pattern for aliases of +foot+ unit.
57
+ #
58
+ # @author {Harshal V. Ladhe}[https://shivam091.github.io/]
59
+ # @since 0.2.0
60
+ FOOT_ALIASES = /(?:'|ft|foot|feet)/.freeze
61
+
62
+ # Regex pattern for aliases of +inch+ unit.
63
+ #
64
+ # @author {Harshal V. Ladhe}[https://shivam091.github.io/]
65
+ # @since 0.2.0
66
+ INCH_ALIASES = /(?:"|in|inch(?:es)?)/.freeze
67
+
68
+ # Regex pattern for parsing a length measurement in the format of +foot-inch+.
69
+ #
70
+ # @author {Harshal V. Ladhe}[https://shivam091.github.io/]
71
+ # @since 0.2.0
72
+ FOOT_INCH = /\A#{ANY_NUMBER}\s*#{FOOT_ALIASES}\s*#{ANY_NUMBER}\s*#{INCH_ALIASES}\z/.freeze
73
+ end
74
+ end
@@ -0,0 +1,67 @@
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 DURATION then parse_duration(string)
28
+ else raise UnitMeasurements::ParseError, string
29
+ end
30
+ end
31
+
32
+ private
33
+
34
+ # @private
35
+ # Parses a +string+ representing time duration in the format of
36
+ # +hour:minute:second,microsecond+ or +hour:minute:second+.
37
+ #
38
+ # @param [String] string The string representing time duration.
39
+ # @return [UnitMeasurements::Time]
40
+ # Returns a UnitMeasurements::Time object if parsing is successful.
41
+ # @raise [ArgumentError]
42
+ # Raises an ArgumentError for an invalid duration format.
43
+ #
44
+ # @see DURATION
45
+ # @author {Harshal V. Ladhe}[https://shivam091.github.io/]
46
+ # @since 0.2.0
47
+ def parse_duration(string)
48
+ hour, minute, second, microsecond = string.match(DURATION)&.captures
49
+ raise ArgumentError, "Invalid Duration" if [hour, minute, second, microsecond].all?(&:nil?)
50
+
51
+ UnitMeasurements::Time.new((hour || 0), :h) +
52
+ UnitMeasurements::Time.new((minute || 0), :min) +
53
+ UnitMeasurements::Time.new((second || 0), :s) +
54
+ UnitMeasurements::Time.new((microsecond || 0), :μs)
55
+ end
56
+ end
57
+
58
+ private
59
+
60
+ # Regex pattern for parsing duration in the format of +hour:minute:second+ or
61
+ # +hour:minute:second,microsecond+.
62
+ #
63
+ # @author {Harshal V. Ladhe}[https://shivam091.github.io/]
64
+ # @since 0.2.0
65
+ DURATION = /\A(?<hour>#{REAL_NUMBER}):(?<min>#{REAL_NUMBER}):(?:(?<sec>#{REAL_NUMBER}))?(?:,(?<msec>#{REAL_NUMBER}))?\z/.freeze
66
+ end
67
+ end
@@ -3,5 +3,6 @@
3
3
  # -*- warn_indent: true -*-
4
4
 
5
5
  module CompositeUnitMeasurements
6
- VERSION = "0.1.0"
6
+ # Current stable version
7
+ VERSION = "0.2.0"
7
8
  end
@@ -0,0 +1,106 @@
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
+ else raise UnitMeasurements::ParseError, string
30
+ end
31
+ end
32
+
33
+ private
34
+
35
+ # @private
36
+ # Parses a +string+ representing a weight in the format of +pound-ounce+.
37
+ #
38
+ # @param [String] string
39
+ # The string representing weight measurement in the format of *pound-ounce*.
40
+ # @return [UnitMeasurements::Weight]
41
+ # Returns a UnitMeasurements::Weight object if parsing is successful.
42
+ #
43
+ # @see POUND_OUNCE
44
+ # @author {Harshal V. Ladhe}[https://shivam091.github.io/]
45
+ # @since 0.2.0
46
+ def parse_pound_ounce(string)
47
+ pound, ounce = string.match(POUND_OUNCE)&.captures
48
+
49
+ if pound && ounce
50
+ UnitMeasurements::Weight.new(pound, :lb) + UnitMeasurements::Weight.new(ounce, :oz)
51
+ end
52
+ end
53
+
54
+ # @private
55
+ # Parses a +string+ representing a weight in the format of +stone-pound+.
56
+ #
57
+ # @param [String] string
58
+ # The string representing weight measurement in the format of *stone-pound*.
59
+ # @return [UnitMeasurements::Weight]
60
+ # Returns a UnitMeasurements::Weight object if parsing is successful.
61
+ #
62
+ # @see STONE_POUND
63
+ # @author {Harshal V. Ladhe}[https://shivam091.github.io/]
64
+ # @since 0.2.0
65
+ def parse_stone_pound(string)
66
+ stone, pound = string.match(STONE_POUND)&.captures
67
+
68
+ if stone && pound
69
+ UnitMeasurements::Weight.new(stone, :st) + UnitMeasurements::Weight.new(pound, :lb)
70
+ end
71
+ end
72
+ end
73
+
74
+ private
75
+
76
+ # Regex pattern for aliases of +pound+ unit.
77
+ #
78
+ # @author {Harshal V. Ladhe}[https://shivam091.github.io/]
79
+ # @since 0.2.0
80
+ POUND_UNITS = /(?:#|lb|lbs|lbm|pound-mass|pound(?:s)?)/.freeze
81
+
82
+ # Regex pattern for aliases of +ounce+ unit.
83
+ #
84
+ # @author {Harshal V. Ladhe}[https://shivam091.github.io/]
85
+ # @since 0.2.0
86
+ OUNCE_UNITS = /(?:oz|ounce(?:s)?)/.freeze
87
+
88
+ # Regex pattern for aliases of +stone+ unit.
89
+ #
90
+ # @author {Harshal V. Ladhe}[https://shivam091.github.io/]
91
+ # @since 0.2.0
92
+ STONE_UNITS = /(?:st|stone(?:s)?)/.freeze
93
+
94
+ # Regex pattern for parsing a weight measurement in the format of +pound-ounce+.
95
+ #
96
+ # @author {Harshal V. Ladhe}[https://shivam091.github.io/]
97
+ # @since 0.2.0
98
+ POUND_OUNCE = /\A#{ANY_NUMBER}\s*#{POUND_UNITS}\s*#{ANY_NUMBER}\s*#{OUNCE_UNITS}\z/.freeze
99
+
100
+ # Regex pattern for parsing a weight measurement in the format of +stone-pound+.
101
+ #
102
+ # @author {Harshal V. Ladhe}[https://shivam091.github.io/]
103
+ # @since 0.2.0
104
+ STONE_POUND = /\A#{ANY_NUMBER}\s*#{STONE_UNITS}\s*#{ANY_NUMBER}\s*#{POUND_UNITS}\z/.freeze
105
+ end
106
+ 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.2.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-17 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