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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 31f1479fd17f9303641a356e7db5697e2b5b113c
4
- data.tar.gz: a65c103541374642713b8a27fbeb7b0e4b09518e
3
+ metadata.gz: 46b1fb5697f15f8789f8d174bdee4e946862cbd1
4
+ data.tar.gz: 2c05138de95c75628c2ddea4d24508ddbd511248
5
5
  SHA512:
6
- metadata.gz: e089a327e4e5ce48a62c38b47889e5f696e1cf4641da3c69f04ffa9a69bc93ae1cdc98a6c0a36258207f0d4e3ed190bdc9c7d3e80eb562436cbc11a40e8ecdcc
7
- data.tar.gz: 1c9781eaa496a291f361ca10e3e3ee44e6adf66d6353c00b8810d15b0962aeef0270241a3edf71fd9f2f5538f861757c13cfd7fffd6f9967593c37d748cf897f
6
+ metadata.gz: 788668ec2fb6bf0bc24db2d2675e9dfea2cd9e852cd4197d411e6113486a2b2ac88c165b74a0dc74b944c2246ab101f2137cdcb62797d5871019301e877fb090
7
+ data.tar.gz: 19a7388ad9014f195860aeb37732810a0dd5494d62a9721a0c4e18402d219ab81c004a4be97f4fe1ea9d835ab39ac0f6f915c472d29c37d13d39dbb92d296473
data/.gitignore CHANGED
@@ -11,3 +11,4 @@
11
11
  # rspec failure tracking
12
12
  .rspec_status
13
13
  *.gem
14
+ *.sqlite
data/.rspec CHANGED
@@ -1,2 +1 @@
1
- --format documentation
2
1
  --color
@@ -0,0 +1,5 @@
1
+ v 0.2.0
2
+ - allows for filtering and sorting enumerable collections via associated attributes
3
+ v 0.1.0
4
+ - initial version
5
+ - allows for filtering, sorting, and pagination enumerable collections via direct attributes
data/Gemfile CHANGED
@@ -6,3 +6,8 @@ git_source(:github) { |repo_name| "https://github.com/#{repo_name}" }
6
6
 
7
7
  # Specify your gem's dependencies in activeset.gemspec
8
8
  gemspec
9
+
10
+ group :test do
11
+ gem 'activerecord'
12
+ gem 'sqlite3'
13
+ end
data/README.md CHANGED
@@ -1,8 +1,4 @@
1
- # Activeset
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
- TODO: Write usage instructions here
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/[USERNAME]/activeset.
52
+ Bug reports and pull requests are welcome on GitHub at https://github.com/fractaledmind/activeset.
36
53
 
37
54
  ## License
38
55
 
@@ -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
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
3
  require 'bundler/setup'
4
- require 'activeset'
4
+ require 'active_set'
5
5
 
6
6
  # You can add fixtures and/or initialization code here to make experimenting
7
7
  # with your gem easier. You can also use a different console, if you like.
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rubygems'
4
+ require 'bundler'
5
+
6
+ Bundler.require :default, :development
7
+
8
+ Combustion.initialize! :all
9
+ run Combustion::Application
@@ -2,9 +2,9 @@
2
2
 
3
3
  require 'active_set/version'
4
4
 
5
- require 'active_set/filter/processor'
6
- require 'active_set/sort/processor'
7
- require 'active_set/paginate/processor'
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 = Filter::Processor.new(@set, structure)
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 = Sort::Processor.new(@set, structure)
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 = Paginate::Processor.new(@set, structure)
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 './structure_path'
3
+ require_relative '../structure/path'
4
4
 
5
5
  class BaseAdapter
6
6
  def initialize(keypath, value)
7
- @structure_path = StructurePath.new(keypath)
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
- module Paginate
7
+ class PaginateProcessor < BaseProcessor
7
8
  class EnumerableAdapter < BaseAdapter
8
9
  def process(set)
9
- @set = set
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class ActiveSet
4
- VERSION = '0.2.0'
4
+ VERSION = '0.3.0'
5
5
  end
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.2.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-09 00:00:00.000000000 Z
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: '0'
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: '0'
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/enumerable_adapter.rb
91
- - lib/active_set/filter/processor.rb
92
- - lib/active_set/paginate/enumerable_adapter.rb
93
- - lib/active_set/paginate/processor.rb
94
- - lib/active_set/sort/enumerable_adapter.rb
95
- - lib/active_set/sort/processor.rb
96
- - lib/active_set/structure_path.rb
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