rose 0.0.5

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,650 @@
1
+ require 'spec_helper'
2
+
3
+ class RoseyObject < Struct.new(:petals, :thorns)
4
+ end
5
+
6
+ class Flower < Struct.new(:id, :type, :color, :age)
7
+ end
8
+
9
+ describe Rose, "Object adapter" do
10
+ before do
11
+ Rose.make(:with_direct_attrs) {
12
+ rows do
13
+ column :petals
14
+ column :thorns
15
+ end
16
+ }
17
+
18
+ Rose.make(:with_named_direct_attrs) {
19
+ rows do
20
+ column(:petals => "Petals")
21
+ column(:thorns => "Thorns")
22
+ end
23
+ }
24
+
25
+ Rose.make(:with_named_indirect_attrs) {
26
+ rows do
27
+ column("Petals") { |item| item.petals - 1 }
28
+ column("Thorns", &:thorns)
29
+ end
30
+ }
31
+
32
+ Rose.make(:with_enforced_class, :class => RoseyObject) {
33
+ rows do
34
+ column :petals
35
+ column :thorns
36
+ end
37
+ }
38
+
39
+ Rose.make(:with_summary, :class => Flower) {
40
+ rows do
41
+ column("Type", &:type)
42
+ column(:color => "Color")
43
+ end
44
+ summary("Type") do
45
+ column("Color") { |colors| colors.join(", ") }
46
+ end
47
+ }
48
+
49
+ Rose.make(:with_blank_summary, :class => Flower) {
50
+ rows do
51
+ column("Type", &:type)
52
+ column(:color => "Color")
53
+ end
54
+ summary("Type") do
55
+ end
56
+ }
57
+
58
+ Rose.make(:with_additional_summary, :class => Flower) {
59
+ rows do
60
+ column("Type", &:type)
61
+ column(:color => "Color")
62
+ end
63
+ summary("Type") do
64
+ column("Color") { |colors| colors.uniq.join(", ") }
65
+ column("Count") { |colors| colors.size }
66
+ column("Count 2") { |colors| colors.size }
67
+ end
68
+ }
69
+
70
+ @value_block = value_block = lambda { |rows| rows.map(&:Age).map(&:to_i).inject(0) { |sum,x| sum+x } }
71
+
72
+ Rose.make(:with_pivot, :class => Flower) {
73
+ rows do
74
+ column(:type => "Type")
75
+ column(:color => "Color")
76
+ column(:age => "Age")
77
+ end
78
+ pivot("Color", "Type", &value_block)
79
+ }
80
+
81
+ Rose.make(:with_sort_by_color, :class => Flower) {
82
+ rows do
83
+ column("Type", &:type)
84
+ column(:color => "Color")
85
+ end
86
+ sort("Color")
87
+ }
88
+
89
+ Rose.make(:with_sort_by_color_descending, :class => Flower) {
90
+ rows do
91
+ column("Type", &:type)
92
+ column(:color => "Color")
93
+ end
94
+ sort("Color", :descending)
95
+ }
96
+
97
+ Rose.make(:with_sort_by_age, :class => Flower) {
98
+ rows do
99
+ column(:type => "Type")
100
+ column(:color => "Color")
101
+ column(:age => "Age")
102
+ end
103
+ sort("Age")
104
+ }
105
+
106
+ Rose.make(:with_sort_by_age_descending, :class => Flower) {
107
+ rows do
108
+ column(:type => "Type")
109
+ column(:color => "Color")
110
+ column(:age => "Age")
111
+ end
112
+ sort("Age", :descending)
113
+ }
114
+
115
+ @negative_sort_block = negative_sort_block = lambda { |v| v.to_i * -1 }
116
+ @positive_sort_block = positive_sort_block = lambda { |v| v.to_i }
117
+
118
+ Rose.make(:with_sort_by_block_negative, :class => Flower) {
119
+ rows do
120
+ column(:type => "Type")
121
+ column(:age => "Age")
122
+ end
123
+ sort("Age", :descending, &negative_sort_block)
124
+ }
125
+
126
+ Rose.make(:with_sort_by_block_positive, :class => Flower) {
127
+ rows do
128
+ column(:type => "Type")
129
+ column(:age => "Age")
130
+ end
131
+ sort("Age", :descending, &positive_sort_block)
132
+ }
133
+
134
+ Rose.make(:with_ordered_execution_asc, :class => Flower) {
135
+ rows do
136
+ column("Type", &:type)
137
+ column(:color => "Color")
138
+ end
139
+ sort("Color")
140
+ summary("Type") do
141
+ column("Color") { |colors| colors.join(", ") }
142
+ end
143
+ }
144
+
145
+ Rose.make(:with_ordered_execution_desc, :class => Flower) {
146
+ rows do
147
+ column("Type", &:type)
148
+ column(:color => "Color")
149
+ end
150
+ sort("Color", :descending)
151
+ summary("Type") do
152
+ column("Color") { |colors| colors.join(", ") }
153
+ end
154
+ }
155
+
156
+ @filter_block = filter_block = lambda { |row| row["Color"] != "blue" }
157
+
158
+ Rose.make(:with_filter, :class => Flower) {
159
+ rows do
160
+ column(:type => "Type")
161
+ column(:color => "Color")
162
+ column(:age => "Age")
163
+ end
164
+ filter(&filter_block)
165
+ }
166
+
167
+ @find_block = find_block = lambda { |items, idy|
168
+ items.find { |item| item.id.to_s == idy }
169
+ }
170
+ @update_block = update_block = lambda { |item, updates| item.color = updates["Color"] }
171
+
172
+ Rose.make(:with_find_and_update) do
173
+ rows do
174
+ identity(:id => "ID")
175
+ column(:type => "Type")
176
+ column(:color => "Color")
177
+ column(:age => "Age")
178
+ end
179
+ roots do
180
+ find(&find_block)
181
+ update(&update_block)
182
+ end
183
+ end
184
+
185
+ Rose.make(:with_update) do
186
+ rows do
187
+ identity(:id => "ID")
188
+ column(:type => "Type")
189
+ column(:color => "Color")
190
+ column(:age => "Age")
191
+ end
192
+ roots do
193
+ update(&update_block)
194
+ end
195
+ end
196
+
197
+ @preview_update_block = preview_update_block = lambda { |item, updates| item.preview(true); item.color = updates["Color"] }
198
+
199
+ Rose.make(:with_preview_update) do
200
+ rows do
201
+ identity(:id => "ID")
202
+ column(:type => "Type")
203
+ column(:color => "Color")
204
+ column(:age => "Age")
205
+ end
206
+ roots do
207
+ preview_update(&preview_update_block)
208
+ update { raise Exception, "you shouldn't be calling me" }
209
+ end
210
+ end
211
+
212
+ @created = created = []
213
+ @create_block = create_block = lambda { |idy, updates| created << [idy, updates] }
214
+
215
+ Rose.make(:with_create) do
216
+ rows do
217
+ identity(:id => "ID")
218
+ column(:type => "Type")
219
+ column(:color => "Color")
220
+ column(:age => "Age")
221
+ end
222
+ roots do
223
+ create(&create_block)
224
+ update {}
225
+ end
226
+ end
227
+
228
+ @preview_created = preview_created = []
229
+ @preview_create_block = preview_create_block = lambda { |idy, updates| preview_created << [idy, updates] }
230
+
231
+ Rose.make(:with_preview_create) do
232
+ rows do
233
+ identity(:id => "ID")
234
+ column(:type => "Type")
235
+ column(:color => "Color")
236
+ column(:age => "Age")
237
+ end
238
+ roots do
239
+ preview_create(&preview_create_block)
240
+ create { raise "Not me!"}
241
+ update {}
242
+ end
243
+ end
244
+ end
245
+
246
+ after do
247
+ Rose.seedlings.clear
248
+ end
249
+
250
+ context "make report" do
251
+ it "should support bloom and photosynthesize" do
252
+ Rose(:with_direct_attrs).tap do |rose|
253
+ rose.should be_kind_of(Rose::Shell)
254
+ rose.should respond_to(:bloom)
255
+ rose.should respond_to(:photosynthesize)
256
+ end
257
+ end
258
+
259
+ it "should support direct attributes" do
260
+ Rose(:with_direct_attrs).tap do |report|
261
+ report.row.attributes.map(&:column_name).should == [:petals, :thorns]
262
+ report.row.attributes.map(&:method_name).should == [:petals, :thorns]
263
+ end
264
+ end
265
+
266
+ it "should support direct attributes with column name" do
267
+ Rose(:with_named_direct_attrs).tap do |report|
268
+ report.row.attributes.map(&:column_name).should == ["Petals", "Thorns"]
269
+ report.row.attributes.map(&:method_name).should == [:petals, :thorns]
270
+ end
271
+ end
272
+
273
+ it "should support indirect (dynamic) attributes with column name" do
274
+ Rose(:with_named_indirect_attrs).tap do |report|
275
+ report.row.attributes.map(&:column_name).should == ["Petals", "Thorns"]
276
+ report.row.attributes.map(&:method_name).should == ["Petals", "Thorns"]
277
+ end
278
+ end
279
+
280
+ it "should support :class option" do
281
+ Rose(:with_enforced_class).tap do |report|
282
+ report.options[:class].should == RoseyObject
283
+ end
284
+ end
285
+
286
+ it "should support sort by block" do
287
+ Rose(:with_sort_by_block_negative).tap do |report|
288
+ report.options[:sort].column_name.should == "Age"
289
+ report.options[:sort].order.should == :descending
290
+ report.options[:sort].sort_block.should == @negative_sort_block
291
+ end
292
+ end
293
+
294
+ it "should support summary" do
295
+ Rose(:with_summary).tap do |report|
296
+ report.options[:summary].attributes.map(&:column_name).should == ["Color"]
297
+ report.options[:summary].attributes.map(&:method_name).should == ["Color"]
298
+ end
299
+ end
300
+
301
+ it "should support pivoting" do
302
+ Rose(:with_pivot).tap do |report|
303
+ report.options[:pivot].group_column.should == "Color"
304
+ report.options[:pivot].pivot_column.should == "Type"
305
+ report.options[:pivot].value_block.should == @value_block
306
+ end
307
+ end
308
+
309
+ it "should support filtering" do
310
+ Rose(:with_filter).tap do |report|
311
+ report.options[:filter].value_block.should == @filter_block
312
+ end
313
+ end
314
+
315
+ it "should support identity" do
316
+ Rose(:with_update).tap do |report|
317
+ report.row.identity_attribute.column_name.should == "ID"
318
+ end
319
+ end
320
+
321
+ it "should support find and update" do
322
+ Rose(:with_find_and_update).tap do |report|
323
+ report.root.finder.should == @find_block
324
+ report.root.updater.should == @update_block
325
+ end
326
+ end
327
+
328
+ it "should support preview" do
329
+ Rose(:with_preview_update).tap do |report|
330
+ report.root.update_previewer.should == @preview_update_block
331
+ end
332
+ end
333
+
334
+ it "should support create" do
335
+ Rose(:with_create).tap do |report|
336
+ report.root.creator.should == @create_block
337
+ end
338
+ end
339
+
340
+ it "should support preview create" do
341
+ Rose(:with_preview_create).tap do |report|
342
+ report.root.create_previewer.should == @preview_create_block
343
+ end
344
+ end
345
+ end
346
+
347
+ context "run report" do
348
+ before do
349
+ @arr = [RoseyObject.new(30, 10)]
350
+ @flowers = [
351
+ Flower.new(0, :roses, :red, 1),
352
+ Flower.new(1, :violets, :blue, 2),
353
+ Flower.new(2, :roses, :red, 3)
354
+ ]
355
+ end
356
+
357
+ it "should run with direct attributes" do
358
+ Rose(:with_direct_attrs).bloom(@arr).should match_table <<-eo_table.gsub(%r{^ }, '')
359
+ +-----------------+
360
+ | petals | thorns |
361
+ +-----------------+
362
+ | 30 | 10 |
363
+ +-----------------+
364
+ eo_table
365
+ end
366
+
367
+ it "should run with direct attributes with column name" do
368
+ Rose(:with_named_direct_attrs).bloom(@arr).should match_table <<-eo_table.gsub(%r{^ }, '')
369
+ +-----------------+
370
+ | Petals | Thorns |
371
+ +-----------------+
372
+ | 30 | 10 |
373
+ +-----------------+
374
+ eo_table
375
+ end
376
+
377
+ it "should run with indirect (dynamic) attributes with column name" do
378
+ Rose(:with_named_indirect_attrs).bloom(@arr).should match_table <<-eo_table.gsub(%r{^ }, '')
379
+ +-----------------+
380
+ | Petals | Thorns |
381
+ +-----------------+
382
+ | 29 | 10 |
383
+ +-----------------+
384
+ eo_table
385
+ end
386
+
387
+ it "should not run with wrong class" do
388
+ lambda {
389
+ Rose(:with_enforced_class).bloom([mock('Something else')])
390
+ }.should raise_error(TypeError, "Expected RoseyObject, got Mocha::Mock")
391
+ end
392
+
393
+ it "should sort by color (ascending)" do
394
+ Rose(:with_sort_by_color).bloom(@flowers).should match_table <<-eo_table.gsub(%r{^ }, '')
395
+ +-----------------+
396
+ | Type | Color |
397
+ +-----------------+
398
+ | violets | blue |
399
+ | roses | red |
400
+ | roses | red |
401
+ +-----------------+
402
+ eo_table
403
+ end
404
+
405
+ it "should sort by color (descending)" do
406
+ Rose(:with_sort_by_color_descending).bloom(@flowers).should match_table <<-eo_table.gsub(%r{^ }, '')
407
+ +-----------------+
408
+ | Type | Color |
409
+ +-----------------+
410
+ | roses | red |
411
+ | roses | red |
412
+ | violets | blue |
413
+ +-----------------+
414
+ eo_table
415
+ end
416
+
417
+ it "should sort by age (ascending)" do
418
+ Rose(:with_sort_by_age).bloom(@flowers).should match_table <<-eo_table.gsub(%r{^ }, '')
419
+ +-----------------------+
420
+ | Type | Color | Age |
421
+ +-----------------------+
422
+ | roses | red | 1 |
423
+ | violets | blue | 2 |
424
+ | roses | red | 3 |
425
+ +-----------------------+
426
+ eo_table
427
+ end
428
+
429
+ it "should sort by age (descending)" do
430
+ Rose(:with_sort_by_age_descending).bloom(@flowers).should match_table <<-eo_table.gsub(%r{^ }, '')
431
+ +-----------------------+
432
+ | Type | Color | Age |
433
+ +-----------------------+
434
+ | roses | red | 3 |
435
+ | violets | blue | 2 |
436
+ | roses | red | 1 |
437
+ +-----------------------+
438
+ eo_table
439
+ end
440
+
441
+ it "should sort by block (-)" do
442
+ Rose(:with_sort_by_block_negative).bloom(@flowers).should match_table <<-eo_table.gsub(%r{^ }, '')
443
+ +---------------+
444
+ | Type | Age |
445
+ +---------------+
446
+ | roses | 1 |
447
+ | violets | 2 |
448
+ | roses | 3 |
449
+ +---------------+
450
+ eo_table
451
+ end
452
+
453
+ it "should sort by block (+)" do
454
+ Rose(:with_sort_by_block_positive).bloom(@flowers).should match_table <<-eo_table.gsub(%r{^ }, '')
455
+ +---------------+
456
+ | Type | Age |
457
+ +---------------+
458
+ | roses | 3 |
459
+ | violets | 2 |
460
+ | roses | 1 |
461
+ +---------------+
462
+ eo_table
463
+ end
464
+
465
+ it "should summarize columns" do
466
+ Rose(:with_summary).bloom(@flowers).should match_table <<-eo_table.gsub(%r{^ }, '')
467
+ +--------------------+
468
+ | Type | Color |
469
+ +--------------------+
470
+ | roses | red, red |
471
+ | violets | blue |
472
+ +--------------------+
473
+ eo_table
474
+ end
475
+
476
+ it "should summarize columns omitting columns" do
477
+ Rose(:with_blank_summary).bloom(@flowers).should match_table <<-eo_table.gsub(%r{^ }, '')
478
+ +---------+
479
+ | Type |
480
+ +---------+
481
+ | roses |
482
+ | violets |
483
+ +---------+
484
+ eo_table
485
+ end
486
+
487
+ it "should summarize columns adding additional columns" do
488
+ Rose(:with_additional_summary).bloom(@flowers).should match_table <<-eo_table.gsub(%r{^ }, '')
489
+ +-----------------------------------+
490
+ | Type | Color | Count | Count 2 |
491
+ +-----------------------------------+
492
+ | roses | red | 2 | 2 |
493
+ | violets | blue | 1 | 1 |
494
+ +-----------------------------------+
495
+ eo_table
496
+ end
497
+
498
+ it "should pivot table" do
499
+ Rose(:with_pivot).bloom(@flowers).should match_table <<-eo_table.gsub(%r{^ }, '')
500
+ +-------------------------+
501
+ | Color | roses | violets |
502
+ +-------------------------+
503
+ | red | 4 | 0 |
504
+ | blue | 0 | 2 |
505
+ +-------------------------+
506
+ eo_table
507
+ end
508
+
509
+ it "should run in order" do
510
+ @flowers << Flower.new(3, :roses, :maroon, 3)
511
+ Rose(:with_ordered_execution_asc).bloom(@flowers).should match_table <<-eo_table.gsub(%r{^ }, '')
512
+ +----------------------------+
513
+ | Type | Color |
514
+ +----------------------------+
515
+ | violets | blue |
516
+ | roses | maroon, red, red |
517
+ +----------------------------+
518
+ eo_table
519
+
520
+ Rose(:with_ordered_execution_desc).bloom(@flowers).should match_table <<-eo_table.gsub(%r{^ }, '')
521
+ +----------------------------+
522
+ | Type | Color |
523
+ +----------------------------+
524
+ | roses | red, red, maroon |
525
+ | violets | blue |
526
+ +----------------------------+
527
+ eo_table
528
+ end
529
+
530
+ it "should filter rows" do
531
+ Rose(:with_filter).bloom(@flowers).should match_table <<-eo_table.gsub(%r{^ }, '')
532
+ +---------------------+
533
+ | Type | Color | Age |
534
+ +---------------------+
535
+ | roses | red | 1 |
536
+ | roses | red | 3 |
537
+ +---------------------+
538
+ eo_table
539
+ end
540
+
541
+ it "should find and update" do
542
+ Rose(:with_find_and_update).photosynthesize(@flowers, {
543
+ :with => {
544
+ "0" => { "Color" => "blue" }
545
+ }
546
+ }).should match_table <<-eo_table.gsub(%r{^ }, '')
547
+ +----------------------------+
548
+ | ID | Type | Color | Age |
549
+ +----------------------------+
550
+ | 0 | roses | blue | 1 |
551
+ | 1 | violets | blue | 2 |
552
+ | 2 | roses | red | 3 |
553
+ +----------------------------+
554
+ eo_table
555
+ end
556
+
557
+ it "should update" do
558
+ Rose(:with_update).photosynthesize(@flowers, {
559
+ :with => {
560
+ "0" => { "Color" => "blue" }
561
+ }
562
+ }).should match_table <<-eo_table.gsub(%r{^ }, '')
563
+ +----------------------------+
564
+ | ID | Type | Color | Age |
565
+ +----------------------------+
566
+ | 0 | roses | blue | 1 |
567
+ | 1 | violets | blue | 2 |
568
+ | 2 | roses | red | 3 |
569
+ +----------------------------+
570
+ eo_table
571
+ end
572
+
573
+ it "should update from CSV" do
574
+ Rose(:with_update).photosynthesize(@flowers, {
575
+ :with => "spec/examples/update_flowers.csv"
576
+ }).should match_table <<-eo_table.gsub(%r{^ }, '')
577
+ +----------------------------+
578
+ | ID | Type | Color | Age |
579
+ +----------------------------+
580
+ | 0 | roses | blue | 1 |
581
+ | 1 | violets | red | 2 |
582
+ | 2 | roses | green | 3 |
583
+ +----------------------------+
584
+ eo_table
585
+ end
586
+
587
+ it "should preview" do
588
+ @flowers.each do |flower|
589
+ flower.expects(:preview).with(true)
590
+ end
591
+
592
+ Rose(:with_preview_update).photosynthesize(@flowers, {
593
+ :with => {
594
+ "0" => { "Color" => "blue" },
595
+ "1" => { "Color" => "blue" },
596
+ "2" => { "Color" => "blue" }
597
+ },
598
+ :preview => true
599
+ }).should match_table <<-eo_table.gsub(%r{^ }, '')
600
+ +----------------------------+
601
+ | ID | Type | Color | Age |
602
+ +----------------------------+
603
+ | 0 | roses | blue | 1 |
604
+ | 1 | violets | blue | 2 |
605
+ | 2 | roses | blue | 3 |
606
+ +----------------------------+
607
+ eo_table
608
+ end
609
+
610
+ it "should preview from CSV" do
611
+ @flowers.each do |flower|
612
+ flower.expects(:preview).with(true)
613
+ end
614
+
615
+ Rose(:with_preview_update).photosynthesize(@flowers, {
616
+ :with => "spec/examples/update_flowers.csv",
617
+ :preview => true
618
+ }).should match_table <<-eo_table.gsub(%r{^ }, '')
619
+ +----------------------------+
620
+ | ID | Type | Color | Age |
621
+ +----------------------------+
622
+ | 0 | roses | blue | 1 |
623
+ | 1 | violets | red | 2 |
624
+ | 2 | roses | green | 3 |
625
+ +----------------------------+
626
+ eo_table
627
+ end
628
+
629
+ it "should create" do
630
+ Rose(:with_create).photosynthesize(@flowers, {
631
+ :with => {
632
+ "9" => { "Color" => "blue" }
633
+ }
634
+ })
635
+
636
+ @created.should == [["9", { "Color" => "blue" }]]
637
+ end
638
+
639
+ it "should preview create" do
640
+ Rose(:with_preview_create).photosynthesize(@flowers, {
641
+ :with => {
642
+ "9" => { "Color" => "blue" }
643
+ },
644
+ :preview => true
645
+ })
646
+
647
+ @preview_created.should == [["9", { "Color" => "blue" }]]
648
+ end
649
+ end
650
+ end