resource_this 1.0.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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 3d1ca98d91b7f77a27fd92f24d30117981c181d9
4
+ data.tar.gz: cb660dc5474ca506caa49a54c381ac8b44816450
5
+ SHA512:
6
+ metadata.gz: b59545fc746ce5d24ebdfd6b26d3dd6ef950ab0715ee6bfc63ea85eadc0a3cbebd5c622094e98865b06883364594ad5d98f627800e5fa844d28119d9e2e38a9c
7
+ data.tar.gz: c6f07405700cb3f79e0dc2fe1e3842508120d3e21a3438c9ef9ab3f2fcc0d40ad845817650c47577ba151e237937c9dda664e232fb1080255e29003f6663387b
data/.gitignore ADDED
@@ -0,0 +1,5 @@
1
+ doc/
2
+ pkg/
3
+ Gemfile.lock
4
+ *.gemfile.lock
5
+ coverage
data/CHANGELOG.md ADDED
@@ -0,0 +1,10 @@
1
+ # 1.0.0
2
+
3
+ * Gem-ification work
4
+ * Revert returning true { ... }, since it no longer exists in Rails 3.2
5
+
6
+ # Pre 1.0.0
7
+
8
+ * Added resource_this generator
9
+ * Add support for :path_prefix options on resource_this. Useful for admin namespaced controllers
10
+ * wrap some before_filters in returning true { ... } do
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in ar_protobuf_store.gemspec
4
+ gemspec
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2004-2007 Jesse Newland
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,200 @@
1
+ resouce_this
2
+ ===========
3
+
4
+ Not scaffolding. Resourcing. Creates extremely customizable resource controllers with one line of code.
5
+
6
+
7
+ ```ruby
8
+ class PostsController < ActionController::Base
9
+ resource_this
10
+ end
11
+ ```
12
+
13
+ ...will generate the following code:
14
+
15
+ ```ruby
16
+ class PostsController < ActionController::Base
17
+ before_filter :load_post, :only => [ :show, :edit, :update, :destroy ]
18
+ before_filter :load_posts, :only => [ :index ]
19
+ before_filter :new_post, :only => [ :new ]
20
+ before_filter :create_post, :only => [ :create ]
21
+ before_filter :update_post, :only => [ :update ]
22
+ before_filter :destroy_post, :only => [ :destroy ]
23
+
24
+ protected
25
+ def load_post
26
+ @post = Post.find(params[:id])
27
+ end
28
+
29
+ def new_post
30
+ @post = Post.new
31
+ end
32
+
33
+ def create_post
34
+ @post = Post.new(params[:post])
35
+ @created = @post.save
36
+ return true
37
+ end
38
+
39
+ def update_post
40
+ @updated = @post.update_attributes(params[:post])
41
+ return true
42
+ end
43
+
44
+ def destroy_post
45
+ @post = @post.destroy
46
+ end
47
+
48
+ def load_posts
49
+ @posts = Post.find(:all)
50
+ end
51
+
52
+ public
53
+ def index
54
+ respond_to do |format|
55
+ format.html
56
+ format.xml { render :xml => @posts }
57
+ format.js
58
+ end
59
+ end
60
+
61
+ def show
62
+ respond_to do |format|
63
+ format.html
64
+ format.xml { render :xml => @post }
65
+ format.js
66
+ end
67
+ end
68
+
69
+ def new
70
+ respond_to do |format|
71
+ format.html { render :action => :edit }
72
+ format.xml { render :xml => @post }
73
+ format.js
74
+ end
75
+ end
76
+
77
+ def create
78
+ respond_to do |format|
79
+ if @created
80
+ flash[:notice] = 'Post was successfully created.'
81
+ format.html { redirect_to @post }
82
+ format.xml { render :xml => @post, :status => :created, :location => @post }
83
+ format.js
84
+ else
85
+ format.html { render :action => :new }
86
+ format.xml { render :xml => @post.errors, :status => :unprocessable_entity }
87
+ format.js
88
+ end
89
+ end
90
+ end
91
+
92
+ def edit
93
+ respond_to do |format|
94
+ format.html
95
+ format.js
96
+ end
97
+ end
98
+
99
+ def update
100
+ respond_to do |format|
101
+ if @updated
102
+ flash[:notice] = 'Post was successfully updated.'
103
+ format.html { redirect_to @post }
104
+ format.xml { head :ok }
105
+ format.js
106
+ else
107
+ format.html { render :action => :edit }
108
+ format.xml { render :xml => @post.errors, :status => :unprocessable_entity }
109
+ format.js
110
+ end
111
+ end
112
+ end
113
+
114
+ def destroy
115
+ respond_to do |format|
116
+ format.html { redirect_to :action => posts_url }
117
+ format.xml { head :ok }
118
+ format.js
119
+ end
120
+ end
121
+ end
122
+ ```
123
+
124
+ Nested Resources
125
+ ===========
126
+
127
+ ```ruby
128
+ class CommentsController < ActionController::Base
129
+ resource_this :nested => [:posts]
130
+ end
131
+ ```
132
+
133
+ This generates a very similar controller to the one above with adjusted redirects and one additional before_filter / loader method pair to grab the parent resource. In this case:
134
+
135
+ ```ruby
136
+ before_filter :load_post
137
+
138
+ def load_post
139
+ @post = Post.find(params[:post_id])
140
+ end
141
+ ```
142
+
143
+ Sorting, etc
144
+ ===========
145
+
146
+ ```ruby
147
+ class CommentsController < ActionController::Base
148
+ resource_this :finder_options => {:order => 'created_on'}
149
+ end
150
+ ```
151
+
152
+ ...or, for lazily evaluated sorting options:
153
+
154
+ ```ruby
155
+ class CommentsController < ActionController::Base
156
+ resource_this :finder_options => Proc.new { finder_options }
157
+
158
+ protected
159
+
160
+ def finder_options
161
+ order = case params[:sort]
162
+ when 'date_reverse' then 'created_on desc'
163
+ else 'created_on'
164
+ end
165
+ {:order => order, :limit => params[:limit] || 10 }
166
+ end
167
+
168
+ end
169
+ ```
170
+
171
+ will_paginate
172
+ ===========
173
+
174
+ will_paginate support is baked right in:
175
+
176
+ ```ruby
177
+ class CommentsController < ActionController::Base
178
+ resource_this :will_paginate => true
179
+ end
180
+ ```
181
+
182
+ This works with the :finder_options option as well
183
+
184
+ Opinionated Software
185
+ ===========
186
+
187
+ The separation of logic - DB operations in before_filters, rendering in the standard resource controller methods - makes this approach ridiculously easy to customize. Need to load an additional object for the :show action? Slap another before_filter on it. Need to change the path that the :update action redirects to? Override the :update action with your new rendering behavior.
188
+
189
+ Generator
190
+ ===========
191
+
192
+ A resource_this generator is included - does the same thing as the 'resource' generator but adds 'resource_this' to the generated controller.
193
+
194
+ Questions? Comments? Flames? Patches?
195
+ ===========
196
+ jnewland@gmail.com
197
+
198
+ Copyright
199
+ ===========
200
+ Copyright (c) 2007 Jesse Newland, released under the MIT license
data/Rakefile ADDED
@@ -0,0 +1,25 @@
1
+ # encoding: utf-8
2
+
3
+ require "rubygems"
4
+ require "rake"
5
+ require "rake/testtask"
6
+
7
+ desc "Default: run unit tests."
8
+ task :default => :test
9
+
10
+ desc "Test the resource_this plugin."
11
+ Rake::TestTask.new(:test) do |t|
12
+ t.libs << "lib"
13
+ t.pattern = "test/**/*_test.rb"
14
+ t.verbose = true
15
+ end
16
+
17
+ begin
18
+ gem 'rubygems-tasks', '~> 0.2'
19
+ require 'rubygems/tasks'
20
+
21
+ Gem::Tasks.new
22
+ rescue LoadError => e
23
+ warn e.message
24
+ warn "Run `gem install rubygems-tasks` to install Gem::Tasks."
25
+ end
@@ -0,0 +1,24 @@
1
+ Description:
2
+ Stubs out a new resource including an empty model and controller suitable
3
+ for a restful, resource-oriented application. Pass the singular model name,
4
+ either CamelCased or under_scored, as the first argument, and an optional
5
+ list of attribute pairs.
6
+
7
+ Attribute pairs are column_name:sql_type arguments specifying the
8
+ model's attributes. Timestamps are added by default, so you don't have to
9
+ specify them by hand as 'created_at:datetime updated_at:datetime'.
10
+
11
+ You don't have to think up every attribute up front, but it helps to
12
+ sketch out a few so you can start working with the resource immediately.
13
+
14
+ This creates a model, controller, tests and fixtures for both, and the
15
+ corresponding map.resources declaration in config/routes.rb
16
+
17
+ This generates a DRY resource controller using resource_this:
18
+
19
+ http://jnewland.com/svn/public/ruby/rails/plugins/resource_this/README
20
+
21
+ Examples:
22
+ `./script/generate resource_this post` # no attributes
23
+ `./script/generate resource_this post title:string body:text published:boolean`
24
+ `./script/generate resource_this purchase order_id:integer amount:decimal`
@@ -0,0 +1,72 @@
1
+ class ResourceThisGenerator < Rails::Generator::NamedBase
2
+ default_options :skip_migration => false
3
+
4
+ attr_reader :controller_name,
5
+ :controller_class_path,
6
+ :controller_file_path,
7
+ :controller_class_nesting,
8
+ :controller_class_nesting_depth,
9
+ :controller_class_name,
10
+ :controller_singular_name,
11
+ :controller_plural_name
12
+ alias_method :controller_file_name, :controller_singular_name
13
+ alias_method :controller_table_name, :controller_plural_name
14
+
15
+ def initialize(runtime_args, runtime_options = {})
16
+ super
17
+
18
+ @controller_name = @name.pluralize
19
+
20
+ base_name, @controller_class_path, @controller_file_path, @controller_class_nesting, @controller_class_nesting_depth = extract_modules(@controller_name)
21
+ @controller_class_name_without_nesting, @controller_singular_name, @controller_plural_name = inflect_names(base_name)
22
+
23
+ if @controller_class_nesting.empty?
24
+ @controller_class_name = @controller_class_name_without_nesting
25
+ else
26
+ @controller_class_name = "#{@controller_class_nesting}::#{@controller_class_name_without_nesting}"
27
+ end
28
+ end
29
+
30
+ def manifest
31
+ record do |m|
32
+ # Check for class naming collisions.
33
+ m.class_collisions(controller_class_path, "#{controller_class_name}Controller", "#{controller_class_name}Helper")
34
+ m.class_collisions(class_path, "#{class_name}")
35
+
36
+ # Controller, helper, views, and test directories.
37
+ m.directory(File.join('app/models', class_path))
38
+ m.directory(File.join('app/controllers', controller_class_path))
39
+ m.directory(File.join('app/helpers', controller_class_path))
40
+ m.directory(File.join('app/views', controller_class_path, controller_file_name))
41
+ m.directory(File.join('test/functional', controller_class_path))
42
+ m.directory(File.join('test/unit', class_path))
43
+
44
+ m.dependency 'model', [singular_name] + @args, :collision => :skip
45
+
46
+ m.template(
47
+ 'controller.rb', File.join('app/controllers', controller_class_path, "#{controller_file_name}_controller.rb")
48
+ )
49
+
50
+ m.template('functional_test.rb', File.join('test/functional', controller_class_path, "#{controller_file_name}_controller_test.rb"))
51
+ m.template('helper.rb', File.join('app/helpers', controller_class_path, "#{controller_file_name}_helper.rb"))
52
+
53
+ m.route_resources controller_file_name
54
+ end
55
+ end
56
+
57
+ protected
58
+ def banner
59
+ "Usage: #{$0} resource_this ModelName [field:type, field:type]"
60
+ end
61
+
62
+ def add_options!(opt)
63
+ opt.separator ''
64
+ opt.separator 'Options:'
65
+ opt.on("--skip-migration",
66
+ "Don't generate a migration file for this model") { |v| options[:skip_migration] = v }
67
+ end
68
+
69
+ def model_name
70
+ class_name.demodulize
71
+ end
72
+ end
@@ -0,0 +1,3 @@
1
+ class <%= controller_class_name %>Controller < ApplicationController
2
+ resource_this
3
+ end
@@ -0,0 +1,59 @@
1
+ require File.dirname(__FILE__) + '<%= '/..' * controller_class_nesting_depth %>/../test_helper'
2
+ require '<%= controller_file_path %>_controller'
3
+
4
+ # Re-raise errors caught by the controller.
5
+ class <%= controller_class_name %>Controller; def rescue_action(e) raise e end; end
6
+
7
+ class <%= controller_class_name %>ControllerTest < Test::Unit::TestCase
8
+ fixtures :<%= table_name %>
9
+
10
+ def setup
11
+ @controller = <%= controller_class_name %>Controller.new
12
+ @request = ActionController::TestRequest.new
13
+ @response = ActionController::TestResponse.new
14
+ end
15
+
16
+ def test_should_get_index
17
+ get :index
18
+ assert_response :success
19
+ assert assigns(:<%= table_name %>)
20
+ end
21
+
22
+ def test_should_get_new
23
+ @request.accept = 'application/xml'
24
+ get :new
25
+ assert_response :success
26
+ end
27
+
28
+ def test_should_create_<%= file_name %>
29
+ assert_difference('<%= class_name %>.count') do
30
+ post :create, :<%= file_name %> => { }
31
+ end
32
+
33
+ assert_redirected_to <%= file_name %>_path(assigns(:<%= file_name %>))
34
+ end
35
+
36
+ def test_should_show_<%= file_name %>
37
+ @request.accept = 'application/xml'
38
+ get :show, :id => 1
39
+ assert_response :success
40
+ end
41
+
42
+ def test_should_get_edit
43
+ #TODO: replace this with a real test once views are in place
44
+ assert true
45
+ end
46
+
47
+ def test_should_update_<%= file_name %>
48
+ put :update, :id => 1, :<%= file_name %> => { }
49
+ assert_redirected_to <%= file_name %>_path(assigns(:<%= file_name %>))
50
+ end
51
+
52
+ def test_should_destroy_<%= file_name %>
53
+ assert_difference('<%= class_name %>.count', -1) do
54
+ delete :destroy, :id => 1
55
+ end
56
+
57
+ assert_redirected_to <%= table_name %>_path
58
+ end
59
+ end
@@ -0,0 +1,2 @@
1
+ module <%= controller_class_name %>Helper
2
+ end
data/init.rb ADDED
@@ -0,0 +1 @@
1
+ ActionController::Base.send :include, ResourceThis
@@ -0,0 +1,208 @@
1
+ module ResourceThis # :nodoc:
2
+ def self.included(base)
3
+ base.extend(ClassMethods)
4
+ end
5
+
6
+ module ClassMethods
7
+ def resource_this(options = {})
8
+ options.assert_valid_keys(:class_name, :will_paginate, :finder_options, :nested, :path_prefix)
9
+
10
+ singular_name = controller_name.singularize
11
+ singular_name = options[:class_name].downcase.singularize unless options[:class_name].nil?
12
+ class_name = options[:class_name] || singular_name.camelize
13
+ plural_name = singular_name.pluralize
14
+ will_paginate_index = options[:will_paginate] || false
15
+ resource_url = "#{singular_name}_url(@#{singular_name})"
16
+ collection_url = "#{plural_name}_url"
17
+ resource_url = options[:path_prefix] + resource_url unless options[:path_prefix].nil?
18
+ collection_url = options[:path_prefix] + collection_url unless options[:path_prefix].nil?
19
+
20
+ class_attribute :resource_this_finder_options
21
+ self.resource_this_finder_options = options[:finder_options] || {}
22
+
23
+ unless options[:nested].nil?
24
+ nested = options[:nested].to_s.singularize
25
+ nested_class = nested.camelize
26
+ nested_resource_url = "#{nested}_#{singular_name}_url(" + [nested, singular_name].map { |route| "@#{route}"}.join(', ') + ')'
27
+ nested_collection_url = "#{nested}_#{plural_name}_url(@#{nested})"
28
+ nested_resource_url = options[:path_prefix] + nested_resource_url unless options[:path_prefix].nil?
29
+ nested_collection_url = options[:path_prefix] + nested_collection_url unless options[:path_prefix].nil?
30
+ module_eval <<-"end_eval", __FILE__, __LINE__
31
+ before_filter :load_#{nested}
32
+ end_eval
33
+ end
34
+
35
+ #standard before_filters
36
+ module_eval <<-"end_eval", __FILE__, __LINE__
37
+ before_filter :load_#{singular_name}, :only => [ :show, :edit, :update, :destroy ]
38
+ before_filter :load_#{plural_name}, :only => [ :index ]
39
+ before_filter :new_#{singular_name}, :only => [ :new ]
40
+ before_filter :create_#{singular_name}, :only => [ :create ]
41
+ before_filter :update_#{singular_name}, :only => [ :update ]
42
+ before_filter :destroy_#{singular_name}, :only => [ :destroy ]
43
+
44
+ protected
45
+
46
+ def finder_options
47
+ resource_this_finder_options.class == Proc ? resource_this_finder_options.call : {}
48
+ end
49
+
50
+ end_eval
51
+
52
+ if options[:nested].nil?
53
+ module_eval <<-"end_eval", __FILE__, __LINE__
54
+ def finder_base
55
+ #{class_name}
56
+ end
57
+
58
+ def collection
59
+ #{class_name}.find(:all, finder_options)
60
+ end
61
+
62
+ def collection_url
63
+ #{collection_url}
64
+ end
65
+
66
+ def resource_url
67
+ #{resource_url}
68
+ end
69
+ end_eval
70
+ else
71
+ module_eval <<-"end_eval", __FILE__, __LINE__
72
+ def load_#{nested}
73
+ @#{nested} = #{nested_class}.find(params[:#{nested}_id]) rescue nil
74
+ end
75
+
76
+ def finder_base
77
+ @#{nested}.nil? ? #{class_name} : @#{nested}.#{plural_name}
78
+ end
79
+
80
+ def collection
81
+ @#{nested}.nil? ? #{class_name}.find(:all, finder_options) : @#{nested}.#{plural_name}.find(:all, finder_options)
82
+ end
83
+
84
+ def collection_url
85
+ @#{nested}.nil? ? #{collection_url} : #{nested_collection_url}
86
+ end
87
+
88
+ def resource_url
89
+ @#{nested}.nil? ? #{resource_url} : #{nested_resource_url}
90
+ end
91
+ end_eval
92
+ end
93
+
94
+ module_eval <<-"end_eval", __FILE__, __LINE__
95
+ def load_#{singular_name}
96
+ @#{singular_name} = finder_base.find(params[:id])
97
+ end
98
+
99
+ def new_#{singular_name}
100
+ @#{singular_name} = finder_base.new
101
+ end
102
+
103
+ def create_#{singular_name}
104
+ @#{singular_name} = finder_base.new(params[:#{singular_name}])
105
+ @created = @#{singular_name}.save
106
+ return true
107
+ end
108
+
109
+ def update_#{singular_name}
110
+ @updated = @#{singular_name}.update_attributes(params[:#{singular_name}])
111
+ return true
112
+ end
113
+
114
+ def destroy_#{singular_name}
115
+ @#{singular_name} = @#{singular_name}.destroy
116
+ end
117
+ end_eval
118
+
119
+ if will_paginate_index
120
+ module_eval <<-"end_eval", __FILE__, __LINE__
121
+ def load_#{plural_name}
122
+ @#{plural_name} = finder_base.paginate(finder_options.merge(:page => params[:page]))
123
+ end
124
+ end_eval
125
+ else
126
+ module_eval <<-"end_eval", __FILE__, __LINE__
127
+ def load_#{plural_name}
128
+ @#{plural_name} = collection
129
+ end
130
+ end_eval
131
+ end
132
+
133
+ module_eval <<-"end_eval", __FILE__, __LINE__
134
+ public
135
+ def index
136
+ respond_to do |format|
137
+ format.html
138
+ format.xml { render :xml => @#{plural_name} }
139
+ format.js
140
+ end
141
+ end
142
+
143
+ def show
144
+ respond_to do |format|
145
+ format.html
146
+ format.xml { render :xml => @#{singular_name} }
147
+ format.js
148
+ end
149
+ end
150
+
151
+ def new
152
+ respond_to do |format|
153
+ format.html { render :action => :edit }
154
+ format.xml { render :xml => @#{singular_name} }
155
+ format.js
156
+ end
157
+ end
158
+
159
+ def create
160
+ respond_to do |format|
161
+ if @created
162
+ flash[:notice] = '#{class_name} was successfully created.'
163
+ format.html { redirect_to(resource_url) }
164
+ format.xml { render :xml => @#{singular_name}, :status => :created, :location => resource_url }
165
+ format.js
166
+ else
167
+ format.html { render :action => :edit }
168
+ format.xml { render :xml => @#{singular_name}.errors, :status => :unprocessable_entity }
169
+ format.js
170
+ end
171
+ end
172
+ end
173
+
174
+ def edit
175
+ respond_to do |format|
176
+ format.html
177
+ format.js
178
+ end
179
+ end
180
+
181
+ def update
182
+ respond_to do |format|
183
+ if @updated
184
+ flash[:notice] = '#{class_name} was successfully updated.'
185
+ format.html { redirect_to(resource_url) }
186
+ format.xml { head :ok }
187
+ format.js
188
+ else
189
+ format.html { render :action => :edit }
190
+ format.xml { render :xml => @#{singular_name}.errors, :status => :unprocessable_entity }
191
+ format.js
192
+ end
193
+ end
194
+ end
195
+
196
+ def destroy
197
+ respond_to do |format|
198
+ format.html { redirect_to(collection_url) }
199
+ format.xml { head :ok }
200
+ format.js
201
+ end
202
+ end
203
+ end_eval
204
+ end
205
+ end
206
+ end
207
+
208
+ ActionController::Base.send :include, ResourceThis
@@ -0,0 +1,25 @@
1
+ spec = Gem::Specification.new do |s|
2
+ s.name = 'resource_this'
3
+ s.version = '1.0.0'
4
+ s.summary = "Not scaffolding. Resourcing. Creates extremely customizable resource controllers with one line of code."
5
+ s.description = %{Not scaffolding. Resourcing. Creates extremely customizable resource controllers with one line of code.
6
+
7
+ class PostsController < ActionController::Base
8
+ resource_this
9
+ end}
10
+ s.authors = ["Hsiu-Fan Wang", "Jesse Newland"]
11
+ s.email = "hfwang@porkbuns.net"
12
+ s.homepage = "https://github.com/hfwang/resource_this"
13
+
14
+ s.files = `git ls-files`.split($/)
15
+ s.executables = s.files.grep(%r{^bin/}).map { |f| File.basename(f) }
16
+ s.test_files = s.files.grep(%r{^(test|spec|features)/})
17
+ s.require_paths = ["lib"]
18
+
19
+
20
+ s.add_runtime_dependency "rails", "~> 3.2"
21
+
22
+ s.add_development_dependency "rspec", "~> 2.4"
23
+ s.add_development_dependency "rubygems-tasks", "~> 0.2"
24
+ s.add_development_dependency "yard", "~> 0.8"
25
+ end
@@ -0,0 +1,134 @@
1
+ require File.join(File.dirname(__FILE__), 'test_helper')
2
+
3
+ class ResourceThisNestingTest < Test::Unit::TestCase
4
+ def setup
5
+ @controller = CommentsController.new
6
+ @request = ActionController::TestRequest.new
7
+ @request.accept = 'application/xml'
8
+ @response = ActionController::TestResponse.new
9
+ @first = Post.create(:title => "test", :body => "test")
10
+ @second = Post.create(:title => "test2", :body => "test2")
11
+ @first_comment = Comment.create(:post => @first, :body => "test")
12
+ @second_comment = Comment.create(:post => @second, :body => "test")
13
+ ActionController::Routing::Routes.draw do |map|
14
+ map.resources :posts do |post|
15
+ post.resources :comments
16
+ end
17
+ map.resources :comments
18
+ end
19
+ end
20
+
21
+ def teardown
22
+ Post.find(:all).each { |post| post.destroy }
23
+ Comment.find(:all).each { |comment| comment.destroy }
24
+ end
25
+
26
+ def test_should_get_index
27
+ get :index, :post_id => @first.id
28
+ assert_response :success
29
+ assert_equal @first.comments, assigns(:comments)
30
+ assert_equal @first, assigns(:post)
31
+ end
32
+
33
+ def test_should_get_index_without_post
34
+ get :index
35
+ assert_response :success
36
+ assert assigns(:post).nil?
37
+ assert_equal Comment.find(:all), assigns(:comments)
38
+ end
39
+
40
+ def test_should_get_new
41
+ get :new, :post_id => @first.id
42
+ assert_response :success
43
+ assert assigns(:comment)
44
+ assert assigns(:post)
45
+ end
46
+
47
+ def test_should_get_new_without_post
48
+ get :new
49
+ assert_response :success
50
+ assert assigns(:post).nil?
51
+ assert assigns(:comment)
52
+ end
53
+
54
+ def test_should_create_comment
55
+ assert_difference('Comment.count') do
56
+ post :create, :post_id => @first.id, :comment => { :body => "test" }
57
+ end
58
+ assert_response :created
59
+ assert assigns(:comment)
60
+ assert assigns(:post)
61
+ end
62
+
63
+ def test_should_create_comment_html
64
+ @request.accept = 'text/html'
65
+ assert_difference('Comment.count') do
66
+ post :create, :post_id => @first.id, :comment => { :body => "test" }
67
+ end
68
+ assert_redirected_to "posts/#{assigns(:post).id}/comments/#{assigns(:comment).id}"
69
+ end
70
+
71
+ def test_should_create_comment_html_without_post
72
+ @request.accept = 'text/html'
73
+ assert_difference('Comment.count') do
74
+ post :create, :comment => { :body => "test" }
75
+ end
76
+ assert_redirected_to "/comments/#{assigns(:comment).id}"
77
+ end
78
+
79
+ def test_should_show_comment
80
+ get :show, :post_id => @first.id, :id => @first_comment.id
81
+ assert_response :success
82
+ assert assigns(:comment)
83
+ assert assigns(:post)
84
+ end
85
+
86
+ def test_should_show_comment_without_post
87
+ get :show, :id => @first_comment.id
88
+ assert_response :success
89
+ assert_equal Comment.find(@first_comment.id), assigns(:comment)
90
+ assert assigns(:post).nil?
91
+ end
92
+
93
+ def test_should_update_comment
94
+ put :update, :post_id => @first.id, :id => @first_comment.id, :comment => { :post => @first, :body => "test" }
95
+ assert_response :success
96
+ assert assigns(:comment)
97
+ assert assigns(:post)
98
+ end
99
+
100
+ def test_should_update_comment_html
101
+ @request.accept = 'text/html'
102
+ put :update, :post_id => @first.id, :id => @first_comment.id, :comment => { :post => @first, :body => "test" }
103
+ assert_redirected_to "posts/#{assigns(:post).id}/comments/#{assigns(:comment).id}"
104
+ end
105
+
106
+ def test_should_update_comment_html_without_post
107
+ @request.accept = 'text/html'
108
+ put :update, :id => @first_comment.id, :comment => { :post => @first, :body => "test2" }
109
+ assert_redirected_to "/comments/#{assigns(:comment).id}"
110
+ end
111
+
112
+ def test_should_destroy_comment
113
+ assert_difference('Comment.count', -1) do
114
+ delete :destroy, :post_id => @first.id, :id => @first_comment.id
115
+ end
116
+ assert_response :success
117
+ end
118
+
119
+ def test_should_destroy_html
120
+ @request.accept = 'text/html'
121
+ assert_difference('Comment.count', -1) do
122
+ delete :destroy, :post_id => @first.id, :id => @first_comment.id
123
+ end
124
+ assert_redirected_to "posts/#{assigns(:post).id}/comments"
125
+ end
126
+
127
+ def test_should_destroy_html_without_post
128
+ @request.accept = 'text/html'
129
+ assert_difference('Comment.count', -1) do
130
+ delete :destroy, :id => @first_comment.id
131
+ end
132
+ assert_redirected_to "/comments"
133
+ end
134
+ end
@@ -0,0 +1,51 @@
1
+ require File.join(File.dirname(__FILE__), 'test_helper')
2
+
3
+ class ResourceThisSortingTest < Test::Unit::TestCase
4
+ def setup
5
+ @controller = WidgetsController.new
6
+ @request = ActionController::TestRequest.new
7
+ @request.accept = 'application/xml'
8
+ @response = ActionController::TestResponse.new
9
+ @a = Widget.create(:title => "aaa", :body => "zzz")
10
+ @z = Widget.create(:title => "zzz", :body => "aaa")
11
+ 100.times do
12
+ Widget.create(:title => "foo", :body => "bar")
13
+ end
14
+ ActionController::Routing::Routes.draw do |map|
15
+ map.resources :widgets
16
+ end
17
+ end
18
+
19
+ def teardown
20
+ Widget.find(:all).each { |w| w.destroy }
21
+ end
22
+
23
+ def test_should_get_index
24
+ get :index
25
+ assert_response :success
26
+ assert assigns(:widgets)
27
+ assert_equal @a, assigns(:widgets).first
28
+ end
29
+
30
+ def test_should_get_index_sorted_with_inline_proc
31
+ @controller.resource_this_finder_options = Proc.new { { :order => 'body' } }
32
+ get :index
33
+ assert_response :success
34
+ assert assigns(:widgets)
35
+ assert_equal @z, assigns(:widgets).first
36
+ end
37
+
38
+ def test_should_get_index_sorted_with_proc
39
+ @controller.resource_this_finder_options = Proc.new { finder_options }
40
+ get :index
41
+ assert_response :success
42
+ assert assigns(:widgets)
43
+ assert_equal 2, assigns(:widgets).size
44
+ assert_equal @z, assigns(:widgets).first
45
+ end
46
+
47
+ def finder_options
48
+ {:order => 'body', :limit => 2}
49
+ end
50
+
51
+ end
@@ -0,0 +1,96 @@
1
+ require File.join(File.dirname(__FILE__), 'test_helper')
2
+
3
+ class ResourceThisTest < Test::Unit::TestCase
4
+ def setup
5
+ @controller = PostsController.new
6
+ @request = ActionController::TestRequest.new
7
+ @request.accept = 'application/xml'
8
+ @response = ActionController::TestResponse.new
9
+ @first = Post.create(:title => "test", :body => "test")
10
+ ActionController::Routing::Routes.draw do |map|
11
+ map.resources :posts
12
+ end
13
+ end
14
+
15
+ def teardown
16
+ Post.find(:all).each { |post| post.destroy }
17
+ end
18
+
19
+ def test_should_get_index
20
+ get :index
21
+ assert_response :success
22
+ assert assigns(:posts)
23
+ end
24
+
25
+ def test_should_get_new
26
+ get :new
27
+ assert_response :success
28
+ assert assigns(:post)
29
+ end
30
+
31
+ def test_should_create_post
32
+ assert_difference('Post.count') do
33
+ post :create, :post => { :title => "test", :body => "test" }
34
+ end
35
+ assert_response :created
36
+ assert assigns(:post)
37
+ end
38
+
39
+ def test_should_handle_invalid_post_on_create
40
+ assert_no_difference('Post.count') do
41
+ post :create, :post => { :title => "1" }
42
+ end
43
+ assert_response :unprocessable_entity
44
+ assert assigns(:post).errors
45
+ assert !assigns(:created)
46
+ end
47
+
48
+
49
+ def test_should_create_post_html
50
+ @request.accept = 'text/html'
51
+ assert_difference('Post.count') do
52
+ post :create, :post => { :title => "test", :body => "test" }
53
+ end
54
+ assert_redirected_to "/posts/#{assigns(:post).id}"
55
+ end
56
+
57
+ def test_should_show_post
58
+ get :show, :id => @first.id
59
+ assert_response :success
60
+ assert assigns(:post)
61
+ end
62
+
63
+ def test_should_update_post
64
+ put :update, :id => @first.id, :post => { :title => "test", :body => "test" }
65
+ assert_response :success
66
+ assert assigns(:post)
67
+ end
68
+
69
+ def test_should_handle_invalid_post_on_update
70
+ post :update, :id => @first.id, :post => { :title => "1" }
71
+ assert_response :unprocessable_entity
72
+ assert assigns(:post).errors
73
+ assert !assigns(:updated)
74
+ end
75
+
76
+ def test_should_update_post_html
77
+ @request.accept = 'text/html'
78
+ put :update, :id => @first.id, :post => { :title => "test", :body => "test" }
79
+ assert_redirected_to "/posts/#{assigns(:post).id}"
80
+ end
81
+
82
+ def test_should_destroy_post
83
+ assert_difference('Post.count', -1) do
84
+ delete :destroy, :id => @first.id
85
+ end
86
+ assert_response :success
87
+ end
88
+
89
+ def test_should_destroy_post_html
90
+ @request.accept = 'text/html'
91
+ assert_difference('Post.count', -1) do
92
+ delete :destroy, :id => @first.id
93
+ end
94
+ assert_redirected_to "/posts"
95
+ end
96
+ end
@@ -0,0 +1,39 @@
1
+ require File.join(File.dirname(__FILE__), 'test_helper')
2
+
3
+ class ResourceThisUrlPrefixTest < Test::Unit::TestCase
4
+ def setup
5
+ @controller = Admin::PostsController.new
6
+ @request = ActionController::TestRequest.new
7
+ @response = ActionController::TestResponse.new
8
+ @first = Post.create(:title => "test", :body => "test")
9
+ ActionController::Routing::Routes.draw do |map|
10
+ map.resources :posts
11
+ map.with_options :path_prefix => 'admin', :name_prefix => 'admin_' do |map|
12
+ map.resources :posts, :controller => 'admin/posts'
13
+ end
14
+ end
15
+ end
16
+
17
+ def teardown
18
+ Post.find(:all).each { |post| post.destroy }
19
+ end
20
+
21
+ def test_should_create_post
22
+ assert_difference('Post.count') do
23
+ post :create, :post => { :title => "test", :body => "test" }
24
+ end
25
+ assert_redirected_to "/admin/posts/#{assigns(:post).id}"
26
+ end
27
+
28
+ def test_should_update_post
29
+ put :update, :id => @first.id, :post => { :title => "test", :body => "test" }
30
+ assert_redirected_to "/admin/posts/#{assigns(:post).id}"
31
+ end
32
+
33
+ def test_should_destroy_post
34
+ assert_difference('Post.count', -1) do
35
+ delete :destroy, :id => @first.id
36
+ end
37
+ assert_redirected_to "/admin/posts"
38
+ end
39
+ end
@@ -0,0 +1,81 @@
1
+ $LOAD_PATH.unshift 'lib/'
2
+
3
+ require 'rubygems'
4
+ require 'multi_rails_init'
5
+ require 'action_controller/test_process'
6
+ require 'test/unit'
7
+ require 'resource_this'
8
+
9
+ begin
10
+ require 'redgreen'
11
+ rescue LoadError
12
+ nil
13
+ end
14
+
15
+ RAILS_ROOT = '.' unless defined? RAILS_ROOT
16
+ RAILS_ENV = 'test' unless defined? RAILS_ENV
17
+
18
+ ActiveRecord::Base.logger = Logger.new(STDOUT) if ENV['DEBUG']
19
+ ActionController::Base.logger = Logger.new(STDOUT) if ENV['DEBUG']
20
+
21
+ ActionController::Base.send :include, ResourceThis
22
+
23
+ ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :dbfile => ":memory:")
24
+
25
+ ActiveRecord::Schema.define(:version => 1) do
26
+ create_table :posts do |t|
27
+ t.column :title, :string
28
+ t.column :body, :text
29
+ t.column :created_at, :datetime
30
+ t.column :updated_at, :datetime
31
+ end
32
+ create_table :comments do |t|
33
+ t.column :body, :text
34
+ t.column :post_id, :integer
35
+ t.column :created_at, :datetime
36
+ t.column :updated_at, :datetime
37
+ end
38
+ create_table :widgets do |t|
39
+ t.column :title, :string
40
+ t.column :body, :text
41
+ t.column :created_at, :datetime
42
+ t.column :updated_at, :datetime
43
+ end
44
+ end
45
+
46
+ class Post < ActiveRecord::Base
47
+ has_many :comments
48
+ validates_length_of :title, :within => 2..100
49
+ def validate
50
+ end
51
+ end
52
+
53
+ class Comment < ActiveRecord::Base
54
+ belongs_to :post
55
+ def validate
56
+ end
57
+ validates_associated :post
58
+ end
59
+
60
+ class Widget < ActiveRecord::Base
61
+ def validate
62
+ end
63
+ end
64
+
65
+ class PostsController < ActionController::Base
66
+ resource_this
67
+ end
68
+
69
+ class WidgetsController < ActionController::Base
70
+ resource_this
71
+ end
72
+
73
+ module Admin; end
74
+
75
+ class Admin::PostsController < ActionController::Base
76
+ resource_this :path_prefix => "admin_"
77
+ end
78
+
79
+ class CommentsController < ActionController::Base
80
+ resource_this :nested => [:posts]
81
+ end
metadata ADDED
@@ -0,0 +1,129 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: resource_this
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Hsiu-Fan Wang
8
+ - Jesse Newland
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2014-08-25 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rails
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - "~>"
19
+ - !ruby/object:Gem::Version
20
+ version: '3.2'
21
+ type: :runtime
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - "~>"
26
+ - !ruby/object:Gem::Version
27
+ version: '3.2'
28
+ - !ruby/object:Gem::Dependency
29
+ name: rspec
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - "~>"
33
+ - !ruby/object:Gem::Version
34
+ version: '2.4'
35
+ type: :development
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - "~>"
40
+ - !ruby/object:Gem::Version
41
+ version: '2.4'
42
+ - !ruby/object:Gem::Dependency
43
+ name: rubygems-tasks
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - "~>"
47
+ - !ruby/object:Gem::Version
48
+ version: '0.2'
49
+ type: :development
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - "~>"
54
+ - !ruby/object:Gem::Version
55
+ version: '0.2'
56
+ - !ruby/object:Gem::Dependency
57
+ name: yard
58
+ requirement: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - "~>"
61
+ - !ruby/object:Gem::Version
62
+ version: '0.8'
63
+ type: :development
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - "~>"
68
+ - !ruby/object:Gem::Version
69
+ version: '0.8'
70
+ description: |-
71
+ Not scaffolding. Resourcing. Creates extremely customizable resource controllers with one line of code.
72
+
73
+ class PostsController < ActionController::Base
74
+ resource_this
75
+ end
76
+ email: hfwang@porkbuns.net
77
+ executables: []
78
+ extensions: []
79
+ extra_rdoc_files: []
80
+ files:
81
+ - ".gitignore"
82
+ - CHANGELOG.md
83
+ - Gemfile
84
+ - MIT-LICENSE
85
+ - README.md
86
+ - Rakefile
87
+ - generators/resource_this/USAGE
88
+ - generators/resource_this/resource_this_generator.rb
89
+ - generators/resource_this/templates/controller.rb
90
+ - generators/resource_this/templates/functional_test.rb
91
+ - generators/resource_this/templates/helper.rb
92
+ - init.rb
93
+ - lib/resource_this.rb
94
+ - resource_this.gemspec
95
+ - test/resource_this_nesting_test.rb
96
+ - test/resource_this_sorting_test.rb
97
+ - test/resource_this_test.rb
98
+ - test/resource_this_url_prefix_test.rb
99
+ - test/test_helper.rb
100
+ homepage: https://github.com/hfwang/resource_this
101
+ licenses: []
102
+ metadata: {}
103
+ post_install_message:
104
+ rdoc_options: []
105
+ require_paths:
106
+ - lib
107
+ required_ruby_version: !ruby/object:Gem::Requirement
108
+ requirements:
109
+ - - ">="
110
+ - !ruby/object:Gem::Version
111
+ version: '0'
112
+ required_rubygems_version: !ruby/object:Gem::Requirement
113
+ requirements:
114
+ - - ">="
115
+ - !ruby/object:Gem::Version
116
+ version: '0'
117
+ requirements: []
118
+ rubyforge_project:
119
+ rubygems_version: 2.2.2
120
+ signing_key:
121
+ specification_version: 4
122
+ summary: Not scaffolding. Resourcing. Creates extremely customizable resource controllers
123
+ with one line of code.
124
+ test_files:
125
+ - test/resource_this_nesting_test.rb
126
+ - test/resource_this_sorting_test.rb
127
+ - test/resource_this_test.rb
128
+ - test/resource_this_url_prefix_test.rb
129
+ - test/test_helper.rb