| 1 | """ |
|---|
| 2 | MakeAClassHierarchy.cobra |
|---|
| 3 | |
|---|
| 4 | This HowTo shows the syntax for classes, inheritance, initializers, properties, |
|---|
| 5 | defining toString, unit tests and so forth. |
|---|
| 6 | |
|---|
| 7 | The class hierarchy is: |
|---|
| 8 | |
|---|
| 9 | Object |
|---|
| 10 | Vehicle |
|---|
| 11 | Aircraft |
|---|
| 12 | Plane |
|---|
| 13 | Train |
|---|
| 14 | Automobile |
|---|
| 15 | """ |
|---|
| 16 | |
|---|
| 17 | |
|---|
| 18 | enum Medium |
|---|
| 19 | """ |
|---|
| 20 | Defines the various mediums that a vehicle can travel through. |
|---|
| 21 | """ |
|---|
| 22 | belowWater |
|---|
| 23 | aboveWater |
|---|
| 24 | land |
|---|
| 25 | air |
|---|
| 26 | space |
|---|
| 27 | |
|---|
| 28 | |
|---|
| 29 | class Vehicle |
|---|
| 30 | |
|---|
| 31 | test |
|---|
| 32 | v = Vehicle() |
|---|
| 33 | assert not v.isMoving |
|---|
| 34 | assert not v.hasMoved |
|---|
| 35 | assert v.serialNum > 0 |
|---|
| 36 | |
|---|
| 37 | v.startMoving |
|---|
| 38 | assert v.isMoving |
|---|
| 39 | assert not v.hasMoved # because no miles accumulated |
|---|
| 40 | |
|---|
| 41 | v.move(5) |
|---|
| 42 | assert v.isMoving |
|---|
| 43 | assert v.hasMoved |
|---|
| 44 | assert v.numMiles == 5 |
|---|
| 45 | |
|---|
| 46 | v.move(3) |
|---|
| 47 | assert v.numMiles == 8 |
|---|
| 48 | |
|---|
| 49 | v.stopMoving |
|---|
| 50 | assert not v.isMoving |
|---|
| 51 | assert v.hasMoved |
|---|
| 52 | |
|---|
| 53 | w = Vehicle() |
|---|
| 54 | assert v.serialNum <> w.serialNum |
|---|
| 55 | |
|---|
| 56 | |
|---|
| 57 | shared |
|---|
| 58 | var __nextSerialNum = 1001 |
|---|
| 59 | |
|---|
| 60 | cue init |
|---|
| 61 | base.init |
|---|
| 62 | _serialNum = __nextSerialNum |
|---|
| 63 | __nextSerialNum += 1 |
|---|
| 64 | |
|---|
| 65 | get serialNum from var as int |
|---|
| 66 | # `get` defines a read-only property. |
|---|
| 67 | # `from var` is a shortcut syntax to cover |
|---|
| 68 | # the variable with the matching name. |
|---|
| 69 | |
|---|
| 70 | get hasMoved as bool |
|---|
| 71 | return _numMiles > 0 |
|---|
| 72 | |
|---|
| 73 | get isMoving from var as bool |
|---|
| 74 | |
|---|
| 75 | get numMiles from var as number |
|---|
| 76 | |
|---|
| 77 | def startMoving |
|---|
| 78 | assert not _isMoving, 'Already moving.' |
|---|
| 79 | _isMoving = true |
|---|
| 80 | |
|---|
| 81 | def move(distance as decimal) |
|---|
| 82 | assert _isMoving, 'Invoke startMoving first.' |
|---|
| 83 | assert distance > 0 |
|---|
| 84 | _numMiles += distance |
|---|
| 85 | |
|---|
| 86 | def stopMoving |
|---|
| 87 | assert _isMoving, 'Not moving.' |
|---|
| 88 | _isMoving = false |
|---|
| 89 | |
|---|
| 90 | def canTravelIn(medium as Medium) as bool |
|---|
| 91 | """ |
|---|
| 92 | Returns true if the given medium is the primary medium that the vehicle |
|---|
| 93 | normally travels through. |
|---|
| 94 | """ |
|---|
| 95 | return false |
|---|
| 96 | |
|---|
| 97 | def toString as String is override |
|---|
| 98 | test |
|---|
| 99 | v = Vehicle() |
|---|
| 100 | sn = v.serialNum |
|---|
| 101 | assert v.toString == 'Vehicle([sn])' |
|---|
| 102 | body |
|---|
| 103 | sb = StringBuilder() |
|---|
| 104 | sb.append('[.typeOf.name]([_serialNum]') # example: 'Foo(1001)' |
|---|
| 105 | .buildString(sb) # so subclasses can add their fields |
|---|
| 106 | sb.append(')') |
|---|
| 107 | return sb.toString |
|---|
| 108 | |
|---|
| 109 | def buildString(sb as StringBuilder) is protected |
|---|
| 110 | """ |
|---|
| 111 | Invoked by `toString` so that subclasses can add their information. |
|---|
| 112 | Subclasses should normally invoke base. |
|---|
| 113 | """ |
|---|
| 114 | pass |
|---|
| 115 | |
|---|
| 116 | |
|---|
| 117 | class Aircraft inherits Vehicle |
|---|
| 118 | |
|---|
| 119 | def canTravelIn(medium as Medium) as bool is override |
|---|
| 120 | return medium == Medium.air |
|---|
| 121 | |
|---|
| 122 | |
|---|
| 123 | class Plane inherits Aircraft |
|---|
| 124 | |
|---|
| 125 | pass |
|---|
| 126 | |
|---|
| 127 | |
|---|
| 128 | class Train inherits Vehicle |
|---|
| 129 | |
|---|
| 130 | cue init(numUnits as int) |
|---|
| 131 | require numUnits > 0 # see "Declare Contracts" How To |
|---|
| 132 | base.init |
|---|
| 133 | _numUnits = numUnits |
|---|
| 134 | |
|---|
| 135 | get numUnits from var as int |
|---|
| 136 | """ |
|---|
| 137 | The number of locomotives and railroad cars in the train. |
|---|
| 138 | """ |
|---|
| 139 | |
|---|
| 140 | def canTravelIn(medium as Medium) as bool is override |
|---|
| 141 | return medium == Medium.land |
|---|
| 142 | |
|---|
| 143 | def buildString(sb as StringBuilder) is protected, override |
|---|
| 144 | base.buildString(sb) |
|---|
| 145 | sb.append(', [_numUnits] units') |
|---|
| 146 | |
|---|
| 147 | |
|---|
| 148 | class Automobile inherits Vehicle |
|---|
| 149 | |
|---|
| 150 | def canTravelIn(medium as Medium) as bool is override |
|---|
| 151 | return medium == Medium.land |
|---|
| 152 | |
|---|
| 153 | |
|---|
| 154 | class Program |
|---|
| 155 | |
|---|
| 156 | def main |
|---|
| 157 | # create some vehicles |
|---|
| 158 | p = Plane() |
|---|
| 159 | t = Train(5) |
|---|
| 160 | a = Automobile() |
|---|
| 161 | |
|---|
| 162 | vehicles = [p, t, a] # a list |
|---|
| 163 | |
|---|
| 164 | for v in vehicles |
|---|
| 165 | assert v.serialNum > 0 |
|---|
| 166 | print v |
|---|