Class: Pulo::Quantity
- Inherits:
-
Object
show all
- Includes:
- Comparable
- Defined in:
- lib/pulo/quantity/quantity.rb
Class Attribute Summary collapse
Instance Attribute Summary collapse
-
#unit ⇒ Object
Instance variables and methods - Child Quantities =====================================.
-
#value ⇒ Object
Instance variables and methods - Child Quantities =====================================.
Class Method Summary
collapse
Instance Method Summary
collapse
Constructor Details
#initialize(value = nil, unit = nil) ⇒ Quantity
Returns a new instance of 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
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
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
|