has_scope 0.2 → 0.3
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/README.rdoc +50 -2
- data/Rakefile +1 -1
- data/init.rb +1 -0
- data/lib/has_scope.rb +38 -9
- data/test/has_scope_test.rb +43 -3
- metadata +2 -2
- data/CHANGELOG.rdoc +0 -0
data/README.rdoc
CHANGED
@@ -40,8 +40,56 @@ Then for each request:
|
|
40
40
|
You can retrieve all the scopes applied in one action with <tt>current_scopes</tt> method.
|
41
41
|
In the last case, it would return: { :featured => true, :by_degree => "phd" }.
|
42
42
|
|
43
|
-
|
44
|
-
|
43
|
+
== Installation
|
44
|
+
|
45
|
+
HasScope is available as gem on Gemcutter, so just run the following:
|
46
|
+
|
47
|
+
sudo gem install has_scope
|
48
|
+
|
49
|
+
If you want it as plugin, just do:
|
50
|
+
|
51
|
+
script/plugin install git://github.com/plataformatec/has_scope.git
|
52
|
+
|
53
|
+
== Options
|
54
|
+
|
55
|
+
HasScope support several options:
|
56
|
+
|
57
|
+
* <tt>:type</tt> - Checks the type of the parameter sent. If set to :boolean
|
58
|
+
it just calls the named scope, without any argument. By default,
|
59
|
+
it does not allow hashes or arrays to be given, except if type
|
60
|
+
:hash or :array are set.
|
61
|
+
|
62
|
+
* <tt>:only</tt> - In which actions the scope is applied.
|
63
|
+
|
64
|
+
* <tt>:except</tt> - In which actions the scope is not applied.
|
65
|
+
|
66
|
+
* <tt>:as</tt> - The key in the params hash expected to find the scope.
|
67
|
+
Defaults to the scope name.
|
68
|
+
|
69
|
+
* <tt>:if</tt> - Specifies a method, proc or string to call to determine
|
70
|
+
if the scope should apply
|
71
|
+
|
72
|
+
* <tt>:unless</tt> - Specifies a method, proc or string to call to determine
|
73
|
+
if the scope should NOT apply.
|
74
|
+
|
75
|
+
* <tt>:default</tt> - Default value for the scope. Whenever supplied the scope
|
76
|
+
is always called.
|
77
|
+
|
78
|
+
* <tt>:allow_blank</tt> - Blank values are not sent to scopes by default. Set to true to overwrite.
|
79
|
+
|
80
|
+
== Block usage
|
81
|
+
|
82
|
+
has_scope also accepts a block. The controller, current scope and value are yielded
|
83
|
+
to the block so the user can apply the scope on its own. This is useful in case we
|
84
|
+
need to manipulate the given value:
|
85
|
+
|
86
|
+
has_scope :category do |controller, scope, value|
|
87
|
+
value != "all" ? scope.by_category(value) : scope
|
88
|
+
end
|
89
|
+
|
90
|
+
has_scope :not_voted_by_me, :type => :boolean do |controller, scope|
|
91
|
+
scope.not_voted_by(controller.current_user.id)
|
92
|
+
end
|
45
93
|
|
46
94
|
== Bugs and Feedback
|
47
95
|
|
data/Rakefile
CHANGED
@@ -27,7 +27,7 @@ begin
|
|
27
27
|
require 'jeweler'
|
28
28
|
Jeweler::Tasks.new do |s|
|
29
29
|
s.name = "has_scope"
|
30
|
-
s.version = "0.
|
30
|
+
s.version = "0.3"
|
31
31
|
s.summary = "Maps controller filters to your resource scopes"
|
32
32
|
s.email = "contact@plataformatec.com.br"
|
33
33
|
s.homepage = "http://github.com/plataformatec/has_scope"
|
data/init.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'has_scope'
|
data/lib/has_scope.rb
CHANGED
@@ -4,6 +4,7 @@ module HasScope
|
|
4
4
|
ALLOWED_TYPES = {
|
5
5
|
:array => [ Array ],
|
6
6
|
:hash => [ Hash ],
|
7
|
+
:boolean => [ Object ],
|
7
8
|
:default => [ String, Numeric ]
|
8
9
|
}
|
9
10
|
|
@@ -43,7 +44,23 @@ module HasScope
|
|
43
44
|
# * <tt>:default</tt> - Default value for the scope. Whenever supplied the scope
|
44
45
|
# is always called.
|
45
46
|
#
|
46
|
-
|
47
|
+
# * <tt>:allow_blank</tt> - Blank values are not sent to scopes by default. Set to true to overwrite.
|
48
|
+
#
|
49
|
+
# == Block usage
|
50
|
+
#
|
51
|
+
# has_scope also accepts a block. The controller, current scope and value are yielded
|
52
|
+
# to the block so the user can apply the scope on its own. This is useful in case we
|
53
|
+
# need to manipulate the given value:
|
54
|
+
#
|
55
|
+
# has_scope :category do |controller, scope, value|
|
56
|
+
# value != "all" ? scope.by_category(value) : scope
|
57
|
+
# end
|
58
|
+
#
|
59
|
+
# has_scope :not_voted_by_me, :type => :boolean do |controller, scope|
|
60
|
+
# scope.not_voted_by(controller.current_user.id)
|
61
|
+
# end
|
62
|
+
#
|
63
|
+
def has_scope(*scopes, &block)
|
47
64
|
options = scopes.extract_options!
|
48
65
|
options.symbolize_keys!
|
49
66
|
|
@@ -51,13 +68,13 @@ module HasScope
|
|
51
68
|
options[:type] ||= :boolean
|
52
69
|
ActiveSupport::Deprecation.warn(":boolean => true is deprecated, use :type => :boolean instead", caller)
|
53
70
|
end
|
54
|
-
options.assert_valid_keys(:type, :only, :except, :if, :unless, :default, :as)
|
71
|
+
options.assert_valid_keys(:type, :only, :except, :if, :unless, :default, :as, :allow_blank)
|
55
72
|
|
56
73
|
options[:only] = Array(options[:only])
|
57
74
|
options[:except] = Array(options[:except])
|
58
75
|
|
59
76
|
scopes.each do |scope|
|
60
|
-
self.scopes_configuration[scope] ||= { :as => scope, :type => :default }
|
77
|
+
self.scopes_configuration[scope] ||= { :as => scope, :type => :default, :block => block }
|
61
78
|
self.scopes_configuration[scope].merge!(options)
|
62
79
|
end
|
63
80
|
end
|
@@ -88,22 +105,34 @@ module HasScope
|
|
88
105
|
value = value.call(self) if value.is_a?(Proc)
|
89
106
|
end
|
90
107
|
|
91
|
-
|
108
|
+
if call_scope && (value.present? || options[:allow_blank])
|
109
|
+
set_current_scope(options[:type], key, value)
|
110
|
+
target = apply_scope_by_type(options[:type], scope, target, current_scopes[key], options[:block])
|
111
|
+
end
|
92
112
|
end
|
93
113
|
|
94
114
|
target
|
95
115
|
end
|
96
116
|
|
97
|
-
#
|
98
|
-
def
|
117
|
+
# Set the real value for the current scope if type check.
|
118
|
+
def set_current_scope(type, key, value) #:nodoc:
|
99
119
|
if type == :boolean
|
100
120
|
current_scopes[key] = TRUE_VALUES.include?(value)
|
101
|
-
current_scopes[key] ? target.send(scope) : target
|
102
121
|
elsif ALLOWED_TYPES[type].none?{ |klass| value.is_a?(klass) }
|
103
122
|
raise "Expected type :#{type} in params[:#{key}], got :#{value.class}"
|
104
123
|
else
|
105
124
|
current_scopes[key] = value
|
106
|
-
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
# Apply the scope taking into account its type.
|
129
|
+
def apply_scope_by_type(type, scope, target, value, block) #:nodoc:
|
130
|
+
return target if type == :boolean && value == false
|
131
|
+
|
132
|
+
if type == :boolean
|
133
|
+
block ? block.call(self, target) : target.send(scope)
|
134
|
+
else
|
135
|
+
block ? block.call(self, target, value) : target.send(scope, value)
|
107
136
|
end
|
108
137
|
end
|
109
138
|
|
@@ -140,4 +169,4 @@ module HasScope
|
|
140
169
|
end
|
141
170
|
end
|
142
171
|
|
143
|
-
|
172
|
+
ActionController::Base.send :include, HasScope
|
data/test/has_scope_test.rb
CHANGED
@@ -6,12 +6,20 @@ end
|
|
6
6
|
class TreesController < ApplicationController
|
7
7
|
has_scope :color, :unless => :show_all_colors?
|
8
8
|
has_scope :only_tall, :type => :boolean, :only => :index, :if => :restrict_to_only_tall_trees?
|
9
|
-
has_scope :shadown_range, :default => 10, :except => [ :index, :show, :
|
10
|
-
has_scope :root_type, :as => :root
|
9
|
+
has_scope :shadown_range, :default => 10, :except => [ :index, :show, :new ]
|
10
|
+
has_scope :root_type, :as => :root, :allow_blank => true
|
11
11
|
has_scope :calculate_height, :default => proc {|c| c.session[:height] || 20 }, :only => :new
|
12
12
|
has_scope :paginate, :type => :hash
|
13
13
|
has_scope :categories, :type => :array
|
14
14
|
|
15
|
+
has_scope :only_short, :type => :boolean do |controller, scope|
|
16
|
+
scope.only_really_short!(controller.object_id)
|
17
|
+
end
|
18
|
+
|
19
|
+
has_scope :by_category do |controller, scope, value|
|
20
|
+
scope.by_given_category(controller.object_id, value + "_id")
|
21
|
+
end
|
22
|
+
|
15
23
|
def index
|
16
24
|
@trees = apply_scopes(Tree).all
|
17
25
|
end
|
@@ -50,7 +58,7 @@ class HasScopeTest < ActionController::TestCase
|
|
50
58
|
assert_equal({ :only_tall => true }, current_scopes)
|
51
59
|
end
|
52
60
|
|
53
|
-
def
|
61
|
+
def test_boolean_scope_is_not_called_when_boolean_param_is_false
|
54
62
|
Tree.expects(:only_tall).never
|
55
63
|
Tree.expects(:all).returns([mock_tree])
|
56
64
|
get :index, :only_tall => 'false'
|
@@ -100,6 +108,22 @@ class HasScopeTest < ActionController::TestCase
|
|
100
108
|
assert_equal({ :color => 'blue' }, current_scopes)
|
101
109
|
end
|
102
110
|
|
111
|
+
def test_scope_is_not_called_if_blank
|
112
|
+
Tree.expects(:color).never
|
113
|
+
Tree.expects(:all).returns([mock_tree]).in_sequence
|
114
|
+
get :index, :color => ''
|
115
|
+
assert_equal([mock_tree], assigns(:trees))
|
116
|
+
assert_equal({ }, current_scopes)
|
117
|
+
end
|
118
|
+
|
119
|
+
def test_scope_is_called_when_blank_if_allow_blank_is_given
|
120
|
+
Tree.expects(:root_type).with('').returns(Tree)
|
121
|
+
Tree.expects(:all).returns([mock_tree]).in_sequence
|
122
|
+
get :index, :root => ''
|
123
|
+
assert_equal([mock_tree], assigns(:trees))
|
124
|
+
assert_equal({ :root => '' }, current_scopes)
|
125
|
+
end
|
126
|
+
|
103
127
|
def test_multiple_scopes_are_called
|
104
128
|
Tree.expects(:only_tall).with().returns(Tree)
|
105
129
|
Tree.expects(:color).with('blue').returns(Tree)
|
@@ -172,6 +196,22 @@ class HasScopeTest < ActionController::TestCase
|
|
172
196
|
assert_equal({ :calculate_height => 100 }, current_scopes)
|
173
197
|
end
|
174
198
|
|
199
|
+
def test_scope_with_boolean_block
|
200
|
+
Tree.expects(:only_really_short!).with(@controller.object_id).returns(Tree)
|
201
|
+
Tree.expects(:all).returns([mock_tree])
|
202
|
+
get :index, :only_short => 'true'
|
203
|
+
assert_equal([mock_tree], assigns(:trees))
|
204
|
+
assert_equal({ :only_short => true }, current_scopes)
|
205
|
+
end
|
206
|
+
|
207
|
+
def test_scope_with_other_block_types
|
208
|
+
Tree.expects(:by_given_category).with(@controller.object_id, 'for_id').returns(Tree)
|
209
|
+
Tree.expects(:all).returns([mock_tree])
|
210
|
+
get :index, :by_category => 'for'
|
211
|
+
assert_equal([mock_tree], assigns(:trees))
|
212
|
+
assert_equal({ :by_category => 'for' }, current_scopes)
|
213
|
+
end
|
214
|
+
|
175
215
|
protected
|
176
216
|
|
177
217
|
def mock_tree(stubs={})
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: has_scope
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: "0.
|
4
|
+
version: "0.3"
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- "Jos\xC3\xA9 Valim"
|
@@ -22,10 +22,10 @@ extensions: []
|
|
22
22
|
extra_rdoc_files:
|
23
23
|
- README.rdoc
|
24
24
|
files:
|
25
|
-
- CHANGELOG.rdoc
|
26
25
|
- MIT-LICENSE
|
27
26
|
- README.rdoc
|
28
27
|
- Rakefile
|
28
|
+
- init.rb
|
29
29
|
- lib/has_scope.rb
|
30
30
|
has_rdoc: true
|
31
31
|
homepage: http://github.com/plataformatec/has_scope
|
data/CHANGELOG.rdoc
DELETED
File without changes
|