Module: SY::Magnitude

Includes:
Comparable, ExpressibleInUnits
Defined in:
lib/sy/magnitude.rb

Overview

This module defines common assets of a magnitude – be it absolute (number of unit objects), or relative (magnitude difference).

Constant Summary

Constants included from ExpressibleInUnits

ExpressibleInUnits::COLLISION_WARNING, ExpressibleInUnits::REDEFINE_WARNING, ExpressibleInUnits::RecursionError

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from ExpressibleInUnits

exponentiation_string, find_unit, included, included_in, known_units, method_family, #method_missing, prefix_method_string, #respond_to_missing?, unit_namespace

Dynamic Method Handling

This class handles dynamic methods through the method_missing method in the class SY::ExpressibleInUnits

Instance Attribute Details

#amountObject (readonly) Also known as: in_standard_unit

Returns the value of attribute amount.



55
56
57
# File 'lib/sy/magnitude.rb', line 55

def amount
  @amount
end

#quantityObject (readonly)

Returns the value of attribute quantity.



55
56
57
# File 'lib/sy/magnitude.rb', line 55

def quantity
  @quantity
end

Class Method Details

.absolute(of: nil, amount: nil) ⇒ Object

Constructs an absolute magnitude of a given quantity.



10
11
12
# File 'lib/sy/magnitude.rb', line 10

def absolute( of: nil, amount: nil )
  of.absolute.magnitude( amount )
end

.difference(of: nil, amount: nil) ⇒ Object

Constructs a relative magnitude of a given quantity.



16
17
18
# File 'lib/sy/magnitude.rb', line 16

def difference( of: nil, amount: nil )
  of.relative.magnitude( amount )
end

.of(quantity, amount: nil) ⇒ Object

Constructs a magnitude of a given quantity.



22
23
24
# File 'lib/sy/magnitude.rb', line 22

def of( quantity, amount: nil )
  quantity.magnitude( amount )
end

.one(of: nil) ⇒ Object

Magnitude 1 of a given quantity.



34
35
36
# File 'lib/sy/magnitude.rb', line 34

def one( of: nil )
  absolute of: of, amount: 1
end

.zero(of: nil) ⇒ Object

Zero magnitude of a given quantity.



28
29
30
# File 'lib/sy/magnitude.rb', line 28

def zero( of: nil )
  absolute of: of, amount: 0
end

Instance Method Details

#%(m2) ⇒ Object

Percent operator (remainder after division)



177
178
179
180
181
# File 'lib/sy/magnitude.rb', line 177

def % m2
  return magnitude amount % m2.amount if quantity == m2.quantity
  return self % m2.( quantity ) if quantity.coerces? m2.quantity
  apply_through_coerce :%, m2
end

#*(m2) ⇒ Object

Multiplication.



128
129
130
131
132
133
134
135
136
137
138
139
# File 'lib/sy/magnitude.rb', line 128

def * m2
  case m2
  when Numeric then
    magnitude amount * m2
  # when SY::ZERO then
  #   return magnitude 0
  when Matrix then
    m2.map { |e| self * e }
  else
    ( quantity * m2.quantity ).magnitude( amount * m2.amount )
  end
end

#**(exp) ⇒ Object

Exponentiation.



158
159
160
161
162
163
164
165
166
167
# File 'lib/sy/magnitude.rb', line 158

def ** exp
  case exp
  when SY::Magnitude then
    raise SY::DimensionError, "Exponent must have zero dimension! " +
      "(exp given)" unless exp.dimension.zero?
    ( quantity ** exp.amount ).magnitude( amount ** exp.amount )
  else
    ( quantity ** exp ).magnitude( amount ** exp )
  end
end

#+(m2) ⇒ Object

Addition.



112
113
114
115
116
# File 'lib/sy/magnitude.rb', line 112

def + m2
  return magnitude amount + m2.amount if quantity == m2.quantity
  return self + m2.( quantity ) if quantity.coerces? m2.quantity
  apply_through_coerce :+, m2
end

#+@Object

Reframes the magnitude into its relative quantity.



88
89
90
# File 'lib/sy/magnitude.rb', line 88

def +@
  quantity.relative.magnitude( amount )
end

#-(m2) ⇒ Object

Subtraction.



120
121
122
123
124
# File 'lib/sy/magnitude.rb', line 120

def - m2
  return magnitude amount - m2.amount if quantity == m2.quantity
  return self - m2.( quantity ) if quantity.coerces? m2.quantity
  apply_through_coerce :-, m2
end

#-@Object

Reframes the magnitude into its relative quantity, with negative amount.



94
95
96
# File 'lib/sy/magnitude.rb', line 94

def -@
  quantity.relative.magnitude( -amount )
end

#/(m2) ⇒ Object

Division.



143
144
145
146
147
148
149
150
151
152
153
154
# File 'lib/sy/magnitude.rb', line 143

def / m2
  case m2
  when Numeric then
    magnitude amount / m2
  # when SY::ZERO then
  #   raise ZeroDivisionError, "Attempt to divide #{self} by #{SY::ZERO}."
  when Matrix then
    amount / m2 * quantity.magnitude( 1 )
  else
    ( quantity / m2.quantity ).magnitude( amount / m2.amount )
  end
end

#<=>(m2) ⇒ Object

Three-way comparison operator of magnitudes.



49
50
51
52
53
# File 'lib/sy/magnitude.rb', line 49

def <=> m2
  return amount <=> m2.amount if quantity == m2.quantity
  return self <=> m2.( quantity ) if quantity.coerces? m2.quantity
  apply_through_coerce :<=>, m2
end

#absObject

Absolute value of a magnitude (no reframe).



100
101
102
# File 'lib/sy/magnitude.rb', line 100

def abs
  magnitude amount.abs
end

#absoluteObject

Computes absolute value and reframes into the absolute quantity.



76
77
78
# File 'lib/sy/magnitude.rb', line 76

def absolute
  quantity.absolute.magnitude( amount.abs )
end

#call(q2) ⇒ Object

Reframes a magnitude into a relative version of a given quantity. (If absolute quantity is supplied as an argument, its relative colleague is used to reframe.)



229
230
231
232
233
234
# File 'lib/sy/magnitude.rb', line 229

def call q2
  case q2
  when SY::Quantity then q2.relative.read self
  when SY::Unit then q2.quantity.relative.read self
  else raise TypeError, "Unable to reframe into a #{q2.class}!" end
end

#coerce(m2) ⇒ Object

Type coercion for magnitudes.



185
186
187
188
189
190
191
192
193
194
195
# File 'lib/sy/magnitude.rb', line 185

def coerce m2
  if m2.is_a? Numeric then
    return SY::Amount.relative.magnitude( m2 ), self
  elsif m2.is_a? Matrix then
    return m2 * SY::UNIT, self
  elsif quantity.coerces? m2.quantity then
    return m2.( quantity ), self
  else
    raise TypeError, "#{self} cannot be coerced into a #{m2.class}!"
  end
end

#eql?(other) ⇒ Boolean

Same magnitudes and same (#eql) quantities.

Returns:

  • (Boolean)


171
172
173
# File 'lib/sy/magnitude.rb', line 171

def eql? other
  quantity == other.quantity && amount == other.amount
end

#in(m2) ⇒ Object

Gives the magnitude as a plain number in multiples of another magnitude, supplied as argument. The quantities must match.



200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
# File 'lib/sy/magnitude.rb', line 200

def in m2
  case m2
  when Symbol, String then
    begin
      self.in eval( "1.#{m2}" ).aT_kind_of SY::Magnitude # digest it
    rescue TypeError
      raise TypeError, "Evaluating 1.#{m2} does not result in a magnitude; " +
        "method collision with another library?"
    end
  when SY::Magnitude then
    quantity.measure( of: m2.quantity ).w.( amount ) / m2.amount
  else
    raise TypeError, "Unexpected type for Magnitude#in method! (#{m2.class})"
  end
end

#inspectObject

Inspect string of the magnitude



310
311
312
# File 'lib/sy/magnitude.rb', line 310

def inspect
  "#<#{çς}: #{self} >"
end

#negative?Boolean

True if amount is negative. Implicitly false for absolute quantities.

Returns:

  • (Boolean)


238
239
240
# File 'lib/sy/magnitude.rb', line 238

def negative?
  amount < 0
end

#nonnegative?Boolean

Opposite of #negative?. Implicitly true for absolute quantities.

Returns:

  • (Boolean)


244
245
246
# File 'lib/sy/magnitude.rb', line 244

def nonnegative?
  amount >= 0
end

#reframe(q2) ⇒ Object

Reframes a magnitude into a different quantity. Dimension must match.



218
219
220
221
222
223
# File 'lib/sy/magnitude.rb', line 218

def reframe q2
  case q2
  when SY::Quantity then q2.read self
  when SY::Unit then q2.quantity.read self
  else raise TypeError, "Unable to reframe into a #{q2.class}!" end
end

#relativeObject

Reframes into the relative quantity.



82
83
84
# File 'lib/sy/magnitude.rb', line 82

def relative
  quantity.relative.magnitude( amount )
end

#round(*args) ⇒ Object

Rounded value of a Magnitude: A new magnitude with rounded amount.



106
107
108
# File 'lib/sy/magnitude.rb', line 106

def round *args
  magnitude amount.round( *args )
end

#to_magnitudeObject

Without arguments, it returns a new magnitude equal to self. If argument is given, it is treated as factor, by which the amount is to be muliplied.



317
318
319
# File 'lib/sy/magnitude.rb', line 317

def to_magnitude
  magnitude( amount )
end

#to_s(unit = quantity.units.first || quantity.standard_unit, number_format = default_amount_format) ⇒ Object



267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
# File 'lib/sy/magnitude.rb', line 267

def to_s( unit=quantity.units.first || quantity.standard_unit,
          number_format=default_amount_format )
  begin
    un = unit.short || unit.name
    if un then
      number = self.in unit
      number_ς = number_format % number
      prefix = ''
      exp = 1
      # unit_presentation = prefix, unit, exp
      unit_ς = SY::SPS.( [ "#{prefix}#{unit.short}" ], [ exp ] )
      [ number_ς, unit_ς ].join '.'
    else
      number = amount
      # otherwise, use units of component quantities
       = quantity.composition.to_hash
      symbols, exponents = .each_with_object Hash.new do |pair, memo|
        qnt, exp = pair
        if qnt.standard_unit.name
          std_unit = qnt.standard_unit
          memo[ std_unit.short || std_unit.name ] = exp
        else
          m = qnt.magnitude( 1 ).to_s
          memo[ m[2..-1] ] = exp
          number = m[0].to_i * number
        end
      end.to_a.transpose
      # assemble SPS
      unit_ς = SY::SPS.( symbols, exponents )
      # interpolate
      number_ς = number_format % number
      return number_ς if unit_ς == '' || unit_ς == 'unit'
      [ number_ς, unit_ς ].join '.'
    end
  rescue
    fail
    number_ς = number_format % amount
    [ number_ς, "unit[#{quantity}]" ].join '.'
  end
end