unitwise 0.8.1 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  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