unit_measurements_us_complete 5.17.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 +7 -0
- data/.github/workflows/main.yml +31 -0
- data/.github/workflows/pages.yml +31 -0
- data/.gitignore +12 -0
- data/.rspec +3 -0
- data/.yardopts +2 -0
- data/CHANGELOG.md +645 -0
- data/Gemfile +7 -0
- data/Gemfile.lock +56 -0
- data/LICENSE.md +21 -0
- data/README.md +511 -0
- data/Rakefile +10 -0
- data/lib/unit_measurements/arithmetic.rb +225 -0
- data/lib/unit_measurements/base.rb +177 -0
- data/lib/unit_measurements/cache.rb +173 -0
- data/lib/unit_measurements/comparison.rb +64 -0
- data/lib/unit_measurements/configuration.rb +64 -0
- data/lib/unit_measurements/conversion.rb +92 -0
- data/lib/unit_measurements/errors/blank_quantity_error.rb +21 -0
- data/lib/unit_measurements/errors/blank_unit_error.rb +21 -0
- data/lib/unit_measurements/errors/missing_primitive_unit_error.rb +24 -0
- data/lib/unit_measurements/errors/parse_error.rb +37 -0
- data/lib/unit_measurements/errors/primitive_unit_already_set_error.rb +22 -0
- data/lib/unit_measurements/errors/unit_already_defined_error.rb +37 -0
- data/lib/unit_measurements/errors/unit_error.rb +36 -0
- data/lib/unit_measurements/extras/conversion_methods.rb +87 -0
- data/lib/unit_measurements/extras/numeric_methods.rb +85 -0
- data/lib/unit_measurements/formatter.rb +58 -0
- data/lib/unit_measurements/math.rb +120 -0
- data/lib/unit_measurements/measurement.rb +539 -0
- data/lib/unit_measurements/normalizer.rb +155 -0
- data/lib/unit_measurements/parser.rb +220 -0
- data/lib/unit_measurements/unit.rb +243 -0
- data/lib/unit_measurements/unit_group.rb +297 -0
- data/lib/unit_measurements/unit_group_builder.rb +224 -0
- data/lib/unit_measurements/unit_groups/acceleration.rb +36 -0
- data/lib/unit_measurements/unit_groups/all.rb +56 -0
- data/lib/unit_measurements/unit_groups/amount_of_substance.rb +13 -0
- data/lib/unit_measurements/unit_groups/angular_acceleration.rb +14 -0
- data/lib/unit_measurements/unit_groups/angular_velocity.rb +25 -0
- data/lib/unit_measurements/unit_groups/area.rb +49 -0
- data/lib/unit_measurements/unit_groups/catalytic_activity.rb +13 -0
- data/lib/unit_measurements/unit_groups/density.rb +33 -0
- data/lib/unit_measurements/unit_groups/dynamic_viscosity.rb +22 -0
- data/lib/unit_measurements/unit_groups/electric_charge.rb +20 -0
- data/lib/unit_measurements/unit_groups/electric_conductance.rb +15 -0
- data/lib/unit_measurements/unit_groups/electric_current.rb +19 -0
- data/lib/unit_measurements/unit_groups/electric_dipole_moment.rb +13 -0
- data/lib/unit_measurements/unit_groups/electric_potential.rb +17 -0
- data/lib/unit_measurements/unit_groups/electric_quadrupole_moment.rb +14 -0
- data/lib/unit_measurements/unit_groups/electrical_capacitance.rb +15 -0
- data/lib/unit_measurements/unit_groups/electrical_elastance.rb +13 -0
- data/lib/unit_measurements/unit_groups/electrical_inductance.rb +15 -0
- data/lib/unit_measurements/unit_groups/electrical_resistance.rb +16 -0
- data/lib/unit_measurements/unit_groups/energy.rb +58 -0
- data/lib/unit_measurements/unit_groups/force.rb +47 -0
- data/lib/unit_measurements/unit_groups/frequency.rb +16 -0
- data/lib/unit_measurements/unit_groups/illuminance.rb +18 -0
- data/lib/unit_measurements/unit_groups/information_entropy.rb +15 -0
- data/lib/unit_measurements/unit_groups/kinetic_viscosity.rb +18 -0
- data/lib/unit_measurements/unit_groups/length.rb +67 -0
- data/lib/unit_measurements/unit_groups/luminance.rb +21 -0
- data/lib/unit_measurements/unit_groups/luminous_flux.rb +11 -0
- data/lib/unit_measurements/unit_groups/luminous_intensity.rb +13 -0
- data/lib/unit_measurements/unit_groups/magnetic_field.rb +13 -0
- data/lib/unit_measurements/unit_groups/magnetic_flux.rb +15 -0
- data/lib/unit_measurements/unit_groups/magnetic_induction.rb +13 -0
- data/lib/unit_measurements/unit_groups/magnetomotive_force.rb +13 -0
- data/lib/unit_measurements/unit_groups/mass_flow_rate.rb +49 -0
- data/lib/unit_measurements/unit_groups/plane_angle.rb +30 -0
- data/lib/unit_measurements/unit_groups/power.rb +54 -0
- data/lib/unit_measurements/unit_groups/pressure.rb +60 -0
- data/lib/unit_measurements/unit_groups/quantity.rb +14 -0
- data/lib/unit_measurements/unit_groups/radiation_absorbed_dose.rb +14 -0
- data/lib/unit_measurements/unit_groups/radiation_equivalent_dose.rb +13 -0
- data/lib/unit_measurements/unit_groups/radiation_exposure.rb +15 -0
- data/lib/unit_measurements/unit_groups/radioactivity.rb +14 -0
- data/lib/unit_measurements/unit_groups/solid_angle.rb +18 -0
- data/lib/unit_measurements/unit_groups/sound_level.rb +13 -0
- data/lib/unit_measurements/unit_groups/temperature.rb +19 -0
- data/lib/unit_measurements/unit_groups/time.rb +29 -0
- data/lib/unit_measurements/unit_groups/torque.rb +40 -0
- data/lib/unit_measurements/unit_groups/velocity.rb +37 -0
- data/lib/unit_measurements/unit_groups/volume.rb +67 -0
- data/lib/unit_measurements/unit_groups/volumetric_flow_rate.rb +35 -0
- data/lib/unit_measurements/unit_groups/weight.rb +55 -0
- data/lib/unit_measurements/version.rb +8 -0
- data/lib/unit_measurements.rb +7 -0
- data/unit_measurements.gemspec +43 -0
- data/units.md +843 -0
- metadata +216 -0
@@ -0,0 +1,225 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
# -*- frozen_string_literal: true -*-
|
3
|
+
# -*- warn_indent: true -*-
|
4
|
+
|
5
|
+
module UnitMeasurements
|
6
|
+
# The +UnitMeasurements::Arithmetic+ mixin module provides methods for
|
7
|
+
# performing arithmetic operations (addition, subtraction, multiplication,
|
8
|
+
# division, etc) on measurements of the same unit group. In case the
|
9
|
+
# measurements represents different units, the left hand side takes precedence
|
10
|
+
# while performing the arithmetic operation on them.
|
11
|
+
#
|
12
|
+
# This module is included in the +Measurement+ class to allow arithmetic
|
13
|
+
# operations on the measurements.
|
14
|
+
#
|
15
|
+
# @see Measurement
|
16
|
+
# @author {Harshal V. Ladhe}[https://shivam091.github.io/]
|
17
|
+
# @since 1.4.0
|
18
|
+
module Arithmetic
|
19
|
+
extend Forwardable
|
20
|
+
|
21
|
+
# Methods delegated from the Numeric.
|
22
|
+
def_delegators :@quantity, :zero?, :positive?, :negative?, :finite?, :infinite?
|
23
|
+
|
24
|
+
# Adds the quantity of the other measurement or a numeric value to the
|
25
|
+
# quantity of the current measurement.
|
26
|
+
#
|
27
|
+
# @param [Numeric|Measurement] other
|
28
|
+
# The value to be added. It can be a numeric value or another measurement.
|
29
|
+
#
|
30
|
+
# @example
|
31
|
+
# UnitMeasurements::Length.new(1, "km") + UnitMeasurements::Length.new(1, "m")
|
32
|
+
# => 1.001 km
|
33
|
+
#
|
34
|
+
# UnitMeasurements::Length.new(1, "km") + 4.5
|
35
|
+
# => 5.5 km
|
36
|
+
#
|
37
|
+
# @return [Measurement] A new +Measurement+ instance with the combined quantity.
|
38
|
+
#
|
39
|
+
# @author {Harshal V. Ladhe}[https://shivam091.github.io/]
|
40
|
+
# @since 1.4.0
|
41
|
+
def +(other)
|
42
|
+
arithmetic_operation(other, :+)
|
43
|
+
end
|
44
|
+
alias_method :add, :+
|
45
|
+
|
46
|
+
# Subtracts the quantity of the other measurement or a numeric value from the
|
47
|
+
# quantity of the current measurement.
|
48
|
+
#
|
49
|
+
# @param [Numeric|Measurement] other
|
50
|
+
# The value to be subtracted. It can be a numeric value or another measurement.
|
51
|
+
#
|
52
|
+
# @example
|
53
|
+
# UnitMeasurements::Length.new(1, "km") - UnitMeasurements::Length.new(2, "in")
|
54
|
+
# => 0.9999492 km
|
55
|
+
#
|
56
|
+
# UnitMeasurements::Length.new(2, "km") - 1e+2
|
57
|
+
# => -98.0 km
|
58
|
+
#
|
59
|
+
# @return [Measurement] A new +Measurement+ instance with the subtracted quantity.
|
60
|
+
#
|
61
|
+
# @author {Harshal V. Ladhe}[https://shivam091.github.io/]
|
62
|
+
# @since 1.4.0
|
63
|
+
def -(other)
|
64
|
+
arithmetic_operation(other, :-)
|
65
|
+
end
|
66
|
+
alias_method :subtract, :-
|
67
|
+
|
68
|
+
# Multiplies the quantity of the current measurement by the quantity of the
|
69
|
+
# other measurement or a numeric value.
|
70
|
+
#
|
71
|
+
# @param [Numeric|Measurement] other
|
72
|
+
# The value to be multiplied. It can be a numeric value or another measurement.
|
73
|
+
#
|
74
|
+
# @example
|
75
|
+
# UnitMeasurements::Length.new(2, "km") * UnitMeasurements::Length.new(3, "in")
|
76
|
+
# => 0.0001524 km
|
77
|
+
#
|
78
|
+
# UnitMeasurements::Length.new(2, "km") * 2+2i
|
79
|
+
# => 4+2i km
|
80
|
+
#
|
81
|
+
# @return [Measurement] A new +Measurement+ instance with the multiplied quantity.
|
82
|
+
#
|
83
|
+
# @author {Harshal V. Ladhe}[https://shivam091.github.io/]
|
84
|
+
# @since 1.4.0
|
85
|
+
def *(other)
|
86
|
+
arithmetic_operation(other, :*)
|
87
|
+
end
|
88
|
+
alias_method :scale, :*
|
89
|
+
alias_method :times, :*
|
90
|
+
alias_method :multiply, :*
|
91
|
+
|
92
|
+
# Divides the quantity of the current measurement by the quantity of the other
|
93
|
+
# measurement or a numeric value.
|
94
|
+
#
|
95
|
+
# @param [Numeric|Measurement] other
|
96
|
+
# The value to be divided. It can be a numeric value or another measurement.
|
97
|
+
#
|
98
|
+
# @example
|
99
|
+
# UnitMeasurements::Length.new(4, "km") / UnitMeasurements::Length.new(2, "km")
|
100
|
+
# => 2 km
|
101
|
+
#
|
102
|
+
# UnitMeasurements::Length.new(2, "km") / 2
|
103
|
+
# => 1 km
|
104
|
+
#
|
105
|
+
# @return [Measurement] A new +Measurement+ instance with the divided quantity.
|
106
|
+
#
|
107
|
+
# @author {Harshal V. Ladhe}[https://shivam091.github.io/]
|
108
|
+
# @since 1.4.0
|
109
|
+
def /(other)
|
110
|
+
arithmetic_operation(other, :/)
|
111
|
+
end
|
112
|
+
alias_method :divide, :/
|
113
|
+
|
114
|
+
# Raises the quantity of the current measurement to the power of the quantity of
|
115
|
+
# the other measurement or numeric value.
|
116
|
+
#
|
117
|
+
# When +other+ is an instance of +Measurement+, the quantity to raise
|
118
|
+
# is calculated by converting the +other+ measurement to the unit of the +current+
|
119
|
+
# measurement, and then the quantity of the +current+ measurement is raised to
|
120
|
+
# the converted quantity.
|
121
|
+
#
|
122
|
+
# @param [Numeric|Measurement] other
|
123
|
+
# The value to be raised. It can be a numeric value or another measurement.
|
124
|
+
#
|
125
|
+
# @example
|
126
|
+
# UnitMeasurements::Length.new(2, "km") ** UnitMeasurements::Length.new(3, "m")
|
127
|
+
# => 1.00208160507963279 km
|
128
|
+
#
|
129
|
+
# UnitMeasurements::Length.new(2, "km") ** 3
|
130
|
+
# => 8 km
|
131
|
+
#
|
132
|
+
# UnitMeasurements::Length.new(8, "km") ** 1/3r
|
133
|
+
# => 2 km
|
134
|
+
#
|
135
|
+
# @return [Measurement] A new +Measurement+ instance with the raised quantity.
|
136
|
+
#
|
137
|
+
# @author {Harshal V. Ladhe}[https://shivam091.github.io/]
|
138
|
+
# @since 5.1.0
|
139
|
+
def **(other)
|
140
|
+
arithmetic_operation(other, :**)
|
141
|
+
end
|
142
|
+
alias_method :pow, :**
|
143
|
+
alias_method :^, :**
|
144
|
+
|
145
|
+
# Negates the quantity of the measurement.
|
146
|
+
#
|
147
|
+
# @example
|
148
|
+
# -UnitMeasurements::Length.new(2, "km")
|
149
|
+
# => -2 km
|
150
|
+
#
|
151
|
+
# -UnitMeasurements::Length.new(-2, "km")
|
152
|
+
# => 2 km
|
153
|
+
#
|
154
|
+
# @return [Measurement] A new +Measurement+ instance with the negated quantity.
|
155
|
+
#
|
156
|
+
# @author {Harshal V. Ladhe}[https://shivam091.github.io/]
|
157
|
+
# @since 5.1.0
|
158
|
+
def -@
|
159
|
+
self.class.new(-self.quantity, self.unit)
|
160
|
+
end
|
161
|
+
alias_method :inverse, :-@
|
162
|
+
alias_method :negate, :-@
|
163
|
+
|
164
|
+
# Checks whether the quantity of the measurement is nonzero.
|
165
|
+
#
|
166
|
+
# @example
|
167
|
+
# UnitMeasurements::Length.new(2, "km").nonzero?
|
168
|
+
# => true
|
169
|
+
#
|
170
|
+
# UnitMeasurements::Length.new(0, "km").nonzero?
|
171
|
+
# => false
|
172
|
+
#
|
173
|
+
# @return [TrueClass|FalseClass]
|
174
|
+
# +true+ if the quantity is nonzero otherwise it returns +false+.
|
175
|
+
#
|
176
|
+
# @author {Harshal V. Ladhe}[https://shivam091.github.io/]
|
177
|
+
# @since 5.1.0
|
178
|
+
def nonzero?
|
179
|
+
quantity.nonzero? ? true : false
|
180
|
+
end
|
181
|
+
|
182
|
+
private
|
183
|
+
|
184
|
+
# @private
|
185
|
+
# Coerces a numeric value or another measurement for arithmetic operations.
|
186
|
+
#
|
187
|
+
# @param [Numeric|Measurement] other
|
188
|
+
# The value to be coerced. It can be a numeric value or another measurement.
|
189
|
+
#
|
190
|
+
# @return [Array<Measurement>] An array containing the coerced values.
|
191
|
+
#
|
192
|
+
# @raise [TypeError]
|
193
|
+
# If the coercion is not possible due to incompatible types.
|
194
|
+
#
|
195
|
+
# @author {Harshal V. Ladhe}[https://shivam091.github.io/]
|
196
|
+
# @since 1.4.0
|
197
|
+
def coerce(other)
|
198
|
+
case other
|
199
|
+
when Numeric then [self.class.new(other, self.unit), self]
|
200
|
+
when self.class then [other, self]
|
201
|
+
else raise TypeError, "Cannot coerce #{other.class} to #{self.class}"
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
# @private
|
206
|
+
# Performs an arithmetic operation (addition, subtraction, multiplication,
|
207
|
+
# or division) on the current measurement and another numeric value.
|
208
|
+
#
|
209
|
+
# @param [Numeric|Measurement] other
|
210
|
+
# The value to be used in the arithmetic operation. It can be a numeric value
|
211
|
+
# or another measurement.
|
212
|
+
# @param [Symbol] operator The operator to be used for the operation.
|
213
|
+
#
|
214
|
+
# @return [Measurement]
|
215
|
+
# A new +Measurement+ instance with the result of the arithmetic operation.
|
216
|
+
#
|
217
|
+
# @author {Harshal V. Ladhe}[https://shivam091.github.io/]
|
218
|
+
# @since 1.4.0
|
219
|
+
def arithmetic_operation(other, operator)
|
220
|
+
other, _ = coerce(other)
|
221
|
+
|
222
|
+
self.class.new(self.quantity.public_send(operator, other.convert_to(self.unit).quantity), self.unit)
|
223
|
+
end
|
224
|
+
end
|
225
|
+
end
|
@@ -0,0 +1,177 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
# -*- frozen_string_literal: true -*-
|
3
|
+
# -*- warn_indent: true -*-
|
4
|
+
|
5
|
+
require "active_support/all"
|
6
|
+
require "unit_measurements/version"
|
7
|
+
|
8
|
+
# The +UnitMeasurements+ module serves as a container for various functionalities
|
9
|
+
# related to unit measurements. It provides methods for creating custom unit
|
10
|
+
# groups, defining units, performing arithmetic operations, comparison between
|
11
|
+
# measurements, conversions, normalization of input strings, parsing measurements
|
12
|
+
# from strings, and more. It is a fundamental part of the unit measurements library.
|
13
|
+
#
|
14
|
+
# @author {Harshal V. Ladhe}[https://shivam091.github.io/]
|
15
|
+
# @since 0.1.0
|
16
|
+
module UnitMeasurements
|
17
|
+
# This is the base class for custom errors in the +UnitMeasurements+ module.
|
18
|
+
#
|
19
|
+
# @see UnitError
|
20
|
+
# @see ParseError
|
21
|
+
# @see BlankUnitError
|
22
|
+
# @see BlankQuantityError
|
23
|
+
# @see UnitAlreadyDefinedError
|
24
|
+
# @see MissingPrimitiveUnitError
|
25
|
+
# @see PrimitiveUnitAlreadySetError
|
26
|
+
# @author {Harshal V. Ladhe}[https://shivam091.github.io/]
|
27
|
+
# @since 1.1.0
|
28
|
+
class BaseError < StandardError; end
|
29
|
+
|
30
|
+
class << self
|
31
|
+
# Allows setting an instance of +Configuration+ containing values of desired
|
32
|
+
# configurable options.
|
33
|
+
#
|
34
|
+
# @author {Harshal V. Ladhe}[https://shivam091.github.io/]
|
35
|
+
# @since 5.3.0
|
36
|
+
attr_writer :configuration
|
37
|
+
|
38
|
+
# Creates a new unit group based on the provided +block+ of instructions.
|
39
|
+
#
|
40
|
+
# The +build+ method allows you to define and create a custom unit group with
|
41
|
+
# units and their conversions. It takes a block of instructions as an argument,
|
42
|
+
# which is evaluated by an instance of +UnitGroupBuilder+.
|
43
|
+
#
|
44
|
+
# Within the +block+, you can use various methods provided by +UnitGroupBuilder+
|
45
|
+
# to define units, group them into unit system, and set primitive unit of
|
46
|
+
# the unit group. These methods include +primitive+, +system+, +si_unit+,
|
47
|
+
# and +unit+.
|
48
|
+
#
|
49
|
+
# The resulting unit group is encapsulated in a new subclass of +Measurement+.
|
50
|
+
# This subclass will have access to the defined units and their conversions
|
51
|
+
# through the +unit_group+ class attribute.
|
52
|
+
#
|
53
|
+
# This method provides a powerful way to create specialized unit groups tailored
|
54
|
+
# to specific measurement domains.
|
55
|
+
#
|
56
|
+
# @example
|
57
|
+
# UnitMeasurements.build do
|
58
|
+
# primitive "m"
|
59
|
+
#
|
60
|
+
# system :metric do
|
61
|
+
# si_unit "m", aliases: ["meter", "metre", "meters", "metres"]
|
62
|
+
# end
|
63
|
+
#
|
64
|
+
# system :imperial do
|
65
|
+
# unit "in", value: "25.4 mm", aliases: ['"', "inch", "inches"]
|
66
|
+
# end
|
67
|
+
#
|
68
|
+
# cache "length.json"
|
69
|
+
# end
|
70
|
+
#
|
71
|
+
# @yield [builder]
|
72
|
+
# A block that defines the units to be added to the unit group.
|
73
|
+
# The block takes a {UnitGroupBuilder} instance as a parameter.
|
74
|
+
#
|
75
|
+
# @yieldparam builder [UnitGroupBuilder]
|
76
|
+
# The {UnitGroupBuilder} instance to define units within the unit group.
|
77
|
+
#
|
78
|
+
# @yieldreturn [UnitGroup]
|
79
|
+
# Returns an instance of {UnitGroup} containing the units and their conversions
|
80
|
+
# defined within the block.
|
81
|
+
#
|
82
|
+
# @return [Class]
|
83
|
+
# A new subclass of +Measurement+ with the defined units and conversions.
|
84
|
+
#
|
85
|
+
# @see Unit
|
86
|
+
# @see UnitGroup
|
87
|
+
# @see UnitGroupBuilder
|
88
|
+
# @see Measurement
|
89
|
+
# @author {Harshal V. Ladhe}[https://shivam091.github.io/]
|
90
|
+
# @since 1.0.0
|
91
|
+
def build(&block)
|
92
|
+
builder = UnitGroupBuilder.new
|
93
|
+
builder.instance_eval(&block)
|
94
|
+
|
95
|
+
Class.new(Measurement) do
|
96
|
+
class << self
|
97
|
+
attr_reader :unit_group
|
98
|
+
end
|
99
|
+
|
100
|
+
@unit_group = builder.build
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
# Returns an instance of +Configuration+ with the values of desired configurable
|
105
|
+
# options of +*unit_measurements*+. If instance is not present, it initializes
|
106
|
+
# a new instance of {Configuration}.
|
107
|
+
#
|
108
|
+
# @return [Configuration] An instance of +Configuration+.
|
109
|
+
#
|
110
|
+
# @author {Harshal V. Ladhe}[https://shivam091.github.io/]
|
111
|
+
# @since 5.3.0
|
112
|
+
def configuration
|
113
|
+
@configuration ||= Configuration.new
|
114
|
+
end
|
115
|
+
|
116
|
+
# Reset the configuration to its default state.
|
117
|
+
#
|
118
|
+
# @example
|
119
|
+
# UnitMeasurements.reset
|
120
|
+
#
|
121
|
+
# @return [Configuration] A new +Configuration+ object.
|
122
|
+
#
|
123
|
+
# @author {Harshal V. Ladhe}[https://shivam091.github.io/]
|
124
|
+
# @since 5.3.0
|
125
|
+
def reset
|
126
|
+
@configuration = Configuration.new
|
127
|
+
end
|
128
|
+
|
129
|
+
# Configures options of the +*UnitMeasurements*+ module using a block. It
|
130
|
+
# yields the current +Configuration+ instance for updating default values of
|
131
|
+
# options by new values specified within a block.
|
132
|
+
#
|
133
|
+
# @example
|
134
|
+
# UnitMeasurements.configure do |config|
|
135
|
+
# config.use_cache = false
|
136
|
+
# end
|
137
|
+
#
|
138
|
+
# @yield [configuration] The current +Configuration+ instance.
|
139
|
+
#
|
140
|
+
# @yieldparam [Configuration] configuration
|
141
|
+
# An instance of +Configuration+ with the new values of options.
|
142
|
+
#
|
143
|
+
# @yieldreturn [Configuration] The updated +Configuration+ instance.
|
144
|
+
#
|
145
|
+
# @author {Harshal V. Ladhe}[https://shivam091.github.io/]
|
146
|
+
# @since 5.3.0
|
147
|
+
def configure
|
148
|
+
yield configuration
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
# The following requires load various components of the unit measurements library.
|
154
|
+
require "unit_measurements/extras/numeric_methods"
|
155
|
+
require "unit_measurements/extras/conversion_methods"
|
156
|
+
|
157
|
+
require "unit_measurements/configuration"
|
158
|
+
require "unit_measurements/cache"
|
159
|
+
require "unit_measurements/unit_group_builder"
|
160
|
+
require "unit_measurements/unit"
|
161
|
+
require "unit_measurements/unit_group"
|
162
|
+
require "unit_measurements/arithmetic"
|
163
|
+
require "unit_measurements/comparison"
|
164
|
+
require "unit_measurements/conversion"
|
165
|
+
require "unit_measurements/math"
|
166
|
+
require "unit_measurements/normalizer"
|
167
|
+
require "unit_measurements/parser"
|
168
|
+
require "unit_measurements/formatter"
|
169
|
+
require "unit_measurements/measurement"
|
170
|
+
|
171
|
+
require "unit_measurements/errors/unit_error"
|
172
|
+
require "unit_measurements/errors/parse_error"
|
173
|
+
require "unit_measurements/errors/unit_already_defined_error"
|
174
|
+
require "unit_measurements/errors/primitive_unit_already_set_error"
|
175
|
+
require "unit_measurements/errors/blank_quantity_error"
|
176
|
+
require "unit_measurements/errors/blank_unit_error"
|
177
|
+
require "unit_measurements/errors/missing_primitive_unit_error"
|
@@ -0,0 +1,173 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
# -*- frozen_string_literal: true -*-
|
3
|
+
# -*- warn_indent: true -*-
|
4
|
+
|
5
|
+
module UnitMeasurements
|
6
|
+
# The +UnitMeasurements::Cache+ class manages caching of conversion factors
|
7
|
+
# between different units within a unit group. It provides methods to retrieve,
|
8
|
+
# set, and clear cached conversion factors.
|
9
|
+
#
|
10
|
+
# Cached conversion factors are stored in JSON file on the file system.
|
11
|
+
#
|
12
|
+
# @author {Harshal V. Ladhe}[https://shivam091.github.io/]
|
13
|
+
# @since 5.2.0
|
14
|
+
class Cache
|
15
|
+
# The directory path where cache files are stored.
|
16
|
+
#
|
17
|
+
# @author {Harshal V. Ladhe}[https://shivam091.github.io/]
|
18
|
+
# @since 5.2.0
|
19
|
+
CACHE_DIRECTORY = File.expand_path(File.join("..", "..", "cache"), __dir__).freeze
|
20
|
+
|
21
|
+
# Stores cached conversion factors between different units within a unit
|
22
|
+
# group.
|
23
|
+
#
|
24
|
+
# @return [Hash] The cached conversion factors.
|
25
|
+
#
|
26
|
+
# @author {Harshal V. Ladhe}[https://shivam091.github.io/]
|
27
|
+
# @since 5.2.0
|
28
|
+
attr_reader :cached_data
|
29
|
+
|
30
|
+
# Initializes a new +Cache+ instance for a specific unit group.
|
31
|
+
#
|
32
|
+
# Initialization first ensures existence of the cache directory. If the cache
|
33
|
+
# directory does not exist, it gets created.
|
34
|
+
#
|
35
|
+
# @param [UnitGroup] unit_group The unit group associated with the cache.
|
36
|
+
#
|
37
|
+
# @author {Harshal V. Ladhe}[https://shivam091.github.io/]
|
38
|
+
# @since 5.2.0
|
39
|
+
def initialize(unit_group)
|
40
|
+
ensure_cache_directory_exists
|
41
|
+
@cache_file = build_cache_file_path(unit_group)
|
42
|
+
@cached_data ||= load_cache
|
43
|
+
end
|
44
|
+
|
45
|
+
# Retrieves the conversion factor between source and target units from the
|
46
|
+
# cache.
|
47
|
+
#
|
48
|
+
# @param [String] source_unit The source unit name.
|
49
|
+
# @param [String] target_unit The target unit name.
|
50
|
+
#
|
51
|
+
# @return [Numeric|NilClass]
|
52
|
+
# The conversion factor, or +nil+ if not found in the cache.
|
53
|
+
#
|
54
|
+
# @author {Harshal V. Ladhe}[https://shivam091.github.io/]
|
55
|
+
# @since 5.2.0
|
56
|
+
def get(source_unit, target_unit)
|
57
|
+
cached_data.dig(source_unit, target_unit)
|
58
|
+
end
|
59
|
+
|
60
|
+
# Sets the conversion factor between source and target units in the cache.
|
61
|
+
#
|
62
|
+
# @param [String] source_unit The source unit name.
|
63
|
+
# @param [String] target_unit The target unit name.
|
64
|
+
# @param [Numeric] conversion_factor The conversion factor.
|
65
|
+
#
|
66
|
+
# @author {Harshal V. Ladhe}[https://shivam091.github.io/]
|
67
|
+
# @since 5.2.0
|
68
|
+
def set(source_unit, target_unit, conversion_factor)
|
69
|
+
cached_data[source_unit] ||= {}
|
70
|
+
cached_data[source_unit][target_unit] = conversion_factor
|
71
|
+
|
72
|
+
store_cache
|
73
|
+
end
|
74
|
+
|
75
|
+
# Clears the entire cache.
|
76
|
+
#
|
77
|
+
# @author {Harshal V. Ladhe}[https://shivam091.github.io/]
|
78
|
+
# @since 5.2.0
|
79
|
+
def clear_cache
|
80
|
+
@cached_data = {}
|
81
|
+
store_cache
|
82
|
+
end
|
83
|
+
|
84
|
+
private
|
85
|
+
|
86
|
+
# @private
|
87
|
+
# Loads the cache from the cache file.
|
88
|
+
#
|
89
|
+
# @return [Hash] The loaded cache data.
|
90
|
+
#
|
91
|
+
# @raise [Errno::ENOENT] If the cache file does not exist.
|
92
|
+
# @raise [Errno::EACCES]
|
93
|
+
# If the cache file cannot be accessed due to insufficient permissions.
|
94
|
+
# @raise [JSON::ParserError] If there's an error parsing the cache file.
|
95
|
+
#
|
96
|
+
# @author {Harshal V. Ladhe}[https://shivam091.github.io/]
|
97
|
+
# @since 5.2.0
|
98
|
+
def load_cache
|
99
|
+
return {} unless File.exist?(@cache_file)
|
100
|
+
|
101
|
+
begin
|
102
|
+
File.open(@cache_file, "r") { |file| JSON.load(file.read) }
|
103
|
+
rescue Errno::ENOENT, Errno::EACCES, JSON::ParserError => e
|
104
|
+
puts "Error loading cache"
|
105
|
+
{}
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
# @private
|
110
|
+
# Stores the current cache data to the cache file. +cached_data+ is stored in
|
111
|
+
# prettier form.
|
112
|
+
#
|
113
|
+
# @raise [Errno::ENOENT] If the cache file does not exist.
|
114
|
+
# @raise [Errno::EACCES]
|
115
|
+
# If the cache file cannot be accessed due to insufficient permissions.
|
116
|
+
# @raise [Errno::ENOSPC]
|
117
|
+
# If there's not enough space to write to the cache file.
|
118
|
+
# @raise [JSON::GeneratorError] If there's an error generating JSON data.
|
119
|
+
#
|
120
|
+
# @author {Harshal V. Ladhe}[https://shivam091.github.io/]
|
121
|
+
# @since 5.2.0
|
122
|
+
def store_cache
|
123
|
+
begin
|
124
|
+
File.open(@cache_file, "w") do |file|
|
125
|
+
file.write(JSON.pretty_generate(cached_data))
|
126
|
+
end
|
127
|
+
rescue Errno::ENOENT, Errno::EACCES, Errno::ENOSPC, JSON::GeneratorError => e
|
128
|
+
puts "Error saving cache: #{e.message}"
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
# @private
|
133
|
+
# Ensures that the cache directory exists. If the cache directory does not
|
134
|
+
# exist, it gets created.
|
135
|
+
#
|
136
|
+
# @raise [Errno::EEXIST] If the cache directory already exists.
|
137
|
+
# @raise [Errno::EACCES]
|
138
|
+
# If the cache directory cannot be accessed due to insufficient permissions.
|
139
|
+
# @raise [Errno::ENOSPC]
|
140
|
+
# If there's not enough space to create the cache directory.
|
141
|
+
#
|
142
|
+
# @author {Harshal V. Ladhe}[https://shivam091.github.io/]
|
143
|
+
# @since 5.2.0
|
144
|
+
def ensure_cache_directory_exists
|
145
|
+
begin
|
146
|
+
Dir.mkdir(CACHE_DIRECTORY) unless Dir.exist?(CACHE_DIRECTORY)
|
147
|
+
rescue Errno::EACCES, Errno::ENOSPC => e
|
148
|
+
puts "Error creating cache directory: #{e.message}"
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
# @private
|
153
|
+
# Builds and returns an absolute path of the cache file.
|
154
|
+
#
|
155
|
+
# This method first checks if the cache file name is specified for the unit
|
156
|
+
# group. If yes, it builds absolute path of the cache file using specified
|
157
|
+
# cache file name. If not, it builds file name from of the name of the unit
|
158
|
+
# group. This file name is then used to build absolute path of the cache file.
|
159
|
+
#
|
160
|
+
# @param [UnitGroup] unit_group The unit group associated with the cache.
|
161
|
+
#
|
162
|
+
# @return [String] An absolute path of the cache file.
|
163
|
+
#
|
164
|
+
# @author {Harshal V. Ladhe}[https://shivam091.github.io/]
|
165
|
+
# @since 5.2.0
|
166
|
+
def build_cache_file_path(unit_group)
|
167
|
+
cache_file_name = unit_group.cache_file || unit_group.to_s.split("::").last.underscore
|
168
|
+
cache_file_name = File.basename(cache_file_name, ".json") + ".json"
|
169
|
+
|
170
|
+
Pathname.new(File.join(CACHE_DIRECTORY, cache_file_name)).cleanpath
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
# -*- frozen_string_literal: true -*-
|
3
|
+
# -*- warn_indent: true -*-
|
4
|
+
|
5
|
+
module UnitMeasurements
|
6
|
+
# The +UnitMeasurements::Comparison+ mixin module is included in measurement
|
7
|
+
# classes to enable comparison operations (e.g., less than, equal to, greater
|
8
|
+
# than, etc.) between two measurements of the same unit group.
|
9
|
+
#
|
10
|
+
# This module is included in the +Measurement+ class to allow comparison of two
|
11
|
+
# measurements.
|
12
|
+
#
|
13
|
+
# @see Measurement
|
14
|
+
# @author {Harshal V. Ladhe}[https://shivam091.github.io/]
|
15
|
+
# @since 1.3.0
|
16
|
+
module Comparison
|
17
|
+
include Comparable
|
18
|
+
|
19
|
+
# This method is used to compare the quantity of two measurements. It
|
20
|
+
# implements the comparison logic based on the +<=>+ method defined in the
|
21
|
+
# +Comparable+ module.
|
22
|
+
#
|
23
|
+
# @example
|
24
|
+
# UnitMeasurements::Length.new(1, "km") == UnitMeasurements::Length.new(1, :km)
|
25
|
+
# => true
|
26
|
+
#
|
27
|
+
# UnitMeasurements::Length.parse("1 km") == UnitMeasurements::Length.parse("1000 m")
|
28
|
+
# => true
|
29
|
+
#
|
30
|
+
# UnitMeasurements::Length.parse("1 km") != UnitMeasurements::Length.parse("1 m")
|
31
|
+
# => true
|
32
|
+
#
|
33
|
+
# UnitMeasurements::Length.parse("1 km") < UnitMeasurements::Length.parse("0.5 km")
|
34
|
+
# => false
|
35
|
+
#
|
36
|
+
# UnitMeasurements::Length.parse("1 km") > UnitMeasurements::Length.parse("0.5 km")
|
37
|
+
# => true
|
38
|
+
#
|
39
|
+
# UnitMeasurements::Length.parse("1 km") <= UnitMeasurements::Length.parse("0.5 km")
|
40
|
+
# => false
|
41
|
+
#
|
42
|
+
# UnitMeasurements::Length.parse("1 km") >= UnitMeasurements::Length.parse("0.5 km")
|
43
|
+
# => true
|
44
|
+
#
|
45
|
+
# UnitMeasurements::Length.new(1, "ft").between?(UnitMeasurements::Length.new(12, "in"), UnitMeasurements::Length.new(24, "in"))
|
46
|
+
# => true
|
47
|
+
#
|
48
|
+
# @param [Measurement] object The measurement instance to compare with.
|
49
|
+
#
|
50
|
+
# @return
|
51
|
+
# +nil+ if the comparison is not possible (e.g., if the +object+ is not of
|
52
|
+
# the same unit group). A negative integer if +self+ is less than +object+.
|
53
|
+
# +Zero+ if self is equal to +object+. A positive integer if +self+ is
|
54
|
+
# greater than +object+.
|
55
|
+
#
|
56
|
+
# @author {Harshal V. Ladhe}[https://shivam091.github.io/]
|
57
|
+
# @since 1.3.0
|
58
|
+
def <=>(object)
|
59
|
+
return nil unless object.is_a?(self.class)
|
60
|
+
|
61
|
+
quantity <=> object.convert_to(unit.name).quantity
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
# -*- frozen_stringing_literal: true -*-
|
3
|
+
# -*- warn_indent: true -*-
|
4
|
+
|
5
|
+
module UnitMeasurements
|
6
|
+
# The +UnitMeasurements::Configuration+ class maintains and manages the globally
|
7
|
+
# configurable options of +*unit_measurements*+.
|
8
|
+
#
|
9
|
+
# @note
|
10
|
+
# This class is responsible for configuring globally configurable options of
|
11
|
+
# +*unit_measurements*+.
|
12
|
+
#
|
13
|
+
# @author {Harshal V. Ladhe}[https://shivam091.github.io/]
|
14
|
+
# @since 5.3.0
|
15
|
+
class Configuration
|
16
|
+
# Get the current value of the +use_cache+ option.
|
17
|
+
#
|
18
|
+
# @note
|
19
|
+
# This option controls whether caching is enabled for converting measurements.
|
20
|
+
# Defaults to +false+.
|
21
|
+
#
|
22
|
+
# @return [TrueClass|FalseClass]
|
23
|
+
# Returns +true+ if caching is enabled, otherwise +false+.
|
24
|
+
#
|
25
|
+
# @see Cache
|
26
|
+
# @author {Harshal V. Ladhe}[https://shivam091.github.io/]
|
27
|
+
# @since 5.3.0
|
28
|
+
attr_reader :use_cache
|
29
|
+
|
30
|
+
# Initializes a new +Configuration+ instance with default values of configurable
|
31
|
+
# options.
|
32
|
+
#
|
33
|
+
# @author {Harshal V. Ladhe}[https://shivam091.github.io/]
|
34
|
+
# @since 5.3.0
|
35
|
+
def initialize
|
36
|
+
self.use_cache = false
|
37
|
+
end
|
38
|
+
|
39
|
+
# Sets a value for the +use_cache+ option.
|
40
|
+
#
|
41
|
+
# It controls whether caching is enabled for converting measurements. When
|
42
|
+
# caching is enabled, previously computed conversion factors are stored for
|
43
|
+
# future use, improving conversion performance.
|
44
|
+
#
|
45
|
+
# @param [TrueClass|FalseClass] use_cache
|
46
|
+
# +true+ if caching should be used while converting the measurement otherwise
|
47
|
+
# +false+.
|
48
|
+
#
|
49
|
+
# @return [TrueClass|FalseClass] The updated value of +use_cache+.
|
50
|
+
#
|
51
|
+
# @raise [BaseError] if +use_cache+ is not a boolean value.
|
52
|
+
#
|
53
|
+
# @see Cache
|
54
|
+
# @author {Harshal V. Ladhe}[https://shivam091.github.io/]
|
55
|
+
# @since 5.3.0
|
56
|
+
def use_cache=(use_cache)
|
57
|
+
unless [true, false].include?(use_cache)
|
58
|
+
raise ArgumentError, "Configuration#use_cache= only accepts true or false, but received #{use_cache}"
|
59
|
+
end
|
60
|
+
|
61
|
+
@use_cache = use_cache
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|