unitwise 0.8.1 → 0.9.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/README.md +40 -0
- data/lib/unitwise/base.rb +4 -2
- data/lib/unitwise/expression.rb +2 -2
- data/lib/unitwise/expression/composer.rb +8 -4
- data/lib/unitwise/expression/decomposer.rb +18 -17
- data/lib/unitwise/expression/matcher.rb +10 -10
- data/lib/unitwise/expression/transformer.rb +2 -2
- data/lib/unitwise/measurement.rb +2 -2
- data/lib/unitwise/scale.rb +2 -2
- data/lib/unitwise/term.rb +3 -6
- data/lib/unitwise/unit.rb +21 -5
- data/lib/unitwise/version.rb +1 -1
- data/test/support/scale_tests.rb +1 -0
- data/test/unitwise/measurement_test.rb +14 -0
- data/test/unitwise/unit_test.rb +14 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a0843dbdae33b496f257324dc0006e71ac292c7a
|
4
|
+
data.tar.gz: 808f425fccb8a1f757194feecd9de18b91eb03a7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d60cd4a403b09294175f3e0df799a73c14d0c389ebf3141a04dec4de02e0dd5bcbdea8bb99ebb2740ad4f8c86d27534d65b6462c49651670f23561fa7b8013df
|
7
|
+
data.tar.gz: 1ebdb94e5df860af1807b8158f038351be2bc161c713fa186db914a306b5ccc3d08569b0ee293bfb450d9a2b6e128246b694659fd2f88acd685e8f7ffb9fa8d8
|
data/README.md
CHANGED
@@ -204,6 +204,46 @@ You can also get the official list from the UCUM website in XML format at
|
|
204
204
|
or a YAML version within this repo
|
205
205
|
[github.com/joshwlewis/unitwise/tree/master/data](//github.com/joshwlewis/unitwise/tree/master/data).
|
206
206
|
|
207
|
+
### UCUM designations
|
208
|
+
UCUM defines several designations for it's units: `names`,
|
209
|
+
`primary_code`, `secondary_code`, and `symbol`. You can see them all when
|
210
|
+
inspecting an atom:
|
211
|
+
|
212
|
+
```ruby
|
213
|
+
Unitwise::Atom.all.sample
|
214
|
+
# => #<Unitwise::Atom names=["British thermal unit"], primary_code="[Btu]", secondary_code="[BTU]", symbol="btu", scale=#<Unitwise::Scale value=1 unit=[Btu_th]>, classification="heat", property="energy", metric=false, special=false, arbitrary=false, dim="L2.M.T-2">
|
215
|
+
```
|
216
|
+
|
217
|
+
When initializing a measurement, you can use any of the designations:
|
218
|
+
|
219
|
+
```ruby
|
220
|
+
Unitwise(1, '[Btu]') == Unitwise(1, 'British thermal unit')
|
221
|
+
# => true
|
222
|
+
Unitwise(1, 'btu') == Unitwise(1, "[BTU]")
|
223
|
+
# => true
|
224
|
+
```
|
225
|
+
|
226
|
+
When inspecting or printing (`to_s`) that measurement, it will remember the
|
227
|
+
desigation you used. However, if you want to print it with another designation,
|
228
|
+
that's also possible:
|
229
|
+
|
230
|
+
```ruby
|
231
|
+
temperature_change = Unitwise(10, "Cel/h")
|
232
|
+
temperature_change.to_s # => "10 Cel/h"
|
233
|
+
temperature_change.to_s(:names) # => "10 degree Celsius/hour"
|
234
|
+
temperature_change.to_s(:symbol) # => "10 °C/h"
|
235
|
+
```
|
236
|
+
|
237
|
+
There is on caveat here. You must use the same designation for each atom in a
|
238
|
+
complex unit. Meaning you can't mix designations within a unit.
|
239
|
+
|
240
|
+
```ruby
|
241
|
+
Unitwise(1, "m/s") # Works, both atoms use their primary_code
|
242
|
+
Unitwise(1, "meter/second") # Works, both atoms use a name
|
243
|
+
Unitwise(1, "meter/s") # Does not work, mixed designations (name and primary_code)
|
244
|
+
Unitwise(1, "meter") / Unitwise(1, "s") # Also works
|
245
|
+
```
|
246
|
+
|
207
247
|
## Supported Ruby Versions
|
208
248
|
|
209
249
|
This library aims to support and is tested against the following Ruby
|
data/lib/unitwise/base.rb
CHANGED
@@ -47,10 +47,12 @@ module Unitwise
|
|
47
47
|
memoize :slugs
|
48
48
|
|
49
49
|
# String representation for the instance.
|
50
|
+
# @param mode [symbol] The attribute to for stringification
|
50
51
|
# @return [String]
|
51
52
|
# @api public
|
52
|
-
def to_s
|
53
|
-
|
53
|
+
def to_s(mode = :primary_code)
|
54
|
+
res = self.send(mode)
|
55
|
+
res.respond_to?(:each) ? res.first.to_s : res.to_s
|
54
56
|
end
|
55
57
|
end
|
56
58
|
end
|
data/lib/unitwise/expression.rb
CHANGED
@@ -15,8 +15,8 @@ module Unitwise
|
|
15
15
|
# @example
|
16
16
|
# Unitwise::Expression.compose(terms) # => "m2/s2"
|
17
17
|
# @api public
|
18
|
-
def compose(terms)
|
19
|
-
Composer.new(terms).expression
|
18
|
+
def compose(terms, method=:primary_code)
|
19
|
+
Composer.new(terms, method).expression
|
20
20
|
end
|
21
21
|
|
22
22
|
# Convert a string representation of a unit, and turn it into a
|
@@ -1,14 +1,18 @@
|
|
1
1
|
module Unitwise
|
2
2
|
module Expression
|
3
3
|
class Composer
|
4
|
-
attr_reader :terms
|
5
|
-
def initialize(terms)
|
6
|
-
@terms
|
4
|
+
attr_reader :terms, :mode
|
5
|
+
def initialize(terms, mode)
|
6
|
+
@terms = terms
|
7
|
+
@mode = mode || :primary_code
|
7
8
|
end
|
8
9
|
|
9
10
|
def set
|
10
11
|
@set ||= terms.reduce(SignedMultiset.new) do |s, t|
|
11
|
-
|
12
|
+
identifier = { :f => t.factor,
|
13
|
+
:p => (t.prefix.to_s(mode) if t.prefix),
|
14
|
+
:a => (t.atom.to_s(mode) if t.atom) }
|
15
|
+
s.increment(identifier, t.exponent); s
|
12
16
|
end
|
13
17
|
end
|
14
18
|
|
@@ -2,39 +2,40 @@ module Unitwise
|
|
2
2
|
module Expression
|
3
3
|
class Decomposer
|
4
4
|
|
5
|
-
|
5
|
+
MODES = [:primary_code, :secondary_code, :names, :slugs, :symbol]
|
6
6
|
|
7
|
-
PARSERS =
|
8
|
-
hash[
|
7
|
+
PARSERS = MODES.reduce({}) do |hash, mode|
|
8
|
+
hash[mode] = Parser.new(mode); hash
|
9
9
|
end
|
10
10
|
|
11
11
|
TRANSFORMER = Transformer.new
|
12
12
|
|
13
|
-
attr_reader :expression
|
13
|
+
attr_reader :expression, :mode
|
14
14
|
|
15
15
|
def initialize(expression)
|
16
16
|
@expression = expression.to_s
|
17
17
|
if terms.nil? || terms.empty?
|
18
|
-
|
18
|
+
fail ExpressionError, "Could not evaluate '#{@expression}'."
|
19
19
|
end
|
20
20
|
end
|
21
21
|
|
22
|
-
def
|
23
|
-
PARSERS.reduce(nil) do |
|
24
|
-
|
25
|
-
|
26
|
-
|
22
|
+
def parse
|
23
|
+
@parse ||= PARSERS.reduce(nil) do |null,(mode, parser)|
|
24
|
+
parsed = parser.parse(expression) rescue next
|
25
|
+
@mode = mode
|
26
|
+
break parsed
|
27
27
|
end
|
28
28
|
end
|
29
29
|
|
30
|
+
def transform
|
31
|
+
@transform ||= TRANSFORMER.apply(parse, :mode => mode)
|
32
|
+
end
|
33
|
+
|
30
34
|
def terms
|
31
|
-
@terms ||=
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
else
|
36
|
-
Array(transformation)
|
37
|
-
end
|
35
|
+
@terms ||= if transform.respond_to?(:terms)
|
36
|
+
transform.terms
|
37
|
+
else
|
38
|
+
Array(transform)
|
38
39
|
end
|
39
40
|
end
|
40
41
|
|
@@ -2,28 +2,28 @@ module Unitwise
|
|
2
2
|
module Expression
|
3
3
|
class Matcher
|
4
4
|
class << self
|
5
|
-
def atom(
|
6
|
-
new(Atom.all,
|
5
|
+
def atom(mode)
|
6
|
+
new(Atom.all, mode).alternative
|
7
7
|
end
|
8
8
|
|
9
|
-
def metric_atom(
|
10
|
-
new(Atom.all.select(&:metric?),
|
9
|
+
def metric_atom(mode)
|
10
|
+
new(Atom.all.select(&:metric?), mode).alternative
|
11
11
|
end
|
12
12
|
|
13
|
-
def prefix(
|
14
|
-
new(Prefix.all,
|
13
|
+
def prefix(mode)
|
14
|
+
new(Prefix.all, mode).alternative
|
15
15
|
end
|
16
16
|
end
|
17
17
|
|
18
|
-
attr_reader :collection, :
|
18
|
+
attr_reader :collection, :mode
|
19
19
|
|
20
|
-
def initialize(collection,
|
20
|
+
def initialize(collection, mode=:primary_code)
|
21
21
|
@collection = collection
|
22
|
-
@
|
22
|
+
@mode = mode
|
23
23
|
end
|
24
24
|
|
25
25
|
def strings
|
26
|
-
@stings ||= collection.map(&
|
26
|
+
@stings ||= collection.map(&mode).flatten.compact.sort do |x,y|
|
27
27
|
y.length <=> x.length
|
28
28
|
end
|
29
29
|
end
|
@@ -5,8 +5,8 @@ module Unitwise
|
|
5
5
|
rule(:integer => simple(:i)) { i.to_i }
|
6
6
|
rule(:fixnum => simple(:f)) { f.to_f }
|
7
7
|
|
8
|
-
rule(:prefix_code => simple(:c)) { |ctx| Prefix.find(ctx[:c], ctx[:
|
9
|
-
rule(:atom_code => simple(:c)) { |ctx| Atom.find(ctx[:c], ctx[:
|
8
|
+
rule(:prefix_code => simple(:c)) { |ctx| Prefix.find(ctx[:c], ctx[:mode]) }
|
9
|
+
rule(:atom_code => simple(:c)) { |ctx| Atom.find(ctx[:c], ctx[:mode]) }
|
10
10
|
rule(:term => subtree(:h)) { Term.new(h) }
|
11
11
|
|
12
12
|
rule(:operator => simple(:o), :right => simple(:r)) do
|
data/lib/unitwise/measurement.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
module Unitwise
|
2
2
|
# A Measurement is a combination of a numeric value and a unit. You can think
|
3
3
|
# of this as a type of vector where the direction is the unit designation and
|
4
|
-
# the value is the
|
4
|
+
# the value is the magnitude. This is the primary class that outside code
|
5
5
|
# will interact with. Comes with conversion, comparison, and math methods.
|
6
6
|
class Measurement < Scale
|
7
7
|
# Create a new Measurement
|
@@ -13,7 +13,7 @@ module Unitwise
|
|
13
13
|
# @api public
|
14
14
|
def initialize(*args)
|
15
15
|
super(*args)
|
16
|
-
|
16
|
+
terms
|
17
17
|
end
|
18
18
|
|
19
19
|
# Convert this measurement to a compatible unit.
|
data/lib/unitwise/scale.rb
CHANGED
data/lib/unitwise/term.rb
CHANGED
@@ -122,13 +122,10 @@ module Unitwise
|
|
122
122
|
end
|
123
123
|
end
|
124
124
|
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
[(factor if factor != 1), prefix.to_s,
|
129
|
-
atom.to_s, (exponent if exponent != 1)].compact.join('')
|
125
|
+
def to_s(mode = :primary_code)
|
126
|
+
[(factor if factor != 1), (prefix.send(mode) if prefix),
|
127
|
+
(atom.send(mode) if atom), (exponent if exponent != 1)].compact.join('')
|
130
128
|
end
|
131
|
-
memoize :to_s
|
132
129
|
|
133
130
|
private
|
134
131
|
|
data/lib/unitwise/unit.rb
CHANGED
@@ -17,13 +17,23 @@ module Unitwise
|
|
17
17
|
@expression = input.to_s
|
18
18
|
else
|
19
19
|
@terms = input
|
20
|
-
@expression = Expression.compose(input)
|
21
20
|
end
|
22
|
-
freeze
|
23
21
|
end
|
24
22
|
|
25
23
|
def terms
|
26
|
-
|
24
|
+
unless frozen?
|
25
|
+
unless @terms
|
26
|
+
decomposer = Expression::Decomposer.new(@expression)
|
27
|
+
@mode = decomposer.mode
|
28
|
+
@terms = decomposer.terms
|
29
|
+
end
|
30
|
+
freeze
|
31
|
+
end
|
32
|
+
@terms
|
33
|
+
end
|
34
|
+
|
35
|
+
def expression(mode = mode)
|
36
|
+
Expression.compose(terms, mode)
|
27
37
|
end
|
28
38
|
|
29
39
|
def atoms
|
@@ -88,8 +98,14 @@ module Unitwise
|
|
88
98
|
end
|
89
99
|
end
|
90
100
|
|
91
|
-
def to_s
|
92
|
-
expression
|
101
|
+
def to_s(mode = mode)
|
102
|
+
expression(mode || self.mode)
|
93
103
|
end
|
104
|
+
|
105
|
+
def mode
|
106
|
+
terms
|
107
|
+
@mode || :primary_code
|
108
|
+
end
|
109
|
+
|
94
110
|
end
|
95
111
|
end
|
data/lib/unitwise/version.rb
CHANGED
data/test/support/scale_tests.rb
CHANGED
@@ -201,4 +201,18 @@ describe Unitwise::Measurement do
|
|
201
201
|
end
|
202
202
|
end
|
203
203
|
|
204
|
+
describe "#to_s" do
|
205
|
+
it "should include the simplified value and use the mode it was created with" do
|
206
|
+
foot = described_class.new(7.00, "foot")
|
207
|
+
foot.to_s.must_equal "7 foot"
|
208
|
+
meter = described_class.new(Rational(22,7), "m")
|
209
|
+
meter.to_s.must_equal "3.142857142857143 m"
|
210
|
+
end
|
211
|
+
it "should accept a mode and print that mode string" do
|
212
|
+
temp = described_class.new(25, "degree Celsius")
|
213
|
+
temp.to_s(:primary_code).must_equal("25 Cel")
|
214
|
+
temp.to_s(:symbol).must_equal("25 °C")
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
204
218
|
end
|
data/test/unitwise/unit_test.rb
CHANGED
@@ -65,8 +65,22 @@ describe Unitwise::Unit do
|
|
65
65
|
|
66
66
|
describe "#frozen?" do
|
67
67
|
it "should be frozen" do
|
68
|
+
kg.to_s
|
68
69
|
kg.frozen?.must_equal true
|
69
70
|
end
|
70
71
|
end
|
71
72
|
|
73
|
+
describe "#to_s" do
|
74
|
+
it "should return an expression in the same mode it was initialized with" do
|
75
|
+
['meter','m', 'mm', '%'].each do |name|
|
76
|
+
Unitwise::Unit.new(name).to_s.must_equal(name)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
it "should accept an optional mode to build the expression with" do
|
80
|
+
temp_change = Unitwise::Unit.new("degree Celsius/hour")
|
81
|
+
temp_change.to_s(:primary_code).must_equal("Cel/h")
|
82
|
+
temp_change.to_s(:symbol).must_equal("°C/h")
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
72
86
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: unitwise
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.9.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Josh Lewis
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-07-
|
11
|
+
date: 2014-07-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: liner
|