Permalink
Browse files

Add support to :using and release a new gem.

  • Loading branch information...
1 parent 9ea8dfb commit 249a8c885e78cd404a98b99ec8e15cc84e81bac4 @josevalim josevalim committed Mar 23, 2010
Showing with 66 additions and 26 deletions.
  1. +6 −0 README.rdoc
  2. +1 −1 Rakefile
  3. +3 −3 has_scope.gemspec
  4. +34 −18 lib/has_scope.rb
  5. +12 −2 test/has_scope_test.rb
  6. +10 −2 test/test_helper.rb
View
6 README.rdoc
@@ -20,6 +20,7 @@ Now, if you want to apply them to an specific resource, you just need to call <t
class GraduationsController < ApplicationController
has_scope :featured, :type => :boolean
has_scope :by_degree
+ has_scope :by_period, :using => [:started_at, :ended_at]
def index
@graduations = apply_scopes(Graduation).all
@@ -37,6 +38,9 @@ Then for each request:
/graduations?featured=true&by_degree=phd
#=> brings featured graduations with phd degree
+ /graduations?params[by_period][started_at]=20100701&params[by_period][ended_at]=20101013
+ #=> brings graduations in the given period
+
You can retrieve all the scopes applied in one action with <tt>current_scopes</tt> method.
In the last case, it would return: { :featured => true, :by_degree => "phd" }.
@@ -62,6 +66,8 @@ HasScope supports several options:
* <tt>:as</tt> - The key in the params hash expected to find the scope. Defaults to the scope name.
+* <tt>:using</tt> - The subkeys to be used as args when type is a hash.
+
* <tt>:if</tt> - Specifies a method, proc or string to call to determine if the scope should apply.
* <tt>:unless</tt> - Specifies a method, proc or string to call to determine if the scope should NOT apply.
View
2 Rakefile
@@ -27,7 +27,7 @@ begin
require 'jeweler'
Jeweler::Tasks.new do |s|
s.name = "has_scope"
- s.version = "0.4.2"
+ s.version = "0.5.0"
s.summary = "Maps controller filters to your resource scopes"
s.email = "contact@plataformatec.com.br"
s.homepage = "http://github.com/plataformatec/has_scope"
View
6 has_scope.gemspec
@@ -5,11 +5,11 @@
Gem::Specification.new do |s|
s.name = %q{has_scope}
- s.version = "0.4.2"
+ s.version = "0.5.0"
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
s.authors = ["Jos\303\251 Valim"]
- s.date = %q{2010-02-19}
+ s.date = %q{2010-03-23}
s.description = %q{Maps controller filters to your resource scopes}
s.email = %q{contact@plataformatec.com.br}
s.extra_rdoc_files = [
@@ -25,7 +25,7 @@ Gem::Specification.new do |s|
s.homepage = %q{http://github.com/plataformatec/has_scope}
s.rdoc_options = ["--charset=UTF-8"]
s.require_paths = ["lib"]
- s.rubygems_version = %q{1.3.5}
+ s.rubygems_version = %q{1.3.6}
s.summary = %q{Maps controller filters to your resource scopes}
s.test_files = [
"test/has_scope_test.rb",
View
52 lib/has_scope.rb
@@ -33,6 +33,9 @@ module ClassMethods
# * <tt>:as</tt> - The key in the params hash expected to find the scope.
# Defaults to the scope name.
#
+ # * <tt>:using</tt> - If type is a hash, you can provide :using to convert the hash to
+ # a named scope call with several arguments.
+ #
# * <tt>:if</tt> - Specifies a method, proc or string to call to determine
# if the scope should apply
#
@@ -61,7 +64,17 @@ module ClassMethods
def has_scope(*scopes, &block)
options = scopes.extract_options!
options.symbolize_keys!
- options.assert_valid_keys(:type, :only, :except, :if, :unless, :default, :as, :allow_blank)
+ options.assert_valid_keys(:type, :only, :except, :if, :unless, :default, :as, :using, :allow_blank)
+
+ if options.key?(:using)
+ if options.key?(:type) && options[:type] != :hash
+ raise "You cannot use :using with another :type different than :hash"
+ else
+ options[:type] = :hash
+ end
+
+ options[:using] = Array(options[:using])
+ end
options[:only] = Array(options[:only])
options[:except] = Array(options[:except])
@@ -80,56 +93,59 @@ def has_scope(*scopes, &block)
# Receives an object where scopes will be applied to.
#
# class GraduationsController < InheritedResources::Base
- # has_scope :featured, :boolean => true, :only => :index
+ # has_scope :featured, :type => true, :only => :index
# has_scope :by_degree, :only => :index
#
# def index
# @graduations = apply_scopes(Graduation).all
# end
# end
#
- def apply_scopes(target)
+ def apply_scopes(target, hash=params)
return target unless scopes_configuration
self.scopes_configuration.each do |scope, options|
next unless apply_scope_to_action?(options)
key = options[:as]
- if params.key?(key)
- value, call_scope = params[key], true
+ if hash.key?(key)
+ value, call_scope = hash[key], true
elsif options.key?(:default)
value, call_scope = options[:default], true
value = value.call(self) if value.is_a?(Proc)
end
+ value = parse_value(options[:type], key, value)
+
if call_scope && (value.present? || options[:allow_blank])
- set_current_scope(options[:type], key, value)
- target = apply_scope_by_type(options[:type], scope, target, current_scopes[key], options[:block])
+ current_scopes[key] = value
+ target = call_scope_by_type(options[:type], scope, target, value, options)
end
end
target
end
# Set the real value for the current scope if type check.
- def set_current_scope(type, key, value) #:nodoc:
+ def parse_value(type, key, value) #:nodoc:
if type == :boolean
- current_scopes[key] = TRUE_VALUES.include?(value)
- elsif ALLOWED_TYPES[type].none?{ |klass| value.is_a?(klass) }
+ TRUE_VALUES.include?(value)
+ elsif value && ALLOWED_TYPES[type].none?{ |klass| value.is_a?(klass) }
raise "Expected type :#{type} in params[:#{key}], got #{value.class}"
else
- current_scopes[key] = value
+ value
end
end
- # Apply the scope taking into account its type.
- def apply_scope_by_type(type, scope, target, value, block) #:nodoc:
+ # Call the scope taking into account its type.
+ def call_scope_by_type(type, scope, target, value, options) #:nodoc:
+ block = options[:block]
+
if type == :boolean
- if value
- block ? block.call(self, target) : target.send(scope)
- else
- target
- end
+ block ? block.call(self, target) : target.send(scope)
+ elsif value && options.key?(:using)
+ value = value.values_at(*options[:using])
+ block ? block.call(self, target, value) : target.send(scope, *value)
else
block ? block.call(self, target, value) : target.send(scope, value)
end
View
14 test/has_scope_test.rb
@@ -10,6 +10,7 @@ class TreesController < ApplicationController
has_scope :root_type, :as => :root, :allow_blank => true
has_scope :calculate_height, :default => proc {|c| c.session[:height] || 20 }, :only => :new
has_scope :paginate, :type => :hash
+ has_scope :args_paginate, :type => :hash, :using => [:page, :per_page]
has_scope :categories, :type => :array
has_scope :only_short, :type => :boolean do |controller, scope|
@@ -63,7 +64,7 @@ def test_boolean_scope_is_not_called_when_boolean_param_is_false
Tree.expects(:all).returns([mock_tree])
get :index, :only_tall => 'false'
assert_equal([mock_tree], assigns(:trees))
- assert_equal({ :only_tall => false }, current_scopes)
+ assert_equal({}, current_scopes)
end
def test_scope_is_called_only_on_index
@@ -134,14 +135,23 @@ def test_multiple_scopes_are_called
end
def test_scope_of_type_hash
- hash = { "page" => "1", "per_page" => "1" }
+ hash = { "page" => "1", "per_page" => "10" }
Tree.expects(:paginate).with(hash).returns(Tree)
Tree.expects(:all).returns([mock_tree])
get :index, :paginate => hash
assert_equal([mock_tree], assigns(:trees))
assert_equal({ :paginate => hash }, current_scopes)
end
+ def test_scope_of_type_hash_with_using
+ hash = { "page" => "1", "per_page" => "10" }
+ Tree.expects(:args_paginate).with("1", "10").returns(Tree)
+ Tree.expects(:all).returns([mock_tree])
+ get :index, :args_paginate => hash
+ assert_equal([mock_tree], assigns(:trees))
+ assert_equal({ :args_paginate => hash }, current_scopes)
+ end
+
def test_scope_of_type_array
array = %w(book kitchen sport)
Tree.expects(:categories).with(array).returns(Tree)
View
12 test/test_helper.rb
@@ -26,6 +26,14 @@ class ApplicationController < ActionController::Base; end
$:.unshift File.expand_path(File.dirname(__FILE__) + '/../lib')
require 'has_scope'
-ActionController::Routing::Routes.draw do |map|
+HasScope::Router = ActionDispatch::Routing::RouteSet.new
+HasScope::Router.draw do |map|
map.connect ':controller/:action/:id'
-end
+ map.connect ':controller/:action'
+end
+
+class ActiveSupport::TestCase
+ setup do
+ @router = HasScope::Router
+ end
+end

0 comments on commit 249a8c8

Please sign in to comment.