quantify 2.0.2 → 3.0.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/config.rb +2 -0
- data/lib/quantify/core_extensions/string.rb +4 -0
- data/lib/quantify/parser.rb +7 -0
- data/lib/quantify/quantity.rb +32 -15
- data/lib/quantify/unit/base_unit.rb +1 -0
- data/lib/quantify/unit/unit.rb +81 -30
- data/quantify.gemspec +4 -3
- data/spec/quantity_spec.rb +142 -20
- data/spec/unit_spec.rb +11 -3
- metadata +37 -36
data/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
3.0.0
|
data/lib/quantify/config.rb
CHANGED
data/lib/quantify/quantity.rb
CHANGED
|
@@ -44,13 +44,23 @@ module Quantify
|
|
|
44
44
|
|
|
45
45
|
|
|
46
46
|
# Parse a string and return a Quantity object based upon the value and
|
|
47
|
-
# subseqent unit name, symbol or JScience label
|
|
47
|
+
# subseqent unit name, symbol or JScience label. Returns an array containing
|
|
48
|
+
# quantity objects for each quantity recognised.
|
|
48
49
|
def self.parse(string)
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
50
|
+
words = string.words
|
|
51
|
+
quantities = words.each_with_index.map do |word,index|
|
|
52
|
+
if word.starts_with_number?
|
|
53
|
+
# Isolate number from subsequent string
|
|
54
|
+
value, string = word, words[index+1..-1].join(" ")
|
|
55
|
+
# Shift any trailing non-numeric characters to start of string.
|
|
56
|
+
value, string = $1, "#{$2} #{string}" if (/([\d\s.,]+)([^\d\s.,\^]+(\^[\d\.-]*)?)/i).match(word)
|
|
57
|
+
# Parse string for unit references
|
|
58
|
+
unit = Unit.parse(string, :iterative => true) || Unit.dimensionless
|
|
59
|
+
# Instantiate quantity using value and unit
|
|
60
|
+
Quantity.new(value,unit)
|
|
61
|
+
end
|
|
62
|
+
end.compact
|
|
63
|
+
return quantities
|
|
54
64
|
rescue Quantify::Exceptions::InvalidArgumentError
|
|
55
65
|
raise Quantify::Exceptions::QuantityParseError, "Cannot parse string into value and unit"
|
|
56
66
|
end
|
|
@@ -58,6 +68,17 @@ module Quantify
|
|
|
58
68
|
def self.configure(&block)
|
|
59
69
|
self.class_eval(&block) if block
|
|
60
70
|
end
|
|
71
|
+
|
|
72
|
+
protected
|
|
73
|
+
|
|
74
|
+
def self.is_basic_conversion_with_scalings?(quantity,new_unit)
|
|
75
|
+
return true if (quantity.unit.has_scaling? || new_unit.has_scaling?) &&
|
|
76
|
+
!quantity.unit.is_compound_unit? &&
|
|
77
|
+
!new_unit.is_compound_unit?
|
|
78
|
+
return false
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
public
|
|
61
82
|
|
|
62
83
|
attr_accessor :value, :unit
|
|
63
84
|
|
|
@@ -74,7 +95,7 @@ module Quantify
|
|
|
74
95
|
# quantity which is represented by the Dimensions object in the Quantity unit.
|
|
75
96
|
# e.g.
|
|
76
97
|
#
|
|
77
|
-
# Quantity.parse(
|
|
98
|
+
# Quantity.parse("25 yr").represents #=> :time
|
|
78
99
|
#
|
|
79
100
|
# 1.foot.represents #=> :length
|
|
80
101
|
#
|
|
@@ -119,7 +140,7 @@ module Quantify
|
|
|
119
140
|
#
|
|
120
141
|
def to(new_unit)
|
|
121
142
|
new_unit = Unit.for new_unit
|
|
122
|
-
if is_basic_conversion_with_scalings?
|
|
143
|
+
if Quantity.is_basic_conversion_with_scalings?(self,new_unit)
|
|
123
144
|
Quantity.new(@value,@unit).conversion_with_scalings! new_unit
|
|
124
145
|
elsif self.unit.is_alternative_for? new_unit
|
|
125
146
|
Quantity.new(@value,@unit).convert_to_equivalent_unit! new_unit
|
|
@@ -130,13 +151,6 @@ module Quantify
|
|
|
130
151
|
end
|
|
131
152
|
end
|
|
132
153
|
|
|
133
|
-
def is_basic_conversion_with_scalings?(new_unit)
|
|
134
|
-
return true if (@unit.has_scaling? || new_unit.has_scaling?) &&
|
|
135
|
-
!@unit.is_compound_unit? &&
|
|
136
|
-
!new_unit.is_compound_unit?
|
|
137
|
-
return false
|
|
138
|
-
end
|
|
139
|
-
|
|
140
154
|
# Conversion where both units (including compound units) are of precisely
|
|
141
155
|
# equivalent dimensions, i.e. direct alternatives for one another. Where
|
|
142
156
|
# previous unit is a compound unit, new unit must be cancelled by all original
|
|
@@ -317,6 +331,9 @@ module Quantify
|
|
|
317
331
|
range.include? self
|
|
318
332
|
end
|
|
319
333
|
|
|
334
|
+
protected :convert_compound_unit_to_si!, :add_or_subtract!, :multiply_or_divide!
|
|
335
|
+
|
|
336
|
+
|
|
320
337
|
# Enables shorthand for reciprocal of quantity, e.g.
|
|
321
338
|
#
|
|
322
339
|
# quantity = 2.m
|
data/lib/quantify/unit/unit.rb
CHANGED
|
@@ -173,6 +173,12 @@ module Quantify
|
|
|
173
173
|
Quantity.new(value, new_unit)
|
|
174
174
|
end
|
|
175
175
|
|
|
176
|
+
def self.dimensionless
|
|
177
|
+
Unit::Base.new(:dimensions => 'dimensionless') do |unit|
|
|
178
|
+
unit.acts_as_alternative_unit = false
|
|
179
|
+
end
|
|
180
|
+
end
|
|
181
|
+
|
|
176
182
|
# Retrieve an object representing the specified unit.
|
|
177
183
|
#
|
|
178
184
|
# Argument can be the unit name, symbol or JScience label and provided as
|
|
@@ -204,9 +210,12 @@ module Quantify
|
|
|
204
210
|
end
|
|
205
211
|
if unit = Unit.match(name_symbol_or_label)
|
|
206
212
|
return unit
|
|
207
|
-
|
|
208
|
-
if unit = Unit.parse(name_symbol_or_label)
|
|
213
|
+
elsif unit = Unit.parse(name_symbol_or_label)
|
|
209
214
|
return unit
|
|
215
|
+
elsif unit = Unit.parse(name_symbol_or_label, :iterative => true)
|
|
216
|
+
return unit
|
|
217
|
+
else
|
|
218
|
+
return nil
|
|
210
219
|
end
|
|
211
220
|
rescue Exceptions::InvalidUnitError
|
|
212
221
|
return nil
|
|
@@ -214,21 +223,12 @@ module Quantify
|
|
|
214
223
|
|
|
215
224
|
# Parse complex strings into unit.
|
|
216
225
|
#
|
|
217
|
-
def self.parse(string)
|
|
226
|
+
def self.parse(string, options={})
|
|
218
227
|
string = string.remove_underscores.without_superscript_characters
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
units = []
|
|
224
|
-
numerator, per, denominator = string.split(/(\/|per)/)
|
|
225
|
-
units += Unit.parse_numerator_units(numerator)
|
|
226
|
-
units += Unit.parse_denominator_units(denominator) unless denominator.nil?
|
|
227
|
-
if units.size == 1 && units.first.index == 1
|
|
228
|
-
return units.first.unit
|
|
229
|
-
else
|
|
230
|
-
return Unit::Compound.new(*units)
|
|
231
|
-
end
|
|
228
|
+
units = options[:iterative] == true ? Unit.iterative_parse(string) : Unit.simple_parse(string)
|
|
229
|
+
return nil if units.empty?
|
|
230
|
+
return units.first.unit if units.size == 1 && units.first.index == 1
|
|
231
|
+
return Unit::Compound.new(*units)
|
|
232
232
|
end
|
|
233
233
|
|
|
234
234
|
def self.match(name_symbol_or_label)
|
|
@@ -266,23 +266,43 @@ module Quantify
|
|
|
266
266
|
return nil
|
|
267
267
|
end
|
|
268
268
|
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
def self.format_unit_attribute(attribute, string_or_symbol)
|
|
273
|
-
string_or_symbol = case attribute
|
|
274
|
-
when :symbol then string_or_symbol.remove_underscores
|
|
275
|
-
when :name then string_or_symbol.remove_underscores.singularize.downcase
|
|
276
|
-
else string_or_symbol.to_s
|
|
269
|
+
def self.simple_parse(string)
|
|
270
|
+
if string.scan(/(\/|per)/).size > 1
|
|
271
|
+
raise Exceptions::InvalidArgumentError, "Malformed unit: multiple uses of '/' or 'per'"
|
|
277
272
|
end
|
|
278
|
-
|
|
279
|
-
|
|
273
|
+
units = []
|
|
274
|
+
numerator, per, denominator = string.split(/(\/|per)/)
|
|
275
|
+
units += Unit.parse_numerator_units(numerator)
|
|
276
|
+
units += Unit.parse_denominator_units(denominator) unless denominator.nil?
|
|
277
|
+
return units
|
|
278
|
+
end
|
|
279
|
+
|
|
280
|
+
def self.iterative_parse(string)
|
|
281
|
+
units=[]
|
|
282
|
+
current_set = "numerator_units"
|
|
283
|
+
while unit = Unit.unit_label_regex.match(string) || unit = Unit.unit_symbol_regex.match(string) ||
|
|
284
|
+
unit = Unit.unit_name_regex.match(string) || unit = Unit.unit_denominator_regex.match(string) do
|
|
285
|
+
if unit[0] =~ Unit.unit_denominator_regex
|
|
286
|
+
current_set = "denominator_units"
|
|
287
|
+
else
|
|
288
|
+
units += Unit.send("parse_#{current_set}".to_sym, unit[0])
|
|
289
|
+
end
|
|
290
|
+
# Remove matched pattern from string for next iteration
|
|
291
|
+
match_length = unit[0].size
|
|
292
|
+
string = string[match_length, string.length-match_length].strip
|
|
293
|
+
end
|
|
294
|
+
return units
|
|
280
295
|
end
|
|
281
296
|
|
|
282
297
|
def self.parse_unit_and_index(string)
|
|
283
298
|
string.scan(/([^0-9\^]+)\^?([\d\.-]*)?/i)
|
|
284
299
|
index = ($2.nil? || $2.empty? ? 1 : $2.to_i)
|
|
285
|
-
|
|
300
|
+
unit = Unit.match($1.to_s)
|
|
301
|
+
if unit.is_a? Compound
|
|
302
|
+
return unit.base_units.each {|base_unit| base_unit.index = base_unit.index * index}
|
|
303
|
+
else
|
|
304
|
+
return CompoundBaseUnit.new($1.to_s, index)
|
|
305
|
+
end
|
|
286
306
|
end
|
|
287
307
|
|
|
288
308
|
def self.parse_numerator_units(string)
|
|
@@ -294,7 +314,7 @@ module Quantify
|
|
|
294
314
|
end
|
|
295
315
|
num_units.map! do |substring|
|
|
296
316
|
Unit.parse_unit_and_index(substring)
|
|
297
|
-
end
|
|
317
|
+
end.flatten
|
|
298
318
|
end
|
|
299
319
|
|
|
300
320
|
def self.parse_denominator_units(string)
|
|
@@ -304,6 +324,19 @@ module Quantify
|
|
|
304
324
|
end
|
|
305
325
|
end
|
|
306
326
|
|
|
327
|
+
# standardize query strings or symbols into canonical form for unit names,
|
|
328
|
+
# symbols and labels
|
|
329
|
+
#
|
|
330
|
+
def self.format_unit_attribute(attribute, string_or_symbol)
|
|
331
|
+
string_or_symbol = case attribute
|
|
332
|
+
when :symbol then string_or_symbol.remove_underscores
|
|
333
|
+
when :name then string_or_symbol.remove_underscores.singularize.downcase
|
|
334
|
+
else string_or_symbol.to_s
|
|
335
|
+
end
|
|
336
|
+
Unit.use_superscript_characters? ?
|
|
337
|
+
string_or_symbol.with_superscript_characters : string_or_symbol.without_superscript_characters
|
|
338
|
+
end
|
|
339
|
+
|
|
307
340
|
# This returns the suite of units which represents THE SI units for each of
|
|
308
341
|
# the base dimensions, i.e. metre, kilogram, second, etc. but not prefixed
|
|
309
342
|
# versions of the same unit
|
|
@@ -341,6 +374,24 @@ module Quantify
|
|
|
341
374
|
@units.map {|unit| unit.symbol if unit.symbol.word_count > 1 }.compact
|
|
342
375
|
end
|
|
343
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\.-]*)?/
|
|
384
|
+
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
|
+
|
|
344
395
|
# Underscore any parts of string which represent multi-word unit identifiers
|
|
345
396
|
# so that units can be parsed on whitespace
|
|
346
397
|
#
|
|
@@ -354,9 +405,9 @@ module Quantify
|
|
|
354
405
|
# Returns a list of "|" separated unit identifiers for use as regex
|
|
355
406
|
# alternatives. Lists are constructed by calling
|
|
356
407
|
def self.units_for_regex(klass,method,attribute)
|
|
357
|
-
list = klass.send(method).map { |item| item.send(attribute)
|
|
408
|
+
list = klass.send(method).map { |item| item.send(attribute).gsub("/","\\/").gsub("^","\\^") }
|
|
358
409
|
list.map! { |item| item.downcase } if attribute == :name
|
|
359
|
-
list.join("|")
|
|
410
|
+
list.sort {|x, y| y.size <=> x.size }.join("|")
|
|
360
411
|
end
|
|
361
412
|
|
|
362
413
|
end
|
data/quantify.gemspec
CHANGED
|
@@ -5,11 +5,11 @@
|
|
|
5
5
|
|
|
6
6
|
Gem::Specification.new do |s|
|
|
7
7
|
s.name = %q{quantify}
|
|
8
|
-
s.version = "
|
|
8
|
+
s.version = "3.0.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 = %q{2011-
|
|
12
|
+
s.date = %q{2011-11-08}
|
|
13
13
|
s.description = %q{A gem to support physical quantities and unit conversions}
|
|
14
14
|
s.email = %q{andrew.berkeley.is@googlemail.com}
|
|
15
15
|
s.extra_rdoc_files = [
|
|
@@ -30,6 +30,7 @@ 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",
|
|
33
34
|
"lib/quantify/quantify.rb",
|
|
34
35
|
"lib/quantify/quantity.rb",
|
|
35
36
|
"lib/quantify/unit/base_unit.rb",
|
|
@@ -54,7 +55,7 @@ Gem::Specification.new do |s|
|
|
|
54
55
|
s.homepage = %q{https://github.com/spatchcock/quantify}
|
|
55
56
|
s.licenses = ["MIT"]
|
|
56
57
|
s.require_paths = ["lib"]
|
|
57
|
-
s.rubygems_version = %q{1.
|
|
58
|
+
s.rubygems_version = %q{1.5.3}
|
|
58
59
|
s.summary = %q{Support for handling physical quantities, unit conversions, etc}
|
|
59
60
|
|
|
60
61
|
if s.respond_to? :specification_version then
|
data/spec/quantity_spec.rb
CHANGED
|
@@ -34,33 +34,162 @@ describe Quantity do
|
|
|
34
34
|
quantity.unit.name.should == 'kilometre'
|
|
35
35
|
end
|
|
36
36
|
|
|
37
|
+
it "should create valid instances with class parse method" do
|
|
38
|
+
quantities = Quantity.parse "10m driving and 5 tonnes carried"
|
|
39
|
+
quantities.should be_a Array
|
|
40
|
+
quantities.first.value.should == 10
|
|
41
|
+
quantities.first.unit.symbol.should == 'm'
|
|
42
|
+
quantities.last.value.should == 5
|
|
43
|
+
quantities.last.unit.symbol.should == 't'
|
|
44
|
+
end
|
|
45
|
+
|
|
37
46
|
it "should create a valid instance with class parse method" do
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
47
|
+
quantities = Quantity.parse "10 m"
|
|
48
|
+
quantities.first.value.should == 10
|
|
49
|
+
quantities.first.unit.symbol.should == 'm'
|
|
41
50
|
end
|
|
42
51
|
|
|
43
52
|
it "should create a valid instance with class parse method" do
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
53
|
+
quantities = Quantity.parse "155.6789 ly"
|
|
54
|
+
quantities.first.value.should == 155.6789
|
|
55
|
+
quantities.first.unit.name.should == 'light year'
|
|
56
|
+
quantities.first.represents.should == 'length'
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
it "should create a valid instance with class parse method and per unit with symbols" do
|
|
60
|
+
quantities = Quantity.parse "10 m / h"
|
|
61
|
+
quantities.first.value.should == 10
|
|
62
|
+
quantities.first.unit.symbol.should == 'm/h'
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
it "should create a valid instance with class parse method and per unit with names" do
|
|
66
|
+
quantities = Quantity.parse "10 miles / hour"
|
|
67
|
+
quantities.first.value.should == 10
|
|
68
|
+
quantities.first.unit.symbol.should == 'mi/h'
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
it "should create a valid instance with class parse method and compound per unit with names" do
|
|
72
|
+
quantities = Quantity.parse "10 kilograms / tonne kilometre"
|
|
73
|
+
quantities.first.value.should == 10
|
|
74
|
+
quantities.first.unit.symbol.should == 'kg/t km'
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
it "should create a valid instance with class parse method and compound per unit with symbols" do
|
|
78
|
+
quantities = Quantity.parse "10 kg / t km"
|
|
79
|
+
quantities.first.value.should == 10
|
|
80
|
+
quantities.first.unit.symbol.should == 'kg/t km'
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
it "should create a valid instance from complex string with compound per unit" do
|
|
84
|
+
quantities = Quantity.parse "We sent some freight 6000 nautical miles by ship and the emissions rate was 10 kg / t km"
|
|
85
|
+
quantities.first.value.should == 6000
|
|
86
|
+
quantities.first.unit.name.should == 'nautical mile'
|
|
87
|
+
quantities.first.unit.symbol.should == 'nmi'
|
|
88
|
+
quantities[1].value.should == 10
|
|
89
|
+
quantities[1].unit.pluralized_name.should == 'kilograms per tonne kilometre'
|
|
90
|
+
quantities[1].unit.symbol.should == 'kg/t km'
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
it "should create valid instances from complex string" do
|
|
94
|
+
quantities = Quantity.parse "I travelled 220 miles driving my car and using 0.13 UK gallons per mile of diesel"
|
|
95
|
+
quantities.first.value.should == 220
|
|
96
|
+
quantities.first.unit.name.should == 'mile'
|
|
97
|
+
quantities.first.unit.symbol.should == 'mi'
|
|
98
|
+
quantities[1].value.should == 0.13
|
|
99
|
+
quantities[1].unit.pluralized_name.should == 'UK gallons per mile'
|
|
100
|
+
quantities[1].unit.symbol.should == 'gal/mi'
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
it "should create valid instances from easy string" do
|
|
104
|
+
quantities = Quantity.parse "100km"
|
|
105
|
+
quantities.first.value.should == 100
|
|
106
|
+
quantities.first.unit.name.should == 'kilometre'
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
it "should create valid instances from complex string, no space and two-digit symbol" do
|
|
110
|
+
quantities = Quantity.parse "100km driving cars"
|
|
111
|
+
quantities.first.value.should == 100
|
|
112
|
+
quantities.first.unit.name.should == 'kilometre'
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
it "should create valid instances from complex string with punctuation" do
|
|
116
|
+
quantities = Quantity.parse "66666 kg; 5 lb; 86 gigagrams per kelvin and some more words"
|
|
117
|
+
quantities.first.value.should == 66666
|
|
118
|
+
quantities.first.unit.name.should == 'kilogram'
|
|
119
|
+
quantities[1].value.should == 5
|
|
120
|
+
quantities[1].unit.pluralized_name.should == 'pounds'
|
|
121
|
+
quantities[1].unit.symbol.should == 'lb'
|
|
122
|
+
quantities[2].value.should == 86
|
|
123
|
+
quantities[2].unit.pluralized_name.should == 'gigagrams per kelvin'
|
|
124
|
+
quantities[2].unit.symbol.should == 'Gg/K'
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
it "should create valid instances from complex string with punctuation" do
|
|
128
|
+
quantities = Quantity.parse "6 kilogram square metre per second^2"
|
|
129
|
+
quantities.first.value.should == 6
|
|
130
|
+
quantities.first.unit.name.should == 'kilogram square metre per square second'
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
it "should create valid instances from complex string with punctuation" do
|
|
134
|
+
quantities = Quantity.parse "I make 1 cup of tea with 1 tea bag, 0.3 litres of water, 10 g of sugar and 1 dram of milk"
|
|
135
|
+
quantities.first.value.should == 1
|
|
136
|
+
quantities.first.unit.name.should == 'cup'
|
|
137
|
+
quantities[1].value.should == 1
|
|
138
|
+
quantities[1].unit.name.should == ''
|
|
139
|
+
quantities[2].value.should == 0.3
|
|
140
|
+
quantities[2].unit.name.should == 'litre'
|
|
141
|
+
quantities[3].value.should == 10
|
|
142
|
+
quantities[3].unit.name.should == 'gram'
|
|
143
|
+
quantities[4].value.should == 1
|
|
144
|
+
quantities[4].unit.name.should == 'dram'
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
it "should create valid instances from complex string with indices" do
|
|
148
|
+
quantities = Quantity.parse "I sprayed 500 litres of fertilizer across 6000 m^2 of farmland"
|
|
149
|
+
quantities.first.value.should == 500
|
|
150
|
+
quantities.first.unit.name.should == 'litre'
|
|
151
|
+
quantities.first.unit.symbol.should == 'L'
|
|
152
|
+
quantities[1].value.should == 6000
|
|
153
|
+
quantities[1].unit.pluralized_name.should == 'square metres'
|
|
154
|
+
quantities[1].unit.symbol.should == 'm²'
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
it "should create valid instances from complex string with no spaces" do
|
|
158
|
+
quantities = Quantity.parse "I sprayed 500L of fertilizer across 6000m^2 of farmland"
|
|
159
|
+
quantities.first.value.should == 500
|
|
160
|
+
quantities.first.unit.name.should == 'litre'
|
|
161
|
+
quantities.first.unit.symbol.should == 'L'
|
|
162
|
+
quantities[1].value.should == 6000
|
|
163
|
+
quantities[1].unit.pluralized_name.should == 'square metres'
|
|
164
|
+
quantities[1].unit.symbol.should == 'm²'
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
it "should create a valid instance with class parse method and per unit" do
|
|
168
|
+
quantities = Quantity.parse "10 miles / hour"
|
|
169
|
+
quantities.first.value.should == 10
|
|
170
|
+
quantities.first.unit.symbol.should == 'mi/h'
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
it "should parse using string method" do
|
|
174
|
+
"20 m".to_q.first.value.should == 20.0
|
|
175
|
+
"45.45 BTU".to_q.first.class.should == Quantity
|
|
176
|
+
"65 kilometres per hour".to_q.first.unit.class.should == Unit::Compound
|
|
48
177
|
end
|
|
49
178
|
|
|
50
179
|
it "should create a valid instance with class parse method based on to_string method" do
|
|
51
180
|
quantity_1 = Quantity.new 15, :watt
|
|
52
181
|
quantity_2 = Quantity.parse quantity_1.to_s
|
|
53
|
-
quantity_2.value.should == 15
|
|
54
|
-
quantity_2.unit.name.should == 'watt'
|
|
55
|
-
quantity_2.represents.should == 'power'
|
|
182
|
+
quantity_2.first.value.should == 15
|
|
183
|
+
quantity_2.first.unit.name.should == 'watt'
|
|
184
|
+
quantity_2.first.represents.should == 'power'
|
|
56
185
|
end
|
|
57
186
|
|
|
58
187
|
it "should create a valid instance with class parse method and unit prefix based on to_string method" do
|
|
59
188
|
quantity_1 = Quantity.new 15, :watt
|
|
60
189
|
quantity_2 = Quantity.parse quantity_1.to_s
|
|
61
|
-
quantity_2.value.should == 15
|
|
62
|
-
quantity_2.unit.name.should == 'watt'
|
|
63
|
-
quantity_2.represents.should == 'power'
|
|
190
|
+
quantity_2.first.value.should == 15
|
|
191
|
+
quantity_2.first.unit.name.should == 'watt'
|
|
192
|
+
quantity_2.first.represents.should == 'power'
|
|
64
193
|
end
|
|
65
194
|
|
|
66
195
|
it "should convert quantity correctly" do
|
|
@@ -243,13 +372,6 @@ describe Quantity do
|
|
|
243
372
|
lambda{ ((10.m/1.s).pow! 0.5) }.should raise_error
|
|
244
373
|
end
|
|
245
374
|
|
|
246
|
-
it "should parse using string method" do
|
|
247
|
-
"20 m".to_q.value.should == 20.0
|
|
248
|
-
"45.45 BTU".to_q.class.should == Quantity
|
|
249
|
-
"65 kilometres per hour".to_q.unit.class.should == Unit::Compound
|
|
250
|
-
"65 kilometre per hour".to_q.unit.class.should == Unit::Compound
|
|
251
|
-
end
|
|
252
|
-
|
|
253
375
|
it "should cancel by base units of original compound unit if necessary" do
|
|
254
376
|
quantity = Quantity.new(20, Unit.psi).to(Unit.inches_of_mercury)
|
|
255
377
|
quantity.unit.base_units.size.should == 1
|
data/spec/unit_spec.rb
CHANGED
|
@@ -239,6 +239,7 @@ describe Unit do
|
|
|
239
239
|
it "should NOT ignore case when initialising units by symbol" do
|
|
240
240
|
Unit.m.label.should eql 'm'
|
|
241
241
|
lambda{Unit.M}.should raise_error
|
|
242
|
+
|
|
242
243
|
Unit.Gg.name.should eql 'gigagram'
|
|
243
244
|
lambda{Unit.GG}.should raise_error
|
|
244
245
|
end
|
|
@@ -325,8 +326,8 @@ describe Unit do
|
|
|
325
326
|
it "dynamic unit retrieval with symbol should be successful" do
|
|
326
327
|
Unit.m.name.should == 'metre'
|
|
327
328
|
Unit.ft.symbol.should == 'ft'
|
|
328
|
-
#
|
|
329
|
-
#
|
|
329
|
+
#Unit.μm.factor.should == 0.000001
|
|
330
|
+
#Unit.°C.name.should == 'degree celsius'
|
|
330
331
|
end
|
|
331
332
|
|
|
332
333
|
it "dynamic unit retrieval with symbol and prefix should be successful" do
|
|
@@ -455,10 +456,17 @@ describe Unit do
|
|
|
455
456
|
unit.symbol.should == 'Mpd'
|
|
456
457
|
end
|
|
457
458
|
|
|
458
|
-
it "should raise with block initialize and no name" do
|
|
459
|
+
it "should not raise with block initialize and no name if dimensionless" do
|
|
459
460
|
lambda{unit = Unit::Base.new do |unit|
|
|
460
461
|
unit.symbol = 'Mpd'
|
|
461
462
|
unit.dimensions = Dimensions.dimensionless
|
|
463
|
+
end}.should_not raise_error
|
|
464
|
+
end
|
|
465
|
+
|
|
466
|
+
it "should raise with block initialize and no name" do
|
|
467
|
+
lambda{unit = Unit::Base.new do |unit|
|
|
468
|
+
unit.symbol = 'Mpd'
|
|
469
|
+
unit.dimensions = Dimensions.mass
|
|
462
470
|
end}.should raise_error
|
|
463
471
|
end
|
|
464
472
|
|
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: 7
|
|
5
5
|
prerelease:
|
|
6
6
|
segments:
|
|
7
|
-
-
|
|
7
|
+
- 3
|
|
8
8
|
- 0
|
|
9
|
-
-
|
|
10
|
-
version:
|
|
9
|
+
- 0
|
|
10
|
+
version: 3.0.0
|
|
11
11
|
platform: ruby
|
|
12
12
|
authors:
|
|
13
13
|
- Andrew Berkeley
|
|
@@ -15,13 +15,12 @@ autorequire:
|
|
|
15
15
|
bindir: bin
|
|
16
16
|
cert_chain: []
|
|
17
17
|
|
|
18
|
-
date: 2011-
|
|
18
|
+
date: 2011-11-08 00:00:00 +00:00
|
|
19
19
|
default_executable:
|
|
20
20
|
dependencies:
|
|
21
21
|
- !ruby/object:Gem::Dependency
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
requirement: &id001 !ruby/object:Gem::Requirement
|
|
22
|
+
name: activesupport
|
|
23
|
+
version_requirements: &id001 !ruby/object:Gem::Requirement
|
|
25
24
|
none: false
|
|
26
25
|
requirements:
|
|
27
26
|
- - ~>
|
|
@@ -31,12 +30,12 @@ dependencies:
|
|
|
31
30
|
- 3
|
|
32
31
|
- 0
|
|
33
32
|
version: "3.0"
|
|
34
|
-
name: activesupport
|
|
35
|
-
version_requirements: *id001
|
|
36
|
-
- !ruby/object:Gem::Dependency
|
|
37
33
|
prerelease: false
|
|
38
34
|
type: :runtime
|
|
39
|
-
requirement:
|
|
35
|
+
requirement: *id001
|
|
36
|
+
- !ruby/object:Gem::Dependency
|
|
37
|
+
name: i18n
|
|
38
|
+
version_requirements: &id002 !ruby/object:Gem::Requirement
|
|
40
39
|
none: false
|
|
41
40
|
requirements:
|
|
42
41
|
- - ">="
|
|
@@ -45,12 +44,12 @@ dependencies:
|
|
|
45
44
|
segments:
|
|
46
45
|
- 0
|
|
47
46
|
version: "0"
|
|
48
|
-
name: i18n
|
|
49
|
-
version_requirements: *id002
|
|
50
|
-
- !ruby/object:Gem::Dependency
|
|
51
47
|
prerelease: false
|
|
52
|
-
type: :
|
|
53
|
-
requirement:
|
|
48
|
+
type: :runtime
|
|
49
|
+
requirement: *id002
|
|
50
|
+
- !ruby/object:Gem::Dependency
|
|
51
|
+
name: bundler
|
|
52
|
+
version_requirements: &id003 !ruby/object:Gem::Requirement
|
|
54
53
|
none: false
|
|
55
54
|
requirements:
|
|
56
55
|
- - ~>
|
|
@@ -61,12 +60,12 @@ dependencies:
|
|
|
61
60
|
- 0
|
|
62
61
|
- 0
|
|
63
62
|
version: 1.0.0
|
|
64
|
-
name: bundler
|
|
65
|
-
version_requirements: *id003
|
|
66
|
-
- !ruby/object:Gem::Dependency
|
|
67
63
|
prerelease: false
|
|
68
64
|
type: :development
|
|
69
|
-
requirement:
|
|
65
|
+
requirement: *id003
|
|
66
|
+
- !ruby/object:Gem::Dependency
|
|
67
|
+
name: jeweler
|
|
68
|
+
version_requirements: &id004 !ruby/object:Gem::Requirement
|
|
70
69
|
none: false
|
|
71
70
|
requirements:
|
|
72
71
|
- - ~>
|
|
@@ -77,12 +76,12 @@ dependencies:
|
|
|
77
76
|
- 6
|
|
78
77
|
- 4
|
|
79
78
|
version: 1.6.4
|
|
80
|
-
name: jeweler
|
|
81
|
-
version_requirements: *id004
|
|
82
|
-
- !ruby/object:Gem::Dependency
|
|
83
79
|
prerelease: false
|
|
84
80
|
type: :development
|
|
85
|
-
requirement:
|
|
81
|
+
requirement: *id004
|
|
82
|
+
- !ruby/object:Gem::Dependency
|
|
83
|
+
name: rspec
|
|
84
|
+
version_requirements: &id005 !ruby/object:Gem::Requirement
|
|
86
85
|
none: false
|
|
87
86
|
requirements:
|
|
88
87
|
- - ~>
|
|
@@ -93,12 +92,12 @@ dependencies:
|
|
|
93
92
|
- 6
|
|
94
93
|
- 0
|
|
95
94
|
version: 2.6.0
|
|
96
|
-
name: rspec
|
|
97
|
-
version_requirements: *id005
|
|
98
|
-
- !ruby/object:Gem::Dependency
|
|
99
95
|
prerelease: false
|
|
100
96
|
type: :development
|
|
101
|
-
requirement:
|
|
97
|
+
requirement: *id005
|
|
98
|
+
- !ruby/object:Gem::Dependency
|
|
99
|
+
name: rcov
|
|
100
|
+
version_requirements: &id006 !ruby/object:Gem::Requirement
|
|
102
101
|
none: false
|
|
103
102
|
requirements:
|
|
104
103
|
- - ">="
|
|
@@ -107,12 +106,12 @@ dependencies:
|
|
|
107
106
|
segments:
|
|
108
107
|
- 0
|
|
109
108
|
version: "0"
|
|
110
|
-
name: rcov
|
|
111
|
-
version_requirements: *id006
|
|
112
|
-
- !ruby/object:Gem::Dependency
|
|
113
109
|
prerelease: false
|
|
114
110
|
type: :development
|
|
115
|
-
requirement:
|
|
111
|
+
requirement: *id006
|
|
112
|
+
- !ruby/object:Gem::Dependency
|
|
113
|
+
name: rdoc
|
|
114
|
+
version_requirements: &id007 !ruby/object:Gem::Requirement
|
|
116
115
|
none: false
|
|
117
116
|
requirements:
|
|
118
117
|
- - ">="
|
|
@@ -121,8 +120,9 @@ dependencies:
|
|
|
121
120
|
segments:
|
|
122
121
|
- 0
|
|
123
122
|
version: "0"
|
|
124
|
-
|
|
125
|
-
|
|
123
|
+
prerelease: false
|
|
124
|
+
type: :development
|
|
125
|
+
requirement: *id007
|
|
126
126
|
description: A gem to support physical quantities and unit conversions
|
|
127
127
|
email: andrew.berkeley.is@googlemail.com
|
|
128
128
|
executables: []
|
|
@@ -146,6 +146,7 @@ files:
|
|
|
146
146
|
- lib/quantify/dimensions.rb
|
|
147
147
|
- lib/quantify/exception.rb
|
|
148
148
|
- lib/quantify/inflections.rb
|
|
149
|
+
- lib/quantify/parser.rb
|
|
149
150
|
- lib/quantify/quantify.rb
|
|
150
151
|
- lib/quantify/quantity.rb
|
|
151
152
|
- lib/quantify/unit/base_unit.rb
|
|
@@ -196,7 +197,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
196
197
|
requirements: []
|
|
197
198
|
|
|
198
199
|
rubyforge_project:
|
|
199
|
-
rubygems_version: 1.
|
|
200
|
+
rubygems_version: 1.5.3
|
|
200
201
|
signing_key:
|
|
201
202
|
specification_version: 3
|
|
202
203
|
summary: Support for handling physical quantities, unit conversions, etc
|