unit_measurements 5.1.1 → 5.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 +4 -4
- data/.gitignore +1 -0
- data/CHANGELOG.md +21 -0
- data/Gemfile.lock +1 -1
- data/README.md +43 -11
- data/lib/unit_measurements/base.rb +58 -4
- data/lib/unit_measurements/cache.rb +173 -0
- data/lib/unit_measurements/configuration.rb +64 -0
- data/lib/unit_measurements/measurement.rb +105 -17
- data/lib/unit_measurements/unit_group.rb +15 -1
- data/lib/unit_measurements/unit_group_builder.rb +14 -1
- data/lib/unit_measurements/version.rb +1 -1
- data/units.md +7 -7
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 006027cb5f557c69f5ba083f6624cf9e424fcb00cc794b8f50912907538a3689
|
4
|
+
data.tar.gz: 4db6ec5c12a752191933c5aa6d99837c1e2dc5e8269e5d05339a6e9b631d3e7f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fe13840ae30879e2068b4a0628e073259d8faab8efc615f0ff6da1b4fc7307b2a4285ebe44425fc4bedf26263e02a5f29e34df6ac792e3c16429f214262dbc31
|
7
|
+
data.tar.gz: d9f28aecb8b8dea511466a8e4f71288581c35407d841b20d65006a9bb8e3dad8d3ec53da4b2f83c0235d9a919a2dccf572371957c1010a8d449c7b11bdf1947f
|
data/.gitignore
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,24 @@
|
|
1
|
+
## [5.3.0](https://github.com/shivam091/unit_measurements/compare/v5.2.0...v5.3.0) - 2023-10-24
|
2
|
+
|
3
|
+
### What's new
|
4
|
+
|
5
|
+
- Added ability set globally configurable options for **`unit_measurements`**.
|
6
|
+
|
7
|
+
### What's improved
|
8
|
+
|
9
|
+
- Code coverage improvements.
|
10
|
+
|
11
|
+
----------
|
12
|
+
|
13
|
+
## [5.2.0](https://github.com/shivam091/unit_measurements/compare/v5.1.1...v5.2.0) - 2023-10-22
|
14
|
+
|
15
|
+
### What's new
|
16
|
+
|
17
|
+
- Added ability to set name of the cache file for the unit group.
|
18
|
+
- Added support for caching conversion factors between units of the unit group.
|
19
|
+
|
20
|
+
----------
|
21
|
+
|
1
22
|
## [5.1.1](https://github.com/shivam091/unit_measurements/compare/v5.1.0...v5.1.1) - 2023-10-20
|
2
23
|
|
3
24
|
### What's updated
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -22,13 +22,16 @@ to numerous errors.
|
|
22
22
|
|
23
23
|
The `unit_measurements` gem is designed to simplify the handling of units for scientific calculations.
|
24
24
|
|
25
|
-
## Features
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
4.
|
31
|
-
|
25
|
+
## Key Features
|
26
|
+
1. **Simplified Measurement Conversion:** Easily convert measurements between compatible units, reducing the likelihood of errors in scientific calculations.
|
27
|
+
2. **Extensible Unit Groups:** Effortlessly build own unit groups with specific units and conversions tailored to your needs.
|
28
|
+
3. **Built-in Unit Groups:** Comes bundled with a wide range of standard [unit groups](https://github.com/shivam091/unit_measurements/blob/main/units.md),
|
29
|
+
covering various units.
|
30
|
+
4. **String Parsing Capabilities:** Effortlessly parse strings representing complex, fractional, mixed fractional, scientific numbers, and ratios directly
|
31
|
+
saving you the hassle of manually extracting and converting them.
|
32
|
+
5. **Comprehensive Documentation:** Well-organized and descriptive [documentation](https://shivam091.github.io/unit_measurements) for quick reference and implementation guidance.
|
33
|
+
6. **Configurable Options:** Fine-tune behavior with configurable options, including caching for enhanced performance.
|
34
|
+
7. **Error Handling:** Robust error handling ensures stability and reliability during conversions.
|
32
35
|
|
33
36
|
## Disclaimer
|
34
37
|
|
@@ -56,6 +59,23 @@ Or otherwise simply install it yourself as:
|
|
56
59
|
|
57
60
|
`$ gem install unit_measurements`
|
58
61
|
|
62
|
+
## Configuration
|
63
|
+
|
64
|
+
`unit_measurements` is designed to work out of the box, but you can customize its behavior by placing
|
65
|
+
the configuration block in an initializer file before requiring the library files:
|
66
|
+
|
67
|
+
```ruby
|
68
|
+
UnitMeasurements.configure do |config|
|
69
|
+
config.use_cache = false
|
70
|
+
end
|
71
|
+
```
|
72
|
+
|
73
|
+
The current available configurable options are:
|
74
|
+
|
75
|
+
| Option | Default value | Description |
|
76
|
+
| ------ | ------------- | ----------- |
|
77
|
+
| **use_cache** | false | Set to `true` to enable caching during conversions. |
|
78
|
+
|
59
79
|
## Usage
|
60
80
|
|
61
81
|
The **`UnitMeasurements::Measurement`** class is responsible for conversion of quantity to various compatible units
|
@@ -74,6 +94,8 @@ UnitMeasurements::Length.new(1, "km")
|
|
74
94
|
This gem allows you to convert among units of same unit group. You can convert measurement to other unit using `#convert_to`
|
75
95
|
(aliased as `#to`, `#in`, and `#as`) or `#convert_to!` (aliased as `#to!`, `#in!`, and `#as!`) methods.
|
76
96
|
|
97
|
+
These methods provide `use_cache` parameter which can be used to indicate whether the caching of conversion factors should happen.
|
98
|
+
|
77
99
|
You can use `#convert_to` as:
|
78
100
|
|
79
101
|
```ruby
|
@@ -104,6 +126,8 @@ UnitMeasurements::Length.new(100, "m").convert_to("ft").convert_to!("in")
|
|
104
126
|
|
105
127
|
**Parse string without having to split out the quantity and source unit:**
|
106
128
|
|
129
|
+
This method provides `use_cache` parameter which can be used to indicate whether the caching of conversion factors should happen.
|
130
|
+
|
107
131
|
```ruby
|
108
132
|
UnitMeasurements::Length.parse("1 km")
|
109
133
|
#=> 1.0 km
|
@@ -254,6 +278,12 @@ UnitMeasurements::Length.unit_or_alias?("metre")
|
|
254
278
|
#=> true
|
255
279
|
```
|
256
280
|
|
281
|
+
**Clear cached data for the unit group:**
|
282
|
+
|
283
|
+
```ruby
|
284
|
+
UnitMeasurements::Length.clear_cache
|
285
|
+
```
|
286
|
+
|
257
287
|
### Comparisons
|
258
288
|
|
259
289
|
You have ability to compare the measurements with the same or different units within the same unit group.
|
@@ -389,10 +419,9 @@ gem "unit_measurements", require: ["unit_measurements/base", "unit_measurements/
|
|
389
419
|
|
390
420
|
### Building new unit groups
|
391
421
|
|
392
|
-
This library provides a simpler way to define your own unit groups. Use the
|
393
|
-
|
394
|
-
|
395
|
-
each unit group using the `primitive` method.
|
422
|
+
This library provides a simpler way to define your own unit groups. Use the `UnitMeasurements.build` method to define
|
423
|
+
units within it. You can group units by the unit system using the `system` method and set the primitive unit for the
|
424
|
+
unit group using the `primitive` method. You can specify cache file name in unit group definition using the `cache` method.
|
396
425
|
|
397
426
|
```ruby
|
398
427
|
UnitMeasurements::Time = UnitMeasurements.build do
|
@@ -413,6 +442,9 @@ UnitMeasurements::Time = UnitMeasurements.build do
|
|
413
442
|
# You can also specify unit value as an array.
|
414
443
|
unit "h", value: [60, "min"], aliases: ["day", "days"]
|
415
444
|
end
|
445
|
+
|
446
|
+
# Sets the name of the cache file (optional).
|
447
|
+
cache "time_cache.json"
|
416
448
|
end
|
417
449
|
```
|
418
450
|
|
@@ -7,6 +7,13 @@ require "unit_measurements/version"
|
|
7
7
|
|
8
8
|
module UnitMeasurements
|
9
9
|
class << self
|
10
|
+
# Allows setting an instance of +Configuration+ containing values of desired
|
11
|
+
# configurable options.
|
12
|
+
#
|
13
|
+
# @author {Harshal V. Ladhe}[https://shivam091.github.io/]
|
14
|
+
# @since 5.3.0
|
15
|
+
attr_writer :configuration
|
16
|
+
|
10
17
|
# Creates a new unit group based on the provided +block+ of instructions.
|
11
18
|
#
|
12
19
|
# The +build+ method allows you to define and create a custom unit group with
|
@@ -36,11 +43,9 @@ module UnitMeasurements
|
|
36
43
|
# system :imperial do
|
37
44
|
# unit "in", value: "25.4 mm", aliases: ['"', "inch", "inches"]
|
38
45
|
# end
|
39
|
-
# end
|
40
46
|
#
|
41
|
-
#
|
42
|
-
#
|
43
|
-
# the unit group.
|
47
|
+
# cache "length.json"
|
48
|
+
# end
|
44
49
|
#
|
45
50
|
# @yield [builder]
|
46
51
|
# A block that defines the units to be added to the unit group.
|
@@ -74,10 +79,59 @@ module UnitMeasurements
|
|
74
79
|
@unit_group = builder.build
|
75
80
|
end
|
76
81
|
end
|
82
|
+
|
83
|
+
# Returns an instance of +Configuration+ with the values of desired configurable
|
84
|
+
# options of +*unit_measurements*+. If instance is not present, it initializes
|
85
|
+
# a new instance of {Configuration}.
|
86
|
+
#
|
87
|
+
# @return [Configuration] An instance of +Configuration+.
|
88
|
+
#
|
89
|
+
# @author {Harshal V. Ladhe}[https://shivam091.github.io/]
|
90
|
+
# @since 5.3.0
|
91
|
+
def configuration
|
92
|
+
@configuration ||= Configuration.new
|
93
|
+
end
|
94
|
+
|
95
|
+
# Reset the configuration to its default state.
|
96
|
+
#
|
97
|
+
# @example
|
98
|
+
# UnitMeasurements.reset
|
99
|
+
#
|
100
|
+
# @return [Configuration] A new +Configuration+ object.
|
101
|
+
#
|
102
|
+
# @author {Harshal V. Ladhe}[https://shivam091.github.io/]
|
103
|
+
# @since 5.3.0
|
104
|
+
def reset
|
105
|
+
@configuration = Configuration.new
|
106
|
+
end
|
107
|
+
|
108
|
+
# Configures options of the +*UnitMeasurements*+ module using a block. It
|
109
|
+
# yields the current +Configuration+ instance for updating default values of
|
110
|
+
# options by new values specified within a block.
|
111
|
+
#
|
112
|
+
# @example
|
113
|
+
# UnitMeasurements.configure do |config|
|
114
|
+
# config.use_cache = false
|
115
|
+
# end
|
116
|
+
#
|
117
|
+
# @yield [configuration] The current +Configuration+ instance.
|
118
|
+
#
|
119
|
+
# @yieldparam [Configuration] configuration
|
120
|
+
# An instance of +Configuration+ with the new values of options.
|
121
|
+
#
|
122
|
+
# @yieldreturn [Configuration] The updated +Configuration+ instance.
|
123
|
+
#
|
124
|
+
# @author {Harshal V. Ladhe}[https://shivam091.github.io/]
|
125
|
+
# @since 5.3.0
|
126
|
+
def configure
|
127
|
+
yield configuration
|
128
|
+
end
|
77
129
|
end
|
78
130
|
end
|
79
131
|
|
80
132
|
# The following requires load various components of the unit measurements library.
|
133
|
+
require "unit_measurements/configuration"
|
134
|
+
require "unit_measurements/cache"
|
81
135
|
require "unit_measurements/unit_group_builder"
|
82
136
|
require "unit_measurements/unit"
|
83
137
|
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
|
@@ -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 BaseError, "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
|
@@ -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 = (
|
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
|
-
#
|
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, :
|
223
|
-
:
|
224
|
-
:unit_or_alias?, :[],
|
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
|
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
|
286
|
+
# UnitMeasurements::Length.parse("2 ½ km in m")
|
264
287
|
# => 2500.0 m
|
265
288
|
#
|
266
|
-
# UnitMeasurements::Length.parse("2 1/2 km
|
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
|
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
|
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,37 @@ 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
|
+
use_cache = (UnitMeasurements.configuration.use_cache || use_cache)
|
466
|
+
|
467
|
+
if use_cache && (cached_factor = self.class.cached.get(unit.name, target_unit.name))
|
468
|
+
cached_factor
|
469
|
+
else
|
470
|
+
factor = unit.conversion_factor / target_unit.conversion_factor
|
471
|
+
self.class.cached.set(unit.name, target_unit.name, factor) if use_cache
|
472
|
+
factor
|
473
|
+
end
|
474
|
+
end
|
387
475
|
end
|
388
476
|
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
|
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
|
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
|
8
|
-
2. Unit names suffixed with `**` support
|
9
|
-
|
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.
|
4
|
+
version: 5.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-10-
|
11
|
+
date: 2023-10-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -107,7 +107,9 @@ files:
|
|
107
107
|
- lib/unit_measurements.rb
|
108
108
|
- lib/unit_measurements/arithmetic.rb
|
109
109
|
- lib/unit_measurements/base.rb
|
110
|
+
- lib/unit_measurements/cache.rb
|
110
111
|
- lib/unit_measurements/comparison.rb
|
112
|
+
- lib/unit_measurements/configuration.rb
|
111
113
|
- lib/unit_measurements/conversion.rb
|
112
114
|
- lib/unit_measurements/errors/parse_error.rb
|
113
115
|
- lib/unit_measurements/errors/primitive_unit_already_set_error.rb
|