unit_measurements 5.1.0 → 5.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a8e055ec9a81c6c27050136128e36d6bceba2b3292e6494a2bbd3305ccbcb20b
4
- data.tar.gz: 381e87126aaa72bd762f537fe6be8638adbf07105ed992009a8298f6d6159de4
3
+ metadata.gz: 30ecc167254df71dd7e6415ea85e4042837d37294041d5fc1791e395711a5774
4
+ data.tar.gz: c7e5382424fbb305607a312e6fec931e0967c09d402f08ce88343909a7c0a89e
5
5
  SHA512:
6
- metadata.gz: b8b3831f2e780623cd1d7d8e86d7f4687c58ed380dabccfa2eff81ab1c9cb13c8295970c1980acbf920ee00bffcba6fd3d310563fc3d27ecbc6946e14fadddea
7
- data.tar.gz: d45c0207c736ca65b6041483d609a6390784fd60334c49220d36580f5fb3e3882c1f5a49d5951e6bc3f46386769cd18168bb8fcb6e897fb9b742fa3445acd8b7
6
+ metadata.gz: b50e6cf5076ed8a27b16b81246c864cb0b3dcbeba9e91b400d7e377f91bd9497667312f2ff551cb43abc4a3520ee11d31f4926b20bbf40010f0895d19d0c32e7
7
+ data.tar.gz: 948c1541e6e57613839a88dee8c5f99e583f0137c2bfc3114fa1e9eb758bce608b6f194adbab2f8e85216768127630ec65c90bb4fd685054cbb69000fa0a9a9e
@@ -23,7 +23,7 @@ jobs:
23
23
  - name: Install Dependencies
24
24
  run: gem install yard
25
25
  - name: Generate Documentation
26
- run: yardoc --private --exclude "unit_groups/*"
26
+ run: yardoc
27
27
  - name: Deploy to GitHub Pages
28
28
  uses: peaceiris/actions-gh-pages@v3.9.3
29
29
  with:
data/.gitignore CHANGED
@@ -6,6 +6,7 @@
6
6
  /pkg/
7
7
  /spec/reports/
8
8
  /tmp/
9
+ /cache/*.json
9
10
 
10
11
  # rspec failure tracking
11
12
  .rspec_status
data/.yardopts ADDED
@@ -0,0 +1,2 @@
1
+ --exclude unit_groups/*
2
+ --private
data/CHANGELOG.md CHANGED
@@ -1,3 +1,21 @@
1
+ ## [5.2.0](https://github.com/shivam091/unit_measurements/compare/v5.1.1...v5.2.0) - 2023-10-22
2
+
3
+ ### What's new
4
+
5
+ - Added ability to set name of the cache file for the unit group.
6
+ - Added support for caching conversion factors between units of the unit group.
7
+
8
+ ----------
9
+
10
+ ## [5.1.1](https://github.com/shivam091/unit_measurements/compare/v5.1.0...v5.1.1) - 2023-10-20
11
+
12
+ ### What's updated
13
+
14
+ - Updated readme and documentation.
15
+ - Updated documentation hosting link to `https://shivam091.github.io/unit_measurements`.
16
+
17
+ ----------
18
+
1
19
  ## [5.1.0](https://github.com/shivam091/unit_measurements/compare/v5.0.0...v5.1.0) - 2023-10-19
2
20
 
3
21
  ### What's new
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- unit_measurements (5.1.0)
4
+ unit_measurements (5.2.0)
5
5
  activesupport (~> 7.0)
6
6
 
7
7
  GEM
data/README.md CHANGED
@@ -24,11 +24,12 @@ The `unit_measurements` gem is designed to simplify the handling of units for sc
24
24
 
25
25
  ## Features
26
26
 
27
- - Easy unit conversion.
28
- - Lightweight and extensible for adding custom units and conversions.
29
- - Supports various [unit groups](https://github.com/shivam091/unit_measurements/blob/main/units.md).
30
- - Well-documented: [Documentation](https://rubydoc.info/gems/unit_measurements).
31
- - Parses complex, fractional, mixed fractional, scientific numbers, and ratios.
27
+ 1. Provides easy conversion between units.
28
+ 2. Lightweight and easily extensible to include other units and conversions.
29
+ 3. Built in support for various [unit groups](https://github.com/shivam091/unit_measurements/blob/main/units.md).
30
+ 4. Ability to parse strings representing complex, fractional, mixed fractional, scientific numbers, and ratios.
31
+ 5. Well organized and descriptive documentation published [here](https://shivam091.github.io/unit_measurements).
32
+ 6. Supports caching of conversion factors between different units of the unit group.
32
33
 
33
34
  ## Disclaimer
34
35
 
@@ -74,6 +75,8 @@ UnitMeasurements::Length.new(1, "km")
74
75
  This gem allows you to convert among units of same unit group. You can convert measurement to other unit using `#convert_to`
75
76
  (aliased as `#to`, `#in`, and `#as`) or `#convert_to!` (aliased as `#to!`, `#in!`, and `#as!`) methods.
76
77
 
78
+ These methods provide `use_cache` parameter which can be used to indicate whether the caching of conversion factors should happen.
79
+
77
80
  You can use `#convert_to` as:
78
81
 
79
82
  ```ruby
@@ -104,6 +107,8 @@ UnitMeasurements::Length.new(100, "m").convert_to("ft").convert_to!("in")
104
107
 
105
108
  **Parse string without having to split out the quantity and source unit:**
106
109
 
110
+ This method provides `use_cache` parameter which can be used to indicate whether the caching of conversion factors should happen.
111
+
107
112
  ```ruby
108
113
  UnitMeasurements::Length.parse("1 km")
109
114
  #=> 1.0 km
@@ -127,7 +132,7 @@ UnitMeasurements::Length.parse("2e+2 km to m")
127
132
  #=> 200000.0 m
128
133
  ```
129
134
  You can check supported special characters for exponents
130
- [here](https://rubydoc.info/gems/unit_measurements/UnitMeasurements/Normalizer.html).
135
+ [here](https://shivam091.github.io/unit_measurements/UnitMeasurements/Normalizer.html).
131
136
 
132
137
  **Parse complex numbers, source unit, and (or) target unit:**
133
138
 
@@ -148,7 +153,7 @@ UnitMeasurements::Length.parse("2/3 km to m")
148
153
  ```
149
154
 
150
155
  You can check supported special characters for fractional notations
151
- [here](https://rubydoc.info/gems/unit_measurements/UnitMeasurements/Normalizer.html).
156
+ [here](https://shivam091.github.io/unit_measurements/UnitMeasurements/Normalizer.html).
152
157
 
153
158
  **Parse ratios, source unit, and (or) target unit:**
154
159
 
@@ -170,7 +175,7 @@ UnitMeasurements::Length.new(100, "m").to("in").format("%.4<quantity>f %<unit>s"
170
175
  ```
171
176
 
172
177
  You can check more about formatting along with their examples
173
- [here](https://rubydoc.info/gems/unit_measurements/UnitMeasurements/Formatter.html).
178
+ [here](https://shivam091.github.io/unit_measurements/UnitMeasurements/Formatter.html).
174
179
 
175
180
  **Extract the unit and the quantity from measurement:**
176
181
 
@@ -254,6 +259,12 @@ UnitMeasurements::Length.unit_or_alias?("metre")
254
259
  #=> true
255
260
  ```
256
261
 
262
+ **Clear cached data for the unit group:**
263
+
264
+ ```ruby
265
+ UnitMeasurements::Length.clear_cache
266
+ ```
267
+
257
268
  ### Comparisons
258
269
 
259
270
  You have ability to compare the measurements with the same or different units within the same unit group.
@@ -265,7 +276,7 @@ UnitMeasurements::Length.parse("1 km") != UnitMeasurements::Length.parse("1 m")
265
276
  ```
266
277
 
267
278
  You can check supported comparisons along with their examples
268
- [here](https://rubydoc.info/gems/unit_measurements/UnitMeasurements/Comparison.html).
279
+ [here](https://shivam091.github.io/unit_measurements/UnitMeasurements/Comparison.html).
269
280
 
270
281
  ### Arithmetic
271
282
 
@@ -282,7 +293,7 @@ UnitMeasurements::Length.new(2, "km") * 2+2i
282
293
  ```
283
294
 
284
295
  You can check supported arithmetic operations along with their examples
285
- [here](https://rubydoc.info/gems/unit_measurements/UnitMeasurements/Arithmetic.html).
296
+ [here](https://shivam091.github.io/unit_measurements/UnitMeasurements/Arithmetic.html).
286
297
 
287
298
  ### Math
288
299
 
@@ -294,7 +305,7 @@ UnitMeasurements::Length.new(17.625, "m").round
294
305
  ```
295
306
 
296
307
  You can check supported mathematical functions along with their examples
297
- [here](https://rubydoc.info/gems/unit_measurements/UnitMeasurements/Math.html).
308
+ [here](https://shivam091.github.io/unit_measurements/UnitMeasurements/Math.html).
298
309
 
299
310
  ### Conversions
300
311
 
@@ -307,7 +318,7 @@ UnitMeasurements::Length.new(2.25567, "km").to_i
307
318
  ```
308
319
 
309
320
  You can check more about them along with their examples
310
- [here](https://rubydoc.info/gems/unit_measurements/UnitMeasurements/Conversion.html).
321
+ [here](https://shivam091.github.io/unit_measurements/UnitMeasurements/Conversion.html).
311
322
 
312
323
  ## Units
313
324
 
@@ -413,6 +424,9 @@ UnitMeasurements::Time = UnitMeasurements.build do
413
424
  # You can also specify unit value as an array.
414
425
  unit "h", value: [60, "min"], aliases: ["day", "days"]
415
426
  end
427
+
428
+ # Sets the name of the cache file (optional).
429
+ cache "time_cache.json"
416
430
  end
417
431
  ```
418
432
 
@@ -36,6 +36,8 @@ module UnitMeasurements
36
36
  # system :imperial do
37
37
  # unit "in", value: "25.4 mm", aliases: ['"', "inch", "inches"]
38
38
  # end
39
+ #
40
+ # cache "length.json"
39
41
  # end
40
42
  #
41
43
  # @param block
@@ -78,6 +80,7 @@ module UnitMeasurements
78
80
  end
79
81
 
80
82
  # The following requires load various components of the unit measurements library.
83
+ require "unit_measurements/cache"
81
84
  require "unit_measurements/unit_group_builder"
82
85
  require "unit_measurements/unit"
83
86
  require "unit_measurements/unit_group"
@@ -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
@@ -120,6 +120,11 @@ module UnitMeasurements
120
120
  # Converts the measurement to a +target_unit+ and returns new instance of the
121
121
  # measurement.
122
122
  #
123
+ # When +use_cache+ value is true, conversion factor between units are checked
124
+ # in cache file of the unit group. If cached conversion factor is present in
125
+ # the cache file, it is used for conversion otherwise conversion factor is
126
+ # stored in the cache before converting the measurement to the +target_unit+.
127
+ #
123
128
  # @example
124
129
  # UnitMeasurements::Length.new(1, "m").convert_to("cm")
125
130
  # => 100.0 cm
@@ -127,9 +132,14 @@ module UnitMeasurements
127
132
  # UnitMeasurements::Length.new(1, "cm").convert_to("primitive")
128
133
  # => 0.01 m
129
134
  #
135
+ # UnitMeasurements::Length.new(1, "m").convert_to("cm", use_cache: true)
136
+ # => 100.0 cm
137
+ #
130
138
  # @param [String|Symbol] target_unit
131
139
  # The target unit for conversion. Specifing +primitive+ will convert the
132
140
  # measurement to a primitive unit of the unit group.
141
+ # @param [TrueClass|FalseClass] use_cache
142
+ # Indicates whether to use cached conversion factors.
133
143
  #
134
144
  # @return [Measurement]
135
145
  # A new +Measurement+ instance with the converted +quantity+ and
@@ -137,16 +147,15 @@ module UnitMeasurements
137
147
  #
138
148
  # @author {Harshal V. Ladhe}[https://shivam091.github.io/]
139
149
  # @since 1.0.0
140
- def convert_to(target_unit)
150
+ def convert_to(target_unit, use_cache: false)
141
151
  target_unit = if target_unit.to_s.eql?("primitive")
142
152
  self.class.unit_group.primitive
143
153
  else
144
154
  unit_from_unit_or_name!(target_unit)
145
155
  end
146
-
147
156
  return self if target_unit == unit
148
157
 
149
- conversion_factor = (unit.conversion_factor / target_unit.conversion_factor)
158
+ conversion_factor = calculate_conversion_factor(target_unit, use_cache)
150
159
 
151
160
  self.class.new((quantity * conversion_factor), target_unit)
152
161
  end
@@ -160,7 +169,17 @@ module UnitMeasurements
160
169
  # UnitMeasurements::Length.new(1, "m").convert_to!("cm")
161
170
  # => 100.0 cm
162
171
  #
163
- # @param [String|Symbol] target_unit The target unit for conversion.
172
+ # UnitMeasurements::Length.new(1, "cm").convert_to!("primitive")
173
+ # => 0.01 m
174
+ #
175
+ # UnitMeasurements::Length.new(1, "m").convert_to!("cm", use_cache: true)
176
+ # => 100.0 cm
177
+ #
178
+ # @param [String|Symbol] target_unit
179
+ # The target unit for conversion. Specifing +primitive+ will convert the
180
+ # measurement to a primitive unit of the unit group.
181
+ # @param [TrueClass|FalseClass] use_cache
182
+ # Indicates whether to use cached conversion factors.
164
183
  #
165
184
  # @return [Measurement]
166
185
  # The current +Measurement+ instance with updated +quantity+ and +unit+.
@@ -168,8 +187,8 @@ module UnitMeasurements
168
187
  # @see #convert_to
169
188
  # @author {Harshal V. Ladhe}[https://shivam091.github.io/]
170
189
  # @since 1.0.0
171
- def convert_to!(target_unit)
172
- measurement = convert_to(target_unit)
190
+ def convert_to!(target_unit, use_cache: false)
191
+ measurement = convert_to(target_unit, use_cache: use_cache)
173
192
  @quantity, @unit = measurement.quantity, measurement.unit
174
193
 
175
194
  self
@@ -219,16 +238,20 @@ module UnitMeasurements
219
238
  extend Forwardable
220
239
 
221
240
  # Methods delegated from the unit group.
222
- def_delegators :unit_group, :primitive, :units, :unit_names, :unit_with_name_and_aliases,
223
- :unit_names_with_aliases, :unit_for, :unit_for!, :defined?,
224
- :unit_or_alias?, :[], :units_for, :units_for!
241
+ def_delegators :unit_group, :primitive, :units, :cache_file, :unit_names,
242
+ :unit_with_name_and_aliases, :unit_names_with_aliases,
243
+ :unit_for, :unit_for!, :defined?, :unit_or_alias?, :[],
244
+ :units_for, :units_for!
225
245
 
226
246
  # Parses an input string and returns a +Measurement+ instance depending on
227
247
  # the input string. This method first normalizes the +input+ internally,
228
248
  # using the +Normalizer+ before parsing it using the +Parser+.
229
249
  #
250
+ # You can separate *source* and *target* units from each other in +input+
251
+ # using +to+, +in+, or +as+.
252
+ #
230
253
  # If only the source unit is provided, it returns a new +Measurement+
231
- # instance with the quantity in the source unit.If both source and target
254
+ # instance with the quantity in the source unit. If both source and target
232
255
  # units are provided in the input string, it returns a new +Measurement+
233
256
  # instance with the quantity converted to the target unit.
234
257
  #
@@ -237,7 +260,7 @@ module UnitMeasurements
237
260
  # => 2.0+3.0i km
238
261
  #
239
262
  # @example Parsing string representing a complex number, source, and target units:
240
- # UnitMeasurements::Length.parse("2+3i km to m")
263
+ # UnitMeasurements::Length.parse("2+3i km in m")
241
264
  # => 2000.0+3000.0i m
242
265
  #
243
266
  # @example Parsing string representing a rational or mixed rational number and source unit:
@@ -260,10 +283,10 @@ module UnitMeasurements
260
283
  # UnitMeasurements::Length.parse("2/3 km to m")
261
284
  # => 666.666666666667 m
262
285
  #
263
- # UnitMeasurements::Length.parse("2 ½ km to m")
286
+ # UnitMeasurements::Length.parse("2 ½ km in m")
264
287
  # => 2500.0 m
265
288
  #
266
- # UnitMeasurements::Length.parse("2 1/2 km to m")
289
+ # UnitMeasurements::Length.parse("2 1/2 km as m")
267
290
  # => 2500.0 m
268
291
  #
269
292
  # @example Parsing string representing a scientific number and source unit:
@@ -281,7 +304,7 @@ module UnitMeasurements
281
304
  # UnitMeasurements::Length.parse("2e+2 km to m")
282
305
  # => 200000.0 m
283
306
  #
284
- # UnitMeasurements::Length.parse("2e⁻² km to m")
307
+ # UnitMeasurements::Length.parse("2e⁻² km as m")
285
308
  # => 20.0 m
286
309
  #
287
310
  # @example Parsing string representing a ratio and source unit:
@@ -289,10 +312,12 @@ module UnitMeasurements
289
312
  # => 0.5 km
290
313
  #
291
314
  # @example Parsing string representing a ratio, source, and target units:
292
- # UnitMeasurements::Length.parse("1:2 km to m")
315
+ # UnitMeasurements::Length.parse("1:2 km in m")
293
316
  # => 500.0 m
294
317
  #
295
318
  # @param [String] input The input string to be parsed.
319
+ # @param [TrueClass|FalseClass] use_cache
320
+ # Indicates whether to use cached conversion factors.
296
321
  #
297
322
  # @return [Measurement] The +Measurement+ instance.
298
323
  #
@@ -303,11 +328,42 @@ module UnitMeasurements
303
328
  # @see #convert_to
304
329
  # @author {Harshal V. Ladhe}[https://shivam091.github.io/]
305
330
  # @since 1.0.0
306
- def parse(input)
331
+ def parse(input, use_cache: false)
307
332
  input = Normalizer.normalize(input)
308
333
  source, target = input.match(CONVERSION_STRING_REGEXP)&.captures
309
334
 
310
- target ? _parse(source).convert_to(target) : _parse(source)
335
+ target ? _parse(source).convert_to(target, use_cache: use_cache) : _parse(source)
336
+ end
337
+
338
+ # Returns the +Cache+ instance for the unit group to store and retrieve
339
+ # conversion factors.
340
+ #
341
+ # @return [Cache] The +Cache+ instance.
342
+ #
343
+ # @example
344
+ # UnitMeasurements::Length.cached
345
+ # => #<UnitMeasurements::Cache:0x00007fe407249750>
346
+ #
347
+ # @see Cache
348
+ # @author {Harshal V. Ladhe}[https://shivam091.github.io/]
349
+ # @since 5.2.0
350
+ def cached
351
+ @cached ||= Cache.new(self)
352
+ end
353
+
354
+ # Clears the cached conversion factors of the unit group.
355
+ #
356
+ # @return [void]
357
+ #
358
+ # @example
359
+ # UnitMeasurements::Length.clear_cache
360
+ #
361
+ # @see Cache#clear_cache
362
+ #
363
+ # @author {Harshal V. Ladhe}[https://shivam091.github.io/]
364
+ # @since 5.2.0
365
+ def clear_cache
366
+ cached.clear_cache
311
367
  end
312
368
 
313
369
  private
@@ -384,5 +440,35 @@ module UnitMeasurements
384
440
  def unit_from_unit_or_name!(value)
385
441
  value.is_a?(Unit) ? value : self.class.send(:unit_group).unit_for!(value)
386
442
  end
443
+
444
+ # Calculates the conversion factor between the current unit and the target
445
+ # unit.
446
+ #
447
+ # If caching is enabled and a cached factor is available, it will be used.
448
+ # Otherwise, the conversion factor will be computed and, if caching is
449
+ # enabled, stored in the cache.
450
+ #
451
+ # @param [Unit] target_unit The target unit for conversion.
452
+ # @param [TrueClass|FalseClass] use_cache
453
+ # Indicates whether caching should be used.
454
+ #
455
+ # @return [Numeric] The conversion factor.
456
+ #
457
+ # @see Unit
458
+ # @see #convert_to
459
+ #
460
+ # @note If caching is enabled, the calculated conversion factor will be stored in the cache.
461
+ #
462
+ # @author {Harshal V. Ladhe}[https://shivam091.github.io/]
463
+ # @since 5.2.0
464
+ def calculate_conversion_factor(target_unit, use_cache)
465
+ if use_cache && (cached_factor = self.class.cached.get(unit.name, target_unit.name))
466
+ cached_factor
467
+ else
468
+ factor = unit.conversion_factor / target_unit.conversion_factor
469
+ self.class.cached.set(unit.name, target_unit.name, factor) if use_cache
470
+ factor
471
+ end
472
+ end
387
473
  end
388
474
  end
@@ -36,16 +36,30 @@ module UnitMeasurements
36
36
  # @since 1.0.0
37
37
  attr_reader :units
38
38
 
39
+ # The name of the cache file.
40
+ #
41
+ # @example
42
+ # UnitMeasurements::Length.cache_file
43
+ # => "length.json"
44
+ #
45
+ # @return [String] The name of the cache file.
46
+ #
47
+ # @author {Harshal V. Ladhe}[https://shivam091.github.io/]
48
+ # @since 5.2.0
49
+ attr_reader :cache_file
50
+
39
51
  # Initializes a new +UnitGroup+ instance.
40
52
  #
41
53
  # @param [String|Symbol, optional] primitive The name of the primitive unit.
42
54
  # @param [Array<Unit>] units An array of +Unit+ instances.
55
+ # @param [String] cache_file The name of the cache file.
43
56
  #
44
57
  # @author {Harshal V. Ladhe}[https://shivam091.github.io/]
45
58
  # @since 1.0.0
46
- def initialize(primitive, units)
59
+ def initialize(primitive, units, cache_file)
47
60
  @units = units.map { |unit| unit.with(unit_group: self) }
48
61
  @primitive = unit_for!(primitive) if primitive
62
+ @cache_file = cache_file
49
63
  end
50
64
 
51
65
  # Returns the unit instance for a given unit name. It returns +nil+ if unit
@@ -82,7 +82,7 @@ module UnitMeasurements
82
82
  # @author {Harshal V. Ladhe}[https://shivam091.github.io/]
83
83
  # @since 1.0.0
84
84
  def build
85
- UnitGroup.new(@primitive, @units)
85
+ UnitGroup.new(@primitive, @units, @cache_file)
86
86
  end
87
87
 
88
88
  # Defines the +unit system+ within the unit group and evaluates the provided
@@ -130,6 +130,19 @@ module UnitMeasurements
130
130
  @primitive = primitive
131
131
  end
132
132
 
133
+ # Sets the name of the cache file for the unit group.
134
+ #
135
+ # @example
136
+ # cache "conversion_cache.json"
137
+ #
138
+ # @param [String] cache_file The name of the cache file.
139
+ #
140
+ # @author {Harshal V. Ladhe}[https://shivam091.github.io/]
141
+ # @since 5.2.0
142
+ def cache(cache_file)
143
+ @cache_file = cache_file
144
+ end
145
+
133
146
  private
134
147
 
135
148
  # @private
@@ -4,5 +4,5 @@
4
4
 
5
5
  module UnitMeasurements
6
6
  # Current stable version.
7
- VERSION = "5.1.0"
7
+ VERSION = "5.2.0"
8
8
  end
@@ -22,7 +22,7 @@ Gem::Specification.new do |spec|
22
22
  spec.metadata["allowed_push_host"] = "https://rubygems.org"
23
23
 
24
24
  spec.metadata["homepage_uri"] = spec.homepage
25
- spec.metadata["documentation_uri"] = "https://rubydoc.info/gems/unit_measurements"
25
+ spec.metadata["documentation_uri"] = "https://shivam091.github.io/unit_measurements"
26
26
  spec.metadata["source_code_uri"] = "https://github.com/shivam091/unit_measurements"
27
27
  spec.metadata["changelog_uri"] = "https://github.com/shivam091/unit_measurements/blob/main/CHANGELOG.md"
28
28
  spec.metadata["bug_tracker_uri"] = "https://github.com/shivam091/unit_measurements/issues"
data/units.md CHANGED
@@ -1,12 +1,12 @@
1
1
  # Bundled unit groups and units
2
2
 
3
- As there are lots of units bundled with `unit_measurements`, we recommend you to check below list of
4
- bundled units before converting your measurements.
3
+ As there are lots of units bundled with `unit_measurements`, we recommend you to
4
+ check below list of bundled units before converting your measurements.
5
5
 
6
6
  **Notes:**
7
- 1. Unit names suffixed with `*` support all [Decimal SI prefixes](README.md#decimal-si-prefixes).
8
- 2. Unit names suffixed with `**` support all [Decimal SI prefixes](README.md#decimal-si-prefixes)
9
- and [Binary SI prefixes](README.md#binary-si-prefixes).
7
+ 1. Unit names suffixed with `*` support [Decimal SI prefixes](README.md#decimal-si-prefixes).
8
+ 2. Unit names suffixed with `**` support [Binary SI prefixes](README.md#binary-si-prefixes)
9
+ in addition to [Decimal SI prefixes](README.md#decimal-si-prefixes).
10
10
  3. Primitive unit of the unit group is in _emphasised typeface_.
11
11
 
12
12
  ## 1. Length/Distance
@@ -125,7 +125,7 @@ These units are defined in `UnitMeasurements::Area`.
125
125
  | 12 | fur² | fur^2, sq fur, square furlong, square furlongs |
126
126
  | 13 | rod² | rod^2, sq rod, square rod, square rods |
127
127
 
128
- ## 9. Volume
128
+ ## 9. Volume & Capacity
129
129
 
130
130
  These units are defined in `UnitMeasurements::Volume`.
131
131
 
@@ -328,7 +328,7 @@ These units are defined in `UnitMeasurements::ElectricalElastance`.
328
328
  | _1_ | _D*_ | _F⁻¹, daraf, darafs, reciprocal farad, reciprocal farads_ |
329
329
  | 2 | V/C | V·C⁻¹, volt/coulomb, volts/coulomb, volt per coulomb, volts per coulomb |
330
330
 
331
- ## 24. Electrical resistance
331
+ ## 24. Electrical resistance/Impedance
332
332
 
333
333
  These units are defined in `UnitMeasurements::ElectricalResistance`.
334
334
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: unit_measurements
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.1.0
4
+ version: 5.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-10-19 00:00:00.000000000 Z
11
+ date: 2023-10-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -97,6 +97,7 @@ files:
97
97
  - ".github/workflows/pages.yml"
98
98
  - ".gitignore"
99
99
  - ".rspec"
100
+ - ".yardopts"
100
101
  - CHANGELOG.md
101
102
  - Gemfile
102
103
  - Gemfile.lock
@@ -106,6 +107,7 @@ files:
106
107
  - lib/unit_measurements.rb
107
108
  - lib/unit_measurements/arithmetic.rb
108
109
  - lib/unit_measurements/base.rb
110
+ - lib/unit_measurements/cache.rb
109
111
  - lib/unit_measurements/comparison.rb
110
112
  - lib/unit_measurements/conversion.rb
111
113
  - lib/unit_measurements/errors/parse_error.rb
@@ -178,7 +180,7 @@ licenses:
178
180
  metadata:
179
181
  allowed_push_host: https://rubygems.org
180
182
  homepage_uri: https://github.com/shivam091/unit_measurements
181
- documentation_uri: https://rubydoc.info/gems/unit_measurements
183
+ documentation_uri: https://shivam091.github.io/unit_measurements
182
184
  source_code_uri: https://github.com/shivam091/unit_measurements
183
185
  changelog_uri: https://github.com/shivam091/unit_measurements/blob/main/CHANGELOG.md
184
186
  bug_tracker_uri: https://github.com/shivam091/unit_measurements/issues