has_scope 0.1 → 0.2

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.
@@ -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