unitwise 1.0.1 → 1.0.2

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: 7de40334f99c4238cd5e8c492b52a2e6556f80fd
4
- data.tar.gz: 52c7bce118481d12d1955d7395b06068dc400c23
3
+ metadata.gz: 410fb733b657a34122237793d03bf634fa0676b2
4
+ data.tar.gz: 57ab5cfe90d3bfb9dea058ea3b85904b3bb451dd
5
5
  SHA512:
6
- metadata.gz: 9e3e7a34913889ff32d9d7f7af7e4f3dc3ef563295f0469653f5f46f84c1977cd022a888a2a31efbe6b33f2397dfa5eac1810781b061716f6c233acd3e9a91e3
7
- data.tar.gz: 4635700db7000da9b2a2958e1f0bdd2696bc8bdf698396cf90ce66da6750d173402c9ddb04162e2375766ddc287e5f1c7cda19e9bdf650e260b2ff35826e63c3
6
+ metadata.gz: 0171c1aef8b9daf3e07a89959bbde2ee947854c51b6f7be0c1d569e140b0e9f24e95ec9a455babcb489d105c1656928cb207180b935fc02b329c330c9e3a41b8
7
+ data.tar.gz: 389f2c83e8505e1e7e6df4b8a9aeb6ae79869e2693dd3bb9d9476667ed440823f32faa63403c78a234a7fbdb83fd46d7e48072bed52c1946615bd408ef13bf6d
@@ -5,6 +5,13 @@ version 1.0.0.
5
5
 
6
6
  Unitwise uses semantic versioning.
7
7
 
8
+ ## 1.0.2 - 2014-09-14
9
+
10
+ ## Fixed
11
+
12
+ - Decomposer caching is now a little smarter. This resulted in a mild
13
+ performance increase.
14
+
8
15
  ## 1.0.1 - 2014-08-30
9
16
 
10
17
  ### Fixed
@@ -19,8 +19,7 @@ module Unitwise
19
19
  Composer.new(terms, method).expression
20
20
  end
21
21
 
22
- # Convert a string representation of a unit, and turn it into a
23
- # an array of terms
22
+ # Convert a string representation of a unit into an array of terms
24
23
  # @param expression [String] The string you wish to convert
25
24
  # @return [Array]
26
25
  # @example
@@ -28,26 +27,9 @@ module Unitwise
28
27
  # # => [<Unitwise::Term m2>, <Unitwise::Term s-2>]
29
28
  # @api public
30
29
  def decompose(expression)
31
- expression = expression.to_s
32
- if decomposed.key?(expression)
33
- decomposed[expression]
34
- else
35
- decomposed[expression] = begin
36
- Decomposer.new(expression).terms
37
- rescue ExpressionError
38
- nil
39
- end
40
- end
30
+ Decomposer.parse(expression)
41
31
  end
42
32
 
43
- private
44
-
45
- # A cache of decomposed strings.
46
- # @return [Hash]
47
- # @api private
48
- def decomposed
49
- @decomposed ||= {}
50
- end
51
33
  end
52
34
  end
53
35
  end
@@ -13,17 +13,38 @@ module Unitwise
13
13
 
14
14
  TRANSFORMER = Transformer.new
15
15
 
16
+ class << self
17
+
18
+ # Parse an expression to an array of terms and cache the results
19
+ def parse(expression)
20
+ expression = expression.to_s
21
+ if cache.key?(expression)
22
+ cache[expression]
23
+ elsif decomposer = new(expression)
24
+ cache[expression] = decomposer
25
+ end
26
+ end
27
+
28
+ private
29
+
30
+ # A simple cache to prevent re-decomposing the same units
31
+ # api private
32
+ def cache
33
+ @cache ||= {}
34
+ end
35
+ end
36
+
16
37
  attr_reader :expression, :mode
17
38
 
18
39
  def initialize(expression)
19
40
  @expression = expression.to_s
20
41
  if terms.nil? || terms.empty?
21
- fail ExpressionError, "Could not evaluate '#{@expression}'."
42
+ fail(ExpressionError, "Could not evaluate '#{ expression }'.")
22
43
  end
23
44
  end
24
45
 
25
46
  def parse
26
- @parse ||= PARSERS.reduce(nil) do |_, (mode, parser)|
47
+ PARSERS.reduce(nil) do |_, (mode, parser)|
27
48
  parsed = parser.parse(expression) rescue next
28
49
  @mode = mode
29
50
  break parsed
@@ -41,7 +62,7 @@ module Unitwise
41
62
  Array(transform)
42
63
  end
43
64
  end
44
-
65
+
45
66
  end
46
67
  end
47
68
  end
@@ -5,15 +5,19 @@ module Unitwise
5
5
  class Matcher
6
6
  class << self
7
7
  def atom(mode)
8
- new(Atom.all, mode).alternative
8
+ @atom ||= {}
9
+ @atom[mode] ||= new(Atom.all, mode).alternative
9
10
  end
10
11
 
11
12
  def metric_atom(mode)
12
- new(Atom.all.select(&:metric?), mode).alternative
13
+ @metric_atom ||= {}
14
+ @metric_atom[mode] ||=
15
+ new(Atom.all.select(&:metric?), mode).alternative
13
16
  end
14
17
 
15
18
  def prefix(mode)
16
- new(Prefix.all, mode).alternative
19
+ @prefix ||= {}
20
+ @prefix[mode] ||= new(Prefix.all, mode).alternative
17
21
  end
18
22
  end
19
23
 
@@ -25,17 +29,17 @@ module Unitwise
25
29
  end
26
30
 
27
31
  def strings
28
- @stings ||= collection.map(&mode).flatten.compact.sort do |x, y|
32
+ collection.map(&mode).flatten.compact.sort do |x, y|
29
33
  y.length <=> x.length
30
34
  end
31
35
  end
32
36
 
33
37
  def matchers
34
- @matchers ||= strings.map { |s| Parslet::Atoms::Str.new(s) }
38
+ strings.map { |s| Parslet::Atoms::Str.new(s) }
35
39
  end
36
40
 
37
41
  def alternative
38
- @alternative ||= Parslet::Atoms::Alternative.new(*matchers)
42
+ Parslet::Atoms::Alternative.new(*matchers)
39
43
  end
40
44
 
41
45
  end
@@ -20,13 +20,15 @@ class Numeric
20
20
  def method_missing(meth, *args, &block)
21
21
  if args.empty? && !block_given?
22
22
  unit = (match = /\Ato_(\w+)\Z/.match(meth.to_s)) ? match[1] : meth
23
- begin
24
- res = convert_to(unit)
25
- Numeric.define_unit_conversion_methods_for(unit)
26
- res
23
+ converted = begin
24
+ convert_to(unit)
27
25
  rescue Unitwise::ExpressionError
28
- super(meth, *args, &block)
26
+ nil
29
27
  end
28
+ end
29
+ if converted
30
+ Numeric.define_unit_conversion_methods_for(unit)
31
+ converted
30
32
  else
31
33
  super(meth, *args, &block)
32
34
  end
@@ -81,7 +81,7 @@ module Unitwise
81
81
  end
82
82
  memoize :root_terms
83
83
 
84
- # How far away is this instances unit from the deepest leve atom.
84
+ # How far away is this instances unit from the deepest level atom.
85
85
  # @return [Integer]
86
86
  # @api public
87
87
  def depth
@@ -89,28 +89,19 @@ module Unitwise
89
89
  # params other [Unit, Term, Numeric]
90
90
  # @return [Term]
91
91
  def *(other)
92
- if other.respond_to?(:terms)
93
- Unit.new(other.terms << self)
94
- elsif other.respond_to?(:atom)
95
- Unit.new([self, other])
96
- elsif other.is_a?(Numeric)
97
- self.class.new(to_hash.merge(:factor => factor * other))
98
- end
92
+ operate('*', other) ||
93
+ fail(TypeError, "Can't multiply #{ self } by #{ other }.")
99
94
  end
100
95
 
101
96
  # Term division. Divide by a Unit, another Term, or a Numeric.
102
97
  # params other [Unit, Term, Numeric]
103
98
  # @return [Term]
104
99
  def /(other)
105
- if other.respond_to?(:terms)
106
- Unit.new(other.terms.map { |t| t ** -1 } << self)
107
- elsif other.respond_to?(:atom)
108
- Unit.new([self, other ** -1])
109
- elsif other.is_a?(Numeric)
110
- self.class.new(to_hash.merge(:factor => factor / other))
111
- end
100
+ operate('/', other) ||
101
+ fail(TypeError, "Can't divide #{ self } by #{ other }.")
112
102
  end
113
103
 
104
+
114
105
  # Term exponentiation. Raise a term to a numeric power.
115
106
  # params other [Numeric]
116
107
  # @return [Term]
@@ -133,5 +124,19 @@ module Unitwise
133
124
  def calculate(value)
134
125
  (factor * (prefix ? prefix.scalar : 1) * value) ** exponent
135
126
  end
127
+
128
+ # Multiply or divide a term
129
+ # @api private
130
+ def operate(operator, other)
131
+ exp = operator == '/' ? -1 : 1
132
+ if other.respond_to?(:terms)
133
+ Unit.new(other.terms.map { |t| t ** exp } << self)
134
+ elsif other.respond_to?(:atom)
135
+ Unit.new([self, other ** exp])
136
+ elsif other.is_a?(Numeric)
137
+ self.class.new(to_hash.merge(:factor => factor.send(operator, other)))
138
+ end
139
+ end
140
+
136
141
  end
137
142
  end
@@ -27,7 +27,7 @@ module Unitwise
27
27
  def terms
28
28
  unless frozen?
29
29
  unless @terms
30
- decomposer = Expression::Decomposer.new(@expression)
30
+ decomposer = Expression.decompose(@expression)
31
31
  @mode = decomposer.mode
32
32
  @terms = decomposer.terms
33
33
  end
@@ -41,11 +41,14 @@ module Unitwise
41
41
  # (:primary_code, :names, :secondary_code).
42
42
  # @return [String]
43
43
  # @api public
44
- def expression(mode = mode)
45
- Expression.compose(terms, mode)
44
+ def expression(mode=nil)
45
+ if @expression && (mode.nil? || mode == self.mode)
46
+ @expression
47
+ else
48
+ Expression.compose(terms, mode || self.mode)
49
+ end
46
50
  end
47
51
 
48
-
49
52
  # The collection of atoms that compose this unit. Essentially delegated to
50
53
  # terms.
51
54
  # @return [Array]
@@ -105,15 +108,8 @@ module Unitwise
105
108
  # @return [Unitwise::Unit]
106
109
  # @api public
107
110
  def *(other)
108
- if other.respond_to?(:terms)
109
- self.class.new(terms + other.terms)
110
- elsif other.respond_to?(:atom)
111
- self.class.new(terms << other)
112
- elsif other.is_a?(Numeric)
113
- self.class.new(terms.map { |t| t * other })
114
- else
115
- fail TypeError, "Can't multiply #{self} by #{other}."
116
- end
111
+ operate('*', other) ||
112
+ fail(TypeError, "Can't multiply #{ self } by #{ other }.")
117
113
  end
118
114
 
119
115
  # Divide this unit by another unit,term, or number.
@@ -121,17 +117,11 @@ module Unitwise
121
117
  # @return [Unitwise::Unit]
122
118
  # @api public
123
119
  def /(other)
124
- if other.respond_to?(:terms)
125
- self.class.new(terms + other.terms.map { |t| t ** -1 })
126
- elsif other.respond_to?(:atom)
127
- self.class.new(terms << other ** -1)
128
- elsif other.is_a?(Numeric)
129
- self.class.new(terms.map { |t| t / other })
130
- else
131
- fail TypeError, "Can't divide #{self} by #{other}."
132
- end
120
+ operate('/', other) ||
121
+ fail(TypeError, "Can't divide #{ self } by #{ other }.")
133
122
  end
134
123
 
124
+
135
125
  # Raise this unit to a numeric power.
136
126
  # @param other [Numeric]
137
127
  # @return [Unitwise::Unit]
@@ -149,8 +139,8 @@ module Unitwise
149
139
  # (:primary_code, :names, :secondary_code)
150
140
  # @return [String]
151
141
  # @api public
152
- def to_s(mode = mode)
153
- expression(mode || self.mode)
142
+ def to_s(mode = nil)
143
+ expression(mode)
154
144
  end
155
145
 
156
146
  # A collection of the possible string representations of this unit.
@@ -172,5 +162,20 @@ module Unitwise
172
162
  @mode || :primary_code
173
163
  end
174
164
 
165
+ private
166
+
167
+ # Multiply or divide units
168
+ # @api private
169
+ def operate(operator, other)
170
+ exp = operator == '/' ? -1 : 1
171
+ if other.respond_to?(:terms)
172
+ self.class.new(terms + other.terms.map { |t| t ** exp })
173
+ elsif other.respond_to?(:atom)
174
+ self.class.new(terms << other ** exp)
175
+ elsif other.is_a?(Numeric)
176
+ self.class.new(terms.map { |t| t.send(operator, other) })
177
+ end
178
+ end
179
+
175
180
  end
176
181
  end
@@ -1,3 +1,3 @@
1
1
  module Unitwise
2
- VERSION = '1.0.1'
2
+ VERSION = '1.0.2'
3
3
  end
@@ -45,5 +45,11 @@ describe Unitwise::Term do
45
45
  subject.frozen?.must_equal true
46
46
  end
47
47
  end
48
+
49
+ describe "#to_s" do
50
+ it "should return the UCUM code" do
51
+ subject.to_s.must_equal "kJ"
52
+ end
53
+ end
48
54
  end
49
55
  end
@@ -66,7 +66,7 @@ describe Unitwise::Unit do
66
66
 
67
67
  describe "#frozen?" do
68
68
  it "should be frozen" do
69
- kg.to_s
69
+ kg.scalar
70
70
  kg.frozen?.must_equal true
71
71
  end
72
72
  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: 1.0.1
4
+ version: 1.0.2
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-08-30 00:00:00.000000000 Z
11
+ date: 2014-09-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: liner
@@ -183,7 +183,6 @@ files:
183
183
  - lib/unitwise/term.rb
184
184
  - lib/unitwise/unit.rb
185
185
  - lib/unitwise/version.rb
186
- - simple_bench.rb
187
186
  - test/support/scale_tests.rb
188
187
  - test/test_helper.rb
189
188
  - test/unitwise/atom_test.rb
@@ -1,21 +0,0 @@
1
- require 'unitwise'
2
- require 'ruby-units'
3
- require 'benchmark'
4
-
5
- Benchmark.bm(10) do |x|
6
-
7
- x.report('unitwise') do
8
- 100000.times do |x|
9
- expression = "mm#{x % 20}"
10
- Unitwise::Measurement.new(x, expression)
11
- end
12
- end
13
-
14
- x.report('ruby-units') do
15
- 100000.times do |x|
16
- expression = "mm^#{x % 20}"
17
- Unit(x, expression)
18
- end
19
- end
20
-
21
- end