1 ## our_shell: ysh
2 ## oils_failures_allowed: 1
3
4 #### New Obj API
5 shopt --set ysh:upgrade
6
7 try {
8 var obj = Obj.new({x: 4}, null)
9 pp test_ (obj)
10 }
11 echo $[_error.code]
12
13 try {
14 pp test_ (first(obj))
15 }
16 echo $[_error.code]
17
18 try {
19 pp test_ (rest(obj))
20 }
21 echo $[_error.code]
22
23 # Second arg is optional
24 var obj2 = Obj.new({y: 5})
25 pp test_ (obj2)
26
27 ## STDOUT:
28 (Obj) ("x":4)
29 0
30 (Dict) {"x":4}
31 0
32 (Null) null
33 0
34 (Obj) ("y":5)
35 ## END
36
37 #### Object() creates prototype chain
38
39 func Rect_area(this) {
40 return (this.x * this.y)
41 }
42
43 var Rect = Object(null, {area: Rect_area})
44
45 var rect1 = Object(Rect, {x: 3, y: 4})
46 var rect2 = Object(Rect, {x: 10, y: 20})
47
48 # This could change to show the object?
49 # pp test_ (rect)
50
51 # TODO: This should be a bound function
52 #pp asdl_ (rect)
53 #pp (rect.area)
54 #pp (rect->area)
55
56 var area1 = rect1.area()
57 var area2 = rect2.area()
58
59 pp test_ ([rect1.x, rect1.y])
60 echo "area1 = $area1"
61
62 pp test_ ([rect2.x, rect2.y])
63 echo "area2 = $area2"
64
65 #pp test_ (rect1.nonexistent)
66
67 ## STDOUT:
68 (List) [3,4]
69 area1 = 12
70 (List) [10,20]
71 area2 = 200
72 ## END
73
74 #### prototype()
75
76 func Rect_area(this) {
77 return (this.x * this.y)
78 }
79
80 var Rect = Object(null, {area: Rect_area})
81
82 var obj = Object(Rect, {x: 3, y: 4})
83
84 pp test_ (prototype(Rect))
85 pp test_ (prototype(obj))
86
87 ## STDOUT:
88 (Null) null
89 (Obj) ("area":<Func>)
90 ## END
91
92 #### propView()
93
94 var obj = Object(null, {x: 3, y: 4})
95 var props = propView(obj)
96
97 pp test_ (props)
98
99 # object can be mutated
100 setvar props.x = 99
101
102 pp test_ (props)
103
104 var e = propView(null) # error
105
106 ## status: 3
107 ## STDOUT:
108 (Dict) {"x":3,"y":4}
109 (Dict) {"x":99,"y":4}
110 ## END
111
112 #### Mutating method lookup with ->
113
114 func inc(self, n) {
115 setvar self.i += n
116 }
117 var Counter_methods = Object(null, {'M/inc': inc})
118
119 var c = Object(Counter_methods, {i: 5})
120
121 echo $[c.i]
122 call c->inc(3)
123 echo $[c.i]
124
125 ## STDOUT:
126 5
127 8
128 ## END
129
130 #### Mutating method must be up the prototype chain, not on the object
131
132 func inc(self, n) {
133 setvar self.i += n
134 }
135 var c = Object(null, {'M/inc': inc, i: 0})
136
137 call c->inc(3)
138
139 ## status: 3
140 ## STDOUT:
141 ## END
142
143
144 #### Copy to Dict with dict(), and mutate
145
146 var rect = Object(null, {x: 3, y: 4})
147 var d = dict(rect)
148
149 pp test_ (rect)
150 pp test_ (d)
151
152 setvar rect.x = 99
153 setvar d.x = 100
154
155 pp test_ (rect)
156 pp test_ (d)
157 ## STDOUT:
158 (Obj) ("x":3,"y":4)
159 (Dict) {"x":3,"y":4}
160 (Obj) ("x":99,"y":4)
161 (Dict) {"x":100,"y":4}
162 ## END
163
164 #### setvar obj.attr = and += and ...
165
166 var rect = Object(null, {x: 3, y: 4})
167 pp test_ (rect)
168
169 setvar rect.y = 99
170 pp test_ (rect)
171
172 setvar rect.y += 3
173 pp test_ (rect)
174
175 setvar rect.x *= 5
176 pp test_ (rect)
177
178 ## STDOUT:
179 (Obj) ("x":3,"y":4)
180 (Obj) ("x":3,"y":99)
181 (Obj) ("x":3,"y":102)
182 (Obj) ("x":15,"y":102)
183 ## END
184
185 #### obj['attr'] not allowed (for now)
186
187 var rect = Object(null, {x: 3, y: 4})
188
189 pp test_ ([rect['x'], rect['y']])
190
191 ## status: 3
192 ## STDOUT:
193 ## END
194
195 #### setvar obj['attr'] = 3 ?
196
197 var rect = Object(null, {x: 3, y: 4})
198
199 setvar rect['x'] = 99
200
201 pp test_ (rect)
202
203 # The reason this is allowed is because setvar does EvalLhsExpr(), which
204 # handles:
205 #
206 # - y_lhs.SubScript -> y_lvalue.Container
207 # - y_lhs.Attribute -> y_lvalue.Container
208 #
209 # So that means obj['x'] is allowed too?
210 # We could possible add y_lvalue.Container(is_subscript)
211
212 ## status: 3
213 ## STDOUT:
214 ## END
215
216 #### can't encode objects as JSON
217
218 var Rect = Object(null, {})
219
220 json write (Rect)
221 echo 'nope'
222
223 ## status: 1
224 ## STDOUT:
225 ## END
226
227 #### Can all builtin methods with s.upper()
228
229 var s = 'foo'
230 var x = s.upper()
231 var y = "--$[x.lower()]"
232
233 pp test_ (x)
234 pp test_ (y)
235
236 ## STDOUT:
237 (Str) "FOO"
238 (Str) "--foo"
239 ## END
240
241 #### invokable Obj must be have prototype containing __invoke__ of value.Proc - type -t
242
243 proc p (w; self) {
244 pp test_ ([w, self])
245 }
246 p a ({x: 5, y: 6})
247 echo
248
249 var methods = Object(null, {__invoke__: p})
250
251 var o1 = Object(methods, {})
252 type -t o1
253 echo
254
255 # errors
256
257 var o2 = Object(null, {})
258 if ! type -t o2 {
259 echo 'no prototype'
260 }
261
262 var o3 = Object(Object(null, {}), {})
263 if ! type -t o3 {
264 echo 'no __invoke__ method in prototype'
265 }
266
267 var bad_methods = Object(null, {__invoke__: 42})
268 var o4 = Object(bad_methods, {})
269 if ! type -t o4 {
270 echo '__invoke__ of wrong type'
271 }
272
273 ## STDOUT:
274 (List) ["a",{"x":5,"y":6}]
275
276 invokable
277
278 no prototype
279 no __invoke__ method in prototype
280 __invoke__ of wrong type
281 ## END
282
283 #### Object with longer prototype chain
284
285 # prototypal inheritance pattern
286 var superClassMethods = Object(null, {foo: 'zz'})
287 var methods = Object(superClassMethods, {foo: 42, bar: [1,2]})
288 var instance = Object(methods, {foo: 1, bar: 2, x: 3})
289
290 pp test_ (instance)
291 pp value (instance)
292
293 ## STDOUT:
294 (Obj) ("foo":1,"bar":2,"x":3) --> ("foo":42,"bar":[1,2]) --> ("foo":"zz")
295 (Obj) (foo: 1, bar: 2, x: 3) --> (foo: 42, bar: [1, 2]) --> (foo: 'zz')
296 ## END