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.
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
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -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
@@ -0,0 +1,3 @@
1
+ machine:
2
+ ruby:
3
+ version: 2.3.1
@@ -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,4 @@
1
+ # frozen_string_literal: true
2
+ module CheeseCloth
3
+ VERSION = "0.1.0"
4
+ 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: []