object-filters 0.0.5

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/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ /pkg
2
+ .rvmrc
3
+ .DS_Store
4
+ Gemfile.lock
data/Gemfile ADDED
@@ -0,0 +1,8 @@
1
+ source :rubygems
2
+
3
+ gemspec
4
+
5
+ group :development do
6
+ gem 'bundler'
7
+ gem 'rspec'
8
+ end
data/Rakefile ADDED
@@ -0,0 +1,28 @@
1
+ require 'rake/version_task'
2
+ require 'rspec/core/rake_task'
3
+
4
+ spec = Gem::Specification.new do |s|
5
+ s.name = 'object-filters'
6
+ s.platform = Gem::Platform::RUBY
7
+ s.author = 'Ryan Scott Lewis'
8
+ s.email = 'ryan@rynet.us'
9
+ s.homepage = "http://rubygems.org/gems/#{s.name}"
10
+ s.summary = 'Use before, after, and around filters with your objects!'
11
+ s.description = 'This gem provides ActionController::Filters for your custom classes.'
12
+ s.require_path = 'lib'
13
+ s.post_install_message = "This is a placeholder gem... for now. Check back in a few versions!"
14
+ s.files = `git ls-files`.lines.to_a.collect { |s| s.strip }
15
+ s.executables = `git ls-files -- bin/*`.lines.to_a.collect { |s| File.basename(s.strip) }
16
+
17
+ s.add_dependency 'version', '~> 1'
18
+ s.add_dependency 'active_support', '~> 3'
19
+ end
20
+
21
+ Rake::VersionTask.new do |t|
22
+ t.with_git_tag = true
23
+ t.with_gemspec = spec
24
+ end
25
+
26
+ RSpec::Core::RakeTask.new
27
+
28
+ task :default => :spec
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.5
data/filters.gemspec ADDED
@@ -0,0 +1,33 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = "object-filters"
5
+ s.version = "0.0.5"
6
+
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["Ryan Scott Lewis"]
9
+ s.date = "2012-10-08"
10
+ s.description = "This gem provides ActionController::Filters for normal applications."
11
+ s.email = ["ryan@rynet.us"]
12
+ s.files = [".gitignore", "Gemfile", "Rakefile", "VERSION", "filters.gemspec", "lib/filters.rb", "spec/filters_spec.rb", "spec/spec_helper.rb"]
13
+ s.homepage = "http://rubygems.org/gems/filters"
14
+ s.post_install_message = "This is a placeholder gem... for now. Check back in a few versions!"
15
+ s.require_paths = ["lib"]
16
+ s.rubygems_version = "1.8.24"
17
+ s.summary = "Use before, after, and around filters with your objects!"
18
+
19
+ if s.respond_to? :specification_version then
20
+ s.specification_version = 3
21
+
22
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
23
+ s.add_runtime_dependency(%q<version>, ["~> 1"])
24
+ s.add_runtime_dependency(%q<active_support>, ["~> 3"])
25
+ else
26
+ s.add_dependency(%q<version>, ["~> 1"])
27
+ s.add_dependency(%q<active_support>, ["~> 3"])
28
+ end
29
+ else
30
+ s.add_dependency(%q<version>, ["~> 1"])
31
+ s.add_dependency(%q<active_support>, ["~> 3"])
32
+ end
33
+ end
data/lib/filters.rb ADDED
@@ -0,0 +1,203 @@
1
+ require 'pathname'
2
+ require 'bundler/setup'
3
+ require 'version'
4
+ require 'active_support/concern'
5
+ require 'active_support/callbacks'
6
+
7
+ __PATH__ = Pathname.new(__FILE__)
8
+ $:.unshift(__PATH__.dirname.to_s) unless $:.include?(__PATH__.dirname.to_s)
9
+
10
+ module AbstractController
11
+ module Callbacks
12
+ extend ActiveSupport::Concern
13
+
14
+ # Uses ActiveSupport::Callbacks as the base functionality. For
15
+ # more details on the whole callback system, read the documentation
16
+ # for ActiveSupport::Callbacks.
17
+ include ActiveSupport::Callbacks
18
+
19
+ included do
20
+ define_callbacks :process_action, :terminator => "response_body", :skip_after_callbacks_if_terminated => true
21
+ end
22
+
23
+ # Override AbstractController::Base's process_action to run the
24
+ # process_action callbacks around the normal behavior.
25
+ def process_action(*args)
26
+ run_callbacks(:process_action) do
27
+ super
28
+ end
29
+ end
30
+
31
+ module ClassMethods
32
+ # If :only or :except are used, convert the options into the
33
+ # :unless and :if options of ActiveSupport::Callbacks.
34
+ # The basic idea is that :only => :index gets converted to
35
+ # :if => proc {|c| c.action_name == "index" }.
36
+ #
37
+ # ==== Options
38
+ # * <tt>only</tt> - The callback should be run only for this action
39
+ # * <tt>except</tt> - The callback should be run for all actions except this action
40
+ def _normalize_callback_options(options)
41
+ if only = options[:only]
42
+ only = Array(only).map {|o| "action_name == '#{o}'"}.join(" || ")
43
+ options[:if] = Array(options[:if]) << only
44
+ end
45
+ if except = options[:except]
46
+ except = Array(except).map {|e| "action_name == '#{e}'"}.join(" || ")
47
+ options[:unless] = Array(options[:unless]) << except
48
+ end
49
+ end
50
+
51
+ # Skip before, after, and around filters matching any of the names
52
+ #
53
+ # ==== Parameters
54
+ # * <tt>names</tt> - A list of valid names that could be used for
55
+ # callbacks. Note that skipping uses Ruby equality, so it's
56
+ # impossible to skip a callback defined using an anonymous proc
57
+ # using #skip_filter
58
+ def skip_filter(*names)
59
+ skip_before_filter(*names)
60
+ skip_after_filter(*names)
61
+ skip_around_filter(*names)
62
+ end
63
+
64
+ # Take callback names and an optional callback proc, normalize them,
65
+ # then call the block with each callback. This allows us to abstract
66
+ # the normalization across several methods that use it.
67
+ #
68
+ # ==== Parameters
69
+ # * <tt>callbacks</tt> - An array of callbacks, with an optional
70
+ # options hash as the last parameter.
71
+ # * <tt>block</tt> - A proc that should be added to the callbacks.
72
+ #
73
+ # ==== Block Parameters
74
+ # * <tt>name</tt> - The callback to be added
75
+ # * <tt>options</tt> - A hash of options to be used when adding the callback
76
+ def _insert_callbacks(callbacks, block = nil)
77
+ options = callbacks.last.is_a?(Hash) ? callbacks.pop : {}
78
+ _normalize_callback_options(options)
79
+ callbacks.push(block) if block
80
+ callbacks.each do |callback|
81
+ yield callback, options
82
+ end
83
+ end
84
+
85
+ ##
86
+ # :method: before_filter
87
+ #
88
+ # :call-seq: before_filter(names, block)
89
+ #
90
+ # Append a before filter. See _insert_callbacks for parameter details.
91
+
92
+ ##
93
+ # :method: prepend_before_filter
94
+ #
95
+ # :call-seq: prepend_before_filter(names, block)
96
+ #
97
+ # Prepend a before filter. See _insert_callbacks for parameter details.
98
+
99
+ ##
100
+ # :method: skip_before_filter
101
+ #
102
+ # :call-seq: skip_before_filter(names)
103
+ #
104
+ # Skip a before filter. See _insert_callbacks for parameter details.
105
+
106
+ ##
107
+ # :method: append_before_filter
108
+ #
109
+ # :call-seq: append_before_filter(names, block)
110
+ #
111
+ # Append a before filter. See _insert_callbacks for parameter details.
112
+
113
+ ##
114
+ # :method: after_filter
115
+ #
116
+ # :call-seq: after_filter(names, block)
117
+ #
118
+ # Append an after filter. See _insert_callbacks for parameter details.
119
+
120
+ ##
121
+ # :method: prepend_after_filter
122
+ #
123
+ # :call-seq: prepend_after_filter(names, block)
124
+ #
125
+ # Prepend an after filter. See _insert_callbacks for parameter details.
126
+
127
+ ##
128
+ # :method: skip_after_filter
129
+ #
130
+ # :call-seq: skip_after_filter(names)
131
+ #
132
+ # Skip an after filter. See _insert_callbacks for parameter details.
133
+
134
+ ##
135
+ # :method: append_after_filter
136
+ #
137
+ # :call-seq: append_after_filter(names, block)
138
+ #
139
+ # Append an after filter. See _insert_callbacks for parameter details.
140
+
141
+ ##
142
+ # :method: around_filter
143
+ #
144
+ # :call-seq: around_filter(names, block)
145
+ #
146
+ # Append an around filter. See _insert_callbacks for parameter details.
147
+
148
+ ##
149
+ # :method: prepend_around_filter
150
+ #
151
+ # :call-seq: prepend_around_filter(names, block)
152
+ #
153
+ # Prepend an around filter. See _insert_callbacks for parameter details.
154
+
155
+ ##
156
+ # :method: skip_around_filter
157
+ #
158
+ # :call-seq: skip_around_filter(names)
159
+ #
160
+ # Skip an around filter. See _insert_callbacks for parameter details.
161
+
162
+ ##
163
+ # :method: append_around_filter
164
+ #
165
+ # :call-seq: append_around_filter(names, block)
166
+ #
167
+ # Append an around filter. See _insert_callbacks for parameter details.
168
+
169
+ # set up before_filter, prepend_before_filter, skip_before_filter, etc.
170
+ # for each of before, after, and around.
171
+ [:before, :after, :around].each do |filter|
172
+ class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1
173
+ # Append a before, after or around filter. See _insert_callbacks
174
+ # for details on the allowed parameters.
175
+ def #{filter}_filter(*names, &blk) # def before_filter(*names, &blk)
176
+ _insert_callbacks(names, blk) do |name, options| # _insert_callbacks(names, blk) do |name, options|
177
+ set_callback(:process_action, :#{filter}, name, options) # set_callback(:process_action, :before, name, options)
178
+ end # end
179
+ end # end
180
+
181
+ # Prepend a before, after or around filter. See _insert_callbacks
182
+ # for details on the allowed parameters.
183
+ def prepend_#{filter}_filter(*names, &blk) # def prepend_before_filter(*names, &blk)
184
+ _insert_callbacks(names, blk) do |name, options| # _insert_callbacks(names, blk) do |name, options|
185
+ set_callback(:process_action, :#{filter}, name, options.merge(:prepend => true)) # set_callback(:process_action, :before, name, options.merge(:prepend => true))
186
+ end # end
187
+ end # end
188
+
189
+ # Skip a before, after or around filter. See _insert_callbacks
190
+ # for details on the allowed parameters.
191
+ def skip_#{filter}_filter(*names) # def skip_before_filter(*names)
192
+ _insert_callbacks(names) do |name, options| # _insert_callbacks(names) do |name, options|
193
+ skip_callback(:process_action, :#{filter}, name, options) # skip_callback(:process_action, :before, name, options)
194
+ end # end
195
+ end # end
196
+
197
+ # *_filter is the same as append_*_filter
198
+ alias_method :append_#{filter}_filter, :#{filter}_filter # alias_method :append_before_filter, :before_filter
199
+ RUBY_EVAL
200
+ end
201
+ end
202
+ end
203
+ end
@@ -0,0 +1,298 @@
1
+ require 'spec_helper'
2
+
3
+ __END__
4
+
5
+ module AbstractController
6
+ module Testing
7
+
8
+ class ControllerWithCallbacks < AbstractController::Base
9
+ include AbstractController::Callbacks
10
+ end
11
+
12
+ class Callback1 < ControllerWithCallbacks
13
+ set_callback :process_action, :before, :first
14
+
15
+ def first
16
+ @text = "Hello world"
17
+ end
18
+
19
+ def index
20
+ self.response_body = @text
21
+ end
22
+ end
23
+
24
+ class TestCallbacks1 < ActiveSupport::TestCase
25
+ test "basic callbacks work" do
26
+ controller = Callback1.new
27
+ controller.process(:index)
28
+ assert_equal "Hello world", controller.response_body
29
+ end
30
+ end
31
+
32
+ class Callback2 < ControllerWithCallbacks
33
+ before_filter :first
34
+ after_filter :second
35
+ around_filter :aroundz
36
+
37
+ def first
38
+ @text = "Hello world"
39
+ end
40
+
41
+ def second
42
+ @second = "Goodbye"
43
+ end
44
+
45
+ def aroundz
46
+ @aroundz = "FIRST"
47
+ yield
48
+ @aroundz << "SECOND"
49
+ end
50
+
51
+ def index
52
+ @text ||= nil
53
+ self.response_body = @text.to_s
54
+ end
55
+ end
56
+
57
+ class Callback2Overwrite < Callback2
58
+ before_filter :first, :except => :index
59
+ end
60
+
61
+ class TestCallbacks2 < ActiveSupport::TestCase
62
+ def setup
63
+ @controller = Callback2.new
64
+ end
65
+
66
+ test "before_filter works" do
67
+ @controller.process(:index)
68
+ assert_equal "Hello world", @controller.response_body
69
+ end
70
+
71
+ test "after_filter works" do
72
+ @controller.process(:index)
73
+ assert_equal "Goodbye", @controller.instance_variable_get("@second")
74
+ end
75
+
76
+ test "around_filter works" do
77
+ @controller.process(:index)
78
+ assert_equal "FIRSTSECOND", @controller.instance_variable_get("@aroundz")
79
+ end
80
+
81
+ test "before_filter with overwritten condition" do
82
+ @controller = Callback2Overwrite.new
83
+ @controller.process(:index)
84
+ assert_equal "", @controller.response_body
85
+ end
86
+ end
87
+
88
+ class Callback3 < ControllerWithCallbacks
89
+ before_filter do |c|
90
+ c.instance_variable_set("@text", "Hello world")
91
+ end
92
+
93
+ after_filter do |c|
94
+ c.instance_variable_set("@second", "Goodbye")
95
+ end
96
+
97
+ def index
98
+ self.response_body = @text
99
+ end
100
+ end
101
+
102
+ class TestCallbacks3 < ActiveSupport::TestCase
103
+ def setup
104
+ @controller = Callback3.new
105
+ end
106
+
107
+ test "before_filter works with procs" do
108
+ @controller.process(:index)
109
+ assert_equal "Hello world", @controller.response_body
110
+ end
111
+
112
+ test "after_filter works with procs" do
113
+ @controller.process(:index)
114
+ assert_equal "Goodbye", @controller.instance_variable_get("@second")
115
+ end
116
+ end
117
+
118
+ class CallbacksWithConditions < ControllerWithCallbacks
119
+ before_filter :list, :only => :index
120
+ before_filter :authenticate, :except => :index
121
+
122
+ def index
123
+ self.response_body = @list.join(", ")
124
+ end
125
+
126
+ def sekrit_data
127
+ self.response_body = (@list + [@authenticated]).join(", ")
128
+ end
129
+
130
+ private
131
+ def list
132
+ @list = ["Hello", "World"]
133
+ end
134
+
135
+ def authenticate
136
+ @list ||= []
137
+ @authenticated = "true"
138
+ end
139
+ end
140
+
141
+ class TestCallbacksWithConditions < ActiveSupport::TestCase
142
+ def setup
143
+ @controller = CallbacksWithConditions.new
144
+ end
145
+
146
+ test "when :only is specified, a before filter is triggered on that action" do
147
+ @controller.process(:index)
148
+ assert_equal "Hello, World", @controller.response_body
149
+ end
150
+
151
+ test "when :only is specified, a before filter is not triggered on other actions" do
152
+ @controller.process(:sekrit_data)
153
+ assert_equal "true", @controller.response_body
154
+ end
155
+
156
+ test "when :except is specified, an after filter is not triggered on that action" do
157
+ @controller.process(:index)
158
+ assert !@controller.instance_variable_defined?("@authenticated")
159
+ end
160
+ end
161
+
162
+ class CallbacksWithArrayConditions < ControllerWithCallbacks
163
+ before_filter :list, :only => [:index, :listy]
164
+ before_filter :authenticate, :except => [:index, :listy]
165
+
166
+ def index
167
+ self.response_body = @list.join(", ")
168
+ end
169
+
170
+ def sekrit_data
171
+ self.response_body = (@list + [@authenticated]).join(", ")
172
+ end
173
+
174
+ private
175
+ def list
176
+ @list = ["Hello", "World"]
177
+ end
178
+
179
+ def authenticate
180
+ @list = []
181
+ @authenticated = "true"
182
+ end
183
+ end
184
+
185
+ class TestCallbacksWithArrayConditions < ActiveSupport::TestCase
186
+ def setup
187
+ @controller = CallbacksWithArrayConditions.new
188
+ end
189
+
190
+ test "when :only is specified with an array, a before filter is triggered on that action" do
191
+ @controller.process(:index)
192
+ assert_equal "Hello, World", @controller.response_body
193
+ end
194
+
195
+ test "when :only is specified with an array, a before filter is not triggered on other actions" do
196
+ @controller.process(:sekrit_data)
197
+ assert_equal "true", @controller.response_body
198
+ end
199
+
200
+ test "when :except is specified with an array, an after filter is not triggered on that action" do
201
+ @controller.process(:index)
202
+ assert !@controller.instance_variable_defined?("@authenticated")
203
+ end
204
+ end
205
+
206
+ class ChangedConditions < Callback2
207
+ before_filter :first, :only => :index
208
+
209
+ def not_index
210
+ @text ||= nil
211
+ self.response_body = @text.to_s
212
+ end
213
+ end
214
+
215
+ class TestCallbacksWithChangedConditions < ActiveSupport::TestCase
216
+ def setup
217
+ @controller = ChangedConditions.new
218
+ end
219
+
220
+ test "when a callback is modified in a child with :only, it works for the :only action" do
221
+ @controller.process(:index)
222
+ assert_equal "Hello world", @controller.response_body
223
+ end
224
+
225
+ test "when a callback is modified in a child with :only, it does not work for other actions" do
226
+ @controller.process(:not_index)
227
+ assert_equal "", @controller.response_body
228
+ end
229
+ end
230
+
231
+ class SetsResponseBody < ControllerWithCallbacks
232
+ before_filter :set_body
233
+
234
+ def index
235
+ self.response_body = "Fail"
236
+ end
237
+
238
+ def set_body
239
+ self.response_body = "Success"
240
+ end
241
+ end
242
+
243
+ class TestHalting < ActiveSupport::TestCase
244
+ test "when a callback sets the response body, the action should not be invoked" do
245
+ controller = SetsResponseBody.new
246
+ controller.process(:index)
247
+ assert_equal "Success", controller.response_body
248
+ end
249
+ end
250
+
251
+ class CallbacksWithArgs < ControllerWithCallbacks
252
+ set_callback :process_action, :before, :first
253
+
254
+ def first
255
+ @text = "Hello world"
256
+ end
257
+
258
+ def index(text)
259
+ self.response_body = @text + text
260
+ end
261
+ end
262
+
263
+ class TestCallbacksWithArgs < ActiveSupport::TestCase
264
+ test "callbacks still work when invoking process with multiple args" do
265
+ controller = CallbacksWithArgs.new
266
+ controller.process(:index, " Howdy!")
267
+ assert_equal "Hello world Howdy!", controller.response_body
268
+ end
269
+ end
270
+
271
+
272
+ end
273
+ end
274
+
275
+ __END__
276
+ describe Filters do
277
+
278
+ let(:dummy_class) { Class.new { include(Filters) } }
279
+
280
+ describe 'ClassMethods' do
281
+ subject { dummy_class }
282
+
283
+ describe '.some_class_method' do
284
+ it { should respond_to(:some_class_method) }
285
+ end
286
+
287
+ end
288
+
289
+ describe 'InstanceMethods' do
290
+ subject { dummy_class.new }
291
+
292
+ describe '#some_instance_method' do
293
+ it { should respond_to(:some_instance_method) }
294
+ end
295
+
296
+ end
297
+
298
+ end
@@ -0,0 +1 @@
1
+ require 'filters'
metadata ADDED
@@ -0,0 +1,85 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: object-filters
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.5
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Ryan Scott Lewis
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-10-08 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: version
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: '1'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: '1'
30
+ - !ruby/object:Gem::Dependency
31
+ name: active_support
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ~>
36
+ - !ruby/object:Gem::Version
37
+ version: '3'
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ version: '3'
46
+ description: This gem provides ActionController::Filters for normal applications.
47
+ email:
48
+ - ryan@rynet.us
49
+ executables: []
50
+ extensions: []
51
+ extra_rdoc_files: []
52
+ files:
53
+ - .gitignore
54
+ - Gemfile
55
+ - Rakefile
56
+ - VERSION
57
+ - filters.gemspec
58
+ - lib/filters.rb
59
+ - spec/filters_spec.rb
60
+ - spec/spec_helper.rb
61
+ homepage: http://rubygems.org/gems/filters
62
+ licenses: []
63
+ post_install_message: This is a placeholder gem... for now. Check back in a few versions!
64
+ rdoc_options: []
65
+ require_paths:
66
+ - lib
67
+ required_ruby_version: !ruby/object:Gem::Requirement
68
+ none: false
69
+ requirements:
70
+ - - ! '>='
71
+ - !ruby/object:Gem::Version
72
+ version: '0'
73
+ required_rubygems_version: !ruby/object:Gem::Requirement
74
+ none: false
75
+ requirements:
76
+ - - ! '>='
77
+ - !ruby/object:Gem::Version
78
+ version: '0'
79
+ requirements: []
80
+ rubyforge_project:
81
+ rubygems_version: 1.8.24
82
+ signing_key:
83
+ specification_version: 3
84
+ summary: Use before, after, and around filters with your objects!
85
+ test_files: []