responder_controller 0.3.0 → 0.4.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/.rspec ADDED
@@ -0,0 +1 @@
1
+ --colour
data/CHANGELOG CHANGED
@@ -1,8 +1,23 @@
1
+ *ResponderController 0.4.0*
2
+
3
+ * #find_model will call #from_param(params['id']) instead of #find on the
4
+ query returned by #find_models if that query responds to #from_param.
5
+
6
+ * Enable color in rspec
7
+
8
+ *ResponderController 0.3.0*
9
+
10
+ * Broke modules out into separate files.
11
+ * Actions#index calls #to_a on @models before passing to #respond_with. This
12
+ makes rails 3.0.0beta3 happy: otherwise "object references itself" errors
13
+ would occur in the json encoder.
14
+
1
15
  *ResponderController 0.2.0*
2
16
 
3
- * Added .serves_scopes, which takes :only and :except options to restrict the list of active
4
- record scopes that #index will serve. If a forbidden scope is requested, ForbiddenScope will be
5
- raised, which will render as a 403 if uncaught.
17
+ * Added .serves_scopes, which takes :only and :except options to restrict the
18
+ list of active record scopes that #index will serve. If a forbidden scope
19
+ is requested, ForbiddenScope will be raised, which will render as a 403 if
20
+ uncaught.
6
21
 
7
22
  *ResponderController 0.1.3*
8
23
 
@@ -10,8 +25,10 @@
10
25
 
11
26
  *ResponderController 0.1.2*
12
27
 
13
- * If a requested scope errors out, raise a BadScope exception. Tell rails (if present) to render these as 422s.
28
+ * If a requested scope errors out, raise a BadScope exception. Tell rails (if
29
+ present) to render these as 422s.
14
30
 
15
31
  *ResponderController 0.1.1*
16
32
 
17
- * Use AR#scoped instead of #all to create initial query, as #all gives a literal array (whoops.)
33
+ * Use AR#scoped instead of #all to create initial query, as #all gives a
34
+ literal array (whoops.)
@@ -1,8 +1,9 @@
1
1
  = responder_controller
2
2
 
3
- Rails 3 responders wrap up as much crud controller code as possible without finding or mutating
4
- models on your behalf. This is a sensible cut-off for framework support, but it still leaves a
5
- fair amount of duplicate code in crud controllers. App developers are free to abstract more.
3
+ Rails 3 responders wrap up as much crud controller code as possible without
4
+ finding or mutating models on your behalf. This is a sensible cut-off for
5
+ framework support, but it still leaves a fair amount of duplicate code in crud
6
+ controllers. App developers are free to abstract more.
6
7
 
7
8
  This is me abstracting more for my own apps. If it's handy for you, go nuts.
8
9
 
@@ -13,7 +14,7 @@ This is me abstracting more for my own apps. If it's handy for you, go nuts.
13
14
  belongs_to :user
14
15
 
15
16
  scope :authored_by, lambda { |user_id| where(:user_id => user_id) }
16
- scope :recent, lambda { |count| order("updated_at DESC").limit(limit.to_i) }
17
+ scope :recent, lambda { |num| order("updated_at DESC").limit(num.to_i) }
17
18
  end
18
19
 
19
20
  # app/controllers/posts_controller.rb
@@ -29,7 +30,7 @@ This is me abstracting more for my own apps. If it's handy for you, go nuts.
29
30
  # Client-side
30
31
  GET /posts.html # renders Post.authored_by(your_id)
31
32
  GET /posts.html?recent=10 # renders Post.authored_by(your_id).recent(10)
32
- GET /posts/1.html # renders post 1 if it is authored by you, otherwise 404
33
+ GET /posts/1.html # renders post 1 if you authored it, or 404
33
34
  PUT /posts/1.html # update same
34
35
  DELETE /posts/1.html # or delete it
35
36
 
@@ -94,13 +95,14 @@ This is me abstracting more for my own apps. If it's handy for you, go nuts.
94
95
  * Add tests for it. This is important so I don't break it in a
95
96
  future version unintentionally.
96
97
  * Commit, do not mess with rakefile, version, or history.
97
- (if you want to have your own version, that is fine but bump version in a commit by itself I can
98
- ignore when I pull)
98
+ (if you want to have your own version, that is fine but bump version in a
99
+ commit by itself I can ignore when I pull)
99
100
  * Send me a pull request. Bonus points for topic branches.
100
101
 
101
102
  == Thanks
102
103
 
103
- Thanks to SEOmoz (http://seomoz.org) for letting me build this at my desk in the afternoons instead of on the couch in the middle of the night ^_^.
104
+ Thanks to SEOmoz (http://seomoz.org) for letting me build this at my desk in
105
+ the afternoons instead of on the couch in the middle of the night ^_^.
104
106
 
105
107
  == Copyright
106
108
 
data/Rakefile CHANGED
@@ -6,17 +6,20 @@ begin
6
6
  Jeweler::Tasks.new do |gem|
7
7
  gem.name = "responder_controller"
8
8
  gem.summary = %Q{like resources_controller, but for rails 3 responders}
9
- gem.description = %Q{Responders make crud controllers tiny, this wraps the rest.}
9
+ gem.description =
10
+ %Q{Responders make crud controllers tiny, this wraps the rest.}
10
11
  gem.email = "phil.h.smith@gmail.com"
11
12
  gem.homepage = "http://github.com/phs/responder_controller"
12
13
  gem.authors = ["Phil Smith"]
13
14
  gem.add_dependency "activesupport", ">= 3.0.0.beta3"
14
15
  gem.add_development_dependency "rspec", ">= 1.2.9"
15
- # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
16
+ # gem is a Gem::Specification...
17
+ # see http://www.rubygems.org/read/chapter/20 for additional settings
16
18
  end
17
19
  Jeweler::GemcutterTasks.new
18
20
  rescue LoadError
19
- puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
21
+ puts "Jeweler (or a dependency) not available. " \
22
+ "Install it with: gem install jeweler"
20
23
  end
21
24
 
22
25
  require 'spec/rake/spectask'
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.3.0
1
+ 0.4.0
@@ -16,7 +16,8 @@ module ResponderController
16
16
  class BadScope < ScopeError
17
17
  end
18
18
 
19
- # Raised when attempting to call a scope forbidden by ClassMethods.serves_scopes.
19
+ # Raised when attempting to call a scope forbidden by
20
+ # ClassMethods.serves_scopes.
20
21
  #
21
22
  # If this exception bubbles up, rails will render it as a 403.
22
23
  class ForbiddenScope < ScopeError
@@ -15,8 +15,9 @@ module ResponderController
15
15
 
16
16
  # Build (but do not save), assign and respond with a new model.
17
17
  #
18
- # The new model is built from the <tt>InstanceMethods#find_models</tt> collection, meaning it
19
- # could inherit any properties implied by those scopes.
18
+ # The new model is built from the <tt>InstanceMethods#find_models</tt>
19
+ # collection, meaning it could inherit any properties implied by those
20
+ # scopes.
20
21
  def new
21
22
  self.model = find_models.build
22
23
  respond_with_contextual model
@@ -48,7 +49,8 @@ module ResponderController
48
49
  respond_with_contextual model
49
50
  end
50
51
 
51
- # Find and destroy a model. Respond with <tt>InstanceMethods#models_slug</tt>.
52
+ # Find and destroy a model. Respond with
53
+ # <tt>InstanceMethods#models_slug</tt>.
52
54
  def destroy
53
55
  find_model.destroy
54
56
  respond_with_contextual models_slug
@@ -3,16 +3,18 @@ module ResponderController
3
3
  module ClassMethods
4
4
  # The underscored, fully-qualified name of the served model class.
5
5
  #
6
- # By default, it is the underscored controller class name, without +_controller+.
6
+ # By default, it is the underscored controller class name, without
7
+ # +_controller+.
7
8
  def model_class_name
8
- @model_class_name || name.underscore.gsub(/_controller$/, '').singularize
9
+ @model_class_name || \
10
+ name.underscore.gsub(/_controller$/, '').singularize
9
11
  end
10
12
 
11
13
  # Declare the underscored, fully-qualified name of the served model class.
12
14
  #
13
- # Modules are declared with separating slashes, such as in <tt>admin/setting</tt>. Strings
14
- # or symbols are accepted, but other values (including actual classes) will raise
15
- # <tt>ArgumentError</tt>s.
15
+ # Modules are declared with separating slashes, such as in
16
+ # <tt>admin/setting</tt>. Strings or symbols are accepted, but other
17
+ # values (including actual classes) will raise <tt>ArgumentError</tt>s.
16
18
  def serves_model(model_class_name)
17
19
  unless model_class_name.is_a? String or model_class_name.is_a? Symbol
18
20
  raise ArgumentError.new "Model must be a string or symbol"
@@ -23,13 +25,14 @@ module ResponderController
23
25
 
24
26
  # Declare what active record scopes to allow or forbid to requests.
25
27
  #
26
- # .serves_scopes follows the regular :only/:except form: white-listed scopes are passed by
27
- # name as <tt>:only => [:allowed, :scopes]</tt> or <tt>:only => :just_one</tt>. Similarly,
28
- # black-listed ones are passed under <tt>:except</tt>.
28
+ # .serves_scopes follows the regular :only/:except form: white-listed
29
+ # scopes are passed by name as <tt>:only => [:allowed, :scopes]</tt> or
30
+ # <tt>:only => :just_one</tt>. Similarly, black-listed ones are passed
31
+ # under <tt>:except</tt>.
29
32
  #
30
- # If a white-list is passed, all other requested scopes (i.e. scopes named by query parameters)
31
- # will be denied, raising <tt>ForbiddenScope</tt>. If a black-list is passed, only they will
32
- # raise the exception.
33
+ # If a white-list is passed, all other requested scopes (i.e. scopes named
34
+ # by query parameters) will be denied, raising <tt>ForbiddenScope</tt>.
35
+ # If a black-list is passed, only they will raise the exception.
33
36
  def serves_scopes(options = nil)
34
37
  @serves_scopes ||= {}
35
38
 
@@ -38,7 +41,8 @@ module ResponderController
38
41
 
39
42
  new_keys = @serves_scopes.keys | options.keys
40
43
  unless new_keys == [:only] or new_keys == [:except]
41
- raise ArgumentError.new("serves_scopes takes exactly one of :only and :except")
44
+ raise ArgumentError.new(
45
+ "serves_scopes takes exactly one of :only and :except")
42
46
  end
43
47
 
44
48
  @serves_scopes[options.keys.first] ||= []
@@ -48,18 +52,21 @@ module ResponderController
48
52
  @serves_scopes
49
53
  end
50
54
 
51
- # Declare leading arguments ("responder context") for +respond_with+ calls.
55
+ # Declare leading arguments ("responder context") for +#respond_with+.
52
56
  #
53
- # +respond_with+ creates urls from models. To avoid strongly coupling models to a url
54
- # structure, it can take any number of leading parameters a la +polymorphic_url+.
55
- # +responds_within+ declares these leading parameters, to be used on each +respond_with+ call.
57
+ # +respond_with+ creates urls from models. To avoid strongly coupling
58
+ # models to a url structure, it can take any number of leading parameters
59
+ # a la +#polymorphic_url+. +#responds_within+ declares these leading
60
+ # parameters, to be used on each +respond_with+ call.
56
61
  #
57
62
  # It takes either a varargs or a block, but not both. In
58
- # InstanceMethods#respond_with_contextual, the blocks are called with +instance_exec+, taking
59
- # the model (or models) as a parameter. They should return an array.
63
+ # InstanceMethods#respond_with_contextual, the blocks are called with
64
+ # +#instance_exec+, taking the model (or models) as a parameter. They
65
+ # should return an array.
60
66
  def responds_within(*args, &block)
61
67
  if block and args.any?
62
- raise ArgumentError.new("responds_within can take arguments or a block, but not both")
68
+ raise ArgumentError.new(
69
+ "responds_within can take arguments or a block, but not both")
63
70
  elsif block or args.any?
64
71
  @responds_within ||= []
65
72
  if not args.empty?
@@ -69,7 +76,8 @@ module ResponderController
69
76
  end
70
77
  end
71
78
 
72
- @responds_within || model_class_name.split('/')[0...-1].collect { |m| m.to_sym }
79
+ @responds_within || \
80
+ model_class_name.split('/')[0...-1].collect { |m| m.to_sym }
73
81
  end
74
82
 
75
83
  # The served model class, identified by #model_class_name.
@@ -79,13 +87,14 @@ module ResponderController
79
87
 
80
88
  # Declare a class-level scope for model collections.
81
89
  #
82
- # The model class is expected to respond to +all+, returning an Enumerable of models.
83
- # Declared scopes are applied to (and replace) this collection, suitable for active record
84
- # scopes.
90
+ # The model class is expected to respond to +all+, returning an Enumerable
91
+ # of models. Declared scopes are applied to (and replace) this
92
+ # collection, suitable for active record scopes.
85
93
  #
86
- # It takes one of a string, symbol or block. Symbols and strings are called as methods on the
87
- # collection without arguments. Blocks are called with +instance_exec+ taking the current,
88
- # accumulated query and returning the new, scoped one.
94
+ # It takes one of a string, symbol or block. Symbols and strings are
95
+ # called as methods on the collection without arguments. Blocks are
96
+ # called with +#instance_exec+ taking the current, accumulated query and
97
+ # returning the new, scoped one.
89
98
  def scope(*args, &block)
90
99
  scope = args.first || block
91
100
 
@@ -102,10 +111,12 @@ module ResponderController
102
111
 
103
112
  # Declare a (non-singleton) parent resource class.
104
113
  #
105
- # <tt>children_of 'accounts/user'</tt> implies a scope and some responder context. The scope
106
- # performs an ActiveRecord <tt>where :user_id => params[:user_id]</tt>. The responder context
107
- # is a call to <tt>#responds_within</tt> declaring the parent model's modules along with the
108
- # parent itself, found with <tt>Accounts::User.find(params[:user_id])</tt>.
114
+ # <tt>children_of 'accounts/user'</tt> implies a scope and some responder
115
+ # context. The scope performs an ActiveRecord
116
+ # <tt>where :user_id => params[:user_id]</tt>. The responder context is a
117
+ # call to <tt>#responds_within</tt> declaring the parent model's modules
118
+ # along with the parent itself, found with
119
+ # <tt>Accounts::User.find(params[:user_id])</tt>.
109
120
  def children_of(parent_model_class_name)
110
121
  parent_model_class_name = parent_model_class_name.to_s.underscore
111
122
 
@@ -118,7 +129,8 @@ module ResponderController
118
129
  end
119
130
 
120
131
  responds_within do
121
- parent = parent_model_class_name.camelize.constantize.find params[parent_id]
132
+ parent = parent_model_class_name.camelize.constantize.
133
+ find params[parent_id]
122
134
  parent_modules + [parent]
123
135
  end
124
136
  end
@@ -3,20 +3,21 @@ require 'active_support/core_ext/module/delegation'
3
3
  module ResponderController
4
4
  # Instance methods that support the Actions module.
5
5
  module InstanceMethods
6
- delegate :model_class_name, :model_class, :scopes, :responds_within, :serves_scopes,
7
- :to => "self.class"
6
+ delegate :model_class_name, :model_class, :scopes, :responds_within,
7
+ :serves_scopes, :to => "self.class"
8
8
 
9
9
  # Apply scopes to the given query.
10
10
  #
11
- # Applicable scopes come from two places. They are either declared at the class level with
12
- # <tt>ClassMethods#scope</tt>, or named in the request itself. The former is good for
13
- # defining topics or enforcing security, while the latter is free slicing and dicing for
14
- # clients.
11
+ # Applicable scopes come from two places. They are either declared at the
12
+ # class level with <tt>ClassMethods#scope</tt>, or named in the request
13
+ # itself. The former is good for defining topics or enforcing security,
14
+ # while the latter is free slicing and dicing for clients.
15
15
  #
16
- # Class-level scopes are applied first. Request scopes come after, and are discovered by
17
- # examining +params+. If any +params+ key matches a name found in
18
- # <tt>ClassMethods#model_class.scopes.keys</tt>, then it is taken to be a scope and is
19
- # applied. The values under that +params+ key are passed along as arguments.
16
+ # Class-level scopes are applied first. Request scopes come after, and
17
+ # are discovered by examining +params+. If any +params+ key matches a
18
+ # name found in <tt>ClassMethods#model_class.scopes.keys</tt>, then it is
19
+ # taken to be a scope and is applied. The values under that +params+ key
20
+ # are passed along as arguments.
20
21
  def scope(query)
21
22
  query = (scopes || []).inject(query) do |query, scope|
22
23
  if Symbol === scope and model_class.scopes.key? scope
@@ -28,9 +29,15 @@ module ResponderController
28
29
  end
29
30
  end
30
31
 
31
- requested = (model_class.scopes.keys & params.keys.collect { |k| k.to_sym })
32
- raise ForbiddenScope if serves_scopes[:only] && (requested - serves_scopes[:only]).any?
33
- raise ForbiddenScope if serves_scopes[:except] && (requested & serves_scopes[:except]).any?
32
+ requested = model_class.scopes.keys & params.keys.collect(&:to_sym)
33
+
34
+ if serves_scopes[:only] && (requested - serves_scopes[:only]).any?
35
+ raise ForbiddenScope
36
+ end
37
+
38
+ if serves_scopes[:except] && (requested & serves_scopes[:except]).any?
39
+ raise ForbiddenScope
40
+ end
34
41
 
35
42
  query = requested.inject(query) do |query, scope|
36
43
  query.send scope, *params[scope.to_s] rescue raise BadScope
@@ -48,10 +55,12 @@ module ResponderController
48
55
 
49
56
  # Find a particular model.
50
57
  #
51
- # #find_models is asked to find a model with <tt>params[:id]</tt>. This ensures that
52
- # class-level scopes are enforced (potentially for security.)
58
+ # #find_models is asked to find a model with <tt>params[:id]</tt>. This
59
+ # ensures that class-level scopes are enforced (potentially for security.)
53
60
  def find_model
54
- find_models.find(params[:id])
61
+ models = find_models
62
+ finder = models.respond_to?(:from_param) ? :from_param : :find
63
+ models.send finder, params[:id]
55
64
  end
56
65
 
57
66
  # The underscored model class name, as a symbol.
@@ -98,11 +107,12 @@ module ResponderController
98
107
 
99
108
  # Apply ClassMethods#responds_within to the given model (or symbol.)
100
109
  #
101
- # "Apply" just means turning +responds_within+ into an array and appending +model+ to the
102
- # end. If +responds_within+ is an array, it used directly.
110
+ # "Apply" just means turning +responds_within+ into an array and appending
111
+ # +model+ to the end. If +responds_within+ is an array, it used directly.
103
112
  #
104
- # If it is a proc, it is called with +instance_exec+, passing +model+ in. It should return an
105
- # array, which +model+ will be appended to. (So, don't include it in the return value.)
113
+ # If it is a proc, it is called with +instance_exec+, passing +model+ in.
114
+ # It should return an array, which +model+ will be appended to. (So,
115
+ # don't include it in the return value.)
106
116
  def responder_context(model)
107
117
  context = responds_within.collect do |o|
108
118
  o = instance_exec model, &o if o.is_a? Proc
@@ -110,7 +120,8 @@ module ResponderController
110
120
  end.flatten + [model]
111
121
  end
112
122
 
113
- # Pass +model+ through InstanceMethods#responder_context, and pass that to #respond_with.
123
+ # Pass +model+ through InstanceMethods#responder_context, and pass that to
124
+ # #respond_with.
114
125
  def respond_with_contextual(model)
115
126
  respond_with *responder_context(model)
116
127
  end
@@ -1,59 +1,58 @@
1
1
  # Generated by jeweler
2
2
  # DO NOT EDIT THIS FILE DIRECTLY
3
- # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
4
  # -*- encoding: utf-8 -*-
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{responder_controller}
8
- s.version = "0.3.0"
8
+ s.version = "0.4.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Phil Smith"]
12
- s.date = %q{2010-05-21}
12
+ s.date = %q{2011-01-03}
13
13
  s.description = %q{Responders make crud controllers tiny, this wraps the rest.}
14
14
  s.email = %q{phil.h.smith@gmail.com}
15
15
  s.extra_rdoc_files = [
16
16
  "LICENSE",
17
- "README.rdoc"
17
+ "README.rdoc"
18
18
  ]
19
19
  s.files = [
20
20
  ".document",
21
- ".gitignore",
22
- "CHANGELOG",
23
- "LICENSE",
24
- "README.rdoc",
25
- "Rakefile",
26
- "VERSION",
27
- "lib/responder_controller.rb",
28
- "lib/responder_controller/actions.rb",
29
- "lib/responder_controller/class_methods.rb",
30
- "lib/responder_controller/instance_methods.rb",
31
- "responder_controller.gemspec",
32
- "spec/responder_controller/actions_spec.rb",
33
- "spec/responder_controller/class_methods_spec.rb",
34
- "spec/responder_controller/instance_methods_spec.rb",
35
- "spec/responder_controller_spec.rb",
36
- "spec/spec.opts",
37
- "spec/spec_helper.rb"
21
+ ".rspec",
22
+ "CHANGELOG",
23
+ "LICENSE",
24
+ "README.rdoc",
25
+ "Rakefile",
26
+ "VERSION",
27
+ "lib/responder_controller.rb",
28
+ "lib/responder_controller/actions.rb",
29
+ "lib/responder_controller/class_methods.rb",
30
+ "lib/responder_controller/instance_methods.rb",
31
+ "responder_controller.gemspec",
32
+ "spec/responder_controller/actions_spec.rb",
33
+ "spec/responder_controller/class_methods_spec.rb",
34
+ "spec/responder_controller/instance_methods_spec.rb",
35
+ "spec/responder_controller_spec.rb",
36
+ "spec/spec.opts",
37
+ "spec/spec_helper.rb"
38
38
  ]
39
39
  s.homepage = %q{http://github.com/phs/responder_controller}
40
- s.rdoc_options = ["--charset=UTF-8"]
41
40
  s.require_paths = ["lib"]
42
- s.rubygems_version = %q{1.3.6}
41
+ s.rubygems_version = %q{1.3.7}
43
42
  s.summary = %q{like resources_controller, but for rails 3 responders}
44
43
  s.test_files = [
45
44
  "spec/responder_controller/actions_spec.rb",
46
- "spec/responder_controller/class_methods_spec.rb",
47
- "spec/responder_controller/instance_methods_spec.rb",
48
- "spec/responder_controller_spec.rb",
49
- "spec/spec_helper.rb"
45
+ "spec/responder_controller/class_methods_spec.rb",
46
+ "spec/responder_controller/instance_methods_spec.rb",
47
+ "spec/responder_controller_spec.rb",
48
+ "spec/spec_helper.rb"
50
49
  ]
51
50
 
52
51
  if s.respond_to? :specification_version then
53
52
  current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
54
53
  s.specification_version = 3
55
54
 
56
- if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
55
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
57
56
  s.add_runtime_dependency(%q<activesupport>, [">= 3.0.0.beta3"])
58
57
  s.add_development_dependency(%q<rspec>, [">= 1.2.9"])
59
58
  else
@@ -32,8 +32,8 @@ describe ResponderController do
32
32
  end
33
33
 
34
34
  it '#respond_with_contextual @models.to_a' do
35
- @posts.should_receive(:to_a).and_return(:posts_array)
36
- @controller.should_receive(:respond_with_contextual).with(:posts_array)
35
+ @posts.should_receive(:to_a).and_return(:posts)
36
+ @controller.should_receive(:respond_with_contextual).with(:posts)
37
37
  @controller.index
38
38
  end
39
39
  end
@@ -132,7 +132,9 @@ describe ResponderController::ClassMethods do
132
132
  end
133
133
 
134
134
  it 'can specify a white list of active record scopes to serve' do
135
- PostsController.serves_scopes :only => [:recent, :authored_by, :published_after]
135
+ PostsController.serves_scopes :only => [
136
+ :recent, :authored_by, :published_after]
137
+
136
138
  lambda do
137
139
  @controller.scope @query
138
140
  end.should raise_error(ResponderController::ForbiddenScope)
@@ -146,7 +148,9 @@ describe ResponderController::ClassMethods do
146
148
  end
147
149
 
148
150
  it 'can specify a black list of active record scopes to deny' do
149
- PostsController.serves_scopes :except => [:commented_on_by, :unpublished]
151
+ PostsController.serves_scopes :except => [
152
+ :commented_on_by, :unpublished]
153
+
150
154
  lambda do
151
155
  @controller.scope @query
152
156
  end.should raise_error(ResponderController::ForbiddenScope)
@@ -173,11 +177,12 @@ describe ResponderController::ClassMethods do
173
177
 
174
178
  it 'whines when both :only and :except are passed' do
175
179
  lambda do
176
- PostsController.serves_scopes :only => :recent, :except => :commented_on_by
180
+ PostsController.serves_scopes :only => :recent,
181
+ :except => :commented_on_by
177
182
  end.should raise_error ArgumentError
178
183
  end
179
184
 
180
- it 'whines if both :only and :except are passed between different calls' do
185
+ it 'whines if :only and :except are passed between different calls' do
181
186
  PostsController.serves_scopes :only => :recent
182
187
  lambda do
183
188
  PostsController.serves_scopes :except => :commented_on_by
@@ -202,7 +207,8 @@ describe ResponderController::ClassMethods do
202
207
  end
203
208
 
204
209
  it "takes, saves and returns a varargs" do
205
- PostsController.responds_within(:foo, :bar, :baz).should == [:foo, :bar, :baz]
210
+ PostsController.responds_within(:foo, :bar, :baz).should == \
211
+ [:foo, :bar, :baz]
206
212
  PostsController.responds_within.should == [:foo, :bar, :baz]
207
213
  end
208
214
 
@@ -225,7 +231,8 @@ describe ResponderController::ClassMethods do
225
231
  end
226
232
 
227
233
  after :each do
228
- PostsController.instance_variable_set "@responds_within", nil # clear out the garbage
234
+ # Clear out the garbage
235
+ PostsController.instance_variable_set "@responds_within", nil
229
236
  end
230
237
  end
231
238
 
@@ -238,28 +245,33 @@ describe ResponderController::ClassMethods do
238
245
  PostsController.children_of 'accounts/user'.to_sym
239
246
  end
240
247
 
241
- it "creates a scope filtering by the parent model's foreign key as passed in params" do
248
+ it "creates a scope filtering by the parent's key as passed in params" do
242
249
  PostsController.children_of 'accounts/user'
243
250
  controller = PostsController.new
244
251
  controller.params[:user_id] = :the_user_id
245
252
 
246
- user_query = mock("user-restricted query")
247
- @query.should_receive(:where).with(:user_id => :the_user_id).and_return(user_query)
253
+ @query.should_receive(:where).
254
+ with(:user_id => :the_user_id).
255
+ and_return(user_query = mock("user-restricted query"))
256
+
248
257
  controller.scope(@query).should == user_query
249
258
  end
250
259
 
251
- it "adds a responds_within context, of the parent modules followed by the parent itself" do
260
+ it "adds a responds_within context, of the parent with its modules" do
252
261
  PostsController.children_of 'accounts/user'
253
262
  controller = PostsController.new
254
263
  controller.params[:user_id] = :the_user_id
255
264
 
256
- Accounts::User.should_receive(:find).with(:the_user_id).and_return(user = mock("the user"))
265
+ Accounts::User.should_receive(:find).with(:the_user_id).
266
+ and_return(user = mock("the user"))
257
267
 
258
- controller.responder_context(:argument).should == [:accounts, user, :argument]
268
+ controller.responder_context(:argument).should == [
269
+ :accounts, user, :argument]
259
270
  end
260
271
 
261
272
  after :each do
262
- PostsController.instance_variable_set "@responds_within", nil # clear out the garbage
273
+ # Clear out the garbage
274
+ PostsController.instance_variable_set "@responds_within", nil
263
275
  PostsController.scopes.clear
264
276
  end
265
277
  end
@@ -35,56 +35,57 @@ describe ResponderController::InstanceMethods do
35
35
  @query.stub!(:unpublished).and_return(@query)
36
36
  @query.stub!(:recent).and_return(@query)
37
37
  @query.stub!(:owned_by).with('me').and_return(@query)
38
+
39
+ @controller = PostsController.new
38
40
  end
39
41
 
40
42
  describe '#model_class_name' do
41
43
  it "is .model_class_name" do
42
- PostsController.new.model_class_name.should == PostsController.model_class_name
44
+ @controller.model_class_name.should == PostsController.model_class_name
43
45
  end
44
46
  end
45
47
 
46
48
  describe '#model_class' do
47
49
  it 'is .model_class' do
48
- PostsController.new.model_class.should == PostsController.model_class
50
+ @controller.model_class.should == PostsController.model_class
49
51
  end
50
52
  end
51
53
 
52
54
  describe '#scopes' do
53
55
  it 'is .scopes' do
54
- PostsController.new.scopes.should == PostsController.scopes
56
+ @controller.scopes.should == PostsController.scopes
55
57
  end
56
58
  end
57
59
 
58
60
  describe '#scope' do
59
61
  it "passes its argument out by default" do
60
- PostsController.new.scope(@query).should == @query
62
+ @controller.scope(@query).should == @query
61
63
  end
62
64
 
63
- it "with explicit scopes asks model_class for the declared scopes in order" do
65
+ it "sends explicit, declared scopes to the query in order" do
64
66
  PostsController.scope :unpublished
65
67
  PostsController.scope :recent
66
68
 
67
69
  @query.should_receive(:unpublished).and_return(@query)
68
70
  @query.should_receive(:recent).and_return(@query)
69
- PostsController.new.scope(@query).should == @query
71
+ @controller.scope(@query).should == @query
70
72
  end
71
73
 
72
- it 'with a block scope instance_execs the block while passing in the current query' do
74
+ it '#instance_execs block scopes, passing in the query' do
73
75
  PostsController.scope do |posts|
74
76
  posts.owned_by(params[:user_id])
75
77
  end
76
78
 
77
79
  @query.should_receive(:owned_by).with('me').and_return(@query)
78
80
 
79
- controller = PostsController.new
80
- controller.scope(@query).should == @query
81
+ @controller.scope(@query).should == @query
81
82
  end
82
83
 
83
84
  it 'explodes with an unknown scope' do
84
85
  PostsController.scope :furst_p0sts
85
86
 
86
87
  lambda do
87
- PostsController.new.scope
88
+ @controller.scope
88
89
  end.should raise_error ArgumentError
89
90
 
90
91
  PostsController.scopes.pop
@@ -92,7 +93,6 @@ describe ResponderController::InstanceMethods do
92
93
 
93
94
  context 'with request parameters naming scopes' do
94
95
  before :each do
95
- @controller = PostsController.new
96
96
  @controller.params['commented_on_by'] = 'you'
97
97
  end
98
98
 
@@ -102,10 +102,13 @@ describe ResponderController::InstanceMethods do
102
102
  end
103
103
 
104
104
  it 'is applied after class-level scopes' do
105
+ # owned_by is the last class-level scope
105
106
  class_level_query = mock("class-level scoped query")
106
- @query.should_receive(:owned_by).and_return(class_level_query) # last class-level scope
107
+ @query.should_receive(:owned_by).and_return(class_level_query)
108
+
109
+ class_level_query.should_receive(:commented_on_by).
110
+ with('you').and_return(class_level_query)
107
111
 
108
- class_level_query.should_receive(:commented_on_by).with('you').and_return(class_level_query)
109
112
  @controller.scope(@query).should == class_level_query
110
113
  end
111
114
 
@@ -120,28 +123,44 @@ describe ResponderController::InstanceMethods do
120
123
 
121
124
  describe '#find_models' do
122
125
  it 'is #scope #model_class.scoped' do
123
- controller = PostsController.new
124
-
125
126
  Post.should_receive(:scoped).and_return(@query)
126
- controller.should_receive(:scope).with(@query).and_return(@query)
127
+ @controller.should_receive(:scope).with(@query).and_return(@query)
127
128
 
128
- controller.find_models.should == @query
129
+ @controller.find_models.should == @query
129
130
  end
130
131
  end
131
132
 
132
133
  describe '#find_model' do
133
- it 'is #find_models.find(params[:id])' do
134
- controller = PostsController.new
135
- controller.should_receive(:find_models).and_return(@query)
136
- @query.should_receive(:find).with(controller.params[:id]).and_return(post = mock("the post"))
134
+ before :each do
135
+ @post = mock("the post")
136
+ @query.stub!(:respond_to?).with(:from_param).and_return(false)
137
+ end
138
+
139
+ it 'is #from_param(params[:id]) if #find_models responds to it' do
140
+ @controller.should_receive(:find_models).and_return(@query)
141
+
142
+ @query.should_receive(:respond_to?).with(:from_param).and_return(true)
143
+ @query.should_receive(:from_param).
144
+ with(@controller.params[:id]).
145
+ and_return(@post)
146
+
147
+ @controller.find_model.should == @post
148
+ end
149
+
150
+ it 'is #find_models.find(params[:id]) otherwise' do
151
+ @controller.should_receive(:find_models).and_return(@query)
152
+
153
+ @query.should_receive(:find).
154
+ with(@controller.params[:id]).
155
+ and_return(@post)
137
156
 
138
- controller.find_model.should == post
157
+ @controller.find_model.should == @post
139
158
  end
140
159
  end
141
160
 
142
161
  describe '#model_slug' do
143
162
  it 'is the model class name' do
144
- PostsController.new.model_slug.should == :post
163
+ @controller.model_slug.should == :post
145
164
  end
146
165
 
147
166
  it 'drops the leading module names, if any' do
@@ -151,75 +170,78 @@ describe ResponderController::InstanceMethods do
151
170
 
152
171
  describe '#models_slug' do
153
172
  it 'is ths symbolized plural of #model_slug' do
154
- PostsController.new.models_slug.should == :posts
173
+ @controller.models_slug.should == :posts
155
174
  end
156
175
  end
157
176
 
158
177
  describe '#model_ivar' do
159
178
  it 'is the #model_slug with a leading @' do
160
- PostsController.new.model_ivar.should == '@post'
179
+ @controller.model_ivar.should == '@post'
161
180
  end
162
181
  end
163
182
 
164
183
  describe '#models_ivar' do
165
184
  it 'is the plural #model_ivar' do
166
- (controller = PostsController.new).models_ivar.should == controller.model_ivar.pluralize
185
+ @controller.models_ivar.should == @controller.model_ivar.pluralize
167
186
  end
168
187
  end
169
188
 
170
189
  describe "#models" do
171
190
  it "gets #models_ivar" do
172
- (controller = PostsController.new).instance_variable_set("@posts", :some_posts)
173
- controller.models.should == :some_posts
191
+ @controller.instance_variable_set("@posts", :some_posts)
192
+ @controller.models.should == :some_posts
174
193
  end
175
194
  end
176
195
 
177
196
  describe "#model" do
178
197
  it "gets #model_ivar" do
179
- (controller = PostsController.new).instance_variable_set("@post", :a_post)
180
- controller.model.should == :a_post
198
+ @controller.instance_variable_set("@post", :a_post)
199
+ @controller.model.should == :a_post
181
200
  end
182
201
  end
183
202
 
184
203
  describe "#models=" do
185
204
  it "assigns to #models_ivar" do
186
205
  assigned = mock("some models")
187
- (controller = PostsController.new).models = assigned
188
- controller.instance_variable_get("@posts").should == assigned
206
+ @controller.models = assigned
207
+ @controller.instance_variable_get("@posts").should == assigned
189
208
  end
190
209
  end
191
210
 
192
211
  describe "#model=" do
193
212
  it "assigns to #model_ivar" do
194
213
  assigned = mock("a model")
195
- (controller = PostsController.new).model = assigned
196
- controller.instance_variable_get("@post").should == assigned
214
+ @controller.model = assigned
215
+ @controller.instance_variable_get("@post").should == assigned
197
216
  end
198
217
  end
199
218
 
200
219
  describe '#responds_within' do
201
220
  it 'is .responds_within' do
202
- PostsController.new.responds_within.should == PostsController.responds_within
221
+ @controller.responds_within.should == PostsController.responds_within
203
222
  end
204
223
  end
205
224
 
206
225
  describe '#responder_context' do
207
226
  it "is the argument prepended with responds_within" do
208
- Admin::SettingsController.new.responder_context(:argument).should == [:admin, :argument]
227
+ Admin::SettingsController.new.responder_context(:argument).should == [
228
+ :admin, :argument]
209
229
  end
210
230
 
211
- it "passes the argument to responds_within and prepends the result if it is a lambda" do
231
+ it "passes lambdas to responds_within and prepends the results" do
212
232
  Admin::SettingsController.responds_within do |model|
213
233
  model.should == :argument
214
234
  [:nested, :namespace]
215
235
  end
216
236
 
217
- Admin::SettingsController.new.responder_context(:argument).should == [:nested, :namespace, :argument]
237
+ Admin::SettingsController.new.responder_context(:argument).should == [
238
+ :nested, :namespace, :argument]
218
239
  end
219
240
 
220
241
  it "wraps the lambda result in an array if needed" do
221
242
  Admin::SettingsController.responds_within { |model| :namespace }
222
- Admin::SettingsController.new.responder_context(:argument).should == [:namespace, :argument]
243
+ Admin::SettingsController.new.responder_context(:argument).should == [
244
+ :namespace, :argument]
223
245
  end
224
246
 
225
247
  after :each do
@@ -229,11 +251,11 @@ describe ResponderController::InstanceMethods do
229
251
 
230
252
  describe '#respond_with_contextual' do
231
253
  it 'passed #responder_context to #respond_with' do
232
- controller = PostsController.new
233
- controller.should_receive(:responder_context).with(:argument).and_return([:contextualized_argument])
234
- controller.should_receive(:respond_with).with(:contextualized_argument)
254
+ @controller.should_receive(:responder_context).
255
+ with(:argument).and_return([:contextualized_argument])
256
+ @controller.should_receive(:respond_with).with(:contextualized_argument)
235
257
 
236
- controller.respond_with_contextual :argument
258
+ @controller.respond_with_contextual :argument
237
259
  end
238
260
  end
239
261
  end
metadata CHANGED
@@ -1,12 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: responder_controller
3
3
  version: !ruby/object:Gem::Version
4
+ hash: 15
4
5
  prerelease: false
5
6
  segments:
6
7
  - 0
7
- - 3
8
+ - 4
8
9
  - 0
9
- version: 0.3.0
10
+ version: 0.4.0
10
11
  platform: ruby
11
12
  authors:
12
13
  - Phil Smith
@@ -14,16 +15,18 @@ autorequire:
14
15
  bindir: bin
15
16
  cert_chain: []
16
17
 
17
- date: 2010-05-21 00:00:00 -07:00
18
+ date: 2011-01-03 00:00:00 -08:00
18
19
  default_executable:
19
20
  dependencies:
20
21
  - !ruby/object:Gem::Dependency
21
22
  name: activesupport
22
23
  prerelease: false
23
24
  requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
24
26
  requirements:
25
27
  - - ">="
26
28
  - !ruby/object:Gem::Version
29
+ hash: 299253627
27
30
  segments:
28
31
  - 3
29
32
  - 0
@@ -36,9 +39,11 @@ dependencies:
36
39
  name: rspec
37
40
  prerelease: false
38
41
  requirement: &id002 !ruby/object:Gem::Requirement
42
+ none: false
39
43
  requirements:
40
44
  - - ">="
41
45
  - !ruby/object:Gem::Version
46
+ hash: 13
42
47
  segments:
43
48
  - 1
44
49
  - 2
@@ -57,7 +62,7 @@ extra_rdoc_files:
57
62
  - README.rdoc
58
63
  files:
59
64
  - .document
60
- - .gitignore
65
+ - .rspec
61
66
  - CHANGELOG
62
67
  - LICENSE
63
68
  - README.rdoc
@@ -79,28 +84,32 @@ homepage: http://github.com/phs/responder_controller
79
84
  licenses: []
80
85
 
81
86
  post_install_message:
82
- rdoc_options:
83
- - --charset=UTF-8
87
+ rdoc_options: []
88
+
84
89
  require_paths:
85
90
  - lib
86
91
  required_ruby_version: !ruby/object:Gem::Requirement
92
+ none: false
87
93
  requirements:
88
94
  - - ">="
89
95
  - !ruby/object:Gem::Version
96
+ hash: 3
90
97
  segments:
91
98
  - 0
92
99
  version: "0"
93
100
  required_rubygems_version: !ruby/object:Gem::Requirement
101
+ none: false
94
102
  requirements:
95
103
  - - ">="
96
104
  - !ruby/object:Gem::Version
105
+ hash: 3
97
106
  segments:
98
107
  - 0
99
108
  version: "0"
100
109
  requirements: []
101
110
 
102
111
  rubyforge_project:
103
- rubygems_version: 1.3.6
112
+ rubygems_version: 1.3.7
104
113
  signing_key:
105
114
  specification_version: 3
106
115
  summary: like resources_controller, but for rails 3 responders
data/.gitignore DELETED
@@ -1,21 +0,0 @@
1
- ## MAC OS
2
- .DS_Store
3
-
4
- ## TEXTMATE
5
- *.tmproj
6
- tmtags
7
-
8
- ## EMACS
9
- *~
10
- \#*
11
- .\#*
12
-
13
- ## VIM
14
- *.swp
15
-
16
- ## PROJECT::GENERAL
17
- coverage
18
- rdoc
19
- pkg
20
-
21
- ## PROJECT::SPECIFIC