tag_options 0.9.3 → 1.0.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 +5 -0
- data/README.md +82 -125
- 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 +19 -126
- 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 +14 -143
- 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: 900cd0b42ae1f34b69b7cf227cb4f6bc91cb560f3b04424cdf3e2fd41e5d3f61
|
|
4
|
+
data.tar.gz: b4af6738e8d551d795bab1ef057bb47f49de8d73ba32068c839d04bf50e78a43
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 3322cbce916927b777b7e915e181102cdbc7497c42095edc0e11f009d9a6a3884e8649ce6826d0199ba0ac3e9fe1a8c039bc5bd8c490a6db027714f08e6d88c4
|
|
7
|
+
data.tar.gz: 0d1ebc95b92d489d19c49b33acead9abe88a9fc5932865941454100e11bb877db6baacf7380a85f0495c3d47d3807d02e6d8bbfe08d654dbfb6b17a2940c8393
|
data/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [1.0.0] - 2022-06-14
|
|
6
|
+
|
|
7
|
+
- Rewrote and simplified TagOptions::Hash and supporting classes.
|
|
8
|
+
- BREAKING CHANGES, read documentation for updated usage before updating
|
|
9
|
+
|
|
5
10
|
## [0.9.3] - 2021-11-11
|
|
6
11
|
|
|
7
12
|
- Added TagOptions::Hash() ease-of-use method
|
data/README.md
CHANGED
|
@@ -1,17 +1,20 @@
|
|
|
1
1
|
# Tag Options
|
|
2
2
|
|
|
3
|
-
Simple library for manipulating options passed to the Rails `tag`,
|
|
3
|
+
Simple library for manipulating options passed to the Rails `tag`,
|
|
4
|
+
`content_tag`, and other tag helpers.
|
|
4
5
|
|
|
5
|
-
This library provides a simple class to make authoring resuable helpers and
|
|
6
|
-
easier when you want to allow for
|
|
6
|
+
This library provides a simple class to make authoring resuable helpers and
|
|
7
|
+
[View Components](https://viewcomponent.org) easier when you want to allow for
|
|
8
|
+
the input of properties on HTML elements, but also need to add/set your own.
|
|
7
9
|
|
|
8
|
-
`TagOptions::Hash` is an object that normalizes the options passed to Rails
|
|
9
|
-
to manipulate the values of HTML
|
|
10
|
+
`TagOptions::Hash` is an object that normalizes the options passed to Rails
|
|
11
|
+
helper, while providing helpful methods to manipulate the values of HTML
|
|
12
|
+
properties:
|
|
10
13
|
|
|
11
14
|
```ruby
|
|
12
15
|
def external_link_to(name, url, options={})
|
|
13
16
|
options = TagOptions::Hash.new(options)
|
|
14
|
-
options.
|
|
17
|
+
options.at(:class).combine!("external-link")
|
|
15
18
|
link_to(name, url, options)
|
|
16
19
|
end
|
|
17
20
|
```
|
|
@@ -19,7 +22,7 @@ end
|
|
|
19
22
|
Called with:
|
|
20
23
|
|
|
21
24
|
```ruby
|
|
22
|
-
external_link_to(
|
|
25
|
+
external_link_to("Example", "https://example.com", class: "ml-2")
|
|
23
26
|
```
|
|
24
27
|
|
|
25
28
|
Would render:
|
|
@@ -31,12 +34,11 @@ Would render:
|
|
|
31
34
|
## Table of Contents
|
|
32
35
|
|
|
33
36
|
- [Installation](#installation)
|
|
34
|
-
- [Configuration](#configuration)
|
|
35
37
|
- [General Usage](#general-usage)
|
|
36
|
-
- [
|
|
37
|
-
- [
|
|
38
|
+
- [combine!](#combine)
|
|
39
|
+
- [set!](#set)
|
|
38
40
|
- [Conditional Usage](#conditional-usage)
|
|
39
|
-
- [
|
|
41
|
+
- [Property Resolvers](#property-resolvers)
|
|
40
42
|
- [Development](#development)
|
|
41
43
|
- [Contributing](#contributing)
|
|
42
44
|
- [To Do](#to-do)
|
|
@@ -47,7 +49,7 @@ Would render:
|
|
|
47
49
|
Add this line to your application's Gemfile:
|
|
48
50
|
|
|
49
51
|
```ruby
|
|
50
|
-
gem
|
|
52
|
+
gem "tag_options"
|
|
51
53
|
```
|
|
52
54
|
|
|
53
55
|
And then execute:
|
|
@@ -56,33 +58,6 @@ And then execute:
|
|
|
56
58
|
bundle install
|
|
57
59
|
```
|
|
58
60
|
|
|
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
61
|
## General Usage
|
|
87
62
|
|
|
88
63
|
Initialize a `TagOptions::Hash` directly or by passing an existing `Hash`.
|
|
@@ -91,155 +66,137 @@ Initialize a `TagOptions::Hash` directly or by passing an existing `Hash`.
|
|
|
91
66
|
TagOptions::Hash.new
|
|
92
67
|
=> {}
|
|
93
68
|
|
|
94
|
-
hash = {class:
|
|
69
|
+
hash = {class: "flex"}
|
|
95
70
|
TagOptions::Hash.new(hash)
|
|
96
71
|
=> {:class=>"flex"}
|
|
97
72
|
```
|
|
98
73
|
|
|
99
|
-
###
|
|
74
|
+
### combine!
|
|
100
75
|
|
|
101
|
-
Combine HTML attributes with an existing `TagOptions::Hash`
|
|
76
|
+
Combine HTML attributes with an existing `TagOptions::Hash` by chaining `at` and
|
|
77
|
+
`combine!`
|
|
102
78
|
|
|
103
79
|
```ruby
|
|
104
|
-
options = TagOptions::Hash.new(class:
|
|
105
|
-
options.
|
|
80
|
+
options = TagOptions::Hash.new(class: "flex")
|
|
81
|
+
options.at(:class).combine!("mt-1")
|
|
106
82
|
=> {:class=>"flex mt-1"}
|
|
107
83
|
```
|
|
108
84
|
|
|
109
85
|
Values can also be specified as arrays.
|
|
110
86
|
|
|
111
87
|
```ruby
|
|
112
|
-
options = TagOptions::Hash.new(class:
|
|
113
|
-
options.
|
|
88
|
+
options = TagOptions::Hash.new(class: "flex")
|
|
89
|
+
options.at(:class).combine!(["mt-1", "mx-2"])
|
|
114
90
|
=> {:class=>"flex mt-1 mx-2"}
|
|
115
91
|
```
|
|
116
92
|
|
|
117
93
|
HTML attributes are only added if they don't already exist.
|
|
118
94
|
|
|
119
95
|
```ruby
|
|
120
|
-
options = TagOptions::Hash.new(class:
|
|
121
|
-
options.
|
|
96
|
+
options = TagOptions::Hash.new(class: "flex")
|
|
97
|
+
options.at(:class).combine!("flex flex-col")
|
|
122
98
|
=> {:class=>"flex flex-col"}
|
|
123
99
|
```
|
|
124
100
|
|
|
125
|
-
You can also combine
|
|
101
|
+
You can also combine values on nested hashes.
|
|
126
102
|
|
|
127
103
|
```ruby
|
|
128
|
-
options = TagOptions::Hash.new(class:
|
|
129
|
-
options.
|
|
130
|
-
=> {:class=>"flex
|
|
104
|
+
options = TagOptions::Hash.new(class: "flex", data: {controller: "dropdown"})
|
|
105
|
+
options.at(:data, :controller).combine!("toggle")
|
|
106
|
+
=> {:class=>"flex", :data=>{:controller=>"dropdown toggle"}
|
|
131
107
|
```
|
|
132
108
|
|
|
133
|
-
|
|
109
|
+
If a nested hash doesn't already exist it will be automatically added.
|
|
134
110
|
|
|
135
111
|
```ruby
|
|
136
|
-
options = TagOptions::Hash.new(class:
|
|
137
|
-
options.
|
|
138
|
-
=> {:class=>"flex
|
|
112
|
+
options = TagOptions::Hash.new(class: "flex")
|
|
113
|
+
options.at(:data, :controller).combine!("dropdown")
|
|
114
|
+
=> {:class=>"flex", :data=>{:controller=>"dropdown"}
|
|
139
115
|
```
|
|
140
116
|
|
|
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
|
-
```
|
|
117
|
+
### set!
|
|
148
118
|
|
|
149
|
-
|
|
150
|
-
|
|
119
|
+
Chaining `at` and `set!` functions nearly the same as `combine!` with all same
|
|
120
|
+
usage patterns. The major difference is that the set method will override any
|
|
121
|
+
existing values.
|
|
151
122
|
|
|
152
123
|
```ruby
|
|
153
|
-
options = TagOptions::Hash.new(class:
|
|
154
|
-
options.
|
|
155
|
-
|
|
156
|
-
=> {:class=>"flex mt-1", :"data-controller"=>"dropdown"}
|
|
124
|
+
options = TagOptions::Hash.new(class: "flex")
|
|
125
|
+
options.at(:class).set!("block")
|
|
126
|
+
=> {:class=>"block"}
|
|
157
127
|
```
|
|
158
128
|
|
|
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
129
|
## Conditional Usage
|
|
166
130
|
|
|
167
|
-
Both the `
|
|
168
|
-
array. Where the values are added
|
|
131
|
+
Both the `combine!` and `set!` allow for values to be conditionally added to
|
|
132
|
+
HTML attributes using an argument array. Where the values are added
|
|
133
|
+
unconditionally and key/value pairs have their key added _IF_ the value is true.
|
|
169
134
|
|
|
170
135
|
```ruby
|
|
171
136
|
# assuming `centered?` returns `true`
|
|
172
|
-
options = TagOptions::Hash.new(class:
|
|
173
|
-
options.
|
|
137
|
+
options = TagOptions::Hash.new(class: "flex")
|
|
138
|
+
options.at(:class).combine!("mt-1", "mx-auto": centered?, "mx-2": !centered?)
|
|
174
139
|
=> {:class=>"flex mt-1 mx-auto"}
|
|
175
140
|
```
|
|
176
141
|
|
|
177
|
-
|
|
178
|
-
conditional values to be combined more naturally using a more typical argument pattern.
|
|
179
|
-
|
|
180
|
-
```ruby
|
|
181
|
-
# assuming `centered?` returns `true`
|
|
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
|
-
```
|
|
142
|
+
## Custom Property Resolvers
|
|
186
143
|
|
|
187
|
-
|
|
144
|
+
Chaining `at` to `combine!` or `set!` processes HTML properties similar to
|
|
145
|
+
`class`.
|
|
188
146
|
|
|
189
|
-
|
|
147
|
+
- Multiple are allowed
|
|
148
|
+
- Multiple values are seperated by a space
|
|
149
|
+
- Duplicate values are not added
|
|
190
150
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
- Multiple unique values are allowed
|
|
194
|
-
- Multiple values are seperated by a space
|
|
195
|
-
- `TagOptions::PropertyHandler::Singular` - Processes `id`, `role`, and `aria-*` properties.
|
|
196
|
-
- Both `combine_with!` and `override!` function the same on these attributes.
|
|
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.
|
|
151
|
+
Tag Options also ships with a special `style` resolver, which can be used by
|
|
152
|
+
pass `as: :style` to `at`.
|
|
204
153
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
154
|
+
- Multiple values are allowed
|
|
155
|
+
- Values must be specified as `property: value;`
|
|
156
|
+
- Duplicate `property: value;` pairs are not added
|
|
157
|
+
- The `combine!` method will overwrite an existing style property if it exists,
|
|
158
|
+
add properties that don't exist, and leave the remaining properties untouched.
|
|
159
|
+
- The `set!` method will overwrite all existing style properties.
|
|
208
160
|
|
|
209
161
|
```ruby
|
|
210
|
-
|
|
162
|
+
options = TagOptions::Hash.new(style: "display: block; margin-left: 0;")
|
|
163
|
+
options.at(:style, as: :style).combine!("display: flex; margin-right: 0;")
|
|
164
|
+
=> {:style=>"display: flex; margin-left: 0; margin-right: 0;"}
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
A `TagOptions::Resolver` class is available if you wish to implement your own
|
|
168
|
+
custom handlers. For examples on doing so, see the [built-in
|
|
169
|
+
handlers](https://github.com/wamonroe/tag_options/tree/main/lib/tag_options/resolvers).
|
|
211
170
|
|
|
171
|
+
To register a custom handler:
|
|
172
|
+
|
|
173
|
+
```ruby
|
|
174
|
+
# config/initializers/tag_options.rb
|
|
212
175
|
TagOptions.configure do |config|
|
|
213
|
-
config.
|
|
214
|
-
'TagOptions::PropertyHandler::TailwindCSS',
|
|
215
|
-
'TagOptions::PropertyHandler::Singular',
|
|
216
|
-
'TagOptions::PropertyHandler::Style'
|
|
217
|
-
]
|
|
176
|
+
config.register_resolver :custom, "MyCustomResolver"
|
|
218
177
|
end
|
|
219
178
|
```
|
|
220
179
|
|
|
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
180
|
## Development
|
|
226
181
|
|
|
227
|
-
After checking out the repo, run `bin/setup` to install dependencies. Then, run
|
|
228
|
-
also run:
|
|
182
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run
|
|
183
|
+
`bin/rspec` to run the tests. You can also run:
|
|
229
184
|
|
|
230
185
|
- `bin/console` for an interactive prompt that will allow you to experiment
|
|
231
186
|
- `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
187
|
|
|
235
|
-
To install this gem onto your local machine, run `bundle exec rake install`. To
|
|
236
|
-
version number in `version.rb`, and then run
|
|
237
|
-
|
|
188
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To
|
|
189
|
+
release a new version, update the version number in `version.rb`, and then run
|
|
190
|
+
`bundle exec rake release`, which will create a git tag for the version, push
|
|
191
|
+
git commits and the created tag, and push the `.gem` file to
|
|
192
|
+
[rubygems.org](https://rubygems.org).
|
|
238
193
|
|
|
239
194
|
## Contributing
|
|
240
195
|
|
|
241
|
-
Bug reports and pull requests are welcome on GitHub at
|
|
196
|
+
Bug reports and pull requests are welcome on GitHub at
|
|
197
|
+
https://github.com/wamonroe/tag_options.
|
|
242
198
|
|
|
243
199
|
## License
|
|
244
200
|
|
|
245
|
-
The gem is available as open source under the terms of the [MIT
|
|
201
|
+
The gem is available as open source under the terms of the [MIT
|
|
202
|
+
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,33 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
require 'active_support/core_ext/string'
|
|
4
|
-
require 'active_support/core_ext/array'
|
|
5
|
-
require 'forwardable'
|
|
6
|
-
require 'tag_options/property_handler/resolve_value'
|
|
1
|
+
require "tag_options/hash_at"
|
|
2
|
+
require "tag_options/errors/not_hash_error"
|
|
7
3
|
|
|
8
4
|
module TagOptions
|
|
9
|
-
class Hash
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
# Hashes passed into the initializer are automatically flattened, with nested keys seperated by dashes. For example,
|
|
15
|
-
# `data: { controller: 'dropdown' }`` becomes `'data-controller': 'dropdown'`.
|
|
16
|
-
def initialize(hash={})
|
|
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)
|
|
38
|
-
end
|
|
39
|
-
else
|
|
40
|
-
store(property, value)
|
|
5
|
+
class Hash < ::Hash
|
|
6
|
+
def initialize(hash = {})
|
|
7
|
+
hash.each do |key, value|
|
|
8
|
+
self[key] = value.is_a?(::Hash) ? TagOptions::Hash.new(value) : value
|
|
41
9
|
end
|
|
42
10
|
end
|
|
43
11
|
|
|
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
|
|
67
|
-
end
|
|
68
|
-
|
|
69
|
-
# override!
|
|
70
|
-
# Allows you to override values on multiple HTML properties in one operation. Passed keys should be the HTML
|
|
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
|
|
12
|
+
def at(key, *nested_keys, as: :default)
|
|
13
|
+
TagOptions::HashAt.new(opt_hash: self, keys: [key, *nested_keys], as: as)
|
|
92
14
|
end
|
|
93
15
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
def action_matcher
|
|
97
|
-
/\A(?<action>combine_with|override)_(?<property>.*)!\z/
|
|
16
|
+
def dig(*keys)
|
|
17
|
+
keys.size.zero? ? self : super
|
|
98
18
|
end
|
|
99
19
|
|
|
100
|
-
def
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
20
|
+
def populate!(*keys)
|
|
21
|
+
populated_keys = []
|
|
22
|
+
data = self
|
|
23
|
+
keys.each do |key|
|
|
24
|
+
data[key] ||= TagOptions::Hash.new
|
|
25
|
+
data = data[key]
|
|
26
|
+
unless data.is_a?(TagOptions::Hash)
|
|
27
|
+
raise TagOptions::Errors::NotHashError.new(populated_keys, type: data.class)
|
|
108
28
|
end
|
|
109
29
|
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
|
|
30
|
+
self
|
|
138
31
|
end
|
|
139
32
|
end
|
|
140
33
|
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
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
module TagOptions
|
|
2
|
+
class Resolver
|
|
3
|
+
def initialize(*values, **conditional_values)
|
|
4
|
+
@values = [*values, *resolve_conditional_values(conditional_values)]
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
def self.call(...)
|
|
8
|
+
new(...).call
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
private
|
|
12
|
+
|
|
13
|
+
def resolve_conditional_values(conditional_values)
|
|
14
|
+
conditional_values.select { |_key, value| value }.keys
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|