sinatra-has_scope 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,3 @@
1
+ pkg/*
2
+ *.gem
3
+ .bundle
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source :gemcutter
2
+
3
+ # Specify your gem's dependencies in sinatra-has_scope.gemspec
4
+ gemspec
data/README.mdown ADDED
@@ -0,0 +1,71 @@
1
+ ## Sinatra HasScope
2
+
3
+ Sinatra HasScope is a Sinatra adaptation of the very useful [HasScope Rails library](https://github.com/plataformatec/has_scope).
4
+
5
+ Sinatra HasScope allows you to easily create filters based on your resources named scopes.
6
+ Imagine the following model called Graduation:
7
+
8
+ class Graduation < ActiveRecord::Base
9
+ scope :featured, where('featured = ?', true)
10
+ scope :by_degree, lambda { |degree| { where('degree = ?', degree) } }
11
+ end
12
+
13
+ You can use those named scopes as filters by declaring them on your routes:
14
+
15
+ class MyApp < Sinatra::Base
16
+ has_scope :gradutation, :featured, :type => :boolean
17
+ has_scope :gradutation, :by_degree
18
+ has_scope :gradutation, :by_period, :using => [:started_at, :ended_at]
19
+ end
20
+
21
+ Now, if you want to apply them to an specific resource, you just need to call `apply_scopes`:
22
+
23
+ get '/graduations' do
24
+ @graduations = apply_scopes(:graduation, Graduation, params).all
25
+ end
26
+
27
+ Then for each request:
28
+
29
+ /graduations
30
+ #=> acts like a normal request
31
+
32
+ /graduations?featured=true
33
+ #=> calls the named scope and bring featured graduations
34
+
35
+ /graduations?featured=true&by_degree=phd
36
+ #=> brings featured graduations with phd degree
37
+
38
+ /graduations?params[by_period][started_at]=20100701&params[by_period][ended_at]=20101013
39
+ #=> brings graduations in the given period
40
+
41
+ ## Installation
42
+
43
+ Sinatra HasScope is available as gem on Gemcutter, so just run the following:
44
+
45
+ sudo gem install sinatra-has_scope
46
+
47
+ To install it with bundler, use:
48
+
49
+ gem 'sinatra-has_scope', :require => 'sinatra/has_scope'
50
+
51
+ ## Options
52
+
53
+ HasScope supports several options:
54
+
55
+ * `:type` - Checks the type of the parameter sent. If set to :boolean it just calls the named scope, without any argument. By default, it does not allow hashes or arrays to be given, except if type :hash or :array are set.
56
+
57
+ * `:as` - The key in the params hash expected to find the scope. Defaults to the scope name.
58
+
59
+ * `:using` - The subkeys to be used as args when type is a hash.
60
+
61
+ * `:if` - Specifies a method, proc or string to call to determine if the scope should apply.
62
+
63
+ * `:unless` - Specifies a method, proc or string to call to determine if the scope should NOT apply.
64
+
65
+ * `:default` - Default value for the scope. Whenever supplied the scope is always called.
66
+
67
+ * `:allow_blank` - Blank values are not sent to scopes by default. Set to true to overwrite.
68
+
69
+ ## Bugs and Feedback
70
+
71
+ If you discover any bugs or want to drop a line, feel free to create an [issue on GitHub](http://github.com/simonc/sinatra-has_scope/issues).
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
@@ -0,0 +1,5 @@
1
+ module Sinatra
2
+ module HasScope
3
+ VERSION = "0.0.1"
4
+ end
5
+ end
@@ -0,0 +1,141 @@
1
+ require 'sinatra/base'
2
+
3
+ module Sinatra
4
+ module HasScope
5
+ TRUE_VALUES = ["true", true, "1", 1]
6
+
7
+ ALLOWED_TYPES = {
8
+ :array => [ Array ],
9
+ :hash => [ Hash ],
10
+ :boolean => [ Object ],
11
+ :default => [ String, Numeric ]
12
+ }
13
+
14
+ attr_accessor :scopes_configuration
15
+
16
+ # Detects params from url and apply as scopes to your classes.
17
+ #
18
+ # == Options
19
+ #
20
+ # * <tt>:type</tt> - Checks the type of the parameter sent. If set to :boolean
21
+ # it just calls the named scope, without any argument. By default,
22
+ # it does not allow hashes or arrays to be given, except if type
23
+ # :hash or :array are set.
24
+ #
25
+ # * <tt>:as</tt> - The key in the params hash expected to find the scope.
26
+ # Defaults to the scope name.
27
+ #
28
+ # * <tt>:using</tt> - If type is a hash, you can provide :using to convert the hash to
29
+ # a named scope call with several arguments.
30
+ #
31
+ # * <tt>:if</tt> - Specifies a method, proc or string to call to determine
32
+ # if the scope should apply
33
+ #
34
+ # * <tt>:unless</tt> - Specifies a method, proc or string to call to determine
35
+ # if the scope should NOT apply.
36
+ #
37
+ # * <tt>:default</tt> - Default value for the scope. Whenever supplied the scope
38
+ # is always called.
39
+ #
40
+ # * <tt>:allow_blank</tt> - Blank values are not sent to scopes by default. Set to true to overwrite.
41
+ #
42
+ def has_scope(scope_group, *scopes)
43
+ options = scopes.extract_options!
44
+ options.symbolize_keys!
45
+ options.assert_valid_keys(:type, :if, :unless, :default, :as, :using, :allow_blank)
46
+
47
+ if options.key?(:using)
48
+ if options.key?(:type) && options[:type] != :hash
49
+ raise "You cannot use :using with another :type different than :hash"
50
+ else
51
+ options[:type] = :hash
52
+ end
53
+
54
+ options[:using] = [*options[:using]]
55
+ end
56
+
57
+ self.scopes_configuration ||= {}
58
+ self.scopes_configuration[scope_group] ||= {}
59
+
60
+ scopes.each do |scope|
61
+ self.scopes_configuration[scope_group][scope] ||= {
62
+ :as => scope,
63
+ :type => :default
64
+ }
65
+ self.scopes_configuration[scope_group][scope].merge!(options)
66
+ end
67
+ end
68
+
69
+ # Receives an object where scopes will be applied to.
70
+ #
71
+ # has_scope :graduation, :featured, :type => true
72
+ # has_scope :graduation, :by_degree
73
+ #
74
+ # get '/graduations' do
75
+ # @graduations = apply_scopes(:graduation, Graduation, params).all
76
+ # end
77
+ #
78
+ def apply_scopes(scope_group, target, hash)
79
+ return target unless scopes_configuration
80
+
81
+ self.scopes_configuration[scope_group].each do |scope, options|
82
+ key = options[:as].to_s
83
+
84
+ if hash.key?(key)
85
+ value, call_scope = hash[key], true
86
+ elsif options.key?(:default)
87
+ value, call_scope = options[:default], true
88
+ value = value.call(self) if value.is_a?(Proc)
89
+ end
90
+
91
+ value = parse_value(options[:type], key, value)
92
+
93
+ if call_scope && (value.present? || options[:allow_blank])
94
+ target = call_scope_by_type(options[:type], scope, target, value, options)
95
+ end
96
+ end
97
+
98
+ target
99
+ end
100
+
101
+ # Set the real value for the current scope if type check.
102
+ def parse_value(type, key, value) #:nodoc:
103
+ if type == :boolean
104
+ TRUE_VALUES.include?(value)
105
+ elsif value && ALLOWED_TYPES[type].none?{ |klass| value.is_a?(klass) }
106
+ raise "Expected type :#{type} in params[:#{key}], got #{value.class}"
107
+ else
108
+ value
109
+ end
110
+ end
111
+
112
+ # Call the scope taking into account its type.
113
+ def call_scope_by_type(type, scope, target, value, options) #:nodoc:
114
+ if type == :boolean
115
+ target.send(scope)
116
+ elsif value && options.key?(:using)
117
+ value = value.values_at(*options[:using])
118
+ target.send(scope, *value)
119
+ else
120
+ target.send(scope, value)
121
+ end
122
+ end
123
+
124
+ # Evaluates the scope options :if or :unless. Returns true if the proc
125
+ # method, or string evals to the expected value.
126
+ def applicable?(string_proc_or_symbol, expected) #:nodoc:
127
+ case string_proc_or_symbol
128
+ when String
129
+ eval(string_proc_or_symbol) == expected
130
+ when Proc
131
+ string_proc_or_symbol.call(self) == expected
132
+ when Symbol
133
+ send(string_proc_or_symbol) == expected
134
+ else
135
+ true
136
+ end
137
+ end
138
+ end
139
+
140
+ register HasScope
141
+ end
@@ -0,0 +1,22 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path("../lib/sinatra/has_scope/version", __FILE__)
3
+
4
+ Gem::Specification.new do |s|
5
+ s.name = "sinatra-has_scope"
6
+ s.version = Sinatra::HasScope::VERSION
7
+ s.platform = Gem::Platform::RUBY
8
+ s.authors = ['Simon COURTOIS']
9
+ s.email = ['scourtois@cubyx.fr']
10
+ s.homepage = "http://rubygems.org/gems/sinatra-has_scope"
11
+ s.summary = "HasScope equivalent for Sinatra"
12
+ s.description = "HasScope readaptation for the Sinatra micro-framework"
13
+
14
+ s.required_rubygems_version = ">= 1.3.6"
15
+ s.rubyforge_project = "sinatra-has_scope"
16
+
17
+ s.add_development_dependency "bundler", ">= 1.0.0"
18
+
19
+ s.files = `git ls-files`.split("\n")
20
+ s.executables = `git ls-files`.split("\n").map{|f| f =~ /^bin\/(.*)/ ? $1 : nil}.compact
21
+ s.require_path = 'lib'
22
+ end
metadata ADDED
@@ -0,0 +1,91 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sinatra-has_scope
3
+ version: !ruby/object:Gem::Version
4
+ hash: 29
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 1
10
+ version: 0.0.1
11
+ platform: ruby
12
+ authors:
13
+ - Simon COURTOIS
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2010-12-06 00:00:00 +01:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: bundler
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ hash: 23
30
+ segments:
31
+ - 1
32
+ - 0
33
+ - 0
34
+ version: 1.0.0
35
+ type: :development
36
+ version_requirements: *id001
37
+ description: HasScope readaptation for the Sinatra micro-framework
38
+ email:
39
+ - scourtois@cubyx.fr
40
+ executables: []
41
+
42
+ extensions: []
43
+
44
+ extra_rdoc_files: []
45
+
46
+ files:
47
+ - .gitignore
48
+ - Gemfile
49
+ - README.mdown
50
+ - Rakefile
51
+ - lib/sinatra/has_scope.rb
52
+ - lib/sinatra/has_scope/version.rb
53
+ - sinatra-has_scope.gemspec
54
+ has_rdoc: true
55
+ homepage: http://rubygems.org/gems/sinatra-has_scope
56
+ licenses: []
57
+
58
+ post_install_message:
59
+ rdoc_options: []
60
+
61
+ require_paths:
62
+ - lib
63
+ required_ruby_version: !ruby/object:Gem::Requirement
64
+ none: false
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ hash: 3
69
+ segments:
70
+ - 0
71
+ version: "0"
72
+ required_rubygems_version: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ">="
76
+ - !ruby/object:Gem::Version
77
+ hash: 23
78
+ segments:
79
+ - 1
80
+ - 3
81
+ - 6
82
+ version: 1.3.6
83
+ requirements: []
84
+
85
+ rubyforge_project: sinatra-has_scope
86
+ rubygems_version: 1.3.7
87
+ signing_key:
88
+ specification_version: 3
89
+ summary: HasScope equivalent for Sinatra
90
+ test_files: []
91
+