classy_filter 0.1.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 +11 -0
- data/.rspec +2 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +45 -0
- data/README.md +92 -0
- data/Rakefile +6 -0
- data/classy_filter.gemspec +29 -0
- data/lib/classy_filter.rb +43 -0
- data/lib/classy_filter/class_methods.rb +44 -0
- data/lib/classy_filter/coercions.rb +50 -0
- data/lib/classy_filter/predicates.rb +52 -0
- data/lib/classy_filter/version.rb +3 -0
- metadata +140 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 7d39815c9e5cc38bad174755097ce7e62140800e77123b509ffcc0d9194cade0
|
|
4
|
+
data.tar.gz: bffc8a05381de967fd6b051025431413c639820988f71b364f0a7af240516fa1
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 4ecdba44e99129941af52a39b8cb2d11c3917ed427a060c0372292e502a3324a046ea13d4d96a56ffcb9bc7211a0184d8d16d457c2bb1a06bc71aca9114c24ee
|
|
7
|
+
data.tar.gz: 45473de6711f8e184a051c74c437394f9905bb5a3c3c6797e776dbbb69ffe83a265f25d49db3f5126c89f53ce1b6d30fd8574c649a71e1f176857b4b3cd08b47
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
PATH
|
|
2
|
+
remote: .
|
|
3
|
+
specs:
|
|
4
|
+
classy_filter (0.1.1)
|
|
5
|
+
sequel (~> 5.0)
|
|
6
|
+
|
|
7
|
+
GEM
|
|
8
|
+
remote: https://rubygems.org/
|
|
9
|
+
specs:
|
|
10
|
+
coderay (1.1.2)
|
|
11
|
+
diff-lcs (1.3)
|
|
12
|
+
method_source (0.9.0)
|
|
13
|
+
pry (0.11.3)
|
|
14
|
+
coderay (~> 1.1.0)
|
|
15
|
+
method_source (~> 0.9.0)
|
|
16
|
+
rake (10.5.0)
|
|
17
|
+
rspec (3.7.0)
|
|
18
|
+
rspec-core (~> 3.7.0)
|
|
19
|
+
rspec-expectations (~> 3.7.0)
|
|
20
|
+
rspec-mocks (~> 3.7.0)
|
|
21
|
+
rspec-core (3.7.1)
|
|
22
|
+
rspec-support (~> 3.7.0)
|
|
23
|
+
rspec-expectations (3.7.0)
|
|
24
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
|
25
|
+
rspec-support (~> 3.7.0)
|
|
26
|
+
rspec-mocks (3.7.0)
|
|
27
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
|
28
|
+
rspec-support (~> 3.7.0)
|
|
29
|
+
rspec-support (3.7.1)
|
|
30
|
+
sequel (5.9.0)
|
|
31
|
+
sqlite3 (1.3.13)
|
|
32
|
+
|
|
33
|
+
PLATFORMS
|
|
34
|
+
ruby
|
|
35
|
+
|
|
36
|
+
DEPENDENCIES
|
|
37
|
+
bundler (~> 1.16)
|
|
38
|
+
classy_filter!
|
|
39
|
+
pry
|
|
40
|
+
rake (~> 10.0)
|
|
41
|
+
rspec (~> 3.0)
|
|
42
|
+
sqlite3 (~> 1.0)
|
|
43
|
+
|
|
44
|
+
BUNDLED WITH
|
|
45
|
+
1.16.1
|
data/README.md
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
# ClassyFilter
|
|
2
|
+
|
|
3
|
+
ClassyFilter is a customizeable class-based filtering library. Currently it's only build for Sequel, but there are plans to expand!
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
Add this line to your application's Gemfile:
|
|
8
|
+
|
|
9
|
+
```ruby
|
|
10
|
+
gem 'classy_filter'
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
And then execute:
|
|
14
|
+
|
|
15
|
+
$ bundle
|
|
16
|
+
|
|
17
|
+
Or install it yourself as:
|
|
18
|
+
|
|
19
|
+
$ gem install classy_filter
|
|
20
|
+
|
|
21
|
+
## Usage
|
|
22
|
+
|
|
23
|
+
### Writing a filter
|
|
24
|
+
|
|
25
|
+
To begin using this gem, you must first define your filter class, deriving it from `ClassyFilter::Base`. In this class, you'd specify your filter fields, extra predicates and coercions (should you need those).
|
|
26
|
+
|
|
27
|
+
Let's begin with an example. Assuming you have a table named `people` with this structure:
|
|
28
|
+
|
|
29
|
+
| name | type |
|
|
30
|
+
| ---- | ---- |
|
|
31
|
+
| first_name | varchar(1023) |
|
|
32
|
+
| last_name | varchar(1023) |
|
|
33
|
+
| date_of_birth | date |
|
|
34
|
+
| trust_level | integer |
|
|
35
|
+
|
|
36
|
+
You could write a filter like this:
|
|
37
|
+
|
|
38
|
+
```ruby
|
|
39
|
+
class MyFilter < ClassyFilter::Base
|
|
40
|
+
filter_field :first_name # (1)
|
|
41
|
+
filter_field :last_name_prefix, attribute: :last_name, predicate: :starts_with_i # (2)
|
|
42
|
+
filter_field :dob_after, attribute: :date_of_birth, predicate: :gteq, coercion: :integer # (3)
|
|
43
|
+
filter_field :rough_trust, attribute: :trust_level, predicate: :gt_10x, coercion: :integer # (4)
|
|
44
|
+
|
|
45
|
+
predicate :gt_10x, ->(dataset, attr, input) { dataset.where { |r| Sequel[attr] > input } } # (5)
|
|
46
|
+
end
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Let's walk through this filter line by line.
|
|
50
|
+
|
|
51
|
+
Line `(1)` shows us how to define a very basic filter. This definition lets our filter accept the `first_name` parameter
|
|
52
|
+
and perform simple filtering by equality or inclusion.
|
|
53
|
+
|
|
54
|
+
Line `(2)` shows us how to define a filter with a custom predicate and parameter name. Our filter will accept the
|
|
55
|
+
`last_name_prefix` parameter and filter by the `last_name column`, using `ILIKE` to do it.
|
|
56
|
+
|
|
57
|
+
Line `(3)` shows us how to define a filter not just with a custom predicate, but also with a coercion. Before performing
|
|
58
|
+
the filtering, our filter will attempt to coerce the `dob_after` parameter into an `Integer`.
|
|
59
|
+
|
|
60
|
+
Line `(5)` shows us a custom predicate (that's used on the line `(4)`). A predicate is defined using the
|
|
61
|
+
`ClassyFilter::Base.predicate` method that accepts the predicate name and a proc that receives the dataset, the
|
|
62
|
+
attribute name and the parameter value.
|
|
63
|
+
|
|
64
|
+
You can see all existing predicates [here](/lib/classy_filter/predicates.rb) and all existing coercions
|
|
65
|
+
[here.](lib/classy_filter/coercions.rb)
|
|
66
|
+
|
|
67
|
+
### Performing the filtering
|
|
68
|
+
|
|
69
|
+
This one is actually quite easy. Assuming we have a database named `DB` and receive a hash named `params` from somewhere
|
|
70
|
+
(say, the URL query string), we can use our filter as follows:
|
|
71
|
+
|
|
72
|
+
```ruby
|
|
73
|
+
ds = DB[:people]
|
|
74
|
+
MyFilter.new(params).call(ds)
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## Development
|
|
78
|
+
|
|
79
|
+
After checking out the repo, run `bundle install` to install dependencies. Then, run `rake spec` to run the tests. You can also run `pry -rclassy_filter` for an interactive prompt that will allow you to experiment.
|
|
80
|
+
|
|
81
|
+
## TODO
|
|
82
|
+
|
|
83
|
+
❗ Add collection (array/hash) coercions
|
|
84
|
+
❗ Move the Sequel implementation out of the gem
|
|
85
|
+
⬜ Try to find out a way to simplify predicates definitions
|
|
86
|
+
⬜ More tests. Never enough tests.
|
|
87
|
+
❓ Add a better coercion library. Dry-rb? Or maybe Hashie?
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
## Contributing
|
|
91
|
+
|
|
92
|
+
Bug reports and pull requests are welcome on GitLab at https://gitlab.com/art-solopov/classy_filter.
|
data/Rakefile
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
|
|
2
|
+
lib = File.expand_path("../lib", __FILE__)
|
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
|
+
require "classy_filter/version"
|
|
5
|
+
|
|
6
|
+
Gem::Specification.new do |spec|
|
|
7
|
+
spec.name = "classy_filter"
|
|
8
|
+
spec.version = ClassyFilter::VERSION
|
|
9
|
+
spec.authors = ["Artemiy Solopov"]
|
|
10
|
+
spec.email = ["art-solopov@yandex.ru"]
|
|
11
|
+
|
|
12
|
+
spec.summary = %q{A cutomizeable class-based filtering/searching library for Sequel}
|
|
13
|
+
spec.description = spec.summary
|
|
14
|
+
spec.homepage = "https://gitlab.com/art-solopov/classy_filter"
|
|
15
|
+
spec.license = 'MIT'
|
|
16
|
+
|
|
17
|
+
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
|
18
|
+
f.match(%r{^(test|spec|features)/})
|
|
19
|
+
end
|
|
20
|
+
spec.require_paths = ["lib"]
|
|
21
|
+
|
|
22
|
+
spec.add_runtime_dependency 'sequel', '~> 5.0'
|
|
23
|
+
|
|
24
|
+
spec.add_development_dependency "bundler", "~> 1.16"
|
|
25
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
|
26
|
+
spec.add_development_dependency "rspec", "~> 3.0"
|
|
27
|
+
spec.add_development_dependency 'sqlite3', '~> 1.0'
|
|
28
|
+
spec.add_development_dependency 'pry'
|
|
29
|
+
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
require 'classy_filter/version'
|
|
2
|
+
require 'classy_filter/predicates'
|
|
3
|
+
require 'classy_filter/coercions'
|
|
4
|
+
require 'classy_filter/class_methods'
|
|
5
|
+
|
|
6
|
+
module ClassyFilter
|
|
7
|
+
Field = Struct.new(:param_name, :attribute, :predicate, :coercion)
|
|
8
|
+
|
|
9
|
+
class Base
|
|
10
|
+
extend Forwardable
|
|
11
|
+
|
|
12
|
+
extend ClassMethods
|
|
13
|
+
|
|
14
|
+
attr_reader :params
|
|
15
|
+
|
|
16
|
+
def initialize(params)
|
|
17
|
+
@params = params.transform_keys(&:to_s)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def call(dataset)
|
|
21
|
+
filter_fields.reduce(dataset) do |ds, (value, field)|
|
|
22
|
+
value = coercions_module.coerce(value, field.coercion) if field.coercion
|
|
23
|
+
attribute = field.attribute || field.param_name
|
|
24
|
+
predicates_module.send(field.predicate, ds, attribute, value)
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
private
|
|
29
|
+
|
|
30
|
+
def_delegator :"self.class", :filter_fields, :all_filter_fields
|
|
31
|
+
def_delegator :"self.class", :predicates_module
|
|
32
|
+
def_delegator :"self.class", :coercions_module
|
|
33
|
+
|
|
34
|
+
def filter_fields
|
|
35
|
+
all_filter_fields
|
|
36
|
+
.to_a
|
|
37
|
+
.lazy
|
|
38
|
+
.map { |ff| [params[ff.param_name.to_s], ff] }
|
|
39
|
+
.reject { |param, _| param.nil? }
|
|
40
|
+
.reject { |param, _| param.is_a?(String) && param.empty? }
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
module ClassyFilter
|
|
2
|
+
module ClassMethods
|
|
3
|
+
attr_reader :filter_fields
|
|
4
|
+
|
|
5
|
+
def filter_field(param_name, attribute: nil,
|
|
6
|
+
predicate: :eq_in, coercion: nil)
|
|
7
|
+
@filter_fields ||= []
|
|
8
|
+
@filter_fields << Field.new(param_name, attribute,
|
|
9
|
+
predicate, coercion)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def predicate(name, body)
|
|
13
|
+
predicates_module.define_method(name, &body)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def coercion(name, body)
|
|
17
|
+
coercions_module.define_method(name, &body)
|
|
18
|
+
coercions_module.private(name)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def predicates_module
|
|
22
|
+
@predicates_module || ClassyFilter::Predicates
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def coercions_module
|
|
26
|
+
@coercions_module || ClassyFilter::Coercions
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
protected
|
|
30
|
+
|
|
31
|
+
def build_predicates_module!(base)
|
|
32
|
+
@predicates_module = Module.new do
|
|
33
|
+
extend base.predicates_module
|
|
34
|
+
extend self
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
private
|
|
39
|
+
|
|
40
|
+
def inherited(subclass)
|
|
41
|
+
subclass.build_predicates_module!(self)
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
module ClassyFilter
|
|
2
|
+
module Coercions
|
|
3
|
+
extend self
|
|
4
|
+
|
|
5
|
+
def coerce(value, coercion)
|
|
6
|
+
case coercion
|
|
7
|
+
when Symbol then send(coercion, value)
|
|
8
|
+
when ->(x) { x.respond_to?(:call) } then coercion.call(value)
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
private
|
|
13
|
+
|
|
14
|
+
# Scalar conversions
|
|
15
|
+
# Those are methods that receive a value and return
|
|
16
|
+
# the coerced value
|
|
17
|
+
|
|
18
|
+
def integer(value)
|
|
19
|
+
Integer(value)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def float(value)
|
|
23
|
+
Float(value)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def boolean(value)
|
|
27
|
+
case value
|
|
28
|
+
when true, 'true', 'TRUE', 1, '1' then true
|
|
29
|
+
when false, 'false', 'FALSE', 0, '0' then false
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def date(value)
|
|
34
|
+
case value
|
|
35
|
+
when Date then value
|
|
36
|
+
when Array then Date.new(*value)
|
|
37
|
+
else Date.parse(value.to_s)
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def timestamp(value)
|
|
42
|
+
case value
|
|
43
|
+
when Time then value
|
|
44
|
+
when DateTime then value.to_time
|
|
45
|
+
when Array then Time.new(*value)
|
|
46
|
+
else DateTime.parse(value.to_s).to_time
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
module ClassyFilter
|
|
2
|
+
module Predicates
|
|
3
|
+
extend self
|
|
4
|
+
|
|
5
|
+
def eq_in(ds, attribute, input)
|
|
6
|
+
ds.where(attribute => input)
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
alias eq eq_in
|
|
10
|
+
alias :in eq_in
|
|
11
|
+
|
|
12
|
+
# TODO: think about refactoring
|
|
13
|
+
|
|
14
|
+
def gt(ds, attribute, input)
|
|
15
|
+
ds.where { |_r| sequel_col(ds, attribute) > input }
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def lt(ds, attribute, input)
|
|
19
|
+
ds.where { |_r| sequel_col(ds, attribute) < input }
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def gteq(ds, attribute, input)
|
|
23
|
+
ds.where { |_r| sequel_col(ds, attribute) >= input }
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def lteq(ds, attribute, input)
|
|
27
|
+
ds.where { |_r| sequel_col(ds, attribute) <= input }
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def starts_with(ds, attribute, input)
|
|
31
|
+
ds.where { |_r| Sequel.like(sequel_col(ds, attribute), input + '%') }
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def starts_with_i(ds, attribute, input)
|
|
35
|
+
ds.where { |_r| Sequel.ilike(sequel_col(ds, attribute), input + '%') }
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def contains(ds, attribute, input)
|
|
39
|
+
ds.where { |_r| Sequel.like(sequel_col(ds, attribute), "%#{input}%") }
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def contains_i(ds, attribute, input)
|
|
43
|
+
ds.where { |_r| Sequel.ilike(sequel_col(ds, attribute), "%#{input}%") }
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
private
|
|
47
|
+
|
|
48
|
+
def sequel_col(ds, attribute)
|
|
49
|
+
Sequel[ds.first_source_table][attribute.to_sym]
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: classy_filter
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.1
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Artemiy Solopov
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2018-07-01 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: sequel
|
|
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.16'
|
|
34
|
+
type: :development
|
|
35
|
+
prerelease: false
|
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
+
requirements:
|
|
38
|
+
- - "~>"
|
|
39
|
+
- !ruby/object:Gem::Version
|
|
40
|
+
version: '1.16'
|
|
41
|
+
- !ruby/object:Gem::Dependency
|
|
42
|
+
name: rake
|
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
|
44
|
+
requirements:
|
|
45
|
+
- - "~>"
|
|
46
|
+
- !ruby/object:Gem::Version
|
|
47
|
+
version: '10.0'
|
|
48
|
+
type: :development
|
|
49
|
+
prerelease: false
|
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
51
|
+
requirements:
|
|
52
|
+
- - "~>"
|
|
53
|
+
- !ruby/object:Gem::Version
|
|
54
|
+
version: '10.0'
|
|
55
|
+
- !ruby/object:Gem::Dependency
|
|
56
|
+
name: rspec
|
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
|
58
|
+
requirements:
|
|
59
|
+
- - "~>"
|
|
60
|
+
- !ruby/object:Gem::Version
|
|
61
|
+
version: '3.0'
|
|
62
|
+
type: :development
|
|
63
|
+
prerelease: false
|
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
65
|
+
requirements:
|
|
66
|
+
- - "~>"
|
|
67
|
+
- !ruby/object:Gem::Version
|
|
68
|
+
version: '3.0'
|
|
69
|
+
- !ruby/object:Gem::Dependency
|
|
70
|
+
name: sqlite3
|
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
|
72
|
+
requirements:
|
|
73
|
+
- - "~>"
|
|
74
|
+
- !ruby/object:Gem::Version
|
|
75
|
+
version: '1.0'
|
|
76
|
+
type: :development
|
|
77
|
+
prerelease: false
|
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
79
|
+
requirements:
|
|
80
|
+
- - "~>"
|
|
81
|
+
- !ruby/object:Gem::Version
|
|
82
|
+
version: '1.0'
|
|
83
|
+
- !ruby/object:Gem::Dependency
|
|
84
|
+
name: pry
|
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
|
86
|
+
requirements:
|
|
87
|
+
- - ">="
|
|
88
|
+
- !ruby/object:Gem::Version
|
|
89
|
+
version: '0'
|
|
90
|
+
type: :development
|
|
91
|
+
prerelease: false
|
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
93
|
+
requirements:
|
|
94
|
+
- - ">="
|
|
95
|
+
- !ruby/object:Gem::Version
|
|
96
|
+
version: '0'
|
|
97
|
+
description: A cutomizeable class-based filtering/searching library for Sequel
|
|
98
|
+
email:
|
|
99
|
+
- art-solopov@yandex.ru
|
|
100
|
+
executables: []
|
|
101
|
+
extensions: []
|
|
102
|
+
extra_rdoc_files: []
|
|
103
|
+
files:
|
|
104
|
+
- ".gitignore"
|
|
105
|
+
- ".rspec"
|
|
106
|
+
- Gemfile
|
|
107
|
+
- Gemfile.lock
|
|
108
|
+
- README.md
|
|
109
|
+
- Rakefile
|
|
110
|
+
- classy_filter.gemspec
|
|
111
|
+
- lib/classy_filter.rb
|
|
112
|
+
- lib/classy_filter/class_methods.rb
|
|
113
|
+
- lib/classy_filter/coercions.rb
|
|
114
|
+
- lib/classy_filter/predicates.rb
|
|
115
|
+
- lib/classy_filter/version.rb
|
|
116
|
+
homepage: https://gitlab.com/art-solopov/classy_filter
|
|
117
|
+
licenses:
|
|
118
|
+
- MIT
|
|
119
|
+
metadata: {}
|
|
120
|
+
post_install_message:
|
|
121
|
+
rdoc_options: []
|
|
122
|
+
require_paths:
|
|
123
|
+
- lib
|
|
124
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
125
|
+
requirements:
|
|
126
|
+
- - ">="
|
|
127
|
+
- !ruby/object:Gem::Version
|
|
128
|
+
version: '0'
|
|
129
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
130
|
+
requirements:
|
|
131
|
+
- - ">="
|
|
132
|
+
- !ruby/object:Gem::Version
|
|
133
|
+
version: '0'
|
|
134
|
+
requirements: []
|
|
135
|
+
rubyforge_project:
|
|
136
|
+
rubygems_version: 2.7.3
|
|
137
|
+
signing_key:
|
|
138
|
+
specification_version: 4
|
|
139
|
+
summary: A cutomizeable class-based filtering/searching library for Sequel
|
|
140
|
+
test_files: []
|