actionset 0.8.1 → 0.8.2

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: 2d8befffeaabf8526df7cdd15f501f2e9e99732b
4
- data.tar.gz: 9dc431b8b1af60ed1d6d57d8ba9e66ac6e6a0688
3
+ metadata.gz: dffd9096dbb67844e4cee728dee2dbea434a32e2
4
+ data.tar.gz: a6bcb0b49df525a8d3e6e74f06a067310674fd87
5
5
  SHA512:
6
- metadata.gz: 076e19f851950c2a0c2ac377c51a04eaf16198060ce8a1e6a766339f659c61eab1ae125c34005db809b27b0b0c02aad85e9ad1502f13c11ad04a821be6d40d0d
7
- data.tar.gz: c2de49f8fb3a36ecf86dfc00c51a880b675ea8f7db129de84a0eace0565c9175528cd53fcf25096ff04151c727189ce09c53ac54b50221df20784e8ba8e52270
6
+ metadata.gz: f7400ae1649bde246c247752feabb37adc3c290ce464aee8271980c265965be920ac2cdae6c06b009fbbc59df371ec7e1aad075f4035a2e624ead3f6254e0011
7
+ data.tar.gz: ca373cfc982b4455ec40c5df823c94ccc4a16e0c2fc1fafeb2eb3cc9ea65b8be664df7135d6ef52c9e1b5cca12e959ae23eda6815809cb62e93baae0acec5d96
@@ -1,5 +1,8 @@
1
1
  AllCops:
2
2
  TargetRubyVersion: 2.4
3
+ Exclude:
4
+ - 'actionset.gemspec'
5
+ - 'spec/**/*'
3
6
  Metrics/LineLength:
4
7
  Max: 120
5
8
  # To make it possible to copy or click on URIs in the code, we allow lines
@@ -10,13 +13,10 @@ Metrics/LineLength:
10
13
  - https
11
14
  Style/Documentation:
12
15
  Enabled: false
16
+ Metrics/MethodLength:
17
+ Enabled: false
13
18
  Style/SignalException:
14
19
  EnforcedStyle: semantic
15
- Metrics/BlockLength:
16
- Exclude:
17
- - 'activeset.gemspec'
18
- - 'spec/**/*_spec.rb'
19
- - '**/schema.rb'
20
20
  Naming/VariableNumber:
21
21
  EnforcedStyle: snake_case
22
22
  Style/DateTime:
data/CHANGELOG CHANGED
@@ -1,3 +1,5 @@
1
+ v 0.8.2
2
+ - add `ActiveSet.configuration.on_asc_sort_nils_come` configuration
1
3
  v 0.8.1
2
4
  - add a case-insensitive filtering/sorting option (`/i/`)
3
5
  - standardize how filtering by class scopes behaves
@@ -1,57 +1,57 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- actionset (0.8.1)
4
+ actionset (0.8.2)
5
5
  activesupport (>= 4.0.2)
6
6
  railties
7
7
 
8
8
  GEM
9
9
  remote: https://rubygems.org/
10
10
  specs:
11
- actioncable (5.1.6.1)
12
- actionpack (= 5.1.6.1)
11
+ actioncable (5.1.7)
12
+ actionpack (= 5.1.7)
13
13
  nio4r (~> 2.0)
14
14
  websocket-driver (~> 0.6.1)
15
- actionmailer (5.1.6.1)
16
- actionpack (= 5.1.6.1)
17
- actionview (= 5.1.6.1)
18
- activejob (= 5.1.6.1)
15
+ actionmailer (5.1.7)
16
+ actionpack (= 5.1.7)
17
+ actionview (= 5.1.7)
18
+ activejob (= 5.1.7)
19
19
  mail (~> 2.5, >= 2.5.4)
20
20
  rails-dom-testing (~> 2.0)
21
- actionpack (5.1.6.1)
22
- actionview (= 5.1.6.1)
23
- activesupport (= 5.1.6.1)
21
+ actionpack (5.1.7)
22
+ actionview (= 5.1.7)
23
+ activesupport (= 5.1.7)
24
24
  rack (~> 2.0)
25
25
  rack-test (>= 0.6.3)
26
26
  rails-dom-testing (~> 2.0)
27
27
  rails-html-sanitizer (~> 1.0, >= 1.0.2)
28
- actionview (5.1.6.1)
29
- activesupport (= 5.1.6.1)
28
+ actionview (5.1.7)
29
+ activesupport (= 5.1.7)
30
30
  builder (~> 3.1)
31
31
  erubi (~> 1.4)
32
32
  rails-dom-testing (~> 2.0)
33
33
  rails-html-sanitizer (~> 1.0, >= 1.0.3)
34
- activejob (5.1.6.1)
35
- activesupport (= 5.1.6.1)
34
+ activejob (5.1.7)
35
+ activesupport (= 5.1.7)
36
36
  globalid (>= 0.3.6)
37
- activemodel (5.1.6.1)
38
- activesupport (= 5.1.6.1)
39
- activerecord (5.1.6.1)
40
- activemodel (= 5.1.6.1)
41
- activesupport (= 5.1.6.1)
37
+ activemodel (5.1.7)
38
+ activesupport (= 5.1.7)
39
+ activerecord (5.1.7)
40
+ activemodel (= 5.1.7)
41
+ activesupport (= 5.1.7)
42
42
  arel (~> 8.0)
43
- activesupport (5.1.6.1)
43
+ activesupport (5.1.7)
44
44
  concurrent-ruby (~> 1.0, >= 1.0.2)
45
45
  i18n (>= 0.7, < 2)
46
46
  minitest (~> 5.1)
47
47
  tzinfo (~> 1.1)
48
- addressable (2.5.2)
48
+ addressable (2.6.0)
49
49
  public_suffix (>= 2.0.2, < 4.0)
50
50
  ansi (1.5.0)
51
51
  arel (8.0.0)
52
52
  ast (2.4.0)
53
53
  builder (3.2.3)
54
- capybara (3.12.0)
54
+ capybara (3.19.0)
55
55
  addressable
56
56
  mini_mime (>= 0.1.3)
57
57
  nokogiri (~> 1.8)
@@ -63,27 +63,27 @@ GEM
63
63
  json
64
64
  simplecov
65
65
  url
66
- combustion (0.7.0)
66
+ combustion (1.1.0)
67
67
  activesupport (>= 3.0.0)
68
68
  railties (>= 3.0.0)
69
69
  thor (>= 0.14.6)
70
- concurrent-ruby (1.1.4)
70
+ concurrent-ruby (1.1.5)
71
71
  crass (1.0.4)
72
- database_cleaner (1.6.2)
72
+ database_cleaner (1.7.0)
73
73
  diff-lcs (1.3)
74
- docile (1.1.5)
75
- erubi (1.7.1)
76
- factory_bot (4.8.2)
77
- activesupport (>= 3.0.0)
78
- faker (1.8.7)
74
+ docile (1.3.1)
75
+ erubi (1.8.0)
76
+ factory_bot (5.0.2)
77
+ activesupport (>= 4.2.0)
78
+ faker (1.9.3)
79
79
  i18n (>= 0.7)
80
- globalid (0.4.1)
80
+ globalid (0.4.2)
81
81
  activesupport (>= 4.2.0)
82
82
  hirb (0.7.3)
83
- i18n (1.2.0)
83
+ i18n (1.6.0)
84
84
  concurrent-ruby (~> 1.0)
85
- jaro_winkler (1.5.1)
86
- json (2.1.0)
85
+ jaro_winkler (1.5.2)
86
+ json (2.2.0)
87
87
  loofah (2.2.3)
88
88
  crass (~> 1.0.2)
89
89
  nokogiri (>= 1.5.9)
@@ -94,60 +94,59 @@ GEM
94
94
  mini_portile2 (2.4.0)
95
95
  minitest (5.11.3)
96
96
  nio4r (2.3.1)
97
- nokogiri (1.9.0)
97
+ nokogiri (1.10.3)
98
98
  mini_portile2 (~> 2.4.0)
99
- parallel (1.12.1)
100
- parser (2.5.3.0)
99
+ parallel (1.17.0)
100
+ parser (2.6.3.0)
101
101
  ast (~> 2.4.0)
102
- powerpack (0.1.2)
103
102
  public_suffix (3.0.3)
104
- rack (2.0.6)
103
+ rack (2.0.7)
105
104
  rack-test (1.1.0)
106
105
  rack (>= 1.0, < 3)
107
- rails (5.1.6.1)
108
- actioncable (= 5.1.6.1)
109
- actionmailer (= 5.1.6.1)
110
- actionpack (= 5.1.6.1)
111
- actionview (= 5.1.6.1)
112
- activejob (= 5.1.6.1)
113
- activemodel (= 5.1.6.1)
114
- activerecord (= 5.1.6.1)
115
- activesupport (= 5.1.6.1)
106
+ rails (5.1.7)
107
+ actioncable (= 5.1.7)
108
+ actionmailer (= 5.1.7)
109
+ actionpack (= 5.1.7)
110
+ actionview (= 5.1.7)
111
+ activejob (= 5.1.7)
112
+ activemodel (= 5.1.7)
113
+ activerecord (= 5.1.7)
114
+ activesupport (= 5.1.7)
116
115
  bundler (>= 1.3.0)
117
- railties (= 5.1.6.1)
116
+ railties (= 5.1.7)
118
117
  sprockets-rails (>= 2.0.0)
119
118
  rails-dom-testing (2.0.3)
120
119
  activesupport (>= 4.2.0)
121
120
  nokogiri (>= 1.6)
122
121
  rails-html-sanitizer (1.0.4)
123
122
  loofah (~> 2.2, >= 2.2.2)
124
- railties (5.1.6.1)
125
- actionpack (= 5.1.6.1)
126
- activesupport (= 5.1.6.1)
123
+ railties (5.1.7)
124
+ actionpack (= 5.1.7)
125
+ activesupport (= 5.1.7)
127
126
  method_source
128
127
  rake (>= 0.8.7)
129
128
  thor (>= 0.18.1, < 2.0)
130
129
  rainbow (3.0.0)
131
- rake (10.5.0)
130
+ rake (12.3.2)
132
131
  ransack (2.1.1)
133
132
  actionpack (>= 5.0)
134
133
  activerecord (>= 5.0)
135
134
  activesupport (>= 5.0)
136
135
  i18n
137
- regexp_parser (1.3.0)
136
+ regexp_parser (1.4.0)
138
137
  rspec (3.8.0)
139
138
  rspec-core (~> 3.8.0)
140
139
  rspec-expectations (~> 3.8.0)
141
140
  rspec-mocks (~> 3.8.0)
142
141
  rspec-core (3.8.0)
143
142
  rspec-support (~> 3.8.0)
144
- rspec-expectations (3.8.2)
143
+ rspec-expectations (3.8.3)
145
144
  diff-lcs (>= 1.2.0, < 2.0)
146
145
  rspec-support (~> 3.8.0)
147
146
  rspec-mocks (3.8.0)
148
147
  diff-lcs (>= 1.2.0, < 2.0)
149
148
  rspec-support (~> 3.8.0)
150
- rspec-rails (3.8.1)
149
+ rspec-rails (3.8.2)
151
150
  actionpack (>= 3.0)
152
151
  activesupport (>= 3.0)
153
152
  railties (>= 3.0)
@@ -156,17 +155,16 @@ GEM
156
155
  rspec-mocks (~> 3.8.0)
157
156
  rspec-support (~> 3.8.0)
158
157
  rspec-support (3.8.0)
159
- rubocop (0.61.1)
158
+ rubocop (0.68.1)
160
159
  jaro_winkler (~> 1.5.1)
161
160
  parallel (~> 1.10)
162
161
  parser (>= 2.5, != 2.5.1.1)
163
- powerpack (~> 0.1)
164
162
  rainbow (>= 2.2.2, < 4.0)
165
163
  ruby-progressbar (~> 1.7)
166
- unicode-display_width (~> 1.4.0)
164
+ unicode-display_width (>= 1.4.0, < 1.6)
167
165
  ruby-progressbar (1.10.0)
168
- simplecov (0.15.1)
169
- docile (~> 1.1.0)
166
+ simplecov (0.16.1)
167
+ docile (~> 1.1)
170
168
  json (>= 1.8, < 3)
171
169
  simplecov-html (~> 0.10.0)
172
170
  simplecov-console (0.4.2)
@@ -181,12 +179,12 @@ GEM
181
179
  actionpack (>= 4.0)
182
180
  activesupport (>= 4.0)
183
181
  sprockets (>= 3.0.0)
184
- sqlite3 (1.3.13)
182
+ sqlite3 (1.4.1)
185
183
  thor (0.20.3)
186
184
  thread_safe (0.3.6)
187
185
  tzinfo (1.2.5)
188
186
  thread_safe (~> 0.1)
189
- unicode-display_width (1.4.0)
187
+ unicode-display_width (1.5.0)
190
188
  url (0.3.2)
191
189
  websocket-driver (0.6.5)
192
190
  websocket-extensions (>= 0.1.0)
data/README.md CHANGED
@@ -108,6 +108,32 @@ For pagination, like filtering, we don't enforce any view-layer specifics. You s
108
108
  </nav>
109
109
  ```
110
110
 
111
+ ## Configuration
112
+
113
+ ### ActiveSet.configuration.on_asc_sort_nils_come
114
+
115
+ Example usage in an initializer:
116
+
117
+ ```
118
+ ActiveSet.configure do |c|
119
+ c.on_asc_sort_nils_come = :first
120
+ end
121
+ ```
122
+
123
+ When `ActiveSet.configuration.on_asc_sort_nils_come == :last` (this is the default), null values will be sorted as if larger than any non-null value.
124
+
125
+ ```
126
+ ASC => [-2, -1, 1, 2, nil]
127
+ DESC => [nil, 2, 1, -1, -2]
128
+ ```
129
+
130
+ Otherwise sort nulls as if smaller than any non-null value.
131
+
132
+ ```
133
+ ASC => [nil, -2, -1, 1, 2]
134
+ DESC => [2, 1, -1, -2, nil]
135
+ ```
136
+
111
137
  ## Development
112
138
 
113
139
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
@@ -6,7 +6,7 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
6
6
  Gem::Specification.new do |spec|
7
7
  spec.platform = Gem::Platform::RUBY
8
8
  spec.name = 'actionset'
9
- spec.version = '0.8.1'
9
+ spec.version = '0.8.2'
10
10
  spec.authors = ['Stephen Margheim']
11
11
  spec.email = ['stephen.margheim@gmail.com']
12
12
 
@@ -53,7 +53,7 @@ module ActionSet
53
53
  private
54
54
 
55
55
  def filter_instructions_for(set)
56
- filter_params.flatten_keys.reject { |_, v| v.try(:empty?) }.each_with_object({}) do |(keypath, value), memo|
56
+ flatten_keys_of(filter_params).reject { |_, v| v.try(:empty?) }.each_with_object({}) do |(keypath, value), memo|
57
57
  typecast_value = if value.respond_to?(:each)
58
58
  value.map { |v| filter_typecasted_value_for(keypath, v, set) }
59
59
  else
@@ -1,8 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'active_support/core_ext/hash/reverse_merge'
4
- require 'patches/core_ext/hash/flatten_keys'
5
- require 'helpers/throws'
4
+ require 'helpers/flatten_keys_of'
6
5
  require 'active_set/attribute_instruction'
7
6
  require 'active_set/filtering/operation'
8
7
  require 'active_set/sorting/operation'
@@ -12,6 +11,30 @@ require 'active_set/exporting/operation'
12
11
  class ActiveSet
13
12
  include Enumerable
14
13
 
14
+ class Configuration
15
+ attr_accessor :on_asc_sort_nils_come
16
+
17
+ def initialize
18
+ @on_asc_sort_nils_come = :last
19
+ end
20
+ end
21
+
22
+ class << self
23
+ attr_writer :configuration
24
+ end
25
+
26
+ def self.configuration
27
+ @configuration ||= Configuration.new
28
+ end
29
+
30
+ def self.configure
31
+ yield(configuration)
32
+ end
33
+
34
+ def self.reset_configuration
35
+ @configuration = Configuration.new
36
+ end
37
+
15
38
  attr_reader :set, :view, :instructions
16
39
 
17
40
  def initialize(set, view: nil, instructions: {})
@@ -31,23 +31,27 @@ class ActiveSet
31
31
  end
32
32
  end
33
33
 
34
+ # rubocop:disable Lint/UnderscorePrefixedVariableName
34
35
  def arel_column
35
36
  _arel_column = arel_table[@attribute_instruction.attribute]
36
37
  return _arel_column.lower if case_insensitive_operation?
37
38
 
38
39
  _arel_column
39
40
  end
41
+ # rubocop:enable Lint/UnderscorePrefixedVariableName
40
42
 
41
43
  def arel_operator
42
44
  @attribute_instruction.operator(default: :eq)
43
45
  end
44
46
 
47
+ # rubocop:disable Lint/UnderscorePrefixedVariableName
45
48
  def arel_value
46
49
  _arel_value = @attribute_instruction.value
47
50
  return _arel_value.downcase if case_insensitive_operation?
48
51
 
49
52
  _arel_value
50
53
  end
54
+ # rubocop:enable Lint/UnderscorePrefixedVariableName
51
55
 
52
56
  def case_insensitive_operation?
53
57
  @attribute_instruction.case_insensitive? && arel_type.presence_in(%i[string text])
@@ -92,7 +92,7 @@ class ActiveSet
92
92
  private
93
93
 
94
94
  def operator_regex
95
- %r{\((.*?)\)}
95
+ /\((.*?)\)/
96
96
  end
97
97
 
98
98
  def options_regex
@@ -10,16 +10,18 @@ class ActiveSet
10
10
 
11
11
  def attribute_value_for(item)
12
12
  item_value = @attribute_instruction
13
- .value_for(item: item)
13
+ .value_for(item: item)
14
14
  item_value = item_value.downcase if case_insensitive_operation_for?(item_value)
15
15
  item_value
16
16
  end
17
17
 
18
+ # rubocop:disable Lint/UnderscorePrefixedVariableName
18
19
  def attribute_value
19
20
  _attribute_value = @attribute_instruction.value
20
21
  _attribute_value = _attribute_value.downcase if case_insensitive_operation_for?(_attribute_value)
21
22
  _attribute_value
22
23
  end
24
+ # rubocop:enable Lint/UnderscorePrefixedVariableName
23
25
 
24
26
  def case_insensitive_operation_for?(value)
25
27
  return false unless @attribute_instruction.case_insensitive?
@@ -12,10 +12,8 @@ class ActiveSet
12
12
  @instructions_hash = instructions_hash
13
13
  end
14
14
 
15
- # rubocop:disable Metrics/MethodLength
16
15
  def execute
17
- attribute_instructions = @instructions_hash
18
- .flatten_keys
16
+ attribute_instructions = flatten_keys_of(@instructions_hash)
19
17
  .map { |k, v| AttributeInstruction.new(k, v) }
20
18
 
21
19
  activerecord_filtered_set = attribute_instructions.reduce(@set) do |set, attribute_instruction|
@@ -36,7 +34,6 @@ class ActiveSet
36
34
  maybe_set_or_false
37
35
  end
38
36
  end
39
- # rubocop:enable Metrics/MethodLength
40
37
 
41
38
  def operation_instructions
42
39
  @instructions_hash.symbolize_keys
@@ -41,17 +41,21 @@ class ActiveSet
41
41
  private
42
42
 
43
43
  # https://stackoverflow.com/a/44912964/2884386
44
- # Force null values to be sorted as if larger than any non-null value
44
+ # When ActiveSet.configuration.on_asc_sort_nils_come == :last
45
+ # null values to be sorted as if larger than any non-null value.
45
46
  # ASC => [-2, -1, 1, 2, nil]
46
47
  # DESC => [nil, 2, 1, -1, -2]
48
+ # Otherwise sort nulls as if smaller than any non-null value.
49
+ # ASC => [nil, -2, -1, 1, 2]
50
+ # DESC => [2, 1, -1, -2, nil]
47
51
  def order_operation_for(set_instruction)
48
52
  attribute_model = set_instruction.attribute_model
49
53
 
50
54
  arel_column = set_instruction.arel_column
51
55
  arel_direction = direction_operator(set_instruction.value)
52
- nil_sorter = arel_column.send(arel_direction == :asc ? :eq : :not_eq, nil)
53
56
 
54
- attribute_model.order(nil_sorter).order(arel_column.send(arel_direction))
57
+ attribute_model.order(nil_sorter_for(arel_column, arel_direction))
58
+ .order(arel_column.send(arel_direction))
55
59
  end
56
60
 
57
61
  def direction_operator(direction)
@@ -59,6 +63,16 @@ class ActiveSet
59
63
 
60
64
  :asc
61
65
  end
66
+
67
+ def nil_sorter_for(column, direction)
68
+ nil_sorter_operator = if ActiveSet.configuration.on_asc_sort_nils_come == :last
69
+ direction == :asc ? :eq : :not_eq
70
+ else
71
+ direction == :asc ? :not_eq : :eq
72
+ end
73
+
74
+ column.send(nil_sorter_operator, nil)
75
+ end
62
76
  end
63
77
  end
64
78
  end
@@ -21,11 +21,15 @@ class ActiveSet
21
21
  value_for_comparison = sortable_numeric_for(set_instruction, item)
22
22
  direction_multiplier = direction_multiplier(set_instruction.value)
23
23
 
24
- # Force null values to be sorted as if larger than any non-null value
24
+ # When ActiveSet.configuration.on_asc_sort_nils_come == :last
25
+ # null values to be sorted as if larger than any non-null value.
25
26
  # ASC => [-2, -1, 1, 2, nil]
26
27
  # DESC => [nil, 2, 1, -1, -2]
28
+ # Otherwise sort nulls as if smaller than any non-null value.
29
+ # ASC => [nil, -2, -1, 1, 2]
30
+ # DESC => [2, 1, -1, -2, nil]
27
31
  if value_for_comparison.nil?
28
- [direction_multiplier, 0]
32
+ [direction_multiplier * nil_sorter, 0]
29
33
  else
30
34
  [0, value_for_comparison * direction_multiplier]
31
35
  end
@@ -44,6 +48,12 @@ class ActiveSet
44
48
 
45
49
  1
46
50
  end
51
+
52
+ def nil_sorter
53
+ return 1 if ActiveSet.configuration.on_asc_sort_nils_come == :last
54
+
55
+ -1
56
+ end
47
57
  end
48
58
  end
49
59
  end
@@ -13,8 +13,7 @@ class ActiveSet
13
13
  end
14
14
 
15
15
  def execute
16
- attribute_instructions = @instructions_hash
17
- .flatten_keys
16
+ attribute_instructions = flatten_keys_of(@instructions_hash)
18
17
  .map { |k, v| AttributeInstruction.new(k, v) }
19
18
 
20
19
  activerecord_strategy = ActiveRecordStrategy.new(@set, attribute_instructions)
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'active_support/core_ext/array/wrap'
4
+
5
+ # Returns a flat hash where all nested keys are flattened into an array of keys.
6
+ #
7
+ # hash = { key: 'value', nested: { key: 'nested_value' }, array: [0, 1, 2] }
8
+ # flatten_keys_of(hash)
9
+ # => { [:key]=>"value", [:nested, :key]=>"nested_value", [:array]=>[0, 1, 2] }
10
+ #
11
+ # Can also pass a Proc to change how nested keys are flattened:
12
+ # flatten_keys_of(hash, flattener: ->(*keys) { keys.join('.') })
13
+ # => { "key"=>"value", "nested.key"=>"nested_value", "array"=>[0, 1, 2] }
14
+ # flatten_keys_of(hash, flattener: ->(*keys) { keys.join('-') })
15
+ # => { "key"=>"value", "nested-key"=>"nested_value", "array"=>[0, 1, 2] }
16
+ # flatten_keys_of(hash, flattener: ->(*keys) { keys.map(&:to_s).reduce { |memo, key| memo + "[#{key}]" } })
17
+ # => { "key"=>"value", "nested[key]"=>"nested_value", "array"=>[0, 1, 2] }
18
+ #
19
+ # Can also determine if array values should be flattened as well:
20
+ # hash = { person: { age: '28', siblings: ['Tom', 'Sally'] } }
21
+ # flatten_keys_of(hash, flatten_arrays: true)
22
+ # => { [:key]=>"value", [:nested, :key]=>"nested_value", [:array, 0]=>0, [:array, 1]=>1, [:array, 2]=>2 }
23
+ # flatten_keys_of(hash, flattener: ->(*keys) { keys.join('.') }, flatten_arrays: true)
24
+ # => { "key"=>"value", "nested.key"=>"nested_value", "array.0"=>0, "array.1"=>1, "array.2"=>2 }
25
+
26
+ # refactored from https://stackoverflow.com/a/23861946/2884386
27
+ def flatten_keys_of(input, keys = [], output = {}, flattener: ->(*keys) { keys }, flatten_arrays: false)
28
+ if input.is_a?(Hash)
29
+ input.each do |key, value|
30
+ flatten_keys_of(
31
+ value,
32
+ keys + Array.wrap(key),
33
+ output,
34
+ flattener: flattener,
35
+ flatten_arrays: flatten_arrays
36
+ )
37
+ end
38
+ elsif input.is_a?(Array) && flatten_arrays
39
+ input.each_with_index do |value, index|
40
+ flatten_keys_of(
41
+ value,
42
+ keys + Array.wrap(index),
43
+ output,
44
+ flattener: flattener,
45
+ flatten_arrays: flatten_arrays
46
+ )
47
+ end
48
+ else
49
+ return output.merge!(flattener.call(*keys) => input)
50
+ end
51
+
52
+ output
53
+ end
@@ -13,7 +13,7 @@
13
13
  # transform_to_sortable_numeric(Date.new(2000, 12, 25))
14
14
  # => 977720400000
15
15
 
16
- # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
16
+ # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
17
17
  def transform_to_sortable_numeric(value)
18
18
  # https://www.justinweiss.com/articles/4-simple-memoization-patterns-in-ruby-and-one-gem/#and-what-about-parameters
19
19
  @sortable_numeric ||= Hash.new do |h, key|
@@ -35,8 +35,7 @@ def transform_to_sortable_numeric(value)
35
35
  end
36
36
  @sortable_numeric[value]
37
37
  end
38
- # rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
39
- # rubocop:enable Style/AsciiComments
38
+ # rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
40
39
 
41
40
  def string_to_sortable_numeric(string)
42
41
  string # 'aB09ü'
@@ -46,6 +45,7 @@ def string_to_sortable_numeric(string)
46
45
  .reduce(&:concat) # "097.066048057252"
47
46
  .to_r # (24266512014313/250000000000)
48
47
  end
48
+ # rubocop:enable Style/AsciiComments
49
49
 
50
50
  def time_to_sortable_numeric(time)
51
51
  # https://stackoverflow.com/a/30604935/2884386
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: actionset
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.1
4
+ version: 0.8.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Stephen Margheim
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-05-11 00:00:00.000000000 Z
11
+ date: 2019-06-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -295,9 +295,8 @@ files:
295
295
  - lib/active_set/sorting/active_record_strategy.rb
296
296
  - lib/active_set/sorting/enumerable_strategy.rb
297
297
  - lib/active_set/sorting/operation.rb
298
- - lib/helpers/throws.rb
298
+ - lib/helpers/flatten_keys_of.rb
299
299
  - lib/helpers/transform_to_sortable_numeric.rb
300
- - lib/patches/core_ext/hash/flatten_keys.rb
301
300
  - pagination.png
302
301
  homepage: https://github.com/fractaledmind/actionset
303
302
  licenses:
@@ -1,19 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # Returns a Boolean for whether the block raises the Exception expected
4
- #
5
- # throws?(StandardError) { raise }
6
- # => true
7
- # throws?(NameError) { raise NameError }
8
- # => true
9
- # throws?(NoMethodError) { raise NameError }
10
- # => false
11
- # throws?(StandardError) { 'foo' }
12
- # => false
13
-
14
- def throws?(exception)
15
- yield
16
- false
17
- rescue StandardError => e
18
- e.is_a? exception
19
- end
@@ -1,58 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'active_support/core_ext/array/wrap'
4
-
5
- class Hash
6
- # Returns a flat hash where all nested keys are collapsed into an array of keys.
7
- #
8
- # hash = { person: { name: { first: 'Rob' }, age: '28' } }
9
- # hash.flatten_keys_to_array
10
- # => {[:person, :name, :first] => "Rob", [:person, :age]=>"28" }
11
- def flatten_keys_to_array
12
- _flatten_keys(self)
13
- end
14
- alias flatten_keys flatten_keys_to_array
15
-
16
- # Returns a flat hash where all nested keys are collapsed into a dot-separated string of keys.
17
- #
18
- # hash = { person: { name: { first: 'Rob' }, age: '28' } }
19
- # hash.flatten_keys_to_dotpath
20
- # => { 'person.name.first' => "Rob", 'person.age'=>"28" }
21
- def flatten_keys_to_dotpath
22
- _flatten_keys(self, ->(*keys) { keys.join('.') })
23
- end
24
-
25
- # Returns a flat hash where all nested keys are collapsed into a dast-separated string of keys.
26
- #
27
- # hash = { person: { name: { first: 'Rob' }, age: '28' } }
28
- # hash.flatten_keys_to_html_attribute
29
- # => { 'person-name-first' => "Rob", 'person-age'=>"28" }
30
- def flatten_keys_to_html_attribute
31
- _flatten_keys(self, ->(*keys) { keys.join('-') })
32
- end
33
-
34
- # Returns a flat hash where all nested keys are collapsed into a string of keys
35
- # fitting the Rails request param pattern.
36
- #
37
- # hash = { person: { name: { first: 'Rob' }, age: '28' } }
38
- # hash.flatten_keys_to_rails_param
39
- # => { 'person[name][first]' => "Rob", 'person[age]'=>"28" }
40
- def flatten_keys_to_rails_param
41
- _flatten_keys(self, ->(*keys) { keys.map(&:to_s).reduce { |memo, key| memo + "[#{key}]" } })
42
- end
43
-
44
- private
45
-
46
- # refactored from https://stackoverflow.com/a/23861946/2884386
47
- def _flatten_keys(input, keypath_gen = ->(*keys) { keys }, keys = [], output = {})
48
- if input.is_a? Hash
49
- input.each { |k, v| _flatten_keys(v, keypath_gen, keys + Array(k), output) }
50
- # elsif input.is_a? Array
51
- # input.each_with_index { |v, i| _flatten_keys(v, keypath_gen, keys + Array(i), output) }
52
- else
53
- return output.merge!(keypath_gen.call(*keys) => input)
54
- end
55
-
56
- output
57
- end
58
- end