quantify 1.1.0 → 1.2.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/.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