tag_options 0.9.3 → 1.1.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/CHANGELOG.md +10 -0
- data/README.md +92 -132
- data/Rakefile +5 -5
- data/lib/tag_options/configuration.rb +16 -13
- data/lib/tag_options/error.rb +4 -0
- data/lib/tag_options/errors/not_hash_error.rb +12 -0
- data/lib/tag_options/errors/resolver_error.rb +11 -0
- data/lib/tag_options/hash.rb +25 -125
- data/lib/tag_options/hash_at.rb +30 -0
- data/lib/tag_options/resolver.rb +17 -0
- data/lib/tag_options/resolvers/default.rb +11 -0
- data/lib/tag_options/resolvers/style.rb +26 -0
- data/lib/tag_options/version.rb +1 -3
- data/lib/tag_options.rb +3 -12
- metadata +16 -131
- data/lib/generators/tag_options/install/USAGE +0 -9
- data/lib/generators/tag_options/install/install_generator.rb +0 -13
- data/lib/generators/tag_options/install/templates/tag_options.rb +0 -18
- data/lib/tag_options/property_handler/base.rb +0 -36
- data/lib/tag_options/property_handler/generic.rb +0 -15
- data/lib/tag_options/property_handler/resolve_value.rb +0 -33
- data/lib/tag_options/property_handler/singular.rb +0 -15
- data/lib/tag_options/property_handler/style.rb +0 -42
- data/lib/tag_options/property_handler/tailwind_css.rb +0 -598
- data/lib/tag_options/railtie.rb +0 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5802916aaa57253843bc9fa02aed005828d4ffa30a8ccf514b9949c5c0859d2d
|
4
|
+
data.tar.gz: 80ee0b00682ee8d94595039cd1569c0152d0dedb225a78672986416118bec6fe
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f498f2aa015310a8b4d3800dcb435c5b946665f5f53bf54630a80666e3c56f05c54b75788ea84b2d57829d2369404408621a4b2b7adeec1c5668fad2e61ac37a
|
7
|
+
data.tar.gz: 9e04caa1298cec89d34af81daa7c11b51c18020c3bb013aaf7b104de5f1e5c80d545aeaae334929d3c2796d5fa00f31aafb59028b588bf9aefd218278e56bb9c
|
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,16 @@
|
|
2
2
|
|
3
3
|
## [Unreleased]
|
4
4
|
|
5
|
+
## [1.1.0] - 2023-03-01
|
6
|
+
|
7
|
+
- Switched to inheriting from ActiveSupport::HashWithIndifferentAccess.
|
8
|
+
- Added before/after/around initialize callback support.
|
9
|
+
|
10
|
+
## [1.0.0] - 2022-06-14
|
11
|
+
|
12
|
+
- Rewrote and simplified TagOptions::Hash and supporting classes.
|
13
|
+
- BREAKING CHANGES, read documentation for updated usage before updating.
|
14
|
+
|
5
15
|
## [0.9.3] - 2021-11-11
|
6
16
|
|
7
17
|
- Added TagOptions::Hash() ease-of-use method
|
data/README.md
CHANGED
@@ -1,17 +1,22 @@
|
|
1
1
|
# Tag Options
|
2
2
|
|
3
|
-
|
3
|
+
[](https://github.com/wamonroe/tag_options/actions/workflows/test.yml)
|
4
4
|
|
5
|
-
|
6
|
-
|
5
|
+
Simple library for manipulating options passed to the Rails `tag`,
|
6
|
+
`content_tag`, and other tag helpers.
|
7
7
|
|
8
|
-
|
9
|
-
|
8
|
+
This library provides a simple class to make authoring resuable helpers and
|
9
|
+
[View Components](https://viewcomponent.org) easier when you want to allow for
|
10
|
+
the input of properties on HTML elements, but also need to add/set your own.
|
11
|
+
|
12
|
+
`TagOptions::Hash` is an object that normalizes the options passed to Rails
|
13
|
+
helper, while providing helpful methods to manipulate the values of HTML
|
14
|
+
properties:
|
10
15
|
|
11
16
|
```ruby
|
12
17
|
def external_link_to(name, url, options={})
|
13
18
|
options = TagOptions::Hash.new(options)
|
14
|
-
options.
|
19
|
+
options.at(:class).combine!("external-link")
|
15
20
|
link_to(name, url, options)
|
16
21
|
end
|
17
22
|
```
|
@@ -19,7 +24,7 @@ end
|
|
19
24
|
Called with:
|
20
25
|
|
21
26
|
```ruby
|
22
|
-
external_link_to(
|
27
|
+
external_link_to("Example", "https://example.com", class: "ml-2")
|
23
28
|
```
|
24
29
|
|
25
30
|
Would render:
|
@@ -30,24 +35,24 @@ Would render:
|
|
30
35
|
|
31
36
|
## Table of Contents
|
32
37
|
|
33
|
-
- [
|
34
|
-
- [
|
35
|
-
- [
|
36
|
-
- [
|
37
|
-
|
38
|
-
- [
|
39
|
-
- [
|
40
|
-
- [
|
41
|
-
- [
|
42
|
-
- [
|
43
|
-
- [License](#license)
|
38
|
+
- [Tag Options](#tag-options)
|
39
|
+
- [Table of Contents](#table-of-contents)
|
40
|
+
- [Installation](#installation)
|
41
|
+
- [General Usage](#general-usage)
|
42
|
+
- [combine!](#combine)
|
43
|
+
- [set!](#set)
|
44
|
+
- [Conditional Usage](#conditional-usage)
|
45
|
+
- [Custom Property Resolvers](#custom-property-resolvers)
|
46
|
+
- [Development](#development)
|
47
|
+
- [Contributing](#contributing)
|
48
|
+
- [License](#license)
|
44
49
|
|
45
50
|
## Installation
|
46
51
|
|
47
52
|
Add this line to your application's Gemfile:
|
48
53
|
|
49
54
|
```ruby
|
50
|
-
gem
|
55
|
+
gem "tag_options"
|
51
56
|
```
|
52
57
|
|
53
58
|
And then execute:
|
@@ -56,33 +61,6 @@ And then execute:
|
|
56
61
|
bundle install
|
57
62
|
```
|
58
63
|
|
59
|
-
## Configuration
|
60
|
-
|
61
|
-
Generate an initializer to customize the default configuration:
|
62
|
-
|
63
|
-
```sh
|
64
|
-
rails generate arc_options:install
|
65
|
-
```
|
66
|
-
|
67
|
-
```ruby
|
68
|
-
TagOptions.configure do |config|
|
69
|
-
# fallback_property_handler
|
70
|
-
#
|
71
|
-
# Defines the default behavior of how values are treated on HTML properties. `TagOptions::PropertyHandler::Generic`
|
72
|
-
# allows for multiple, unique, values seperated by spaces.
|
73
|
-
config.fallback_property_handler = 'TagOptions::PropertyHandler::Generic'
|
74
|
-
|
75
|
-
# property_handlers
|
76
|
-
#
|
77
|
-
# Allows of the custom handling of HTML properties that match the defined property handler. Properties are handled by
|
78
|
-
# the first matching property handler.
|
79
|
-
config.property_handlers = [
|
80
|
-
'TagOptions::PropertyHandler::Singular',
|
81
|
-
'TagOptions::PropertyHandler::Style'
|
82
|
-
]
|
83
|
-
end
|
84
|
-
```
|
85
|
-
|
86
64
|
## General Usage
|
87
65
|
|
88
66
|
Initialize a `TagOptions::Hash` directly or by passing an existing `Hash`.
|
@@ -91,155 +69,137 @@ Initialize a `TagOptions::Hash` directly or by passing an existing `Hash`.
|
|
91
69
|
TagOptions::Hash.new
|
92
70
|
=> {}
|
93
71
|
|
94
|
-
hash = {class:
|
72
|
+
hash = {class: "flex"}
|
95
73
|
TagOptions::Hash.new(hash)
|
96
74
|
=> {:class=>"flex"}
|
97
75
|
```
|
98
76
|
|
99
|
-
###
|
77
|
+
### combine!
|
100
78
|
|
101
|
-
Combine HTML attributes with an existing `TagOptions::Hash`
|
79
|
+
Combine HTML attributes with an existing `TagOptions::Hash` by chaining `at` and
|
80
|
+
`combine!`
|
102
81
|
|
103
82
|
```ruby
|
104
|
-
options = TagOptions::Hash.new(class:
|
105
|
-
options.
|
83
|
+
options = TagOptions::Hash.new(class: "flex")
|
84
|
+
options.at(:class).combine!("mt-1")
|
106
85
|
=> {:class=>"flex mt-1"}
|
107
86
|
```
|
108
87
|
|
109
88
|
Values can also be specified as arrays.
|
110
89
|
|
111
90
|
```ruby
|
112
|
-
options = TagOptions::Hash.new(class:
|
113
|
-
options.
|
91
|
+
options = TagOptions::Hash.new(class: "flex")
|
92
|
+
options.at(:class).combine!(["mt-1", "mx-2"])
|
114
93
|
=> {:class=>"flex mt-1 mx-2"}
|
115
94
|
```
|
116
95
|
|
117
96
|
HTML attributes are only added if they don't already exist.
|
118
97
|
|
119
98
|
```ruby
|
120
|
-
options = TagOptions::Hash.new(class:
|
121
|
-
options.
|
99
|
+
options = TagOptions::Hash.new(class: "flex")
|
100
|
+
options.at(:class).combine!("flex flex-col")
|
122
101
|
=> {:class=>"flex flex-col"}
|
123
102
|
```
|
124
103
|
|
125
|
-
You can also combine
|
104
|
+
You can also combine values on nested hashes.
|
126
105
|
|
127
106
|
```ruby
|
128
|
-
options = TagOptions::Hash.new(class:
|
129
|
-
options.
|
130
|
-
=> {:class=>"flex
|
107
|
+
options = TagOptions::Hash.new(class: "flex", data: {controller: "dropdown"})
|
108
|
+
options.at(:data, :controller).combine!("toggle")
|
109
|
+
=> {:class=>"flex", :data=>{:controller=>"dropdown toggle"}
|
131
110
|
```
|
132
111
|
|
133
|
-
|
112
|
+
If a nested hash doesn't already exist it will be automatically added.
|
134
113
|
|
135
114
|
```ruby
|
136
|
-
options = TagOptions::Hash.new(class:
|
137
|
-
options.
|
138
|
-
=> {:class=>"flex
|
115
|
+
options = TagOptions::Hash.new(class: "flex")
|
116
|
+
options.at(:data, :controller).combine!("dropdown")
|
117
|
+
=> {:class=>"flex", :data=>{:controller=>"dropdown"}
|
139
118
|
```
|
140
119
|
|
141
|
-
|
142
|
-
|
143
|
-
```ruby
|
144
|
-
options = TagOptions::Hash.new(class: 'flex')
|
145
|
-
options.combine_with!(class: 'mt-1', data_controller: 'dropdown')
|
146
|
-
=> {:class=>"flex mt-1", :"data-controller"=>"dropdown"}
|
147
|
-
```
|
120
|
+
### set!
|
148
121
|
|
149
|
-
|
150
|
-
|
122
|
+
Chaining `at` and `set!` functions nearly the same as `combine!` with all same
|
123
|
+
usage patterns. The major difference is that the set method will override any
|
124
|
+
existing values.
|
151
125
|
|
152
126
|
```ruby
|
153
|
-
options = TagOptions::Hash.new(class:
|
154
|
-
options.
|
155
|
-
|
156
|
-
=> {:class=>"flex mt-1", :"data-controller"=>"dropdown"}
|
127
|
+
options = TagOptions::Hash.new(class: "flex")
|
128
|
+
options.at(:class).set!("block")
|
129
|
+
=> {:class=>"block"}
|
157
130
|
```
|
158
131
|
|
159
|
-
### override!
|
160
|
-
|
161
|
-
The method `override!` functions nearly the same as `combine_with!` with all same usage patterns, including ease of
|
162
|
-
use methods, such as `override_class!`. The major difference is that the override methods will not combine specified
|
163
|
-
values with existing values. Any specified values will override any existing values.
|
164
|
-
|
165
132
|
## Conditional Usage
|
166
133
|
|
167
|
-
Both the `
|
168
|
-
array. Where the values are added
|
134
|
+
Both the `combine!` and `set!` allow for values to be conditionally added to
|
135
|
+
HTML attributes using an argument array. Where the values are added
|
136
|
+
unconditionally and key/value pairs have their key added _IF_ the value is true.
|
169
137
|
|
170
138
|
```ruby
|
171
139
|
# assuming `centered?` returns `true`
|
172
|
-
options = TagOptions::Hash.new(class:
|
173
|
-
options.
|
140
|
+
options = TagOptions::Hash.new(class: "flex")
|
141
|
+
options.at(:class).combine!("mt-1", "mx-auto": centered?, "mx-2": !centered?)
|
174
142
|
=> {:class=>"flex mt-1 mx-auto"}
|
175
143
|
```
|
176
144
|
|
177
|
-
|
178
|
-
conditional values to be combined more naturally using a more typical argument pattern.
|
145
|
+
## Custom Property Resolvers
|
179
146
|
|
180
|
-
|
181
|
-
|
182
|
-
options = TagOptions::Hash.new(class: 'flex')
|
183
|
-
options.combine_with_class!('mt-1', 'mx-auto': centered?, 'mx-2': !centered?)
|
184
|
-
=> {:class=>"flex mt-1 mx-auto"}
|
185
|
-
```
|
147
|
+
Chaining `at` to `combine!` or `set!` processes HTML properties similar to
|
148
|
+
`class`.
|
186
149
|
|
187
|
-
|
150
|
+
- Multiple are allowed
|
151
|
+
- Multiple values are seperated by a space
|
152
|
+
- Duplicate values are not added
|
188
153
|
|
189
|
-
Tag Options ships with
|
154
|
+
Tag Options also ships with a special `style` resolver, which can be used by
|
155
|
+
pass `as: :style` to `at`.
|
190
156
|
|
191
|
-
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
- The last specified/resolved value is assigned to the property.
|
198
|
-
- `TagOptions::PropertyHandler::Style` - Processes the `style` property. Allows for the parsing of HTML style property.
|
199
|
-
- Multiple values are allowed
|
200
|
-
- Values must be specified as `property: value;`
|
201
|
-
- The `combine_with!` method will overwrite an existing style property if it exists, but leave the reamining style
|
202
|
-
properties untouched.
|
203
|
-
- The `override!` method will overwrite all existing style properties.
|
204
|
-
|
205
|
-
Tag Options also ships with an optional property handler for sorting Tailwind CSS classes inspired by/based on the
|
206
|
-
VS Code extension [Headwind](https://github.com/heybourn/headwind). To enable this optional property handler,
|
207
|
-
[generate a configuration](#configuration) and then add it as a property handler:
|
157
|
+
- Multiple values are allowed
|
158
|
+
- Values must be specified as `property: value;`
|
159
|
+
- Duplicate `property: value;` pairs are not added
|
160
|
+
- The `combine!` method will overwrite an existing style property if it exists,
|
161
|
+
add properties that don't exist, and leave the remaining properties untouched.
|
162
|
+
- The `set!` method will overwrite all existing style properties.
|
208
163
|
|
209
164
|
```ruby
|
210
|
-
|
165
|
+
options = TagOptions::Hash.new(style: "display: block; margin-left: 0;")
|
166
|
+
options.at(:style, as: :style).combine!("display: flex; margin-right: 0;")
|
167
|
+
=> {:style=>"display: flex; margin-left: 0; margin-right: 0;"}
|
168
|
+
```
|
169
|
+
|
170
|
+
A `TagOptions::Resolver` class is available if you wish to implement your own
|
171
|
+
custom handlers. For examples on doing so, see the [built-in
|
172
|
+
handlers](https://github.com/wamonroe/tag_options/tree/main/lib/tag_options/resolvers).
|
211
173
|
|
174
|
+
To register a custom handler:
|
175
|
+
|
176
|
+
```ruby
|
177
|
+
# config/initializers/tag_options.rb
|
212
178
|
TagOptions.configure do |config|
|
213
|
-
config.
|
214
|
-
'TagOptions::PropertyHandler::TailwindCSS',
|
215
|
-
'TagOptions::PropertyHandler::Singular',
|
216
|
-
'TagOptions::PropertyHandler::Style'
|
217
|
-
]
|
179
|
+
config.register_resolver :custom, "MyCustomResolver"
|
218
180
|
end
|
219
181
|
```
|
220
182
|
|
221
|
-
A `TagOptions::PropertyHandler::Base` class is available if you wish to implement your own custom handlers. For
|
222
|
-
examples on doing so, see the
|
223
|
-
[built-in handlers](https://github.com/wamonroe/tag_options/tree/main/lib/tag_options/property_handler).
|
224
|
-
|
225
183
|
## Development
|
226
184
|
|
227
|
-
After checking out the repo, run `bin/setup` to install dependencies. Then, run
|
228
|
-
also run:
|
185
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run
|
186
|
+
`bin/rspec` to run the tests. You can also run:
|
229
187
|
|
230
188
|
- `bin/console` for an interactive prompt that will allow you to experiment
|
231
189
|
- `bin/rubocop` to run RuboCop to check the code style and formatting
|
232
|
-
- `bin/update_tailwindcss` to update the sort order from the latest [Headwind](https://github.com/heybourn/headwind)
|
233
|
-
configuration.
|
234
190
|
|
235
|
-
To
|
236
|
-
version number in `version.rb`, and then run
|
237
|
-
|
191
|
+
To build this gem on your local machine, run `bundle exec rake build`. To
|
192
|
+
release a new version, update the version number in `version.rb`, and then run
|
193
|
+
`bundle exec rake release`, which will create a git tag for the version, push
|
194
|
+
git commits and the created tag, and push the `.gem` file to
|
195
|
+
[rubygems.org](https://rubygems.org).
|
238
196
|
|
239
197
|
## Contributing
|
240
198
|
|
241
|
-
Bug reports and pull requests are welcome on GitHub at
|
199
|
+
Bug reports and pull requests are welcome on GitHub at
|
200
|
+
https://github.com/wamonroe/tag_options.
|
242
201
|
|
243
202
|
## License
|
244
203
|
|
245
|
-
The gem is available as open source under the terms of the [MIT
|
204
|
+
The gem is available as open source under the terms of the [MIT
|
205
|
+
License](https://opensource.org/licenses/MIT).
|
data/Rakefile
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
3
|
+
require "bundler/setup"
|
4
4
|
|
5
|
-
require
|
6
|
-
require
|
5
|
+
require "bundler/gem_tasks"
|
6
|
+
require "rake/testtask"
|
7
7
|
|
8
8
|
Rake::TestTask.new(:test) do |t|
|
9
|
-
t.libs <<
|
10
|
-
t.pattern =
|
9
|
+
t.libs << "test"
|
10
|
+
t.pattern = "test/**/*_test.rb"
|
11
11
|
t.verbose = false
|
12
12
|
end
|
13
13
|
|
@@ -1,4 +1,6 @@
|
|
1
|
-
|
1
|
+
require "tag_options/resolvers/default"
|
2
|
+
require "tag_options/resolvers/style"
|
3
|
+
require "tag_options/errors/resolver_error"
|
2
4
|
|
3
5
|
module TagOptions
|
4
6
|
class << self
|
@@ -11,24 +13,25 @@ module TagOptions
|
|
11
13
|
def configure
|
12
14
|
yield(configuration)
|
13
15
|
end
|
14
|
-
|
15
|
-
def reset_configuration
|
16
|
-
@configuration = TagOptions::Configuration.new
|
17
|
-
end
|
18
16
|
end
|
19
17
|
|
20
18
|
class Configuration
|
21
|
-
|
19
|
+
def initialize
|
20
|
+
@resolvers = {
|
21
|
+
default: "TagOptions::Resolvers::Default",
|
22
|
+
style: "TagOptions::Resolvers::Style"
|
23
|
+
}
|
24
|
+
end
|
22
25
|
|
23
|
-
def
|
24
|
-
|
26
|
+
def resolver(name)
|
27
|
+
unless (resolver_name = @resolvers[name])
|
28
|
+
raise TagOptions::Errors::ResolverError, name
|
29
|
+
end
|
30
|
+
Object.const_get(resolver_name)
|
25
31
|
end
|
26
32
|
|
27
|
-
def
|
28
|
-
@
|
29
|
-
'TagOptions::PropertyHandler::Singular',
|
30
|
-
'TagOptions::PropertyHandler::Style'
|
31
|
-
]
|
33
|
+
def register_resolver(name, class_name)
|
34
|
+
@resolvers[name] = class_name
|
32
35
|
end
|
33
36
|
end
|
34
37
|
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require "tag_options/error"
|
2
|
+
|
3
|
+
module TagOptions
|
4
|
+
module Errors
|
5
|
+
class NotHashError < Error
|
6
|
+
def initialize(key, *keys, type:)
|
7
|
+
hash_path = [key, *keys].join("=>")
|
8
|
+
super("unsupport type `#{type}` is already located at #{hash_path}")
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
data/lib/tag_options/hash.rb
CHANGED
@@ -1,140 +1,40 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require 'forwardable'
|
6
|
-
require 'tag_options/property_handler/resolve_value'
|
1
|
+
require "active_support/callbacks"
|
2
|
+
require "active_support/core_ext/hash/indifferent_access"
|
3
|
+
require "tag_options/hash_at"
|
4
|
+
require "tag_options/errors/not_hash_error"
|
7
5
|
|
8
6
|
module TagOptions
|
9
|
-
class Hash
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
@data = {}
|
18
|
-
flatten_hash(hash).each do |property, value|
|
19
|
-
self[property] = value
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
# []
|
24
|
-
# Underscores in a property name is automatically coverted to dashes. Properties can be specified as strings or
|
25
|
-
# symbols, both return the same value.
|
26
|
-
def [](property)
|
27
|
-
@data[normalize_property(property)]
|
28
|
-
end
|
29
|
-
|
30
|
-
# []=
|
31
|
-
# Hashes assigned to a property are automatically flatten, with nested keys seperated by dashes. Underscores in a
|
32
|
-
# property name are automatically converted to dashes. Propertiess can be specified as strings or symbols, both will
|
33
|
-
# assign the value to the same property.
|
34
|
-
def []=(property, value)
|
35
|
-
if value.is_a?(::Hash)
|
36
|
-
flatten_hash({ property => value }).each do |flat_property, flat_value|
|
37
|
-
store(flat_property, flat_value)
|
7
|
+
class Hash < ActiveSupport::HashWithIndifferentAccess
|
8
|
+
include ActiveSupport::Callbacks
|
9
|
+
define_callbacks :initialize
|
10
|
+
|
11
|
+
def initialize(hash = {})
|
12
|
+
run_callbacks :initialize do
|
13
|
+
hash.each do |key, value|
|
14
|
+
self[key] = value.is_a?(::Hash) ? self.class.new(value) : value
|
38
15
|
end
|
39
|
-
else
|
40
|
-
store(property, value)
|
41
16
|
end
|
42
17
|
end
|
43
18
|
|
44
|
-
|
45
|
-
|
46
|
-
# property to combine the values with. The values can be specified as single string (e.g. `class: 'flex'`) or as an
|
47
|
-
# argument array (e.g. `class: ['flex', 'mt-2', 'flex-col': layout_column?]`). Hashes in an argument array have
|
48
|
-
# their keys combined only their value is true. Nested keys will automatically be flattened and combine with the
|
49
|
-
# associated property (e.g. `data: { controller: 'dropdown' }` would be combined with `data-controller`).
|
50
|
-
#
|
51
|
-
# #combine_with!(
|
52
|
-
# class: ['flex', 'mt-2', 'flex-col': layout_column?],
|
53
|
-
# data: {
|
54
|
-
# controller: ['dropdown', 'navbar': navbar?]
|
55
|
-
# }
|
56
|
-
# )
|
57
|
-
#
|
58
|
-
# TagOptions::Hash also responses to combine_with_<name>!, where `<name>` is the name of the HTML attribute to
|
59
|
-
# combine the passed argument array with. If `<name>` is specified with a value containing underscores, the HTML
|
60
|
-
# attribute is converted to dashes, for example: `combine_with_data_controller!` will result in the argument array
|
61
|
-
# being combined with existing values in `data-controller`.
|
62
|
-
def combine_with!(hash={})
|
63
|
-
flatten_hash(hash).each do |property, args|
|
64
|
-
store(property, self[property], *args)
|
65
|
-
end
|
66
|
-
self
|
19
|
+
def at(key, *nested_keys, as: :default)
|
20
|
+
TagOptions::HashAt.new(opt_hash: self, keys: [key, *nested_keys], as: as)
|
67
21
|
end
|
68
22
|
|
69
|
-
|
70
|
-
|
71
|
-
# properties to override the values of. The values can be passed as single string (e.g. `class: 'flex'`) or as an
|
72
|
-
# argument array (e.g. `class: ['flex', 'mt-2', 'flex-col': layout_column?]`). Hashes in an argument array have
|
73
|
-
# their keys added only if their value is true. Nested keys will automatically be flattened and override the value
|
74
|
-
# at the associated property (e.g. `data: { controller: 'dropdown' }` would override values at `data-controller`).
|
75
|
-
#
|
76
|
-
# #override!(
|
77
|
-
# class: ['flex', 'mt-2', 'flex-col': layout_column?],
|
78
|
-
# data: {
|
79
|
-
# controller: ['dropdown', 'navbar': navbar?]
|
80
|
-
# }
|
81
|
-
# )
|
82
|
-
#
|
83
|
-
# TagOptions::Hash also responses to override_<name>!, where `<name>` is the name of the HTML attribute to override
|
84
|
-
# the passed argument array on. If `<name>` is specified with a value containing underscores, the resulting HTML
|
85
|
-
# attribute is automatically nested, for example `override_data_controller!` will result in the argument array
|
86
|
-
# overriding the existing values in `data-controller`.
|
87
|
-
def override!(hash={})
|
88
|
-
flatten_hash(hash).each do |property, args|
|
89
|
-
store(property, *args)
|
90
|
-
end
|
91
|
-
self
|
23
|
+
def dig(*keys)
|
24
|
+
keys.size.zero? ? self : super
|
92
25
|
end
|
93
26
|
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
if value.is_a?(::Hash)
|
103
|
-
flatten_hash(value).map do |nested_property, nested_value|
|
104
|
-
result["#{property}-#{nested_property}".to_sym] = nested_value
|
105
|
-
end
|
106
|
-
else
|
107
|
-
result[property] = value
|
27
|
+
def populate!(*keys)
|
28
|
+
populated_keys = []
|
29
|
+
data = self
|
30
|
+
keys.each do |key|
|
31
|
+
data[key] ||= TagOptions::Hash.new
|
32
|
+
data = data[key]
|
33
|
+
unless data.is_a?(TagOptions::Hash)
|
34
|
+
raise TagOptions::Errors::NotHashError.new(populated_keys, type: data.class)
|
108
35
|
end
|
109
36
|
end
|
110
|
-
|
111
|
-
|
112
|
-
def method_missing(method_name, *args, &block)
|
113
|
-
match_data = action_matcher.match(method_name.to_s)
|
114
|
-
if match_data
|
115
|
-
public_send("#{match_data['action']}!", { match_data['property'] => args }, &block)
|
116
|
-
else
|
117
|
-
super
|
118
|
-
end
|
119
|
-
end
|
120
|
-
|
121
|
-
def store(property, *values)
|
122
|
-
property = normalize_property(property)
|
123
|
-
conditions = values.extract_options!
|
124
|
-
value = resolve_value(property, *values, **conditions)
|
125
|
-
value.empty? ? @data.delete(property) : @data[property] = value
|
126
|
-
end
|
127
|
-
|
128
|
-
def resolve_value(property, *values, **conditions)
|
129
|
-
TagOptions::PropertyHandler::ResolveValue.call(property, *values, **conditions)
|
130
|
-
end
|
131
|
-
|
132
|
-
def normalize_property(property)
|
133
|
-
property.to_s.downcase.dasherize.to_sym
|
134
|
-
end
|
135
|
-
|
136
|
-
def respond_to_missing?(method_name, include_private=false)
|
137
|
-
action_matcher.match?(method_name.to_s) || super
|
37
|
+
self
|
138
38
|
end
|
139
39
|
end
|
140
40
|
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require "tag_options/configuration"
|
2
|
+
|
3
|
+
module TagOptions
|
4
|
+
class HashAt
|
5
|
+
def initialize(opt_hash:, keys:, as:)
|
6
|
+
@opt_hash = opt_hash
|
7
|
+
@keys = keys[..-2]
|
8
|
+
@value_key = keys[-1]
|
9
|
+
@resolver = TagOptions.configuration.resolver(as)
|
10
|
+
end
|
11
|
+
|
12
|
+
def combine!(*values, **conditions)
|
13
|
+
@opt_hash.populate!(*@keys)
|
14
|
+
current_value = @opt_hash.dig(*@keys, @value_key)
|
15
|
+
set_value! @resolver.call(current_value, *values, **conditions)
|
16
|
+
end
|
17
|
+
|
18
|
+
def set!(*values, **conditions)
|
19
|
+
@opt_hash.populate!(*@keys)
|
20
|
+
set_value! @resolver.call(*values, **conditions)
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def set_value!(value)
|
26
|
+
@opt_hash.dig(*@keys)[@value_key] = value
|
27
|
+
@opt_hash
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|