tag_options 1.2.1 → 1.3.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c947925081a723a10b0cb16c68efa3895556df3f87246bb0b9795d8b942e01f3
4
- data.tar.gz: c8b215bf6c0a2f8ee726055350c78c07efbe9575f22defb6ab483a01df23eb5d
3
+ metadata.gz: 416b4a714b85d92ffe1d81481749e7e75f3ebb6a5ef2f9c40330a544dd3cd774
4
+ data.tar.gz: ef14412ef73a773aaec41c5f2cd7f9a715e7f3368b5d1338d4d85dfaf6af0d4c
5
5
  SHA512:
6
- metadata.gz: 8764d6f0ebd02bebdc40bf449a58a21b5eea8ac8746fabb5c45980403f121efde6f210011b396f788ca8d6ca8cb5c553c032cdffff71c53a4558af3f1406d07c
7
- data.tar.gz: 0caa39cf680e022b64609c224e359188e1025d9c52bddb2c80ae5e1d60e9a1cdadf3b45581e927119971d552b1c4014f8ed4e0a809be6c4199229bcea30849b5
6
+ metadata.gz: 664555bb319ec2add3dc7887b80b3e8e4ce84e288707c2a73eb003e72474549505bd401cebab4adc3eae78ed624a60ff28f9f50af9b431bae2322a5038a5b821
7
+ data.tar.gz: 0c5693a2ab6f3ad7ed39a1f4b29a0b0683394cfd6b1895f8d9a33379aa72c63d241f0285055296c7cd228a8741d482f5fee030cc5dd8751e07ad128119fb213c
data/CHANGELOG.md CHANGED
@@ -2,6 +2,20 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [1.3.1] - 2023-03-06
6
+
7
+ - Fixed a bug where keys with empty values were being populated when using
8
+ `at()` against a non-existant key and the values passed to `combine!`, `set!`,
9
+ or `default` resolved to no values or where `remove!` removed all values.
10
+
11
+ ## [1.3.0] - 2023-03-03
12
+
13
+ - Added `at().remove!` option for removing values.
14
+
15
+ **NOTE**: If you have implemented custom resolvers, you will need to modify them
16
+ in order to support `remove!`. For examples, see the [built-in
17
+ handlers](https://github.com/wamonroe/tag_options/tree/main/lib/tag_options/resolvers)
18
+ for more information.
5
19
 
6
20
  ## [1.2.1] - 2023-03-02
7
21
 
@@ -23,7 +37,8 @@
23
37
  ## [1.0.0] - 2022-06-14
24
38
 
25
39
  - Rewrote and simplified TagOptions::Hash and supporting classes.
26
- - BREAKING CHANGES, read documentation for updated usage before updating.
40
+
41
+ **BREAKING CHANGES**: Read documentation for updated usage before updating.
27
42
 
28
43
  ## [0.9.3] - 2021-11-11
29
44
 
data/README.md CHANGED
@@ -42,6 +42,7 @@ Would render:
42
42
  - [combine!](#combine)
43
43
  - [set!](#set)
44
44
  - [default!](#default)
45
+ - [remove!](#remove)
45
46
  - [Conditional Usage](#conditional-usage)
46
47
  - [Custom Property Resolvers](#custom-property-resolvers)
47
48
  - [Development](#development)
@@ -64,7 +65,7 @@ bundle install
64
65
 
65
66
  ## General Usage
66
67
 
67
- Initialize a `TagOptions::Hash` directly or by passing an existing `Hash`.
68
+ Instantiate a `TagOptions::Hash` directly or by passing an existing `Hash`.
68
69
 
69
70
  ```ruby
70
71
  TagOptions::Hash.new
@@ -75,6 +76,24 @@ TagOptions::Hash.new(hash)
75
76
  => {:class=>"flex"}
76
77
  ```
77
78
 
79
+ Similar to `Array()`, you can also instantiate a new `TagOptions::Hash` by
80
+ passing a has to `TagOptions::Hash()`.
81
+
82
+ ```ruby
83
+ hash = {class: "flex"}
84
+ TagOptions::Hash(hash)
85
+ => {:class=>"flex"}
86
+ ```
87
+
88
+ The values of the hash passed to `TagOptions::Hash.new` or `TagOptions::Hash()`
89
+ are automatically converted to strings.
90
+
91
+ ```ruby
92
+ hash = {disabled: true}
93
+ TagOptions::Hash.new(hash)
94
+ => {:disabled=>"true"}
95
+ ```
96
+
78
97
  `TagOptions::Hash` inherits from `ActiveSupport::HashWithIndifferentAccess`,
79
98
  implementing a hash where keys `:foo` and `"foo"` are considered to be the same.
80
99
  It differs from `ActiveSupport::HashWithIndifferentAccess`, however, by storing
@@ -149,11 +168,31 @@ options.at(:role).default!("alert")
149
168
  => {:class=>"flex", :role=>"alert"}
150
169
  ```
151
170
 
171
+ ### remove!
172
+
173
+ Remove HTML attributes from an existing `TagOptions::Hash` by chaining `at` and
174
+ `remove!`.
175
+
176
+ ```ruby
177
+ options = TagOptions::Hash.new(class: "flex ml-1 mr-1")
178
+ options.at(:class).remove!("mr-1")
179
+ => {:class=>"flex ml-1"}
180
+ ```
181
+
182
+ In addition to string values, you can also pass regular expression to `remove!`.
183
+
184
+ ```ruby
185
+ options = TagOptions::Hash.new(class: "flex ml-1 mr-2")
186
+ options.at(:class).remove!(/m.-\d/)
187
+ => {:class=>"flex"}
188
+ ```
189
+
152
190
  ## Conditional Usage
153
191
 
154
- Both the `combine!` and `set!` allow for values to be conditionally added to
155
- HTML attributes using an argument array. Where the values are added
156
- unconditionally and key/value pairs have their key added _IF_ the value is true.
192
+ The `combine!`, `set!`, `default!`, and `remove!` methods allow for values to be
193
+ conditionally resolved using an argument array. Where the values are passed
194
+ unconditionally and key/value pairs have their key passed _IF_ the value is
195
+ true.
157
196
 
158
197
  ```ruby
159
198
  # assuming `centered?` returns `true`
@@ -162,6 +201,27 @@ options.at(:class).combine!("mt-1", "mx-auto": centered?, "mx-2": !centered?)
162
201
  => {:class=>"flex mt-1 mx-auto"}
163
202
  ```
164
203
 
204
+ ```ruby
205
+ # assuming `centered?` returns `true`
206
+ options = TagOptions::Hash.new(class: "flex")
207
+ options.at(:class).set!("block", "mx-auto": centered?, "mx-2": !centered?)
208
+ => {:class=>"block mx-auto"}
209
+ ```
210
+
211
+ ```ruby
212
+ # assuming `centered?` returns `true`
213
+ options = TagOptions::Hash.new(role: "alert")
214
+ options.at(:class).default!("flex", "mx-auto": centered?, "mx-2": !centered?)
215
+ => {:role=>"alert", :class=>"flex mx-auto"}
216
+ ```
217
+
218
+ ```ruby
219
+ # assuming `centered?` returns `true`
220
+ options = TagOptions::Hash.new(class: "flex mx-auto mx-2")
221
+ options.at(:class).remove!("mt-1", "mx-auto": centered?, "mx-2": !centered?)
222
+ => {:class=>"flex mx-2"}
223
+ ```
224
+
165
225
  ## Custom Property Resolvers
166
226
 
167
227
  Chaining `at` to `combine!` or `set!` processes HTML properties similar to
@@ -1,5 +1,6 @@
1
1
  require "active_support/callbacks"
2
2
  require "active_support/core_ext/hash/indifferent_access"
3
+ require "active_support/core_ext/object/blank"
3
4
  require "tag_options/convert_key"
4
5
  require "tag_options/hash_at"
5
6
  require "tag_options/errors/not_hash_error"
@@ -14,8 +15,9 @@ module TagOptions
14
15
  def initialize(hash = {})
15
16
  run_callbacks :initialize do
16
17
  hash.each do |key, value|
17
- self[convert_key(key)] = value.is_a?(::Hash) ? self.class.new(value) : value
18
+ self[convert_key(key)] = value.is_a?(::Hash) ? self.class.new(value) : value.to_s
18
19
  end
20
+ remove_blank!
19
21
  end
20
22
  end
21
23
 
@@ -24,21 +26,50 @@ module TagOptions
24
26
  end
25
27
 
26
28
  def dig(*keys)
27
- keys = keys.map { |key| convert_key(key) }
28
- keys.size.zero? ? self : super(*keys)
29
+ return self if keys.size.zero?
30
+
31
+ dug_keys = []
32
+ data = self
33
+ keys.each_with_index do |key, index|
34
+ key = convert_key(key)
35
+ return nil unless data.key?(key)
36
+
37
+ data = data[key]
38
+ dug_keys << key
39
+ last_key = index == keys.size - 1
40
+ unless last_key || data.is_a?(self.class)
41
+ raise TagOptions::Errors::NotHashError.new(dug_keys, type: data.class)
42
+ end
43
+ end
44
+ data
29
45
  end
30
46
 
31
47
  def populate!(*keys)
32
48
  populated_keys = []
33
49
  data = self
34
50
  keys.each do |key|
35
- data[convert_key(key)] ||= self.class.new
36
- data = data[convert_key(key)]
51
+ key = convert_key(key)
52
+ data[key] ||= self.class.new
53
+ data = data[key]
54
+ populated_keys << key
37
55
  unless data.is_a?(self.class)
38
56
  raise TagOptions::Errors::NotHashError.new(populated_keys, type: data.class)
39
57
  end
40
58
  end
41
59
  self
42
60
  end
61
+
62
+ def remove_blank!(hash = self, parent_hash: nil)
63
+ hash.each do |key, value|
64
+ if value.blank?
65
+ hash.delete(key)
66
+ remove_blank!(parent_hash, parent_hash: nil) if parent_hash
67
+ elsif value.is_a?(Hash)
68
+ remove_blank!(value, parent_hash: hash)
69
+ remove_blank!(parent_hash, parent_hash: nil) if parent_hash
70
+ end
71
+ end
72
+ hash
73
+ end
43
74
  end
44
75
  end
@@ -13,30 +13,53 @@ module TagOptions
13
13
  end
14
14
 
15
15
  def combine!(*values, **conditions)
16
- @opt_hash.populate!(*@keys)
17
16
  current_value = @opt_hash.dig(*@keys, @value_key)
18
17
  set_value! @resolver.call(current_value, *values, **conditions)
19
18
  end
20
19
 
21
20
  def default!(*values, **conditions)
22
- @opt_hash.populate!(*@keys)
23
21
  set_default! @resolver.call(*values, **conditions)
24
22
  end
25
23
 
26
24
  def set!(*values, **conditions)
27
- @opt_hash.populate!(*@keys)
28
25
  set_value! @resolver.call(*values, **conditions)
29
26
  end
30
27
 
28
+ def remove!(*values, **conditions)
29
+ regex_values, values = values.flatten.partition { |v| v.is_a?(Regexp) }
30
+ remove_values!(*regex_values, *@resolver.values(*values, **conditions))
31
+ end
32
+
31
33
  private
32
34
 
35
+ def remove_values!(*values_to_remove)
36
+ values = @resolver.values(@opt_hash.dig(*@keys)&.[](@value_key))
37
+ values_to_remove.each do |value|
38
+ if value.is_a?(Regexp)
39
+ values.reject! { |current_value| value.match?(current_value) }
40
+ else
41
+ values.reject! { |current_value| value == current_value }
42
+ end
43
+ end
44
+ @opt_hash.populate!(*@keys)
45
+ @opt_hash.dig(*@keys)[@value_key] = @resolver.call(*values)
46
+ @opt_hash.remove_blank!
47
+ @opt_hash
48
+ end
49
+
33
50
  def set_default!(value)
51
+ return @opt_hash if value.blank?
52
+
53
+ @opt_hash.populate!(*@keys)
34
54
  root = @opt_hash.dig(*@keys)
35
55
  root[@value_key] = value unless root.key?(@value_key)
36
56
  @opt_hash
37
57
  end
38
58
 
39
59
  def set_value!(value)
60
+ return @opt_hash if value.blank?
61
+
62
+ @opt_hash.populate!(*@keys)
40
63
  @opt_hash.dig(*@keys)[@value_key] = value
41
64
  @opt_hash
42
65
  end
@@ -8,6 +8,10 @@ module TagOptions
8
8
  new(...).call
9
9
  end
10
10
 
11
+ def self.values(...)
12
+ new(...).values
13
+ end
14
+
11
15
  private
12
16
 
13
17
  def resolve_conditional_values(conditional_values)
@@ -4,7 +4,11 @@ module TagOptions
4
4
  module Resolvers
5
5
  class Default < Resolver
6
6
  def call
7
- @values.map { |v| v.to_s.split }.flatten.compact.uniq.join(" ")
7
+ values.join(" ")
8
+ end
9
+
10
+ def values
11
+ @values.map { |v| v.to_s.split }.flatten.compact.uniq
8
12
  end
9
13
  end
10
14
  end
@@ -4,7 +4,11 @@ module TagOptions
4
4
  module Resolvers
5
5
  class Style < Resolver
6
6
  def call
7
- styles.map { |p, v| "#{p}: #{v};" }.join(" ")
7
+ values.join(" ")
8
+ end
9
+
10
+ def values
11
+ styles.map { |p, v| "#{p}: #{v};" }
8
12
  end
9
13
 
10
14
  private
@@ -1,3 +1,3 @@
1
1
  module TagOptions
2
- VERSION = "1.2.1"
2
+ VERSION = "1.3.1"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tag_options
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.1
4
+ version: 1.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alex Monroe
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-03-02 00:00:00.000000000 Z
11
+ date: 2023-03-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport