quantify 1.1.0 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/.rvmrc ADDED
@@ -0,0 +1 @@
1
+ rvm 1.8.7@quantify
data/Gemfile ADDED
@@ -0,0 +1,14 @@
1
+ source "http://rubygems.org"
2
+
3
+ gem "activesupport"
4
+ gem "i18n"
5
+
6
+ # Add dependencies to develop your gem here.
7
+ # Include everything needed to run rake, tests, features, etc.
8
+ group :development do
9
+ gem "bundler", "~> 1.0.0"
10
+ gem "jeweler", "~> 1.6.4"
11
+ gem 'rspec', '1.3.0'
12
+ gem 'rcov'
13
+ gem 'rspec_spinner', '1.1.3'
14
+ end
data/README CHANGED
@@ -9,7 +9,7 @@ Quick introduction
9
9
 
10
10
  12.feet + 12.feet => "24.0 feet"
11
11
 
12
- 6.m ** 2 => "36.0 m^2"
12
+ 6.m ** 2 => "36.0 m²"
13
13
 
14
14
  100.km / 2.h => "50 kilometers per hour"
15
15
 
@@ -124,11 +124,11 @@ Convert a quantity to a different unit
124
124
 
125
125
  Convert the units of a quantity with a compound unit
126
126
 
127
- speed = 70.mi/1.h => "70.0 mi h^-1"
127
+ speed = 70.mi/1.h => "70.0 mi/h"
128
128
 
129
- speed_in_kms = speed.to_km => "112.65408 km h^-1"
129
+ speed_in_kms = speed.to_km => "112.65408 km/h"
130
130
 
131
- speed_in_mins = speed_in_kms.to_min => "1.877568 km min^-1"
131
+ speed_in_mins = speed_in_kms.to_min => "1.877568 km/min"
132
132
 
133
133
  # Note: all of the above results are string representations of the actual
134
134
  # objects which result from these operations.
@@ -180,18 +180,18 @@ and the user may not necessarily prefer a conversion into consistent mass units
180
180
  area = 12.yd * 36.ft => <Quantify::Quantity:0xb7332bbc ... >
181
181
  area.to_s => "432.0 yd ft"
182
182
  area.to_yd
183
- area.to_s => "144.0 yd^2"
183
+ area.to_s => "144.0 yd²"
184
184
 
185
185
  # Alternatively, all units within the numerator and denominator respectively
186
186
  # can be standardized.
187
187
  quantity = (12.ft*8.mi)/(1.s*8.min)
188
- quantity.to_s => 12.0 ft mi s^-1 min^-1
188
+ quantity.to_s => 12.0 ft mi/s min
189
189
  quantity.rationalize_units!
190
- quantity.to_s => 1056.0 ft^2 s^-2
190
+ quantity.to_s => 1056.0 ft²/s²
191
191
 
192
192
  # A quantity with arbitrary cancelable units can be cancelled manually
193
193
  quantity = (12.m**6) / 2.m**2
194
- quantity.to_s => "746496.0 m^6 m^-2"
194
+ quantity.to_s => "746496.0 m^6/m²"
195
195
  quantity.cancel_base_units! :m
196
196
  quantity.to_s => "746496.0 m^4"
197
197
 
@@ -228,14 +228,14 @@ Initialize a unit object
228
228
 
229
229
  another_unit = unit / other_unit => <Quantify::Unit::Compound:0xb74af323 ... >
230
230
  another_unit.name => 'kilometer per hour'
231
- another_unit.symbol => 'km h^-1'
231
+ another_unit.symbol => 'km/h'
232
232
  another_unit.measures => 'velocity'
233
233
  another_unit.base_units.map(&:name) => ['kilogram','hour']
234
234
 
235
235
  last_unit = Unit.m
236
236
  last.unit.measures => 'length'
237
237
  square = last_unit ** 2 => <Quantify::Unit::Compound:0xb446f12f ... >
238
- square.symbol => 'm^2'
238
+ square.symbol => 'm²'
239
239
  square.measures => 'area'
240
240
 
241
241
 
data/Rakefile ADDED
@@ -0,0 +1,65 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rubygems'
4
+ require 'bundler'
5
+ begin
6
+ Bundler.setup(:default, :development)
7
+ rescue Bundler::BundlerError => e
8
+ $stderr.puts e.message
9
+ $stderr.puts "Run `bundle install` to install missing gems"
10
+ exit e.status_code
11
+ end
12
+ require 'rake'
13
+ require 'spec'
14
+ require 'spec/rake/spectask'
15
+
16
+ task :default => [:spec]
17
+
18
+ Spec::Rake::SpecTask.new do |t|
19
+ t.spec_opts = ['--options', "spec/spec.opts"]
20
+ t.spec_files = FileList['spec/**/*_spec.rb']
21
+ t.rcov = true
22
+ t.rcov_opts = ['--exclude', 'spec,/*ruby*,']
23
+ end
24
+
25
+ require 'jeweler'
26
+
27
+ Jeweler::Tasks.new do |gem|
28
+ # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
29
+ gem.name = "quantify"
30
+ gem.homepage = "https://github.com/spatchcock/quantify"
31
+ gem.license = "MIT"
32
+ gem.summary = %Q{Support for handling physical quantities, unit conversions, etc}
33
+ gem.description = %Q{A gem to support physical quantities and unit conversions}
34
+ gem.email = "andrew.berkeley.is@googlemail.com"
35
+ gem.authors = ["Andrew Berkeley"]
36
+ # dependencies defined in Gemfile
37
+ end
38
+ Jeweler::RubygemsDotOrgTasks.new
39
+
40
+ require 'rake/testtask'
41
+ Rake::TestTask.new(:test) do |test|
42
+ test.libs << 'lib' << 'test'
43
+ test.pattern = 'test/**/test_*.rb'
44
+ test.verbose = true
45
+ end
46
+
47
+ require 'rcov/rcovtask'
48
+ Rcov::RcovTask.new do |test|
49
+ test.libs << 'test'
50
+ test.pattern = 'test/**/test_*.rb'
51
+ test.verbose = true
52
+ test.rcov_opts << '--exclude "gems/*"'
53
+ end
54
+
55
+ task :default => :test
56
+
57
+ require 'rake/rdoctask'
58
+ Rake::RDocTask.new do |rdoc|
59
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
60
+
61
+ rdoc.rdoc_dir = 'rdoc'
62
+ rdoc.title = "quantify #{version}"
63
+ rdoc.rdoc_files.include('README*')
64
+ rdoc.rdoc_files.include('lib/**/*.rb')
65
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 1.2.0
@@ -177,24 +177,24 @@ Unit::SI.configure do
177
177
  load :name => 'kilogram', :physical_quantity => :mass, :symbol => 'kg', :label => 'kg'
178
178
  load :name => 'gram', :physical_quantity => :mass, :symbol => 'g', :label => 'g', :factor => 1e-3
179
179
 
180
- # Define units on the basis of unit operations
180
+ # Define compound units on the basis of SI units
181
181
 
182
- construct_and_load metre**2
183
- construct_and_load metre**3
184
- construct_and_load(metre/second)
185
- construct_and_load(metre/second**2)
182
+ (metre**2).load
183
+ (metre**3).load
184
+ (metre/second).load
185
+ (metre/second**2).load
186
186
 
187
- construct_and_load(1/centimetre) do |unit|
187
+ (1/centimetre).configure do |unit|
188
188
  unit.name = 'inverse centimetre'
189
- end
189
+ end.load
190
190
 
191
- construct_and_load(centimetre/second**2) do |unit|
191
+ (centimetre/second**2).configure do |unit|
192
192
  unit.name = 'galileo'
193
193
  unit.symbol = 'Gal'
194
194
  unit.label = 'galileo'
195
- end
195
+ end.load
196
196
 
197
- # add required prefixed unit individually
197
+ # add required prefixed units individually
198
198
 
199
199
  kilometre.load
200
200
 
@@ -215,8 +215,6 @@ Unit::SI.configure do
215
215
 
216
216
  si_base_units.each { |unit| unit.acts_as_equivalent_unit = true }
217
217
 
218
- cubic_metre.acts_as_equivalent_unit = true
219
-
220
218
  joule.acts_as_equivalent_unit = true
221
219
 
222
220
  newton.acts_as_equivalent_unit = true
@@ -225,8 +223,6 @@ Unit::SI.configure do
225
223
 
226
224
  pascal.acts_as_equivalent_unit = true
227
225
 
228
- square_metre.acts_as_equivalent_unit = true
229
-
230
226
  end
231
227
 
232
228
  Unit::NonSI.configure do
@@ -51,7 +51,7 @@ module Quantify
51
51
  #
52
52
  def self.base_dimensions
53
53
  @@dimensions.select do |dimensions|
54
- BASE_QUANTITIES.map {|q| q.remove_underscores}.include?(dimensions.describe)
54
+ BASE_QUANTITIES.map {|quantity| quantity.remove_underscores}.include?(dimensions.describe)
55
55
  end
56
56
  end
57
57
 
@@ -1,40 +1,7 @@
1
1
  module Quantify
2
2
 
3
- def self.configure &block
4
- self.module_eval &block if block
5
- end
6
-
7
- # Check whether superscript characters are turned on.
8
- def self.use_superscript_characters?
9
- @use_superscript_characters.nil? ? true : @use_superscript_characters
10
- end
11
-
12
- # Shorthand method for Quantify.use_superscript_characters=true
13
- def self.use_superscript_characters!
14
- self.use_superscript_characters=true
15
- end
16
-
17
- # Declare whether superscript characters should be used for unit names, symbols
18
- # and labels - i.e. "²" and "³" rather than "^2" and "^3". Set to either true or
19
- # false. If not set, superscript characters are used by default.
20
- #
21
- def self.use_superscript_characters=(true_or_false)
22
- raise Exceptions::InvalidArgumentError,
23
- "Argument must be true or false" unless true_or_false == true || true_or_false == false
24
- @use_superscript_characters = true_or_false
25
- refresh_all_unit_identifiers!
26
- end
27
-
28
- # Switch all unit identifiers (name, symbol, label) to use the currently
29
- # configured system for superscripts.
30
- #
31
- def refresh_all_unit_identifiers!
32
- Unit.units.replace(
33
- Unit.units.map do |unit|
34
- unit.refresh_identifiers!
35
- unit
36
- end
37
- )
3
+ def self.configure(&block)
4
+ self.module_eval(&block) if block
38
5
  end
39
6
 
40
7
  module ExtendedMethods
@@ -52,13 +52,13 @@ module Quantify
52
52
  # Syntactic sugar for defining the units known to the system, enabling the
53
53
  # required associated units to be loaded at runtime, e.g.
54
54
  #
55
- # Unit::[Base|SI|NonSI].configure do |config|
55
+ # Unit::[Base|SI|NonSI].configure do |config|
56
56
  #
57
- # load :name => :metre, :physical_quantity => :length
58
- # load :name => 'hectare', :physical_quantity => :area, :factor => 10000
59
- # load :name => :watt, :physical_quantity => :power, :symbol => 'W'
57
+ # load :name => :metre, :physical_quantity => :length
58
+ # load :name => 'hectare', :physical_quantity => :area, :factor => 10000
59
+ # load :name => :watt, :physical_quantity => :power, :symbol => 'W'
60
60
  #
61
- # end
61
+ # end
62
62
  #
63
63
  def self.configure &block
64
64
  class_eval &block if block
@@ -138,7 +138,7 @@ module Quantify
138
138
  #
139
139
  def name=(name)
140
140
  name = name.to_s.remove_underscores.singularize
141
- @name = Quantify.use_superscript_characters? ? name.with_superscript_characters : name.without_superscript_characters
141
+ @name = Unit.use_superscript_characters? ? name.with_superscript_characters : name.without_superscript_characters
142
142
  end
143
143
 
144
144
  # Set the symbol attribute of self. Symbols are stringified and stripped of
@@ -151,7 +151,7 @@ module Quantify
151
151
  #
152
152
  def symbol=(symbol)
153
153
  symbol = symbol.to_s.remove_underscores
154
- @symbol = Quantify.use_superscript_characters? ? symbol.with_superscript_characters : symbol.without_superscript_characters
154
+ @symbol = Unit.use_superscript_characters? ? symbol.with_superscript_characters : symbol.without_superscript_characters
155
155
  end
156
156
 
157
157
  # Set the label attribute of self. This represents the unique identifier for
@@ -165,13 +165,13 @@ module Quantify
165
165
  #
166
166
  def label=(label)
167
167
  label = label.to_s.gsub(" ","_")
168
- @label = Quantify.use_superscript_characters? ? label.with_superscript_characters : label.without_superscript_characters
168
+ @label = Unit.use_superscript_characters? ? label.with_superscript_characters : label.without_superscript_characters
169
169
  end
170
170
 
171
171
  # Refresh the name, symbol and label attributes of self with respect to the
172
172
  # configuration found in Quantify.use_superscript_characters?
173
173
  #
174
- def refresh_identifiers!
174
+ def refresh_attributes
175
175
  self.name = name
176
176
  self.symbol = symbol
177
177
  self.label = label
@@ -448,7 +448,7 @@ module Quantify
448
448
  # "T", "P" ... ]
449
449
  #
450
450
  def valid_prefixes(by=nil)
451
- return [] if self.is_compound_unit?
451
+ return [] if is_compound_unit? && has_multiple_base_units?
452
452
  return Unit::Prefix.si_prefixes.map(&by) if is_si_unit?
453
453
  return Unit::Prefix.non_si_prefixes.map(&by) if is_non_si_unit?
454
454
  end
@@ -513,25 +513,20 @@ module Quantify
513
513
  # of self, complete with modified name, symbol, factor, etc..
514
514
  #
515
515
  def with_prefix(name_or_symbol)
516
- if @name =~ /\A(#{valid_prefixes(:name).join("|")})/
517
- raise Exceptions::InvalidArgumentError, "Cannot add prefix where one already exists: #{self.name}"
518
- end
516
+ raise Exceptions::InvalidArgumentError, "No valid prefixes exist for unit: #{self.name}" if valid_prefixes.empty?
517
+ raise Exceptions::InvalidArgumentError, "Cannot add prefix where one already exists: #{self.name}" if @name =~ /\A(#{valid_prefixes(:name).join("|")})/
519
518
 
520
519
  prefix = Unit::Prefix.for(name_or_symbol,valid_prefixes)
521
-
522
- unless prefix.nil?
523
- new_unit_options = {}
524
- new_unit_options[:name] = "#{prefix.name}#{@name}"
525
- new_unit_options[:symbol] = "#{prefix.symbol}#{@symbol}"
526
- new_unit_options[:label] = "#{prefix.symbol}#{@label}"
527
- new_unit_options[:factor] = prefix.factor * @factor
528
- new_unit_options[:physical_quantity] = @dimensions
529
- self.class.new(new_unit_options)
520
+ if !prefix.nil?
521
+ self.class.new(options_for_prefixed_version(prefix))
530
522
  else
531
523
  raise Exceptions::InvalidArgumentError, "Prefix unit is not known: #{prefix}"
532
524
  end
533
525
  end
534
526
 
527
+ # Return an array of new unit instances based upon self, together with the
528
+ # prefixes specified by <tt>prefixes</tt>
529
+ #
535
530
  def with_prefixes(*prefixes)
536
531
  [prefixes].map { |prefix| self.with_prefix(prefix) }
537
532
  end
@@ -561,6 +556,18 @@ module Quantify
561
556
  raise Exceptions::InvalidArgumentError, "Cannot coerce #{self.class} into #{object.class}"
562
557
  end
563
558
  end
559
+
560
+ 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
564
571
 
565
572
  # Clone self and explicitly clone the associated Dimensions object located
566
573
  # at @dimensions.
@@ -573,9 +580,6 @@ module Quantify
573
580
  def initialize_copy(source)
574
581
  super
575
582
  instance_variable_set("@dimensions", @dimensions.clone)
576
- if self.is_compound_unit?
577
- instance_variable_set("@base_units", @base_units.map {|base| base.clone })
578
- end
579
583
  end
580
584
 
581
585
  # Provides syntactic sugar for several methods. E.g.
@@ -31,7 +31,7 @@ module Quantify
31
31
  end
32
32
 
33
33
  # Absolute index as names always contain 'per' before denominator units
34
- def name
34
+ def name(reciprocal=false)
35
35
  name_to_power(@unit.name, @index.abs)
36
36
  end
37
37
 
@@ -39,20 +39,12 @@ module Quantify
39
39
  name_to_power(@unit.pluralized_name, @index.abs)
40
40
  end
41
41
 
42
- def symbol
43
- @unit.symbol.to_s + ( @index.nil? || @index == 1 ? "" : formatted_index )
42
+ def symbol(reciprocal=false)
43
+ @unit.symbol + index_as_string(reciprocal)
44
44
  end
45
45
 
46
- def label
47
- @unit.label + (@index == 1 ? "" : formatted_index)
48
- end
49
-
50
- # Reciprocalized version of label, i.e. sign changed. This is used to make
51
- # a denominator unit renderable in cases where there are no numerator units,
52
- # i.e. where no '/' appears in the label
53
- #
54
- def reciprocalized_label
55
- @unit.label + (@index == -1 ? "" : formatted_index(@index * -1))
46
+ def label(reciprocal=false)
47
+ @unit.label + index_as_string(reciprocal)
56
48
  end
57
49
 
58
50
  def factor
@@ -67,8 +59,9 @@ module Quantify
67
59
  @index < 0
68
60
  end
69
61
 
70
- # The following methods refer only to the unit of the CompoundBaseUnit
71
- # object, rather than the unit *together with its index*
62
+ def measures
63
+ dimensions.describe
64
+ end
72
65
 
73
66
  def is_base_quantity_si_unit?
74
67
  @unit.is_base_quantity_si_unit?
@@ -97,10 +90,6 @@ module Quantify
97
90
  def is_derived_unit?
98
91
  @unit.is_derived_unit?
99
92
  end
100
-
101
- def measures
102
- @unit.measures
103
- end
104
93
 
105
94
  def initialize_copy(source)
106
95
  instance_variable_set("@unit", @unit.clone)
@@ -109,11 +98,21 @@ module Quantify
109
98
  private
110
99
 
111
100
  # Returns a string representation of the unit index, formatted according to
112
- # the global superscript configuration
101
+ # the global superscript configuration.
102
+ #
103
+ # The index value can be overridden by specifying as an argument.
113
104
  #
114
105
  def formatted_index(index=nil)
115
106
  index = "^#{index.nil? ? @index : index}"
116
- Quantify.use_superscript_characters? ? index.with_superscript_characters : index
107
+ Unit.use_superscript_characters? ? index.with_superscript_characters : index
108
+ end
109
+
110
+ def index_as_string(reciprocal=false)
111
+ if reciprocal == true
112
+ @index == -1 ? "" : formatted_index(@index * -1)
113
+ else
114
+ @index.nil? || @index == 1 ? "" : formatted_index
115
+ end
117
116
  end
118
117
 
119
118
  def name_to_power(string,index)
@@ -123,7 +122,7 @@ module Quantify
123
122
  when 2 then "square #{name}"
124
123
  when 3 then "cubic #{name}"
125
124
  else
126
- ordinal = ActiveSupport::Inflector.ordinalize index
125
+ ordinal = ActiveSupport::Inflector.ordinalize(index)
127
126
  name << " to the #{ordinal} power"
128
127
  end
129
128
  end