scoping 0.0.1
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.
- checksums.yaml +7 -0
- data/.gitignore +17 -0
- data/Gemfile +3 -0
- data/LICENSE.txt +22 -0
- data/README.md +29 -0
- data/Rakefile +6 -0
- data/lib/scoping/scope_composer.rb +134 -0
- data/lib/scoping/version.rb +3 -0
- data/lib/scoping.rb +5 -0
- data/scoping.gemspec +24 -0
- data/spec/scoping/scope_composer_spec.rb +81 -0
- data/spec/spec_helper.rb +10 -0
- metadata +113 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: bf670267565ddc463c9db198a7ada3844bedfc44
|
4
|
+
data.tar.gz: 018e1965ce44d3bf3cf72495e49cb72450613f67
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: e5ff5856a942ef716e168af4a2807d4c8fe18e7ab22696184cc5412236e2fe2934fd566e00434b75065f35e61848537350da2b2843a71b10dbb59dd04d315348
|
7
|
+
data.tar.gz: 01f8918f0c44d6f1c4b6f4567fac64fefd36fb06700c17d69c090609f178b000c33a6eb3697400b049fcec8bbaf9ca227e922259353bb420627444527171c010
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Jiří Zajpt
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# ScopeComposer
|
2
|
+
|
3
|
+
TODO: Write a gem description
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'scoping'
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install scoping
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
TODO: Write usage instructions here
|
22
|
+
|
23
|
+
## Contributing
|
24
|
+
|
25
|
+
1. Fork it ( http://github.com/<my-github-username>/scope_composer/fork )
|
26
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
27
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
28
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
29
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,134 @@
|
|
1
|
+
require 'ostruct'
|
2
|
+
require 'active_support/core_ext/object'
|
3
|
+
|
4
|
+
# This is light-weight filtering helper class that will compose all given
|
5
|
+
# criteria (scopes). When using this class all filtering logic has to be stored
|
6
|
+
# in scopes instead of creating ad-hoc filtering objects.
|
7
|
+
#
|
8
|
+
# Usage example:
|
9
|
+
#
|
10
|
+
# composer = ScopeComposer.new(Challenge)
|
11
|
+
# composer.with_state = 'cancelled'
|
12
|
+
# composer.created_during_past = '1 week'
|
13
|
+
#
|
14
|
+
# Or you can provide criteria as a second argument to new:
|
15
|
+
#
|
16
|
+
# ScopeComposer.new(Challenge,
|
17
|
+
# with_state: 'cancelled',
|
18
|
+
# created_during_past: '1 week')
|
19
|
+
#
|
20
|
+
# Which translates to:
|
21
|
+
#
|
22
|
+
# Challenge.with_state(:cancelled).created_during_past('1 week')
|
23
|
+
#
|
24
|
+
#
|
25
|
+
# If you want to call the scopes which do not take arguments, you can safely
|
26
|
+
# use them with one condition - the scope is ommited if the argument value
|
27
|
+
# given is not "1" or true.
|
28
|
+
#
|
29
|
+
# For example:
|
30
|
+
#
|
31
|
+
# ScopeComposer.new(Challenge, accepted: false)
|
32
|
+
#
|
33
|
+
# Would not result in the scope `accepted` applied, but on the other hand
|
34
|
+
# following code would:
|
35
|
+
#
|
36
|
+
# ScopeComposer.new(Challenge, accepted: "1")
|
37
|
+
#
|
38
|
+
module Scoping
|
39
|
+
class ScopeComposer < OpenStruct
|
40
|
+
|
41
|
+
# Initialize new instance with given scope and criteria table.
|
42
|
+
#
|
43
|
+
# @param [ActiveRecord::Base] base_scope
|
44
|
+
# @param [Hash] table
|
45
|
+
def initialize(base_scope, table = nil)
|
46
|
+
@base_scope = base_scope
|
47
|
+
@current_scope = base_scope
|
48
|
+
@applied = false
|
49
|
+
super({})
|
50
|
+
@table = table if table
|
51
|
+
end
|
52
|
+
|
53
|
+
# Apply the scopes and return all the matching records.
|
54
|
+
#
|
55
|
+
# @return [ActiveRecord::Relation]
|
56
|
+
def all
|
57
|
+
return @current_scope.all if fields.empty?
|
58
|
+
apply_fields_on_current_scope
|
59
|
+
end
|
60
|
+
|
61
|
+
# Apply the scopes and return decorated the matching records.
|
62
|
+
#
|
63
|
+
# @return [ActiveRecord::Relation]
|
64
|
+
def decorate
|
65
|
+
all.decorate
|
66
|
+
end
|
67
|
+
|
68
|
+
# Apply the scopes and return paginated records.
|
69
|
+
#
|
70
|
+
# @return [Array]
|
71
|
+
def paginate(*args)
|
72
|
+
apply_fields_on_current_scope
|
73
|
+
@current_scope.paginate(*args)
|
74
|
+
end
|
75
|
+
|
76
|
+
# Apply the scopes and return count.
|
77
|
+
#
|
78
|
+
# @return [Fixnum]
|
79
|
+
def count
|
80
|
+
apply_fields_on_current_scope
|
81
|
+
@current_scope.count
|
82
|
+
end
|
83
|
+
|
84
|
+
# Apply the scopes and return the resulting scope.
|
85
|
+
#
|
86
|
+
# @return [ActiveRecord::Relation]
|
87
|
+
def scope
|
88
|
+
apply_fields_on_current_scope
|
89
|
+
@current_scope
|
90
|
+
end
|
91
|
+
|
92
|
+
private
|
93
|
+
|
94
|
+
# Applies assigned scopes and returns the result scope.
|
95
|
+
#
|
96
|
+
# The scope is called only when the value (argument for scope) is non-empty
|
97
|
+
# value.
|
98
|
+
def apply_fields_on_current_scope
|
99
|
+
return @current_scope if @applied
|
100
|
+
fields.each do |field|
|
101
|
+
value = public_send(field)
|
102
|
+
next unless value.present?
|
103
|
+
apply_field_on_current_scope field, value
|
104
|
+
end
|
105
|
+
@applied = true
|
106
|
+
@current_scope
|
107
|
+
end
|
108
|
+
|
109
|
+
# Applies given scope with given argument to current scope
|
110
|
+
#
|
111
|
+
# @param [String] field
|
112
|
+
# @param [Object] value
|
113
|
+
def apply_field_on_current_scope(field, value)
|
114
|
+
arity = @base_scope.method(field).arity
|
115
|
+
if arity == 0
|
116
|
+
if value == "1" || value == true
|
117
|
+
@current_scope = @current_scope.public_send field
|
118
|
+
end
|
119
|
+
else
|
120
|
+
@current_scope = @current_scope.public_send field, value
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
# Return the filter fields.
|
125
|
+
#
|
126
|
+
# @return [Array]
|
127
|
+
def fields
|
128
|
+
@table.keys
|
129
|
+
end
|
130
|
+
|
131
|
+
end
|
132
|
+
|
133
|
+
end
|
134
|
+
|
data/lib/scoping.rb
ADDED
data/scoping.gemspec
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'scoping/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "scoping"
|
8
|
+
spec.version = Scoping::VERSION
|
9
|
+
spec.authors = ["Jiří Zajpt"]
|
10
|
+
spec.email = ["jzajpt@blueberry.cz"]
|
11
|
+
spec.summary = %q{Scoping is utility gem for AR composing scopes}
|
12
|
+
spec.homepage = ""
|
13
|
+
spec.license = "MIT"
|
14
|
+
|
15
|
+
spec.files = `git ls-files`.split($/)
|
16
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
17
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
18
|
+
spec.require_paths = ["lib"]
|
19
|
+
|
20
|
+
spec.add_development_dependency 'bundler', '~> 1.5'
|
21
|
+
spec.add_development_dependency 'rake'
|
22
|
+
spec.add_development_dependency 'rspec'
|
23
|
+
spec.add_dependency 'activesupport'
|
24
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require "spec_helper"
|
4
|
+
|
5
|
+
describe Scoping::ScopeComposer do
|
6
|
+
describe "#all" do
|
7
|
+
let(:scope) { double "Scope" }
|
8
|
+
subject { Scoping::ScopeComposer.new scope, table }
|
9
|
+
|
10
|
+
context 'given criteria table' do
|
11
|
+
let(:table) { { a: '1', b: '2', c: '3' } }
|
12
|
+
|
13
|
+
it "applies all scopes" do
|
14
|
+
scope.stub_chain(:method, :arity).and_return 1
|
15
|
+
scope.stub_chain(:a, :b, :c).and_return "halelujah"
|
16
|
+
expect(subject.all).to eq "halelujah"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
context 'not given any criteria table' do
|
21
|
+
let(:table) { nil }
|
22
|
+
|
23
|
+
it "applies all scopes" do
|
24
|
+
expect(scope).to receive :all
|
25
|
+
subject.all
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
describe "#count" do
|
31
|
+
let(:scope) { double "Scope" }
|
32
|
+
subject { Scoping::ScopeComposer.new scope, table }
|
33
|
+
|
34
|
+
context 'given criteria table' do
|
35
|
+
let(:table) { { a: '1', b: '2', c: '3' } }
|
36
|
+
let(:result) { double "ResultScope" }
|
37
|
+
|
38
|
+
it "applies all scopes" do
|
39
|
+
scope.stub_chain(:method, :arity).and_return 1
|
40
|
+
scope.stub_chain(:a, :b, :c).and_return result
|
41
|
+
expect(result).to receive :count
|
42
|
+
subject.count
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
context 'not given any criteria table' do
|
47
|
+
let(:table) { nil }
|
48
|
+
|
49
|
+
it "applies all scopes" do
|
50
|
+
expect(scope).to receive :count
|
51
|
+
subject.count
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
describe "#paginate" do
|
57
|
+
let(:scope) { double "Scope" }
|
58
|
+
subject { Scoping::ScopeComposer.new scope, table }
|
59
|
+
|
60
|
+
context 'given criteria table' do
|
61
|
+
let(:table) { { a: '1', b: '2', c: '3' } }
|
62
|
+
let(:result) { double "ResultScope" }
|
63
|
+
|
64
|
+
it "applies all scopes" do
|
65
|
+
scope.stub_chain(:method, :arity).and_return 1
|
66
|
+
scope.stub_chain(:a, :b, :c).and_return result
|
67
|
+
expect(result).to receive(:paginate).with page: 1, per_page: 123
|
68
|
+
subject.paginate(page: 1, per_page: 123)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
context 'not given any criteria table' do
|
73
|
+
let(:table) { nil }
|
74
|
+
|
75
|
+
it "applies all scopes" do
|
76
|
+
expect(scope).to receive :paginate
|
77
|
+
subject.paginate
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,113 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: scoping
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Jiří Zajpt
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-01-12 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.5'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.5'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: activesupport
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
description:
|
70
|
+
email:
|
71
|
+
- jzajpt@blueberry.cz
|
72
|
+
executables: []
|
73
|
+
extensions: []
|
74
|
+
extra_rdoc_files: []
|
75
|
+
files:
|
76
|
+
- ".gitignore"
|
77
|
+
- Gemfile
|
78
|
+
- LICENSE.txt
|
79
|
+
- README.md
|
80
|
+
- Rakefile
|
81
|
+
- lib/scoping.rb
|
82
|
+
- lib/scoping/scope_composer.rb
|
83
|
+
- lib/scoping/version.rb
|
84
|
+
- scoping.gemspec
|
85
|
+
- spec/scoping/scope_composer_spec.rb
|
86
|
+
- spec/spec_helper.rb
|
87
|
+
homepage: ''
|
88
|
+
licenses:
|
89
|
+
- MIT
|
90
|
+
metadata: {}
|
91
|
+
post_install_message:
|
92
|
+
rdoc_options: []
|
93
|
+
require_paths:
|
94
|
+
- lib
|
95
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
96
|
+
requirements:
|
97
|
+
- - ">="
|
98
|
+
- !ruby/object:Gem::Version
|
99
|
+
version: '0'
|
100
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
101
|
+
requirements:
|
102
|
+
- - ">="
|
103
|
+
- !ruby/object:Gem::Version
|
104
|
+
version: '0'
|
105
|
+
requirements: []
|
106
|
+
rubyforge_project:
|
107
|
+
rubygems_version: 2.2.0
|
108
|
+
signing_key:
|
109
|
+
specification_version: 4
|
110
|
+
summary: Scoping is utility gem for AR composing scopes
|
111
|
+
test_files:
|
112
|
+
- spec/scoping/scope_composer_spec.rb
|
113
|
+
- spec/spec_helper.rb
|