responder_controller 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
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