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