cheesecloth 0.1.0
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 +9 -0
- data/.rspec +2 -0
- data/.rubocop.yml +561 -0
- data/Gemfile +5 -0
- data/LICENSE.txt +21 -0
- data/README.md +414 -0
- data/Rakefile +7 -0
- data/bin/console +12 -0
- data/bin/setup +8 -0
- data/cheesecloth.gemspec +43 -0
- data/circle.yml +3 -0
- data/lib/cheesecloth.rb +46 -0
- data/lib/cheesecloth/errors.rb +23 -0
- data/lib/cheesecloth/filter.rb +25 -0
- data/lib/cheesecloth/filter_list.rb +27 -0
- data/lib/cheesecloth/version.rb +4 -0
- data/lib/cheesecloth/wrapper.rb +29 -0
- metadata +134 -0
data/bin/console
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require "bundler/setup"
|
5
|
+
require "cheesecloth"
|
6
|
+
|
7
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
8
|
+
# with your gem easier. You can also use a different console, if you like.
|
9
|
+
|
10
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
11
|
+
require "pry"
|
12
|
+
Pry.start
|
data/bin/setup
ADDED
data/cheesecloth.gemspec
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
lib = File.expand_path("../lib", __FILE__)
|
4
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
5
|
+
require "cheesecloth/version"
|
6
|
+
|
7
|
+
Gem::Specification.new do |spec|
|
8
|
+
spec.name = "cheesecloth"
|
9
|
+
spec.version = CheeseCloth::VERSION
|
10
|
+
spec.authors = ["Steven Petryk"]
|
11
|
+
spec.email = ["me@stevenpetryk.com"]
|
12
|
+
|
13
|
+
spec.summary = "Take the boilerplate out of filtering a collection based on params."
|
14
|
+
spec.description = <<-DESCRIPTION
|
15
|
+
Dealing with filtering based on params in Rails APIs is a pain. CheeseCloth is designed to take
|
16
|
+
the pain out of parsing, validating, and acting upon params designed to filter collections.
|
17
|
+
DESCRIPTION
|
18
|
+
spec.homepage = "https://github.com/stevenpetryk/"
|
19
|
+
spec.license = "MIT"
|
20
|
+
|
21
|
+
# Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
|
22
|
+
# to allow pushing to a single host or delete this section to allow pushing to any host.
|
23
|
+
if spec.respond_to?(:metadata)
|
24
|
+
spec.metadata["allowed_push_host"] = "https://rubygems.org"
|
25
|
+
else
|
26
|
+
raise "RubyGems 2.0 or newer is required to protect against " \
|
27
|
+
"public gem pushes."
|
28
|
+
end
|
29
|
+
|
30
|
+
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
31
|
+
f.match(%r{^(test|spec|features)/})
|
32
|
+
end
|
33
|
+
spec.bindir = "exe"
|
34
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
35
|
+
spec.require_paths = ["lib"]
|
36
|
+
|
37
|
+
spec.add_dependency "activesupport", "~> 5.0"
|
38
|
+
|
39
|
+
spec.add_development_dependency "bundler", "~> 1.13"
|
40
|
+
spec.add_development_dependency "pry", "~> 0.10"
|
41
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
42
|
+
spec.add_development_dependency "rspec", "~> 3.0"
|
43
|
+
end
|
data/circle.yml
ADDED
data/lib/cheesecloth.rb
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require "active_support"
|
3
|
+
|
4
|
+
require_relative "cheesecloth/version"
|
5
|
+
require_relative "cheesecloth/errors"
|
6
|
+
require_relative "cheesecloth/filter"
|
7
|
+
require_relative "cheesecloth/filter_list"
|
8
|
+
require_relative "cheesecloth/wrapper"
|
9
|
+
|
10
|
+
module CheeseCloth
|
11
|
+
extend ActiveSupport::Concern
|
12
|
+
|
13
|
+
included do
|
14
|
+
cattr_accessor :cheesecloth_wrapper
|
15
|
+
self.cheesecloth_wrapper = Wrapper.new(self)
|
16
|
+
|
17
|
+
attr_accessor :scope_override
|
18
|
+
attr_writer :scope
|
19
|
+
end
|
20
|
+
|
21
|
+
class_methods do
|
22
|
+
def scope(*args)
|
23
|
+
cheesecloth_wrapper.assign_default_scope_proc(*args)
|
24
|
+
end
|
25
|
+
|
26
|
+
def filter(conditions = nil, &block)
|
27
|
+
cheesecloth_wrapper.filter_list.add_filter(conditions, block)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def scope
|
32
|
+
@scope || scope_override || cheesecloth_wrapper.scope
|
33
|
+
end
|
34
|
+
|
35
|
+
def filtered_scope(scope: nil)
|
36
|
+
self.scope_override = scope
|
37
|
+
cheesecloth_wrapper.prepare_and_run(self)
|
38
|
+
self.scope
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def cheesecloth_wrapper
|
44
|
+
self.class.cheesecloth_wrapper
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module CheeseCloth
|
4
|
+
class MissingScopeError < StandardError
|
5
|
+
def initialize(klass)
|
6
|
+
@klass = klass
|
7
|
+
end
|
8
|
+
|
9
|
+
def message
|
10
|
+
<<-MSG.strip_heredoc
|
11
|
+
Was unable to determine the base scope. Perhaps you forgot to call `scope`?"
|
12
|
+
|
13
|
+
Try something like:
|
14
|
+
|
15
|
+
class #{@klass.name || 'FooFilterer'}
|
16
|
+
include CheeseCloth
|
17
|
+
|
18
|
+
scope -> { Model.all }
|
19
|
+
end
|
20
|
+
MSG
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module CheeseCloth
|
3
|
+
class Filter
|
4
|
+
attr_reader :klass, :conditions, :block
|
5
|
+
|
6
|
+
def initialize(conditions, block)
|
7
|
+
@conditions = wrap(conditions)
|
8
|
+
@block = block
|
9
|
+
end
|
10
|
+
|
11
|
+
def run(instance)
|
12
|
+
instance.instance_eval(&block)
|
13
|
+
end
|
14
|
+
|
15
|
+
def conditions_satisfied?(instance)
|
16
|
+
conditions.all? { |condition| instance.send(condition) }
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def wrap(possible_array)
|
22
|
+
[possible_array].flatten.compact
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module CheeseCloth
|
3
|
+
class FilterList
|
4
|
+
attr_reader :instance, :filters
|
5
|
+
|
6
|
+
def initialize(instance)
|
7
|
+
@instance = instance
|
8
|
+
@filters = []
|
9
|
+
end
|
10
|
+
|
11
|
+
def add_filter(conditions, block)
|
12
|
+
@filters << Filter.new(conditions, block)
|
13
|
+
end
|
14
|
+
|
15
|
+
def run_filters(instance)
|
16
|
+
runnable_filters_on(instance).each do |filter|
|
17
|
+
instance.scope = filter.run(instance)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def runnable_filters_on(instance)
|
24
|
+
filters.select { |filter| filter.conditions_satisfied?(instance) }
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module CheeseCloth
|
3
|
+
class Wrapper
|
4
|
+
attr_reader :klass, :filter_list, :scope, :default_scope_proc
|
5
|
+
|
6
|
+
def initialize(klass)
|
7
|
+
@klass = klass
|
8
|
+
@filter_list = FilterList.new(klass)
|
9
|
+
end
|
10
|
+
|
11
|
+
def assign_default_scope_proc(block)
|
12
|
+
@default_scope_proc = block
|
13
|
+
end
|
14
|
+
|
15
|
+
def prepare_and_run(instance)
|
16
|
+
assign_and_check_scope(instance)
|
17
|
+
run(instance)
|
18
|
+
end
|
19
|
+
|
20
|
+
def assign_and_check_scope(instance)
|
21
|
+
@scope ||= default_scope_proc && default_scope_proc.call
|
22
|
+
raise MissingScopeError, self.class unless instance.scope
|
23
|
+
end
|
24
|
+
|
25
|
+
def run(instance)
|
26
|
+
filter_list.run_filters(instance)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
metadata
ADDED
@@ -0,0 +1,134 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: cheesecloth
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Steven Petryk
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-12-30 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: activesupport
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '5.0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '5.0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: bundler
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.13'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.13'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: pry
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0.10'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0.10'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rake
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '10.0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '10.0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rspec
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '3.0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '3.0'
|
83
|
+
description: |2
|
84
|
+
Dealing with filtering based on params in Rails APIs is a pain. CheeseCloth is designed to take
|
85
|
+
the pain out of parsing, validating, and acting upon params designed to filter collections.
|
86
|
+
email:
|
87
|
+
- me@stevenpetryk.com
|
88
|
+
executables: []
|
89
|
+
extensions: []
|
90
|
+
extra_rdoc_files: []
|
91
|
+
files:
|
92
|
+
- ".gitignore"
|
93
|
+
- ".rspec"
|
94
|
+
- ".rubocop.yml"
|
95
|
+
- Gemfile
|
96
|
+
- LICENSE.txt
|
97
|
+
- README.md
|
98
|
+
- Rakefile
|
99
|
+
- bin/console
|
100
|
+
- bin/setup
|
101
|
+
- cheesecloth.gemspec
|
102
|
+
- circle.yml
|
103
|
+
- lib/cheesecloth.rb
|
104
|
+
- lib/cheesecloth/errors.rb
|
105
|
+
- lib/cheesecloth/filter.rb
|
106
|
+
- lib/cheesecloth/filter_list.rb
|
107
|
+
- lib/cheesecloth/version.rb
|
108
|
+
- lib/cheesecloth/wrapper.rb
|
109
|
+
homepage: https://github.com/stevenpetryk/
|
110
|
+
licenses:
|
111
|
+
- MIT
|
112
|
+
metadata:
|
113
|
+
allowed_push_host: https://rubygems.org
|
114
|
+
post_install_message:
|
115
|
+
rdoc_options: []
|
116
|
+
require_paths:
|
117
|
+
- lib
|
118
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
119
|
+
requirements:
|
120
|
+
- - ">="
|
121
|
+
- !ruby/object:Gem::Version
|
122
|
+
version: '0'
|
123
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
124
|
+
requirements:
|
125
|
+
- - ">="
|
126
|
+
- !ruby/object:Gem::Version
|
127
|
+
version: '0'
|
128
|
+
requirements: []
|
129
|
+
rubyforge_project:
|
130
|
+
rubygems_version: 2.5.1
|
131
|
+
signing_key:
|
132
|
+
specification_version: 4
|
133
|
+
summary: Take the boilerplate out of filtering a collection based on params.
|
134
|
+
test_files: []
|