activeset 0.3.0 → 0.3.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 46b1fb5697f15f8789f8d174bdee4e946862cbd1
4
- data.tar.gz: 2c05138de95c75628c2ddea4d24508ddbd511248
3
+ metadata.gz: fc73d4a0f511ddca2d0c895b7867816dc571102f
4
+ data.tar.gz: 02ac9b548790d30b2dac78a372b3ccc091769ed2
5
5
  SHA512:
6
- metadata.gz: 788668ec2fb6bf0bc24db2d2675e9dfea2cd9e852cd4197d411e6113486a2b2ac88c165b74a0dc74b944c2246ab101f2137cdcb62797d5871019301e877fb090
7
- data.tar.gz: 19a7388ad9014f195860aeb37732810a0dd5494d62a9721a0c4e18402d219ab81c004a4be97f4fe1ea9d835ab39ac0f6f915c472d29c37d13d39dbb92d296473
6
+ metadata.gz: 029232215b1cd1280f1b75757198bce5e97aa2e64603f2fa5c51aef8304407c7b56e1b0928a0e09fac080c9de272b00716842d94ad122a99f97d8f5337a1d58b
7
+ data.tar.gz: e73777713e06505233491977d66b4f48966e3ce5a50b4b99dcc242f00db13349e10ac3166a6ac5fff0da0cfcad02fffcf61359cba737b6e20c63d8694df8216a
data/CHANGELOG CHANGED
@@ -1,3 +1,9 @@
1
+ v 0.3.1
2
+ - Implement an Instructions object layer for handling the hashes passed into Processors
3
+ v 0.3.0
4
+ - remove the typecasting functionality
5
+ - bug fixes
6
+ - improved specs
1
7
  v 0.2.0
2
8
  - allows for filtering and sorting enumerable collections via associated attributes
3
9
  v 0.1.0
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative './entry'
4
+
5
+ class ActiveSet
6
+ class Instructions
7
+ attr_reader :hash
8
+
9
+ def initialize(hash)
10
+ @hash = hash
11
+ @flattened_hash = hash.flatten_keys
12
+ end
13
+
14
+ def process_adapter(set:, adapter:)
15
+ @flattened_hash.reject { |_, v| v.blank? }
16
+ .reduce(set) do |inner_set, (keypath, value)|
17
+ instruction = Entry.new(keypath, value)
18
+ adapter.new(instruction).process(inner_set)
19
+ end
20
+ end
21
+
22
+ def get(keypath)
23
+ @hash.dig(*keypath)
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'active_support/core_ext/module/delegation'
4
+
5
+ require_relative 'entry/keypath'
6
+ require_relative 'entry/value'
7
+
8
+ class ActiveSet
9
+ class Instructions
10
+ class Entry
11
+ attr_reader :keypath
12
+
13
+ delegate :attribute, :operator, :associations_array, :associations_hash, :value_for, :resource_for,
14
+ to: :keypath
15
+
16
+ def initialize(keypath, value)
17
+ @keypath = KeyPath.new(keypath)
18
+ @value = Value.new(value)
19
+ end
20
+
21
+ def value
22
+ @value.raw
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,58 @@
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 ActiveSet
7
+ class Instructions
8
+ class Entry
9
+ class KeyPath
10
+ attr_reader :path
11
+
12
+ def initialize(path)
13
+ # `path` can be an Array (e.g. [:parent, :child, :grandchild])
14
+ # or a String (e.g. 'parent.child.grandchild')
15
+ @path = path.is_a?(String) ? path.split('.') : Array.wrap(path).map(&:to_s)
16
+ end
17
+
18
+ def attribute
19
+ attribute = @path.last
20
+ return attribute.sub(operator_regex, '') if attribute.match operator_regex
21
+ attribute
22
+ end
23
+
24
+ def operator
25
+ attribute = @path.last
26
+ return attribute[operator_regex, 1] if attribute.match operator_regex
27
+ '=='
28
+ end
29
+
30
+ def associations_array
31
+ @path.slice(0, @path.length - 1)
32
+ end
33
+
34
+ def associations_hash
35
+ associations_array.reverse.reduce({}) { |a, e| { e => a } }
36
+ end
37
+
38
+ def value_for(item:)
39
+ resource_for(item: item).send(attribute)
40
+ rescue
41
+ nil
42
+ end
43
+
44
+ def resource_for(item:)
45
+ associations_array.reduce(item, :try)
46
+ rescue
47
+ nil
48
+ end
49
+
50
+ private
51
+
52
+ def operator_regex
53
+ /\((.*?)\)/
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ class ActiveSet
4
+ class Instructions
5
+ class Entry
6
+ class Value
7
+ attr_reader :raw
8
+
9
+ def initialize(value)
10
+ @raw = value
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -1,10 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative '../structure/path'
4
-
5
- class BaseAdapter
6
- def initialize(keypath, value)
7
- @structure_path = Structure::Path.new(keypath)
8
- @value = value
3
+ class ActiveSet
4
+ class BaseAdapter
5
+ def initialize(instruction)
6
+ @instruction = instruction
7
+ end
9
8
  end
10
9
  end
@@ -1,19 +1,22 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'patches/core_ext/hash/flatten_keys'
4
+ require_relative '../instructions/base'
4
5
 
5
- class BaseProcessor
6
- def self.queue_adapter(adapter)
7
- @adapters ||= []
8
- @adapters |= [adapter]
9
- end
6
+ class ActiveSet
7
+ class BaseProcessor
8
+ def self.queue_adapter(adapter)
9
+ @adapters ||= []
10
+ @adapters |= [adapter]
11
+ end
10
12
 
11
- def initialize(set, structure)
12
- @set = set
13
- @structure = structure.flatten_keys
14
- end
13
+ def initialize(set, instructions)
14
+ @set = set
15
+ @instructions = Instructions.new(instructions)
16
+ end
15
17
 
16
- def adapters
17
- self.class.instance_variable_get(:@adapters)
18
+ def adapters
19
+ self.class.instance_variable_get(:@adapters)
20
+ end
18
21
  end
19
22
  end
@@ -19,34 +19,34 @@ class ActiveSet
19
19
  def attribute_is_field?
20
20
  return false unless attribute_model
21
21
  attribute_model.attribute_names
22
- .include?(@structure_path.attribute)
22
+ .include?(@instruction.attribute)
23
23
  end
24
24
 
25
25
  def query
26
- @set.includes(@structure_path.to_h)
27
- .references(@structure_path.to_h)
26
+ @set.includes(@instruction.associations_hash)
27
+ .references(@instruction.associations_hash)
28
28
  .where(arel_operation)
29
29
  end
30
30
 
31
31
  def arel_operation
32
- Arel::Nodes::InfixOperation.new(@structure_path.operator,
32
+ Arel::Nodes::InfixOperation.new(@instruction.operator,
33
33
  arel_column,
34
34
  arel_value)
35
35
  end
36
36
 
37
37
  def attribute_model
38
- @structure_path.to_a
39
- .reduce(@set) do |obj, assoc|
40
- obj.reflections[assoc.to_s]&.klass
41
- end
38
+ @instruction.associations_array
39
+ .reduce(@set) do |obj, assoc|
40
+ obj.reflections[assoc.to_s]&.klass
41
+ end
42
42
  end
43
43
 
44
44
  def arel_column
45
- arel_table[@structure_path.attribute]
45
+ arel_table[@instruction.attribute]
46
46
  end
47
47
 
48
48
  def arel_value
49
- Arel.sql(ActiveRecord::Base.connection.quote(@value))
49
+ Arel.sql(ActiveRecord::Base.connection.quote(@instruction.value))
50
50
  end
51
51
 
52
52
  def arel_table
@@ -7,7 +7,7 @@ class ActiveSet
7
7
  class EnumerableAdapter < BaseAdapter
8
8
  def process(set)
9
9
  set.select do |item|
10
- value_for(item).send(@structure_path.operator,
10
+ value_for(item).send(@instruction.operator,
11
11
  passed_value)
12
12
  end
13
13
  end
@@ -15,11 +15,11 @@ class ActiveSet
15
15
  private
16
16
 
17
17
  def value_for(item)
18
- convert_datetime_values_to_integer(@structure_path.value_for(item: item))
18
+ convert_datetime_values_to_integer(@instruction.value_for(item: item))
19
19
  end
20
20
 
21
21
  def passed_value
22
- convert_datetime_values_to_integer(@value)
22
+ convert_datetime_values_to_integer(@instruction.value)
23
23
  end
24
24
 
25
25
  def convert_datetime_values_to_integer(value)
@@ -13,10 +13,7 @@ class ActiveSet
13
13
 
14
14
  def process
15
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
16
+ @instructions.process_adapter(set: outer_set, adapter: adapter)
20
17
  end
21
18
  end
22
19
  end
@@ -13,11 +13,11 @@ class ActiveSet
13
13
  private
14
14
 
15
15
  def pagesize
16
- @value
16
+ @instruction.value
17
17
  end
18
18
 
19
19
  def page_number
20
- @structure_path.attribute.to_i
20
+ @instruction.attribute.to_i
21
21
  end
22
22
  end
23
23
  end
@@ -7,7 +7,7 @@ class ActiveSet
7
7
  class PaginateProcessor < BaseProcessor
8
8
  def process
9
9
  return @set if @set.count < pagesize
10
- adapter.new(page_number, pagesize).process(@set)
10
+ adapter.new(instruction).process(@set)
11
11
  end
12
12
 
13
13
  private
@@ -16,12 +16,16 @@ class ActiveSet
16
16
  EnumerableAdapter
17
17
  end
18
18
 
19
+ def instruction
20
+ Instructions::Entry.new(page_number, pagesize)
21
+ end
22
+
19
23
  def page_number
20
- @structure[[:page]] || 1
24
+ @instructions.get(:page) || 1
21
25
  end
22
26
 
23
27
  def pagesize
24
- @structure[[:size]] || 25
28
+ @instructions.get(:size) || 25
25
29
  end
26
30
  end
27
31
  end
@@ -11,8 +11,8 @@ class ActiveSet
11
11
  return @set unless @set.respond_to? :to_sql
12
12
  return @set unless attribute_is_field?
13
13
 
14
- @set.includes(@structure_path.to_h)
15
- .references(@structure_path.to_h)
14
+ @set.includes(@instruction.associations_hash)
15
+ .references(@instruction.associations_hash)
16
16
  .merge(arel_operation)
17
17
  end
18
18
 
@@ -21,32 +21,32 @@ class ActiveSet
21
21
  def attribute_is_field?
22
22
  return false unless attribute_model
23
23
  attribute_model.attribute_names
24
- .include?(@structure_path.attribute)
25
- end
26
-
27
- def case_insensitive?
28
- @structure_path.operator.to_s == 'i'
24
+ .include?(@instruction.attribute)
29
25
  end
30
26
 
31
27
  def arel_operation
32
28
  column = case_insensitive? ? arel_column.lower : arel_column
33
- attribute_model.order(column.send(@value))
29
+ attribute_model.order(column.send(@instruction.value))
34
30
  end
35
31
 
36
32
  def attribute_model
37
- @structure_path.to_a
38
- .reduce(@set) do |obj, assoc|
39
- obj.reflections[assoc.to_s]&.klass
40
- end
33
+ @instruction.associations_array
34
+ .reduce(@set) do |obj, assoc|
35
+ obj.reflections[assoc.to_s]&.klass
36
+ end
41
37
  end
42
38
 
43
39
  def arel_column
44
- arel_table[@structure_path.attribute]
40
+ arel_table[@instruction.attribute]
45
41
  end
46
42
 
47
43
  def arel_table
48
44
  Arel::Table.new(attribute_model.table_name)
49
45
  end
46
+
47
+ def case_insensitive?
48
+ @instruction.operator.to_s == 'i'
49
+ end
50
50
  end
51
51
  end
52
52
  end
@@ -8,9 +8,9 @@ class ActiveSet
8
8
  class EnumerableAdapter < BaseAdapter
9
9
  def process(set)
10
10
  set.sort_by do |item|
11
- attribute_value = @structure_path.value_for(item: item)
11
+ attribute_value = @instruction.value_for(item: item)
12
12
  case_insensitive?(attribute_value) ? insensify(attribute_value) : attribute_value
13
- end.tap { |c| c.reverse! if @value.to_s == 'desc' }
13
+ end.tap { |c| c.reverse! if @instruction.value.to_s == 'desc' }
14
14
  end
15
15
 
16
16
  private
@@ -19,7 +19,7 @@ class ActiveSet
19
19
  # Cannot sort pure Booleans or Nils, so we _must_ cast to Strings
20
20
  return true if value.is_a?(TrueClass) || value.is_a?(FalseClass)
21
21
  return true if value.is_a?(NilClass)
22
- @structure_path.operator.to_s == 'i'
22
+ @instruction.operator.to_s == 'i'
23
23
  end
24
24
 
25
25
  def insensify(value)
@@ -13,10 +13,7 @@ class ActiveSet
13
13
 
14
14
  def process
15
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
16
+ @instructions.process_adapter(set: outer_set, adapter: adapter)
20
17
  end
21
18
  end
22
19
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class ActiveSet
4
- VERSION = '0.3.0'
4
+ VERSION = '0.3.1'
5
5
  end
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'active_support/core_ext/array/wrap'
4
+
3
5
  class Hash
4
6
  # Returns a flat hash where all nested keys are collapsed into a an array of keys.
5
7
  #
@@ -24,7 +26,7 @@ class Hash
24
26
 
25
27
  def _flatten_keys(h, keys = [], res = {})
26
28
  return res.merge!(keys => h) unless h.is_a? Hash
27
- h.each { |k, r| _flatten_keys(r, keys + [k], res) }
29
+ h.each { |k, r| _flatten_keys(r, keys + Array.wrap(k), res) }
28
30
  res
29
31
  end
30
32
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: activeset
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.3.1
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-15 00:00:00.000000000 Z
11
+ date: 2017-09-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -171,6 +171,10 @@ files:
171
171
  - bin/setup
172
172
  - config.ru
173
173
  - lib/active_set.rb
174
+ - lib/active_set/instructions/base.rb
175
+ - lib/active_set/instructions/entry.rb
176
+ - lib/active_set/instructions/entry/keypath.rb
177
+ - lib/active_set/instructions/entry/value.rb
174
178
  - lib/active_set/processors/base_adapter.rb
175
179
  - lib/active_set/processors/base_processor.rb
176
180
  - lib/active_set/processors/filter/active_record_adapter.rb
@@ -181,7 +185,6 @@ files:
181
185
  - lib/active_set/processors/sort/active_record_adapter.rb
182
186
  - lib/active_set/processors/sort/enumerable_adapter.rb
183
187
  - lib/active_set/processors/sort_processor.rb
184
- - lib/active_set/structure/path.rb
185
188
  - lib/active_set/version.rb
186
189
  - lib/patches/core_ext/hash/flatten_keys.rb
187
190
  homepage: https://github.com/fractaledmind/activeset
@@ -1,54 +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
- 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