quantify 3.0.0 → 3.1.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.
- data/VERSION +1 -1
- data/lib/quantify/core_extensions/string.rb +11 -1
- data/lib/quantify/inflections.rb +27 -3
- data/lib/quantify/quantity.rb +79 -82
- data/lib/quantify/unit/base_unit.rb +30 -53
- data/lib/quantify/unit/compound_unit.rb +21 -12
- data/lib/quantify/unit/prefix/prefix.rb +3 -3
- data/lib/quantify/unit/unit.rb +107 -75
- data/quantify.gemspec +8 -10
- data/spec/compound_unit_spec.rb +1 -16
- data/spec/quantity_spec.rb +38 -0
- data/spec/unit_spec.rb +6 -10
- metadata +26 -30
- data/lib/quantify/parser.rb +0 -7
- data/spec/quantify_spec.rb +0 -6
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
3.
|
1
|
+
3.1.0
|
@@ -22,7 +22,17 @@ class String
|
|
22
22
|
end
|
23
23
|
|
24
24
|
def starts_with_number?
|
25
|
-
(/\A
|
25
|
+
(/\A#{Unit::NUMBER_REGEX}/i).match(self) ? true : false
|
26
|
+
end
|
27
|
+
|
28
|
+
def starts_with_valid_unit_term?
|
29
|
+
return false unless
|
30
|
+
term = /\A#{Unit.unit_label_regex}#{Unit::INDEX_REGEX}?/.match(self) ||
|
31
|
+
/\A#{Unit.unit_symbol_regex}#{Unit::INDEX_REGEX}?/.match(self) ||
|
32
|
+
/\A#{Unit.unit_name_regex}#{Unit::INDEX_REGEX}?/.match(self) ||
|
33
|
+
/\A#{Unit::UNIT_DENOMINATOR_REGEX}/.match(self) ||
|
34
|
+
/\A(#{Unit::UNIT_PREFIX_TERMS_REGEX}|#{Unit::UNIT_SUFFIX_TERMS_REGEX})/i.match(self)
|
35
|
+
return term[0]
|
26
36
|
end
|
27
37
|
|
28
38
|
def to_quantity
|
data/lib/quantify/inflections.rb
CHANGED
@@ -1,8 +1,6 @@
|
|
1
1
|
|
2
2
|
ActiveSupport::Inflector.inflections do |inflect|
|
3
3
|
|
4
|
-
inflect.uncountable %w( clo hertz lux siemens )
|
5
|
-
|
6
4
|
inflect.plural /(metre)/i, '\1s'
|
7
5
|
inflect.singular /(metre)s?/i, '\1'
|
8
6
|
|
@@ -27,9 +25,11 @@ ActiveSupport::Inflector.inflections do |inflect|
|
|
27
25
|
inflect.plural /(gallon)/i, '\1s'
|
28
26
|
inflect.singular /(gallon)s?/i, '\1'
|
29
27
|
|
28
|
+
# 'uncountable' but required regex inflection definition for cases where combined with prefix
|
30
29
|
inflect.plural /(horsepower)/i, '\1'
|
31
30
|
inflect.singular /(horsepower)/i, '\1'
|
32
31
|
|
32
|
+
# 'uncountable' but required regex inflection definition for cases where combined with prefix
|
33
33
|
inflect.plural /(hundredweight)/i, '\1'
|
34
34
|
inflect.singular /(hundredweight)/i, '\1'
|
35
35
|
|
@@ -48,6 +48,10 @@ ActiveSupport::Inflector.inflections do |inflect|
|
|
48
48
|
inflect.plural /(pound)/i, '\1s'
|
49
49
|
inflect.singular /(pound)s?/i, '\1'
|
50
50
|
|
51
|
+
# This inflection is defined after that of 'pound' so that 'pound mole' is inflected appropriately
|
52
|
+
inflect.plural /(mole)/i, '\1s'
|
53
|
+
inflect.singular /(mole)s?/i, '\1'
|
54
|
+
|
51
55
|
inflect.plural /(ton)/i, '\1s'
|
52
56
|
inflect.singular /(ton)s?/i, '\1'
|
53
57
|
|
@@ -56,7 +60,27 @@ ActiveSupport::Inflector.inflections do |inflect|
|
|
56
60
|
|
57
61
|
inflect.plural /(stone)/i, '\1s'
|
58
62
|
inflect.singular /(stone)s?/i, '\1'
|
59
|
-
|
63
|
+
|
64
|
+
# 'uncountable' but required regex inflection definition for cases where combined with prefix
|
65
|
+
inflect.plural /(gauss)/i, '\1'
|
66
|
+
inflect.singular /(gauss)/i, '\1'
|
67
|
+
|
68
|
+
# 'uncountable' but required regex inflection definition for cases where combined with prefix
|
69
|
+
inflect.plural /(clo)/i, '\1'
|
70
|
+
inflect.singular /(clo)/i, '\1'
|
71
|
+
|
72
|
+
# 'uncountable' but required regex inflection definition for cases where combined with prefix
|
73
|
+
inflect.plural /(hertz)/i, '\1'
|
74
|
+
inflect.singular /(hertz)/i, '\1'
|
75
|
+
|
76
|
+
# 'uncountable' but required regex inflection definition for cases where combined with prefix
|
77
|
+
inflect.plural /(lux)/i, '\1'
|
78
|
+
inflect.singular /(lux)/i, '\1'
|
79
|
+
|
80
|
+
# 'uncountable' but required regex inflection definition for cases where combined with prefix
|
81
|
+
inflect.plural /(siemens)/i, '\1'
|
82
|
+
inflect.singular /(siemens)/i, '\1'
|
83
|
+
|
60
84
|
inflect.irregular 'footcandle', 'footcandles'
|
61
85
|
inflect.irregular 'kilowatt hour', 'kilowatt hours'
|
62
86
|
|
data/lib/quantify/quantity.rb
CHANGED
@@ -41,8 +41,6 @@ module Quantify
|
|
41
41
|
#
|
42
42
|
# 16.Gg #=> Quantity (gigagrams)
|
43
43
|
|
44
|
-
|
45
|
-
|
46
44
|
# Parse a string and return a Quantity object based upon the value and
|
47
45
|
# subseqent unit name, symbol or JScience label. Returns an array containing
|
48
46
|
# quantity objects for each quantity recognised.
|
@@ -53,7 +51,7 @@ module Quantify
|
|
53
51
|
# Isolate number from subsequent string
|
54
52
|
value, string = word, words[index+1..-1].join(" ")
|
55
53
|
# Shift any trailing non-numeric characters to start of string.
|
56
|
-
value, string = $1, "#{$2} #{string}" if (
|
54
|
+
value, string = $1, "#{$2} #{string}" if (Unit::QUANTITY_REGEX).match(word)
|
57
55
|
# Parse string for unit references
|
58
56
|
unit = Unit.parse(string, :iterative => true) || Unit.dimensionless
|
59
57
|
# Instantiate quantity using value and unit
|
@@ -77,7 +75,7 @@ module Quantify
|
|
77
75
|
!new_unit.is_compound_unit?
|
78
76
|
return false
|
79
77
|
end
|
80
|
-
|
78
|
+
|
81
79
|
public
|
82
80
|
|
83
81
|
attr_accessor :value, :unit
|
@@ -150,40 +148,7 @@ module Quantify
|
|
150
148
|
nil # raise? or ...
|
151
149
|
end
|
152
150
|
end
|
153
|
-
|
154
|
-
# Conversion where both units (including compound units) are of precisely
|
155
|
-
# equivalent dimensions, i.e. direct alternatives for one another. Where
|
156
|
-
# previous unit is a compound unit, new unit must be cancelled by all original
|
157
|
-
# base units
|
158
|
-
#
|
159
|
-
def convert_to_equivalent_unit!(new_unit)
|
160
|
-
old_unit = @unit
|
161
|
-
self.multiply!(Unit.ratio new_unit, old_unit)
|
162
|
-
old_base_units = old_unit.base_units.map { |base| base.unit } if old_unit.is_compound_unit?
|
163
|
-
self.cancel_base_units!(*old_base_units || old_unit)
|
164
|
-
end
|
165
|
-
|
166
|
-
def conversion_with_scalings!(new_unit)
|
167
|
-
@value = (((@value + @unit.scaling) * @unit.factor) / new_unit.factor) - new_unit.scaling
|
168
|
-
@unit = new_unit
|
169
|
-
return self
|
170
|
-
end
|
171
|
-
|
172
|
-
# Conversion where self is a compound unit, and new unit is not an alternative
|
173
|
-
# to the whole compound but IS an alternative to one or more of the base units,
|
174
|
-
# e.g.,
|
175
|
-
#
|
176
|
-
# Unit.kilowatt_hour.to :second #=> 'kilowatt second'
|
177
|
-
#
|
178
|
-
def convert_compound_unit_to_non_equivalent_unit!(new_unit)
|
179
|
-
@unit.base_units.select do |base|
|
180
|
-
base.unit.is_alternative_for? new_unit
|
181
|
-
end.inject(self) do |quantity,base|
|
182
|
-
factor = Unit.ratio(new_unit**base.index, base.unit**base.index)
|
183
|
-
quantity.multiply!(factor).cancel_base_units!(base.unit)
|
184
|
-
end
|
185
|
-
end
|
186
|
-
|
151
|
+
|
187
152
|
# Converts a quantity to the equivalent quantity using only SI units
|
188
153
|
def to_si
|
189
154
|
if @unit.is_compound_unit?
|
@@ -192,49 +157,7 @@ module Quantify
|
|
192
157
|
self.to(@unit.si_unit)
|
193
158
|
end
|
194
159
|
end
|
195
|
-
|
196
|
-
def convert_compound_unit_to_si!
|
197
|
-
until @unit.is_base_quantity_si_unit? do
|
198
|
-
unit = @unit.base_units.find do |base|
|
199
|
-
!base.is_base_quantity_si_unit?
|
200
|
-
end.unit
|
201
|
-
self.convert_compound_unit_to_non_equivalent_unit!(unit.si_unit)
|
202
|
-
end
|
203
|
-
return self
|
204
|
-
end
|
205
|
-
|
206
|
-
# Quantities must be of the same dimension in order to operate. If they are
|
207
|
-
# represented by different units (but represent the same physical quantity)
|
208
|
-
# the second quantity is converted into the unit belonging to the first unit
|
209
|
-
# and the addition is completed
|
210
|
-
#
|
211
|
-
def add_or_subtract!(operator,other)
|
212
|
-
if other.is_a? Quantity
|
213
|
-
other = other.to(@unit) if other.unit.is_alternative_for?(@unit)
|
214
|
-
if @unit.is_equivalent_to? other.unit
|
215
|
-
@value = @value.send operator, other.value
|
216
|
-
return self
|
217
|
-
else
|
218
|
-
raise Quantify::Exceptions::InvalidObjectError "Cannot add or subtract Quantities with different dimensions"
|
219
|
-
end
|
220
|
-
else
|
221
|
-
raise Quantify::Exceptions::InvalidObjectError "Cannot add or subtract non-Quantity objects"
|
222
|
-
end
|
223
|
-
end
|
224
|
-
|
225
|
-
def multiply_or_divide!(operator,other)
|
226
|
-
if other.kind_of? Numeric
|
227
|
-
@value = @value.send(operator,other)
|
228
|
-
return self
|
229
|
-
elsif other.kind_of? Quantity
|
230
|
-
@unit = @unit.send(operator,other.unit).or_equivalent
|
231
|
-
@value = @value.send(operator,other.value)
|
232
|
-
return self
|
233
|
-
else
|
234
|
-
raise Quantify::Exceptions::InvalidArgumentError "Cannot multiply or divide a Quantity by a non-Quantity or non-Numeric object"
|
235
|
-
end
|
236
|
-
end
|
237
|
-
|
160
|
+
|
238
161
|
def pow!(power)
|
239
162
|
raise Exceptions::InvalidArgumentError, "Argument must be an integer" unless power.is_a? Integer
|
240
163
|
@value = @value ** power
|
@@ -331,8 +254,82 @@ module Quantify
|
|
331
254
|
range.include? self
|
332
255
|
end
|
333
256
|
|
334
|
-
protected
|
257
|
+
protected
|
258
|
+
|
259
|
+
# Quantities must be of the same dimension in order to operate. If they are
|
260
|
+
# represented by different units (but represent the same physical quantity)
|
261
|
+
# the second quantity is converted into the unit belonging to the first unit
|
262
|
+
# and the addition is completed
|
263
|
+
#
|
264
|
+
def add_or_subtract!(operator,other)
|
265
|
+
if other.is_a? Quantity
|
266
|
+
other = other.to(@unit) if other.unit.is_alternative_for?(@unit)
|
267
|
+
if @unit.is_equivalent_to? other.unit
|
268
|
+
@value = @value.send operator, other.value
|
269
|
+
return self
|
270
|
+
else
|
271
|
+
raise Quantify::Exceptions::InvalidObjectError, "Cannot add or subtract Quantities with different dimensions"
|
272
|
+
end
|
273
|
+
else
|
274
|
+
raise Quantify::Exceptions::InvalidObjectError, "Cannot add or subtract non-Quantity objects"
|
275
|
+
end
|
276
|
+
end
|
277
|
+
|
278
|
+
def multiply_or_divide!(operator,other)
|
279
|
+
if other.kind_of? Numeric
|
280
|
+
@value = @value.send(operator,other)
|
281
|
+
return self
|
282
|
+
elsif other.kind_of? Quantity
|
283
|
+
@unit = @unit.send(operator,other.unit).or_equivalent
|
284
|
+
@value = @value.send(operator,other.value)
|
285
|
+
return self
|
286
|
+
else
|
287
|
+
raise Quantify::Exceptions::InvalidArgumentError, "Cannot multiply or divide a Quantity by a non-Quantity or non-Numeric object"
|
288
|
+
end
|
289
|
+
end
|
290
|
+
|
291
|
+
# Conversion where both units (including compound units) are of precisely
|
292
|
+
# equivalent dimensions, i.e. direct alternatives for one another. Where
|
293
|
+
# previous unit is a compound unit, new unit must be cancelled by all original
|
294
|
+
# base units
|
295
|
+
#
|
296
|
+
def convert_to_equivalent_unit!(new_unit)
|
297
|
+
old_unit = @unit
|
298
|
+
self.multiply!(Unit.ratio new_unit, old_unit)
|
299
|
+
old_base_units = old_unit.base_units.map { |base| base.unit } if old_unit.is_compound_unit?
|
300
|
+
self.cancel_base_units!(*old_base_units || old_unit)
|
301
|
+
end
|
302
|
+
|
303
|
+
def conversion_with_scalings!(new_unit)
|
304
|
+
@value = (((@value + @unit.scaling) * @unit.factor) / new_unit.factor) - new_unit.scaling
|
305
|
+
@unit = new_unit
|
306
|
+
return self
|
307
|
+
end
|
335
308
|
|
309
|
+
# Conversion where self is a compound unit, and new unit is not an alternative
|
310
|
+
# to the whole compound but IS an alternative to one or more of the base units,
|
311
|
+
# e.g.,
|
312
|
+
#
|
313
|
+
# Unit.kilowatt_hour.to :second #=> 'kilowatt second'
|
314
|
+
#
|
315
|
+
def convert_compound_unit_to_non_equivalent_unit!(new_unit)
|
316
|
+
@unit.base_units.select do |base|
|
317
|
+
base.unit.is_alternative_for? new_unit
|
318
|
+
end.inject(self) do |quantity,base|
|
319
|
+
factor = Unit.ratio(new_unit**base.index, base.unit**base.index)
|
320
|
+
quantity.multiply!(factor).cancel_base_units!(base.unit)
|
321
|
+
end
|
322
|
+
end
|
323
|
+
|
324
|
+
def convert_compound_unit_to_si!
|
325
|
+
until @unit.is_base_quantity_si_unit? do
|
326
|
+
unit = @unit.base_units.find do |base|
|
327
|
+
!base.is_base_quantity_si_unit?
|
328
|
+
end.unit
|
329
|
+
self.convert_compound_unit_to_non_equivalent_unit!(unit.si_unit)
|
330
|
+
end
|
331
|
+
return self
|
332
|
+
end
|
336
333
|
|
337
334
|
# Enables shorthand for reciprocal of quantity, e.g.
|
338
335
|
#
|
@@ -17,6 +17,14 @@ module Quantify
|
|
17
17
|
def self.construct_and_load(unit,&block)
|
18
18
|
self.construct(unit, &block).load
|
19
19
|
end
|
20
|
+
|
21
|
+
def self.initialize_prefixed_version(prefix,unit)
|
22
|
+
prefix, unit = Prefix.for(prefix), Unit.for(unit)
|
23
|
+
raise Exceptions::InvalidArgumentError, "Prefix is not known" if prefix.nil?
|
24
|
+
raise Exceptions::InvalidArgumentError, "Unit is not known" if unit.nil?
|
25
|
+
raise Exceptions::InvalidArgumentError, "Cannot add prefix where one already exists: #{unit.prefix.name}" if unit.prefix
|
26
|
+
self.new &self.block_for_prefixed_version(prefix,unit)
|
27
|
+
end
|
20
28
|
|
21
29
|
# Mass load prefixed units. First argument is a single or array of units.
|
22
30
|
# Second argument is a single or array of prefixes. All specfied units will
|
@@ -36,9 +44,9 @@ module Quantify
|
|
36
44
|
# unit becomes a representation of the compound - without explicitly holding
|
37
45
|
# the base units, e.g.
|
38
46
|
#
|
39
|
-
# Unit::Base.
|
47
|
+
# Unit::Base.construct(Unit.m**2).name #=> "square metre"
|
40
48
|
#
|
41
|
-
# Unit::Base.
|
49
|
+
# Unit::Base.construct(Unit.m**3) do |unit|
|
42
50
|
# unit.name = "metres cubed"
|
43
51
|
# end.name #=> "metres cubed"
|
44
52
|
#
|
@@ -65,6 +73,7 @@ module Quantify
|
|
65
73
|
|
66
74
|
attr_reader :name, :symbol, :label, :factor, :dimensions
|
67
75
|
attr_reader :acts_as_alternative_unit, :acts_as_equivalent_unit
|
76
|
+
attr_accessor :base_unit, :prefix
|
68
77
|
|
69
78
|
# Create a new Unit::Base instance.
|
70
79
|
#
|
@@ -104,10 +113,13 @@ module Quantify
|
|
104
113
|
self.factor = 1.0
|
105
114
|
self.symbol = nil
|
106
115
|
self.label = nil
|
116
|
+
self.name = nil
|
117
|
+
self.base_unit = nil
|
118
|
+
self.prefix = nil
|
107
119
|
if options.is_a? Hash
|
108
|
-
self.dimensions = options[:dimensions] || options[:physical_quantity]
|
109
|
-
self.name = options[:name]
|
120
|
+
self.dimensions = options[:dimensions] || options[:physical_quantity] if options[:dimensions] || options[:physical_quantity]
|
110
121
|
self.factor = options[:factor] if options[:factor]
|
122
|
+
self.name = options[:name] if options[:name]
|
111
123
|
self.symbol = options[:symbol] if options[:symbol]
|
112
124
|
self.label = options[:label] if options[:label]
|
113
125
|
end
|
@@ -303,9 +315,7 @@ module Quantify
|
|
303
315
|
|
304
316
|
# Determine if the unit is a prefixed unit
|
305
317
|
def is_prefixed_unit?
|
306
|
-
|
307
|
-
self.name =~ /\A(#{valid_prefixes.map {|p| p.name}.join("|")})/
|
308
|
-
return false
|
318
|
+
self.prefix ? true : false
|
309
319
|
end
|
310
320
|
|
311
321
|
# Determine if the unit is one of the units against which all other units
|
@@ -428,31 +438,6 @@ module Quantify
|
|
428
438
|
@dimensions.is_a? Dimensions
|
429
439
|
end
|
430
440
|
|
431
|
-
# Returns an array representing the valid prefixes for the unit described
|
432
|
-
# by self
|
433
|
-
#
|
434
|
-
# If no argument is given, the array holds instances of Prefix::Base (or
|
435
|
-
# subclasses; SI, NonSI...). Alternatively only the names or symbols of each
|
436
|
-
# prefix can be returned by providing the appropriate prefix attribute as a
|
437
|
-
# symbolized argument, e.g.
|
438
|
-
#
|
439
|
-
# Unit.m.valid_prefixes #=> [ #<Quantify::Prefix: .. >,
|
440
|
-
# #<Quantify::Prefix: .. >,
|
441
|
-
# ... ]
|
442
|
-
#
|
443
|
-
# Unit.m.valid_prefixes :name #=> [ "deca", "hecto", "kilo",
|
444
|
-
# "mega", "giga", "tera"
|
445
|
-
# ... ]
|
446
|
-
#
|
447
|
-
# Unit.m.valid_prefixes :symbol #=> [ "da", "h", "k", "M", "G",
|
448
|
-
# "T", "P" ... ]
|
449
|
-
#
|
450
|
-
def valid_prefixes(by=nil)
|
451
|
-
return [] if is_compound_unit? && has_multiple_base_units?
|
452
|
-
return Unit::Prefix.si_prefixes.map(&by).to_a if is_si_unit?
|
453
|
-
return Unit::Prefix.non_si_prefixes.map(&by).to_a if is_non_si_unit?
|
454
|
-
end
|
455
|
-
|
456
441
|
# Multiply two units together. This results in the generation of a compound
|
457
442
|
# unit.
|
458
443
|
#
|
@@ -513,15 +498,7 @@ module Quantify
|
|
513
498
|
# of self, complete with modified name, symbol, factor, etc..
|
514
499
|
#
|
515
500
|
def with_prefix(name_or_symbol)
|
516
|
-
|
517
|
-
raise Exceptions::InvalidArgumentError, "Cannot add prefix where one already exists: #{self.name}" if @name =~ /\A(#{valid_prefixes(:name).join("|")})/
|
518
|
-
|
519
|
-
prefix = Unit::Prefix.for(name_or_symbol,valid_prefixes)
|
520
|
-
if !prefix.nil?
|
521
|
-
self.class.new(options_for_prefixed_version(prefix))
|
522
|
-
else
|
523
|
-
raise Exceptions::InvalidArgumentError, "Prefix unit is not known: #{prefix}"
|
524
|
-
end
|
501
|
+
self.class.initialize_prefixed_version(name_or_symbol,self)
|
525
502
|
end
|
526
503
|
|
527
504
|
# Return an array of new unit instances based upon self, together with the
|
@@ -558,16 +535,6 @@ module Quantify
|
|
558
535
|
end
|
559
536
|
|
560
537
|
private
|
561
|
-
|
562
|
-
def options_for_prefixed_version(prefix)
|
563
|
-
options = {}
|
564
|
-
options[:name] = "#{prefix.name}#{@name}"
|
565
|
-
options[:symbol] = "#{prefix.symbol}#{@symbol}"
|
566
|
-
options[:label] = "#{prefix.symbol}#{@label}"
|
567
|
-
options[:factor] = prefix.factor * @factor
|
568
|
-
options[:physical_quantity] = @dimensions
|
569
|
-
return options
|
570
|
-
end
|
571
538
|
|
572
539
|
# Clone self and explicitly clone the associated Dimensions object located
|
573
540
|
# at @dimensions.
|
@@ -581,6 +548,18 @@ module Quantify
|
|
581
548
|
super
|
582
549
|
instance_variable_set("@dimensions", @dimensions.clone)
|
583
550
|
end
|
551
|
+
|
552
|
+
def self.block_for_prefixed_version(prefix,unit)
|
553
|
+
return Proc.new do |new_unit|
|
554
|
+
new_unit.base_unit = unit.clone
|
555
|
+
new_unit.prefix = prefix
|
556
|
+
new_unit.dimensions = unit.dimensions.clone
|
557
|
+
new_unit.name = "#{prefix.name}#{unit.name}"
|
558
|
+
new_unit.factor = prefix.factor * unit.factor
|
559
|
+
new_unit.symbol = "#{prefix.symbol}#{unit.symbol}"
|
560
|
+
new_unit.label = "#{prefix.symbol}#{unit.label}"
|
561
|
+
end
|
562
|
+
end
|
584
563
|
|
585
564
|
# Provides syntactic sugar for several methods. E.g.
|
586
565
|
#
|
@@ -597,8 +576,6 @@ module Quantify
|
|
597
576
|
return self.with_prefix(prefix)
|
598
577
|
elsif method.to_s =~ /(alternatives_by_)(.*)/ && self.respond_to?($2.to_sym)
|
599
578
|
return self.alternatives($2.to_sym)
|
600
|
-
elsif method.to_s =~ /(valid_prefixes_by_)(.*)/ && Prefix::Base.instance_methods.include?($2.to_s)
|
601
|
-
return self.valid_prefixes($2.to_sym)
|
602
579
|
end
|
603
580
|
super
|
604
581
|
end
|
@@ -19,7 +19,14 @@ module Quantify
|
|
19
19
|
#
|
20
20
|
# The Compound class provides support for arbitrarily defined compound units
|
21
21
|
# which don't have well-established names.
|
22
|
-
|
22
|
+
|
23
|
+
def self.initialize_prefixed_version(prefix,compound)
|
24
|
+
if compound.has_multiple_base_units?
|
25
|
+
raise Exceptions::InvalidArgumentError, "Cannot apply prefix to compound unit with multiple base units: #{self.name}"
|
26
|
+
end
|
27
|
+
super
|
28
|
+
end
|
29
|
+
|
23
30
|
attr_reader :base_units, :acts_as_equivalent_unit
|
24
31
|
|
25
32
|
# Initialize a compound unit by providing an array containing a represenation
|
@@ -34,7 +41,7 @@ module Quantify
|
|
34
41
|
# 3. a sub-array of size 2 containing an instance of Unit::Base and an
|
35
42
|
# explicit index
|
36
43
|
#
|
37
|
-
def initialize(*units)
|
44
|
+
def initialize(*units,&block)
|
38
45
|
@base_units = CompoundBaseUnitList.new
|
39
46
|
units.each do |unit|
|
40
47
|
if unit.is_a? CompoundBaseUnit
|
@@ -50,6 +57,7 @@ module Quantify
|
|
50
57
|
end
|
51
58
|
@acts_as_alternative_unit = true
|
52
59
|
@acts_as_equivalent_unit = false
|
60
|
+
block.call(self) if block_given?
|
53
61
|
consolidate_numerator_and_denominator_units!
|
54
62
|
end
|
55
63
|
|
@@ -180,23 +188,24 @@ module Quantify
|
|
180
188
|
@base_units.rationalize_numerator_and_denominator!(*units)
|
181
189
|
initialize_attributes
|
182
190
|
end
|
183
|
-
|
191
|
+
|
184
192
|
private
|
185
193
|
|
186
194
|
def initialize_attributes
|
187
195
|
self.dimensions = @base_units.dimensions
|
188
|
-
self.name
|
189
|
-
self.symbol
|
190
|
-
self.factor
|
191
|
-
self.label
|
196
|
+
self.name = @base_units.name
|
197
|
+
self.symbol = @base_units.symbol
|
198
|
+
self.factor = @base_units.factor
|
199
|
+
self.label = @base_units.label
|
192
200
|
return self
|
193
201
|
end
|
194
|
-
|
195
|
-
def
|
196
|
-
|
197
|
-
base = @base_units.first
|
202
|
+
|
203
|
+
def self.block_for_prefixed_version(prefix,compound)
|
204
|
+
base = compound.base_units.first
|
198
205
|
base.unit = base.unit.with_prefix(prefix)
|
199
|
-
return
|
206
|
+
return Proc.new do |compound|
|
207
|
+
compound.base_units << base
|
208
|
+
end
|
200
209
|
end
|
201
210
|
|
202
211
|
def initialize_copy(source)
|
@@ -22,10 +22,10 @@ module Quantify
|
|
22
22
|
@prefixes
|
23
23
|
end
|
24
24
|
|
25
|
-
def self.for(name_or_symbol
|
25
|
+
def self.for(name_or_symbol)
|
26
26
|
return name_or_symbol.clone if name_or_symbol.is_a? Quantify::Unit::Prefix::Base
|
27
27
|
if name_or_symbol.is_a?(String) || name_or_symbol.is_a?(Symbol)
|
28
|
-
if prefix =
|
28
|
+
if prefix = @prefixes.find do |prefix|
|
29
29
|
prefix.name == name_or_symbol.remove_underscores.downcase ||
|
30
30
|
prefix.symbol == name_or_symbol.remove_underscores
|
31
31
|
end
|
@@ -64,7 +64,7 @@ module Quantify
|
|
64
64
|
elsif prefix = self.for(method)
|
65
65
|
return prefix
|
66
66
|
else
|
67
|
-
|
67
|
+
super
|
68
68
|
end
|
69
69
|
end
|
70
70
|
|
data/lib/quantify/unit/unit.rb
CHANGED
@@ -4,7 +4,7 @@ module Quantify
|
|
4
4
|
module Unit
|
5
5
|
|
6
6
|
extend ExtendedMethods
|
7
|
-
|
7
|
+
|
8
8
|
# The Unit module contains functionality for defining and handling
|
9
9
|
# representations of physical units.
|
10
10
|
#
|
@@ -19,7 +19,24 @@ module Quantify
|
|
19
19
|
# prefixes specified in config.rb. New units can be defined (with or without
|
20
20
|
# prefixes) at any time and either used in place or loaded into the known
|
21
21
|
# system.
|
22
|
+
|
23
|
+
NUMBER_REGEX = /([\d\s.,]+)/i
|
24
|
+
|
25
|
+
UNIT_DENOMINATOR_REGEX = /(\/|per)/i
|
26
|
+
|
27
|
+
ORDINAL_SUFFIXES_REGEX = /(st|nd|rd|th)\b/i
|
28
|
+
|
29
|
+
UNIT_PREFIX_TERMS_REGEX = /\A(square|cubic)\b/i
|
30
|
+
|
31
|
+
INDEX_REGEX = /\^?([\d\.-]*)/
|
22
32
|
|
33
|
+
WORD_WITH_INDEX_REGEX = /([^\d\s.,\^]+)#{INDEX_REGEX}?/i
|
34
|
+
|
35
|
+
UNIT_SUFFIX_TERMS_REGEX = /\A(squared|cubed|to the \d+(#{ORDINAL_SUFFIXES_REGEX}) power)\b/i
|
36
|
+
|
37
|
+
QUANTITY_REGEX = /#{Unit::NUMBER_REGEX}(#{Quantify::Unit::WORD_WITH_INDEX_REGEX})/i
|
38
|
+
|
39
|
+
|
23
40
|
class << self
|
24
41
|
attr_reader :units
|
25
42
|
end
|
@@ -221,6 +238,13 @@ module Quantify
|
|
221
238
|
return nil
|
222
239
|
end
|
223
240
|
|
241
|
+
def self.match(name_symbol_or_label)
|
242
|
+
return name_symbol_or_label.clone if name_symbol_or_label.is_a? Unit::Base
|
243
|
+
Unit.match_known_unit_or_prefixed_variant(:label, name_symbol_or_label) or
|
244
|
+
Unit.match_known_unit_or_prefixed_variant(:name, name_symbol_or_label) or
|
245
|
+
Unit.match_known_unit_or_prefixed_variant(:symbol, name_symbol_or_label)
|
246
|
+
end
|
247
|
+
|
224
248
|
# Parse complex strings into unit.
|
225
249
|
#
|
226
250
|
def self.parse(string, options={})
|
@@ -230,21 +254,43 @@ module Quantify
|
|
230
254
|
return units.first.unit if units.size == 1 && units.first.index == 1
|
231
255
|
return Unit::Compound.new(*units)
|
232
256
|
end
|
257
|
+
|
258
|
+
# This returns the suite of units which represents THE SI units for each of
|
259
|
+
# the base dimensions, i.e. metre, kilogram, second, etc. but not prefixed
|
260
|
+
# versions of the same unit
|
261
|
+
#
|
262
|
+
def self.base_quantity_si_units
|
263
|
+
@units.select {|unit| unit.is_base_quantity_si_unit? }
|
264
|
+
end
|
265
|
+
|
266
|
+
# This can be replicated by method missing approach, but explicit method provided
|
267
|
+
# given importance in #match (and #for) methods regexen
|
268
|
+
#
|
269
|
+
def self.non_prefixed_units
|
270
|
+
@units.select {|unit| !unit.is_prefixed_unit? }
|
271
|
+
end
|
233
272
|
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
273
|
+
# This can be replicated by method missing approach, but explicit method provided
|
274
|
+
# given importance in #match (and #for) methods regexen
|
275
|
+
#
|
276
|
+
def self.si_non_prefixed_units
|
277
|
+
@units.select {|unit| unit.is_si_unit? && !unit.is_prefixed_unit? }
|
239
278
|
end
|
240
279
|
|
280
|
+
# This can be replicated by method missing approach, but explicit method provided
|
281
|
+
# given importance in #match (and #for) methods regexen
|
282
|
+
#
|
283
|
+
def self.non_si_non_prefixed_units
|
284
|
+
@units.select {|unit| unit.is_non_si_unit? && !unit.is_prefixed_unit? }
|
285
|
+
end
|
286
|
+
|
241
287
|
protected
|
242
|
-
|
288
|
+
|
243
289
|
def self.match_known_unit_or_prefixed_variant(attribute, string_or_symbol)
|
244
290
|
Unit.match_known_unit(attribute, string_or_symbol) or
|
245
291
|
Unit.match_prefixed_variant(attribute, string_or_symbol)
|
246
292
|
end
|
247
|
-
|
293
|
+
|
248
294
|
def self.match_known_unit(attribute, string_or_symbol)
|
249
295
|
string_or_symbol = Unit.format_unit_attribute(attribute, string_or_symbol)
|
250
296
|
@units.find do |unit|
|
@@ -256,46 +302,52 @@ module Quantify
|
|
256
302
|
end
|
257
303
|
end.clone rescue nil
|
258
304
|
end
|
259
|
-
|
305
|
+
|
260
306
|
def self.match_prefixed_variant(attribute, string_or_symbol)
|
261
307
|
string_or_symbol = Unit.format_unit_attribute(attribute, string_or_symbol)
|
262
|
-
if string_or_symbol =~ /\A(#{
|
263
|
-
string_or_symbol =~ /\A(#{units_for_regex(Unit::Prefix,:non_si_prefixes,attribute)})(#{units_for_regex(Unit,:non_si_non_prefixed_units,attribute)})\z/
|
308
|
+
if string_or_symbol =~ /\A(#{Unit.terms_for_regex(Unit::Prefix,:prefixes,attribute)})(#{Unit.terms_for_regex(Unit,:non_prefixed_units,attribute)})\z/
|
264
309
|
return Unit.for($2).with_prefix($1).clone
|
265
310
|
end
|
266
311
|
return nil
|
267
312
|
end
|
268
|
-
|
313
|
+
|
269
314
|
def self.simple_parse(string)
|
270
|
-
if string.scan(
|
315
|
+
if string.scan(UNIT_DENOMINATOR_REGEX).size > 1
|
271
316
|
raise Exceptions::InvalidArgumentError, "Malformed unit: multiple uses of '/' or 'per'"
|
272
317
|
end
|
273
318
|
units = []
|
274
|
-
numerator, per, denominator = string.split(
|
319
|
+
numerator, per, denominator = string.split(UNIT_DENOMINATOR_REGEX)
|
275
320
|
units += Unit.parse_numerator_units(numerator)
|
276
321
|
units += Unit.parse_denominator_units(denominator) unless denominator.nil?
|
277
322
|
return units
|
278
323
|
end
|
279
|
-
|
324
|
+
|
280
325
|
def self.iterative_parse(string)
|
281
326
|
units=[]
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
if
|
286
|
-
|
327
|
+
is_denominator = false
|
328
|
+
current_exponent = nil
|
329
|
+
while term = string.starts_with_valid_unit_term? do
|
330
|
+
if term =~ /^#{UNIT_PREFIX_TERMS_REGEX}$/
|
331
|
+
current_exponent = Unit.exponent_term_to_number(term)
|
332
|
+
elsif term =~ /^#{UNIT_SUFFIX_TERMS_REGEX}$/
|
333
|
+
units.last.index *= Unit.exponent_term_to_number(term)
|
334
|
+
elsif term =~ /^#{UNIT_DENOMINATOR_REGEX}/
|
335
|
+
is_denominator = true
|
287
336
|
else
|
288
|
-
|
337
|
+
unit = Unit.send("parse_#{is_denominator ? 'denominator' : 'numerator'}_units".to_sym, term).first
|
338
|
+
unit.index *= current_exponent if current_exponent
|
339
|
+
units << unit
|
340
|
+
current_exponent = nil
|
289
341
|
end
|
290
342
|
# Remove matched pattern from string for next iteration
|
291
|
-
match_length =
|
343
|
+
match_length = term.size
|
292
344
|
string = string[match_length, string.length-match_length].strip
|
293
345
|
end
|
294
346
|
return units
|
295
347
|
end
|
296
348
|
|
297
349
|
def self.parse_unit_and_index(string)
|
298
|
-
string.scan(
|
350
|
+
string.scan(WORD_WITH_INDEX_REGEX)
|
299
351
|
index = ($2.nil? || $2.empty? ? 1 : $2.to_i)
|
300
352
|
unit = Unit.match($1.to_s)
|
301
353
|
if unit.is_a? Compound
|
@@ -304,7 +356,7 @@ module Quantify
|
|
304
356
|
return CompoundBaseUnit.new($1.to_s, index)
|
305
357
|
end
|
306
358
|
end
|
307
|
-
|
359
|
+
|
308
360
|
def self.parse_numerator_units(string)
|
309
361
|
# If no middot then names parsed by whitespace
|
310
362
|
if string =~ /·/
|
@@ -316,14 +368,14 @@ module Quantify
|
|
316
368
|
Unit.parse_unit_and_index(substring)
|
317
369
|
end.flatten
|
318
370
|
end
|
319
|
-
|
371
|
+
|
320
372
|
def self.parse_denominator_units(string)
|
321
373
|
Unit.parse_numerator_units(string).map do |unit|
|
322
374
|
unit.index *= -1
|
323
375
|
unit
|
324
376
|
end
|
325
377
|
end
|
326
|
-
|
378
|
+
|
327
379
|
# standardize query strings or symbols into canonical form for unit names,
|
328
380
|
# symbols and labels
|
329
381
|
#
|
@@ -334,64 +386,24 @@ module Quantify
|
|
334
386
|
else string_or_symbol.to_s
|
335
387
|
end
|
336
388
|
Unit.use_superscript_characters? ?
|
337
|
-
|
389
|
+
string_or_symbol.with_superscript_characters : string_or_symbol.without_superscript_characters
|
338
390
|
end
|
339
391
|
|
340
|
-
# This returns the suite of units which represents THE SI units for each of
|
341
|
-
# the base dimensions, i.e. metre, kilogram, second, etc. but not prefixed
|
342
|
-
# versions of the same unit
|
343
|
-
#
|
344
|
-
def self.base_quantity_si_units
|
345
|
-
@units.select {|unit| unit.is_base_quantity_si_unit? }
|
346
|
-
end
|
347
|
-
|
348
|
-
# This can be replicated by method missing approach, but explicit method provided
|
349
|
-
# given importance in #match (and #for) methods regexen
|
350
|
-
#
|
351
|
-
def self.si_non_prefixed_units
|
352
|
-
@units.select {|unit| unit.is_si_unit? && !unit.is_prefixed_unit? }
|
353
|
-
end
|
354
|
-
|
355
|
-
# This can be replicated by method missing approach, but explicit method provided
|
356
|
-
# given importance in #match (and #for) methods regexen
|
357
|
-
#
|
358
|
-
def self.non_si_non_prefixed_units
|
359
|
-
@units.select {|unit| unit.is_non_si_unit? && !unit.is_prefixed_unit? }
|
360
|
-
end
|
361
|
-
|
362
392
|
# Return a list of unit names which are multi-word
|
363
393
|
def self.multi_word_unit_names
|
364
|
-
|
394
|
+
Unit.units.map {|unit| unit.name if unit.name.word_count > 1 }.compact
|
365
395
|
end
|
366
|
-
|
396
|
+
|
367
397
|
# Return a list of pluralised unit names which are multi-word
|
368
398
|
def self.multi_word_unit_pluralized_names
|
369
399
|
multi_word_unit_names.map {|name| name.pluralize }
|
370
400
|
end
|
371
|
-
|
401
|
+
|
372
402
|
# Return a list of unit symbols which are multi-word
|
373
403
|
def self.multi_word_unit_symbols
|
374
|
-
|
375
|
-
end
|
376
|
-
|
377
|
-
# might want to try atomic groupings, but must get units in size order perhaps first
|
378
|
-
def self.unit_label_regex
|
379
|
-
/\A((#{Unit.units_for_regex(Unit::Prefix,:non_si_prefixes,:label)})?((#{Unit.units_for_regex(Unit,:non_si_non_prefixed_units,:label)})\b)|(#{Unit.units_for_regex(Unit::Prefix,:si_prefixes,:label)})?((#{Unit.units_for_regex(Unit,:si_non_prefixed_units,:label)})\b))(\^[\d\.-]*)?/
|
380
|
-
end
|
381
|
-
|
382
|
-
def self.unit_symbol_regex
|
383
|
-
/\A((#{Unit.units_for_regex(Unit::Prefix,:si_prefixes,:symbol)})?((#{Unit.units_for_regex(Unit,:si_non_prefixed_units,:symbol)})\b)|(#{Unit.units_for_regex(Unit::Prefix,:non_si_prefixes,:symbol)})?((#{Unit.units_for_regex(Unit,:non_si_non_prefixed_units,:symbol)})\b))(\^[\d\.-]*)?/
|
404
|
+
Unit.units.map {|unit| unit.symbol if unit.symbol.word_count > 1 }.compact
|
384
405
|
end
|
385
|
-
|
386
|
-
def self.unit_name_regex
|
387
|
-
# Specifically case insensitive
|
388
|
-
/\A((#{Unit.units_for_regex(Unit::Prefix,:non_si_prefixes,:name)})?((#{Unit.units_for_regex(Unit,:non_si_non_prefixed_units,:pluralized_name)}|#{Unit.units_for_regex(Unit,:non_si_non_prefixed_units,:name)})\b)|(#{Unit.units_for_regex(Unit::Prefix,:si_prefixes,:name)})?((#{Unit.units_for_regex(Unit,:si_non_prefixed_units,:pluralized_name)}|#{Unit.units_for_regex(Unit,:si_non_prefixed_units,:name)})\b))(\^[\d\.-]*)?/i
|
389
|
-
end
|
390
|
-
|
391
|
-
def self.unit_denominator_regex
|
392
|
-
/\A(\/|per)/i
|
393
|
-
end
|
394
|
-
|
406
|
+
|
395
407
|
# Underscore any parts of string which represent multi-word unit identifiers
|
396
408
|
# so that units can be parsed on whitespace
|
397
409
|
#
|
@@ -401,14 +413,34 @@ module Quantify
|
|
401
413
|
end
|
402
414
|
string
|
403
415
|
end
|
404
|
-
|
416
|
+
|
417
|
+
def self.exponent_term_to_number(term)
|
418
|
+
return 2 if /square(d)?/i.match(term)
|
419
|
+
return 3 if /cub(ic|ed)/i.match(term)
|
420
|
+
end
|
421
|
+
|
405
422
|
# Returns a list of "|" separated unit identifiers for use as regex
|
406
423
|
# alternatives. Lists are constructed by calling
|
407
|
-
def self.
|
424
|
+
def self.terms_for_regex(klass,method,attribute)
|
408
425
|
list = klass.send(method).map { |item| item.send(attribute).gsub("/","\\/").gsub("^","\\^") }
|
409
426
|
list.map! { |item| item.downcase } if attribute == :name
|
427
|
+
list.reject! { |item| item == "" }
|
410
428
|
list.sort {|x, y| y.size <=> x.size }.join("|")
|
411
429
|
end
|
412
|
-
|
430
|
+
|
431
|
+
def self.unit_label_regex
|
432
|
+
/(#{Unit.terms_for_regex(Unit::Prefix,:prefixes,:label)})??((#{Unit.terms_for_regex(Unit,:non_prefixed_units,:label)})\b)/
|
433
|
+
end
|
434
|
+
|
435
|
+
def self.unit_symbol_regex
|
436
|
+
/(#{Unit.terms_for_regex(Unit::Prefix,:prefixes,:symbol)})??((#{Unit.terms_for_regex(Unit,:non_prefixed_units,:symbol)})\b)/
|
437
|
+
end
|
438
|
+
|
439
|
+
def self.unit_name_regex
|
440
|
+
# Specifically case insensitive
|
441
|
+
# Double '?' (i.e. '??') makes prefix matching lazy, e.g. "centimetres of mercury" is matched fully rather than as 'centimetres'
|
442
|
+
/(#{Unit.terms_for_regex(Unit::Prefix,:prefixes,:name)})??((#{Unit.terms_for_regex(Unit,:non_prefixed_units,:pluralized_name)}|#{Unit.terms_for_regex(Unit,:non_prefixed_units,:name)})\b)/i
|
443
|
+
end
|
444
|
+
|
413
445
|
end
|
414
446
|
end
|
data/quantify.gemspec
CHANGED
@@ -4,14 +4,14 @@
|
|
4
4
|
# -*- encoding: utf-8 -*-
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
|
-
s.name =
|
8
|
-
s.version = "3.
|
7
|
+
s.name = "quantify"
|
8
|
+
s.version = "3.1.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Andrew Berkeley"]
|
12
|
-
s.date =
|
13
|
-
s.description =
|
14
|
-
s.email =
|
12
|
+
s.date = "2011-12-21"
|
13
|
+
s.description = "A gem to support physical quantities and unit conversions"
|
14
|
+
s.email = "andrew.berkeley.is@googlemail.com"
|
15
15
|
s.extra_rdoc_files = [
|
16
16
|
"README"
|
17
17
|
]
|
@@ -30,7 +30,6 @@ Gem::Specification.new do |s|
|
|
30
30
|
"lib/quantify/dimensions.rb",
|
31
31
|
"lib/quantify/exception.rb",
|
32
32
|
"lib/quantify/inflections.rb",
|
33
|
-
"lib/quantify/parser.rb",
|
34
33
|
"lib/quantify/quantify.rb",
|
35
34
|
"lib/quantify/quantity.rb",
|
36
35
|
"lib/quantify/unit/base_unit.rb",
|
@@ -47,16 +46,15 @@ Gem::Specification.new do |s|
|
|
47
46
|
"quantify.gemspec",
|
48
47
|
"spec/compound_unit_spec.rb",
|
49
48
|
"spec/dimension_spec.rb",
|
50
|
-
"spec/quantify_spec.rb",
|
51
49
|
"spec/quantity_spec.rb",
|
52
50
|
"spec/string_spec.rb",
|
53
51
|
"spec/unit_spec.rb"
|
54
52
|
]
|
55
|
-
s.homepage =
|
53
|
+
s.homepage = "https://github.com/spatchcock/quantify"
|
56
54
|
s.licenses = ["MIT"]
|
57
55
|
s.require_paths = ["lib"]
|
58
|
-
s.rubygems_version =
|
59
|
-
s.summary =
|
56
|
+
s.rubygems_version = "1.8.10"
|
57
|
+
s.summary = "Support for handling physical quantities, unit conversions, etc"
|
60
58
|
|
61
59
|
if s.respond_to? :specification_version then
|
62
60
|
s.specification_version = 3
|
data/spec/compound_unit_spec.rb
CHANGED
@@ -285,22 +285,7 @@ describe Unit do
|
|
285
285
|
|
286
286
|
end
|
287
287
|
|
288
|
-
describe "adding prefixes" do
|
289
|
-
|
290
|
-
it "should have no valid prefixes with multiple base units" do
|
291
|
-
(Unit.kg*Unit.m*Unit.m/Unit.s/Unit.s).valid_prefixes.should be_empty
|
292
|
-
end
|
293
|
-
|
294
|
-
it "should return SI prefixes with single SI unit" do
|
295
|
-
prefixes = (Unit.kg**3).valid_prefixes
|
296
|
-
prefixes.should_not be_empty
|
297
|
-
prefixes.first.should be_a Unit::Prefix::SI
|
298
|
-
end
|
299
|
-
|
300
|
-
it "should return SI prefixes with single SI unit" do
|
301
|
-
prefixes = (Unit.lb**3).valid_prefixes
|
302
|
-
prefixes.should be_empty # no NonSI prefixes defined
|
303
|
-
end
|
288
|
+
describe "adding prefixes" do
|
304
289
|
|
305
290
|
it "should refuse to add prefix to multi-unit compound unit" do
|
306
291
|
lambda{(Unit.kg*Unit.m*Unit.m/Unit.s/Unit.s).with_prefix(:giga)}.should raise_error
|
data/spec/quantity_spec.rb
CHANGED
@@ -89,6 +89,16 @@ describe Quantity do
|
|
89
89
|
quantities[1].unit.pluralized_name.should == 'kilograms per tonne kilometre'
|
90
90
|
quantities[1].unit.symbol.should == 'kg/t km'
|
91
91
|
end
|
92
|
+
|
93
|
+
it "should create a valid instance from complex string with compound per unit and no spaces" do
|
94
|
+
quantities = Quantity.parse "We sent some freight 6000 nautical miles by ship and the emissions rate was 10 kg/t km"
|
95
|
+
quantities.first.value.should == 6000
|
96
|
+
quantities.first.unit.name.should == 'nautical mile'
|
97
|
+
quantities.first.unit.symbol.should == 'nmi'
|
98
|
+
quantities[1].value.should == 10
|
99
|
+
quantities[1].unit.pluralized_name.should == 'kilograms per tonne kilometre'
|
100
|
+
quantities[1].unit.symbol.should == 'kg/t km'
|
101
|
+
end
|
92
102
|
|
93
103
|
it "should create valid instances from complex string" do
|
94
104
|
quantities = Quantity.parse "I travelled 220 miles driving my car and using 0.13 UK gallons per mile of diesel"
|
@@ -153,6 +163,34 @@ describe Quantity do
|
|
153
163
|
quantities[1].unit.pluralized_name.should == 'square metres'
|
154
164
|
quantities[1].unit.symbol.should == 'm²'
|
155
165
|
end
|
166
|
+
|
167
|
+
it "should create valid instance from string with 'square' prefix descriptor" do
|
168
|
+
quantities = Quantity.parse "25 square feet"
|
169
|
+
quantities.first.value.should == 25
|
170
|
+
quantities.first.unit.name.should == 'square foot'
|
171
|
+
quantities.first.unit.symbol.should == 'ft²'
|
172
|
+
end
|
173
|
+
|
174
|
+
it "should create valid instance from string with 'cubic' prefix descriptor" do
|
175
|
+
quantities = Quantity.parse "25 cubic feet"
|
176
|
+
quantities.first.value.should == 25
|
177
|
+
quantities.first.unit.name.should == 'cubic foot'
|
178
|
+
quantities.first.unit.symbol.should == 'ft³'
|
179
|
+
end
|
180
|
+
|
181
|
+
it "should create valid instance from string with 'squared' suffix descriptor" do
|
182
|
+
quantities = Quantity.parse "25 feet squared"
|
183
|
+
quantities.first.value.should == 25
|
184
|
+
quantities.first.unit.name.should == 'square foot'
|
185
|
+
quantities.first.unit.symbol.should == 'ft²'
|
186
|
+
end
|
187
|
+
|
188
|
+
it "should create valid instance from string with 'cubed' suffix descriptor" do
|
189
|
+
quantities = Quantity.parse "25 feet cubed"
|
190
|
+
quantities.first.value.should == 25
|
191
|
+
quantities.first.unit.name.should == 'cubic foot'
|
192
|
+
quantities.first.unit.symbol.should == 'ft³'
|
193
|
+
end
|
156
194
|
|
157
195
|
it "should create valid instances from complex string with no spaces" do
|
158
196
|
quantities = Quantity.parse "I sprayed 500L of fertilizer across 6000m^2 of farmland"
|
data/spec/unit_spec.rb
CHANGED
@@ -241,7 +241,7 @@ describe Unit do
|
|
241
241
|
lambda{Unit.M}.should raise_error
|
242
242
|
|
243
243
|
Unit.Gg.name.should eql 'gigagram'
|
244
|
-
|
244
|
+
Unit.GG.name.should eql 'gigagauss'
|
245
245
|
end
|
246
246
|
|
247
247
|
it "should NOT ignore case when initialising units by label" do
|
@@ -319,10 +319,6 @@ describe Unit do
|
|
319
319
|
unit.factor.should == 1000
|
320
320
|
end
|
321
321
|
|
322
|
-
it "dynamic unit retrieval with name and invalid prefix should throw error" do
|
323
|
-
lambda{Unit.megafoot}.should raise_error
|
324
|
-
end
|
325
|
-
|
326
322
|
it "dynamic unit retrieval with symbol should be successful" do
|
327
323
|
Unit.m.name.should == 'metre'
|
328
324
|
Unit.ft.symbol.should == 'ft'
|
@@ -342,7 +338,6 @@ describe Unit do
|
|
342
338
|
|
343
339
|
it "dynamic unit retrieval with symbol and invalid prefix should raise error" do
|
344
340
|
lambda{Unit.MMm}.should raise_error
|
345
|
-
lambda{Unit.Gft}.should raise_error
|
346
341
|
lambda{Unit.centimetre.with_prefix :kilo}.should raise_error
|
347
342
|
end
|
348
343
|
|
@@ -1060,12 +1055,12 @@ describe Unit do
|
|
1060
1055
|
lambda{Unit.kilometre.with_prefix :giga}.should raise_error
|
1061
1056
|
end
|
1062
1057
|
|
1063
|
-
it "should add prefix with
|
1058
|
+
it "should add prefix with explicit method" do
|
1064
1059
|
Unit.metre.with_prefix(:c).name.should == 'centimetre'
|
1065
|
-
end
|
1060
|
+
end
|
1066
1061
|
|
1067
|
-
it "
|
1068
|
-
|
1062
|
+
it "should pluralise uncountable unit with prefix correctly" do
|
1063
|
+
Unit.siemens.with_prefix(:kilo).name.should == 'kilosiemens'
|
1069
1064
|
end
|
1070
1065
|
|
1071
1066
|
end
|
@@ -1075,6 +1070,7 @@ describe Unit do
|
|
1075
1070
|
it "should represent the pound mole correctly" do
|
1076
1071
|
unit = Unit.lbmol
|
1077
1072
|
unit.name.should eql 'pound mole'
|
1073
|
+
unit.pluralized_name.should eql 'pound moles'
|
1078
1074
|
Unit.ratio(Unit.mol,unit).value.should eql 453.59237
|
1079
1075
|
unit.alternatives_by_name.should eql ['mole']
|
1080
1076
|
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: quantify
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 3
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 3
|
8
|
+
- 1
|
8
9
|
- 0
|
9
|
-
|
10
|
-
version: 3.0.0
|
10
|
+
version: 3.1.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Andrew Berkeley
|
@@ -15,12 +15,10 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-
|
19
|
-
default_executable:
|
18
|
+
date: 2011-12-21 00:00:00 Z
|
20
19
|
dependencies:
|
21
20
|
- !ruby/object:Gem::Dependency
|
22
|
-
|
23
|
-
version_requirements: &id001 !ruby/object:Gem::Requirement
|
21
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
24
22
|
none: false
|
25
23
|
requirements:
|
26
24
|
- - ~>
|
@@ -30,12 +28,12 @@ dependencies:
|
|
30
28
|
- 3
|
31
29
|
- 0
|
32
30
|
version: "3.0"
|
31
|
+
version_requirements: *id001
|
32
|
+
name: activesupport
|
33
33
|
prerelease: false
|
34
34
|
type: :runtime
|
35
|
-
requirement: *id001
|
36
35
|
- !ruby/object:Gem::Dependency
|
37
|
-
|
38
|
-
version_requirements: &id002 !ruby/object:Gem::Requirement
|
36
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
39
37
|
none: false
|
40
38
|
requirements:
|
41
39
|
- - ">="
|
@@ -44,12 +42,12 @@ dependencies:
|
|
44
42
|
segments:
|
45
43
|
- 0
|
46
44
|
version: "0"
|
45
|
+
version_requirements: *id002
|
46
|
+
name: i18n
|
47
47
|
prerelease: false
|
48
48
|
type: :runtime
|
49
|
-
requirement: *id002
|
50
49
|
- !ruby/object:Gem::Dependency
|
51
|
-
|
52
|
-
version_requirements: &id003 !ruby/object:Gem::Requirement
|
50
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
53
51
|
none: false
|
54
52
|
requirements:
|
55
53
|
- - ~>
|
@@ -60,12 +58,12 @@ dependencies:
|
|
60
58
|
- 0
|
61
59
|
- 0
|
62
60
|
version: 1.0.0
|
61
|
+
version_requirements: *id003
|
62
|
+
name: bundler
|
63
63
|
prerelease: false
|
64
64
|
type: :development
|
65
|
-
requirement: *id003
|
66
65
|
- !ruby/object:Gem::Dependency
|
67
|
-
|
68
|
-
version_requirements: &id004 !ruby/object:Gem::Requirement
|
66
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
69
67
|
none: false
|
70
68
|
requirements:
|
71
69
|
- - ~>
|
@@ -76,12 +74,12 @@ dependencies:
|
|
76
74
|
- 6
|
77
75
|
- 4
|
78
76
|
version: 1.6.4
|
77
|
+
version_requirements: *id004
|
78
|
+
name: jeweler
|
79
79
|
prerelease: false
|
80
80
|
type: :development
|
81
|
-
requirement: *id004
|
82
81
|
- !ruby/object:Gem::Dependency
|
83
|
-
|
84
|
-
version_requirements: &id005 !ruby/object:Gem::Requirement
|
82
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
85
83
|
none: false
|
86
84
|
requirements:
|
87
85
|
- - ~>
|
@@ -92,12 +90,12 @@ dependencies:
|
|
92
90
|
- 6
|
93
91
|
- 0
|
94
92
|
version: 2.6.0
|
93
|
+
version_requirements: *id005
|
94
|
+
name: rspec
|
95
95
|
prerelease: false
|
96
96
|
type: :development
|
97
|
-
requirement: *id005
|
98
97
|
- !ruby/object:Gem::Dependency
|
99
|
-
|
100
|
-
version_requirements: &id006 !ruby/object:Gem::Requirement
|
98
|
+
requirement: &id006 !ruby/object:Gem::Requirement
|
101
99
|
none: false
|
102
100
|
requirements:
|
103
101
|
- - ">="
|
@@ -106,12 +104,12 @@ dependencies:
|
|
106
104
|
segments:
|
107
105
|
- 0
|
108
106
|
version: "0"
|
107
|
+
version_requirements: *id006
|
108
|
+
name: rcov
|
109
109
|
prerelease: false
|
110
110
|
type: :development
|
111
|
-
requirement: *id006
|
112
111
|
- !ruby/object:Gem::Dependency
|
113
|
-
|
114
|
-
version_requirements: &id007 !ruby/object:Gem::Requirement
|
112
|
+
requirement: &id007 !ruby/object:Gem::Requirement
|
115
113
|
none: false
|
116
114
|
requirements:
|
117
115
|
- - ">="
|
@@ -120,9 +118,10 @@ dependencies:
|
|
120
118
|
segments:
|
121
119
|
- 0
|
122
120
|
version: "0"
|
121
|
+
version_requirements: *id007
|
122
|
+
name: rdoc
|
123
123
|
prerelease: false
|
124
124
|
type: :development
|
125
|
-
requirement: *id007
|
126
125
|
description: A gem to support physical quantities and unit conversions
|
127
126
|
email: andrew.berkeley.is@googlemail.com
|
128
127
|
executables: []
|
@@ -146,7 +145,6 @@ files:
|
|
146
145
|
- lib/quantify/dimensions.rb
|
147
146
|
- lib/quantify/exception.rb
|
148
147
|
- lib/quantify/inflections.rb
|
149
|
-
- lib/quantify/parser.rb
|
150
148
|
- lib/quantify/quantify.rb
|
151
149
|
- lib/quantify/quantity.rb
|
152
150
|
- lib/quantify/unit/base_unit.rb
|
@@ -163,11 +161,9 @@ files:
|
|
163
161
|
- quantify.gemspec
|
164
162
|
- spec/compound_unit_spec.rb
|
165
163
|
- spec/dimension_spec.rb
|
166
|
-
- spec/quantify_spec.rb
|
167
164
|
- spec/quantity_spec.rb
|
168
165
|
- spec/string_spec.rb
|
169
166
|
- spec/unit_spec.rb
|
170
|
-
has_rdoc: true
|
171
167
|
homepage: https://github.com/spatchcock/quantify
|
172
168
|
licenses:
|
173
169
|
- MIT
|
@@ -197,7 +193,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
197
193
|
requirements: []
|
198
194
|
|
199
195
|
rubyforge_project:
|
200
|
-
rubygems_version: 1.
|
196
|
+
rubygems_version: 1.8.10
|
201
197
|
signing_key:
|
202
198
|
specification_version: 3
|
203
199
|
summary: Support for handling physical quantities, unit conversions, etc
|
data/lib/quantify/parser.rb
DELETED