mon 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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