tag_options 0.9.1 → 1.0.0

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: 83e261e9adfa9aeb2c3dff7ea1a96feef6b879643232d84135739204bbac2eb1
4
- data.tar.gz: 4f5017d33651e2274f6a28200c402e840ec044c5c33e9458f73720177cbf6cc1
3
+ metadata.gz: 900cd0b42ae1f34b69b7cf227cb4f6bc91cb560f3b04424cdf3e2fd41e5d3f61
4
+ data.tar.gz: b4af6738e8d551d795bab1ef057bb47f49de8d73ba32068c839d04bf50e78a43
5
5
  SHA512:
6
- metadata.gz: abd1baed79e11a1ecbf6bef278a4d607400e2aaedbe5b3d6d62b9b7480ff2acb4b47091f476c199cffd40ead699be7edcb18f4e5f4e68d90e2fc16e35618c073
7
- data.tar.gz: 3606249e0673f84f8f00a407c2fe9f73eea3286e1309f10fca238ca906ff3aef8da4e20114eba04e097622317ba5cf74c534f032cb3367e8b2936ec94dac977d
6
+ metadata.gz: 3322cbce916927b777b7e915e181102cdbc7497c42095edc0e11f009d9a6a3884e8649ce6826d0199ba0ac3e9fe1a8c039bc5bd8c490a6db027714f08e6d88c4
7
+ data.tar.gz: 0d1ebc95b92d489d19c49b33acead9abe88a9fc5932865941454100e11bb877db6baacf7380a85f0495c3d47d3807d02e6d8bbfe08d654dbfb6b17a2940c8393
data/CHANGELOG.md CHANGED
@@ -2,10 +2,24 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
- ## [0.9.0] - 2021-11-04
5
+ ## [1.0.0] - 2022-06-14
6
6
 
7
- - Initial release
7
+ - Rewrote and simplified TagOptions::Hash and supporting classes.
8
+ - BREAKING CHANGES, read documentation for updated usage before updating
9
+
10
+ ## [0.9.3] - 2021-11-11
11
+
12
+ - Added TagOptions::Hash() ease-of-use method
13
+ - Bug fixes for Ruby 3.0
14
+
15
+ ## [0.9.2] - 2021-11-09
16
+
17
+ - Added optional TailwindCSS property handler
8
18
 
9
19
  ## [0.9.1] - 2021-11-08
10
20
 
11
- - Implement property handling
21
+ - Implemented property handling
22
+
23
+ ## [0.9.0] - 2021-11-04
24
+
25
+ - Initial release
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`, `content_tag`, and other tag helpers.
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 [View Components](https://viewcomponent.org)
6
- easier when you want to allow for the input of attributes on HTML elements, but also need to add/set your own.
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 helper, while providing helpful methods
9
- to manipulate the values of HTML attributes:
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.combine_with_class!('external-link')
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('Example', 'https://example.com', class: 'ml-2')
25
+ external_link_to("Example", "https://example.com", class: "ml-2")
23
26
  ```
24
27
 
25
28
  Would render:
@@ -31,11 +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
- - [combine_with!](#combinewith)
37
- - [override!](#override)
38
+ - [combine!](#combine)
39
+ - [set!](#set)
38
40
  - [Conditional Usage](#conditional-usage)
41
+ - [Property Resolvers](#property-resolvers)
39
42
  - [Development](#development)
40
43
  - [Contributing](#contributing)
41
44
  - [To Do](#to-do)
@@ -46,7 +49,7 @@ Would render:
46
49
  Add this line to your application's Gemfile:
47
50
 
48
51
  ```ruby
49
- gem 'tag_options'
52
+ gem "tag_options"
50
53
  ```
51
54
 
52
55
  And then execute:
@@ -55,14 +58,6 @@ And then execute:
55
58
  bundle install
56
59
  ```
57
60
 
58
- ## Configuration
59
-
60
- Generate an initializer to customize the default configuration:
61
-
62
- ```sh
63
- rails generate arc_options:install
64
- ```
65
-
66
61
  ## General Usage
67
62
 
68
63
  Initialize a `TagOptions::Hash` directly or by passing an existing `Hash`.
@@ -71,115 +66,137 @@ Initialize a `TagOptions::Hash` directly or by passing an existing `Hash`.
71
66
  TagOptions::Hash.new
72
67
  => {}
73
68
 
74
- hash = {class: 'flex'}
69
+ hash = {class: "flex"}
75
70
  TagOptions::Hash.new(hash)
76
71
  => {:class=>"flex"}
77
72
  ```
78
73
 
79
- ### combine_with!
74
+ ### combine!
80
75
 
81
- Combine HTML attributes with an existing `TagOptions::Hash` using `combine_with!`
76
+ Combine HTML attributes with an existing `TagOptions::Hash` by chaining `at` and
77
+ `combine!`
82
78
 
83
79
  ```ruby
84
- options = TagOptions::Hash.new(class: 'flex')
85
- options.combine_with!(class: 'mt-1')
80
+ options = TagOptions::Hash.new(class: "flex")
81
+ options.at(:class).combine!("mt-1")
86
82
  => {:class=>"flex mt-1"}
87
83
  ```
88
84
 
89
85
  Values can also be specified as arrays.
90
86
 
91
87
  ```ruby
92
- options = TagOptions::Hash.new(class: 'flex')
93
- options.combine_with!(class: ['mt-1', 'mx-2'])
88
+ options = TagOptions::Hash.new(class: "flex")
89
+ options.at(:class).combine!(["mt-1", "mx-2"])
94
90
  => {:class=>"flex mt-1 mx-2"}
95
91
  ```
96
92
 
97
93
  HTML attributes are only added if they don't already exist.
98
94
 
99
95
  ```ruby
100
- options = TagOptions::Hash.new(class: 'flex')
101
- options.combine_with!(class: 'flex flex-col')
96
+ options = TagOptions::Hash.new(class: "flex")
97
+ options.at(:class).combine!("flex flex-col")
102
98
  => {:class=>"flex flex-col"}
103
99
  ```
104
100
 
105
- You can also combine multiple HTML attributes in one operation.
101
+ You can also combine values on nested hashes.
106
102
 
107
103
  ```ruby
108
- options = TagOptions::Hash.new(class: 'flex')
109
- options.combine_with!(class: 'mt-1', 'data-controller': 'dropdown')
110
- => {:class=>"flex mt-1", :"data-controller"=>"dropdown"}
104
+ options = TagOptions::Hash.new(class: "flex", data: {controller: "dropdown"})
105
+ options.at(:data, :controller).combine!("toggle")
106
+ => {:class=>"flex", :data=>{:controller=>"dropdown toggle"}
111
107
  ```
112
108
 
113
- Dash seperated HTML attributes, such as `data-controller` can also be specified as nested hashes.
109
+ If a nested hash doesn't already exist it will be automatically added.
114
110
 
115
111
  ```ruby
116
- options = TagOptions::Hash.new(class: 'flex')
117
- options.combine_with!(class: 'mt-1', data: { controller: 'dropdown' })
118
- => {:class=>"flex mt-1", :"data-controller"=>"dropdown"}
112
+ options = TagOptions::Hash.new(class: "flex")
113
+ options.at(:data, :controller).combine!("dropdown")
114
+ => {:class=>"flex", :data=>{:controller=>"dropdown"}
119
115
  ```
120
116
 
121
- Dash seperated HTML attributes can also be specified using underscores.
117
+ ### set!
118
+
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.
122
122
 
123
123
  ```ruby
124
- options = TagOptions::Hash.new(class: 'flex')
125
- options.combine_with!(class: 'mt-1', data_controller: 'dropdown')
126
- => {:class=>"flex mt-1", :"data-controller"=>"dropdown"}
124
+ options = TagOptions::Hash.new(class: "flex")
125
+ options.at(:class).set!("block")
126
+ => {:class=>"block"}
127
127
  ```
128
128
 
129
- For ease of use, you can also combine values into a single HTML attribute using `combine_with_<attribute>!`, where
130
- `<attribute>` is the name of the HTML attribute. Dash seperated HTML attributes should be specified using underscores.
129
+ ## Conditional Usage
130
+
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.
131
134
 
132
135
  ```ruby
133
- options = TagOptions::Hash.new(class: 'flex')
134
- options.combine_with_class! 'mt-1'
135
- options.combine_with_data_controller! 'dropdown'
136
- => {:class=>"flex mt-1", :"data-controller"=>"dropdown"}
136
+ # assuming `centered?` returns `true`
137
+ options = TagOptions::Hash.new(class: "flex")
138
+ options.at(:class).combine!("mt-1", "mx-auto": centered?, "mx-2": !centered?)
139
+ => {:class=>"flex mt-1 mx-auto"}
137
140
  ```
138
141
 
139
- ### override!
142
+ ## Custom Property Resolvers
140
143
 
141
- The method `override!` functions nearly the same as `combine_with!` with all same usage patterns, including ease of
142
- use methods, such as `override_class!`. The major difference is that the override methods will not combine specified
143
- values with existing values. Any specified values will override any existing values.
144
+ Chaining `at` to `combine!` or `set!` processes HTML properties similar to
145
+ `class`.
144
146
 
145
- ## Conditional Usage
147
+ - Multiple are allowed
148
+ - Multiple values are seperated by a space
149
+ - Duplicate values are not added
150
+
151
+ Tag Options also ships with a special `style` resolver, which can be used by
152
+ pass `as: :style` to `at`.
146
153
 
147
- Both the `combine_with!` and `override!` allow for values to be conditionally added to HTML attributes using an argument
148
- array. Where the values are added unconditionally and key/value pairs have their key added _IF_ the value is true.
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.
149
160
 
150
161
  ```ruby
151
- # assuming `centered?` returns `true`
152
- options = TagOptions::Hash.new(class: 'flex')
153
- options.combine_with!(class: ['mt-1', 'mx-auto': centered?, 'mx-2': !centered?])
154
- => {:class=>"flex mt-1 mx-auto"}
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;"}
155
165
  ```
156
166
 
157
- The syntax of the `combine_with_<attribute>!` and `override_<attribute>!` ease of use method allow for values and
158
- conditional values to be combined more naturally using a more typical argument pattern.
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).
170
+
171
+ To register a custom handler:
159
172
 
160
173
  ```ruby
161
- # assuming `centered?` returns `true`
162
- options = TagOptions::Hash.new(class: 'flex')
163
- options.combine_with_class!('mt-1', 'mx-auto': centered?, 'mx-2': !centered?)
164
- => {:class=>"flex mt-1 mx-auto"}
174
+ # config/initializers/tag_options.rb
175
+ TagOptions.configure do |config|
176
+ config.register_resolver :custom, "MyCustomResolver"
177
+ end
165
178
  ```
166
179
 
167
180
  ## Development
168
181
 
169
- After checking out the repo, run `bin/setup` to install dependencies. Then, run `bin/test` to run the tests. You can
170
- 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:
171
184
 
172
185
  - `bin/console` for an interactive prompt that will allow you to experiment
173
186
  - `bin/rubocop` to run RuboCop to check the code style and formatting
174
187
 
175
- To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the
176
- version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version,
177
- push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
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).
178
193
 
179
194
  ## Contributing
180
195
 
181
- Bug reports and pull requests are welcome on GitHub at https://github.com/wamonroe/tag_options.
196
+ Bug reports and pull requests are welcome on GitHub at
197
+ https://github.com/wamonroe/tag_options.
182
198
 
183
199
  ## License
184
200
 
185
- The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/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 'bundler/setup'
3
+ require "bundler/setup"
4
4
 
5
- require 'bundler/gem_tasks'
6
- require 'rake/testtask'
5
+ require "bundler/gem_tasks"
6
+ require "rake/testtask"
7
7
 
8
8
  Rake::TestTask.new(:test) do |t|
9
- t.libs << 'test'
10
- t.pattern = 'test/**/*_test.rb'
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
- # frozen_string_literal: true
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
@@ -14,17 +16,22 @@ module TagOptions
14
16
  end
15
17
 
16
18
  class Configuration
17
- attr_writer :fallback_property_handler, :property_handlers
19
+ def initialize
20
+ @resolvers = {
21
+ default: "TagOptions::Resolvers::Default",
22
+ style: "TagOptions::Resolvers::Style"
23
+ }
24
+ end
18
25
 
19
- def fallback_property_handler
20
- @fallback_property_handler ||= 'TagOptions::PropertyHandler::Generic'
26
+ def resolver(name)
27
+ unless (resolver_name = @resolvers[name])
28
+ raise TagOptions::Errors::ResolverError, name
29
+ end
30
+ Object.const_get(resolver_name)
21
31
  end
22
32
 
23
- def property_handlers
24
- @property_handlers ||= [
25
- 'TagOptions::PropertyHandler::Singular',
26
- 'TagOptions::PropertyHandler::Style'
27
- ]
33
+ def register_resolver(name, class_name)
34
+ @resolvers[name] = class_name
28
35
  end
29
36
  end
30
37
  end
@@ -0,0 +1,4 @@
1
+ module TagOptions
2
+ class Error < StandardError
3
+ end
4
+ 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
@@ -0,0 +1,11 @@
1
+ require "tag_options/error"
2
+
3
+ module TagOptions
4
+ module Errors
5
+ class ResolverError < Error
6
+ def initialize(name)
7
+ super("a resolver named `#{name}` has not been registered")
8
+ end
9
+ end
10
+ end
11
+ end
@@ -1,138 +1,33 @@
1
- # frozen_string_literal: true
2
-
3
- require 'active_support/core_ext/string'
4
- require 'forwardable'
5
- require 'tag_options/property_handler/resolve_value'
1
+ require "tag_options/hash_at"
2
+ require "tag_options/errors/not_hash_error"
6
3
 
7
4
  module TagOptions
8
- class Hash
9
- extend Forwardable
10
-
11
- def_delegators :@data, :inspect, :to_h, :to_hash, :to_s, :stringify_keys, :<, :<=, :==, :>, :>=
12
-
13
- # Hashes passed into the initializer are automatically flattened, with nested keys seperated by dashes. For example,
14
- # `data: { controller: 'dropdown' }`` becomes `'data-controller': 'dropdown'`.
15
- def initialize(hash={})
16
- @data = {}
17
- flatten_hash(hash).each do |property, value|
18
- self[property] = value
19
- end
20
- end
21
-
22
- # []
23
- # Underscores in a property name is automatically coverted to dashes. Properties can be specified as strings or
24
- # symbols, both return the same value.
25
- def [](property)
26
- @data[normalize_property(property)]
27
- end
28
-
29
- # []=
30
- # Hashes assigned to a property are automatically flatten, with nested keys seperated by dashes. Underscores in a
31
- # property name are automatically converted to dashes. Propertiess can be specified as strings or symbols, both will
32
- # assign the value to the same property.
33
- def []=(property, value)
34
- if value.is_a?(::Hash)
35
- flatten_hash({ property => value }).each do |flat_property, flat_value|
36
- store(flat_property, flat_value)
37
- end
38
- else
39
- 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
40
9
  end
41
10
  end
42
11
 
43
- # combine_with!
44
- # Allows you to combine values with multiple HTML attributes in one operation. Passed keys should be the HTML
45
- # property to combine the values with. The values can be specified as single string (e.g. `class: 'flex'`) or as an
46
- # argument array (e.g. `class: ['flex', 'mt-2', 'flex-col': layout_column?]`). Hashes in an argument array have
47
- # their keys combined only their value is true. Nested keys will automatically be flattened and combine with the
48
- # associated property (e.g. `data: { controller: 'dropdown' }` would be combined with `data-controller`).
49
- #
50
- # #combine_with!(
51
- # class: ['flex', 'mt-2', 'flex-col': layout_column?],
52
- # data: {
53
- # controller: ['dropdown', 'navbar': navbar?]
54
- # }
55
- # )
56
- #
57
- # TagOptions::Hash also responses to combine_with_<name>!, where `<name>` is the name of the HTML attribute to
58
- # combine the passed argument array with. If `<name>` is specified with a value containing underscores, the HTML
59
- # attribute is converted to dashes, for example: `combine_with_data_controller!` will result in the argument array
60
- # being combined with existing values in `data-controller`.
61
- def combine_with!(hash={})
62
- flatten_hash(hash).each do |property, args|
63
- store(property, self[property], *args)
64
- end
65
- self
66
- end
67
-
68
- # override!
69
- # Allows you to override values on multiple HTML properties in one operation. Passed keys should be the HTML
70
- # properties to override the values of. The values can be passed as single string (e.g. `class: 'flex'`) or as an
71
- # argument array (e.g. `class: ['flex', 'mt-2', 'flex-col': layout_column?]`). Hashes in an argument array have
72
- # their keys added only if their value is true. Nested keys will automatically be flattened and override the value
73
- # at the associated property (e.g. `data: { controller: 'dropdown' }` would override values at `data-controller`).
74
- #
75
- # #override!(
76
- # class: ['flex', 'mt-2', 'flex-col': layout_column?],
77
- # data: {
78
- # controller: ['dropdown', 'navbar': navbar?]
79
- # }
80
- # )
81
- #
82
- # TagOptions::Hash also responses to override_<name>!, where `<name>` is the name of the HTML attribute to override
83
- # the passed argument array on. If `<name>` is specified with a value containing underscores, the resulting HTML
84
- # attribute is automatically nested, for example `override_data_controller!` will result in the argument array
85
- # overriding the existing values in `data-controller`.
86
- def override!(hash={})
87
- flatten_hash(hash).each do |property, args|
88
- store(property, *args)
89
- end
90
- self
12
+ def at(key, *nested_keys, as: :default)
13
+ TagOptions::HashAt.new(opt_hash: self, keys: [key, *nested_keys], as: as)
91
14
  end
92
15
 
93
- private
94
-
95
- def action_matcher
96
- /\A(?<action>combine_with|override)_(?<property>.*)!\z/
16
+ def dig(*keys)
17
+ keys.size.zero? ? self : super
97
18
  end
98
19
 
99
- def flatten_hash(hash)
100
- hash.each_with_object({}) do |(property, value), result|
101
- if value.is_a?(::Hash)
102
- flatten_hash(value).map do |nested_property, nested_value|
103
- result["#{property}-#{nested_property}".to_sym] = nested_value
104
- end
105
- else
106
- result[property] = value
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)
107
28
  end
108
29
  end
109
- end
110
-
111
- def method_missing(method_name, *args, &block)
112
- match_data = action_matcher.match(method_name.to_s)
113
- if match_data
114
- public_send("#{match_data['action']}!", { match_data['property'] => args }, &block)
115
- else
116
- super
117
- end
118
- end
119
-
120
- def store(property, *values, **conditions)
121
- property = normalize_property(property)
122
- value = resolve_value(property, *values, **conditions)
123
- value.empty? ? @data.delete(property) : @data[property] = value
124
- end
125
-
126
- def resolve_value(property, *values, **conditions)
127
- TagOptions::PropertyHandler::ResolveValue.call(property, *values, **conditions)
128
- end
129
-
130
- def normalize_property(property)
131
- property.to_s.downcase.dasherize.to_sym
132
- end
133
-
134
- def respond_to_missing?(method_name, include_private=false)
135
- action_matcher.match?(method_name.to_s) || super
30
+ self
136
31
  end
137
32
  end
138
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
@@ -0,0 +1,11 @@
1
+ require "tag_options/resolver"
2
+
3
+ module TagOptions
4
+ module Resolvers
5
+ class Default < Resolver
6
+ def call
7
+ @values.map { |v| v.to_s.split }.flatten.compact.uniq.join(" ")
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,26 @@
1
+ require "tag_options/resolver"
2
+
3
+ module TagOptions
4
+ module Resolvers
5
+ class Style < Resolver
6
+ def call
7
+ styles.map { |p, v| "#{p}: #{v};" }.join(" ")
8
+ end
9
+
10
+ private
11
+
12
+ def styles
13
+ {}.tap do |result|
14
+ @values.each do |string|
15
+ string.to_s.split(";").compact.each do |property_value_pair|
16
+ property, value = property_value_pair.split(":")
17
+ next unless property && value
18
+
19
+ result[property.strip.downcase.to_sym] = value.strip
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -1,5 +1,3 @@
1
- # frozen_string_literal: true
2
-
3
1
  module TagOptions
4
- VERSION = '0.9.1'
2
+ VERSION = "1.0.0"
5
3
  end
data/lib/tag_options.rb CHANGED
@@ -1,11 +1,8 @@
1
- # frozen_string_literal: true
1
+ require "tag_options/hash"
2
+ require "tag_options/version"
2
3
 
3
- require 'tag_options/property_handler/base'
4
- require 'tag_options/property_handler/generic'
5
- require 'tag_options/property_handler/resolve_value'
6
- require 'tag_options/property_handler/singular'
7
- require 'tag_options/property_handler/style'
8
- require 'tag_options/configuration'
9
- require 'tag_options/hash'
10
- require 'tag_options/railtie'
11
- require 'tag_options/version'
4
+ module TagOptions
5
+ def self.Hash(hash = {})
6
+ TagOptions::Hash.new(hash)
7
+ end
8
+ end
metadata CHANGED
@@ -1,17 +1,17 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tag_options
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.1
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alex Monroe
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-11-08 00:00:00.000000000 Z
11
+ date: 2022-06-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: debug
14
+ name: rspec
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
17
  - - ">="
@@ -24,132 +24,6 @@ dependencies:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0'
27
- - !ruby/object:Gem::Dependency
28
- name: minitest
29
- requirement: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - ">="
32
- - !ruby/object:Gem::Version
33
- version: '0'
34
- type: :development
35
- prerelease: false
36
- version_requirements: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - ">="
39
- - !ruby/object:Gem::Version
40
- version: '0'
41
- - !ruby/object:Gem::Dependency
42
- name: mocha
43
- requirement: !ruby/object:Gem::Requirement
44
- requirements:
45
- - - ">="
46
- - !ruby/object:Gem::Version
47
- version: '0'
48
- type: :development
49
- prerelease: false
50
- version_requirements: !ruby/object:Gem::Requirement
51
- requirements:
52
- - - ">="
53
- - !ruby/object:Gem::Version
54
- version: '0'
55
- - !ruby/object:Gem::Dependency
56
- name: rubocop
57
- requirement: !ruby/object:Gem::Requirement
58
- requirements:
59
- - - ">="
60
- - !ruby/object:Gem::Version
61
- version: '0'
62
- type: :development
63
- prerelease: false
64
- version_requirements: !ruby/object:Gem::Requirement
65
- requirements:
66
- - - ">="
67
- - !ruby/object:Gem::Version
68
- version: '0'
69
- - !ruby/object:Gem::Dependency
70
- name: rubocop-minitest
71
- requirement: !ruby/object:Gem::Requirement
72
- requirements:
73
- - - ">="
74
- - !ruby/object:Gem::Version
75
- version: '0'
76
- type: :development
77
- prerelease: false
78
- version_requirements: !ruby/object:Gem::Requirement
79
- requirements:
80
- - - ">="
81
- - !ruby/object:Gem::Version
82
- version: '0'
83
- - !ruby/object:Gem::Dependency
84
- name: rubocop-performance
85
- requirement: !ruby/object:Gem::Requirement
86
- requirements:
87
- - - ">="
88
- - !ruby/object:Gem::Version
89
- version: '0'
90
- type: :development
91
- prerelease: false
92
- version_requirements: !ruby/object:Gem::Requirement
93
- requirements:
94
- - - ">="
95
- - !ruby/object:Gem::Version
96
- version: '0'
97
- - !ruby/object:Gem::Dependency
98
- name: rubocop-rake
99
- requirement: !ruby/object:Gem::Requirement
100
- requirements:
101
- - - ">="
102
- - !ruby/object:Gem::Version
103
- version: '0'
104
- type: :development
105
- prerelease: false
106
- version_requirements: !ruby/object:Gem::Requirement
107
- requirements:
108
- - - ">="
109
- - !ruby/object:Gem::Version
110
- version: '0'
111
- - !ruby/object:Gem::Dependency
112
- name: shoulda
113
- requirement: !ruby/object:Gem::Requirement
114
- requirements:
115
- - - ">="
116
- - !ruby/object:Gem::Version
117
- version: '0'
118
- type: :development
119
- prerelease: false
120
- version_requirements: !ruby/object:Gem::Requirement
121
- requirements:
122
- - - ">="
123
- - !ruby/object:Gem::Version
124
- version: '0'
125
- - !ruby/object:Gem::Dependency
126
- name: simplecov
127
- requirement: !ruby/object:Gem::Requirement
128
- requirements:
129
- - - ">="
130
- - !ruby/object:Gem::Version
131
- version: '0'
132
- type: :development
133
- prerelease: false
134
- version_requirements: !ruby/object:Gem::Requirement
135
- requirements:
136
- - - ">="
137
- - !ruby/object:Gem::Version
138
- version: '0'
139
- - !ruby/object:Gem::Dependency
140
- name: rails
141
- requirement: !ruby/object:Gem::Requirement
142
- requirements:
143
- - - ">="
144
- - !ruby/object:Gem::Version
145
- version: 5.2.0
146
- type: :runtime
147
- prerelease: false
148
- version_requirements: !ruby/object:Gem::Requirement
149
- requirements:
150
- - - ">="
151
- - !ruby/object:Gem::Version
152
- version: 5.2.0
153
27
  description: Simple library for manipulating options passed to various Rails tag helpers.
154
28
  email:
155
29
  - alex@monroepost.com
@@ -161,18 +35,16 @@ files:
161
35
  - MIT-LICENSE
162
36
  - README.md
163
37
  - Rakefile
164
- - lib/generators/tag_options/install/USAGE
165
- - lib/generators/tag_options/install/install_generator.rb
166
- - lib/generators/tag_options/install/templates/tag_options.rb
167
38
  - lib/tag_options.rb
168
39
  - lib/tag_options/configuration.rb
40
+ - lib/tag_options/error.rb
41
+ - lib/tag_options/errors/not_hash_error.rb
42
+ - lib/tag_options/errors/resolver_error.rb
169
43
  - lib/tag_options/hash.rb
170
- - lib/tag_options/property_handler/base.rb
171
- - lib/tag_options/property_handler/generic.rb
172
- - lib/tag_options/property_handler/resolve_value.rb
173
- - lib/tag_options/property_handler/singular.rb
174
- - lib/tag_options/property_handler/style.rb
175
- - lib/tag_options/railtie.rb
44
+ - lib/tag_options/hash_at.rb
45
+ - lib/tag_options/resolver.rb
46
+ - lib/tag_options/resolvers/default.rb
47
+ - lib/tag_options/resolvers/style.rb
176
48
  - lib/tag_options/version.rb
177
49
  homepage: https://github.com/wamonroe/tag_options
178
50
  licenses:
@@ -196,7 +68,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
196
68
  - !ruby/object:Gem::Version
197
69
  version: '0'
198
70
  requirements: []
199
- rubygems_version: 3.1.6
71
+ rubygems_version: 3.3.7
200
72
  signing_key:
201
73
  specification_version: 4
202
74
  summary: Simple library for manipulating options passed to various Rails tag helpers.
@@ -1,9 +0,0 @@
1
- Description:
2
- Creates a new initializer containing the default settings of the gem.
3
-
4
- Examples:
5
- `rails generate tag_options:install`
6
-
7
- Creates the following:
8
-
9
- Initializer: config/tag_options.rb
@@ -1,11 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module TagOptions
4
- class InstallGenerator < Rails::Generators::Base
5
- source_root File.expand_path('templates', __dir__)
6
-
7
- def copy_initializer
8
- copy_file 'tag_options.rb', 'config/initializers/tag_options.rb'
9
- end
10
- end
11
- end
@@ -1,18 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- TagOptions.configure do |config|
4
- # fallback_property_handler
5
- #
6
- # Defines the default behavior of how values are treated on HTML properties. `TagOptions::PropertyHandler::Generic`
7
- # allows for multiple, unique, values seperated by spaces.
8
- config.fallback_property_handler = 'TagOptions::PropertyHandler::Generic'
9
-
10
- # property_handlers
11
- #
12
- # Allows of the custom handling of HTML properties that match the defined property handler. Properties are handled by
13
- # the first matching property handler.
14
- config.property_handlers = [
15
- 'TagOptions::PropertyHandler::Singular',
16
- 'TagOptions::PropertyHandler::Style'
17
- ]
18
- end
@@ -1,36 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module TagOptions
4
- module PropertyHandler
5
- class Base
6
- attr_reader :values, :conditions
7
-
8
- def initialize(*values, **conditions)
9
- @values = values
10
- @conditions = conditions
11
- end
12
-
13
- def self.call(...)
14
- new(...).call
15
- end
16
-
17
- def self.handler_for?(property_name)
18
- self::MATCHER.match?(property_name.to_s)
19
- end
20
-
21
- private
22
-
23
- def combine_values(*values, **conditions)
24
- resolve_uniq_values(*values, **conditions).join(' ')
25
- end
26
-
27
- def resolve_uniq_values(*values, **conditions)
28
- [*values, *resolve_conditions(conditions)].map { |v| v.to_s.split }.flatten.compact.uniq
29
- end
30
-
31
- def resolve_conditions(conditions)
32
- conditions.select { |_key, value| value }.keys
33
- end
34
- end
35
- end
36
- end
@@ -1,15 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'tag_options/property_handler/base'
4
-
5
- module TagOptions
6
- module PropertyHandler
7
- class Generic < Base
8
- MATCHER = /\A.*\z/.freeze
9
-
10
- def call
11
- combine_values(*values, **conditions)
12
- end
13
- end
14
- end
15
- end
@@ -1,33 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'tag_options/configuration'
4
-
5
- module TagOptions
6
- module PropertyHandler
7
- class ResolveValue
8
- attr_reader :property
9
-
10
- def initialize(property)
11
- @property = property
12
- end
13
-
14
- def call(...)
15
- handler.call(...)
16
- end
17
-
18
- def self.call(property, *values, **conditions)
19
- new(property).call(*values, **conditions)
20
- end
21
-
22
- private
23
-
24
- def handler
25
- TagOptions.configuration.property_handlers.each do |handler_string|
26
- handler = handler_string.constantize
27
- return handler if handler.handler_for?(property)
28
- end
29
- TagOptions.configuration.fallback_property_handler.constantize
30
- end
31
- end
32
- end
33
- end
@@ -1,15 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'tag_options/property_handler/base'
4
-
5
- module TagOptions
6
- module PropertyHandler
7
- class Singular < Base
8
- MATCHER = /\Aid|role|aria-.+\z/.freeze
9
-
10
- def call
11
- resolve_uniq_values(*values, **conditions).last.to_s
12
- end
13
- end
14
- end
15
- end
@@ -1,42 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'tag_options/property_handler/base'
4
-
5
- module TagOptions
6
- module PropertyHandler
7
- class Style < Base
8
- MATCHER = /\Astyle\z/.freeze
9
-
10
- def call
11
- styles.map { |p, v| "#{p}: #{v};" }.join(' ')
12
- end
13
-
14
- private
15
-
16
- def styles
17
- styles_from_values.merge(styles_from_conditions)
18
- end
19
-
20
- def styles_from_values
21
- style_hash_from(values)
22
- end
23
-
24
- def styles_from_conditions
25
- style_hash_from(resolve_conditions(conditions))
26
- end
27
-
28
- def style_hash_from(strings)
29
- {}.tap do |result|
30
- Array(strings).each do |string|
31
- string.to_s.split(';').compact.each do |property_value_pair|
32
- property, value = property_value_pair.split(':')
33
- next unless property && value
34
-
35
- result[property.strip.downcase.to_sym] = value.strip
36
- end
37
- end
38
- end
39
- end
40
- end
41
- end
42
- end
@@ -1,8 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'rails/railtie'
4
-
5
- module TagOptions
6
- class Railtie < ::Rails::Railtie
7
- end
8
- end