paloma 1.2.6 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +2 -3
- data/Changelog.md +0 -4
- data/README.md +206 -67
- data/app/templates/_filters.js +14 -0
- data/app/templates/application/_locals.js +13 -0
- data/app/templates/controller/_locals.js +19 -0
- data/app/templates/controller/_manifest.js +3 -0
- data/app/templates/controller/action.js +23 -0
- data/app/templates/index.js +3 -1
- data/app/templates/namespace/_locals.js +16 -0
- data/app/templates/namespace/_manifest.js +3 -0
- data/app/views/paloma/_callback_hook.html.erb +31 -26
- data/lib/paloma.rb +3 -0
- data/lib/paloma/action_controller_extension.rb +18 -16
- data/lib/paloma/action_controller_filters.rb +4 -7
- data/lib/paloma/generators/add_generator.rb +81 -85
- data/lib/paloma/generators/setup_generator.rb +15 -5
- data/lib/paloma/rails/controller_generator.rb +11 -0
- data/lib/paloma/rails/engine.rb +6 -0
- data/paloma.gemspec +1 -3
- data/spec/test_app/.gitignore +15 -0
- data/spec/test_app/.rspec +1 -0
- data/spec/test_app/Gemfile +2 -0
- data/spec/test_app/README.rdoc +261 -0
- data/spec/test_app/Rakefile +16 -0
- data/spec/test_app/app/assets/javascripts/application.js +16 -0
- data/spec/test_app/app/assets/javascripts/paloma/_filters.js +130 -0
- data/spec/test_app/app/assets/javascripts/paloma/_locals.js +17 -0
- data/spec/test_app/app/assets/javascripts/paloma/bar/_filters.js +96 -0
- data/spec/test_app/app/assets/javascripts/paloma/bar/_locals.js +1 -0
- data/spec/test_app/app/assets/javascripts/paloma/bar/_manifest.js +3 -0
- data/spec/test_app/app/assets/javascripts/paloma/bar/another_basic_action.js +5 -0
- data/spec/test_app/app/assets/javascripts/paloma/bar/basic_action.js +5 -0
- data/spec/test_app/app/assets/javascripts/paloma/bar/different_params.js +4 -0
- data/spec/test_app/app/assets/javascripts/paloma/bar/yet_another_basic_action.js +5 -0
- data/spec/test_app/app/assets/javascripts/paloma/foo/_filters.js +24 -0
- data/spec/test_app/app/assets/javascripts/paloma/foo/_locals.js +21 -0
- data/spec/test_app/app/assets/javascripts/paloma/foo/_manifest.js +3 -0
- data/spec/test_app/app/assets/javascripts/paloma/foo/basic_action.js +21 -0
- data/spec/test_app/app/assets/javascripts/paloma/foo/skip_callback.js +6 -0
- data/spec/test_app/app/assets/javascripts/paloma/index.js +6 -0
- data/spec/test_app/app/assets/javascripts/paloma/sample_namespace/_filters.js +83 -0
- data/spec/test_app/app/assets/javascripts/paloma/sample_namespace/_manifest.js +2 -0
- data/spec/test_app/app/assets/javascripts/paloma/sample_namespace/baz/_filters.js +84 -0
- data/spec/test_app/app/assets/javascripts/paloma/sample_namespace/baz/_locals.js +1 -0
- data/spec/test_app/app/assets/javascripts/paloma/sample_namespace/baz/_manifest.js +2 -0
- data/spec/test_app/app/assets/javascripts/paloma/sample_namespace/baz/another_basic_action.js +5 -0
- data/spec/test_app/app/assets/javascripts/paloma/sample_namespace/baz/basic_action.js +5 -0
- data/spec/test_app/app/assets/javascripts/paloma/sample_namespace/baz/yet_another_basic_action.js +5 -0
- data/spec/test_app/app/controllers/application_controller.rb +3 -0
- data/spec/test_app/app/controllers/bar_controller.rb +28 -0
- data/spec/test_app/app/controllers/foo_controller.rb +25 -0
- data/spec/test_app/app/controllers/sample_namespace/baz_controller.rb +23 -0
- data/spec/{sample_app → test_app}/app/views/layouts/application.html.erb +0 -0
- data/spec/test_app/config.ru +4 -0
- data/spec/test_app/config/application.rb +74 -0
- data/spec/test_app/config/boot.rb +6 -0
- data/spec/test_app/config/environment.rb +5 -0
- data/spec/test_app/config/environments/development.rb +31 -0
- data/spec/test_app/config/environments/production.rb +64 -0
- data/spec/test_app/config/environments/test.rb +35 -0
- data/spec/test_app/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/test_app/config/initializers/inflections.rb +15 -0
- data/spec/test_app/config/initializers/mime_types.rb +5 -0
- data/spec/test_app/config/initializers/secret_token.rb +7 -0
- data/spec/test_app/config/initializers/session_store.rb +8 -0
- data/spec/test_app/config/initializers/wrap_parameters.rb +10 -0
- data/spec/test_app/config/locales/en.yml +5 -0
- data/spec/test_app/config/routes.rb +33 -0
- data/spec/test_app/log/.gitkeep +0 -0
- data/spec/test_app/public/404.html +26 -0
- data/spec/test_app/public/422.html +26 -0
- data/spec/test_app/public/500.html +25 -0
- data/spec/test_app/public/favicon.ico +0 -0
- data/spec/test_app/public/robots.txt +5 -0
- data/spec/test_app/script/rails +6 -0
- data/spec/test_app/spec/generator_helper.rb +87 -0
- data/spec/test_app/spec/generators/paloma_generator_spec.rb +199 -0
- data/spec/test_app/spec/generators/rails_generator_spec.rb +54 -0
- data/spec/test_app/spec/javascripts/callback_spec.rb +64 -0
- data/spec/test_app/spec/javascripts/filters_spec.rb +187 -0
- data/spec/test_app/spec/javascripts/locals_spec.rb +27 -0
- data/spec/test_app/spec/javascripts/params_spec.rb +116 -0
- data/spec/test_app/spec/javascripts/skip_filters_spec.rb +58 -0
- data/spec/test_app/spec/javascripts/variable_container_spec.rb +21 -0
- data/spec/test_app/spec/spec_helper.rb +26 -0
- data/vendor/assets/javascripts/paloma_core.js +294 -0
- metadata +79 -68
- data/Rakefile +0 -28
- data/app/templates/_callbacks.js +0 -2
- data/app/templates/_local.js +0 -20
- data/app/templates/action.js +0 -5
- data/app/templates/paloma.js +0 -22
- data/spec/callback_spec.rb +0 -81
- data/spec/generator_spec.rb +0 -425
- data/spec/sample_app/app/assets/javascripts/application.js +0 -4
- data/spec/sample_app/app/assets/javascripts/paloma/articles/_callbacks.js +0 -1
- data/spec/sample_app/app/assets/javascripts/paloma/articles/create.js +0 -3
- data/spec/sample_app/app/assets/javascripts/paloma/articles/edit.js +0 -3
- data/spec/sample_app/app/assets/javascripts/paloma/articles/index.js +0 -3
- data/spec/sample_app/app/assets/javascripts/paloma/articles/new.js +0 -3
- data/spec/sample_app/app/assets/javascripts/paloma/articles/show.js +0 -3
- data/spec/sample_app/app/assets/javascripts/paloma/articles/update.js +0 -3
- data/spec/sample_app/app/assets/javascripts/paloma/index.js +0 -3
- data/spec/sample_app/app/assets/javascripts/paloma/paloma.js +0 -1
- data/spec/sample_app/app/assets/javascripts/paloma/sample_namespace/_callbacks.js +0 -1
- data/spec/sample_app/app/assets/javascripts/paloma/sample_namespace/categories/_callbacks.js +0 -1
- data/spec/sample_app/app/assets/javascripts/paloma/sample_namespace/categories/index.js +0 -3
- data/spec/sample_app/app/views/articles/index.html.erb +0 -5
- data/spec/sample_app/app/views/articles/new.html.erb +0 -9
- data/spec/sample_app/app/views/articles/show.html.erb +0 -2
- data/spec/sample_app/app/views/sample_namespace/categories/index.html.erb +0 -5
- data/spec/sample_app/app/views/sample_namespace/categories/new.html.erb +0 -5
- data/spec/sample_app/controllers.rb +0 -68
- data/spec/sample_app/init.rb +0 -37
- data/spec/sample_app/models.rb +0 -40
- data/spec/spec_helper.rb +0 -21
- data/spec/test_app/log/development.log +0 -4
- data/spec/test_app/tmp/cache/assets/CF0/DA0/sprockets%2Fd7d5b37686831d37c4dd75e645f5e016 +0 -0
- data/spec/test_app/tmp/cache/assets/E25/4C0/sprockets%2Fde2fd9fd11c04a582cdbbe3d84a35ae6 +0 -0
@@ -0,0 +1,187 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'Paloma.FilterScope', :type => :feature, :js => true do
|
4
|
+
|
5
|
+
shared_context 'paths-' do
|
6
|
+
let(:basic_action) { basic_action_bar_path }
|
7
|
+
let(:another_basic_action) { another_basic_action_bar_path }
|
8
|
+
let(:yet_another_basic_action) { yet_another_basic_action_bar_path}
|
9
|
+
end
|
10
|
+
|
11
|
+
shared_context 'paths-Application' do
|
12
|
+
include_context 'paths-'
|
13
|
+
end
|
14
|
+
|
15
|
+
shared_context 'paths-Namespaced' do
|
16
|
+
let(:basic_action) { basic_action_sample_namespace_baz_path }
|
17
|
+
let(:another_basic_action) { another_basic_action_sample_namespace_baz_path }
|
18
|
+
let(:yet_another_basic_action) { yet_another_basic_action_sample_namespace_baz_path }
|
19
|
+
end
|
20
|
+
|
21
|
+
|
22
|
+
|
23
|
+
shared_examples 'standard' do |options|
|
24
|
+
type = options[:type]
|
25
|
+
name = options[:name]
|
26
|
+
method = options[:method] || "##{type}"
|
27
|
+
scope = parse_scope options[:scope]
|
28
|
+
filter = "#{scope}Standard #{name}"
|
29
|
+
|
30
|
+
describe method do
|
31
|
+
it "executes filter #{type} callbacks for the passed actions" do
|
32
|
+
visit basic_action
|
33
|
+
page.evaluate_script("filtersExecuted.#{type}").should include filter
|
34
|
+
end
|
35
|
+
|
36
|
+
it "does not execute filter #{type} callbacks for other actions" do
|
37
|
+
visit yet_another_basic_action
|
38
|
+
page.evaluate_script("filtersExecuted.#{type}").should_not include filter
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
|
44
|
+
shared_examples 'all' do |options|
|
45
|
+
type = options[:type]
|
46
|
+
name = options[:name]
|
47
|
+
method = options[:method] || "##{type}_all"
|
48
|
+
scope = parse_scope options[:scope]
|
49
|
+
filter = "#{scope}#{name} All"
|
50
|
+
|
51
|
+
describe method do
|
52
|
+
it "executes filter #{type} callbacks on all actions" do
|
53
|
+
visit basic_action
|
54
|
+
page.evaluate_script("filtersExecuted.#{type}").should include filter
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
|
60
|
+
shared_examples 'except' do |options|
|
61
|
+
type = options[:type]
|
62
|
+
name = options[:name]
|
63
|
+
method = options[:method] || "#except_#{type}"
|
64
|
+
scope = parse_scope options[:scope]
|
65
|
+
filter = "#{scope}Except #{name}"
|
66
|
+
|
67
|
+
describe method do
|
68
|
+
it "executes filter #{type} callback on all actions except for passed actions" do
|
69
|
+
visit another_basic_action
|
70
|
+
page.evaluate_script("filtersExecuted.#{type}").should include filter
|
71
|
+
end
|
72
|
+
|
73
|
+
it "does not execute filter #{type} callback on passed actions" do
|
74
|
+
visit basic_action
|
75
|
+
page.evaluate_script("filtersExecuted.#{type}").should_not include filter
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
|
81
|
+
shared_examples 'filter subtypes' do |options|
|
82
|
+
params = {:type => options[:type],
|
83
|
+
:name => options[:type].titleize,
|
84
|
+
:scope => options[:scope]}
|
85
|
+
|
86
|
+
include_examples 'standard', params
|
87
|
+
include_examples 'all', params
|
88
|
+
include_examples 'except', params
|
89
|
+
end
|
90
|
+
|
91
|
+
|
92
|
+
shared_examples 'filters' do |scope|
|
93
|
+
context "when inside the scope of #{scope}" do
|
94
|
+
include_context "paths-#{scope}"
|
95
|
+
|
96
|
+
def self.parse_scope scope
|
97
|
+
scope.blank? ? scope : "#{scope} "
|
98
|
+
end
|
99
|
+
|
100
|
+
# Before and After Filters
|
101
|
+
include_examples 'filter subtypes', {:type => 'before', :scope => scope}
|
102
|
+
include_examples 'filter subtypes', {:type => 'after', :scope => scope}
|
103
|
+
|
104
|
+
# Around Filters
|
105
|
+
include_examples 'standard', {:name => 'Around',
|
106
|
+
:type => 'before',
|
107
|
+
:method => '#around',
|
108
|
+
:scope => scope}
|
109
|
+
|
110
|
+
include_examples 'standard', {:name => 'Around',
|
111
|
+
:type => 'after',
|
112
|
+
:method => '#around',
|
113
|
+
:scope => scope}
|
114
|
+
|
115
|
+
include_examples 'all', {:name => 'Around',
|
116
|
+
:type => 'before',
|
117
|
+
:method => '#around_all',
|
118
|
+
:scope => scope}
|
119
|
+
|
120
|
+
include_examples 'all', {:name => 'Around',
|
121
|
+
:type => 'after',
|
122
|
+
:method => '#around_all',
|
123
|
+
:scope => scope}
|
124
|
+
|
125
|
+
include_examples 'except', {:name => 'Around',
|
126
|
+
:type => 'before',
|
127
|
+
:method => '#except_around',
|
128
|
+
:scope => scope}
|
129
|
+
|
130
|
+
include_examples 'except', {:name => 'Around',
|
131
|
+
:type => 'after',
|
132
|
+
:method => '#except_around',
|
133
|
+
:scope => scope}
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
|
138
|
+
|
139
|
+
shared_examples 'skip filters' do |type|
|
140
|
+
name = type.titleize
|
141
|
+
filter = "- Skip This #{name} Filter"
|
142
|
+
|
143
|
+
describe "#skip_#{type}_filter" do
|
144
|
+
context 'when not appended with #only or #expect' do
|
145
|
+
it "skips passed #{type} filters for all actions" do
|
146
|
+
visit basic_action_sample_namespace_baz_path
|
147
|
+
page.evaluate_script("filtersExecuted.#{type}").should_not include "All #{filter}"
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
context 'with #only' do
|
152
|
+
it "skips passed #{type} filters for actions passed on #only" do
|
153
|
+
visit another_basic_action_sample_namespace_baz_path
|
154
|
+
page.evaluate_script("filtersExecuted.#{type}").should_not include "Only #{filter}"
|
155
|
+
end
|
156
|
+
|
157
|
+
it "performs passed #{type} filters for actions not passed on #only" do
|
158
|
+
visit basic_action_sample_namespace_baz_path
|
159
|
+
page.evaluate_script("filtersExecuted.#{type}").should include "Only #{filter}"
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
context 'with #except' do
|
164
|
+
it "skips passed #{type} filters for actions not passed on #except" do
|
165
|
+
visit yet_another_basic_action_sample_namespace_baz_path
|
166
|
+
page.evaluate_script("filtersExecuted.#{type}").should_not include "Except #{filter}"
|
167
|
+
end
|
168
|
+
|
169
|
+
it "performs passed #{type} filters for actions passed on #except" do
|
170
|
+
visit another_basic_action_sample_namespace_baz_path
|
171
|
+
page.evaluate_script("filtersExecuted.#{type}").should include "Except #{filter}"
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
|
178
|
+
|
179
|
+
# Testing starts here
|
180
|
+
include_examples 'filters', '' # non-namespaced filters
|
181
|
+
include_examples 'filters', 'Namespaced' # namespaced filters
|
182
|
+
include_examples 'filters', 'Application' # application-wide filters
|
183
|
+
|
184
|
+
#include_examples 'skip filters', 'before'
|
185
|
+
#include_examples 'skip filters', 'after'
|
186
|
+
#include_examples 'skip filters', 'around'
|
187
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
|
4
|
+
describe 'Locals', :type => :feature, :js => true do
|
5
|
+
|
6
|
+
before do
|
7
|
+
visit basic_action_foo_path
|
8
|
+
end
|
9
|
+
|
10
|
+
|
11
|
+
describe '_l' do
|
12
|
+
it 'has access to local methods' do
|
13
|
+
page.evaluate_script('helperMethodValue').should be 100
|
14
|
+
end
|
15
|
+
|
16
|
+
|
17
|
+
it 'has access to local variables' do
|
18
|
+
page.evaluate_script('helperVariableValue').should be 99
|
19
|
+
end
|
20
|
+
|
21
|
+
|
22
|
+
it 'can override locals from its parent scope' do
|
23
|
+
page.evaluate_script('overriden').should eq 'Override!'
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
@@ -0,0 +1,116 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'Callback params', :type => :feature, :js => true do
|
4
|
+
|
5
|
+
shared_examples 'check params' do |params|
|
6
|
+
specify "callback_controller must be the callback's controller" do
|
7
|
+
page.evaluate_script('params.callback_controller').should eq params[:callback_controller]
|
8
|
+
end
|
9
|
+
|
10
|
+
specify "callback_action must be the callback's action" do
|
11
|
+
page.evaluate_script('params.callback_action').should eq params[:callback_action]
|
12
|
+
end
|
13
|
+
|
14
|
+
specify "callback_namespace must be callback's namespace" do
|
15
|
+
page.evaluate_script('params.callback_namespace').should eq params[:callback_namespace]
|
16
|
+
end
|
17
|
+
|
18
|
+
specify "callback_controller_path must be callback's namespace and controller" do
|
19
|
+
page.evaluate_script('params.callback_controller_path').should eq params[:callback_controller_path]
|
20
|
+
end
|
21
|
+
|
22
|
+
specify "controller must be request's controller" do
|
23
|
+
page.evaluate_script('params.controller').should eq params[:controller]
|
24
|
+
end
|
25
|
+
|
26
|
+
specify "action must be request's action" do
|
27
|
+
page.evaluate_script('params.action').should eq params[:action]
|
28
|
+
end
|
29
|
+
|
30
|
+
specify "namespace must be request's namespace" do
|
31
|
+
page.evaluate_script('params.namespace').should eq params[:namespace]
|
32
|
+
end
|
33
|
+
|
34
|
+
specify "controller_path must be request's namespace and controller" do
|
35
|
+
page.evaluate_script('params.controller_path').should eq params[:controller_path]
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
|
40
|
+
context 'within a non-namespaced callback' do
|
41
|
+
before do
|
42
|
+
visit callback_from_another_action_foo_path
|
43
|
+
end
|
44
|
+
|
45
|
+
include_examples('check params', {
|
46
|
+
:controller => 'foo',
|
47
|
+
:action => 'callback_from_another_action',
|
48
|
+
:namespace => '',
|
49
|
+
:controller_path => 'foo',
|
50
|
+
:callback_controller => 'foo',
|
51
|
+
:callback_action => 'basic_action',
|
52
|
+
:callback_namespace => '',
|
53
|
+
:callback_controller_path => 'foo'})
|
54
|
+
end
|
55
|
+
|
56
|
+
|
57
|
+
context 'within a namespaced callback' do
|
58
|
+
before do
|
59
|
+
visit callback_from_another_action_sample_namespace_baz_path
|
60
|
+
end
|
61
|
+
|
62
|
+
include_examples('check params', {
|
63
|
+
:controller => 'baz',
|
64
|
+
:action => 'callback_from_another_action',
|
65
|
+
:namespace => 'sample_namespace',
|
66
|
+
:controller_path => 'sample_namespace/baz',
|
67
|
+
:callback_controller => 'baz',
|
68
|
+
:callback_action => 'basic_action',
|
69
|
+
:callback_namespace => 'sample_namespace',
|
70
|
+
:callback_controller_path => 'sample_namespace/baz'})
|
71
|
+
end
|
72
|
+
|
73
|
+
|
74
|
+
context 'with passed parameter' do
|
75
|
+
before do
|
76
|
+
visit different_params_bar_path
|
77
|
+
end
|
78
|
+
|
79
|
+
context 'of type TrueClass or FalseClass' do
|
80
|
+
it 'has the boolean equivalent' do
|
81
|
+
page.evaluate_script("params['boolean'] == true").should be_true
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
context 'of type Array' do
|
86
|
+
it 'has the array equivalent' do
|
87
|
+
page.evaluate_script("JSON.stringify(params['array']) == JSON.stringify([1, 2, 3])").should be_true
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
context 'of type String' do
|
92
|
+
it 'has the string equivalent' do
|
93
|
+
page.evaluate_script("params['string'] == 'Banana'").should be_true
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
context 'of type Fixnum' do
|
98
|
+
it 'has the number equivalent' do
|
99
|
+
page.evaluate_script("params['integer'] == 69").should be_true
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
context 'of type Float' do
|
104
|
+
it 'has the number equivalent' do
|
105
|
+
page.evaluate_script("params['float'] == 3.1416").should be_true
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
context 'of type Hash' do
|
110
|
+
it 'has the object equivalent' do
|
111
|
+
page.evaluate_script(
|
112
|
+
"JSON.stringify(params['hash']) == JSON.stringify({a : 'Hello', b : 'World'})").should be_true
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
|
4
|
+
describe 'Skip Filter', :type => :feature, :js => true do
|
5
|
+
|
6
|
+
def filters_executed type
|
7
|
+
page.evaluate_script("filtersExecuted.#{type}")
|
8
|
+
end
|
9
|
+
|
10
|
+
|
11
|
+
shared_examples 'skip_*_filter/s' do |execution, name|
|
12
|
+
|
13
|
+
describe "#skip_#{name}_filter/s" do
|
14
|
+
context "with no inclusion method called" do
|
15
|
+
it "skips the #{name} filters" do
|
16
|
+
visit basic_action_bar_path
|
17
|
+
filters_executed(execution).should_not include "Standard Skip #{name.titleize} Filter"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
|
22
|
+
context "with #only inclusion method called" do
|
23
|
+
filter = "Only Skip #{name.titleize} Filter"
|
24
|
+
|
25
|
+
it "skips the #{name} filters for the actions passed" do
|
26
|
+
visit basic_action_bar_path
|
27
|
+
filters_executed(execution).should_not include filter
|
28
|
+
end
|
29
|
+
|
30
|
+
it "does not skip the #{name} filters for the other actions" do
|
31
|
+
visit another_basic_action_bar_path
|
32
|
+
filters_executed(execution).should include filter
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
|
37
|
+
context "with #except inclusion method called" do
|
38
|
+
filter = "Except Skip #{name.titleize} Filter"
|
39
|
+
|
40
|
+
it "skips the #{name} filters for the actions which are not passed" do
|
41
|
+
visit basic_action_bar_path
|
42
|
+
filters_executed(execution).should_not include filter
|
43
|
+
end
|
44
|
+
|
45
|
+
it "does not skip the #{name} filters for the actions passed" do
|
46
|
+
visit yet_another_basic_action_bar_path
|
47
|
+
filters_executed(execution).should include filter
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
|
54
|
+
include_examples 'skip_*_filter/s', 'before', 'before'
|
55
|
+
include_examples 'skip_*_filter/s', 'after', 'after'
|
56
|
+
include_examples 'skip_*_filter/s', 'before', 'around'
|
57
|
+
include_examples 'skip_*_filter/s', 'after', 'around'
|
58
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
|
4
|
+
describe '_x', :type => :feature, :js => true do
|
5
|
+
|
6
|
+
before do
|
7
|
+
visit basic_action_foo_path
|
8
|
+
end
|
9
|
+
|
10
|
+
|
11
|
+
it 'is visible on filters and callback' do
|
12
|
+
final_x = page.evaluate_script 'window.xVisibilityFinal'
|
13
|
+
final_x.should eq ['Before Foo', 'Around Foo', 'Foo', 'After Foo', 'Around Foo']
|
14
|
+
end
|
15
|
+
|
16
|
+
|
17
|
+
it 'is empty after filter and callback executions' do
|
18
|
+
x = page.evaluate_script 'Paloma.variableContainer'
|
19
|
+
x.should be_empty
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# This file is copied to spec/ when you run 'rails generate rspec:install'
|
2
|
+
ENV["RAILS_ENV"] ||= 'test'
|
3
|
+
require File.expand_path("../../config/environment", __FILE__)
|
4
|
+
require 'rspec/rails'
|
5
|
+
require 'rspec/autorun'
|
6
|
+
require 'capybara/rspec'
|
7
|
+
|
8
|
+
# Requires supporting ruby files with custom matchers and macros, etc,
|
9
|
+
# in spec/support/ and its subdirectories.
|
10
|
+
Dir[Rails.root.join("spec/support/**/*.rb")].each {|f| require f}
|
11
|
+
|
12
|
+
RSpec.configure do |config|
|
13
|
+
# If true, the base class of anonymous controllers will be inferred
|
14
|
+
# automatically. This will be the default behavior in future versions of
|
15
|
+
# rspec-rails.
|
16
|
+
config.infer_base_class_for_anonymous_controllers = false
|
17
|
+
|
18
|
+
# Run specs in random order to surface order dependencies. If you find an
|
19
|
+
# order dependency and want to debug it, you can fix the order by providing
|
20
|
+
# the seed, which is printed after each run.
|
21
|
+
# --seed 1234
|
22
|
+
config.order = "random"
|
23
|
+
end
|
24
|
+
|
25
|
+
|
26
|
+
|
@@ -0,0 +1,294 @@
|
|
1
|
+
(function(){
|
2
|
+
window.Paloma = {
|
3
|
+
callbacks : {},
|
4
|
+
filterScopes : {},
|
5
|
+
locals : {},
|
6
|
+
variableContainer : {}
|
7
|
+
};
|
8
|
+
|
9
|
+
|
10
|
+
var FILTER_TYPES = {},
|
11
|
+
FILTER_TYPE_NAMES = ['BEFORE', 'AFTER', 'AROUND'],
|
12
|
+
INCLUSION_TYPES = {},
|
13
|
+
INCLUSION_TYPE_NAMES = ['ALL', 'ONLY', 'EXCEPT'];
|
14
|
+
|
15
|
+
FILTER_TYPES.BEFORE = 0;
|
16
|
+
FILTER_TYPES.AFTER = 1;
|
17
|
+
FILTER_TYPES.AROUND = 2;
|
18
|
+
|
19
|
+
INCLUSION_TYPES.ALL = 3;
|
20
|
+
INCLUSION_TYPES.ONLY = 4;
|
21
|
+
INCLUSION_TYPES.EXCEPT = 5;
|
22
|
+
|
23
|
+
|
24
|
+
Paloma.inheritLocals = function(options){
|
25
|
+
var from = Paloma.locals[options['from']],
|
26
|
+
to = Paloma.locals[options['to']];
|
27
|
+
|
28
|
+
for (var local in from){
|
29
|
+
// Overriding is allowed.
|
30
|
+
if ( to.hasOwnProperty(local) ){ continue; }
|
31
|
+
|
32
|
+
to[local] = from[local];
|
33
|
+
}
|
34
|
+
};
|
35
|
+
|
36
|
+
|
37
|
+
|
38
|
+
Paloma.FilterScope = function(name){
|
39
|
+
this.name = name;
|
40
|
+
|
41
|
+
this.filters = {};
|
42
|
+
this.skippers = {};
|
43
|
+
|
44
|
+
for (var i = 0, n = FILTER_TYPE_NAMES.length; i < n; i++){
|
45
|
+
var type = FILTER_TYPE_NAMES[i].toUpperCase();
|
46
|
+
this.filters[ FILTER_TYPES[type] ] = [];
|
47
|
+
this.skippers[ FILTER_TYPES[type] ] = [];
|
48
|
+
}
|
49
|
+
|
50
|
+
Paloma.filterScopes[name] = this;
|
51
|
+
};
|
52
|
+
|
53
|
+
|
54
|
+
// Creates a new Filter instance registered under this FilterScope.
|
55
|
+
Paloma.FilterScope.prototype.as = function(filterName){
|
56
|
+
return (new Paloma.Filter(this, filterName));
|
57
|
+
};
|
58
|
+
|
59
|
+
|
60
|
+
// skip_*_filter/s methods
|
61
|
+
(function(){
|
62
|
+
for (var i = 0, n = FILTER_TYPE_NAMES.length; i < n; i++){
|
63
|
+
var type = FILTER_TYPE_NAMES[i],
|
64
|
+
singular = 'skip_' + type.toLowerCase() + '_filter',
|
65
|
+
plural = singular + 's',
|
66
|
+
method = function(skipperType){
|
67
|
+
return function(){
|
68
|
+
return (new Paloma.Skipper(this, FILTER_TYPES[skipperType], arguments));
|
69
|
+
};
|
70
|
+
};
|
71
|
+
|
72
|
+
Paloma.FilterScope.prototype[singular] = new method(type);
|
73
|
+
Paloma.FilterScope.prototype[plural] = Paloma.FilterScope.prototype[singular];
|
74
|
+
}
|
75
|
+
})();
|
76
|
+
|
77
|
+
|
78
|
+
|
79
|
+
|
80
|
+
// Skipper class
|
81
|
+
Paloma.Skipper = function(scope, type, filters){
|
82
|
+
this.scope = scope;
|
83
|
+
this.type = type;
|
84
|
+
this.filters = Array.prototype.slice.call(filters);
|
85
|
+
this.inclusionType = INCLUSION_TYPES.ALL;
|
86
|
+
this.actions = [];
|
87
|
+
|
88
|
+
// Register this skipper on its scope.
|
89
|
+
this.scope.skippers[this.type].push(this);
|
90
|
+
};
|
91
|
+
|
92
|
+
|
93
|
+
Paloma.Skipper.prototype.skip = function(filter, action){
|
94
|
+
if (this.filters.indexOf(filter.name) == -1){ return false; }
|
95
|
+
|
96
|
+
var actionIsListed = this.actions.indexOf(action) != -1,
|
97
|
+
isAllActions = this.inclusionType == INCLUSION_TYPES.ALL,
|
98
|
+
isQualified = this.inclusionType == INCLUSION_TYPES.ONLY && actionIsListed,
|
99
|
+
isNotExcepted = this.inclusionType == INCLUSION_TYPES.EXCEPT && !actionIsListed;
|
100
|
+
|
101
|
+
return (isAllActions || isQualified || isNotExcepted);
|
102
|
+
};
|
103
|
+
|
104
|
+
|
105
|
+
Paloma.Skipper.prototype.only = function(){
|
106
|
+
this.inclusionType = INCLUSION_TYPES.ONLY;
|
107
|
+
this.actions = Array.prototype.slice.call(arguments);
|
108
|
+
};
|
109
|
+
|
110
|
+
|
111
|
+
Paloma.Skipper.prototype.except = function(){
|
112
|
+
this.inclusionType = INCLUSION_TYPES.EXCEPT;
|
113
|
+
this.actions = Array.prototype.slice.call(arguments);
|
114
|
+
};
|
115
|
+
|
116
|
+
|
117
|
+
|
118
|
+
// Filter class
|
119
|
+
Paloma.Filter = function(scope, name){
|
120
|
+
this.scope = scope;
|
121
|
+
this.name = name;
|
122
|
+
|
123
|
+
this.type = undefined;
|
124
|
+
this.inclusionType = INCLUSION_TYPES.ONLY;
|
125
|
+
|
126
|
+
this.actions = [];
|
127
|
+
this.method = undefined;
|
128
|
+
};
|
129
|
+
|
130
|
+
|
131
|
+
// Create Methods:
|
132
|
+
// - before, after, around, *_all, except_*
|
133
|
+
(function(){
|
134
|
+
var Basic = function(type){
|
135
|
+
return function(){
|
136
|
+
return this.setProperties(type, INCLUSION_TYPES.ONLY, arguments);
|
137
|
+
};
|
138
|
+
};
|
139
|
+
|
140
|
+
var All = function(type){
|
141
|
+
return function(){
|
142
|
+
return this.setProperties(type, INCLUSION_TYPES.ALL, []);
|
143
|
+
};
|
144
|
+
};
|
145
|
+
|
146
|
+
var Except = function(type){
|
147
|
+
return function(){
|
148
|
+
return this.setProperties(type, INCLUSION_TYPES.EXCEPT, arguments);
|
149
|
+
};
|
150
|
+
};
|
151
|
+
|
152
|
+
for (var i = 0, n = FILTER_TYPE_NAMES.length; i < n; i++){
|
153
|
+
var name = FILTER_TYPE_NAMES[i].toLowerCase(),
|
154
|
+
type = FILTER_TYPES[name.toUpperCase()];
|
155
|
+
|
156
|
+
Paloma.Filter.prototype[name] = new Basic(type);
|
157
|
+
Paloma.Filter.prototype[name + '_all'] = new All(type);
|
158
|
+
Paloma.Filter.prototype['except_' + name] = new Except(type);
|
159
|
+
}
|
160
|
+
})();
|
161
|
+
// End of creating methods.
|
162
|
+
|
163
|
+
|
164
|
+
// This will be the last method to be invoked when declaring a filter.
|
165
|
+
// This will set what method/function will be executed when the filter is called.
|
166
|
+
Paloma.Filter.prototype.perform = function(method){
|
167
|
+
this.method = method;
|
168
|
+
|
169
|
+
// This is the only time the filter is registered to its owner scope.
|
170
|
+
this.scope.filters[this.type].push(this);
|
171
|
+
return this;
|
172
|
+
};
|
173
|
+
|
174
|
+
|
175
|
+
Paloma.Filter.prototype.isApplicable = function(action){
|
176
|
+
var actionIsListed = this.actions.indexOf(action) != -1,
|
177
|
+
isAllActions = this.inclusionType == INCLUSION_TYPES.ALL,
|
178
|
+
isQualified = this.inclusionType == INCLUSION_TYPES.ONLY && actionIsListed,
|
179
|
+
isNotExcepted = this.inclusionType == INCLUSION_TYPES.EXCEPT && !actionIsListed;
|
180
|
+
|
181
|
+
return (isAllActions || isQualified || isNotExcepted);
|
182
|
+
};
|
183
|
+
|
184
|
+
|
185
|
+
Paloma.Filter.prototype.setProperties = function(type, inclusion, actions){
|
186
|
+
this.type = type;
|
187
|
+
this.inclusionType = inclusion;
|
188
|
+
this.actions = Array.prototype.slice.call(actions);
|
189
|
+
return this;
|
190
|
+
};
|
191
|
+
|
192
|
+
|
193
|
+
|
194
|
+
|
195
|
+
// Execute callback that corresponds to the controller and action passed.
|
196
|
+
Paloma.execute = function(controller, action, params){
|
197
|
+
var callbackFound = true;
|
198
|
+
|
199
|
+
var callback = Paloma.callbacks[controller];
|
200
|
+
callbackFound = callback != undefined;
|
201
|
+
|
202
|
+
callback = callback[action];
|
203
|
+
callbackFound = callback != undefined;
|
204
|
+
|
205
|
+
// Parse parameters
|
206
|
+
params = params || {};
|
207
|
+
|
208
|
+
// Request details
|
209
|
+
var requestControllerPath = params['controller_path'].split('/');
|
210
|
+
params['controller'] = requestControllerPath.pop();
|
211
|
+
params['namespace'] = requestControllerPath.join('/');
|
212
|
+
|
213
|
+
// Callback details
|
214
|
+
var callbackControllerPath = controller.split('/');
|
215
|
+
params['callback_controller'] = callbackControllerPath.pop();
|
216
|
+
params['callback_namespace'] = callbackControllerPath.join('/');
|
217
|
+
params['callback_controller_path'] = controller;
|
218
|
+
params['callback_action'] = action;
|
219
|
+
|
220
|
+
|
221
|
+
var beforeFilters = getOrderedFilters(
|
222
|
+
FILTER_TYPES.BEFORE,
|
223
|
+
params['callback_namespace'],
|
224
|
+
controller,
|
225
|
+
action);
|
226
|
+
|
227
|
+
var afterFilters = getOrderedFilters(
|
228
|
+
FILTER_TYPES.AFTER,
|
229
|
+
params['callback_namespace'],
|
230
|
+
controller,
|
231
|
+
action);
|
232
|
+
|
233
|
+
// Start filter and callback executions
|
234
|
+
performFilters(beforeFilters);
|
235
|
+
if (callbackFound){ callback(params); }
|
236
|
+
performFilters(afterFilters);
|
237
|
+
|
238
|
+
// variableContainer is used to share variable between filters and callbacks.
|
239
|
+
// It will be cleared after it is used.
|
240
|
+
Paloma.variableContainer = [];
|
241
|
+
};
|
242
|
+
|
243
|
+
|
244
|
+
var getOrderedFilters = function(beforeOrAfter, namespace, controller, action){
|
245
|
+
var filters = [],
|
246
|
+
applicableFilters = [],
|
247
|
+
skippers = [],
|
248
|
+
scopes = [
|
249
|
+
Paloma.filterScopes['/'],
|
250
|
+
Paloma.filterScopes[namespace],
|
251
|
+
Paloma.filterScopes[controller]];
|
252
|
+
|
253
|
+
for (var i = 0, n = scopes.length; i < n; i++){
|
254
|
+
var scope = scopes[i];
|
255
|
+
if (scope == undefined){ continue; }
|
256
|
+
|
257
|
+
var mainFilters = scope.filters[beforeOrAfter],
|
258
|
+
aroundFilters = scope.filters[FILTER_TYPES.AROUND];
|
259
|
+
|
260
|
+
// Around Filters have lower precedence than before or after filters.
|
261
|
+
if (mainFilters != undefined){ filters = filters.concat(mainFilters); }
|
262
|
+
if (aroundFilters != undefined){ filters = filters.concat(aroundFilters); }
|
263
|
+
|
264
|
+
skippers = skippers.concat(
|
265
|
+
scope.skippers[beforeOrAfter],
|
266
|
+
scope.skippers[FILTER_TYPES.AROUND]);
|
267
|
+
}
|
268
|
+
|
269
|
+
|
270
|
+
// Select only applicable filters for the passed action.
|
271
|
+
for (var i = 0, n = filters.length; i < n; i++){
|
272
|
+
var filter = filters[i],
|
273
|
+
isApplicable = filter.isApplicable(action),
|
274
|
+
isNotSkipped = true;
|
275
|
+
|
276
|
+
for (var k = 0, len = skippers.length; k < len; k++){
|
277
|
+
if ( skippers[k].skip(filter, action) ){ isNotSkipped = false; break;}
|
278
|
+
}
|
279
|
+
|
280
|
+
if (isApplicable && isNotSkipped){ applicableFilters.push(filter); }
|
281
|
+
}
|
282
|
+
|
283
|
+
return applicableFilters;
|
284
|
+
};
|
285
|
+
|
286
|
+
|
287
|
+
var performFilters = function(filters, params){
|
288
|
+
for (var i = 0, n = filters.length; i < n; i++){
|
289
|
+
filters[i].method(params);
|
290
|
+
}
|
291
|
+
};
|
292
|
+
|
293
|
+
|
294
|
+
})();
|