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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: efe1918460c38d338cba7dda0e8f267d344df801
4
- data.tar.gz: 545fe050c3ed7f2f09ed5b58d013d4a2176ce280
3
+ metadata.gz: a0843dbdae33b496f257324dc0006e71ac292c7a
4
+ data.tar.gz: 808f425fccb8a1f757194feecd9de18b91eb03a7
5
5
  SHA512:
6
- metadata.gz: ba9651ddcf3dad823abdfaf1a24e7860a3917b13c026f993523bc939da4abbe76e0da4669be68deb56eccc7743cac44fcbc6db4bc86a413594298cff746c08ed
7
- data.tar.gz: 06b6747e60076e5b9629aefe2632cd6095122d14337cd583869171be32ca8157f4d416e56392857e10ebe84bc0a445c02f4efd4bd4cce22ca188ecb1288dcdb1
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
- primary_code
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
@@ -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 = 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
- s.increment({:f => t.factor, :p => t.prefix, :a => t.atom}, t.exponent); s
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
- METHODS = [:primary_code, :secondary_code, :names, :slugs, :symbol]
5
+ MODES = [:primary_code, :secondary_code, :names, :slugs, :symbol]
6
6
 
7
- PARSERS = METHODS.reduce({}) do |hash, method|
8
- hash[method] = Parser.new(method); 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
- raise ExpressionError, "Could not evaluate '#{@expression}'."
18
+ fail ExpressionError, "Could not evaluate '#{@expression}'."
19
19
  end
20
20
  end
21
21
 
22
- def transform
23
- PARSERS.reduce(nil) do |foo, (method, parser)|
24
- if parsed = parser.parse(expression) rescue next
25
- return TRANSFORMER.apply(parsed, :key => method)
26
- end
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 ||= begin
32
- transformation = transform
33
- if transformation.respond_to?(:terms)
34
- transformation.terms
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(method)
6
- new(Atom.all, method).alternative
5
+ def atom(mode)
6
+ new(Atom.all, mode).alternative
7
7
  end
8
8
 
9
- def metric_atom(method)
10
- new(Atom.all.select(&:metric?), method).alternative
9
+ def metric_atom(mode)
10
+ new(Atom.all.select(&:metric?), mode).alternative
11
11
  end
12
12
 
13
- def prefix(method)
14
- new(Prefix.all, method).alternative
13
+ def prefix(mode)
14
+ new(Prefix.all, mode).alternative
15
15
  end
16
16
  end
17
17
 
18
- attr_reader :collection, :method
18
+ attr_reader :collection, :mode
19
19
 
20
- def initialize(collection, method=:primary_code)
20
+ def initialize(collection, mode=:primary_code)
21
21
  @collection = collection
22
- @method = method
22
+ @mode = mode
23
23
  end
24
24
 
25
25
  def strings
26
- @stings ||= collection.map(&method).flatten.compact.sort do |x,y|
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[:key]) }
9
- rule(:atom_code => simple(:c)) { |ctx| Atom.find(ctx[:c], ctx[:key]) }
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
@@ -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 magnitued. This is the primary class that outside code
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
- fail ExpressionError, "Could not evaluate `#{unit}`." if terms.nil?
16
+ terms
17
17
  end
18
18
 
19
19
  # Convert this measurement to a compatible unit.
@@ -100,8 +100,8 @@ module Unitwise
100
100
 
101
101
  # Convert to a simple string representing the scale.
102
102
  # @api public
103
- def to_s
104
- "#{simplified_value} #{unit}"
103
+ def to_s(mode = nil)
104
+ "#{simplified_value} #{unit.to_s(mode)}"
105
105
  end
106
106
 
107
107
  def inspect
data/lib/unitwise/term.rb CHANGED
@@ -122,13 +122,10 @@ module Unitwise
122
122
  end
123
123
  end
124
124
 
125
- # String representation for this term.
126
- # @return [String]
127
- def to_s
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
- @terms || Expression.decompose(expression)
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
@@ -1,3 +1,3 @@
1
1
  module Unitwise
2
- VERSION = '0.8.1'
2
+ VERSION = '0.9.0'
3
3
  end
@@ -106,6 +106,7 @@ module ScaleTests
106
106
  end
107
107
  end
108
108
  end
109
+
109
110
  end
110
111
  end
111
112
  end
@@ -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
@@ -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.8.1
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-07 00:00:00.000000000 Z
11
+ date: 2014-07-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: liner