autoforme 0.5.0

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.
data/spec/mtm_spec.rb ADDED
@@ -0,0 +1,333 @@
1
+ require './spec/spec_helper'
2
+
3
+ describe AutoForme do
4
+ before(:all) do
5
+ db_setup(:artists=>[[:name, :string]], :albums=>[[:name, :string]], :albums_artists=>[[:album_id, :integer, {:table=>:albums}], [:artist_id, :integer, {:table=>:artists}]])
6
+ model_setup(:Artist=>[:artists, [[:many_to_many, :albums]]], :Album=>[:albums, [[:many_to_many, :artists]]])
7
+ end
8
+ after(:all) do
9
+ Object.send(:remove_const, :Album)
10
+ Object.send(:remove_const, :Artist)
11
+ end
12
+
13
+ it "should have basic many to many association editing working" do
14
+ app_setup do
15
+ model Artist do
16
+ mtm_associations :albums
17
+ end
18
+ model Album
19
+ end
20
+
21
+ Artist.create(:name=>'Artist1')
22
+ Album.create(:name=>'Album1')
23
+ Album.create(:name=>'Album2')
24
+ Album.create(:name=>'Album3')
25
+
26
+ visit("/Artist/mtm_edit")
27
+ page.find('title').text.should == 'Artist - Many To Many Edit'
28
+ select("Artist1")
29
+ click_button "Edit"
30
+
31
+ select("albums")
32
+ click_button "Edit"
33
+
34
+ all('select')[0].all('option').map{|s| s.text}.should == ["Album1", "Album2", "Album3"]
35
+ all('select')[1].all('option').map{|s| s.text}.should == []
36
+ select("Album1", :from=>"Associate With")
37
+ click_button "Update"
38
+ page.html.should =~ /Updated albums association for Artist/
39
+ Artist.first.albums.map{|x| x.name}.should == %w'Album1'
40
+
41
+ all('select')[0].all('option').map{|s| s.text}.should == ["Album2", "Album3"]
42
+ all('select')[1].all('option').map{|s| s.text}.should == ["Album1"]
43
+ select("Album2", :from=>"Associate With")
44
+ select("Album3", :from=>"Associate With")
45
+ select("Album1", :from=>"Disassociate From")
46
+ click_button "Update"
47
+ Artist.first.refresh.albums.map{|x| x.name}.should == %w'Album2 Album3'
48
+
49
+ all('select')[0].all('option').map{|s| s.text}.should == ["Album1"]
50
+ all('select')[1].all('option').map{|s| s.text}.should == ["Album2", "Album3"]
51
+ end
52
+
53
+ it "should have many to many association editing working with autocompletion" do
54
+ app_setup do
55
+ model Artist do
56
+ mtm_associations :albums
57
+ end
58
+ model Album do
59
+ autocomplete_options({})
60
+ end
61
+ end
62
+
63
+ Artist.create(:name=>'Artist1')
64
+ a1 = Album.create(:name=>'Album1')
65
+ a2 = Album.create(:name=>'Album2')
66
+ a3 = Album.create(:name=>'Album3')
67
+
68
+ visit("/Artist/mtm_edit")
69
+ select("Artist1")
70
+ click_button "Edit"
71
+
72
+ select("albums")
73
+ click_button "Edit"
74
+
75
+ all('select')[0].all('option').map{|s| s.text}.should == []
76
+ fill_in "Associate With", :with=>a1.id
77
+ click_button "Update"
78
+ page.html.should =~ /Updated albums association for Artist/
79
+ Artist.first.albums.map{|x| x.name}.should == %w'Album1'
80
+
81
+ all('select')[0].all('option').map{|s| s.text}.should == ["Album1"]
82
+ fill_in "Associate With", :with=>a2.id
83
+ select("Album1", :from=>"Disassociate From")
84
+ click_button "Update"
85
+ Artist.first.refresh.albums.map{|x| x.name}.should == %w'Album2'
86
+
87
+ all('select')[0].all('option').map{|s| s.text}.should == ["Album2"]
88
+ select("Album2", :from=>"Disassociate From")
89
+ click_button "Update"
90
+ Artist.first.refresh.albums.map{|x| x.name}.should == []
91
+ all('select')[0].all('option').map{|s| s.text}.should == []
92
+ end
93
+
94
+ it "should have inline many to many association editing working" do
95
+ app_setup do
96
+ model Artist do
97
+ inline_mtm_associations :albums
98
+ end
99
+ model Album
100
+ end
101
+
102
+ Artist.create(:name=>'Artist1')
103
+ Album.create(:name=>'Album1')
104
+ Album.create(:name=>'Album2')
105
+ Album.create(:name=>'Album3')
106
+
107
+ visit("/Artist/edit")
108
+ select("Artist1")
109
+ click_button "Edit"
110
+ select 'Album1'
111
+ click_button 'Add'
112
+ page.html.should =~ /Updated albums association for Artist/
113
+ Artist.first.albums.map{|x| x.name}.should == %w'Album1'
114
+
115
+ select 'Album2'
116
+ click_button 'Add'
117
+ Artist.first.refresh.albums.map{|x| x.name}.sort.should == %w'Album1 Album2'
118
+
119
+ click_button 'Remove'
120
+ Artist.first.refresh.albums.map{|x| x.name}.should == %w'Album2'
121
+
122
+ select 'Album3'
123
+ click_button 'Add'
124
+ Artist.first.refresh.albums.map{|x| x.name}.sort.should == %w'Album2 Album3'
125
+ end
126
+
127
+ it "should have inline many to many association editing working with autocompletion" do
128
+ app_setup do
129
+ model Artist do
130
+ inline_mtm_associations :albums
131
+ end
132
+ model Album do
133
+ autocomplete_options({})
134
+ end
135
+ end
136
+
137
+ Artist.create(:name=>'Artist1')
138
+ a1 = Album.create(:name=>'Album1')
139
+ a2 = Album.create(:name=>'Album2')
140
+ a3 = Album.create(:name=>'Album3')
141
+
142
+ visit("/Artist/edit")
143
+ select("Artist1")
144
+ click_button "Edit"
145
+ fill_in 'Albums', :with=>a1.id.to_s
146
+ click_button 'Add'
147
+ page.html.should =~ /Updated albums association for Artist/
148
+ Artist.first.albums.map{|x| x.name}.should == %w'Album1'
149
+
150
+ fill_in 'Albums', :with=>a2.id.to_s
151
+ click_button 'Add'
152
+ Artist.first.refresh.albums.map{|x| x.name}.sort.should == %w'Album1 Album2'
153
+
154
+ click_button 'Remove'
155
+ Artist.first.refresh.albums.map{|x| x.name}.should == %w'Album2'
156
+
157
+ fill_in 'Albums', :with=>a3.id.to_s
158
+ click_button 'Add'
159
+ Artist.first.refresh.albums.map{|x| x.name}.sort.should == %w'Album2 Album3'
160
+ end
161
+
162
+ it "should have working many to many association links on show and edit pages" do
163
+ app_setup do
164
+ model Artist do
165
+ mtm_associations :albums
166
+ association_links :all_except_mtm
167
+ end
168
+ model Album do
169
+ mtm_associations [:artists]
170
+ association_links :all
171
+ end
172
+ end
173
+
174
+ visit("/Artist/new")
175
+ fill_in 'Name', :with=>'Artist1'
176
+ click_button 'Create'
177
+ click_link 'Edit'
178
+ select 'Artist1'
179
+ click_button 'Edit'
180
+ page.html.should_not =~ /Albums/
181
+
182
+ visit("/Album/new")
183
+ fill_in 'Name', :with=>'Album1'
184
+ click_button 'Create'
185
+ click_link 'Edit'
186
+ select 'Album1'
187
+ click_button 'Edit'
188
+ click_link 'associate'
189
+ select("Artist1", :from=>"Associate With")
190
+ click_button 'Update'
191
+ click_link 'Show'
192
+ select 'Album1'
193
+ click_button 'Show'
194
+ click_link 'Artist1'
195
+ page.current_path.should =~ %r{Artist/show/\d+}
196
+ page.html.should_not =~ /Albums/
197
+ end
198
+
199
+ it "should have many to many association editing working when associated class is not using autoforme" do
200
+ app_setup do
201
+ model Artist do
202
+ mtm_associations [:albums]
203
+ end
204
+ end
205
+
206
+ Artist.create(:name=>'Artist1')
207
+ Album.create(:name=>'Album1')
208
+ Album.create(:name=>'Album2')
209
+ Album.create(:name=>'Album3')
210
+
211
+ visit("/Artist/mtm_edit")
212
+ select("Artist1")
213
+ click_button "Edit"
214
+
215
+ select("albums")
216
+ click_button "Edit"
217
+
218
+ all('select')[0].all('option').map{|s| s.text}.should == ["Album1", "Album2", "Album3"]
219
+ all('select')[1].all('option').map{|s| s.text}.should == []
220
+ select("Album1", :from=>"Associate With")
221
+ click_button "Update"
222
+ Artist.first.refresh.albums.map{|x| x.name}.should == %w'Album1'
223
+
224
+ all('select')[0].all('option').map{|s| s.text}.should == ["Album2", "Album3"]
225
+ all('select')[1].all('option').map{|s| s.text}.should == ["Album1"]
226
+ select("Album2", :from=>"Associate With")
227
+ select("Album3", :from=>"Associate With")
228
+ select("Album1", :from=>"Disassociate From")
229
+ click_button "Update"
230
+ Artist.first.refresh.albums.map{|x| x.name}.should == %w'Album2 Album3'
231
+
232
+ all('select')[0].all('option').map{|s| s.text}.should == ["Album1"]
233
+ all('select')[1].all('option').map{|s| s.text}.should == ["Album2", "Album3"]
234
+ end
235
+
236
+ it "should use filter/order from associated class" do
237
+ app_setup do
238
+ model Artist do
239
+ mtm_associations :all
240
+ end
241
+ model Album do
242
+ filter{|ds, req| ds.where(:name=>'A'..'M')}
243
+ order :name
244
+ end
245
+ end
246
+
247
+ Artist.create(:name=>'Artist1')
248
+ Album.create(:name=>'E1')
249
+ Album.create(:name=>'B1')
250
+ Album.create(:name=>'O1')
251
+
252
+ visit("/Artist/mtm_edit")
253
+ select("Artist1")
254
+ click_button "Edit"
255
+ select("albums")
256
+ click_button "Edit"
257
+
258
+ all('select')[0].all('option').map{|s| s.text}.should == ["B1", "E1"]
259
+ all('select')[1].all('option').map{|s| s.text}.should == []
260
+ select("E1", :from=>"Associate With")
261
+ click_button "Update"
262
+ Artist.first.albums.map{|x| x.name}.should == %w'E1'
263
+
264
+ all('select')[0].all('option').map{|s| s.text}.should == ["B1"]
265
+ all('select')[1].all('option').map{|s| s.text}.should == ["E1"]
266
+ select("B1", :from=>"Associate With")
267
+ select("E1", :from=>"Disassociate From")
268
+ click_button "Update"
269
+ Artist.first.refresh.albums.map{|x| x.name}.should == %w'B1'
270
+
271
+ all('select')[0].all('option').map{|s| s.text}.should == ["E1"]
272
+ all('select')[1].all('option').map{|s| s.text}.should == ["B1"]
273
+
274
+ select("B1", :from=>"Disassociate From")
275
+ Album.where(:name=>'B1').update(:name=>'Z1')
276
+ proc{click_button "Update"}.should raise_error(Sequel::NoMatchingRow)
277
+
278
+ visit('/Artist/mtm_edit')
279
+ select("Artist1")
280
+ click_button "Edit"
281
+ select("albums")
282
+ click_button "Edit"
283
+ select("E1", :from=>"Associate With")
284
+ Album.where(:name=>'E1').update(:name=>'Y1')
285
+ proc{click_button "Update"}.should raise_error(Sequel::NoMatchingRow)
286
+
287
+ visit('/Artist/mtm_edit')
288
+ select("Artist1")
289
+ click_button "Edit"
290
+ select("albums")
291
+ click_button "Edit"
292
+ all('select')[0].all('option').map{|s| s.text}.should == []
293
+ all('select')[1].all('option').map{|s| s.text}.should == []
294
+ end
295
+
296
+ it "should support column options on mtm_edit page" do
297
+ app_setup do
298
+ model Artist do
299
+ mtm_associations :albums
300
+ column_options :albums=>{:as=>:checkbox, :remove=>{:name_method=>proc{|obj| obj.name * 2}}}
301
+ end
302
+ model Album do
303
+ display_name{|obj, req| obj.name + "2"}
304
+ end
305
+ end
306
+
307
+ Artist.create(:name=>'Artist1')
308
+ Album.create(:name=>'Album1')
309
+ Album.create(:name=>'Album2')
310
+ Album.create(:name=>'Album3')
311
+
312
+ visit("/Artist/mtm_edit")
313
+ select("Artist1")
314
+ click_button "Edit"
315
+
316
+ select("albums")
317
+ click_button "Edit"
318
+
319
+ check "Album12"
320
+ click_button "Update"
321
+ Artist.first.albums.map{|x| x.name}.should == %w'Album1'
322
+
323
+ check "Album1Album1"
324
+ check "Album22"
325
+ check "Album32"
326
+ click_button "Update"
327
+ Artist.first.refresh.albums.map{|x| x.name}.should == %w'Album2 Album3'
328
+
329
+ check "Album12"
330
+ check "Album2Album2"
331
+ check "Album3Album3"
332
+ end
333
+ end
@@ -0,0 +1,75 @@
1
+ require 'rubygems'
2
+ require 'action_controller/railtie'
3
+ require 'autoforme'
4
+
5
+ RSpec.configure do |c|
6
+ c.after(:each) do |example|
7
+ if Object.const_defined?(:AutoformeController)
8
+ Object.send(:remove_const, :AutoformeController)
9
+ Rails.application = nil
10
+ end
11
+ end
12
+ end
13
+
14
+ class AutoFormeSpec::App
15
+ def self.autoforme(klass=nil, opts={}, &block)
16
+ sc = Class.new(Rails::Application)
17
+ framework = nil
18
+ sc.class_eval do
19
+ controller = Class.new(ActionController::Base)
20
+ Object.send(:const_set, :AutoformeController, controller)
21
+
22
+ resolver = Class.new(ActionView::Resolver)
23
+ resolver.class_eval do
24
+ template = ActionView::Template
25
+ t = [template.new(<<HTML, "layout", template.handler_for_extension(:erb), {:virtual_path=>'layout', :format=>'erb', :updated_at=>Time.now})]
26
+ <!DOCTYPE html>
27
+ <html>
28
+ <head><title><%= @autoforme_action.title if @autoforme_action %></title></head>
29
+ <body>
30
+ <% if flash[:notice] %>
31
+ <div class="alert alert-success"><p><%= flash[:notice] %></p></div>
32
+ <% end %>
33
+ <% if flash[:error] %>
34
+ <div class="alert alert-error"><p><%= flash[:error] %></p></div>
35
+ <% end %>
36
+ <%= yield %>
37
+ </body></html>"
38
+ HTML
39
+
40
+ define_method(:find_templates){|*args| t}
41
+ end
42
+
43
+ controller.class_eval do
44
+ self.view_paths = resolver.new
45
+ layout 'layout'
46
+
47
+ def session_set
48
+ session.merge!(params)
49
+ render :text=>''
50
+ end
51
+
52
+ AutoForme.for(:rails, self, opts) do
53
+ framework = self
54
+ model_type :sequel
55
+ if klass
56
+ model(klass, &block)
57
+ elsif block
58
+ instance_eval(&block)
59
+ end
60
+ end
61
+ end
62
+
63
+ config.secret_token = routes.append do
64
+ get 'session/set', :controller=>'autoforme', :action=>'session_set'
65
+ end.inspect
66
+ config.active_support.deprecation = :stderr
67
+ config.middleware.delete(ActionDispatch::ShowExceptions)
68
+ config.middleware.delete("Rack::Lock")
69
+ config.secret_key_base = 'foo'
70
+ config.eager_load = true
71
+ initialize!
72
+ end
73
+ [sc, framework]
74
+ end
75
+ end
@@ -0,0 +1,44 @@
1
+ require 'rubygems'
2
+ require 'sequel'
3
+ require 'logger'
4
+
5
+ RSpec.configure do |c|
6
+ c.around(:each) do |example|
7
+ if db
8
+ db.transaction(:rollback=>:always){example.run}
9
+ else
10
+ example.run
11
+ end
12
+ end
13
+ end
14
+
15
+ module AutoFormeSpec
16
+ TYPE_MAP = {:string=>String, :integer=>Integer}
17
+ def self.db_setup(tables)
18
+ db = Sequel.connect(ENV['DATABASE_URL'] || 'sqlite:/')
19
+ #db.loggers << Logger.new($stdout)
20
+ tables.each do |table, columns|
21
+ db.create_table(table) do
22
+ primary_key :id
23
+ columns.each do |name, type, opts|
24
+ column name, TYPE_MAP[type], opts||{}
25
+ end
26
+ end
27
+ end
28
+ db
29
+ end
30
+
31
+ def self.model_setup(db, models)
32
+ models.each do |name, (table, associations)|
33
+ klass = Class.new(Sequel::Model(db[table]))
34
+ Object.const_set(name, klass)
35
+ klass.class_eval do
36
+ if associations
37
+ associations.each do |type, assoc, opts|
38
+ associate(type, assoc, opts||{})
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,53 @@
1
+ require 'rubygems'
2
+ require 'sinatra/base'
3
+ require 'autoforme'
4
+ require 'sinatra/flash'
5
+ require 'rack/csrf'
6
+
7
+ class AutoFormeSpec::App < Sinatra::Base
8
+ disable :run
9
+ enable :sessions
10
+ enable :raise_errors
11
+ set :environment, "test"
12
+ register Sinatra::Flash
13
+ use Rack::Csrf
14
+
15
+ get '/session/set' do
16
+ session.merge!(params)
17
+ ''
18
+ end
19
+
20
+ template :layout do
21
+ <<HTML
22
+ <!DOCTYPE html>
23
+ <html>
24
+ <head><title><%= @autoforme_action.title if @autoforme_action %></title></head>
25
+ <body>
26
+ <% if flash[:notice] %>
27
+ <div class="alert alert-success"><p><%= flash[:notice] %></p></div>
28
+ <% end %>
29
+ <% if flash[:error] %>
30
+ <div class="alert alert-error"><p><%= flash[:error] %></p></div>
31
+ <% end %>
32
+ <%= yield %>
33
+ </body></html>"
34
+ HTML
35
+ end
36
+
37
+ def self.autoforme(klass=nil, opts={}, &block)
38
+ sc = Class.new(self)
39
+ framework = nil
40
+ sc.class_eval do
41
+ AutoForme.for(:sinatra, self, opts) do
42
+ framework = self
43
+ model_type :sequel
44
+ if klass
45
+ model(klass, &block)
46
+ elsif block
47
+ instance_eval(&block)
48
+ end
49
+ end
50
+ end
51
+ [sc, framework]
52
+ end
53
+ end
@@ -0,0 +1,51 @@
1
+ require 'rubygems'
2
+ require 'capybara'
3
+ require 'capybara/dsl'
4
+ require 'capybara/rspec/matchers'
5
+ require 'rack/test'
6
+
7
+ module AutoFormeSpec
8
+ end
9
+
10
+ require './spec/sequel_spec_helper'
11
+
12
+ case ENV['FRAMEWORK']
13
+ when 'rails'
14
+ require './spec/rails_spec_helper'
15
+ else
16
+ require './spec/sinatra_spec_helper'
17
+ end
18
+
19
+ RSpec::Core::ExampleGroup.class_eval do
20
+ include Rack::Test::Methods
21
+ include Capybara::DSL
22
+ include Capybara::RSpecMatchers
23
+
24
+ attr_reader :app
25
+ attr_reader :db
26
+ attr_reader :framework
27
+ attr_reader :model
28
+
29
+ def app=(app)
30
+ @app = Capybara.app = app
31
+ end
32
+
33
+ def db_setup(tables, &block)
34
+ @db = AutoFormeSpec.db_setup(tables)
35
+ end
36
+
37
+ def model_setup(models)
38
+ AutoFormeSpec.model_setup(db, models)
39
+ end
40
+
41
+ def app_setup(klass=nil, opts={}, &block)
42
+ app, @framework = AutoFormeSpec::App.autoforme(klass, opts, &block)
43
+ self.app = app
44
+ @model = @framework.models[klass.name] if klass
45
+ end
46
+
47
+ after do
48
+ Capybara.reset_sessions!
49
+ Capybara.use_default_driver
50
+ end
51
+ end