• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Ducasse / Containers-PropertyEnvironment / 10028001166

21 Jul 2024 11:37AM UTC coverage: 94.876%. Remained the same
10028001166

push

github

web-flow
Merge pull request #4 from Ducasse/fixingNotNil

fixing notNil -> isNotNil

611 of 644 relevant lines covered (94.88%)

0.95 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

83.98
/Containers-PropertyEnvironment/CTEnvironment.class.st
1
"
2
I'm a kind of dictionary with optional lookup in my parent. I'm an environment of properties with values (binding key -> value). I may have an ancestor chain (father, grand-father...) in which I look for my properties when I do not define them. 
3

4
Users should pay attention than getting keys is not the same as iterating on keys since a parent may have the same keys than a child. Therefore the iteration will iterate all the keys/values while getting the keys will return a set of the unique keys and not an array with potential duplicates because from the client of a child it is not possible to access a shadowed keys in a parent.
5

6

7
Implementation notes.
8

9
For the moment keysDo: do not garantee any order. A possible improvement would be to use an orderedUniqueCollection to keep the keys. 
10

11
"
12
Class {
13
        #name : 'CTEnvironment',
14
        #superclass : 'Object',
15
        #instVars : [
16
                'parent',
17
                'properties'
18
        ],
19
        #category : 'Containers-PropertyEnvironment',
20
        #package : 'Containers-PropertyEnvironment'
21
}
22

23
{ #category : 'examples' }
24
CTEnvironment class >> childEnvironmentExample [
×
25
        <sampleInstance>
×
26
        ^ self new
×
27
                propertyAt: #P1inChildren put: 12;
×
28
                propertyAt: #P2inChildren put: 13; yourself
×
29
]
×
30

31
{ #category : 'examples' }
32
CTEnvironment class >> childEnvironmentWithParentExample [
×
33
        <sampleInstance>
×
34
        ^ self childEnvironmentExample parent: self parentEnvironmentExample ; yourself
×
35
]
×
36

37
{ #category : 'instance creation' }
38
CTEnvironment class >> fromDictionary: aDictionary [
1✔
39

1✔
40
        | inst |
1✔
41
        inst := self new. 
1✔
42
        aDictionary keysAndValuesDo: [ :k :v | inst at: k put: v ].
1✔
43
        ^ inst
1✔
44
        
1✔
45
]
1✔
46

47
{ #category : 'examples' }
48
CTEnvironment class >> parentEnvironmentExample [
×
49
        <sampleInstance>
×
50
        ^ self new
×
51
                propertyAt: #P1inChildren put: 24;
×
52
                propertyAt: #P0inParent put: 50 ; yourself
×
53
]
×
54

55
{ #category : 'conversion' }
56
CTEnvironment >> allProperties [
1✔
57
        "Answer all properties of the receiver and its parents."
1✔
58
        "This method should be removed.... or at least should return a CTEnvironment"
1✔
59
        | parentProperties |
1✔
60
        parentProperties := self hasParent
1✔
61
                ifTrue: [ parent allProperties ]
1✔
62
                ifFalse: [ Dictionary new ].
1✔
63
        parentProperties addAll: self properties.
1✔
64
        "addAll: is not in the current API of environment"
1✔
65
        ^ parentProperties
1✔
66
]
1✔
67

68
{ #category : 'conversion' }
69
CTEnvironment >> asFlatDictionary [
×
70
        "Answer a new  of the receiver and its parents."
×
71

×
72
        ^ self flattenIn: Dictionary new
×
73
]
×
74

75
{ #category : 'accessing - dictionary' }
76
CTEnvironment >> at: aKey [
1✔
77
        "Answer the value of the property ==aKey==, potentially looking in the parent, raises an error if the property doesn't exist."
1✔
78

1✔
79

1✔
80
        ^ properties
1✔
81
                at: aKey asSymbol
1✔
82
                ifAbsent: [ self hasParent
1✔
83
                                ifTrue: [ parent at: aKey ]
1✔
84
                                ifFalse: [ self errorPropertyNotFound: aKey ] ]
1✔
85
]
1✔
86

87
{ #category : 'accessing - dictionary' }
88
CTEnvironment >> at: aKey ifAbsent: aBlock [
1✔
89
        "Answer the value of the property ==aKey==, potentially looking in parents, or the result of ==aBlock== if the property doesn't exist."
1✔
90

1✔
91
        ^ properties
1✔
92
                at: aKey asSymbol
1✔
93
                ifAbsent: [ self hasParent
1✔
94
                                ifTrue: [ parent at: aKey ifAbsent: aBlock ]
1✔
95
                                ifFalse: aBlock ]
1✔
96
]
1✔
97

98
{ #category : 'accessing - dictionary' }
99
CTEnvironment >> at: aKey ifAbsentPut: aBlock [
1✔
100
        "Answer the value of the property ==aKey==, potentially defined in parents, or if the property doesn't exist adds and answers the result of evaluating ==aBlock==."
1✔
101

1✔
102
        "We look up first to know and once we know if the property is not defined somewhere, then we set it. We do it like that to avoid to execute the put block on the parent because the put should be executed on the child."
1✔
103
        ^ (self hasProperty: aKey)
1✔
104
                        ifTrue: [ self at: aKey ]
1✔
105
                        ifFalse: [ self at: aKey put: aBlock value ]
1✔
106
]
1✔
107

108
{ #category : 'accessing - dictionary' }
109
CTEnvironment >> at: aKey ifPresent: presentBlock ifAbsent: absentBlock [
1✔
110
        "Answer the result of ==presentBlock== if I have the property ==aKey==, in the receiver or its parents or the result of ==absentBlock==."
1✔
111

1✔
112
        ^ (self hasProperty: aKey)
1✔
113
                        ifTrue: [ presentBlock value: (self at: aKey) ]
1✔
114
                        ifFalse: [ absentBlock value ]
1✔
115
]
1✔
116

117
{ #category : 'accessing - dictionary' }
118
CTEnvironment >> at: aKey put: aValue [
1✔
119
        "Adds or replaces the property ==aKey== with ==aValue== in the receiver."
1✔
120

1✔
121
        ^ properties at: aKey asSymbol put: aValue
1✔
122
]
1✔
123

124
{ #category : 'iteration' }
125
CTEnvironment >> do: aBlock [ 
1✔
126
        "Evaluate aBlock for each of the receiver's values, starting from the receiver and going up in its parent chain if any."
1✔
127

1✔
128
        self valuesDo: aBlock
1✔
129
]
1✔
130

131
{ #category : 'error' }
132
CTEnvironment >> errorPropertyNotFound: aKey [ 
×
133

×
134
        KeyNotFound signal: aKey
×
135
]
×
136

137
{ #category : 'conversion' }
138
CTEnvironment >> flattenIn: aDictionable [
×
139
        "Answer a new aDictionable of the receiver and its parents."
×
140

×
141
        self hasParent
×
142
                ifTrue: [ parent flattenIn: aDictionable ].
×
143
        aDictionable addAll: properties.
×
144
        ^ aDictionable
×
145
]
×
146

147
{ #category : 'testing' }
148
CTEnvironment >> hasLocalProperty: aKey [
1✔
149
        "Test if the property ==aKey== is defined within the receiver, not checking potential parent."
1✔
150

1✔
151
        ^ properties includesKey: aKey asSymbol
1✔
152
]
1✔
153

154
{ #category : 'testing' }
155
CTEnvironment >> hasParent [
1✔
156
        ^ parent isNotNil
1✔
157
]
1✔
158

159
{ #category : 'testing' }
160
CTEnvironment >> hasProperty: aKey [
1✔
161
        "Answer true iff I (or one of my ancestors) contain a property named ==aKey==."
1✔
162

1✔
163
        ^ properties
1✔
164
                at: aKey asSymbol
1✔
165
                ifPresent: [ :value | true ]
1✔
166
                ifAbsent: [ self hasParent
1✔
167
                                ifTrue: [ parent hasProperty: aKey ]
1✔
168
                                ifFalse: [ false ] ]
1✔
169
]
1✔
170

171
{ #category : 'testing-dictionary' }
172
CTEnvironment >> includesKey: aKey [
1✔
173
        "Answer true iff I (or one of my ancestors) contain a property named ==aKey==."
1✔
174

1✔
175
        ^ properties
1✔
176
                at: aKey asSymbol
1✔
177
                ifPresent: [ :value | true ]
1✔
178
                ifAbsent: [ self hasParent
1✔
179
                                ifTrue: [ parent includesKey: aKey ]
1✔
180
                                ifFalse: [ false ] ]
1✔
181
]
1✔
182

183
{ #category : 'testing-dictionary' }
184
CTEnvironment >> includesLocalKey: aKey [
1✔
185
        "Test if the property ==aKey== is defined within the receiver, not checking potential parent."
1✔
186

1✔
187
        ^ properties includesKey: aKey asSymbol
1✔
188
]
1✔
189

190
{ #category : 'initialization' }
191
CTEnvironment >> initialize [
1✔
192
        super initialize.
1✔
193
        properties := OrderedDictionary new.
1✔
194
]
1✔
195

196
{ #category : 'accessing' }
197
CTEnvironment >> keys [
1✔
198
        "Answer a Set containing the receiver's keys."
1✔
199
        | s |
1✔
200
        s := Set new. 
1✔
201
        "we use a set and not an array because we should go over potential parent keys and the intersection between parent and children keys may not be empty. So we should not report duplicates."
1✔
202
        self keysDo: [ :k | s add: k ].
1✔
203
        ^ s 
1✔
204
]
1✔
205

206
{ #category : 'iteration' }
207
CTEnvironment >> keysAndValuesDo: aBlock [ 
1✔
208
        "Evaluate aBlock for each of the receiver's keys and values, starting from the receiver and going up in its parent chain if any."
1✔
209

1✔
210
        properties keysAndValuesDo: aBlock.
1✔
211
        self hasParent ifTrue: [ parent keysAndValuesDo: aBlock ]
1✔
212
        
1✔
213
]
1✔
214

215
{ #category : 'iteration' }
216
CTEnvironment >> keysDo: aBlock [ 
1✔
217
        "Evaluate aBlock for each of the receiver's keys, starting from the receiver and going up in its parent chain if any."
1✔
218

1✔
219
        properties keysDo: aBlock.
1✔
220
        self hasParent ifTrue: [ parent keysDo: aBlock ]
1✔
221
        
1✔
222
]
1✔
223

224
{ #category : 'accessing' }
225
CTEnvironment >> parent [
1✔
226
        "A parent is a Configuration I extends"
1✔
227
        
1✔
228
        ^ parent
1✔
229
]
1✔
230

231
{ #category : 'accessing' }
232
CTEnvironment >> parent: anEnvironment [
1✔
233
        parent := anEnvironment
1✔
234
]
1✔
235

236
{ #category : 'copying' }
237
CTEnvironment >> postCopy [
1✔
238
        "Make sure that properties are properly copied, but not the parent."
1✔
239
        super postCopy.
1✔
240
        properties := properties copy.
1✔
241

1✔
242
]
1✔
243

244
{ #category : 'private' }
245
CTEnvironment >> properties [
1✔
246

1✔
247
        ^ properties
1✔
248
]
1✔
249

250
{ #category : 'accessing - properties' }
251
CTEnvironment >> propertyAt: aKey [
1✔
252
        "Answer the value of the property ==aKey==, potentially looking in the parent, raises an error if the property doesn't exist."
1✔
253

1✔
254
        ^ self at: aKey
1✔
255
]
1✔
256

257
{ #category : 'accessing - properties' }
258
CTEnvironment >> propertyAt: aKey ifAbsent: aBlock [
1✔
259
        "Answer the value of the property ==aKey==, potentially looking in parents, or the result of ==aBlock== if the property doesn't exist."
1✔
260

1✔
261
        ^ self at: aKey ifAbsent: aBlock
1✔
262
]
1✔
263

264
{ #category : 'accessing - properties' }
265
CTEnvironment >> propertyAt: aKey ifAbsentPut: aBlock [
1✔
266
        "Answer the value of the property ==aKey==, potentially defined in parents, or if the property doesn't exist adds and answers the result of evaluating ==aBlock==."
1✔
267

1✔
268
        "We look up first to know and once we know if the property is not defined somewhere, then we set it. We do it like that to avoid to execute the put block on the parent because the put should be executed on the child."
1✔
269
        ^ self at: aKey ifAbsentPut: aBlock
1✔
270
]
1✔
271

272
{ #category : 'accessing - properties' }
273
CTEnvironment >> propertyAt: aKey ifPresent: presentBlock ifAbsent: absentBlock [
1✔
274
        "Answer the result of ==presentBlock== if I have the property ==aKey==, in the receiver or its parents or the result of ==absentBlock==."
1✔
275

1✔
276
        ^ self at: aKey ifPresent: presentBlock ifAbsent: absentBlock
1✔
277
]
1✔
278

279
{ #category : 'accessing - properties' }
280
CTEnvironment >> propertyAt: aKey put: aValue [
1✔
281
        "Adds or replaces the property ==aKey== with ==aValue== in the receiver."
1✔
282

1✔
283
        ^ self at: aKey put: aValue
1✔
284
]
1✔
285

286
{ #category : 'iteration' }
287
CTEnvironment >> valuesDo: aBlock [
1✔
288
        "Evaluate aBlock for each of the receiver's values, starting from the receiver and going up in its parent chain if any."
1✔
289
        
1✔
290
        properties valuesDo: aBlock.
1✔
291
        self hasParent ifTrue: [ parent valuesDo: aBlock ]
1✔
292
        
1✔
293
]
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc