decent_exposure 0.2.4 → 1.0.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -22,11 +22,11 @@ In `config/environment.rb`:
22
22
 
23
23
  config.gem 'decent_exposure'
24
24
 
25
- When used in Rails 3, you must require the Railtie initializer:
25
+ When used in Rails 3:
26
26
 
27
27
  In `Gemfile`:
28
28
 
29
- gem 'decent_exposure', :require => ['decent_exposure', 'decent_exposure/railtie']
29
+ gem 'decent_exposure'
30
30
 
31
31
 
32
32
  The Particulars
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.2.4
1
+ 1.0.0.rc1
@@ -1,3 +1,5 @@
1
+ require 'decent_exposure/railtie'
2
+
1
3
  module DecentExposure
2
4
  def inherited(klass)
3
5
  closured_exposure = default_exposure
@@ -27,5 +29,4 @@ module DecentExposure
27
29
  helper_method name
28
30
  hide_action name
29
31
  end
30
- alias let expose
31
32
  end
@@ -0,0 +1,42 @@
1
+ module DecentExposure
2
+ module DefaultExposure
3
+ def self.included(klass)
4
+ klass.extend(DecentExposure)
5
+ klass.superclass_delegating_accessor(:_default_exposure)
6
+ klass.default_exposure do |name|
7
+ self._resource_name = name.to_s
8
+ if id = params["#{name}_id"] || params[:id]
9
+ _proxy.find(id).tap do |r|
10
+ r.attributes = params[name] unless request.get?
11
+ end
12
+ else
13
+ _proxy.new(params[name])
14
+ end
15
+ end
16
+ end
17
+
18
+ private
19
+ attr_accessor :_resource_name
20
+
21
+ def _resource_class
22
+ _resource_name.classify.constantize
23
+ end
24
+
25
+ def _collection_name
26
+ _resource_name.pluralize
27
+ end
28
+
29
+ def _proxy
30
+ _collection.respond_to?(:scoped) ? _collection : _resource_class
31
+ end
32
+
33
+ def _collection
34
+ unless self.class.method_defined?(_collection_name)
35
+ self.class.expose(_collection_name) do
36
+ _collection_name.classify.constantize.scoped({})
37
+ end
38
+ end
39
+ send(_collection_name)
40
+ end
41
+ end
42
+ end
@@ -1,15 +1,19 @@
1
+ require 'decent_exposure/default_exposure'
2
+
1
3
  module DecentExposure
2
- class Railtie < Rails::Railtie
3
- initializer "decent_exposure.extend_action_controller_base" do |app|
4
- ActionController::Base.class_eval do
5
- extend DecentExposure
6
- superclass_delegating_accessor :_default_exposure
7
- default_exposure do |name|
8
- model_class = name.to_s.classify.constantize
9
- model_class.find(params["#{name}_id"] || params['id'])
4
+ if defined? Rails::Railtie
5
+ class Railtie < Rails::Railtie
6
+ initializer "decent_exposure.extend_action_controller_base" do |app|
7
+ ActiveSupport.on_load(:action_controller) do
8
+ DecentExposure::Railtie.insert
10
9
  end
11
10
  end
12
11
  end
13
12
  end
14
- end
15
13
 
14
+ class Railtie
15
+ def self.insert
16
+ ActionController::Base.send(:include, DecentExposure::DefaultExposure)
17
+ end
18
+ end
19
+ end
@@ -1,14 +1,2 @@
1
- begin
2
- require File.join(File.dirname(__FILE__), 'lib', 'decent_exposure') # From here
3
- rescue LoadError
4
- require 'decent_exposure' # From gem
5
- end
6
-
7
- ActionController::Base.class_eval do
8
- extend DecentExposure
9
- superclass_delegating_accessor :_default_exposure
10
- default_exposure do |name|
11
- model_class = name.to_s.classify.constantize
12
- model_class.find(params["#{name}_id"] || params['id'])
13
- end
14
- end
1
+ require 'decent_exposure/railtie'
2
+ DecentExposure::Railtie.insert
@@ -1,175 +1,79 @@
1
- require File.join(File.dirname(__FILE__), '..', 'helper')
1
+ require 'helper'
2
2
 
3
- class Quacker
4
- extend DecentExposure
5
- def self.helper_method(*args); end
6
- def self.hide_action(*args); end
7
- def memoizable(*args); args; end
8
- expose(:proxy)
9
- end
3
+ describe DecentExposure do
10
4
 
11
- module ActionController
12
- class Base
5
+ class Controller
6
+ extend DecentExposure
13
7
  def self.helper_method(*args); end
14
8
  def self.hide_action(*args); end
15
- def self.superclass_delegating_accessor(*args); end
16
- def params; {'resource_id' => 42}; end
9
+ def memoizable(arg); arg; end
17
10
  end
18
- end
19
- require File.join(File.dirname(__FILE__), '..', '..', 'rails', 'init.rb')
20
-
21
- class MyController < ActionController::Base
22
- end
23
11
 
24
- class Resource
25
- def self.find(*args); end
26
- end
27
-
28
- class Widget
29
- def self.find(*args); end
30
- end
31
-
32
- describe DecentExposure do
33
- context "classes extending DecentExposure" do
34
- it "respond to :expose" do
35
- Quacker.respond_to?(:expose).should be_true
36
- end
12
+ context 'classes extending DecentExposure' do
13
+ subject { Controller }
14
+ specify { should respond_to(:expose) }
15
+ specify { should respond_to(:default_exposure) }
37
16
  end
38
17
 
39
- context "#expose" do
40
- let(:instance){ Quacker.new }
41
-
42
- it "creates a method with the given name" do
43
- Quacker.new.methods.map{|m| m.to_s}.should include('proxy')
44
- end
45
-
46
- it "prevents the method from being a callable action" do
47
- Quacker.expects(:hide_action).with(:blerg)
48
- Quacker.class_eval do
49
- expose(:blerg){ 'ehm' }
50
- end
51
- end
18
+ context '.expose' do
19
+ let(:controller) { Class.new(Controller){ expose(:resource) } }
20
+ let(:instance) { controller.new }
52
21
 
53
- it "declares the method as a helper method" do
54
- Quacker.stubs(:hide_action)
55
- Quacker.expects(:helper_method).with(:blarg)
56
- Quacker.class_eval do
57
- expose(:blarg){ 'uhm' }
58
- end
22
+ it 'creates a method with the given name' do
23
+ instance.methods.should include('resource')
59
24
  end
60
25
 
61
- it "returns the result of the exposed block from the method" do
62
- Quacker.stubs(:hide_action)
63
- Quacker.stubs(:helper_method)
64
- Quacker.class_eval do
65
- expose(:quack){ memoizable('quack!') }
66
- end
67
- instance.quack.should == %w(quack!)
26
+ it 'prevents the method from being a callable action' do
27
+ controller.expects(:hide_action).with(:resources)
28
+ controller.class_eval { expose(:resources) }
68
29
  end
69
30
 
70
- it "memoizes the value of the created method" do
71
- instance.expects(:memoizable).once.returns('value')
72
- instance.quack
73
- instance.quack
31
+ it 'declares the method as a helper method' do
32
+ controller.expects(:helper_method).with(:resources)
33
+ controller.class_eval { expose(:resources) }
74
34
  end
75
35
 
76
- context "when specifying custom default behavior" do
77
- before(:all) do
78
- class ::DuckController
79
- extend DecentExposure
80
- def self.helper_method(*args); end
81
- def self.hide_action(*args); end
82
- def params; end
83
- default_exposure {"default value"}
84
- expose(:quack)
36
+ context 'custom exposures' do
37
+ before do
38
+ controller.class_eval do
39
+ expose(:resource) { memoizable("I'm a resource!") }
85
40
  end
86
41
  end
87
42
 
88
- it "uses that behavior when no block is given" do
89
- DuckController.new.quack.should == "default value"
43
+ it 'returns the result of the exposed block from the method' do
44
+ instance.resource.should == "I'm a resource!"
90
45
  end
91
46
 
92
- it "passes the name given to #expose into the block" do
93
- DuckController.class_eval do
94
- default_exposure {|name| "downy #{name}"}
95
- expose :feathers
96
- end
97
- DuckController.new.feathers.should == "downy feathers"
47
+ it 'memoizes the value of the created method' do
48
+ instance.expects(:memoizable).once.returns('value')
49
+ 2.times { instance.resource }
98
50
  end
99
51
  end
100
- end
101
-
102
- context "within Rails" do
103
- let(:controller) {ActionController::Base.new}
104
-
105
- let(:resource){ 'resource' }
106
- let(:resource_class_name){ 'Resource' }
107
- before do
108
- resource.stubs(:to_s => resource, :classify => resource_class_name)
109
- resource_class_name.stubs(:constantize => Resource)
110
- end
111
-
112
- it "extends ActionController::Base" do
113
- ActionController::Base.respond_to?(:expose).should == true
114
- end
115
52
 
116
- context "by default" do
117
- it "calls find with params[:resource_id] on the resource's class" do
118
- name = resource
119
- Resource.expects(:find).with(42)
120
- ActionController::Base.class_eval do
121
- expose name
122
- end
123
- controller.resource
124
- end
125
- context "or, when there is no :resource_id in params" do
53
+ context '.default_exposure' do
54
+ let(:defaulted_controller) { Class.new(Controller) }
55
+ let(:instance) { defaulted_controller.new }
56
+ context 'when the default_exposure is overridden' do
126
57
  before do
127
- ActionController::Base.class_eval do
128
- def params; {'id' => 24}; end
58
+ defaulted_controller.class_eval do
59
+ default_exposure { 'default value' }
60
+ expose(:default)
129
61
  end
130
62
  end
131
- it "calls find with params[:id] on the resource's class" do
132
- Resource.expects(:find).with(24)
133
- controller.resource
63
+ it 'uses the overridden default_exposure' do
64
+ instance.default.should == 'default value'
134
65
  end
135
66
  end
136
- end
137
-
138
- let(:widget){ 'widget' }
139
- let(:widget_class_name){ 'Widget' }
140
- before do
141
- widget.stubs(:to_s => widget, :classify => widget_class_name)
142
- widget_class_name.stubs(:constantize => Widget)
143
- end
144
-
145
- let(:my_controller) {MyController.new}
146
-
147
- it "works in descendant controllers" do
148
- name = widget
149
- Widget.expects(:find).with(123).returns('a widget')
150
- MyController.class_eval do
151
- def params; {'id' => 123} end
152
- expose name
153
- end
154
-
155
- my_controller.widget.should == 'a widget'
156
- end
157
-
158
- it "allows overridden default in descendant controllers" do
159
- MyController.class_eval do
160
- default_exposure {|name| name.to_s}
161
- expose :overridden
162
- end
163
- my_controller.overridden.should == 'overridden'
164
- end
165
67
 
166
- it "preserves default in ancestors" do
167
- name = widget
168
- Widget.stubs(:find).returns('preserved')
169
- ActionController::Base.class_eval do
170
- expose name
68
+ context 'with named arguments' do
69
+ it 'makes the named arguments available' do
70
+ defaulted_controller.class_eval do
71
+ default_exposure {|name| "I got: '#{name}'"}
72
+ expose :default
73
+ end
74
+ instance.default.should == "I got: 'default'"
75
+ end
171
76
  end
172
- controller.widget.should == 'preserved'
173
77
  end
174
78
  end
175
79
  end
@@ -0,0 +1,130 @@
1
+ require 'helper'
2
+ require 'action_controller'
3
+ require 'decent_exposure/railtie'
4
+ DecentExposure::Railtie.insert
5
+
6
+ class Resource
7
+ def self.scoped(opts); self; end
8
+ def self.find(*args); end
9
+ def initialize(*args); end
10
+ end
11
+
12
+ describe "Rails' integration:", DecentExposure do
13
+ let(:controller) { Class.new(ActionController::Base) }
14
+ let(:instance) { controller.new }
15
+ let(:request) { mock(:get? => true) }
16
+ let(:params) { HashWithIndifferentAccess.new(:resource_id => 42) }
17
+
18
+ before do
19
+ controller.expose(:resource)
20
+ instance.stubs(:request).returns(request)
21
+ end
22
+
23
+ context '.expose' do
24
+ it 'is available to ActionController::Base' do
25
+ ActionController::Base.should respond_to(:expose)
26
+ end
27
+ end
28
+
29
+ context 'within descendant controllers' do
30
+ let(:resource_controller) { Class.new(ActionController::Base) }
31
+ let(:instance) { resource_controller.new }
32
+
33
+ before do
34
+ instance.stubs(:request).returns(request)
35
+ instance.stubs(:params).returns(params)
36
+ resource_controller.expose :resource
37
+ end
38
+
39
+ it 'inherits the default_exposure' do
40
+ Resource.stubs(:find).returns('resource')
41
+ instance.resource.should == 'resource'
42
+ end
43
+
44
+ it 'allows you to override the default_exposure' do
45
+ resource_controller.class_eval do
46
+ default_exposure {|name| name.to_s}
47
+ expose :overridden
48
+ end
49
+ instance.overridden.should == 'overridden'
50
+ end
51
+
52
+ it 'does not override the default in ancestors' do
53
+ Resource.stubs(:find).returns('preserved')
54
+ instance.resource.should == 'preserved'
55
+ end
56
+ end
57
+
58
+ context '.default_exposure' do
59
+ before do
60
+ instance.stubs(:params).returns(params)
61
+ end
62
+
63
+ it 'is available to ActionController::Base' do
64
+ ActionController::Base.should respond_to(:default_exposure)
65
+ end
66
+
67
+ context 'when no collection method exists' do
68
+ it 'creates a collection method to scope from' do
69
+ instance.resource
70
+ instance.methods.should include('resources')
71
+ end
72
+ end
73
+
74
+ context 'when a collection method exists' do
75
+ let(:controller){ Class.new(ActionController::Base) }
76
+ let(:instance){ controller.new }
77
+
78
+ before { class Person < Resource; end }
79
+
80
+ context 'and the collection can be scoped' do
81
+ let(:collection){ mock(:scoped => [self]) }
82
+
83
+ before{ controller.expose(:person) }
84
+
85
+ it 'uses the existing collection method' do
86
+ instance.stubs(:people).returns(collection)
87
+ collection.expects(:new)
88
+ instance.person
89
+ end
90
+ end
91
+ context 'when the collection can not be scoped' do
92
+ let(:collection){ mock }
93
+
94
+ before{ controller.expose(:person) }
95
+
96
+ it 'falls back to the singularized constant' do
97
+ instance.stubs(:people).returns(collection)
98
+ Person.expects(:new)
99
+ instance.person
100
+ end
101
+ end
102
+ end
103
+
104
+ context 'when either :resource_id or :id are present in params' do
105
+ it "calls find with params[:resource_id] on the resource's class" do
106
+ Resource.expects(:find).with(42)
107
+ instance.resource
108
+ end
109
+
110
+ context 'when there is no :resource_id in params' do
111
+ before { instance.stubs(:params).returns({:id => 73}) }
112
+
113
+ it "calls find with params[:id] on the resource's class" do
114
+ Resource.expects(:find).with(73)
115
+ instance.resource
116
+ end
117
+ end
118
+ end
119
+ context 'when there are no ids in params' do
120
+ before do
121
+ instance.stubs(:params).returns({:resource => {:name => 'bob'}})
122
+ end
123
+
124
+ it 'calls new with params[:resouce_name]' do
125
+ Resource.expects(:new).with({:name => 'bob'})
126
+ instance.resource
127
+ end
128
+ end
129
+ end
130
+ end
metadata CHANGED
@@ -1,12 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: decent_exposure
3
3
  version: !ruby/object:Gem::Version
4
- prerelease: false
4
+ prerelease: true
5
5
  segments:
6
+ - 1
7
+ - 0
6
8
  - 0
7
- - 2
8
- - 4
9
- version: 0.2.4
9
+ - rc1
10
+ version: 1.0.0.rc1
10
11
  platform: ruby
11
12
  authors:
12
13
  - Stephen Caudill
@@ -15,7 +16,7 @@ autorequire:
15
16
  bindir: bin
16
17
  cert_chain: []
17
18
 
18
- date: 2010-07-01 00:00:00 -04:00
19
+ date: 2010-07-16 00:00:00 -04:00
19
20
  default_executable:
20
21
  dependencies:
21
22
  - !ruby/object:Gem::Dependency
@@ -46,6 +47,18 @@ dependencies:
46
47
  version: 0.9.8
47
48
  type: :development
48
49
  version_requirements: *id002
50
+ - !ruby/object:Gem::Dependency
51
+ name: actionpack
52
+ prerelease: false
53
+ requirement: &id003 !ruby/object:Gem::Requirement
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ segments:
58
+ - 0
59
+ version: "0"
60
+ type: :development
61
+ version_requirements: *id003
49
62
  description: "\n DecentExposure helps you program to an interface, rather than an implementation\n in your Rails controllers. The fact of the matter is that sharing state\n via instance variables in controllers promotes close coupling with views.\n DecentExposure gives you a declarative manner of exposing an interface to the\n state that controllers contain and thereby decreasing coupling and\n improving your testability and overall design.\n "
50
63
  email: scaudill@gmail.com
51
64
  executables: []
@@ -59,6 +72,7 @@ files:
59
72
  - README.md
60
73
  - VERSION
61
74
  - lib/decent_exposure.rb
75
+ - lib/decent_exposure/default_exposure.rb
62
76
  - lib/decent_exposure/railtie.rb
63
77
  - rails/init.rb
64
78
  has_rdoc: true
@@ -79,11 +93,13 @@ required_ruby_version: !ruby/object:Gem::Requirement
79
93
  version: "0"
80
94
  required_rubygems_version: !ruby/object:Gem::Requirement
81
95
  requirements:
82
- - - ">="
96
+ - - ">"
83
97
  - !ruby/object:Gem::Version
84
98
  segments:
85
- - 0
86
- version: "0"
99
+ - 1
100
+ - 3
101
+ - 1
102
+ version: 1.3.1
87
103
  requirements: []
88
104
 
89
105
  rubyforge_project:
@@ -94,3 +110,4 @@ summary: A helper for creating declarative interfaces in controllers
94
110
  test_files:
95
111
  - spec/helper.rb
96
112
  - spec/lib/decent_exposure_spec.rb
113
+ - spec/lib/rails_integration_spec.rb