unite 1.0.1

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/arithmetic.rb +64 -0
  10. data/lib/unity/comparison.rb +33 -0
  11. data/lib/unity/conversion.rb +46 -0
  12. data/lib/unity/dimension/integer.rb +34 -0
  13. data/lib/unity/dimension/vector.rb +43 -0
  14. data/lib/unity/dimension.rb +37 -0
  15. data/lib/unity/fraction.rb +118 -0
  16. data/lib/unity/lookup/definitions.rb +50 -0
  17. data/lib/unity/lookup/derived_unit.rb +24 -0
  18. data/lib/unity/lookup/property.rb +21 -0
  19. data/lib/unity/lookup/simple_unit.rb +26 -0
  20. data/lib/unity/lookup.rb +102 -0
  21. data/lib/unity/quantity.rb +20 -0
  22. data/lib/unity/version.rb +3 -0
  23. data/lib/unity.rb +20 -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/unite.gemspec +24 -0
  46. metadata +133 -0
data/.gitignore ADDED
@@ -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
data/Gemfile.lock ADDED
@@ -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
+ unite (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
+ unite!
data/Guardfile ADDED
@@ -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
+
data/MIT-LICENSE ADDED
@@ -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
data/Rakefile ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env rake
2
+ require 'bundler'
3
+ Bundler::GemHelper.install_tasks
@@ -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,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
@@ -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,118 @@
1
+ # -*- encoding : utf-8 -*-
2
+ module Unity
3
+ class InvalidFormat < RuntimeError
4
+ end
5
+
6
+ module Fraction
7
+ extend ::ActiveSupport::Concern
8
+
9
+ included do
10
+
11
+ end
12
+
13
+ module ClassMethods
14
+
15
+ end
16
+
17
+ def initialize *args
18
+ self.value ||= 0.0
19
+ self.numerator ||= []
20
+ self.denominator ||= []
21
+ end
22
+
23
+
24
+ def expression=string
25
+ unless string.blank?
26
+ num_denom = string.split('/')
27
+ raise(InvalidFormat, string) if num_denom.length > 2
28
+ self.numerator = num_denom[0].split('*').map(&:strip)
29
+ self.denominator = (num_denom[1].nil? ? [] : num_denom[1].split('*')).map(&:strip)
30
+ self.value = extract_value!(:numerator) / extract_value!(:denominator)
31
+ reduce
32
+ else
33
+ self.value = 0.0
34
+ self.numerator = []
35
+ self.denominator = []
36
+ end
37
+ end
38
+
39
+ def expression
40
+ numertor_string = ([value] + (numerator || [])).join('*')
41
+ denominator.empty? ? numertor_string : "#{numertor_string}/#{denominator.join('*')}"
42
+ end
43
+
44
+ def unit
45
+ numertor_string = (numerator.blank? && !denominator.blank?) ? '1.0' : (numerator || []).join('*')
46
+ denominator.blank? ? numertor_string : "#{numertor_string}/#{denominator.join('*')}"
47
+ end
48
+
49
+ def expanded_numerator
50
+ expand_unit_array numerator
51
+ end
52
+
53
+ def expanded_denominator
54
+ expand_unit_array denominator
55
+ end
56
+
57
+ def inverse
58
+ new_value = value == 0.0 ? 0.0 : 1.0 / value
59
+ self.class.new :value => new_value, :numerator => denominator, :denominator => numerator
60
+ end
61
+
62
+ def reduce
63
+ expand
64
+
65
+ self.denominator.delete_if do |unit|
66
+ if nindex = self.numerator.index(unit)
67
+ self.numerator.delete_at(nindex)
68
+ end
69
+ end
70
+
71
+ self.numerator = reduce_unit_array(self.numerator)
72
+ self.denominator = reduce_unit_array(self.denominator)
73
+
74
+ end
75
+
76
+ private
77
+
78
+ def expand
79
+ self.numerator = expanded_numerator
80
+ self.denominator = expanded_denominator
81
+ end
82
+
83
+ def seperate! array
84
+ [].tap{|rejected| array.delete_if { |v| yield(v) && rejected << v }}
85
+ end
86
+
87
+ def extract_value! method
88
+ number_regex = /\A[-+]?\d*\.?\d+([eE][-+]?\d+)?\Z/
89
+ seperate!(self.send(method)){|x| number_regex =~ x }.map(&:to_f).
90
+ inject(1.0){|product, number| product*number }
91
+ end
92
+
93
+ def reduce_unit_array array
94
+ old_array = array.clone
95
+ [].tap do |new_array|
96
+ while !old_array.empty?
97
+ unit = old_array[0]
98
+ count = old_array.count(unit)
99
+ old_array.delete(unit)
100
+ count = (count == 1) ? '' : "^#{count}"
101
+ new_array.push("#{unit}#{count}")
102
+ end
103
+ end
104
+ end
105
+
106
+ def expand_unit_array array
107
+ array.collect do |unit|
108
+ if /\A([^\^\s]+)(\^(\d+))?\Z/ =~ unit
109
+ unit = Regexp.last_match(1)
110
+ power = Regexp.last_match(3).blank? ? 1 : Regexp.last_match(3).to_i
111
+ Array.new(power, unit)
112
+ else
113
+ raise InvalidFormat, "Invalid format for Unit '#{unit}'"
114
+ end
115
+ end.flatten.compact
116
+ end
117
+ end
118
+ end
@@ -0,0 +1,50 @@
1
+ # -*- encoding : utf-8 -*-
2
+
3
+ module Unity
4
+
5
+ Lookup.clear!
6
+
7
+ #SIMPLE UNITS
8
+
9
+ #TIME
10
+ Lookup.add SimpleUnit.new(:name => "s", :si_factor => 1, :dimension => :time)
11
+ Lookup.add SimpleUnit.new(:name => "h", :si_factor => 3600, :dimension => :time)
12
+
13
+ Lookup.add_property Property.new(:name => :time, :expression => 'h')
14
+
15
+ #LENGTH
16
+ Lookup.add SimpleUnit.new(:name => "m", :si_factor => 1, :dimension => :length)
17
+ Lookup.add SimpleUnit.new(:name => "km", :si_factor => 1000, :dimension => :length)
18
+
19
+ Lookup.add_property Property.new(:name => :distance, :expression => 'km')
20
+
21
+
22
+ #MASS
23
+ Lookup.add SimpleUnit.new(:name => "g", :si_factor => 1, :dimension => :mass)
24
+ Lookup.add SimpleUnit.new(:name => "kg", :si_factor => 1000, :dimension => :mass)
25
+ Lookup.add SimpleUnit.new(:name => "tonne", :si_factor => 1000000, :dimension => :mass)
26
+
27
+ Lookup.add_property Property.new(:name => :mass, :expression => 'tonne')
28
+
29
+
30
+ #DERIVED UNITS
31
+
32
+ #ENERGY
33
+ Lookup.add DerivedUnit.new(:name => "J", :expression => 'kg*m^2/s^2')
34
+ Lookup.add DerivedUnit.new(:name => "kWh", :expression => '3.6e6*J')
35
+
36
+ Lookup.add_property Property.new(:name => :energy, :expression => 'kWh')
37
+
38
+ #AREA
39
+
40
+ Lookup.add DerivedUnit.new(:name => "hectare", :expression => '10000*m^2')
41
+ Lookup.add DerivedUnit.new(:name => "acre", :expression => '4046.85642*m^2')
42
+
43
+ Lookup.add_property Property.new(:name => :area, :expression => 'hectare')
44
+
45
+ end
46
+
47
+
48
+
49
+
50
+
@@ -0,0 +1,24 @@
1
+ # -*- encoding : utf-8 -*-
2
+ module Unity
3
+ class DerivedUnit
4
+
5
+ include ActiveModel::Validations
6
+ include Dimension::Vector
7
+ include Conversion
8
+
9
+ attr_accessor :name, :numerator, :denominator, :value
10
+
11
+ alias :to_s :name
12
+ validates_presence_of :name
13
+ validates_format_of :name, :with => /\A[^\s*\/\^]+\Z/, :message => "cannot contain *, / or ^"
14
+
15
+ def initialize(attributes = {})
16
+ attributes.each do |name, value|
17
+ send("#{name}=", value)
18
+ end
19
+ super
20
+ end
21
+
22
+
23
+ end
24
+ end
@@ -0,0 +1,21 @@
1
+ # -*- encoding : utf-8 -*-
2
+ module Unity
3
+ class Property
4
+
5
+ include ActiveModel::Validations
6
+ include Dimension::Vector
7
+ include Conversion
8
+
9
+ attr_accessor :name, :numerator, :denominator, :value
10
+
11
+ validates_presence_of :name
12
+
13
+ def initialize(attributes = {})
14
+ attributes.each do |name, value|
15
+ send("#{name}=", value)
16
+ end
17
+ super
18
+ end
19
+
20
+ end
21
+ end
@@ -0,0 +1,26 @@
1
+ # -*- encoding : utf-8 -*-
2
+ module Unity
3
+ class SimpleUnit
4
+
5
+ include ActiveModel::Validations
6
+ include Dimension::Integer
7
+
8
+ attr_accessor :dimension, :name, :si_factor
9
+ alias :to_s :name
10
+
11
+ validates_inclusion_of :dimension, :in => Dimension::LIST
12
+ validates_presence_of :si_factor, :dimension, :name
13
+ validates_format_of :name, :with => /\A[^\s*\/\^]+\Z/, :message => "cannot contain *, / or ^"
14
+
15
+ def dimension_vector
16
+ @dimension_vector ||= Dimension::LIST.map{|d| d == dimension ? 1 : 0 }
17
+ end
18
+
19
+ def initialize(attributes = {})
20
+ attributes.each do |name, value|
21
+ send("#{name}=", value)
22
+ end
23
+ end
24
+
25
+ end
26
+ end