has_scope 0.1 → 0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -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, :boolean => true
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, :boolean => true
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
- Please check <tt>has_scope</tt> method for all the supported options.
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.1"
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"
@@ -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
- class_inheritable_accessor :scopes_configuration, :instance_writer => false
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>:boolean</tt> - When set to true, call the scope only when the param is true or 1,
20
- # and does not send the value as argument.
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. This is useful to add easy pagination.
44
+ # is always called.
37
45
  #
38
46
  def has_scope(*scopes)
39
47
  options = scopes.extract_options!
40
48
  options.symbolize_keys!
41
- options.assert_valid_keys(:boolean, :only, :except, :if, :unless, :default, :as)
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][:as] = options[:as] || 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(target_object)
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
- target_object
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
@@ -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, :boolean => true, :only => :index, :if => :restrict_to_only_tall_trees?
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.1"
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-04 00:00:00 -02:00
12
+ date: 2009-12-22 00:00:00 +01:00
13
13
  default_executable:
14
14
  dependencies: []
15
15