unit_measurements 5.1.1 → 5.3.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|