class-action 0.0.1

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.
@@ -0,0 +1,264 @@
1
+ require 'spec_helper'
2
+
3
+ describe ClassAction::Action do
4
+
5
+ let(:controller) { double(:controller, :view_assigns => {}, :response_body => nil) }
6
+ let(:action_class) { Class.new(ClassAction::Action) }
7
+ let(:action) { action_class.new(controller) }
8
+
9
+ it "should by default be available" do
10
+ expect(action).to be_available
11
+ end
12
+
13
+ describe '.helpers && .helper_method' do
14
+ it "should create an empty module upon inheritance" do
15
+ expect(action_class.helpers).to be_a(Module)
16
+ end
17
+
18
+ it "should define the helper method in the action's helpers module, which should call the method on the controller action" do
19
+ action_class.class_eval do
20
+ def helper1
21
+ 'HELPER RESULT'
22
+ end
23
+ helper_method :helper1
24
+ end
25
+
26
+ helpers = action_class.helpers
27
+ klass = Class.new do
28
+ include helpers
29
+ attr_reader :controller
30
+ def initialize(controller)
31
+ @controller = controller
32
+ end
33
+ end
34
+
35
+ obj = klass.new(controller)
36
+
37
+ expect(obj).to respond_to(:helper1)
38
+ expect(controller).to receive(:class_action).and_return(action)
39
+ expect(obj.helper1).to eql('HELPER RESULT')
40
+ end
41
+ end
42
+
43
+ describe '.controller_method' do
44
+ before { allow(controller).to receive(:load_post) }
45
+ before { action_class.class_eval { controller_method :load_post } }
46
+
47
+ it "should create a protected method :load_post" do
48
+ expect(action.protected_methods).to include(:load_post)
49
+ end
50
+
51
+ it "should create a proxy to the controller" do
52
+ result = double(:result)
53
+ expect(controller).to receive(:load_post).and_return(result)
54
+ expect(action.send(:load_post)).to be(result)
55
+ end
56
+
57
+ it "should copy assigns to the controller before executing the controller method, and copy them back afterwards" do
58
+ # Simulate an instance variable.
59
+ var = 1
60
+ allow(controller).to receive(:view_assigns) do
61
+ {'var' => var}
62
+ end
63
+ allow(controller).to receive(:instance_variable_set).with(:@var, an_instance_of(Fixnum)) do |_, num|
64
+ var = num
65
+ end
66
+ expect(controller).to receive(:increase_var) do
67
+ var += 1
68
+ end
69
+
70
+ action_class.class_eval do
71
+ controller_method :increase_var
72
+ def execute
73
+ @var = 2
74
+ increase_var
75
+ end
76
+ end
77
+
78
+ # Even though it's set to 1 initially, it is set to 2 by copying
79
+ # the assigns to the controller, and subsequently increased by 1
80
+ # to end up as 3 - both the controller and the action's versions.
81
+
82
+ action._execute
83
+ expect(var).to eql(3)
84
+ expect(action.instance_variable_get('@var')).to eql(3)
85
+ end
86
+ end
87
+
88
+ describe '.action_methods' do
89
+ it "should include (in order) - only the public defined action methods in the action class" do
90
+ action_class.class_eval do
91
+ def method1; end
92
+ def method2; end
93
+
94
+ protected
95
+ def method3; end
96
+
97
+ private
98
+ def method4; end
99
+ end
100
+
101
+ expect(action_class.action_methods).to eql([ :method1, :method2 ])
102
+ end
103
+ end
104
+
105
+ describe '#_execute' do
106
+ it "should raise an exception if the action is not available" do
107
+ expect(action).to receive(:available?).and_return(false)
108
+ expect{ action._execute }.to raise_error(ClassAction::ActionNotAvailable)
109
+ end
110
+
111
+ it "should execute all action methods in the action, and call #copy_assigns_to_controller finally" do
112
+ called = []
113
+
114
+ expect(action_class).to receive(:action_methods).and_return([:method1, :method2])
115
+ expect(action).to receive(:method1) { called << :method1 }
116
+ expect(action).to receive(:method2) { called << :method2 }
117
+
118
+ action._execute
119
+ expect(called).to eql([:method1, :method2])
120
+ end
121
+
122
+ it "should stop executing when a response body is set" do
123
+ called = []; response_body = nil
124
+
125
+ allow(controller).to receive(:response_body) { response_body }
126
+ expect(action_class).to receive(:action_methods).and_return([:method1, :method2])
127
+ expect(action).to receive(:method1) { called << :method1; response_body = '<html></html>' }
128
+ expect(action).not_to receive(:method2)
129
+
130
+ action._execute
131
+ expect(called).to eql([:method1])
132
+ end
133
+
134
+ it "should call _respond at the end" do
135
+ called = []
136
+
137
+ expect(action_class).to receive(:action_methods).and_return([:method1, :method2])
138
+ expect(action).to receive(:method1) { called << :method1 }
139
+ expect(action).to receive(:method2) { called << :method2 }
140
+ expect(action).to receive(:_respond) { called << :_respond }
141
+
142
+ action._execute
143
+ expect(called).to eql([:method1, :method2, :_respond])
144
+ end
145
+
146
+ it "should not call _respond if a response body is set" do
147
+ allow(controller).to receive(:response_body).and_return('<html></html>')
148
+ expect(action).not_to receive(:_respond)
149
+ action._execute
150
+ end
151
+
152
+ end
153
+
154
+ describe '#_respond' do
155
+
156
+ # Note - as _respond is a private method, we will call _execute to test
157
+ # this method. _execute does not perform other actions if no public methods
158
+ # are defined.
159
+
160
+ it "should always copy assignment variables back to the controller" do
161
+ action_class.class_eval do
162
+ def set_ivar
163
+ @my_var = :test
164
+ end
165
+ end
166
+
167
+ expect(controller).to receive(:instance_variable_set).with(:@my_var, :test)
168
+ action._execute
169
+ end
170
+
171
+ context "with no respond with or responders" do
172
+ it "should not call a respond method, but copy all instance variables into the controller at the end" do
173
+ expect(controller).not_to receive(:respond_with)
174
+ expect(controller).not_to receive(:respond_to)
175
+ action._execute
176
+ end
177
+ end
178
+
179
+ context "having set a respond_with" do
180
+ let(:response) { double(:response) }
181
+ before do
182
+ action_class.class_eval do
183
+ respond_with :response
184
+ end
185
+ expect(action).to receive(:response).and_return(response)
186
+ end
187
+
188
+ it "should call the respond_with method and use it in the response" do
189
+ expect(controller).to receive(:respond_with).with(response) do |&blk|
190
+ expect(blk).to be_nil
191
+ end
192
+
193
+ action._execute
194
+ end
195
+
196
+ it "should use the _respond_block if it is set" do
197
+ block = proc{}
198
+ allow(action).to receive(:_respond_block).and_return(block)
199
+
200
+ expect(controller).to receive(:respond_with).with(response) do |&blk|
201
+ expect(blk).to be(block)
202
+ end
203
+
204
+ action._execute
205
+ end
206
+
207
+ end
208
+
209
+ context "having set _respond_block" do
210
+
211
+ it "should use the _respond_block" do
212
+ block = proc{}
213
+ allow(action).to receive(:_respond_block).and_return(block)
214
+
215
+ expect(controller).to receive(:respond_to) do |&blk|
216
+ expect(blk).to be(block)
217
+ end
218
+
219
+ action._execute
220
+ end
221
+
222
+ end
223
+
224
+ end
225
+
226
+ describe 'responders & _respond_block' do
227
+
228
+ # Private method, but specced individually to make spec terser.
229
+
230
+ let(:respond_block) { action.send(:_respond_block) }
231
+
232
+ it "should create a block using the given responders, which is executed on the action" do
233
+ called = nil; receiver = nil
234
+ json_block = proc { receiver = self; called = :json }
235
+ html_block = proc { receiver = self; called = :html }
236
+ any_block = proc { receiver = self; called = :any }
237
+
238
+ action_class.class_eval do
239
+ respond_to :json, &json_block
240
+ respond_to :html, &html_block
241
+ respond_to_any &any_block
242
+ end
243
+
244
+ # Simulate ActionController's format collector.
245
+ collector = Class.new{ attr_reader :json_block, :html_block, :any_block }.new
246
+ def collector.json(&block) @json_block = block end
247
+ def collector.html(&block) @html_block = block end
248
+ def collector.any(&block) @any_block = block end
249
+
250
+ respond_block.call collector
251
+
252
+ collector.json_block.call
253
+ expect(receiver).to be(action); expect(called).to be(:json)
254
+
255
+ collector.html_block.call
256
+ expect(receiver).to be(action); expect(called).to be(:html)
257
+
258
+ collector.any_block.call
259
+ expect(receiver).to be(action); expect(called).to be(:any)
260
+ end
261
+
262
+ end
263
+
264
+ end
@@ -0,0 +1,185 @@
1
+ require 'spec_helper'
2
+
3
+ describe ClassAction do
4
+
5
+ let(:controller) { ClassActionTestController.new }
6
+
7
+ before do
8
+ Object.send :remove_const, :ClassActionTestController if defined?(ClassActionTestController)
9
+
10
+ class ::ClassActionTestController < ActionController::Base
11
+ include ClassAction
12
+
13
+ def self.logger
14
+ @logger ||= Logger.new(STDOUT)
15
+ end
16
+
17
+ class Show < ClassAction::Action
18
+ end
19
+
20
+ class OtherShow < ClassAction::Action
21
+ end
22
+ end
23
+ end
24
+
25
+ context "adding a class action :show" do
26
+
27
+ before { ClassActionTestController.class_eval { class_action :show } }
28
+
29
+ it "should respond to method :show" do
30
+ expect(controller).to respond_to(:show)
31
+ end
32
+
33
+ it "should add helper methods from the action class to the view context class" do
34
+ helpers = Module.new do
35
+ def method_added_by_class_action
36
+ end
37
+ end
38
+
39
+ action_class = double(:helpers => helpers)
40
+ allow(controller).to receive(:class_action).and_return(double(:class => action_class))
41
+ expect(controller.view_context).to respond_to(:method_added_by_class_action)
42
+ end
43
+
44
+ context "when executing the action" do
45
+ let(:action) { action = double(:action, :_execute => nil) }
46
+ before { expect(ClassActionTestController::Show).to receive(:new).with(controller).and_return(action) }
47
+
48
+ it "should try to instantiate TestController::Show and execute it" do
49
+ expect(action).to receive(:_execute)
50
+ controller.show
51
+ end
52
+
53
+ it "should store the created action in the controller" do
54
+ controller.show
55
+ expect(controller.class_action).to be(action)
56
+ end
57
+
58
+ it "should not appear in the view assigns" do
59
+ controller.show
60
+ expect(controller.view_assigns).not_to have_key('_class_action')
61
+ end
62
+ end
63
+
64
+ context "giving another action class" do
65
+ before do
66
+ ClassActionTestController.class_eval do
67
+ class_action :show, klass: ClassActionTestController::OtherShow
68
+ end
69
+ end
70
+
71
+ it "should try to instantiate the given action class when executed" do
72
+ action = ClassActionTestController::OtherShow.new(controller)
73
+ expect(ClassActionTestController::OtherShow).to receive(:new).with(controller).and_return(action)
74
+ controller.show
75
+
76
+ expect(controller.class_action).to be(action)
77
+ end
78
+ end
79
+
80
+ end
81
+
82
+ describe "respond mime injection" do
83
+
84
+ before do
85
+ ClassActionTestController::Show.class_eval do
86
+ respond_to :html
87
+ end
88
+ end
89
+
90
+ it "should create mimes with :only => 'show' for nonexisting mimes" do
91
+ ClassActionTestController.class_eval { class_action :show }
92
+ ClassActionTestController.mimes_for_respond_to.should eql(
93
+ :html => {:only => %w[show]}
94
+ )
95
+ end
96
+
97
+ it "should append the action 'show' to existing mimes with an :only restriction" do
98
+ ClassActionTestController.class_eval do
99
+ respond_to :html, :only => [ :index ]
100
+ class_action :show
101
+ end
102
+
103
+ ClassActionTestController.mimes_for_respond_to.should eql(
104
+ :html => {:only => %w[index show]}
105
+ )
106
+ end
107
+
108
+ it "should not append the action 'show' to existing mimes with no :only restriction" do
109
+ ClassActionTestController.class_eval do
110
+ respond_to :html
111
+ class_action :show
112
+ end
113
+
114
+ ClassActionTestController.mimes_for_respond_to.should eql(
115
+ :html => {}
116
+ )
117
+ end
118
+
119
+ it "should not append the action 'show' if it was already targeted" do
120
+ ClassActionTestController.class_eval do
121
+ respond_to :html, :only => [ :show ]
122
+ class_action :show
123
+ end
124
+
125
+ ClassActionTestController.mimes_for_respond_to.should eql(
126
+ :html => { :only => %w[show] }
127
+ )
128
+ end
129
+
130
+ it "should not append the action 'show' if it was also already to the :except list (but log a warning)" do
131
+ expect(ClassActionTestController.logger).to receive(:warn).with("Warning: action show (ClassAction) responds to `html` but it does not accept this mime type")
132
+
133
+ ClassActionTestController.class_eval do
134
+ respond_to :html, :except => [ :show ]
135
+ class_action :show
136
+ end
137
+
138
+ ClassActionTestController.mimes_for_respond_to.should eql(
139
+ :html => { :except => %w[show] }
140
+ )
141
+ end
142
+
143
+ it "should exclude the action from any other mime types that may be defined" do
144
+ ClassActionTestController.class_eval do
145
+ respond_to :json
146
+ class_action :show
147
+ end
148
+
149
+ ClassActionTestController.mimes_for_respond_to.should eql(
150
+ :html => { :only => %w[show] },
151
+ :json => { :except => %w[show] }
152
+ )
153
+ end
154
+
155
+ it "should leave everything alone if the class action has no responders" do
156
+ allow(ClassActionTestController::Show).to receive(:responders).and_return({})
157
+
158
+ ClassActionTestController.class_eval do
159
+ respond_to :json
160
+ class_action :show
161
+ end
162
+
163
+ ClassActionTestController.mimes_for_respond_to.should eql(
164
+ :json => {}
165
+ )
166
+ end
167
+
168
+ it "should leave everything alone if the class action has an 'any' responder" do
169
+ ClassActionTestController::Show.class_eval do
170
+ respond_to_any
171
+ end
172
+
173
+ ClassActionTestController.class_eval do
174
+ respond_to :json
175
+ class_action :show
176
+ end
177
+
178
+ ClassActionTestController.mimes_for_respond_to.should eql(
179
+ :json => {}
180
+ )
181
+ end
182
+
183
+ end
184
+
185
+ end
@@ -0,0 +1,15 @@
1
+ require 'action_controller'
2
+ require 'class-action'
3
+ require 'rspec/autorun'
4
+
5
+ RSpec.configure do |config|
6
+
7
+ config.mock_with :rspec do |config|
8
+ config.syntax = :expect
9
+ end
10
+
11
+ end
12
+
13
+ # Requires supporting ruby files with custom matchers and macros, etc,
14
+ # in spec/support/ and its subdirectories.
15
+ Dir[File.expand_path("../support/**/*.rb", __FILE__)].each {|f| require f}
metadata ADDED
@@ -0,0 +1,135 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: class-action
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Joost Lubach
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-09-22 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activesupport
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '3.2'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '3.2'
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: '1.3'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: '1.3'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: '2.14'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ~>
67
+ - !ruby/object:Gem::Version
68
+ version: '2.14'
69
+ - !ruby/object:Gem::Dependency
70
+ name: actionpack
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ~>
74
+ - !ruby/object:Gem::Version
75
+ version: '3.2'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ~>
81
+ - !ruby/object:Gem::Version
82
+ version: '3.2'
83
+ description: Allows you to write controller actions as classes, rather than methods.
84
+ email:
85
+ - joost@yoazt.com
86
+ executables: []
87
+ extensions: []
88
+ extra_rdoc_files: []
89
+ files:
90
+ - .gitignore
91
+ - .ruby-gemset
92
+ - .ruby-version
93
+ - ClassAction.sublime-project
94
+ - ClassAction.sublime-workspace
95
+ - Gemfile
96
+ - LICENSE.txt
97
+ - README.md
98
+ - Rakefile
99
+ - class-action.gemspec
100
+ - lib/class-action.rb
101
+ - lib/class_action.rb
102
+ - lib/class_action/action.rb
103
+ - lib/class_action/version.rb
104
+ - spec/class_action/action_spec.rb
105
+ - spec/class_action_spec.rb
106
+ - spec/spec_helper.rb
107
+ homepage: ''
108
+ licenses:
109
+ - MIT
110
+ metadata: {}
111
+ post_install_message:
112
+ rdoc_options: []
113
+ require_paths:
114
+ - lib
115
+ required_ruby_version: !ruby/object:Gem::Requirement
116
+ requirements:
117
+ - - '>='
118
+ - !ruby/object:Gem::Version
119
+ version: '0'
120
+ required_rubygems_version: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - '>='
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ requirements: []
126
+ rubyforge_project:
127
+ rubygems_version: 2.0.3
128
+ signing_key:
129
+ specification_version: 4
130
+ summary: Allows you to write controller actions as classes, rather than methods.
131
+ test_files:
132
+ - spec/class_action/action_spec.rb
133
+ - spec/class_action_spec.rb
134
+ - spec/spec_helper.rb
135
+ has_rdoc: