Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dev new units #1

Merged
merged 3 commits into from
Oct 7, 2024
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
Adding knot, km/h and nauticMiles
ELePors committed Sep 4, 2024
commit be8e1b59891adef83bd2b296b0384e19e4999781
484 changes: 242 additions & 242 deletions src/Units-Core/BaseUnit.class.st

Large diffs are not rendered by default.

240 changes: 120 additions & 120 deletions src/Units-Core/ComplexUnit.class.st
Original file line number Diff line number Diff line change
@@ -1,120 +1,120 @@
"
This represents a product of one or more different units.
"
Class {
#name : #ComplexUnit,
#superclass : #CompoundUnit,
#instVars : [
'conversionFactor',
'cachedBaseUnits'
],
#category : #'Units-Core'
}

{ #category : #'instance creation' }
ComplexUnit class >> units: units exponents: exponents [
"if we have just one exponent of size one, the unit itself is enough"
(exponents size = 1 and: [exponents first = 1]) ifTrue: [ ^units first ].
units
detect: [:each | each isBaseUnit not]
ifNone: [
"All the units are base units ... we can use a CompoundUnit instead to save space."
^CompoundUnit
units: units
exponents: exponents].
^self new
units: units
exponents: exponents
]

{ #category : #conversion }
ComplexUnit >> baseUnits [
"Since base units are expensive to compute for ComplexUnits, they are cached here."
cachedBaseUnits isNil
ifTrue: [cachedBaseUnits := self calculateBaseUnits].
^cachedBaseUnits
]

{ #category : #conversion }
ComplexUnit >> calculateBaseUnits [
| baseUnits unitDictionary newUnits newExponents scratch |
unitDictionary := IdentityDictionary new.
self unitsAndExponentsDo: [:unit :exponent |
baseUnits := unit baseUnits.
baseUnits unitsAndExponentsDo: [:subunit :subexponent |
(unitDictionary includesKey: subunit)
ifFalse: [
unitDictionary
at: subunit
put: subexponent * exponent]
ifTrue: [
unitDictionary
at: subunit
put: (unitDictionary at: subunit) + (subexponent * exponent)]]].
newUnits := OrderedCollection new.
newExponents := OrderedCollection new.
(unitDictionary keys asSortedCollection: self class sortBlock) do: [:unit |
scratch := unitDictionary at: unit.
scratch isZero ifFalse: [
newUnits add: unit.
newExponents add: scratch]].
^CompoundUnit
units: newUnits
exponents: newExponents
]

{ #category : #consistency }
ComplexUnit >> consistentWith: unit [
^unit consistentWithComplexUnit: self
]

{ #category : #consistency }
ComplexUnit >> consistentWithBaseUnit: baseUnit [
"This might be true, since we may be containing non-base units that reduce
to the base unit."
"For example, 'meters * seconds * Hertz' is consistent with 'meters'."
^self baseUnits consistentWith: baseUnit
]

{ #category : #consistency }
ComplexUnit >> consistentWithComplexUnit: complexUnit [
^self baseUnits consistentWith: complexUnit baseUnits
]

{ #category : #consistency }
ComplexUnit >> consistentWithCompoundUnit: compoundUnit [
^self baseUnits consistentWith: compoundUnit
]

{ #category : #consistency }
ComplexUnit >> consistentWithModifiedUnit: modifiedUnit [
"This might be true, since we may be containing non-base units that reduce to the
modified unit."
"For example, 'moles of hydrogen * seconds * Hertz' is consistent with 'moles of
hydrogen'."
^self baseUnits consistentWith: modifiedUnit
]

{ #category : #conversion }
ComplexUnit >> conversionFactor [
^conversionFactor
]

{ #category : #testing }
ComplexUnit >> isComplexUnit [
^ true
]

{ #category : #conversion }
ComplexUnit >> prefixedBy: prefixName [
^self error: 'You cannot attach prefixes to complex units.'
]

{ #category : #initialization }
ComplexUnit >> units: myUnits exponents: myExponents [
super units: myUnits exponents: myExponents.
conversionFactor := 1.
units with: exponents do: [:unit :exponent |
conversionFactor := conversionFactor *
(unit conversionFactor raisedTo: exponent)]
]
"
This represents a product of one or more different units.
"
Class {
#name : #ComplexUnit,
#superclass : #CompoundUnit,
#instVars : [
'conversionFactor',
'cachedBaseUnits'
],
#category : #'Units-Core'
}
{ #category : #'instance creation' }
ComplexUnit class >> units: units exponents: exponents [
"if we have just one exponent of size one, the unit itself is enough"
(exponents size = 1 and: [exponents first = 1]) ifTrue: [ ^units first ].
units
detect: [:each | each isBaseUnit not]
ifNone: [
"All the units are base units ... we can use a CompoundUnit instead to save space."
^CompoundUnit
units: units
exponents: exponents].
^self new
units: units
exponents: exponents
]
{ #category : #conversion }
ComplexUnit >> baseUnits [
"Since base units are expensive to compute for ComplexUnits, they are cached here."
cachedBaseUnits isNil
ifTrue: [cachedBaseUnits := self calculateBaseUnits].
^cachedBaseUnits
]
{ #category : #conversion }
ComplexUnit >> calculateBaseUnits [
| baseUnits unitDictionary newUnits newExponents scratch |
unitDictionary := IdentityDictionary new.
self unitsAndExponentsDo: [:unit :exponent |
baseUnits := unit baseUnits.
baseUnits unitsAndExponentsDo: [:subunit :subexponent |
(unitDictionary includesKey: subunit)
ifFalse: [
unitDictionary
at: subunit
put: subexponent * exponent]
ifTrue: [
unitDictionary
at: subunit
put: (unitDictionary at: subunit) + (subexponent * exponent)]]].
newUnits := OrderedCollection new.
newExponents := OrderedCollection new.
(unitDictionary keys asSortedCollection: self class sortBlock) do: [:unit |
scratch := unitDictionary at: unit.
scratch isZero ifFalse: [
newUnits add: unit.
newExponents add: scratch]].
^CompoundUnit
units: newUnits
exponents: newExponents
]
{ #category : #consistency }
ComplexUnit >> consistentWith: unit [
^unit consistentWithComplexUnit: self
]
{ #category : #consistency }
ComplexUnit >> consistentWithBaseUnit: baseUnit [
"This might be true, since we may be containing non-base units that reduce
to the base unit."
"For example, 'meters * seconds * Hertz' is consistent with 'meters'."
^self baseUnits consistentWith: baseUnit
]
{ #category : #consistency }
ComplexUnit >> consistentWithComplexUnit: complexUnit [
^self baseUnits consistentWith: complexUnit baseUnits
]
{ #category : #consistency }
ComplexUnit >> consistentWithCompoundUnit: compoundUnit [
^self baseUnits consistentWith: compoundUnit
]
{ #category : #consistency }
ComplexUnit >> consistentWithModifiedUnit: modifiedUnit [
"This might be true, since we may be containing non-base units that reduce to the
modified unit."
"For example, 'moles of hydrogen * seconds * Hertz' is consistent with 'moles of
hydrogen'."
^self baseUnits consistentWith: modifiedUnit
]
{ #category : #conversion }
ComplexUnit >> conversionFactor [
^conversionFactor
]
{ #category : #testing }
ComplexUnit >> isComplexUnit [
^ true
]
{ #category : #conversion }
ComplexUnit >> prefixedBy: prefixName [
^self error: 'You cannot attach prefixes to complex units.'
]
{ #category : #initialization }
ComplexUnit >> units: myUnits exponents: myExponents [
super units: myUnits exponents: myExponents.
conversionFactor := 1.
units with: exponents do: [:unit :exponent |
conversionFactor := conversionFactor *
(unit conversionFactor raisedTo: exponent)]
]
496 changes: 248 additions & 248 deletions src/Units-Core/CompoundUnit.class.st

Large diffs are not rendered by default.

146 changes: 73 additions & 73 deletions src/Units-Core/DerivedUnit.class.st
Original file line number Diff line number Diff line change
@@ -1,73 +1,73 @@
"
This is a definition of a unit in terms of a product of powers of
other units, plus a scalar value associated with the unit.
Example: 1 inch = 2.54 cm
Note that the ""left side"" is always magnitude 1, which corresponds to 1 unit of the DerivedUnit.
"
Class {
#name : #DerivedUnit,
#superclass : #NamedUnit,
#instVars : [
'unitValue'
],
#category : #'Units-Core'
}

{ #category : #'instance creation' }
DerivedUnit class >> abbreviation: abbreviation name: unitName pluralName: pluralName value: unitValue [
| unit |
unit := super
abbreviation: abbreviation
name: unitName
pluralName: pluralName.
unit value: unitValue.
^unit
]

{ #category : #conversion }
DerivedUnit >> baseUnits [
^unitValue unit baseUnits
]

{ #category : #consistency }
DerivedUnit >> consistentWith: unit [
"Short-circuit the double dispatching here."
^unitValue unitPart consistentWith: unit
]

{ #category : #consistency }
DerivedUnit >> consistentWithBaseUnit: baseUnit [
^baseUnit consistentWith: self unit
]

{ #category : #consistency }
DerivedUnit >> consistentWithComplexUnit: complexUnit [
^complexUnit consistentWith: self unit
]

{ #category : #consistency }
DerivedUnit >> consistentWithCompoundUnit: compoundUnit [
^compoundUnit consistentWith: self unit
]

{ #category : #consistency }
DerivedUnit >> consistentWithModifiedUnit: modifiedUnit [
^modifiedUnit consistentWith: self unit
]

{ #category : #conversion }
DerivedUnit >> conversionFactor [
^unitValue value * unitValue unit conversionFactor
]

{ #category : #accessing }
DerivedUnit >> unit [
^unitValue unit
]

{ #category : #initialization }
DerivedUnit >> value: myUnitValue [
unitValue := myUnitValue
]
"
This is a definition of a unit in terms of a product of powers of
other units, plus a scalar value associated with the unit.
Example: 1 inch = 2.54 cm
Note that the ""left side"" is always magnitude 1, which corresponds to 1 unit of the DerivedUnit.
"
Class {
#name : #DerivedUnit,
#superclass : #NamedUnit,
#instVars : [
'unitValue'
],
#category : #'Units-Core'
}

{ #category : #'instance creation' }
DerivedUnit class >> abbreviation: abbreviation name: unitName pluralName: pluralName value: unitValue [
| unit |
unit := super
abbreviation: abbreviation
name: unitName
pluralName: pluralName.
unit value: unitValue.
^unit
]

{ #category : #conversion }
DerivedUnit >> baseUnits [
^unitValue unit baseUnits
]

{ #category : #consistency }
DerivedUnit >> consistentWith: unit [
"Short-circuit the double dispatching here."
^unitValue unitPart consistentWith: unit
]

{ #category : #consistency }
DerivedUnit >> consistentWithBaseUnit: baseUnit [
^baseUnit consistentWith: self unit
]

{ #category : #consistency }
DerivedUnit >> consistentWithComplexUnit: complexUnit [
^complexUnit consistentWith: self unit
]

{ #category : #consistency }
DerivedUnit >> consistentWithCompoundUnit: compoundUnit [
^compoundUnit consistentWith: self unit
]

{ #category : #consistency }
DerivedUnit >> consistentWithModifiedUnit: modifiedUnit [
^modifiedUnit consistentWith: self unit
]

{ #category : #conversion }
DerivedUnit >> conversionFactor [
^unitValue value * unitValue unit conversionFactor
]

{ #category : #accessing }
DerivedUnit >> unit [
^unitValue unit
]

{ #category : #initialization }
DerivedUnit >> value: myUnitValue [
unitValue := myUnitValue
]
78 changes: 39 additions & 39 deletions src/Units-Core/MessageDelegate.class.st
Original file line number Diff line number Diff line change
@@ -1,39 +1,39 @@
"
An object that passes messages on to a private delegate
"
Class {
#name : #MessageDelegate,
#superclass : #ProtoObject,
#instVars : [
'privateDelegate'
],
#category : #'Units-Core'
}

{ #category : #'instance creation' }
MessageDelegate class >> on: anObject [
"Answer a new instance of the receiver with the given delegate."

^self new privateDelegate: anObject
]

{ #category : #'system primitives' }
MessageDelegate >> doesNotUnderstand: aMessage [
"Pass on to the delegate."

^self privateDelegate value: aMessage
]

{ #category : #accessing }
MessageDelegate >> privateDelegate [
"Answer the value of privateDelegate"

^ privateDelegate
]

{ #category : #accessing }
MessageDelegate >> privateDelegate: anObject [
"Set the value of privateDelegate"

privateDelegate := anObject
]
"
An object that passes messages on to a private delegate
"
Class {
#name : #MessageDelegate,
#superclass : #ProtoObject,
#instVars : [
'privateDelegate'
],
#category : #'Units-Core'
}

{ #category : #'instance creation' }
MessageDelegate class >> on: anObject [
"Answer a new instance of the receiver with the given delegate."

^self new privateDelegate: anObject
]

{ #category : #'system primitives' }
MessageDelegate >> doesNotUnderstand: aMessage [
"Pass on to the delegate."

^self privateDelegate value: aMessage
]

{ #category : #accessing }
MessageDelegate >> privateDelegate [
"Answer the value of privateDelegate"

^ privateDelegate
]

{ #category : #accessing }
MessageDelegate >> privateDelegate: anObject [
"Set the value of privateDelegate"

privateDelegate := anObject
]
240 changes: 120 additions & 120 deletions src/Units-Core/ModifiedUnit.class.st
Original file line number Diff line number Diff line change
@@ -1,120 +1,120 @@
"
A base unit with an arbitrary modification that makes it incompatible
with anything that does not have the same modification. Works well with domain-specific
'modifications', e.g.,
1.6 moles
can now become:
1.6 moles of sulfuric acid
(""sulfuric acid"" might be a String, or a ChemicalCompound, or whatever.)
"
Class {
#name : #ModifiedUnit,
#superclass : #Unit,
#instVars : [
'baseUnit',
'modification'
],
#category : #'Units-Core'
}

{ #category : #'instance creation' }
ModifiedUnit class >> baseUnit: baseUnit modification: modification [
^self new
baseUnit: baseUnit
modification: modification
]

{ #category : #comparing }
ModifiedUnit >> = anotherUnit [
self class = anotherUnit class ifFalse: [^false].
modification = anotherUnit modification ifFalse: [^false].
^baseUnit = anotherUnit baseUnit
]

{ #category : #accessing }
ModifiedUnit >> baseUnit [
^baseUnit
]

{ #category : #initialization }
ModifiedUnit >> baseUnit: myBaseUnit modification: myModification [
baseUnit := myBaseUnit.
modification := myModification
]

{ #category : #conversion }
ModifiedUnit >> baseUnits [
^self
]

{ #category : #consistency }
ModifiedUnit >> consistentWith: anotherUnit [
^anotherUnit consistentWithModifiedUnit: self
]

{ #category : #consistency }
ModifiedUnit >> consistentWithBaseUnit: anotherBaseUnit [
^false
]

{ #category : #consistency }
ModifiedUnit >> consistentWithComplexUnit: complexUnit [
^self consistentWith: complexUnit baseUnits
]

{ #category : #consistency }
ModifiedUnit >> consistentWithCompoundUnit: compoundUnit [
^false
]

{ #category : #consistency }
ModifiedUnit >> consistentWithModifiedUnit: modifiedUnit [
self class == modifiedUnit class ifFalse: [^false].
^baseUnit = modifiedUnit baseUnit
and: [modification = modifiedUnit modification]
]

{ #category : #conversion }
ModifiedUnit >> conversionFactor [
^baseUnit conversionFactor
]

{ #category : #comparing }
ModifiedUnit >> hash [
^modification hash bitXor: baseUnit hash
]

{ #category : #predicates }
ModifiedUnit >> isBaseUnit [
"ModifiedUnits are effectively new base units..."
^true
]

{ #category : #accessing }
ModifiedUnit >> modification [
^modification
]

{ #category : #printing }
ModifiedUnit >> printAbbreviationOn: stream [
baseUnit printAbbreviationOn: stream.
stream nextPut: $(.
modification isString
ifTrue: [stream nextPutAll: modification]
ifFalse: [stream print: modification].
stream nextPut: $)
]

{ #category : #printing }
ModifiedUnit >> printFullNameOn: stream pluralized: pluralized [
baseUnit printFullNameOn: stream pluralized: pluralized.
stream nextPutAll: ' (of '.
"Can't avoid the #isString, since strings print differently than other objects,
and it is valid to have non-strings as the modification."
modification isString
ifTrue: [stream nextPutAll: modification]
ifFalse: [stream print: modification].
stream nextPut: $)
]
"
A base unit with an arbitrary modification that makes it incompatible
with anything that does not have the same modification. Works well with domain-specific
'modifications', e.g.,
1.6 moles
can now become:
1.6 moles of sulfuric acid
(""sulfuric acid"" might be a String, or a ChemicalCompound, or whatever.)
"
Class {
#name : #ModifiedUnit,
#superclass : #Unit,
#instVars : [
'baseUnit',
'modification'
],
#category : #'Units-Core'
}

{ #category : #'instance creation' }
ModifiedUnit class >> baseUnit: baseUnit modification: modification [
^self new
baseUnit: baseUnit
modification: modification
]

{ #category : #comparing }
ModifiedUnit >> = anotherUnit [
self class = anotherUnit class ifFalse: [^false].
modification = anotherUnit modification ifFalse: [^false].
^baseUnit = anotherUnit baseUnit
]

{ #category : #accessing }
ModifiedUnit >> baseUnit [
^baseUnit
]

{ #category : #initialization }
ModifiedUnit >> baseUnit: myBaseUnit modification: myModification [
baseUnit := myBaseUnit.
modification := myModification
]

{ #category : #conversion }
ModifiedUnit >> baseUnits [
^self
]

{ #category : #consistency }
ModifiedUnit >> consistentWith: anotherUnit [
^anotherUnit consistentWithModifiedUnit: self
]

{ #category : #consistency }
ModifiedUnit >> consistentWithBaseUnit: anotherBaseUnit [
^false
]

{ #category : #consistency }
ModifiedUnit >> consistentWithComplexUnit: complexUnit [
^self consistentWith: complexUnit baseUnits
]

{ #category : #consistency }
ModifiedUnit >> consistentWithCompoundUnit: compoundUnit [
^false
]

{ #category : #consistency }
ModifiedUnit >> consistentWithModifiedUnit: modifiedUnit [
self class == modifiedUnit class ifFalse: [^false].
^baseUnit = modifiedUnit baseUnit
and: [modification = modifiedUnit modification]
]

{ #category : #conversion }
ModifiedUnit >> conversionFactor [
^baseUnit conversionFactor
]

{ #category : #comparing }
ModifiedUnit >> hash [
^modification hash bitXor: baseUnit hash
]

{ #category : #predicates }
ModifiedUnit >> isBaseUnit [
"ModifiedUnits are effectively new base units..."
^true
]

{ #category : #accessing }
ModifiedUnit >> modification [
^modification
]

{ #category : #printing }
ModifiedUnit >> printAbbreviationOn: stream [
baseUnit printAbbreviationOn: stream.
stream nextPut: $(.
modification isString
ifTrue: [stream nextPutAll: modification]
ifFalse: [stream print: modification].
stream nextPut: $)
]

{ #category : #printing }
ModifiedUnit >> printFullNameOn: stream pluralized: pluralized [
baseUnit printFullNameOn: stream pluralized: pluralized.
stream nextPutAll: ' (of '.
"Can't avoid the #isString, since strings print differently than other objects,
and it is valid to have non-strings as the modification."
modification isString
ifTrue: [stream nextPutAll: modification]
ifFalse: [stream print: modification].
stream nextPut: $)
]
664 changes: 332 additions & 332 deletions src/Units-Core/NamedUnit.class.st

Large diffs are not rendered by default.

1,314 changes: 681 additions & 633 deletions src/Units-Core/Number.extension.st

Large diffs are not rendered by default.

48 changes: 24 additions & 24 deletions src/Units-Core/Point.extension.st
Original file line number Diff line number Diff line change
@@ -1,24 +1,24 @@
Extension { #name : #Point }

{ #category : #'*Units-Core' }
Point >> as [
"Answer a delegate on the receiver #as: to handle the next message."

^MessageDelegate on: [:m | self as: m selector]
]

{ #category : #'*Units-Core' }
Point >> as: anotherUnit [
"Convert the receiver to have the same units as 'anotherUnit'. Apply any appropriate
scaling factors. Gives an error if the receiver's x and y are not consistent with 'anotherUnit'."

^(self x as: anotherUnit) @ (self y as: anotherUnit)
]

{ #category : #'*Units-Core' }
Point >> value [
"Answer a new point with the x and y being the respective
values of the receiver's ordinates."

^self x value @ self y value
]
Extension { #name : #Point }

{ #category : #'*Units-Core' }
Point >> as [
"Answer a delegate on the receiver #as: to handle the next message."

^MessageDelegate on: [:m | self as: m selector]
]

{ #category : #'*Units-Core' }
Point >> as: anotherUnit [
"Convert the receiver to have the same units as 'anotherUnit'. Apply any appropriate
scaling factors. Gives an error if the receiver's x and y are not consistent with 'anotherUnit'."

^(self x as: anotherUnit) @ (self y as: anotherUnit)
]

{ #category : #'*Units-Core' }
Point >> value [
"Answer a new point with the x and y being the respective
values of the receiver's ordinates."

^self x value @ self y value
]
182 changes: 91 additions & 91 deletions src/Units-Core/PrefixedUnit.class.st
Original file line number Diff line number Diff line change
@@ -1,91 +1,91 @@
"
This is a unit with an SI prefix attached.
See class SIPrefix for details.
"
Class {
#name : #PrefixedUnit,
#superclass : #Unit,
#instVars : [
'prefix',
'unit'
],
#category : #'Units-Core'
}

{ #category : #'instance creation' }
PrefixedUnit class >> prefix: prefix unit: unit [
^self new prefix: prefix unit: unit
]

{ #category : #'instance creation' }
PrefixedUnit class >> prefixName: prefixName unit: unit [
| prefix |
prefix := SIPrefix named: prefixName.
^self prefix: prefix unit: unit
]

{ #category : #comparing }
PrefixedUnit >> = anotherUnit [
self class == anotherUnit class ifFalse: [^false].
^prefix = anotherUnit prefix and: [unit = anotherUnit unit]
]

{ #category : #conversion }
PrefixedUnit >> baseUnits [
^unit baseUnits
]

{ #category : #consistency }
PrefixedUnit >> consistentWith: anotherUnit [
"Short-circuit the double dispatching; just compare the actual unit."
^anotherUnit consistentWith: unit
]

{ #category : #consistency }
PrefixedUnit >> consistentWithAnything: anotherUnit [
^unit consistentWith: anotherUnit
]

{ #category : #conversion }
PrefixedUnit >> conversionFactor [
^prefix scalingFactor * unit conversionFactor
]

{ #category : #comparing }
PrefixedUnit >> hash [
^prefix hash bitXor: unit hash
]

{ #category : #accessing }
PrefixedUnit >> prefix [
^prefix
]

{ #category : #initialization }
PrefixedUnit >> prefix: myPrefix unit: myUnit [
prefix := myPrefix.
unit := myUnit
]

{ #category : #conversion }
PrefixedUnit >> prefixedBy: prefixName [
^self error: 'This unit already has a prefix.'
]

{ #category : #printing }
PrefixedUnit >> printAbbreviationOn: stream [
stream nextPutAll: prefix abbreviation.
unit printAbbreviationOn: stream
]

{ #category : #printing }
PrefixedUnit >> printFullNameOn: stream pluralized: pluralized [
stream nextPutAll: prefix name.
unit printFullNameOn: stream pluralized: pluralized
]

{ #category : #accessing }
PrefixedUnit >> unit [
^unit
]
"
This is a unit with an SI prefix attached.
See class SIPrefix for details.
"
Class {
#name : #PrefixedUnit,
#superclass : #Unit,
#instVars : [
'prefix',
'unit'
],
#category : #'Units-Core'
}

{ #category : #'instance creation' }
PrefixedUnit class >> prefix: prefix unit: unit [
^self new prefix: prefix unit: unit
]

{ #category : #'instance creation' }
PrefixedUnit class >> prefixName: prefixName unit: unit [
| prefix |
prefix := SIPrefix named: prefixName.
^self prefix: prefix unit: unit
]

{ #category : #comparing }
PrefixedUnit >> = anotherUnit [
self class == anotherUnit class ifFalse: [^false].
^prefix = anotherUnit prefix and: [unit = anotherUnit unit]
]

{ #category : #conversion }
PrefixedUnit >> baseUnits [
^unit baseUnits
]

{ #category : #consistency }
PrefixedUnit >> consistentWith: anotherUnit [
"Short-circuit the double dispatching; just compare the actual unit."
^anotherUnit consistentWith: unit
]

{ #category : #consistency }
PrefixedUnit >> consistentWithAnything: anotherUnit [
^unit consistentWith: anotherUnit
]

{ #category : #conversion }
PrefixedUnit >> conversionFactor [
^prefix scalingFactor * unit conversionFactor
]

{ #category : #comparing }
PrefixedUnit >> hash [
^prefix hash bitXor: unit hash
]

{ #category : #accessing }
PrefixedUnit >> prefix [
^prefix
]

{ #category : #initialization }
PrefixedUnit >> prefix: myPrefix unit: myUnit [
prefix := myPrefix.
unit := myUnit
]

{ #category : #conversion }
PrefixedUnit >> prefixedBy: prefixName [
^self error: 'This unit already has a prefix.'
]

{ #category : #printing }
PrefixedUnit >> printAbbreviationOn: stream [
stream nextPutAll: prefix abbreviation.
unit printAbbreviationOn: stream
]

{ #category : #printing }
PrefixedUnit >> printFullNameOn: stream pluralized: pluralized [
stream nextPutAll: prefix name.
unit printFullNameOn: stream pluralized: pluralized
]

{ #category : #accessing }
PrefixedUnit >> unit [
^unit
]
244 changes: 122 additions & 122 deletions src/Units-Core/SIPrefix.class.st
Original file line number Diff line number Diff line change
@@ -1,122 +1,122 @@
"
SIPrefix represents a power of 10 attached to a unit.
Examples: milli, micro, kilo, etc.
"
Class {
#name : #SIPrefix,
#superclass : #Object,
#instVars : [
'abbreviation',
'name',
'scalingFactor'
],
#classVars : [
'SIPrefixesByAbbreviation',
'SIPrefixesByName'
],
#category : #'Units-Core'
}

{ #category : #initialization }
SIPrefix class >> abbreviation: abbreviation name: prefixName scalingFactor: scalingFactor [
| prefix |
prefix := self new
abbreviation: abbreviation
name: prefixName
scalingFactor: scalingFactor.
SIPrefixesByAbbreviation at: abbreviation put: prefix.
SIPrefixesByName at: prefixName put: prefix.
^prefix
]

{ #category : #initialization }
SIPrefix class >> initializeClass [
"SIPrefix initializeClass."
"Do not rename this to #initialize."
SIPrefixesByName := Dictionary new.
SIPrefixesByAbbreviation := Dictionary new.
self abbreviation: 'y' name: 'yocto' scalingFactor: (10 raisedTo: -24).
self abbreviation: 'z' name: 'zepto' scalingFactor: (10 raisedTo: -21).
self abbreviation: 'a' name: 'atto' scalingFactor: (10 raisedTo: -18).
self abbreviation: 'f' name: 'femto' scalingFactor: (10 raisedTo: -15).
self abbreviation: 'p' name: 'pico' scalingFactor: (10 raisedTo: -12).
self abbreviation: 'n' name: 'nano' scalingFactor: (10 raisedTo: -9).
self abbreviation: 'u' name: 'micro' scalingFactor: (10 raisedTo: -6).
self abbreviation: 'm' name: 'milli' scalingFactor: (10 raisedTo: -3).
self abbreviation: 'c' name: 'centi' scalingFactor: (10 raisedTo: -2).
self abbreviation: 'd' name: 'deci' scalingFactor: (10 raisedTo: -1).
self abbreviation: 'da' name: 'deka' scalingFactor: (10 raisedTo: 1).
self abbreviation: 'h' name: 'hecto' scalingFactor: (10 raisedTo: 2).
self abbreviation: 'k' name: 'kilo' scalingFactor: (10 raisedTo: 3).
self abbreviation: 'M' name: 'mega' scalingFactor: (10 raisedTo: 6).
self abbreviation: 'G' name: 'giga' scalingFactor: (10 raisedTo: 9).
self abbreviation: 'T' name: 'tera' scalingFactor: (10 raisedTo: 12).
self abbreviation: 'P' name: 'peta' scalingFactor: (10 raisedTo: 15).
self abbreviation: 'E' name: 'exa' scalingFactor: (10 raisedTo: 18).
self abbreviation: 'Z' name: 'zetta' scalingFactor: (10 raisedTo: 21).
self abbreviation: 'Y' name: 'yotta' scalingFactor: (10 raisedTo: 24)
]

{ #category : #accessing }
SIPrefix class >> named: prefixName [
^SIPrefixesByName at: prefixName
]

{ #category : #enumerating }
SIPrefix class >> prefixAbbreviationsDo: block [
"Evaluate 'block' once with each prefix abbreviation, in no particular order."
SIPrefixesByAbbreviation keysDo: block
]

{ #category : #enumerating }
SIPrefix class >> prefixStringsDo: block [
"Evaluate 'block' once with each prefix string, in no particular order."
SIPrefixesByName keysDo: block
]

{ #category : #accessing }
SIPrefix class >> withAbbreviation: abbreviation [
^SIPrefixesByAbbreviation at: abbreviation
]

{ #category : #accessing }
SIPrefix >> abbreviation [
^abbreviation
]

{ #category : #initialization }
SIPrefix >> abbreviation: myAbbreviation name: myName scalingFactor: myScalingFactor [
abbreviation := myAbbreviation.
name := myName.
scalingFactor := myScalingFactor
]

{ #category : #accessing }
SIPrefix >> name [
^name
]

{ #category : #printing }
SIPrefix >> printOn: stream [
super printOn: stream.
stream
nextPutAll: ' [';
nextPutAll: name;
nextPut: $]
]

{ #category : #accessing }
SIPrefix >> scalingFactor [
^scalingFactor
]

{ #category : #printing }
SIPrefix >> storeOn: aStream [
"Store the code to lookup the receiver instead of for a new instance."

aStream
nextPutAll: '(SIPrefix named: ''';
nextPutAll: name;
nextPutAll: ''')'
]
"
SIPrefix represents a power of 10 attached to a unit.
Examples: milli, micro, kilo, etc.
"
Class {
#name : #SIPrefix,
#superclass : #Object,
#instVars : [
'abbreviation',
'name',
'scalingFactor'
],
#classVars : [
'SIPrefixesByAbbreviation',
'SIPrefixesByName'
],
#category : #'Units-Core'
}

{ #category : #initialization }
SIPrefix class >> abbreviation: abbreviation name: prefixName scalingFactor: scalingFactor [
| prefix |
prefix := self new
abbreviation: abbreviation
name: prefixName
scalingFactor: scalingFactor.
SIPrefixesByAbbreviation at: abbreviation put: prefix.
SIPrefixesByName at: prefixName put: prefix.
^prefix
]

{ #category : #initialization }
SIPrefix class >> initializeClass [
"SIPrefix initializeClass."
"Do not rename this to #initialize."
SIPrefixesByName := Dictionary new.
SIPrefixesByAbbreviation := Dictionary new.
self abbreviation: 'y' name: 'yocto' scalingFactor: (10 raisedTo: -24).
self abbreviation: 'z' name: 'zepto' scalingFactor: (10 raisedTo: -21).
self abbreviation: 'a' name: 'atto' scalingFactor: (10 raisedTo: -18).
self abbreviation: 'f' name: 'femto' scalingFactor: (10 raisedTo: -15).
self abbreviation: 'p' name: 'pico' scalingFactor: (10 raisedTo: -12).
self abbreviation: 'n' name: 'nano' scalingFactor: (10 raisedTo: -9).
self abbreviation: 'u' name: 'micro' scalingFactor: (10 raisedTo: -6).
self abbreviation: 'm' name: 'milli' scalingFactor: (10 raisedTo: -3).
self abbreviation: 'c' name: 'centi' scalingFactor: (10 raisedTo: -2).
self abbreviation: 'd' name: 'deci' scalingFactor: (10 raisedTo: -1).
self abbreviation: 'da' name: 'deka' scalingFactor: (10 raisedTo: 1).
self abbreviation: 'h' name: 'hecto' scalingFactor: (10 raisedTo: 2).
self abbreviation: 'k' name: 'kilo' scalingFactor: (10 raisedTo: 3).
self abbreviation: 'M' name: 'mega' scalingFactor: (10 raisedTo: 6).
self abbreviation: 'G' name: 'giga' scalingFactor: (10 raisedTo: 9).
self abbreviation: 'T' name: 'tera' scalingFactor: (10 raisedTo: 12).
self abbreviation: 'P' name: 'peta' scalingFactor: (10 raisedTo: 15).
self abbreviation: 'E' name: 'exa' scalingFactor: (10 raisedTo: 18).
self abbreviation: 'Z' name: 'zetta' scalingFactor: (10 raisedTo: 21).
self abbreviation: 'Y' name: 'yotta' scalingFactor: (10 raisedTo: 24)
]

{ #category : #accessing }
SIPrefix class >> named: prefixName [
^SIPrefixesByName at: prefixName
]

{ #category : #enumerating }
SIPrefix class >> prefixAbbreviationsDo: block [
"Evaluate 'block' once with each prefix abbreviation, in no particular order."
SIPrefixesByAbbreviation keysDo: block
]

{ #category : #enumerating }
SIPrefix class >> prefixStringsDo: block [
"Evaluate 'block' once with each prefix string, in no particular order."
SIPrefixesByName keysDo: block
]

{ #category : #accessing }
SIPrefix class >> withAbbreviation: abbreviation [
^SIPrefixesByAbbreviation at: abbreviation
]

{ #category : #accessing }
SIPrefix >> abbreviation [
^abbreviation
]

{ #category : #initialization }
SIPrefix >> abbreviation: myAbbreviation name: myName scalingFactor: myScalingFactor [
abbreviation := myAbbreviation.
name := myName.
scalingFactor := myScalingFactor
]

{ #category : #accessing }
SIPrefix >> name [
^name
]

{ #category : #printing }
SIPrefix >> printOn: stream [
super printOn: stream.
stream
nextPutAll: ' [';
nextPutAll: name;
nextPut: $]
]

{ #category : #accessing }
SIPrefix >> scalingFactor [
^scalingFactor
]

{ #category : #printing }
SIPrefix >> storeOn: aStream [
"Store the code to lookup the receiver instead of for a new instance."

aStream
nextPutAll: '(SIPrefix named: ''';
nextPutAll: name;
nextPutAll: ''')'
]
40 changes: 20 additions & 20 deletions src/Units-Core/String.extension.st
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
Extension { #name : #String }

{ #category : #'*Units-Core' }
String >> asUnit [
"Answer the receiver as a unit."

^UnitValue unitFor: self asSymbol
]

{ #category : #'*Units-Core' }
String >> asUnitValue [
"Answer the receiver as a unit value."

|n p i|
n := self asNumber.
i := self findString: (p := n printString).
i = 0 ifTrue: [^nil].
^n units: (self allButFirst: p size) withBlanksTrimmed asUnit

]
Extension { #name : #String }

{ #category : #'*Units-Core' }
String >> asUnit [
"Answer the receiver as a unit."

^UnitValue unitFor: self asSymbol
]

{ #category : #'*Units-Core' }
String >> asUnitValue [
"Answer the receiver as a unit value."

|n p i|
n := self asNumber.
i := self findString: (p := n printString).
i = 0 ifTrue: [^nil].
^n units: (self allButFirst: p size) withBlanksTrimmed asUnit

]
48 changes: 24 additions & 24 deletions src/Units-Core/TemperatureBaseUnit.class.st
Original file line number Diff line number Diff line change
@@ -1,24 +1,24 @@
"
Temperature units are different because they require
a general linear transformation for basic arithmetic operations.
"
Class {
#name : #TemperatureBaseUnit,
#superclass : #BaseUnit,
#category : #'Units-Core'
}

{ #category : #predicates }
TemperatureBaseUnit >> isZeroAsValue: value [
^false
]

{ #category : #conversion }
TemperatureBaseUnit >> uncheckedConvertFrom: anotherUnitValue [
| newValue |
newValue :=
(anotherUnitValue value - anotherUnitValue unitPart additiveFactor) *
(anotherUnitValue unit conversionFactorTo: self).
^UnitValue unit: self value: newValue
]
"
Temperature units are different because they require
a general linear transformation for basic arithmetic operations.
"
Class {
#name : #TemperatureBaseUnit,
#superclass : #BaseUnit,
#category : #'Units-Core'
}

{ #category : #predicates }
TemperatureBaseUnit >> isZeroAsValue: value [
^false
]

{ #category : #conversion }
TemperatureBaseUnit >> uncheckedConvertFrom: anotherUnitValue [
| newValue |
newValue :=
(anotherUnitValue value - anotherUnitValue unitPart additiveFactor) *
(anotherUnitValue unit conversionFactorTo: self).
^UnitValue unit: self value: newValue
]
120 changes: 60 additions & 60 deletions src/Units-Core/TemperatureUnit.class.st
Original file line number Diff line number Diff line change
@@ -1,60 +1,60 @@
"
A temperature needs an additional ""additive factor"" to handle,
e.g., Celsius to Fahrenheit.
"
Class {
#name : #TemperatureUnit,
#superclass : #DerivedUnit,
#instVars : [
'additiveFactor'
],
#category : #'Units-Core'
}

{ #category : #'instance creation' }
TemperatureUnit class >> abbreviation: abbreviation
name: unitName
pluralName: pluralName
value: unitValue
additiveFactor: additiveFactor [
| unit |
unit := super
abbreviation: abbreviation
name: unitName
pluralName: pluralName
value: unitValue.
unit additiveFactor: additiveFactor.
^unit
]

{ #category : #accessing }
TemperatureUnit >> additiveFactor [
^additiveFactor
]

{ #category : #initialization }
TemperatureUnit >> additiveFactor: myAdditiveFactor [
additiveFactor := myAdditiveFactor
]

{ #category : #predicates }
TemperatureUnit >> isZeroAsValue: value [

]

{ #category : #conversion }
TemperatureUnit >> uncheckedConvertFrom: anotherUnitValue [
| kelvin newValue |
^anotherUnitValue unit isBaseUnit
ifTrue: [
newValue :=
(anotherUnitValue value /
(self conversionFactorTo: anotherUnitValue unit)) + additiveFactor.
UnitValue
unit: self
value: newValue]
ifFalse: [
kelvin := anotherUnitValue uncheckedConvertTo: Unit kelvin.
kelvin convertTo: self]
]
"
A temperature needs an additional ""additive factor"" to handle,
e.g., Celsius to Fahrenheit.
"
Class {
#name : #TemperatureUnit,
#superclass : #DerivedUnit,
#instVars : [
'additiveFactor'
],
#category : #'Units-Core'
}

{ #category : #'instance creation' }
TemperatureUnit class >> abbreviation: abbreviation
name: unitName
pluralName: pluralName
value: unitValue
additiveFactor: additiveFactor [
| unit |
unit := super
abbreviation: abbreviation
name: unitName
pluralName: pluralName
value: unitValue.
unit additiveFactor: additiveFactor.
^unit
]

{ #category : #accessing }
TemperatureUnit >> additiveFactor [
^additiveFactor
]

{ #category : #initialization }
TemperatureUnit >> additiveFactor: myAdditiveFactor [
additiveFactor := myAdditiveFactor
]

{ #category : #predicates }
TemperatureUnit >> isZeroAsValue: value [

]

{ #category : #conversion }
TemperatureUnit >> uncheckedConvertFrom: anotherUnitValue [
| kelvin newValue |
^anotherUnitValue unit isBaseUnit
ifTrue: [
newValue :=
(anotherUnitValue value /
(self conversionFactorTo: anotherUnitValue unit)) + additiveFactor.
UnitValue
unit: self
value: newValue]
ifFalse: [
kelvin := anotherUnitValue uncheckedConvertTo: Unit kelvin.
kelvin convertTo: self]
]
2,532 changes: 1,284 additions & 1,248 deletions src/Units-Core/Unit.class.st

Large diffs are not rendered by default.

864 changes: 432 additions & 432 deletions src/Units-Core/UnitValue.class.st

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion src/Units-Core/package.st
Original file line number Diff line number Diff line change
@@ -1 +1 @@
Package { #name : #'Units-Core' }
Package { #name : #'Units-Core' }