mon 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,757 @@
1
+ require_relative '../lib/mon'
2
+
3
+ module Mon
4
+
5
+ module Monad
6
+
7
+ describe "List" do
8
+
9
+ describe "[]" do
10
+ it "takes a sequence and turns it into a list monad" do
11
+ List[1, 2, 3].to_a.should eql [1, 2, 3]
12
+ List[].to_a.should eql []
13
+ end
14
+
15
+ it "should preserve arrays" do
16
+ List[[1, 2, 3]].to_a.should eql [[1, 2, 3]]
17
+ end
18
+
19
+ it "should preserve lists" do
20
+ List[List[1, 2, 3]].to_a.should eql [List[1, 2, 3]]
21
+ end
22
+ end
23
+
24
+ describe "==" do
25
+ it "should compare two List monads" do
26
+ List[1, 2, 3].should == List[1, 2, 3]
27
+ List["one", "two"].should == List["one", "two"]
28
+ end
29
+
30
+ it "should compare contents if not given a List monad" do
31
+ List[1, 2, 3].should == [1, 2, 3]
32
+ List["one", "two"].should == ["one", "two"]
33
+ end
34
+
35
+ it "shouldn't match non-matching List monads" do
36
+ List[1, 2, 3].should_not == List[3, 2, 1]
37
+ List["one", "two"].should_not == List["one"]
38
+ end
39
+
40
+ it "shouldn't match contents if not given a List monad" do
41
+ List[1, 2, 3].should_not == [3, 2, 1]
42
+ List["one", "two"].should_not == ["two", "one"]
43
+ end
44
+ end
45
+
46
+ describe "eql" do
47
+ it "should compare two List monads" do
48
+ List[1, 2, 3].should eql List[1, 2, 3]
49
+ List["one", "two"].should eql List["one", "two"]
50
+ end
51
+
52
+ it "should compare contents if not given a List monad" do
53
+ List[1, 2, 3].should eql [1, 2, 3]
54
+ List["one", "two"].should eql ["one", "two"]
55
+ end
56
+
57
+ it "shouldn't match non-matching List monads" do
58
+ List[1, 2, 3].should_not eql List[3, 2, 1]
59
+ List["one", "two"].should_not eql List["one"]
60
+ end
61
+
62
+ it "shouldn't match contents if not given a List monad" do
63
+ List[1, 2, 3].should_not eql [3, 2, 1]
64
+ List["one", "two"].should_not eql ["two", "one"]
65
+ end
66
+ end
67
+
68
+ describe "new" do
69
+ it "should be protected" do
70
+ expect { List.new([1, 2, 3]) }.to raise_error(NoMethodError)
71
+ end
72
+ end
73
+
74
+ describe "get" do
75
+ it "should be protected" do
76
+ expect { List[1, 2, 3].get }.to raise_error(NoMethodError)
77
+ end
78
+ end
79
+
80
+ describe "_canBind?" do
81
+ it "should be protected" do
82
+ expect { List[1]._canBind? :test }.to raise_error(NoMethodError)
83
+ end
84
+ end
85
+
86
+ describe "to_s" do
87
+ it "should properly handle 0, 1, 3, 4+ items" do
88
+ List[].to_s.should eql "List[]"
89
+ List[1].to_s.should eql "List[1]"
90
+ List[1, 2, 3].to_s.should eql "List[1, 2, 3]"
91
+ List[1, 2, 3, 4].to_s.should eql "List[1, 2, 3...]"
92
+ end
93
+ end
94
+
95
+ describe "list functionality" do
96
+ it "should pass methods through to the contained object" do
97
+ (List[1, 2, 3] * 6).to_a.should eql [6, 12, 18]
98
+ (List["Test", "One", "Two"].downcase).to_a.should eql ["test", "one", "two"]
99
+ end
100
+
101
+ it "should treat missing_methods the same as bind" do
102
+ (List[1, 2, 3] * 5).to_a.should eql (List[1, 2, 3].bind { |i| i * 5 }.to_a)
103
+ end
104
+
105
+ it "should flatten once" do
106
+ List[1, 2, 3].bind { |i| [i, i * 2] }.to_a.should eql [1, 2, 2, 4, 3, 6]
107
+ end
108
+
109
+ it "should allow for internal transformation" do
110
+ List[1].bind { |i| Try[i] }.to_a.should eql [Success[1]]
111
+ end
112
+
113
+ it "should allow chaining methods" do
114
+ (((List[1, 2, 3] + 2) * 3) - 5).to_a.should eql [4, 7, 10]
115
+ List[1, 6, 9].to_f.div(2).floor.round.should eql [0, 3, 4]
116
+ end
117
+
118
+ it "should work with empty lists" do
119
+ (List[] * 3 + 5 - 2).should eql List[]
120
+ (List[].upcase.downcase.reverse).should eql List[]
121
+ end
122
+ end
123
+
124
+ describe "monad laws" do
125
+ it "should obey left identity (but it won't)" do
126
+ (List[1] * 3).should eql [(1 * 3)]
127
+ end
128
+
129
+ it "should obey right identity" do
130
+ List[1, 2].bind { |i| i }.should eql List[1, 2]
131
+ List[1, 2].bind { |i| List[i] }.should eql List[1, 2]
132
+ end
133
+
134
+ it "should obey associativity" do
135
+ ((List[3] * 5) * 9).should eql (List[3] * (5 * 9))
136
+ ((3 * List[5]) * 9).should eql (3 * (List[5] * 9))
137
+ (List[3] * 5).should eql (3 * List[5])
138
+ ((3 * List[]) * 9).should eql (3 * (List[] * 9))
139
+ ((List[] * 5) * 9).should eql (List[] * (5 * 9))
140
+ end
141
+ end
142
+ end
143
+
144
+ describe Maybe do
145
+ describe "[]" do
146
+ it "should take an arbitrary object" do
147
+ Maybe[1].or(0).should == 1
148
+ Maybe["test"].or("").should == "test"
149
+ Maybe[[1, 2, 3]].or([]).should == [1, 2, 3]
150
+ Maybe[List[1, 2]].or(List[]).should == List[1, 2]
151
+ end
152
+
153
+ it "should unwrap to one level" do
154
+ Maybe[Maybe[1]].or(Maybe[false]).should == 1
155
+ Maybe[Maybe[Maybe[1]]].or(false).should == Maybe[1]
156
+ end
157
+
158
+ it "should return Some/None appropriately" do
159
+ Maybe[true].should == Some[true]
160
+ Maybe[false].should == None[]
161
+ Maybe[nil].should == None[]
162
+ Maybe[1].should == Some[1]
163
+ Maybe["test"].should == Some["test"]
164
+ end
165
+ end
166
+
167
+ describe "==" do
168
+ it "should compare internals" do
169
+ Maybe[1].should == Maybe[1]
170
+ Maybe["test"].should == Maybe["test"]
171
+ Maybe[[1, 2, 3]].should == Maybe[[1, 2, 3]]
172
+ end
173
+
174
+ it "should not match when objects don't" do
175
+ Maybe[1].should_not == Maybe[2]
176
+ Maybe["test"].should_not == Maybe["other"]
177
+ Maybe[[1, 2, 3]].should_not == Maybe[[3, 2, 1]]
178
+ end
179
+
180
+ it "should compare provided non-options to internals" do
181
+ Maybe[1].should == 1
182
+ Maybe["test"].should == "test"
183
+ Maybe[[1, 2, 3]].should == [1, 2, 3]
184
+ Maybe[1].should_not == 2
185
+ Maybe["test"].should_not == "other"
186
+ Maybe[[1, 2, 3]].should_not == [3, 2, 1]
187
+ end
188
+ end
189
+
190
+ describe "eql" do
191
+ it "should compare internals" do
192
+ Maybe[1].should eql Maybe[1]
193
+ Maybe["test"].should eql Maybe["test"]
194
+ Maybe[[1, 2, 3]].should eql Maybe[[1, 2, 3]]
195
+ end
196
+
197
+ it "should not match when objects don't" do
198
+ Maybe[1].should_not eql Maybe[2]
199
+ Maybe["test"].should_not eql Maybe["other"]
200
+ Maybe[[1, 2, 3]].should_not eql Maybe[[3, 2, 1]]
201
+ end
202
+
203
+ it "should compare provided non-options to internals" do
204
+ Maybe[1].should eql 1
205
+ Maybe["test"].should eql "test"
206
+ Maybe[[1, 2, 3]].should eql [1, 2, 3]
207
+ Maybe[1].should_not eql 2
208
+ Maybe["test"].should_not eql "other"
209
+ Maybe[[1, 2, 3]].should_not eql [3, 2, 1]
210
+ end
211
+ end
212
+
213
+ describe "bind" do
214
+ it "should apply function to the internals" do
215
+ Maybe[1].bind { |i| i * 3 }.should == Maybe[3]
216
+ Maybe["test"].bind { |s| s.upcase }.should == Maybe["TEST"]
217
+ end
218
+
219
+ it "should modify contents of monad" do
220
+ Maybe[1].bind { |i| List[1] }.or(false).should == List[1]
221
+ Maybe["test"].bind { |i| [i] }.or([]).should == ["test"]
222
+ end
223
+ end
224
+
225
+ describe "maybe functionality" do
226
+ it "should pass methods through to the contained object" do
227
+ (Maybe[1] * 3).should == Maybe[3]
228
+ (Maybe["test"].upcase).should == Maybe["TEST"]
229
+ ((Maybe[5] * 10) - 12).should == Maybe[38]
230
+ Maybe["test"].upcase.reverse.downcase.should == Maybe["tset"]
231
+ end
232
+
233
+ it "should treat missing_methods the same as bind" do
234
+ (Maybe[5] * 5).should == Maybe[5].bind { |i| i * 5 }
235
+ end
236
+
237
+ it "should flatten once" do
238
+ Maybe[5].bind { |i| Some[i * 100] }.should == Maybe[500]
239
+ end
240
+
241
+ it "should allow for chained and multibound failures" do
242
+ (Maybe[nil] * 5 + 2 - 3).should == None[]
243
+ end
244
+ end
245
+
246
+ describe "monad laws" do
247
+ it "should obey left identity (but it won't)" do
248
+ (Maybe[1] * 3).should == (1 * 3)
249
+ end
250
+
251
+ it "should obey right identity" do
252
+ Maybe[1].bind { |i| i }.should == Maybe[1]
253
+ Maybe[5].bind { |i| Maybe[i] }.should == Maybe[5]
254
+ end
255
+
256
+ it "should obey associativity" do
257
+ ((Maybe[5] * Maybe[3]) * Maybe[5]).should == (Maybe[5] * (Maybe[3] * Maybe[5]))
258
+ ((Maybe[5] * Maybe[3]) * None[]).should == (Maybe[5] * (Maybe[3] * None[]))
259
+ ((Maybe[5] * 3) * Maybe[5]).should == (5 * (Maybe[3] * Maybe[5]))
260
+ end
261
+ end
262
+ end
263
+
264
+ describe "Try" do
265
+ describe "[]" do
266
+ it "should take an arbitrary object" do
267
+ Try[1].or(0).should == 1
268
+ Try["test"].or("").should == "test"
269
+ Try[[1, 2, 3]].or([]).should == [1, 2, 3]
270
+ Try[List[1, 2]].or(List[]).should == List[1, 2]
271
+ end
272
+
273
+ it "should NOT unwrap" do
274
+ Try[Try[1]].or(Try[false]).should == Try[1].bind { |i| Try[i] }
275
+ end
276
+
277
+ it "should return Success/Failure appropriately" do
278
+ Try[true].should == Success[true]
279
+ Try[false].should == Failure[false]
280
+ Try[nil].should == Failure[false]
281
+ Try[1].should == Success[1]
282
+ Try["test"].should == Try["test"]
283
+ end
284
+ end
285
+
286
+ describe "==" do
287
+ it "should compare internals" do
288
+ Try[1].should == Try[1]
289
+ Try["test"].should == Try["test"]
290
+ Try[[1, 2, 3]].should == Try[[1, 2, 3]]
291
+ end
292
+
293
+ it "should not match when objects don't" do
294
+ Try[1].should_not == Try[2]
295
+ Try["test"].should_not == Try["other"]
296
+ Try[[1, 2, 3]].should_not == Try[[3, 2, 1]]
297
+ end
298
+
299
+ it "should compare provided non-options to internals" do
300
+ Try[1].should == 1
301
+ Try["test"].should == "test"
302
+ Try[[1, 2, 3]].should == [1, 2, 3]
303
+ Try[1].should_not == 2
304
+ Try["test"].should_not == "other"
305
+ Try[[1, 2, 3]].should_not == [3, 2, 1]
306
+ end
307
+ end
308
+
309
+ describe "eql" do
310
+ it "should compare internals" do
311
+ Try[1].should eql Try[1]
312
+ Try["test"].should eql Try["test"]
313
+ Try[[1, 2, 3]].should eql Try[[1, 2, 3]]
314
+ end
315
+
316
+ it "should not match when objects don't" do
317
+ Try[1].should_not eql Try[2]
318
+ Try["test"].should_not eql Try["other"]
319
+ Try[[1, 2, 3]].should_not eql Try[[3, 2, 1]]
320
+ end
321
+
322
+ it "should compare provided non-options to internals" do
323
+ Try[1].should eql 1
324
+ Try["test"].should eql "test"
325
+ Try[[1, 2, 3]].should eql [1, 2, 3]
326
+ Try[1].should_not eql 2
327
+ Try["test"].should_not eql "other"
328
+ Try[[1, 2, 3]].should_not eql [3, 2, 1]
329
+ end
330
+ end
331
+
332
+ describe "bind" do
333
+ it "should apply function to the internals" do
334
+ Try[1].bind { |i| i * 3 }.should == Try[3]
335
+ Try["test"].bind { |s| s.upcase }.should == Try["TEST"]
336
+ end
337
+
338
+ it "should modify contents of monad" do
339
+ Try[1].bind { |i| List[1] }.or(false).should == List[1]
340
+ Try["test"].bind { |i| [i] }.or([]).should == ["test"]
341
+ end
342
+
343
+ it "should catch exceptions" do
344
+ expect(Try[1].bind { |i| i / 0 }).to be_a Failure
345
+ expect(Try[1].bind { |i| i * 5 }).to be_a Success
346
+ end
347
+
348
+ it "should allow chains even for failures" do
349
+ expect(Try[1].bind { |i| i / 0 } * 7 + 3).to be_a Failure
350
+ expect(Try[5].bind { |i| i * 5 } + 6 - 3).to be_a Success
351
+ expect(Try[10].bind { |i| i / 0 }.bind { |i| i + 3}).to be_a Failure
352
+ expect(Try[10].bind { |i| i + 0 }.bind { |i| i + 3}).to be_a Success
353
+ end
354
+
355
+ it "should preserve exceptions" do
356
+ expect{(Try[5].bind { |i| i / 0 } * 7 + 3).orFail}.to raise_error(ZeroDivisionError)
357
+ (Try[5].bind { |i| i / 1 } * 7 + 3).orFail.should == 38
358
+ end
359
+ end
360
+
361
+ describe "try functionality" do
362
+ it "should pass methods through to the contained object" do
363
+ (Try[1] * 3).should == Try[3]
364
+ (Try["test"].upcase).should == Try["TEST"]
365
+ ((Try[5] * 10) - 12).should == Try[38]
366
+ Try["test"].upcase.reverse.downcase.should == Try["tset"]
367
+ end
368
+
369
+ it "should treat missing_methods the same as bind" do
370
+ (Try[5] * 5).should == Try[5].bind { |i| i * 5 }
371
+ end
372
+
373
+ it "should flatten once" do
374
+ Try[5].bind { |i| Some[i * 100] }.should == Try[500]
375
+ end
376
+
377
+ it "should allow for chained and multibound failures" do
378
+ (Try[nil] * 5 + 2 - 3).should == Failure[false]
379
+ end
380
+
381
+ it "should catch exceptions" do
382
+ expect(Try.to(5) { |i| i / 0 }).to be_a Failure
383
+ expect(Try.to(5) { |i| i / 5 }).to be_a Success
384
+ Try.to(5) { |i| i * 5 }.should == Success[25]
385
+ end
386
+ end
387
+
388
+ describe "monad laws" do
389
+ it "should obey left identity (but it won't)" do
390
+ (Try[1] * 3).should == (1 * 3)
391
+ end
392
+
393
+ it "should obey right identity" do
394
+ Try[1].bind { |i| i }.should == Try[1]
395
+ Try[5].bind { |i| Try[i] }.should == Try[5]
396
+ end
397
+
398
+ it "should obey associativity" do
399
+ ((Try[5] * Try[3]) * Try[5]).should == (Try[5] * (Try[3] * Try[5]))
400
+ ((Try[5] * Try[3]) * Failure["Nope!"]).should == (Try[5] * (Try[3] * Failure["Nope!"]))
401
+ ((5 * Try[3]) * Try[5]).should == (Try[5] * (3 * Try[5]))
402
+ ((5 * 3) * Try[5]).should == (5 * (3 * Try[5]))
403
+ end
404
+ end
405
+ end
406
+
407
+ describe "Lazy" do
408
+ describe "[]" do
409
+ it "should wrap an object" do
410
+ Lazy.eventually(1) { |i| 1 }.should == 1
411
+ Lazy.eventually([1, 2, 3]) { |l| l } == [1, 2, 3]
412
+ end
413
+
414
+ it "should return Pending/Final appropriately" do
415
+ expect(Lazy[1]).to be_a Final
416
+ expect(Lazy["testing"]).to be_a Final
417
+ expect(Lazy.eventually { "testing" }).to be_a Pending
418
+ expect(Lazy.eventually { [1, 2] }).to be_a Pending
419
+ end
420
+ end
421
+
422
+ describe "==" do
423
+ it "should compare internals" do
424
+ Lazy[1].should == Lazy[1]
425
+ Lazy[[1, 2, 3]].should == Lazy[[1, 2, 3]]
426
+ end
427
+
428
+ it "should compare pending with final" do
429
+ Lazy.eventually { 1 }.should == Lazy[1]
430
+ Lazy.eventually { [1, 2, 3] }.should == Lazy[[1, 2, 3]]
431
+ end
432
+
433
+ it "should not match when objects don't" do
434
+ Lazy[1].should_not == Lazy[2]
435
+ Lazy.eventually { 1 }.should_not == Lazy.eventually { 2 }
436
+ Lazy.eventually { 2 }.should_not == Lazy[1]
437
+ end
438
+
439
+ it "should compare provided non-Lazy to internals" do
440
+ Lazy[1].should == 1
441
+ Lazy["test"].should == "test"
442
+ Lazy[[1, 2, 3]].should == [1, 2, 3]
443
+ Lazy[].should_not == 1
444
+ Lazy[1].should_not == 2
445
+ Lazy.eventually { 1 }.should == 1
446
+ Lazy.eventually { "test" }.should == "test"
447
+ Lazy.eventually { [1, 2, 3] }.should == [1, 2, 3]
448
+ Lazy.eventually { }.should_not == 1
449
+ Lazy.eventually { 1 }.should_not == 2
450
+ end
451
+ end
452
+
453
+ describe "bind" do
454
+ it "should create a pending calculation" do
455
+ expect(Lazy[5].bind { |i| i * 5 }).to be_a Pending
456
+ expect(Lazy[10].bind { |i| i * 5 }.bind { |i| i * 7 }).to be_a Pending
457
+ end
458
+
459
+ it "should finalize correctly" do
460
+ Lazy[5].bind { |i| i * 5 }.should == Lazy[25]
461
+ Lazy[1].bind { |i| i * 7 }.bind { |i| i * 2 }.should == Lazy[14]
462
+ Lazy["test"].bind { |s| s.upcase }.bind { |s| s.reverse }.should == Lazy["TSET"]
463
+ end
464
+
465
+ it "should be able to modify monad contents" do
466
+ Lazy[5].bind { |i| Try[i] }.should == Lazy[Try[5]]
467
+ Lazy["test"].bind { |i| [i] }.should == Lazy[["test"]]
468
+ end
469
+
470
+ it "should flatten by one level" do
471
+ Lazy[5].bind { |i| Lazy[i] }.should == Lazy[5]
472
+ Lazy.eventually { [1, 2, 3] }.bind { |i| Lazy[i] }.should == Lazy[[1, 2, 3]]
473
+ end
474
+
475
+ end
476
+
477
+ describe "functionality" do
478
+ it "should pass methods through to the contained object" do
479
+ (Lazy[1] * 3).should == Lazy[3]
480
+ (Lazy["test"].upcase.reverse).should == Lazy["TSET"]
481
+ (Lazy["this is a test"][0,4]).should == Lazy["this"]
482
+ end
483
+
484
+ it "shouldn't execute until necessary" do
485
+ expect(Lazy[1] * 3).to be_a Pending
486
+ expect(Lazy["test"].upcase.reverse).to be_a Pending
487
+ expect(Lazy["this is a test"][0,4]).to be_a Pending
488
+ end
489
+
490
+ it "should treat missing_methods the same as bind" do
491
+ (Lazy[5] * 5).should == Lazy[5].bind { |i| i * 5 }
492
+ end
493
+ end
494
+
495
+ describe "monad laws" do
496
+ it "should obey left identity (but it won't)" do
497
+ (Lazy[1] * 3).should == (1 * 3)
498
+ end
499
+
500
+ it "should obey right identity" do
501
+ Lazy[1].bind { |i| i }.should == Lazy[1]
502
+ Lazy[5].bind { |i| Lazy[i] }.should == Lazy[5]
503
+ end
504
+
505
+ it "should obey associativity" do
506
+ ((Lazy[5] * Lazy[3]) * Lazy[5]).should == (Lazy[5] * (Lazy[3] * Lazy[5]))
507
+ ((Lazy[3] * 5) * 9).should eql (Lazy[3] * (5 * 9))
508
+ ((3 * Lazy[5]) * 9).should eql (3 * (Lazy[5] * 9))
509
+ (Lazy[3] * 5).should eql (3 * Lazy[5])
510
+ ((3 * Lazy[7]) * 9).should eql (3 * (Lazy[7] * 9))
511
+ ((Lazy[7] * 5) * 9).should eql (Lazy[7] * (5 * 9))
512
+ end
513
+ end
514
+ end
515
+
516
+ describe "Future" do
517
+ describe "[]" do
518
+ it "should wrap an object" do
519
+ Future[1].should == 1
520
+ Future.eventually(1) { |i| 1 }.should == 1
521
+ Future[[1, 2, 3]].should == [1, 2, 3]
522
+ Future.eventually([1, 2, 3]) { |l| l } == [1, 2, 3]
523
+ end
524
+
525
+ it "should return Complete/Promise appropriately" do
526
+ expect(Future[1]).to be_a FutureComplete
527
+ expect(Future["testing"]).to be_a FutureComplete
528
+ expect(Future.eventually { "testing" }).to be_a FuturePromise
529
+ expect(Future.eventually { [1, 2] }).to be_a FuturePromise
530
+ end
531
+ end
532
+
533
+ describe "==" do
534
+ it "should compare internals" do
535
+ Future[1].should == Future[1]
536
+ Future[[1, 2, 3]].should == Future[[1, 2, 3]]
537
+ end
538
+
539
+ it "should compare pending with final" do
540
+ Future.eventually { 1 }.should == Future[1]
541
+ Future.eventually { [1, 2, 3] }.should == Future[[1, 2, 3]]
542
+ end
543
+
544
+ it "should not match when objects don't" do
545
+ Future[1].should_not == Future[2]
546
+ Future.eventually { 1 }.should_not == Future.eventually { 2 }
547
+ Future.eventually { 2 }.should_not == Future[1]
548
+ end
549
+
550
+ it "should compare provided non-Future to internals" do
551
+ Future[1].should == 1
552
+ Future["test"].should == "test"
553
+ Future[[1, 2, 3]].should == [1, 2, 3]
554
+ Future[1].should_not == 2
555
+ Future.eventually { 1 }.should == 1
556
+ Future.eventually { "test" }.should == "test"
557
+ Future.eventually { [1, 2, 3] }.should == [1, 2, 3]
558
+ Future.eventually { }.should_not == 1
559
+ Future.eventually { 1 }.should_not == 2
560
+ end
561
+ end
562
+
563
+ describe "bind" do
564
+ it "should create a pending calculation" do
565
+ expect(Future[5].bind { |i| i * 5 }).to be_a FuturePromise
566
+ expect(Future[10].bind { |i| i * 5 }.bind { |i| i * 7 }).to be_a FuturePromise
567
+ end
568
+
569
+ it "should finalize correctly" do
570
+ Future[5].bind { |i| i * 5 }.should == Future[25]
571
+ Future[1].bind { |i| i * 7 }.bind { |i| i * 2 }.should == Future[14]
572
+ Future["test"].bind { |s| s.upcase }.bind { |s| s.reverse }.should == Future["TSET"]
573
+ end
574
+
575
+ it "should be able to modify monad contents" do
576
+ Future[5].bind { |i| Try[i] }.should == Future[Try[5]]
577
+ Future["test"].bind { |i| [i] }.should == Future[["test"]]
578
+ end
579
+
580
+ it "should flatten by one level" do
581
+ Future[5].bind { |i| Future[i] }.should == Future[5]
582
+ Future.eventually { [1, 2, 3] }.bind { |i| Future[i] }.should == Future[[1, 2, 3]]
583
+ end
584
+
585
+ end
586
+
587
+ describe "functionality" do
588
+ it "should pass methods through to the contained object" do
589
+ (Future[1] * 3).should == Future[3]
590
+ (Future["test"].upcase.reverse).should == Future["TSET"]
591
+ (Future["this is a test"][0,4]).should == Future["this"]
592
+ end
593
+
594
+ it "should treat missing_methods the same as bind" do
595
+ (Future[5] * 5).should == Future[5].bind { |i| i * 5 }
596
+ end
597
+ end
598
+
599
+ describe "monad laws" do
600
+ it "should obey left identity (but it won't)" do
601
+ (Future[1] * 3).should == (1 * 3)
602
+ end
603
+
604
+ it "should obey right identity" do
605
+ Future[1].bind { |i| i }.should == Future[1]
606
+ Future[5].bind { |i| Future[i] }.should == Future[5]
607
+ end
608
+
609
+ it "should obey associativity" do
610
+ ((Future[5] * Future[3]) * Future[5]).should == (Future[5] * (Future[3] * Future[5]))
611
+ ((Future[3] * 5) * 9).should eql (Future[3] * (5 * 9))
612
+ ((3 * Future[5]) * 9).should eql (3 * (Future[5] * 9))
613
+ (Future[3] * 5).should eql (3 * Future[5])
614
+ ((3 * Future[7]) * 9).should eql (3 * (Future[7] * 9))
615
+ ((Future[7] * 5) * 9).should eql (Future[7] * (5 * 9))
616
+ end
617
+ end
618
+ end
619
+
620
+ describe "Reactron" do
621
+ describe "[]" do
622
+ it "should wrap an object" do
623
+ React[1].should == 1
624
+ React[[1, 2, 3]].should == [1, 2, 3]
625
+ end
626
+
627
+ it "should return Pending/Final appropriately" do
628
+ expect(React[1]).to be_a Reactron
629
+ expect(React["testing"]).to be_a Reactron
630
+ expect(React[5] * 2).to be_a Reactor
631
+ expect(React["test"].upcase).to be_a Reactor
632
+ end
633
+ end
634
+
635
+ describe "==" do
636
+ it "should compare internals" do
637
+ React[1].should == React[1]
638
+ React[[1, 2, 3]].should == React[[1, 2, 3]]
639
+ end
640
+
641
+ it "should compare reactor with reactron" do
642
+ (React[5] * 10).should == React[50]
643
+ end
644
+
645
+ it "should not match when objects don't" do
646
+ React[1].should_not == React[2]
647
+ (React[2] * 4).should_not == React[9]
648
+ end
649
+
650
+ it "should compare provided non-React to internals" do
651
+ React[1].should == 1
652
+ React["test"].should == "test"
653
+ (React[1] * 5).should == 5
654
+ React["test"].upcase.should == "TEST"
655
+ React[[1, 2, 3]].should == [1, 2, 3]
656
+ React[1].should_not == 2
657
+ React[[1, 2, 3]].map { |i| i * 7 }.should == [7, 14, 21]
658
+ React["test"].reverse.should_not == "test"
659
+ end
660
+ end
661
+
662
+ describe "bind" do
663
+ it "should create a pending calculation" do
664
+ expect(React[5].bind { |i| i * 5 }).to be_a Reactor
665
+ expect(React[10].bind { |i| i * 5 }.bind { |i| i * 7 }).to be_a Reactor
666
+ end
667
+
668
+ it "should finalize correctly" do
669
+ React[5].bind { |i| i * 5 }.should == React[25]
670
+ React[1].bind { |i| i * 7 }.bind { |i| i * 2 }.should == React[14]
671
+ React["test"].bind { |s| s.upcase }.bind { |s| s.reverse }.should == React["TSET"]
672
+ end
673
+
674
+ it "should be able to modify monad contents" do
675
+ React[5].bind { |i| Try[i] }.should == React[Try[5]]
676
+ React["test"].bind { |i| [i] }.should == React[["test"]]
677
+ end
678
+
679
+ it "should flatten by one level" do
680
+ React[5].bind { |i| React[i] }.should == React[5]
681
+ React[[1, 2, 3]].bind { |i| React[i] }.should == React[[1, 2, 3]]
682
+ end
683
+
684
+ end
685
+
686
+ describe "functionality" do
687
+ it "should pass methods through to the contained object" do
688
+ (React[1] * 3).should == React[3]
689
+ (React["test"].upcase.reverse).should == React["TSET"]
690
+ (React["this is a test"][0,4]).should == React["this"]
691
+ end
692
+
693
+ it "shouldn't execute until necessary" do
694
+ expect(React[1] * 3).to be_a Reactor
695
+ expect(React["test"].upcase.reverse).to be_a Reactor
696
+ expect(React["this is a test"][0,4]).to be_a Reactor
697
+ end
698
+
699
+ it "should treat missing_methods the same as bind" do
700
+ (React[5] * 5).should == React[5].bind { |i| i * 5 }
701
+ end
702
+
703
+ it "should chain reactions together" do
704
+ x = React[5]
705
+ y = x * 10
706
+ z = y * 10
707
+ a = x * 5
708
+ expect(x.should == 5)
709
+ expect(y.should == 50)
710
+ expect(z.should == 500)
711
+ expect(a.should == 25)
712
+ x << 10
713
+ expect(x.should == 10)
714
+ expect(y.should == 100)
715
+ expect(z.should == 1000)
716
+ expect(a.should == 50)
717
+ end
718
+
719
+ it "should successfully combine reactrons" do
720
+ x = React[5]
721
+ y = React[7]
722
+ z = x * y
723
+ expect(z.should == 35)
724
+ x << 2
725
+ expect(z.should == 14)
726
+ y << 3
727
+ expect(z.should == 6)
728
+ end
729
+ end
730
+
731
+ describe "monad laws" do
732
+ it "should obey left identity (but it won't)" do
733
+ (React[1] * 3).should == (1 * 3)
734
+ end
735
+
736
+ it "should obey right identity" do
737
+ React[1].bind { |i| i }.should == React[1]
738
+ React[5].bind { |i| React[i] }.should == React[5]
739
+ end
740
+
741
+ it "should obey associativity" do
742
+ ((React[5] * React[3]) * React[5]).should == (React[5] * (React[3] * React[5]))
743
+ ((React[3] * 5) * 9).should eql (React[3] * (5 * 9))
744
+ ((3 * React[5]) * 9).should eql (3 * (React[5] * 9))
745
+ (React[3] * 5).should eql (3 * React[5])
746
+ ((3 * React[7]) * 9).should eql (3 * (React[7] * 9))
747
+ ((React[7] * 5) * 9).should eql (React[7] * (5 * 9))
748
+ end
749
+ end
750
+ end
751
+
752
+ describe "State" do
753
+
754
+ end
755
+
756
+ end
757
+ end