unitfy 1.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.
Files changed (46) hide show
  1. data/.gitignore +3 -0
  2. data/.rspec +4 -0
  3. data/Gemfile +18 -0
  4. data/Gemfile.lock +89 -0
  5. data/Guardfile +15 -0
  6. data/MIT-LICENSE +20 -0
  7. data/README +0 -0
  8. data/Rakefile +3 -0
  9. data/lib/unity.rb +20 -0
  10. data/lib/unity/arithmetic.rb +64 -0
  11. data/lib/unity/comparison.rb +33 -0
  12. data/lib/unity/conversion.rb +46 -0
  13. data/lib/unity/dimension.rb +37 -0
  14. data/lib/unity/dimension/integer.rb +34 -0
  15. data/lib/unity/dimension/vector.rb +43 -0
  16. data/lib/unity/fraction.rb +118 -0
  17. data/lib/unity/lookup.rb +102 -0
  18. data/lib/unity/lookup/definitions.rb +50 -0
  19. data/lib/unity/lookup/derived_unit.rb +24 -0
  20. data/lib/unity/lookup/property.rb +21 -0
  21. data/lib/unity/lookup/simple_unit.rb +26 -0
  22. data/lib/unity/quantity.rb +20 -0
  23. data/lib/unity/version.rb +3 -0
  24. data/spec/arithmetic_spec.rb +6 -0
  25. data/spec/comparison_spec.rb +6 -0
  26. data/spec/conversion_spec.rb +8 -0
  27. data/spec/dimension/integer_spec.rb +7 -0
  28. data/spec/dimension/vector_spec.rb +7 -0
  29. data/spec/dimension_spec.rb +7 -0
  30. data/spec/fabricators/unit_fabricator.rb +14 -0
  31. data/spec/fraction_spec.rb +7 -0
  32. data/spec/lookup/derived_unit_spec.rb +44 -0
  33. data/spec/lookup/property_spec.rb +18 -0
  34. data/spec/lookup/simple_unit_spec.rb +41 -0
  35. data/spec/lookup_spec.rb +135 -0
  36. data/spec/quantity_spec.rb +16 -0
  37. data/spec/spec_helper.rb +28 -0
  38. data/spec/support/load_debugger.rb +7 -0
  39. data/spec/support/shared_examples/units/arithmetic.rb +127 -0
  40. data/spec/support/shared_examples/units/comparison.rb +69 -0
  41. data/spec/support/shared_examples/units/conversion.rb +49 -0
  42. data/spec/support/shared_examples/units/dimension/integer.rb +41 -0
  43. data/spec/support/shared_examples/units/dimension/vector.rb +10 -0
  44. data/spec/support/shared_examples/units/fractions.rb +131 -0
  45. data/unitfy.gemspec +24 -0
  46. metadata +133 -0
@@ -0,0 +1,3 @@
1
+ .rvmrc
2
+ .DS_Store
3
+ pkg
data/.rspec ADDED
@@ -0,0 +1,4 @@
1
+ --colour
2
+ --format d
3
+ --profile
4
+ --backtrace
data/Gemfile ADDED
@@ -0,0 +1,18 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in unity.gemspec
4
+ gemspec
5
+
6
+ group :test do
7
+ gem 'SystemTimer', :platform => :mri_18
8
+ gem 'ruby-debug', :platform => :mri_18
9
+ gem 'linecache19', '>= 0.5.13', :platform => :mri_19
10
+ gem 'ruby-debug-base19', '>= 0.11.26', :platform => :mri_19
11
+ gem 'ruby-debug19', :platform => :mri_19, :require => 'ruby-debug'
12
+ gem 'mocha'
13
+ gem 'rspec'
14
+ gem 'shoulda-matchers', :git => 'git://github.com/thoughtbot/shoulda-matchers.git', :require => 'false'
15
+ gem 'fabrication'
16
+ gem 'guard-rspec'
17
+ gem 'guard-bundler'
18
+ end
@@ -0,0 +1,89 @@
1
+ GIT
2
+ remote: git://github.com/thoughtbot/shoulda-matchers.git
3
+ revision: 4fdb82707c252e3bdf6079a8597f2ace350b5d2d
4
+ specs:
5
+ shoulda-matchers (1.1.0)
6
+ activesupport (>= 3.0.0)
7
+
8
+ PATH
9
+ remote: .
10
+ specs:
11
+ unitfy (1.0.0)
12
+ activemodel (>= 3.0.0)
13
+ activesupport (>= 3.0.0)
14
+
15
+ GEM
16
+ remote: http://rubygems.org/
17
+ specs:
18
+ SystemTimer (1.2.3)
19
+ activemodel (3.1.3)
20
+ activesupport (= 3.1.3)
21
+ builder (~> 3.0.0)
22
+ i18n (~> 0.6)
23
+ activesupport (3.1.3)
24
+ multi_json (~> 1.0)
25
+ archive-tar-minitar (0.5.2)
26
+ builder (3.0.0)
27
+ columnize (0.3.6)
28
+ diff-lcs (1.1.3)
29
+ fabrication (1.2.0)
30
+ ffi (1.0.11)
31
+ guard (0.10.0)
32
+ ffi (>= 0.5.0)
33
+ thor (~> 0.14.6)
34
+ guard-bundler (0.1.3)
35
+ bundler (>= 1.0.0)
36
+ guard (>= 0.2.2)
37
+ guard-rspec (0.6.0)
38
+ guard (>= 0.10.0)
39
+ i18n (0.6.0)
40
+ linecache (0.46)
41
+ rbx-require-relative (> 0.0.4)
42
+ linecache19 (0.5.13)
43
+ ruby_core_source (>= 0.1.4)
44
+ metaclass (0.0.1)
45
+ mocha (0.10.1)
46
+ metaclass (~> 0.0.1)
47
+ multi_json (1.3.4)
48
+ rbx-require-relative (0.0.5)
49
+ rspec (2.8.0)
50
+ rspec-core (~> 2.8.0)
51
+ rspec-expectations (~> 2.8.0)
52
+ rspec-mocks (~> 2.8.0)
53
+ rspec-core (2.8.0)
54
+ rspec-expectations (2.8.0)
55
+ diff-lcs (~> 1.1.2)
56
+ rspec-mocks (2.8.0)
57
+ ruby-debug (0.10.4)
58
+ columnize (>= 0.1)
59
+ ruby-debug-base (~> 0.10.4.0)
60
+ ruby-debug-base (0.10.4)
61
+ linecache (>= 0.3)
62
+ ruby-debug-base19 (0.11.26)
63
+ columnize (>= 0.3.1)
64
+ linecache19 (>= 0.5.11)
65
+ ruby_core_source (>= 0.1.4)
66
+ ruby-debug19 (0.11.6)
67
+ columnize (>= 0.3.1)
68
+ linecache19 (>= 0.5.11)
69
+ ruby-debug-base19 (>= 0.11.19)
70
+ ruby_core_source (0.1.5)
71
+ archive-tar-minitar (>= 0.5.2)
72
+ thor (0.14.6)
73
+
74
+ PLATFORMS
75
+ ruby
76
+
77
+ DEPENDENCIES
78
+ SystemTimer
79
+ fabrication
80
+ guard-bundler
81
+ guard-rspec
82
+ linecache19 (>= 0.5.13)
83
+ mocha
84
+ rspec
85
+ ruby-debug
86
+ ruby-debug-base19 (>= 0.11.26)
87
+ ruby-debug19
88
+ shoulda-matchers!
89
+ unitfy!
@@ -0,0 +1,15 @@
1
+ # A sample Guardfile
2
+ # More info at https://github.com/guard/guard#readme
3
+
4
+ guard 'bundler' do
5
+ watch('Gemfile')
6
+ # Uncomment next line if Gemfile contain `gemspec' command
7
+ watch(/^.+\.gemspec/)
8
+ end
9
+
10
+ guard 'rspec', :cli => '--backtrace', :version => 2 do
11
+ watch(%r{^spec/.+_spec\.rb$})
12
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
13
+ watch('spec/spec_helper.rb') { "spec" }
14
+ end
15
+
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2012 Scott Ellard
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README ADDED
File without changes
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env rake
2
+ require 'bundler'
3
+ Bundler::GemHelper.install_tasks
@@ -0,0 +1,20 @@
1
+ require "unity/version"
2
+
3
+ module Unity
4
+
5
+ end
6
+
7
+
8
+ require 'active_support'
9
+
10
+ # Dir["#{Rails.root.to_s}/lib/units/**/*.rb"].each {|file| require file }
11
+ require 'unity/fraction'
12
+ require 'unity/dimension'
13
+ require 'unity/comparison'
14
+ require 'unity/conversion'
15
+ require 'unity/arithmetic'
16
+
17
+
18
+ require 'unity/lookup'
19
+
20
+ require "unity/quantity"
@@ -0,0 +1,64 @@
1
+ # -*- encoding : utf-8 -*-
2
+ module Unity
3
+ module Arithmetic
4
+
5
+ extend ::ActiveSupport::Concern
6
+ include Conversion
7
+
8
+ included do
9
+
10
+ end
11
+
12
+ module ClassMethods
13
+
14
+ end
15
+
16
+ def + other
17
+ other = ensure_not_numeric other
18
+ self.compatible! other
19
+ other = other.convert_to(self)
20
+ self.class.new(:value => (self.value + other.value), :numerator => self.numerator, :denominator => self.denominator)
21
+ end
22
+
23
+
24
+ def - other
25
+ other = ensure_not_numeric other
26
+ self.compatible! other
27
+ other = other.convert_to(self)
28
+ self.class.new(:value => (self.value - other.value), :numerator => self.numerator, :denominator => self.denominator)
29
+ end
30
+
31
+ def / other
32
+ other = ensure_not_numeric other
33
+ other = other.convert_to(self) if self.compatible? other
34
+ self * other.inverse
35
+ end
36
+
37
+ def * other
38
+ other = ensure_not_numeric other
39
+ other = other.convert_to(self) if self.compatible? other
40
+ new_numerator = self.numerator + other.numerator
41
+ new_denominator = self.denominator + other.denominator
42
+ self.class.new(:value => (self.value * other.value), :numerator => new_numerator, :denominator => new_denominator).tap(&:reduce)
43
+ end
44
+
45
+ def coerce(other)
46
+ case other
47
+ when Numeric
48
+ return convert_numeric(other), self
49
+ else
50
+ raise TypeError, "#{self.class} can't be coerced into #{other.class}"
51
+ end
52
+ end
53
+
54
+ private
55
+
56
+ def convert_numeric other
57
+ self.class.new :expression => other.to_s
58
+ end
59
+
60
+ def ensure_not_numeric other
61
+ other.is_a?(Numeric) ? convert_numeric(other) : other
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,33 @@
1
+ # -*- encoding : utf-8 -*-
2
+ module Unity
3
+ class IncompatibleError < RuntimeError
4
+ end
5
+
6
+ module Comparison
7
+
8
+ extend ::ActiveSupport::Concern
9
+ include Dimension::Integer
10
+
11
+ included do
12
+
13
+ end
14
+
15
+ module ClassMethods
16
+
17
+ end
18
+
19
+ def compatible? other
20
+ self.dimension_int == other.dimension_int
21
+ end
22
+
23
+ def compatible! other
24
+ compatible?(other) ? true : raise(IncompatibleError)
25
+ end
26
+
27
+ def == other
28
+ self.compatible?(other) && self.convert_to(other).value == other.value
29
+ end
30
+
31
+ end
32
+ end
33
+
@@ -0,0 +1,46 @@
1
+ # -*- encoding : utf-8 -*-
2
+ module Unity
3
+ class IncompatibleError < RuntimeError
4
+ end
5
+
6
+ module Conversion
7
+
8
+ extend ::ActiveSupport::Concern
9
+ include Comparison
10
+ include Fraction
11
+
12
+ included do
13
+
14
+ end
15
+
16
+ module ClassMethods
17
+
18
+ end
19
+
20
+ def convert_to other
21
+ other = other.clone.tap{|o| o.value = 1.0 } #this is so that only the unit is used for the conversion
22
+ new_value = self.converted_value(other)
23
+ return nil if new_value.nil?
24
+ self.class.new :value => new_value, :numerator => other.numerator, :denominator => other.denominator
25
+ end
26
+
27
+ protected
28
+
29
+ def converted_value other
30
+ return nil unless self.compatible?(other)
31
+ self.si_factor / other.si_factor
32
+ end
33
+
34
+ def si_factor
35
+ value * (get_si_factor(numerator) / get_si_factor(denominator))
36
+ end
37
+
38
+ def get_si_factor unit_array
39
+ expand_unit_array(unit_array).map do |element|
40
+ Lookup.find!(element).si_factor
41
+ end.inject(1.0) {|product, factor| product*factor}
42
+ end
43
+
44
+ end
45
+ end
46
+
@@ -0,0 +1,37 @@
1
+ # -*- encoding : utf-8 -*-
2
+ module Unity
3
+ module Dimension
4
+ extend self
5
+
6
+ #for a description of this algorithm refer to http://www.cs.utexas.edu/users/novak/units95.html
7
+
8
+ # 0 length meter
9
+ # 1 time second
10
+ # 2 temperature kelvin
11
+ # 3 mass kilogram
12
+ # 4 current ampere
13
+ # 5 substance mole
14
+ # 6 luminosity candela
15
+ # 7 money pound
16
+
17
+ LIST = [:length, :time, :temperature, :mass, :current, :substance, :luminosity, :money]
18
+ UNITS = ['meter', 'second', 'kelvin', 'kilogram', 'ampere', 'mole', 'candela', 'pound']
19
+ INDICIES = Hash[*LIST.each_with_index{|d,i| [d,i]}.flatten]
20
+
21
+ DIMSIZES = [20, 20, 20, 10, 10, 10, 10, 10]
22
+ DIMVALS = [1, 20, 400, 8000, 80000, 800000, 8000000, 80000000]
23
+
24
+ def si_unit dimension
25
+ UNITS[INDICIES[dimension.to_sym]]
26
+ end
27
+
28
+ def blank_dimension_vector
29
+ Array.new(LIST.length, 0)
30
+ end
31
+
32
+ end
33
+ end
34
+
35
+ require 'unity/dimension/integer'
36
+ require 'unity/dimension/vector'
37
+
@@ -0,0 +1,34 @@
1
+ # -*- encoding : utf-8 -*-
2
+ module Unity
3
+ module Dimension
4
+ module Integer
5
+ extend ::ActiveSupport::Concern
6
+
7
+ included do
8
+ end
9
+
10
+ module ClassMethods
11
+
12
+ end
13
+
14
+ def dimension_int
15
+ generate_dimension_integer
16
+ end
17
+
18
+ def property_name
19
+ property.nil? ? nil : property.name
20
+ end
21
+
22
+ def property
23
+ Lookup.find_property(dimension_int)
24
+ end
25
+
26
+ private
27
+
28
+ def generate_dimension_integer
29
+ LIST.length.times.inject(0){|sum, i| sum + (DIMVALS[i] * dimension_vector[i])}
30
+ end
31
+
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,43 @@
1
+ # -*- encoding : utf-8 -*-
2
+ module Unity
3
+ module Dimension
4
+ module Vector
5
+ extend ::ActiveSupport::Concern
6
+ include Unity::Fraction
7
+
8
+ included do
9
+ end
10
+
11
+ module ClassMethods
12
+
13
+ end
14
+
15
+ def dimension_vector
16
+ generate_dimension_vector
17
+ end
18
+
19
+ private
20
+
21
+ def generate_dimension_vector
22
+ subtract_vectors numerator_dimension_vector, denominator_dimension_vector
23
+ end
24
+
25
+ def numerator_dimension_vector
26
+ self.expanded_numerator.inject(Dimension.blank_dimension_vector){|v, unit| add_vectors(v, Lookup.find!(unit).dimension_vector) }
27
+ end
28
+
29
+ def denominator_dimension_vector
30
+ self.expanded_denominator.inject(Dimension.blank_dimension_vector){|v, unit| add_vectors(v, Lookup.find!(unit).dimension_vector) }
31
+ end
32
+
33
+ def add_vectors v1, v2
34
+ LIST.length.times.map{|i| v1[i] + v2[i]}
35
+ end
36
+
37
+ def subtract_vectors v1, v2
38
+ LIST.length.times.map{|i| v1[i] - v2[i]}
39
+ end
40
+
41
+ end
42
+ end
43
+ end