Quantity Model in Smalltalk
Object subclass: #Quantity
instanceVariableNames: 'amount unit '
classVariableNames: ''
poolDictionaries: ''!
!Quantity class publicMethods !
amount: aValue unit: aUnit
^(self new)
amount: aValue;
unit: aUnit;
yourself
!
amount: aValue unitNamed: aUnitName
^self amount: aValue unit: (self unitFromName: aUnitName asSymbol)
!
roundingValue
^0.00005
!
unitFromName: aUnitName
^UnitSystem unitFromName: aUnitName
! !
!Quantity publicMethods !
= aQuantity
^aQuantity species = self species
and: [aQuantity amount = self amount and: [aQuantity unit = self unit]]
!
amount
^amount!
amount: aNumber
amount := aNumber
!
amountExpressedOnUnit: aUnitName
| factor |
factor := self unit conversionFactorTo: aUnitName.
^self amount * factor!
create
self isValid ifFalse: [^self].
self assignUniqueKey.
super create!
displayOnUnit: aUnitName
| outStream |
outStream := WriteStream with: String new.
(self expressOnUnit: aUnitName) displayOn: outStream.
^outStream contents
!
displayOnUnits: unitNames
| outStream |
outStream := WriteStream with: String new.
(self expressOnUnits: unitNames) printOn: outStream.
^outStream contents
!
expressOnUnit: aUnitName
| factor |
factor := self unit conversionFactorTo: aUnitName.
^self class amount: self amount * factor unitNamed: aUnitName!
expressOnUnits: aUnitNameCollection
| unitsDecorator |
unitsDecorator := MultiUnitsQuantityDecorator with: self.
^self expressOnUnits: aUnitNameCollection using: unitsDecorator!
expressOnUnits: aUnitNameCollection using: unitsDecorator
| conversionAmount factorCollection |
conversionAmount := self amount.
factorCollection := self unit conversionFactorsTo: aUnitNameCollection.
1 to: factorCollection size - 1
do:
[:index |
| currentFactor |
currentFactor := factorCollection at: index.
conversionAmount := conversionAmount * currentFactor
roundTo: self class roundingValue.
unitsDecorator addUnitNamed: (aUnitNameCollection at: index)
withValue: (conversionAmount truncateTo: 1).
conversionAmount := conversionAmount rem: 1].
unitsDecorator addUnitNamed: aUnitNameCollection last
withValue: (conversionAmount * factorCollection last
roundTo: self class roundingValue).
^unitsDecorator!
isValid
^true!
printOn: aStream
self amount printOn: aStream.
aStream space.
self unit printOn: aStream
!
unit
^unit!
unit: aUnit
unit := aUnit
!
unitSystem
^self unit unitSystem
!
Quantity initializeAfterLoad!
Object subclass: #SiblingUnit
instanceVariableNames: 'subject conversionFactor '
classVariableNames: ''
poolDictionaries: ''!
!SiblingUnit class publicMethods !
unit: anUnit targetUnitSystem: targetUnitSystem
| unitFamily |
unitFamily := targetUnitSystem unitFamily.
^(self new)
subject: anUnit;
computeConversionFactor: (unitFamily factorForSystem: anUnit unitSystem)
/ (unitFamily factorForSystem: targetUnitSystem);
yourself
! !
!SiblingUnit publicMethods !
computeConversionFactor: conversionFactorBetweenSystems
conversionFactor := conversionFactorBetweenSystems
* self subject baseFactor!
conversionFactor
^conversionFactor
!
subject
^subject!
subject: anObject
subject := anObject! !
SiblingUnit initializeAfterLoad!
Object subclass: #Unit
instanceVariableNames: 'name unitSystem '
classVariableNames: ''
poolDictionaries: ''!
!Unit publicMethods !
= anObject
^anObject species = self species and: [anObject name = self name]
!
baseFactor
^self unitSystem baseFactorFor: self
!
conversionFactorsTo: unitNames
| lastUnit |
lastUnit := self.
^unitNames collect:
[:each |
| factor |
factor := lastUnit conversionFactorTo: each.
lastUnit := lastUnit unitFromName: each.
factor]
!
conversionFactorTo: aUnitName
^self unitSystem conversionFactorFrom: self
to: (self unitSystem unitFromName: aUnitName)
!
name
^name!
name: aString
name := aString
!
printOn: aStream
aStream
nextPutAll: self name asString;
space
!
unitFromName: aUnitName
^self unitSystem unitFromName: aUnitName!
unitSystem
^unitSystem!
unitSystem: aUnitSystem
unitSystem := aUnitSystem
! !
Unit initializeAfterLoad!
Object subclass: #UnitFamily
instanceVariableNames: 'name factors baseSystem '
classVariableNames: ''
poolDictionaries: ''!
!UnitFamily class publicMethods !
dimensionUnitFamily
| aUnitFamily |
aUnitFamily := self new.
aUnitFamily name: #dimensionUnitFamily.
aUnitFamily addBaseSystem: UnitSystem dimensionMetric.
aUnitFamily addSystem: UnitSystem dimensionUS factor: 1.094.
^aUnitFamily
!
initializeAfterLoad
super initializeAfterLoad.
UnitSystem resetUnitSystems.
self dimensionUnitFamily.
self massUnitFamily.
self timeUnitFamily.
!
massUnitFamily
| aUnitFamily |
aUnitFamily := self new.
aUnitFamily name: #massUnitFamily.
aUnitFamily addBaseSystem: UnitSystem massMetric.
aUnitFamily addSystem: UnitSystem massUS factor: 0.0022046226.
^aUnitFamily
!
timeUnitFamily
| aUnitFamily |
aUnitFamily := self new.
aUnitFamily name: #timeUnitFamily.
aUnitFamily addBaseSystem: UnitSystem time.
^aUnitFamily
! !
!UnitFamily publicMethods !
addBaseSystem: aSystem
self addSystem: aSystem factor: 1.
self baseSystem: aSystem
!
addSystem: aSystem factor: aNumber
aSystem unitFamily: self.
self factors at: aSystem put: aNumber
!
baseSystem
^baseSystem!
baseSystem: anObject
baseSystem := anObject!
factorForSystem: aUnitSystem
^self factors at: aUnitSystem
!
factors
^factors isNil ifTrue: [factors := Dictionary new] ifFalse: [factors]
!
includedSystems
^factors keys!
name
^name!
name: aSymbol
name := aSymbol
!
printOn: aStream
aStream nextPutAll: self name asString
!
siblingSystemsFor: aUnitSystem
| siblings |
siblings := self factors keys.
siblings remove: aUnitSystem.
^siblings!
siblingUnitNamed: aUnitName for: aUnitSystem
| originUnitSystem |
originUnitSystem := self factors keys
detect: [:each | each definesUnitNamed: aUnitName].
^SiblingUnit unit: (originUnitSystem unitFromName: aUnitName)
targetUnitSystem: aUnitSystem
!
unitSystemFromName: aSystemName
^self factors keys detect: [:each | each name = aSystemName]
! !
UnitFamily initializeAfterLoad!
Object subclass: #UnitSystem
instanceVariableNames: 'name unitFamily factors baseUnit '
classVariableNames: 'UnitSystems '
poolDictionaries: ''!
!UnitSystem class publicMethods !
dimensionMetric
| aSystem |
aSystem := self unitSystemNamed: #dimensionMetric.
aSystem defineBaseUnit: #meters.
aSystem defineUnit: #decimeters factor: 10.
aSystem defineUnit: #centimeters factor: 100.
aSystem defineUnit: #millimeters factor: 1000.
aSystem defineUnit: #micrometers factor: 10000.
aSystem defineUnit: #nanometers factor: 100000.
aSystem defineUnit: #picometers factor: 1000000.
aSystem defineUnit: #dekameters factor: 0.1.
aSystem defineUnit: #hectometers factor: 0.01.
aSystem defineUnit: #kilometers factor: 0.001.
aSystem defineUnit: #megameters factor: 0.0001.
aSystem defineUnit: #gigameters factor: 0.00001.
^aSystem
!
dimensionUS
| aSystem |
aSystem := self unitSystemNamed: #dimensionUS.
aSystem defineBaseUnit: #yards.
aSystem defineUnit: #miles factor: 1 / 1760.
aSystem defineUnit: #fathoms factor: 0.5.
aSystem defineUnit: #feet factor: 3.
aSystem defineUnit: #inches factor: 36.
aSystem defineUnit: #mils factor: 36000.
^aSystem
!
massMetric
| aSystem |
aSystem := self unitSystemNamed: #massMetric.
aSystem defineBaseUnit: #grams.
aSystem defineUnit: #decigrams factor: 10.
aSystem defineUnit: #centigrams factor: 100.
aSystem defineUnit: #milligrams factor: 1000.
aSystem defineUnit: #micrograms factor: 10000.
aSystem defineUnit: #nanograms factor: 100000.
aSystem defineUnit: #picograms factor: 1000000.
aSystem defineUnit: #dekagrams factor: 0.1.
aSystem defineUnit: #hectograms factor: 0.01.
aSystem defineUnit: #kilograms factor: 0.001.
^aSystem
!
massUS
| aSystem |
aSystem := self unitSystemNamed: #massUS.
aSystem defineBaseUnit: #lbs.
aSystem defineUnit: #oz factor: 16.
aSystem defineUnit: #drams factor: 256.
^aSystem
!
resetUnitSystems
UnitSystems := OrderedCollection new!
time
| aSystem |
aSystem := self unitSystemNamed: #time.
aSystem defineBaseUnit: #Weeks.
aSystem defineUnit: #Days factor: 7.
aSystem defineUnit: #Hours factor: 168.
aSystem defineUnit: #Minutes factor: 10080.
aSystem defineUnit: #Seconds factor: 604800.
^aSystem
!
unitFromName: aUnitName
| aUnitSystem |
(aUnitName isNil or:[aUnitName isEmpty]) ifTrue:[^nil].
aUnitSystem := UnitSystems
detect: [:each | each includesUnitNamed: aUnitName].
^aUnitSystem unitFromName: aUnitName
!
unitSystemNamed: aSymbol
| instance |
^UnitSystems detect: [:each | each name = aSymbol]
ifNone:
[instance := super new.
instance name: aSymbol.
UnitSystems add: instance.
instance]
! !
!UnitSystem publicMethods !
baseFactorFor: aUnit
^self factors at: aUnit
!
baseUnit
^baseUnit!
baseUnit: anUnit
baseUnit := anUnit
!
conversionFactorFrom: aUnit to: anotherUnit
| fromFactor toFactor |
fromFactor := self factors at: aUnit
ifAbsent:
[self error: 'Unable to find the unit definition into its UnitSystem'].
toFactor := self factors at: anotherUnit
ifAbsent:
[self
error: 'Unable to find the external unit definition into the UnitSystem'].
^toFactor / fromFactor
!
defineBaseUnit: aUnitName
self baseUnit: (self defineUnit: aUnitName factor: 1).
^self baseUnit
!
definedUnits
^((self factors keys select: [:each | each unitSystem = self])
asSortedCollection: [:a :b | (self baseFactorFor: a) > (self baseFactorFor: b)])
asOrderedCollection!
definesUnitNamed: aSymbol
^self definedUnits contains: [:each | each name = aSymbol asSymbol]
!
defineUnit: aUnitName factor: aNumber
| aUnit |
aUnit := (Unit new)
name: aUnitName;
unitSystem: self;
yourself.
self factors at: aUnit put: aNumber.
^aUnit
!
factors
^factors isNil ifTrue: [factors := Dictionary new] ifFalse: [factors]
!
includesUnitNamed: aSymbol
^self factors keys contains: [:each | each name = aSymbol asSymbol]
!
name
^name!
name: aSymbol
name := aSymbol
!
printOn: aStream
aStream nextPutAll: self name asString
!
siblingUnitSystems
^self unitFamily siblingSystemsFor: self!
unitFamily
^unitFamily!
unitFamily: anUnitFamily
unitFamily := anUnitFamily
!
unitFromName: aUnitName
^self factors keys detect: [:each | each name = aUnitName asSymbol]
ifNone:
[| siblingUnit |
siblingUnit := self unitFamily siblingUnitNamed: aUnitName for: self.
self factors at: siblingUnit subject put: siblingUnit conversionFactor.
siblingUnit subject]! !
UnitSystem initializeAfterLoad!