activeset 0.2.0 → 0.3.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 +4 -4
- data/.gitignore +1 -0
- data/.rspec +0 -1
- data/CHANGELOG +5 -0
- data/Gemfile +5 -0
- data/README.md +24 -7
- data/activeset.gemspec +7 -1
- data/bin/console +1 -1
- data/config.ru +9 -0
- data/lib/active_set.rb +14 -6
- data/lib/active_set/{base_adapter.rb → processors/base_adapter.rb} +2 -2
- data/lib/active_set/{base_processor.rb → processors/base_processor.rb} +9 -0
- data/lib/active_set/processors/filter/active_record_adapter.rb +57 -0
- data/lib/active_set/processors/filter/enumerable_adapter.rb +33 -0
- data/lib/active_set/processors/filter_processor.rb +23 -0
- data/lib/active_set/{paginate → processors/paginate}/enumerable_adapter.rb +3 -3
- data/lib/active_set/processors/paginate_processor.rb +27 -0
- data/lib/active_set/processors/sort/active_record_adapter.rb +52 -0
- data/lib/active_set/processors/sort/enumerable_adapter.rb +30 -0
- data/lib/active_set/processors/sort_processor.rb +23 -0
- data/lib/active_set/structure/path.rb +54 -0
- data/lib/active_set/version.rb +1 -1
- metadata +103 -15
- data/lib/active_set/filter/enumerable_adapter.rb +0 -18
- data/lib/active_set/filter/processor.rb +0 -25
- data/lib/active_set/paginate/processor.rb +0 -29
- data/lib/active_set/sort/enumerable_adapter.rb +0 -17
- data/lib/active_set/sort/processor.rb +0 -25
- data/lib/active_set/structure_path.rb +0 -46
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 46b1fb5697f15f8789f8d174bdee4e946862cbd1
|
4
|
+
data.tar.gz: 2c05138de95c75628c2ddea4d24508ddbd511248
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 788668ec2fb6bf0bc24db2d2675e9dfea2cd9e852cd4197d411e6113486a2b2ac88c165b74a0dc74b944c2246ab101f2137cdcb62797d5871019301e877fb090
|
7
|
+
data.tar.gz: 19a7388ad9014f195860aeb37732810a0dd5494d62a9721a0c4e18402d219ab81c004a4be97f4fe1ea9d835ab39ac0f6f915c472d29c37d13d39dbb92d296473
|
data/.gitignore
CHANGED
data/.rspec
CHANGED
data/CHANGELOG
ADDED
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -1,8 +1,4 @@
|
|
1
|
-
#
|
2
|
-
|
3
|
-
Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/activeset`. To experiment with that code, run `bin/console` for an interactive prompt.
|
4
|
-
|
5
|
-
TODO: Delete this and the text above, and describe your gem
|
1
|
+
# ActiveSet
|
6
2
|
|
7
3
|
## Installation
|
8
4
|
|
@@ -22,7 +18,28 @@ Or install it yourself as:
|
|
22
18
|
|
23
19
|
## Usage
|
24
20
|
|
25
|
-
|
21
|
+
The `ActiveSet` class is an extension of `Enumerable` that adds methods for filtering, sorting, and paginating (right now; other methods are sure to follow).
|
22
|
+
|
23
|
+
Every convenience method added to the `ActiveSet` class is handled via a `Processor` class, and that `Processor` class will then use 1 or more `Adapter` classes to actually fulfill the functional contract.
|
24
|
+
|
25
|
+
an `Adapter` for a particular `Processor` simply handles doing the job of the processor for a particular kind of Set.
|
26
|
+
|
27
|
+
So, for example, the `Filter::Processor` will have an `EnumerableAdapter` (to work with generic enumerable sets) and an `ActiveRecordAdapter` (to work with active record relations).
|
28
|
+
|
29
|
+
When calling a convenience method on an instance of `ActiveSet`, you pass only 1 argument: what I am currently calling a `structure`, which is a plain-old-Ruby-hash. Each convenience method works with hashes of differing signatures.
|
30
|
+
|
31
|
+
e.g. `filter(attribute: 'value', association: { field: 'value' })` or `sort(attribute: :asc, association: { field: 'desc' })` or `paginate(page: 1, size: 10)`
|
32
|
+
|
33
|
+
## Future Feature Ideas
|
34
|
+
|
35
|
+
- allow for filtering thru `to-many` associations (maybe via `associations[any]` or `associations[all]` syntax)
|
36
|
+
- allow for filtering without typecasting the value (maybe via `key*` syntax)
|
37
|
+
|
38
|
+
## Notes
|
39
|
+
|
40
|
+
This library does not deal with typecasting string values; the values of your structures must be of the appropriate data-type.
|
41
|
+
|
42
|
+
This library does not work with `:time` fields in ActiveRecord relations.
|
26
43
|
|
27
44
|
## Development
|
28
45
|
|
@@ -32,7 +49,7 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
|
|
32
49
|
|
33
50
|
## Contributing
|
34
51
|
|
35
|
-
Bug reports and pull requests are welcome on GitHub at https://github.com/
|
52
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/fractaledmind/activeset.
|
36
53
|
|
37
54
|
## License
|
38
55
|
|
data/activeset.gemspec
CHANGED
@@ -24,9 +24,15 @@ Gem::Specification.new do |spec|
|
|
24
24
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
25
25
|
spec.require_paths = ['lib']
|
26
26
|
|
27
|
-
spec.add_dependency 'activesupport'
|
27
|
+
spec.add_dependency 'activesupport', '~> 5.1.3'
|
28
28
|
|
29
29
|
spec.add_development_dependency 'bundler', '~> 1.15'
|
30
30
|
spec.add_development_dependency 'rake', '~> 10.0'
|
31
31
|
spec.add_development_dependency 'rspec', '~> 3.0'
|
32
|
+
spec.add_development_dependency 'database_cleaner', '~> 1.6.1'
|
33
|
+
spec.add_development_dependency 'combustion', '~> 0.7.0'
|
34
|
+
spec.add_development_dependency 'factory_girl', '~> 4.8.0'
|
35
|
+
spec.add_development_dependency 'faker', '~> 1.8.4'
|
36
|
+
spec.add_development_dependency 'simplecov', '~> 0.15.0'
|
37
|
+
spec.add_development_dependency 'simplecov-console', '~> 0.4.2'
|
32
38
|
end
|
data/bin/console
CHANGED
data/config.ru
ADDED
data/lib/active_set.rb
CHANGED
@@ -2,9 +2,9 @@
|
|
2
2
|
|
3
3
|
require 'active_set/version'
|
4
4
|
|
5
|
-
require 'active_set/
|
6
|
-
require 'active_set/
|
7
|
-
require 'active_set/
|
5
|
+
require 'active_set/processors/filter_processor'
|
6
|
+
require 'active_set/processors/sort_processor'
|
7
|
+
require 'active_set/processors/paginate_processor'
|
8
8
|
|
9
9
|
class ActiveSet
|
10
10
|
include Enumerable
|
@@ -24,18 +24,26 @@ class ActiveSet
|
|
24
24
|
@set == other.set
|
25
25
|
end
|
26
26
|
|
27
|
+
def method_missing(method_name, *args, &block)
|
28
|
+
@set.send(method_name, *args, &block) || super
|
29
|
+
end
|
30
|
+
|
31
|
+
def respond_to_missing?(method_name, include_private = false)
|
32
|
+
@set.respond_to?(method_name) || super
|
33
|
+
end
|
34
|
+
|
27
35
|
def filter(structure)
|
28
|
-
filterer =
|
36
|
+
filterer = FilterProcessor.new(@set, structure)
|
29
37
|
self.class.new(filterer.process)
|
30
38
|
end
|
31
39
|
|
32
40
|
def sort(structure)
|
33
|
-
sorter =
|
41
|
+
sorter = SortProcessor.new(@set, structure)
|
34
42
|
self.class.new(sorter.process)
|
35
43
|
end
|
36
44
|
|
37
45
|
def paginate(structure)
|
38
|
-
paginater =
|
46
|
+
paginater = PaginateProcessor.new(@set, structure)
|
39
47
|
self.class.new(paginater.process)
|
40
48
|
end
|
41
49
|
end
|
@@ -1,10 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative '
|
3
|
+
require_relative '../structure/path'
|
4
4
|
|
5
5
|
class BaseAdapter
|
6
6
|
def initialize(keypath, value)
|
7
|
-
@structure_path =
|
7
|
+
@structure_path = Structure::Path.new(keypath)
|
8
8
|
@value = value
|
9
9
|
end
|
10
10
|
end
|
@@ -3,8 +3,17 @@
|
|
3
3
|
require 'patches/core_ext/hash/flatten_keys'
|
4
4
|
|
5
5
|
class BaseProcessor
|
6
|
+
def self.queue_adapter(adapter)
|
7
|
+
@adapters ||= []
|
8
|
+
@adapters |= [adapter]
|
9
|
+
end
|
10
|
+
|
6
11
|
def initialize(set, structure)
|
7
12
|
@set = set
|
8
13
|
@structure = structure.flatten_keys
|
9
14
|
end
|
15
|
+
|
16
|
+
def adapters
|
17
|
+
self.class.instance_variable_get(:@adapters)
|
18
|
+
end
|
10
19
|
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../base_adapter'
|
4
|
+
require_relative '../base_processor'
|
5
|
+
|
6
|
+
class ActiveSet
|
7
|
+
class FilterProcessor < BaseProcessor
|
8
|
+
class ActiveRecordAdapter < BaseAdapter
|
9
|
+
def process(set)
|
10
|
+
@set = set
|
11
|
+
return @set unless @set.respond_to? :to_sql
|
12
|
+
return @set unless attribute_is_field?
|
13
|
+
|
14
|
+
query
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def attribute_is_field?
|
20
|
+
return false unless attribute_model
|
21
|
+
attribute_model.attribute_names
|
22
|
+
.include?(@structure_path.attribute)
|
23
|
+
end
|
24
|
+
|
25
|
+
def query
|
26
|
+
@set.includes(@structure_path.to_h)
|
27
|
+
.references(@structure_path.to_h)
|
28
|
+
.where(arel_operation)
|
29
|
+
end
|
30
|
+
|
31
|
+
def arel_operation
|
32
|
+
Arel::Nodes::InfixOperation.new(@structure_path.operator,
|
33
|
+
arel_column,
|
34
|
+
arel_value)
|
35
|
+
end
|
36
|
+
|
37
|
+
def attribute_model
|
38
|
+
@structure_path.to_a
|
39
|
+
.reduce(@set) do |obj, assoc|
|
40
|
+
obj.reflections[assoc.to_s]&.klass
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def arel_column
|
45
|
+
arel_table[@structure_path.attribute]
|
46
|
+
end
|
47
|
+
|
48
|
+
def arel_value
|
49
|
+
Arel.sql(ActiveRecord::Base.connection.quote(@value))
|
50
|
+
end
|
51
|
+
|
52
|
+
def arel_table
|
53
|
+
Arel::Table.new(attribute_model.table_name)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../base_adapter'
|
4
|
+
|
5
|
+
class ActiveSet
|
6
|
+
class FilterProcessor < BaseProcessor
|
7
|
+
class EnumerableAdapter < BaseAdapter
|
8
|
+
def process(set)
|
9
|
+
set.select do |item|
|
10
|
+
value_for(item).send(@structure_path.operator,
|
11
|
+
passed_value)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def value_for(item)
|
18
|
+
convert_datetime_values_to_integer(@structure_path.value_for(item: item))
|
19
|
+
end
|
20
|
+
|
21
|
+
def passed_value
|
22
|
+
convert_datetime_values_to_integer(@value)
|
23
|
+
end
|
24
|
+
|
25
|
+
def convert_datetime_values_to_integer(value)
|
26
|
+
# DateTimes (and Times) are tricky to compare, Integers are easier
|
27
|
+
# and I only care about second precision
|
28
|
+
return value unless value.is_a?(DateTime)
|
29
|
+
value.to_i
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'active_support/core_ext/object/blank'
|
4
|
+
|
5
|
+
require_relative './base_processor'
|
6
|
+
require_relative './filter/enumerable_adapter'
|
7
|
+
require_relative './filter/active_record_adapter'
|
8
|
+
|
9
|
+
class ActiveSet
|
10
|
+
class FilterProcessor < BaseProcessor
|
11
|
+
queue_adapter ActiveRecordAdapter
|
12
|
+
queue_adapter EnumerableAdapter
|
13
|
+
|
14
|
+
def process
|
15
|
+
adapters.reduce(@set) do |outer_set, adapter|
|
16
|
+
@structure.reject { |_, v| v.blank? }
|
17
|
+
.reduce(outer_set) do |inner_set, (keypath, value)|
|
18
|
+
adapter.new(keypath, value).process(inner_set)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -1,13 +1,13 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require_relative '../base_adapter'
|
4
|
+
require_relative '../base_processor'
|
4
5
|
|
5
6
|
class ActiveSet
|
6
|
-
|
7
|
+
class PaginateProcessor < BaseProcessor
|
7
8
|
class EnumerableAdapter < BaseAdapter
|
8
9
|
def process(set)
|
9
|
-
|
10
|
-
@set.each_slice(pagesize).take(page_number).last
|
10
|
+
set.each_slice(pagesize).take(page_number).last
|
11
11
|
end
|
12
12
|
|
13
13
|
private
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative './base_processor'
|
4
|
+
require_relative './paginate/enumerable_adapter'
|
5
|
+
|
6
|
+
class ActiveSet
|
7
|
+
class PaginateProcessor < BaseProcessor
|
8
|
+
def process
|
9
|
+
return @set if @set.count < pagesize
|
10
|
+
adapter.new(page_number, pagesize).process(@set)
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def adapter
|
16
|
+
EnumerableAdapter
|
17
|
+
end
|
18
|
+
|
19
|
+
def page_number
|
20
|
+
@structure[[:page]] || 1
|
21
|
+
end
|
22
|
+
|
23
|
+
def pagesize
|
24
|
+
@structure[[:size]] || 25
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../base_adapter'
|
4
|
+
require_relative '../base_processor'
|
5
|
+
|
6
|
+
class ActiveSet
|
7
|
+
class SortProcessor < BaseProcessor
|
8
|
+
class ActiveRecordAdapter < BaseAdapter
|
9
|
+
def process(set)
|
10
|
+
@set = set
|
11
|
+
return @set unless @set.respond_to? :to_sql
|
12
|
+
return @set unless attribute_is_field?
|
13
|
+
|
14
|
+
@set.includes(@structure_path.to_h)
|
15
|
+
.references(@structure_path.to_h)
|
16
|
+
.merge(arel_operation)
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def attribute_is_field?
|
22
|
+
return false unless attribute_model
|
23
|
+
attribute_model.attribute_names
|
24
|
+
.include?(@structure_path.attribute)
|
25
|
+
end
|
26
|
+
|
27
|
+
def case_insensitive?
|
28
|
+
@structure_path.operator.to_s == 'i'
|
29
|
+
end
|
30
|
+
|
31
|
+
def arel_operation
|
32
|
+
column = case_insensitive? ? arel_column.lower : arel_column
|
33
|
+
attribute_model.order(column.send(@value))
|
34
|
+
end
|
35
|
+
|
36
|
+
def attribute_model
|
37
|
+
@structure_path.to_a
|
38
|
+
.reduce(@set) do |obj, assoc|
|
39
|
+
obj.reflections[assoc.to_s]&.klass
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def arel_column
|
44
|
+
arel_table[@structure_path.attribute]
|
45
|
+
end
|
46
|
+
|
47
|
+
def arel_table
|
48
|
+
Arel::Table.new(attribute_model.table_name)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../base_adapter'
|
4
|
+
require_relative '../base_processor'
|
5
|
+
|
6
|
+
class ActiveSet
|
7
|
+
class SortProcessor < BaseProcessor
|
8
|
+
class EnumerableAdapter < BaseAdapter
|
9
|
+
def process(set)
|
10
|
+
set.sort_by do |item|
|
11
|
+
attribute_value = @structure_path.value_for(item: item)
|
12
|
+
case_insensitive?(attribute_value) ? insensify(attribute_value) : attribute_value
|
13
|
+
end.tap { |c| c.reverse! if @value.to_s == 'desc' }
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def case_insensitive?(value)
|
19
|
+
# Cannot sort pure Booleans or Nils, so we _must_ cast to Strings
|
20
|
+
return true if value.is_a?(TrueClass) || value.is_a?(FalseClass)
|
21
|
+
return true if value.is_a?(NilClass)
|
22
|
+
@structure_path.operator.to_s == 'i'
|
23
|
+
end
|
24
|
+
|
25
|
+
def insensify(value)
|
26
|
+
value.to_s.downcase
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'active_support/core_ext/object/blank'
|
4
|
+
|
5
|
+
require_relative './base_processor'
|
6
|
+
require_relative './sort/enumerable_adapter'
|
7
|
+
require_relative './sort/active_record_adapter'
|
8
|
+
|
9
|
+
class ActiveSet
|
10
|
+
class SortProcessor < BaseProcessor
|
11
|
+
queue_adapter ActiveRecordAdapter
|
12
|
+
queue_adapter EnumerableAdapter
|
13
|
+
|
14
|
+
def process
|
15
|
+
adapters.reduce(@set) do |outer_set, adapter|
|
16
|
+
@structure.reject { |_, v| v.blank? }
|
17
|
+
.reduce(outer_set) do |inner_set, (keypath, value)|
|
18
|
+
adapter.new(keypath, value).process(inner_set)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'active_support/core_ext/array/wrap'
|
4
|
+
require 'active_support/core_ext/object/try'
|
5
|
+
|
6
|
+
module Structure
|
7
|
+
class Path
|
8
|
+
attr_reader :path
|
9
|
+
|
10
|
+
def initialize(path)
|
11
|
+
# `path` can be an Array (e.g. [:parent, :child, :grandchild])
|
12
|
+
# or a String (e.g. 'parent.child.grandchild')
|
13
|
+
@path = path.is_a?(String) ? path.split('.') : Array.wrap(path).map(&:to_s)
|
14
|
+
end
|
15
|
+
|
16
|
+
def attribute
|
17
|
+
attribute = @path.last
|
18
|
+
return attribute.sub(operator_regex, '') if attribute.match operator_regex
|
19
|
+
attribute
|
20
|
+
end
|
21
|
+
|
22
|
+
def operator
|
23
|
+
attribute = @path.last
|
24
|
+
return attribute[operator_regex, 1] if attribute.match operator_regex
|
25
|
+
'=='
|
26
|
+
end
|
27
|
+
|
28
|
+
def to_a
|
29
|
+
@path.slice(0, @path.length - 1)
|
30
|
+
end
|
31
|
+
|
32
|
+
def to_h
|
33
|
+
to_a.reverse.reduce({}) { |a, e| { e => a } }
|
34
|
+
end
|
35
|
+
|
36
|
+
def value_for(item:)
|
37
|
+
resource_for(item: item).send(attribute)
|
38
|
+
rescue
|
39
|
+
nil
|
40
|
+
end
|
41
|
+
|
42
|
+
def resource_for(item:)
|
43
|
+
to_a.reduce(item, :try)
|
44
|
+
rescue
|
45
|
+
nil
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
def operator_regex
|
51
|
+
/\((.*?)\)/
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
data/lib/active_set/version.rb
CHANGED
metadata
CHANGED
@@ -1,29 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: activeset
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Stephen Margheim
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-09-
|
11
|
+
date: 2017-09-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - "
|
17
|
+
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version:
|
19
|
+
version: 5.1.3
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- - "
|
24
|
+
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version:
|
26
|
+
version: 5.1.3
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: bundler
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -66,6 +66,90 @@ dependencies:
|
|
66
66
|
- - "~>"
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '3.0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: database_cleaner
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 1.6.1
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 1.6.1
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: combustion
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: 0.7.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.7.0
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: factory_girl
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: 4.8.0
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: 4.8.0
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: faker
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - "~>"
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: 1.8.4
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - "~>"
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: 1.8.4
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: simplecov
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - "~>"
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: 0.15.0
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - "~>"
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: 0.15.0
|
139
|
+
- !ruby/object:Gem::Dependency
|
140
|
+
name: simplecov-console
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - "~>"
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: 0.4.2
|
146
|
+
type: :development
|
147
|
+
prerelease: false
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
149
|
+
requirements:
|
150
|
+
- - "~>"
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: 0.4.2
|
69
153
|
description: Easily filter, sort, and paginate enumerable sets.
|
70
154
|
email:
|
71
155
|
- stephen.margheim@gmail.com
|
@@ -77,6 +161,7 @@ files:
|
|
77
161
|
- ".rspec"
|
78
162
|
- ".rubocop.yml"
|
79
163
|
- ".travis.yml"
|
164
|
+
- CHANGELOG
|
80
165
|
- Gemfile
|
81
166
|
- LICENSE.txt
|
82
167
|
- README.md
|
@@ -84,16 +169,19 @@ files:
|
|
84
169
|
- activeset.gemspec
|
85
170
|
- bin/console
|
86
171
|
- bin/setup
|
172
|
+
- config.ru
|
87
173
|
- lib/active_set.rb
|
88
|
-
- lib/active_set/base_adapter.rb
|
89
|
-
- lib/active_set/base_processor.rb
|
90
|
-
- lib/active_set/filter/
|
91
|
-
- lib/active_set/filter/
|
92
|
-
- lib/active_set/
|
93
|
-
- lib/active_set/paginate/
|
94
|
-
- lib/active_set/
|
95
|
-
- lib/active_set/sort/
|
96
|
-
- lib/active_set/
|
174
|
+
- lib/active_set/processors/base_adapter.rb
|
175
|
+
- lib/active_set/processors/base_processor.rb
|
176
|
+
- lib/active_set/processors/filter/active_record_adapter.rb
|
177
|
+
- lib/active_set/processors/filter/enumerable_adapter.rb
|
178
|
+
- lib/active_set/processors/filter_processor.rb
|
179
|
+
- lib/active_set/processors/paginate/enumerable_adapter.rb
|
180
|
+
- lib/active_set/processors/paginate_processor.rb
|
181
|
+
- lib/active_set/processors/sort/active_record_adapter.rb
|
182
|
+
- lib/active_set/processors/sort/enumerable_adapter.rb
|
183
|
+
- lib/active_set/processors/sort_processor.rb
|
184
|
+
- lib/active_set/structure/path.rb
|
97
185
|
- lib/active_set/version.rb
|
98
186
|
- lib/patches/core_ext/hash/flatten_keys.rb
|
99
187
|
homepage: https://github.com/fractaledmind/activeset
|
@@ -1,18 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require_relative '../base_adapter'
|
4
|
-
|
5
|
-
class ActiveSet
|
6
|
-
module Filter
|
7
|
-
class EnumerableAdapter < BaseAdapter
|
8
|
-
def process(set)
|
9
|
-
@set = set
|
10
|
-
@set.select do |item|
|
11
|
-
attribute_value = @structure_path.value_for(item: item)
|
12
|
-
attribute_value.send(@structure_path.operator,
|
13
|
-
@value)
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
@@ -1,25 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'active_support/core_ext/object/blank'
|
4
|
-
|
5
|
-
require_relative '../base_processor'
|
6
|
-
require_relative './enumerable_adapter'
|
7
|
-
|
8
|
-
class ActiveSet
|
9
|
-
module Filter
|
10
|
-
class Processor < BaseProcessor
|
11
|
-
def process
|
12
|
-
@structure.reject { |_, v| v.blank? }
|
13
|
-
.reduce(@set) do |set, (keypath, value)|
|
14
|
-
adapter.new(keypath, value).process(set)
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
private
|
19
|
-
|
20
|
-
def adapter
|
21
|
-
EnumerableAdapter
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
@@ -1,29 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require_relative '../base_processor'
|
4
|
-
require_relative './enumerable_adapter'
|
5
|
-
|
6
|
-
class ActiveSet
|
7
|
-
module Paginate
|
8
|
-
class Processor < BaseProcessor
|
9
|
-
def process
|
10
|
-
return @set if @set.count < pagesize
|
11
|
-
adapter.new(page_number, pagesize).process(@set)
|
12
|
-
end
|
13
|
-
|
14
|
-
private
|
15
|
-
|
16
|
-
def adapter
|
17
|
-
EnumerableAdapter
|
18
|
-
end
|
19
|
-
|
20
|
-
def page_number
|
21
|
-
@structure[[:page]] || 1
|
22
|
-
end
|
23
|
-
|
24
|
-
def pagesize
|
25
|
-
@structure[[:size]] || 25
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|
@@ -1,17 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require_relative '../base_adapter'
|
4
|
-
|
5
|
-
class ActiveSet
|
6
|
-
module Sort
|
7
|
-
class EnumerableAdapter < BaseAdapter
|
8
|
-
def process(set)
|
9
|
-
@set = set
|
10
|
-
@set.sort_by do |item|
|
11
|
-
attribute_value = @structure_path.value_for(item: item)
|
12
|
-
attribute_value.is_a?(String) ? attribute_value.downcase : attribute_value
|
13
|
-
end.tap { |c| c.reverse! if @value.to_s == 'desc' }
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
@@ -1,25 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'active_support/core_ext/object/blank'
|
4
|
-
|
5
|
-
require_relative '../base_processor'
|
6
|
-
require_relative './enumerable_adapter'
|
7
|
-
|
8
|
-
class ActiveSet
|
9
|
-
module Sort
|
10
|
-
class Processor < BaseProcessor
|
11
|
-
def process
|
12
|
-
@structure.reject { |_, value| value.blank? }
|
13
|
-
.reduce(@set) do |set, (keypath, value)|
|
14
|
-
adapter.new(keypath, value).process(set)
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
private
|
19
|
-
|
20
|
-
def adapter
|
21
|
-
EnumerableAdapter
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
@@ -1,46 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'active_support/core_ext/array/wrap'
|
4
|
-
require 'active_support/core_ext/object/try'
|
5
|
-
|
6
|
-
class StructurePath
|
7
|
-
def initialize(path)
|
8
|
-
# `path` can be an Array (e.g. [:parent, :child, :grandchild])
|
9
|
-
# or a String (e.g. 'parent.child.grandchild')
|
10
|
-
@path = path.is_a?(String) ? path.split('.') : Array.wrap(path).map(&:to_s)
|
11
|
-
end
|
12
|
-
|
13
|
-
def attribute
|
14
|
-
attribute = @path.last
|
15
|
-
return attribute.sub(operator_regex, '') if attribute.match operator_regex
|
16
|
-
attribute
|
17
|
-
end
|
18
|
-
|
19
|
-
def operator
|
20
|
-
attribute = @path.last
|
21
|
-
return attribute[operator_regex, 1] if attribute.match operator_regex
|
22
|
-
'=='
|
23
|
-
end
|
24
|
-
|
25
|
-
def to_a
|
26
|
-
@path.slice(0, @path.length - 1)
|
27
|
-
end
|
28
|
-
|
29
|
-
def to_h
|
30
|
-
to_a.reverse.inject({}) { |a, e| { e => a } }
|
31
|
-
end
|
32
|
-
|
33
|
-
def value_for(item:)
|
34
|
-
@path.inject(item, :try)
|
35
|
-
end
|
36
|
-
|
37
|
-
def resource_for(item:)
|
38
|
-
to_a.inject(item, :try)
|
39
|
-
end
|
40
|
-
|
41
|
-
private
|
42
|
-
|
43
|
-
def operator_regex
|
44
|
-
%r{\((.*?)\)}
|
45
|
-
end
|
46
|
-
end
|