has_scope 0.1 → 0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +4 -3
- data/Rakefile +1 -1
- data/lib/has_scope.rb +39 -23
- data/test/has_scope_test.rb +33 -1
- metadata +2 -2
data/README.rdoc
CHANGED
@@ -11,14 +11,14 @@ Imagine the following model called graduations:
|
|
11
11
|
You can use those named scopes as filters by declaring them on your controller:
|
12
12
|
|
13
13
|
class GraduationsController < ApplicationController
|
14
|
-
has_scope :featured, :
|
14
|
+
has_scope :featured, :type => :boolean
|
15
15
|
has_scope :by_degree
|
16
16
|
end
|
17
17
|
|
18
18
|
Now, if you want to apply them to an specific resource, you just need to call <tt>apply_scopes</tt>:
|
19
19
|
|
20
20
|
class GraduationsController < ApplicationController
|
21
|
-
has_scope :featured, :
|
21
|
+
has_scope :featured, :type => :boolean
|
22
22
|
has_scope :by_degree
|
23
23
|
|
24
24
|
def index
|
@@ -40,7 +40,8 @@ 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
|
-
|
43
|
+
<tt>has_scope</tt> support several options (:only, :except, :as, :if, :unless, :default
|
44
|
+
and :type), please check the documentation for a detailed description.
|
44
45
|
|
45
46
|
== Bugs and Feedback
|
46
47
|
|
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.2"
|
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/lib/has_scope.rb
CHANGED
@@ -1,12 +1,18 @@
|
|
1
1
|
module HasScope
|
2
2
|
TRUE_VALUES = ["true", true, "1", 1]
|
3
3
|
|
4
|
+
ALLOWED_TYPES = {
|
5
|
+
:array => [ Array ],
|
6
|
+
:hash => [ Hash ],
|
7
|
+
:default => [ String, Numeric ]
|
8
|
+
}
|
9
|
+
|
4
10
|
def self.included(base)
|
5
11
|
base.class_eval do
|
6
12
|
extend ClassMethods
|
7
13
|
helper_method :current_scopes
|
8
14
|
|
9
|
-
|
15
|
+
class_inheritable_hash :scopes_configuration, :instance_writer => false
|
10
16
|
self.scopes_configuration ||= {}
|
11
17
|
end
|
12
18
|
end
|
@@ -16,8 +22,10 @@ module HasScope
|
|
16
22
|
#
|
17
23
|
# == Options
|
18
24
|
#
|
19
|
-
# * <tt>:
|
20
|
-
#
|
25
|
+
# * <tt>:type</tt> - Checks the type of the parameter sent. If set to :boolean
|
26
|
+
# it just calls the named scope, without any argument. By default,
|
27
|
+
# it does not allow hashes or arrays to be given, except if type
|
28
|
+
# :hash or :array are set.
|
21
29
|
#
|
22
30
|
# * <tt>:only</tt> - In which actions the scope is applied. By default is :all.
|
23
31
|
#
|
@@ -33,22 +41,24 @@ module HasScope
|
|
33
41
|
# if the scope should NOT apply.
|
34
42
|
#
|
35
43
|
# * <tt>:default</tt> - Default value for the scope. Whenever supplied the scope
|
36
|
-
# is always called.
|
44
|
+
# is always called.
|
37
45
|
#
|
38
46
|
def has_scope(*scopes)
|
39
47
|
options = scopes.extract_options!
|
40
48
|
options.symbolize_keys!
|
41
|
-
|
49
|
+
|
50
|
+
if options.delete(:boolean)
|
51
|
+
options[:type] ||= :boolean
|
52
|
+
ActiveSupport::Deprecation.warn(":boolean => true is deprecated, use :type => :boolean instead", caller)
|
53
|
+
end
|
54
|
+
options.assert_valid_keys(:type, :only, :except, :if, :unless, :default, :as)
|
55
|
+
|
56
|
+
options[:only] = Array(options[:only])
|
57
|
+
options[:except] = Array(options[:except])
|
42
58
|
|
43
59
|
scopes.each do |scope|
|
44
|
-
self.scopes_configuration[scope]
|
45
|
-
self.scopes_configuration[scope]
|
46
|
-
self.scopes_configuration[scope][:only] = Array(options[:only])
|
47
|
-
self.scopes_configuration[scope][:except] = Array(options[:except])
|
48
|
-
|
49
|
-
[:if, :unless, :boolean, :default].each do |opt|
|
50
|
-
self.scopes_configuration[scope][opt] = options[opt] if options.key?(opt)
|
51
|
-
end
|
60
|
+
self.scopes_configuration[scope] ||= { :as => scope, :type => :default }
|
61
|
+
self.scopes_configuration[scope].merge!(options)
|
52
62
|
end
|
53
63
|
end
|
54
64
|
end
|
@@ -66,7 +76,7 @@ module HasScope
|
|
66
76
|
# end
|
67
77
|
# end
|
68
78
|
#
|
69
|
-
def apply_scopes(
|
79
|
+
def apply_scopes(target)
|
70
80
|
self.scopes_configuration.each do |scope, options|
|
71
81
|
next unless apply_scope_to_action?(options)
|
72
82
|
key = options[:as]
|
@@ -78,17 +88,23 @@ module HasScope
|
|
78
88
|
value = value.call(self) if value.is_a?(Proc)
|
79
89
|
end
|
80
90
|
|
81
|
-
if call_scope
|
82
|
-
if options[:boolean]
|
83
|
-
target_object = target_object.send(scope) if current_scopes[key] = TRUE_VALUES.include?(value)
|
84
|
-
else
|
85
|
-
current_scopes[key] = value
|
86
|
-
target_object = target_object.send(scope, value)
|
87
|
-
end
|
88
|
-
end
|
91
|
+
target = apply_scope_by_type(options[:type], key, scope, value, target) if call_scope
|
89
92
|
end
|
90
93
|
|
91
|
-
|
94
|
+
target
|
95
|
+
end
|
96
|
+
|
97
|
+
# Apply the scope taking into account its type.
|
98
|
+
def apply_scope_by_type(type, key, scope, value, target) #:nodoc:
|
99
|
+
if type == :boolean
|
100
|
+
current_scopes[key] = TRUE_VALUES.include?(value)
|
101
|
+
current_scopes[key] ? target.send(scope) : target
|
102
|
+
elsif ALLOWED_TYPES[type].none?{ |klass| value.is_a?(klass) }
|
103
|
+
raise "Expected type :#{type} in params[:#{key}], got :#{value.class}"
|
104
|
+
else
|
105
|
+
current_scopes[key] = value
|
106
|
+
target.send(scope, value)
|
107
|
+
end
|
92
108
|
end
|
93
109
|
|
94
110
|
# Given an options with :only and :except arrays, check if the scope
|
data/test/has_scope_test.rb
CHANGED
@@ -5,10 +5,12 @@ end
|
|
5
5
|
|
6
6
|
class TreesController < ApplicationController
|
7
7
|
has_scope :color, :unless => :show_all_colors?
|
8
|
-
has_scope :only_tall, :
|
8
|
+
has_scope :only_tall, :type => :boolean, :only => :index, :if => :restrict_to_only_tall_trees?
|
9
9
|
has_scope :shadown_range, :default => 10, :except => [ :index, :show, :destroy, :new ]
|
10
10
|
has_scope :root_type, :as => :root
|
11
11
|
has_scope :calculate_height, :default => proc {|c| c.session[:height] || 20 }, :only => :new
|
12
|
+
has_scope :paginate, :type => :hash
|
13
|
+
has_scope :categories, :type => :array
|
12
14
|
|
13
15
|
def index
|
14
16
|
@trees = apply_scopes(Tree).all
|
@@ -107,6 +109,36 @@ class HasScopeTest < ActionController::TestCase
|
|
107
109
|
assert_equal({ :color => 'blue', :only_tall => true }, current_scopes)
|
108
110
|
end
|
109
111
|
|
112
|
+
def test_scope_of_type_hash
|
113
|
+
hash = { "page" => "1", "per_page" => "1" }
|
114
|
+
Tree.expects(:paginate).with(hash).returns(Tree)
|
115
|
+
Tree.expects(:all).returns([mock_tree])
|
116
|
+
get :index, :paginate => hash
|
117
|
+
assert_equal([mock_tree], assigns(:trees))
|
118
|
+
assert_equal({ :paginate => hash }, current_scopes)
|
119
|
+
end
|
120
|
+
|
121
|
+
def test_scope_of_type_array
|
122
|
+
array = %w(book kitchen sport)
|
123
|
+
Tree.expects(:categories).with(array).returns(Tree)
|
124
|
+
Tree.expects(:all).returns([mock_tree])
|
125
|
+
get :index, :categories => array
|
126
|
+
assert_equal([mock_tree], assigns(:trees))
|
127
|
+
assert_equal({ :categories => array }, current_scopes)
|
128
|
+
end
|
129
|
+
|
130
|
+
def test_invalid_type_hash_for_default_type_scope
|
131
|
+
assert_raise RuntimeError do
|
132
|
+
get :index, :color => { :blue => :red }
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
def test_invalid_type_string_for_hash_type_scope
|
137
|
+
assert_raise RuntimeError do
|
138
|
+
get :index, :paginate => "1"
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
110
142
|
def test_scope_is_called_with_default_value
|
111
143
|
Tree.expects(:shadown_range).with(10).returns(Tree).in_sequence
|
112
144
|
Tree.expects(:find).with('42').returns(mock_tree).in_sequence
|
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.2"
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- "Jos\xC3\xA9 Valim"
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-12-
|
12
|
+
date: 2009-12-22 00:00:00 +01:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|