rose 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,75 @@
1
+ require 'rose/proxy'
2
+
3
+ module Rose
4
+ # Defines the Rose DSL
5
+ class Seedling
6
+ # @return [Rose::Proxy::Row] the row proxy containing an array of Attributes
7
+ attr_reader :row
8
+
9
+ # @return [Rose::Proxy::Root] the root proxy containing attribute finder and updater
10
+ attr_reader :root
11
+
12
+ # @return [ObjectAdapter] the adapter
13
+ attr_reader :adapter
14
+
15
+ # @return [Hash] the options used by the adapter
16
+ attr_reader :options
17
+
18
+ # @return [Array] the alterations to be applied to the sprouted Seedling (the report)
19
+ attr_reader :alterations
20
+
21
+ # @param [ObjectAdapter] adapter An ObjectAdapter capable of sprouting a Seedling
22
+ # (running the report)
23
+ # @param [Hash] options
24
+ # @option options [Class] :class (nil) Used during by the adapter to enforce items types
25
+ def initialize(adapter, options={})
26
+ @adapter = adapter
27
+ @options = options
28
+ @alterations = @options[:alterations] = []
29
+ end
30
+
31
+ # @yield Proxy::Row
32
+ def rows(&blk)
33
+ proxy = Proxy::Row.new
34
+ proxy.instance_eval(&blk)
35
+ @row = proxy
36
+ end
37
+
38
+ # @param [String, Symbol] column_name the column to sort by
39
+ # @param [:ascending, :descending] order the order to sort by
40
+ def sort(column_name, order = :ascending, &sort_block)
41
+ @options[:sort] = Attribute::Sort.new(column_name, order, &sort_block)
42
+ @alterations << @options[:sort]
43
+ end
44
+
45
+ # @yield Rose::Attribute::Filter
46
+ def filter(&filter_block)
47
+ @options[:filter] = Attribute::Filter.new(nil, nil, filter_block)
48
+ @alterations << @options[:filter]
49
+ end
50
+
51
+ # @param [String, Symbol] column_name the column to group by
52
+ # @yield Proxy::Summary
53
+ def summary(column_name, &blk)
54
+ proxy = Proxy::Summary.new(column_name)
55
+ proxy.instance_eval(&blk)
56
+ @options[:summary] = proxy
57
+ @alterations << @options[:summary]
58
+ end
59
+
60
+ # @param [String, Symbol] group_column the column to use for row data
61
+ # @param [String, Symbol] pivot_column the column to use for column data
62
+ # @param [Proc] value_block the block used to evalue the value data
63
+ def pivot(group_column, pivot_column, &value_block)
64
+ @options[:pivot] = Attribute::Pivot.new(group_column, pivot_column, value_block)
65
+ @alterations << @options[:pivot]
66
+ end
67
+
68
+ # @yield Proxy::Root
69
+ def roots(&blk)
70
+ proxy = Proxy::Root.new
71
+ proxy.instance_eval(&blk)
72
+ @root = proxy
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,40 @@
1
+ module Rose
2
+ # This class is a wrapper around Seedling that provides methods
3
+ # we don't want invoked within the Rose#make DSL.
4
+ #
5
+ # A seedling with a shell is still a seedling. Hence, it should
6
+ # be have as such!
7
+ class Shell
8
+ # @return [Rose::Seedling] the current seedling
9
+ attr_reader :seedling
10
+
11
+ def initialize(seedling)
12
+ @seedling = seedling
13
+ end
14
+
15
+ # Provides bulk exporting
16
+ # @param [Array] items the items to sprout the seedling with
17
+ # @return [Ruport::Data::RoseTable] the resulting table
18
+ def bloom(items=[], options={})
19
+ @seedling.adapter.sprout(@seedling, @seedling.options.merge(options).merge(
20
+ :attributes => @seedling.row.attributes,
21
+ :items => items
22
+ ))
23
+ end
24
+
25
+ # Provides bulk importing
26
+ # @param [Hash] options
27
+ # @option options [Hash,String] :with (required) a Hash of identity (id) => attribute pairs, or a String to a CSV file to update the seedling with
28
+ # @option options [true, false] :preview (false) whether or not to use the previewer
29
+ def photosynthesize(items=[], options={})
30
+ @seedling.adapter.osmosis(@seedling, @seedling.options.merge(options).merge(
31
+ :items => items
32
+ ))
33
+ end
34
+
35
+ # Delegates methods to the current seedling
36
+ def method_missing(*args, &blk)
37
+ @seedling.send(*args, &blk)
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,86 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{rose}
8
+ s.version = "0.0.5"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Henry Hsu"]
12
+ s.date = %q{2010-07-07}
13
+ s.description = %q{A slick Ruby DSL for reporting.}
14
+ s.email = %q{henry@qlane.com}
15
+ s.extra_rdoc_files = [
16
+ "LICENSE",
17
+ "README.markdown"
18
+ ]
19
+ s.files = [
20
+ ".autotest",
21
+ ".document",
22
+ ".gitignore",
23
+ "LICENSE",
24
+ "README.markdown",
25
+ "Rakefile",
26
+ "VERSION",
27
+ "features/rose.feature",
28
+ "features/step_definitions/rose_steps.rb",
29
+ "features/support/env.rb",
30
+ "lib/rose.rb",
31
+ "lib/rose/active_record.rb",
32
+ "lib/rose/attribute.rb",
33
+ "lib/rose/core_extensions.rb",
34
+ "lib/rose/object.rb",
35
+ "lib/rose/proxy.rb",
36
+ "lib/rose/ruport.rb",
37
+ "lib/rose/seedling.rb",
38
+ "lib/rose/shell.rb",
39
+ "rose.gemspec",
40
+ "spec/core_extensions_spec.rb",
41
+ "spec/db/schema.rb",
42
+ "spec/examples/update_flowers.csv",
43
+ "spec/examples/update_posts.csv",
44
+ "spec/rose/active_record_spec.rb",
45
+ "spec/rose/object_spec.rb",
46
+ "spec/rose_spec.rb",
47
+ "spec/spec.opts",
48
+ "spec/spec_helper.rb"
49
+ ]
50
+ s.homepage = %q{http://github.com/hsume2/rose}
51
+ s.rdoc_options = ["--charset=UTF-8"]
52
+ s.require_paths = ["lib"]
53
+ s.rubygems_version = %q{1.3.7}
54
+ s.summary = %q{Reporting like a spring rose, rows and rows of it}
55
+ s.test_files = [
56
+ "spec/core_extensions_spec.rb",
57
+ "spec/db/schema.rb",
58
+ "spec/rose/active_record_spec.rb",
59
+ "spec/rose/object_spec.rb",
60
+ "spec/rose_spec.rb",
61
+ "spec/spec_helper.rb"
62
+ ]
63
+
64
+ if s.respond_to? :specification_version then
65
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
66
+ s.specification_version = 3
67
+
68
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
69
+ s.add_runtime_dependency(%q<ruport>, [">= 1.6.3"])
70
+ s.add_development_dependency(%q<rspec>, [">= 1.2.9"])
71
+ s.add_development_dependency(%q<yard>, [">= 0"])
72
+ s.add_development_dependency(%q<cucumber>, [">= 0"])
73
+ else
74
+ s.add_dependency(%q<ruport>, [">= 1.6.3"])
75
+ s.add_dependency(%q<rspec>, [">= 1.2.9"])
76
+ s.add_dependency(%q<yard>, [">= 0"])
77
+ s.add_dependency(%q<cucumber>, [">= 0"])
78
+ end
79
+ else
80
+ s.add_dependency(%q<ruport>, [">= 1.6.3"])
81
+ s.add_dependency(%q<rspec>, [">= 1.2.9"])
82
+ s.add_dependency(%q<yard>, [">= 0"])
83
+ s.add_dependency(%q<cucumber>, [">= 0"])
84
+ end
85
+ end
86
+
@@ -0,0 +1,52 @@
1
+ require 'spec_helper'
2
+
3
+ class MyObject
4
+ include Rose::CoreExtensions
5
+ end
6
+
7
+ describe "CoreExtensions" do
8
+ before do
9
+ @o = MyObject.new
10
+ end
11
+
12
+ describe "#require_keys" do
13
+ it "should raise exception if missing required key" do
14
+ lambda {
15
+ @o.require_keys({:name => 'foo'}, :value)
16
+ }.should raise_error(ArgumentError, "Missing required key(s): value")
17
+ end
18
+
19
+ it "should not raise exception if not missing required key" do
20
+ lambda {
21
+ @o.require_keys({:name => 'foo', :value => 'bar'}, :value)
22
+ }.should_not raise_error
23
+ end
24
+
25
+ it "should raise exception if missing required keys" do
26
+ lambda {
27
+ @o.require_keys({}, :name, :value)
28
+ }.should raise_error(ArgumentError, "Missing required key(s): name, value")
29
+ end
30
+
31
+ it "should not raise exception if not missing required keys" do
32
+ lambda {
33
+ @o.require_keys({:name => 'foo', :value => 'bar'}, :name, :value)
34
+ }.should_not raise_error
35
+ end
36
+ end
37
+
38
+ describe "#required_values" do
39
+ it "should return values of required keys" do
40
+ @o.expects(:require_keys).with({:name => 'foo', :value => 'bar'}, :name, :value)
41
+ foo, bar = @o.required_values({:name => 'foo', :value => 'bar'}, :name, :value)
42
+ foo.should == 'foo'
43
+ bar.should == 'bar'
44
+ end
45
+
46
+ it "should return value of required key" do
47
+ @o.expects(:require_keys).with({:name => 'foo', :value => 'bar'}, :name)
48
+ foo = @o.required_values({:name => 'foo', :value => 'bar'}, :name)
49
+ foo.should == 'foo'
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,32 @@
1
+ ActiveRecord::Schema.define(:version => 0) do
2
+ create_table :people, :force => true do |t|
3
+ t.column :name, :string
4
+ t.column :type, :string
5
+ t.column :password, :string
6
+ t.column :admin, :boolean, :default => false
7
+ end
8
+
9
+ create_table :posts, :force => true do |t|
10
+ t.column :guid, :string
11
+ t.column :title, :string
12
+ t.column :body, :text
13
+ t.column :published, :boolean, :default => true
14
+ end
15
+
16
+ create_table :comments, :force => true do |t|
17
+ t.column :post_id, :integer
18
+ t.column :author_id, :integer
19
+ t.column :body, :text
20
+ end
21
+
22
+ create_table :subjects, :force => true do |t|
23
+ t.column :name, :string
24
+ end
25
+
26
+ create_table :tests, :force => true do |t|
27
+ t.column :student_id, :integer
28
+ t.column :subject_id, :integer
29
+ t.column :score, :decimal
30
+ t.timestamps
31
+ end
32
+ end
@@ -0,0 +1,4 @@
1
+ ID,Type,Color,Age
2
+ 0,roses,blue,1
3
+ 1,violets,red,2
4
+ 2,roses,green,3
@@ -0,0 +1,5 @@
1
+ ID,Title,Comments
2
+ P1,Post #1,2
3
+ P2,Post #2,1
4
+ P3,Third Post,0
5
+ P4,Fourth Post,0
@@ -0,0 +1,434 @@
1
+ require 'spec_helper'
2
+ require 'rose/active_record'
3
+
4
+ module RoseActiveRecordSpecs
5
+ class Person < ActiveRecord::Base
6
+ attr_protected :password
7
+ end
8
+
9
+ class Admin < Person
10
+ end
11
+
12
+ class Post < ActiveRecord::Base
13
+ has_many :comments
14
+ end
15
+
16
+ class Comment < ActiveRecord::Base
17
+ belongs_to :post
18
+ belongs_to :author, :class_name => "Person"
19
+ end
20
+
21
+ class Subject < ActiveRecord::Base
22
+ has_many :tests
23
+ end
24
+
25
+ class Test < ActiveRecord::Base
26
+ belongs_to :subject
27
+ belongs_to :student, :class_name => "Person"
28
+ end
29
+
30
+ describe Rose, "ActiveRecord adapter" do
31
+ before(:suite) do
32
+ # ActiveRecord::Base.logger = Logger.new(File.dirname(__FILE__) + "/log/test.log")
33
+ ActiveRecord::Migration.verbose = false
34
+ ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :database => ":memory:")
35
+ load(File.dirname(__FILE__) + "/../db/schema.rb")
36
+
37
+ person_1 = Person.create(:name => "Person #1")
38
+ person_2 = Person.create(:name => "Person #2")
39
+
40
+ post_1 = Post.create(:title => "Post #1", :guid => "P1")
41
+ post_1.comments.create(:author => person_1)
42
+ post_1.comments.create(:author => person_2)
43
+ post_2 = Post.create(:title => "Post #2", :guid => "P2")
44
+ post_2.comments.create(:author => person_2)
45
+ end
46
+
47
+ describe "make report" do
48
+ before do
49
+ Post.rose(:post_comments) do
50
+ rows do
51
+ column("Post", &:title)
52
+ column("Comments") { |item| item.comments.size }
53
+ end
54
+ end
55
+
56
+ Post.rose(:post_comments_sorted_asc) do
57
+ rows do
58
+ column("Post", &:title)
59
+ column("Comments") { |item| item.comments.size }
60
+ end
61
+ sort("Comments", :ascending)
62
+ end
63
+
64
+ Post.rose(:post_comments_sorted_desc) do
65
+ rows do
66
+ column("Post", &:title)
67
+ column("Comments") { |item| item.comments.size }
68
+ end
69
+ sort("Comments", :descending)
70
+ end
71
+ end
72
+
73
+ it "should report on posts' comments" do
74
+ Post.rose_for(:post_comments).should match_table <<-eo_table.gsub(%r{^ }, '')
75
+ +--------------------+
76
+ | Post | Comments |
77
+ +--------------------+
78
+ | Post #1 | 2 |
79
+ | Post #2 | 1 |
80
+ +--------------------+
81
+ eo_table
82
+ end
83
+
84
+ it "should order by comments size" do
85
+ Post.rose_for(:post_comments_sorted_asc).should match_table <<-eo_table.gsub(%r{^ }, '')
86
+ +--------------------+
87
+ | Post | Comments |
88
+ +--------------------+
89
+ | Post #2 | 1 |
90
+ | Post #1 | 2 |
91
+ +--------------------+
92
+ eo_table
93
+
94
+ Post.rose_for(:post_comments_sorted_desc).should match_table <<-eo_table.gsub(%r{^ }, '')
95
+ +--------------------+
96
+ | Post | Comments |
97
+ +--------------------+
98
+ | Post #1 | 2 |
99
+ | Post #2 | 1 |
100
+ +--------------------+
101
+ eo_table
102
+ end
103
+
104
+ it "should report only posts with #2" do
105
+ Post.rose_for(:post_comments, :conditions => ["title like ?", "%#2%"]).should match_table <<-eo_table.gsub(%r{^ }, '')
106
+ +--------------------+
107
+ | Post | Comments |
108
+ +--------------------+
109
+ | Post #2 | 1 |
110
+ +--------------------+
111
+ eo_table
112
+ end
113
+ end
114
+
115
+ describe "make report with sigma" do
116
+ before do
117
+ Comment.rose(:author_comments) do
118
+ rows do
119
+ column("Author") { |item| item.author.name }
120
+ column("Posts") { |item| item.post.title }
121
+ column("Comments") { |item| true }
122
+ end
123
+ summary("Author") do
124
+ column("Posts") { |posts| posts.join(", ") }
125
+ column("Comments") { |comments| comments.size }
126
+ end
127
+ end
128
+ end
129
+
130
+ it "should get authors and their comments" do
131
+ Comment.rose_for(:author_comments).should match_table <<-eo_table.gsub(%r{^ }, '')
132
+ +-----------------------------------------+
133
+ | Author | Posts | Comments |
134
+ +-----------------------------------------+
135
+ | Person #1 | Post #1 | 1 |
136
+ | Person #2 | Post #1, Post #2 | 2 |
137
+ +-----------------------------------------+
138
+ eo_table
139
+ end
140
+ end
141
+
142
+ describe "make report with pivot" do
143
+ it "should make report with pivot" do
144
+ elisa = Person.create(:name => "Elisa")
145
+ mary = Person.create(:name => "Mary")
146
+ english = Subject.create(:name => "English")
147
+ math = Subject.create(:name => "Math")
148
+ science = Subject.create(:name => "Science")
149
+ art = Subject.create(:name => "Art")
150
+ history = Subject.create(:name => "History")
151
+ french = Subject.create(:name => "French")
152
+
153
+ Test.create(:student => elisa, :subject => english, :score => 87, :created_at => Date.parse('January 2010'))
154
+ Test.create(:student => elisa, :subject => math, :score => 65, :created_at => Date.parse('January 2010'))
155
+ Test.create(:student => elisa, :subject => science, :score => 58, :created_at => Date.parse('January 2010'))
156
+ Test.create(:student => elisa, :subject => art, :score => 89, :created_at => Date.parse('January 2010'))
157
+ Test.create(:student => elisa, :subject => history, :score => 81, :created_at => Date.parse('January 2010'))
158
+ Test.create(:student => elisa, :subject => french, :score => 62, :created_at => Date.parse('January 2010'))
159
+
160
+ Test.create(:student => elisa, :subject => english, :score => 51, :created_at => Date.parse('February 2010'))
161
+ Test.create(:student => elisa, :subject => math, :score => 72, :created_at => Date.parse('February 2010'))
162
+ Test.create(:student => elisa, :subject => science, :score => 89, :created_at => Date.parse('February 2010'))
163
+ Test.create(:student => elisa, :subject => art, :score => 83, :created_at => Date.parse('February 2010'))
164
+ Test.create(:student => elisa, :subject => history, :score => 84, :created_at => Date.parse('February 2010'))
165
+ Test.create(:student => elisa, :subject => french, :score => 57, :created_at => Date.parse('February 2010'))
166
+
167
+ Test.create(:student => elisa, :subject => english, :score => 41, :created_at => Date.parse('March 2010'))
168
+ Test.create(:student => elisa, :subject => math, :score => 71, :created_at => Date.parse('March 2010'))
169
+ Test.create(:student => elisa, :subject => science, :score => 41, :created_at => Date.parse('March 2010'))
170
+ Test.create(:student => elisa, :subject => art, :score => 92, :created_at => Date.parse('March 2010'))
171
+ Test.create(:student => elisa, :subject => history, :score => 91, :created_at => Date.parse('March 2010'))
172
+ Test.create(:student => elisa, :subject => french, :score => 56, :created_at => Date.parse('March 2010'))
173
+
174
+ Test.create(:student => mary, :subject => english, :score => 87, :created_at => Date.parse('January 2010'))
175
+ Test.create(:student => mary, :subject => math, :score => 53, :created_at => Date.parse('January 2010'))
176
+ Test.create(:student => mary, :subject => science, :score => 35, :created_at => Date.parse('January 2010'))
177
+ Test.create(:student => mary, :subject => art, :score => 61, :created_at => Date.parse('January 2010'))
178
+ Test.create(:student => mary, :subject => history, :score => 58, :created_at => Date.parse('January 2010'))
179
+ Test.create(:student => mary, :subject => french, :score => 92, :created_at => Date.parse('January 2010'))
180
+
181
+ Test.create(:student => mary, :subject => english, :score => 68, :created_at => Date.parse('February 2010'))
182
+ Test.create(:student => mary, :subject => math, :score => 54, :created_at => Date.parse('February 2010'))
183
+ Test.create(:student => mary, :subject => science, :score => 56, :created_at => Date.parse('February 2010'))
184
+ Test.create(:student => mary, :subject => art, :score => 59, :created_at => Date.parse('February 2010'))
185
+ Test.create(:student => mary, :subject => history, :score => 61, :created_at => Date.parse('February 2010'))
186
+ Test.create(:student => mary, :subject => french, :score => 93, :created_at => Date.parse('February 2010'))
187
+
188
+ Test.create(:student => mary, :subject => english, :score => 41, :created_at => Date.parse('March 2010'))
189
+ Test.create(:student => mary, :subject => math, :score => 35, :created_at => Date.parse('March 2010'))
190
+ Test.create(:student => mary, :subject => science, :score => 41, :created_at => Date.parse('March 2010'))
191
+ Test.create(:student => mary, :subject => art, :score => 48, :created_at => Date.parse('March 2010'))
192
+ Test.create(:student => mary, :subject => history, :score => 67, :created_at => Date.parse('March 2010'))
193
+ Test.create(:student => mary, :subject => french, :score => 90, :created_at => Date.parse('March 2010'))
194
+
195
+ Test.rose(:scores) do
196
+ rows do
197
+ column("Month") { |test| I18n.l(test.created_at, :format => :short) }
198
+ column("Subject") { |test| test.subject.name }
199
+ column("Student") { |test| test.student.name }
200
+ column(:score => "Score")
201
+ end
202
+ pivot("Month", "Subject") do |matching_rows|
203
+ matching_rows.map(&:Score).map(&:to_f).sum
204
+ end
205
+ end
206
+
207
+ Test.rose_for(:scores).should match_table <<-eo_table.gsub(%r{^ }, '')
208
+ +---------------------------------------------------------------------+
209
+ | Month | Art | Science | English | French | Math | History |
210
+ +---------------------------------------------------------------------+
211
+ | 01 Jan 00:00 | 150.0 | 93.0 | 174.0 | 154.0 | 118.0 | 139.0 |
212
+ | 01 Feb 00:00 | 142.0 | 145.0 | 119.0 | 150.0 | 126.0 | 145.0 |
213
+ | 01 Mar 00:00 | 140.0 | 82.0 | 82.0 | 146.0 | 106.0 | 158.0 |
214
+ +---------------------------------------------------------------------+
215
+ eo_table
216
+ end
217
+ end
218
+
219
+ describe "run report" do
220
+ before do
221
+ Comment.rose(:author_comments) do
222
+ rows do
223
+ column("Author") { |item| item.author.name }
224
+ column("Posts") { |item| item.post.title }
225
+ column("Comments") { |item| item.destroy }
226
+ end
227
+ end
228
+ end
229
+
230
+ it "should run report within transaction" do
231
+ all_sizes = lambda { [Person.count, Post.count, Comment.count] }
232
+
233
+ lambda {
234
+ Comment.rose_for(:author_comments)
235
+ }.should_not change(all_sizes, :call)
236
+ end
237
+ end
238
+
239
+ describe "import report" do
240
+ before do
241
+ Post.rose(:with_update) {
242
+ rows do
243
+ identity(:guid => "ID")
244
+ column("Title", &:title)
245
+ column("Comments") { |item| item.comments.size }
246
+ end
247
+
248
+ sort("Comments", :descending)
249
+
250
+ roots do
251
+ find do |items, idy|
252
+ items.find { |item| item.guid == idy }
253
+ end
254
+ update do |record, updates|
255
+ record.update_attribute(:title, updates["Title"])
256
+ end
257
+ end
258
+ }
259
+
260
+ @post_3 = Post.create(:title => "Post #3", :guid => "P3")
261
+ @post_4 = Post.create(:title => "Post #4", :guid => "P4")
262
+ end
263
+
264
+ after do
265
+ @post_3.destroy; @post_4.destroy
266
+ end
267
+
268
+ it "should update report" do
269
+ Post.root_for(:with_update, {
270
+ :with => {
271
+ "P3" => { "Title" => "Third Post", "something" => "else" },
272
+ "P4" => { "Title" => "Fourth Post" }
273
+ }
274
+ }).should match_table <<-eo_table.gsub(%r{^ }, '')
275
+ +-----------------------------+
276
+ | ID | Title | Comments |
277
+ +-----------------------------+
278
+ | P1 | Post #1 | 2 |
279
+ | P2 | Post #2 | 1 |
280
+ | P4 | Fourth Post | 0 |
281
+ | P3 | Third Post | 0 |
282
+ +-----------------------------+
283
+ eo_table
284
+
285
+ Post.all.map(&:title).should == ["Post #1", "Post #2", "Third Post", "Fourth Post"]
286
+ end
287
+
288
+ it "should update report with conditions" do
289
+ Post.root_for(:with_update, {
290
+ :with => {
291
+ "P3" => { "Title" => "Third Post", "something" => "else" },
292
+ "P4" => { "Title" => "Fourth Post" }
293
+ }
294
+ }, { :conditions => ["title like ?", "%#3%"] }).should match_table <<-eo_table.gsub(%r{^ }, '')
295
+ +----------------------------+
296
+ | ID | Title | Comments |
297
+ +----------------------------+
298
+ | P3 | Third Post | 0 |
299
+ +----------------------------+
300
+ eo_table
301
+
302
+ Post.all.map(&:title).should == ["Post #1", "Post #2", "Third Post", "Post #4"]
303
+ end
304
+
305
+ it "should update report from CSV" do
306
+ Post.root_for(:with_update, {
307
+ :with => "spec/examples/update_posts.csv"
308
+ }).should match_table <<-eo_table.gsub(%r{^ }, '')
309
+ +-----------------------------+
310
+ | ID | Title | Comments |
311
+ +-----------------------------+
312
+ | P1 | Post #1 | 2 |
313
+ | P2 | Post #2 | 1 |
314
+ | P4 | Fourth Post | 0 |
315
+ | P3 | Third Post | 0 |
316
+ +-----------------------------+
317
+ eo_table
318
+
319
+ Post.all.map(&:title).should == ["Post #1", "Post #2", "Third Post", "Fourth Post"]
320
+ end
321
+ end
322
+
323
+ describe "preview import report" do
324
+ before do
325
+ Post.rose(:for_import) {
326
+ rows do
327
+ identity(:guid => "ID")
328
+ column("Title", &:title)
329
+ column("Comments") { |item| item.comments.size }
330
+ end
331
+
332
+ sort("Comments", :descending)
333
+
334
+ roots do
335
+ find do |items, idy|
336
+ items.find { |item| item.guid == idy }
337
+ end
338
+ preview_update do |record, updates|
339
+ record.title = updates["Title"]
340
+ end
341
+ update { raise Exception, "not me!" }
342
+ end
343
+ }
344
+ end
345
+
346
+ it "should preview changes" do
347
+ Post.root_for(:for_import, {
348
+ :with => {
349
+ "P1" => { "Title" => "First Post", "something" => "else" },
350
+ "P2" => { "Title" => "Second Post" }
351
+ },
352
+ :preview => true
353
+ }).should match_table <<-eo_table.gsub(%r{^ }, '')
354
+ +-----------------------------+
355
+ | ID | Title | Comments |
356
+ +-----------------------------+
357
+ | P1 | First Post | 2 |
358
+ | P2 | Second Post | 1 |
359
+ +-----------------------------+
360
+ eo_table
361
+
362
+ Post.all.map(&:title).should == ["Post #1", "Post #2"]
363
+ end
364
+ end
365
+
366
+ describe "create import report" do
367
+ before do
368
+ Post.rose(:for_create) {
369
+ rows do
370
+ identity(:guid => "ID")
371
+ column("Title", &:title)
372
+ column("Comments") { |item| item.comments.size }
373
+ end
374
+
375
+ sort("Comments", :descending)
376
+
377
+ roots do
378
+ find do |items, idy|
379
+ items.find { |item| item.guid == idy }
380
+ end
381
+ preview_create do |idy, updates|
382
+ post = Post.new(:guid => idy)
383
+ post.title = updates["Title"]
384
+ post
385
+ end
386
+ create do |idy, updates|
387
+ post = create_previewer.call(idy, updates)
388
+ post.save!
389
+ post
390
+ end
391
+ end
392
+ }
393
+ end
394
+
395
+ it "should preview create" do
396
+ Post.root_for(:for_create, {
397
+ :with => {
398
+ "P3" => { "Title" => "Post #3" }
399
+ },
400
+ :preview => true
401
+ }).should match_table <<-eo_table.gsub(%r{^ }, '')
402
+ +-------------------------+
403
+ | ID | Title | Comments |
404
+ +-------------------------+
405
+ | P1 | Post #1 | 2 |
406
+ | P2 | Post #2 | 1 |
407
+ | P3 | Post #3 | 0 |
408
+ +-------------------------+
409
+ eo_table
410
+ end
411
+
412
+ it "should create" do
413
+ Post.root_for(:for_create, {
414
+ :with => {
415
+ "P3" => { "Title" => "Post #3" }
416
+ }
417
+ }).should match_table <<-eo_table.gsub(%r{^ }, '')
418
+ +-------------------------+
419
+ | ID | Title | Comments |
420
+ +-------------------------+
421
+ | P1 | Post #1 | 2 |
422
+ | P2 | Post #2 | 1 |
423
+ | P3 | Post #3 | 0 |
424
+ +-------------------------+
425
+ eo_table
426
+
427
+ Post.last.title.should == "Post #3"
428
+
429
+ Post.last.destroy
430
+ end
431
+ end
432
+ end
433
+
434
+ end