Class: Pulo::Quantity
- Inherits:
-
Object
- Object
- Pulo::Quantity
- Includes:
- Comparable
- Defined in:
- lib/pulo/quantity/quantity.rb
Class Attribute Summary collapse
-
.base_unit ⇒ Object
Returns the value of attribute base_unit.
-
.dimensions ⇒ Object
Returns the value of attribute dimensions.
Instance Attribute Summary collapse
-
#unit ⇒ Object
Instance variables and methods - Child Quantities =====================================.
-
#value ⇒ Object
Instance variables and methods - Child Quantities =====================================.
Class Method Summary collapse
- .best_si_unit(scale) ⇒ Object
- .method_missing(method_sym, *arguments, &block) ⇒ Object
- .quantity_name ⇒ Object
- .si_unit_scales ⇒ Object
- .synonyms ⇒ Object
- .units ⇒ Object
- .units_sorted ⇒ Object
Instance Method Summary collapse
- #*(other) ⇒ Object
- #**(power) ⇒ Object
- #+(other) ⇒ Object
- #-(other) ⇒ Object
- #-@ ⇒ Object
- #/(other) ⇒ Object
- #<=>(other) ⇒ Object
- #dimensions ⇒ Object
- #existing_or_new_quantity(new_dims, target_scale, target_value) ⇒ Object
- #in ⇒ Object
-
#initialize(value = nil, unit = nil) ⇒ Quantity
constructor
A new instance of Quantity.
- #inverse ⇒ Object
- #is_si? ⇒ Boolean
-
#method_missing(method_sym, *arguments, &block) ⇒ Object
Pass unknown methods through to the underlying value (Float) if it responds.
-
#rescale ⇒ Object
Converts to SI and most ‘natural’ scale.
- #rt(power) ⇒ Object
- #to ⇒ Object
- #to_base_unit ⇒ Object
- #to_s(precision = nil, supress_quantity_names = false) ⇒ Object
- #to_si ⇒ Object
Constructor Details
#initialize(value = nil, unit = nil) ⇒ Quantity
90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 |
# File 'lib/pulo/quantity/quantity.rb', line 90 def initialize(value=nil, unit=nil) value ||= 1.0 if unit if unit.is_a?(Symbol) raise "Unit #{unit.to_s} not defined for #{self.class.quantity_name}." unless self.class.units[unit] self.unit=self.class.units[unit] else self.unit=unit end else self.unit=self.class.base_unit end self.value=Float(value) unless self.value.is_a?(Float) self end |
Dynamic Method Handling
This class handles dynamic methods through the method_missing method
#method_missing(method_sym, *arguments, &block) ⇒ Object
Pass unknown methods through to the underlying value (Float) if it responds. eg floor and modulo methods
119 120 121 122 123 |
# File 'lib/pulo/quantity/quantity.rb', line 119 def method_missing(method_sym, *arguments, &block) if self.value.respond_to?(method_sym) self.value.send(method_sym,*arguments,&block) end end |
Class Attribute Details
.base_unit ⇒ Object
Returns the value of attribute base_unit.
47 48 49 |
# File 'lib/pulo/quantity/quantity.rb', line 47 def base_unit @base_unit end |
.dimensions ⇒ Object
Returns the value of attribute dimensions.
48 49 50 |
# File 'lib/pulo/quantity/quantity.rb', line 48 def dimensions @dimensions end |
Instance Attribute Details
#unit ⇒ Object
Instance variables and methods - Child Quantities
88 89 90 |
# File 'lib/pulo/quantity/quantity.rb', line 88 def unit @unit end |
#value ⇒ Object
Instance variables and methods - Child Quantities
88 89 90 |
# File 'lib/pulo/quantity/quantity.rb', line 88 def value @value end |
Class Method Details
.best_si_unit(scale) ⇒ Object
50 51 52 53 54 |
# File 'lib/pulo/quantity/quantity.rb', line 50 def best_si_unit(scale) @si_unit_scales.min_by do |unit| (scale-unit[0]).abs end[1] end |
.method_missing(method_sym, *arguments, &block) ⇒ Object
56 57 58 59 |
# File 'lib/pulo/quantity/quantity.rb', line 56 def method_missing(method_sym, *arguments, &block) puts "#{quantity_name} doesn't have a unit #{method_sym}." puts "Available units are: " + units.map{|unt| unt[1].name }.join(', ') end |
.quantity_name ⇒ Object
61 62 63 |
# File 'lib/pulo/quantity/quantity.rb', line 61 def quantity_name self.name.split('::')[1] end |
.si_unit_scales ⇒ Object
44 |
# File 'lib/pulo/quantity/quantity.rb', line 44 def si_unit_scales; @si_unit_scales ||={};end |
.synonyms ⇒ Object
45 |
# File 'lib/pulo/quantity/quantity.rb', line 45 def synonyms; @synonyms ||=[]; end |
.units ⇒ Object
43 |
# File 'lib/pulo/quantity/quantity.rb', line 43 def units; @units ||={}; end |
.units_sorted ⇒ Object
65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 |
# File 'lib/pulo/quantity/quantity.rb', line 65 def units_sorted self.units.values.sort do |a,b| next -1 if a.is_si? && !b.is_si? next 1 if !a.is_si? && b.is_si? if a.is_si? next -1 if a.scale<b.scale next 1 else if a.si_convert_unit==b.si_convert_unit next a.si_convert_factor<=>b.si_convert_factor else a.si_convert_unit<=>b.si_convert_unit end end end end |
Instance Method Details
#*(other) ⇒ Object
159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 |
# File 'lib/pulo/quantity/quantity.rb', line 159 def *(other) case when other.is_a?(Numeric) self.class.new self.value*other,self.unit when other.is_a?(Quantity) new_dims=self.class.dimensions+other.class.dimensions #get both quantities to their equivalent SI if needed q1=self; q1=q1.to_si unless q1.is_si? q2=other; q2=q2.to_si unless q2.is_si? target_scale=q1.unit.scale+q2.unit.scale target_value=q1.value*q2.value existing_or_new_quantity new_dims,target_scale,target_value else raise QuantitiesException.new("Cannot multiply a #{other.class.name} and a #{self.class.name}") end end |
#**(power) ⇒ Object
194 195 196 197 198 199 200 201 202 203 204 |
# File 'lib/pulo/quantity/quantity.rb', line 194 def **(power) raise QuantitiesException.new('Can only raise a quantity to an integer power') unless power.is_a?(Integer) new_dims=self.class.dimensions*power q1=self; q1=q1.to_si unless q1.is_si? target_scale=q1.unit.scale*power target_value=q1.value**power existing_or_new_quantity new_dims,target_scale,target_value end |
#+(other) ⇒ Object
131 132 133 134 135 136 137 138 139 140 141 142 143 144 |
# File 'lib/pulo/quantity/quantity.rb', line 131 def +(other) case when other.is_a?(Numeric) self.class.new self.value+other,self.unit when other.class.dimensions==self.class.dimensions if self.unit==other.unit self.class.new self.value+other.value,self.unit else self.class.new self.value+other.send(self.unit.name).value,self.unit end else raise QuantitiesException.new("Cannot add a #{other.class.name} to a #{self.class.name}") end end |
#-(other) ⇒ Object
145 146 147 148 149 150 151 152 153 154 155 156 157 158 |
# File 'lib/pulo/quantity/quantity.rb', line 145 def -(other) case when other.is_a?(Numeric) self.class.new self.value-other,self.unit when other.class.dimensions==self.class.dimensions if self.unit==other.unit self.class.new self.value-other.value,self.unit else self.class.new self.value-other.send(self.unit.name).value,self.unit end else raise QuantitiesException.new("Cannot minus a #{other.class.name} from a #{self.class.name}") end end |
#-@ ⇒ Object
128 129 130 |
# File 'lib/pulo/quantity/quantity.rb', line 128 def -@ self.class.new -self.value,self.unit end |
#/(other) ⇒ Object
177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 |
# File 'lib/pulo/quantity/quantity.rb', line 177 def /(other) case when other.is_a?(Numeric) self.class.new self.value/other,self.unit when other.is_a?(Quantity) new_dims=self.class.dimensions-other.class.dimensions q1=self; q1=q1.to_si unless q1.is_si? q2=other; q2=q2.to_si unless q2.is_si? target_scale=q1.unit.scale-q2.unit.scale target_value=q1.value/q2.value existing_or_new_quantity new_dims,target_scale,target_value else raise QuantitiesException.new("Cannot divide a #{self.class.name} by a #{other.class.name}") end end |
#<=>(other) ⇒ Object
221 222 223 224 225 226 227 228 229 |
# File 'lib/pulo/quantity/quantity.rb', line 221 def <=>(other) unless (other.is_a?(Quantity) && self.class.dimensions==other.class.dimensions) || (other.is_a?(Numeric) && self.class==Dimensionless) raise QuantitiesException.new("Can only compare quantities with same dimensions (given: #{self.class} and #{other.class}).") end if other.is_a?(Numeric) other=Dimensionless.n(other) end to_base_unit.value<=>other.to_base_unit.value end |
#dimensions ⇒ Object
107 108 109 |
# File 'lib/pulo/quantity/quantity.rb', line 107 def dimensions self.class.dimensions end |
#existing_or_new_quantity(new_dims, target_scale, target_value) ⇒ Object
231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 |
# File 'lib/pulo/quantity/quantity.rb', line 231 def existing_or_new_quantity(new_dims, target_scale, target_value) if Pulo.quantities[new_dims] klass=Pulo.quantities[new_dims][0] unit=klass.best_si_unit Math.log10(target_value.abs) + target_scale klass.new(target_value*10**(target_scale-unit.scale), unit) else qname=new_dims.to_s(true).gsub(/-/, '_') QuantityBuilder.build(qname) do # noinspection RubyArgCount dimensions new_dims.spec si_unit '0.0'+qname, '', new_dims.to_s, 1.0 unless target_scale==0 si_unit target_scale.to_s+qname, '', new_dims.to_s+'*10^'+target_scale.to_s, 1.0*10**target_scale end end.klass.send(target_scale.to_s+qname, target_value) end end |
#in ⇒ Object
116 |
# File 'lib/pulo/quantity/quantity.rb', line 116 def in; self; end |
#inverse ⇒ Object
125 126 127 |
# File 'lib/pulo/quantity/quantity.rb', line 125 def inverse Dimensionless.new/self end |
#is_si? ⇒ Boolean
253 254 255 |
# File 'lib/pulo/quantity/quantity.rb', line 253 def is_si? @unit.is_si? end |
#rescale ⇒ Object
Converts to SI and most ‘natural’ scale
263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 |
# File 'lib/pulo/quantity/quantity.rb', line 263 def rescale unless self.is_si? return self.to_base_unit.rescale end scale=Math.log10(self.value)+self.unit.scale unit_scales=self.class.si_unit_scales.sort if scale<unit_scales[0][0] return self.send unit_scales[0][1].name end if scale>=unit_scales.last[0] return self.send unit_scales.last[1].name end unit_scales.each_cons(2) do |us| if us[0][0]<=scale && us[1][0]>scale return self.send us[0][1].name end end end |
#rt(power) ⇒ Object
205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 |
# File 'lib/pulo/quantity/quantity.rb', line 205 def rt(power) raise QuantitiesException.new('Can only do integer roots') unless power.is_a?(Integer) self.class.dimensions.spec.each do |dim| if dim[1]/power.to_f % 1 != 0 raise QuantitiesException.new('Root would lead to non-integer dimensions') end end new_dims=self.class.dimensions/power q1=self; q1=q1.to_si unless q1.is_si? target_scale=q1.unit.scale/power target_value=q1.value**(1.0/power) existing_or_new_quantity new_dims,target_scale,target_value end |
#to ⇒ Object
115 |
# File 'lib/pulo/quantity/quantity.rb', line 115 def to; self; end |
#to_base_unit ⇒ Object
249 250 251 |
# File 'lib/pulo/quantity/quantity.rb', line 249 def to_base_unit self.send(self.class.base_unit.name) end |
#to_s(precision = nil, supress_quantity_names = false) ⇒ Object
111 112 113 |
# File 'lib/pulo/quantity/quantity.rb', line 111 def to_s(precision=nil, supress_quantity_names=false) "#{self.class.quantity_name + ': ' unless Pulo.supress_quantity_names || supress_quantity_names || self.class==Dimensionless}#{NumberToRoundedConverter.convert(@value,precision)} #{@unit.abbreviation}" end |
#to_si ⇒ Object
257 258 259 260 |
# File 'lib/pulo/quantity/quantity.rb', line 257 def to_si return self if self.is_si? self.send(self.unit.si_convert_unit) end |