tag_options 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: a5fb04a9c092cabe732ee9a7807861f8a2587b22e9221836d42bf9c2400856be
4
+ data.tar.gz: 229782a164b543562f6f988a7afb486c26715d55f825862bd4a32b0dfd33e42c
5
+ SHA512:
6
+ metadata.gz: 484238573bfd185df2f607efff78d33258c2dbbeff55498ebf1d5d39e9610e374676d8e0a0ebafc32b39bf942717c21e843290d724b3f3ec129a5936ccaf7bb7
7
+ data.tar.gz: 5705a6389364ef3d5761e77b96d41dec2ac225f7deaefcf3995a462221f09aaf65037c3f38b7f838d42021731d1ed82630e0393326f4e023201c87755a599b16
data/CHANGELOG.md ADDED
@@ -0,0 +1,7 @@
1
+ # Changelog
2
+
3
+ ## [Unreleased]
4
+
5
+ ## [0.9.0] - 2021-11-03
6
+
7
+ - Initial release
data/MIT-LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2021 Alex Monroe
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,175 @@
1
+ # Tag Options
2
+
3
+ Simple library for manipulating options passed to the Rails `tag`, `content_tag`, and other tag helpers.
4
+
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.
7
+
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
+
11
+ ```ruby
12
+ def external_link_to(name, url, options={})
13
+ options = TagOptions::Hash.new(options)
14
+ options.combine_with_class!('external-link')
15
+ link_to(name, url, options)
16
+ end
17
+ ```
18
+
19
+ Called with:
20
+
21
+ ```ruby
22
+ external_link_to('Example', 'https://example.com', class: 'ml-2')
23
+ ```
24
+
25
+ Would render:
26
+
27
+ ```html
28
+ <a href="https://example.com" class="ml-2 external-link">Example</a>
29
+ ```
30
+
31
+ ## Table of Contents
32
+
33
+ - [Installation](#installation)
34
+ - [General Usage](#general-usage)
35
+ - [combine_with!](#combinewith)
36
+ - [override!](#override)
37
+ - [Conditional Usage](#conditional-usage)
38
+ - [Development](#development)
39
+ - [Contributing](#contributing)
40
+ - [License](#license)
41
+
42
+ ## Installation
43
+
44
+ Add this line to your application's Gemfile:
45
+
46
+ ```ruby
47
+ gem 'tag_options'
48
+ ```
49
+
50
+ And then execute:
51
+
52
+ ```sh
53
+ bundle install
54
+ ```
55
+
56
+ ## General Usage
57
+
58
+ Initialize a `TagOptions::Hash` directly or by passing an existing `Hash`.
59
+
60
+ ```ruby
61
+ TagOptions::Hash.new
62
+ => {}
63
+
64
+ hash = {class: 'flex'}
65
+ TagOptions::Hash.new(hash)
66
+ => {:class=>"flex"}
67
+ ```
68
+
69
+ ### combine_with!
70
+
71
+ Combine HTML attributes with an existing `TagOptions::Hash` using `combine_with!`
72
+
73
+ ```ruby
74
+ options = TagOptions::Hash.new(class: 'flex')
75
+ options.combine_with!(class: 'mt-1')
76
+ => {:class=>"flex mt-1"}
77
+ ```
78
+
79
+ Values can also be specified as arrays.
80
+
81
+ ```ruby
82
+ options = TagOptions::Hash.new(class: 'flex')
83
+ options.combine_with!(class: ['mt-1', 'mx-2'])
84
+ => {:class=>"flex mt-1 mx-2"}
85
+ ```
86
+
87
+ HTML attributes are only added if they don't already exist.
88
+
89
+ ```ruby
90
+ options = TagOptions::Hash.new(class: 'flex')
91
+ options.combine_with!(class: 'flex flex-col')
92
+ => {:class=>"flex flex-col"}
93
+ ```
94
+
95
+ You can also combine multiple HTML attributes in one operation.
96
+
97
+ ```ruby
98
+ options = TagOptions::Hash.new(class: 'flex')
99
+ options.combine_with!(class: 'mt-1', 'data-controller': 'dropdown')
100
+ => {:class=>"flex mt-1", :"data-controller"=>"dropdown"}
101
+ ```
102
+
103
+ Dash seperated HTML attributes, such as `data-controller` can also be specified as nested hashes.
104
+
105
+ ```ruby
106
+ options = TagOptions::Hash.new(class: 'flex')
107
+ options.combine_with!(class: 'mt-1', data: { controller: 'dropdown' })
108
+ => {:class=>"flex mt-1", :"data-controller"=>"dropdown"}
109
+ ```
110
+
111
+ Dash seperated HTML attributes can also be specified using underscores.
112
+
113
+ ```ruby
114
+ options = TagOptions::Hash.new(class: 'flex')
115
+ options.combine_with!(class: 'mt-1', data_controller: 'dropdown')
116
+ => {:class=>"flex mt-1", :"data-controller"=>"dropdown"}
117
+ ```
118
+
119
+ For ease of use, you can also combine values into a single HTML attribute using `combine_with_<attribute>!`, where
120
+ `<attribute>` is the name of the HTML attribute. Dash seperated HTML attributes should be specified using underscores.
121
+
122
+ ```ruby
123
+ options = TagOptions::Hash.new(class: 'flex')
124
+ options.combine_with_class! 'mt-1'
125
+ options.combine_with_data_controller! 'dropdown'
126
+ => {:class=>"flex mt-1", :"data-controller"=>"dropdown"}
127
+ ```
128
+
129
+ ### override!
130
+
131
+ The method `override!` functions nearly the same as `combine_with!` with all same usage patterns, including ease of
132
+ use methods, such as `override_class!`. The major difference is that the override methods will not combine specified
133
+ values with existing values. Any specified values will override any existing values.
134
+
135
+ ## Conditional Usage
136
+
137
+ Both the `combine_with!` and `override!` allow for values to be conditionally added to HTML attributes using an argument
138
+ array. Where the values are added unconditionally and key/value pairs have their key added _IF_ the value is true.
139
+
140
+ ```ruby
141
+ # assuming `centered?` returns `true`
142
+ options = TagOptions::Hash.new(class: 'flex')
143
+ options.combine_with!(class: ['mt-1', 'mx-auto': centered?, 'mx-2': !centered?])
144
+ => {:class=>"flex mt-1 mx-auto"}
145
+ ```
146
+
147
+ The syntax of the `combine_with_<attribute>!` and `override_<attribute>!` ease of use method allow for values and
148
+ conditional values to be combined more naturally using a more typical argument pattern.
149
+
150
+ ```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"}
155
+ ```
156
+
157
+ ## Development
158
+
159
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `bin/test` to run the tests. You can
160
+ also run:
161
+
162
+ - `bin/console` for an interactive prompt that will allow you to experiment
163
+ - `bin/rubocop` to run RuboCop to check the code style and formatting
164
+
165
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the
166
+ version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version,
167
+ push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
168
+
169
+ ## Contributing
170
+
171
+ Bug reports and pull requests are welcome on GitHub at https://github.com/wamonroe/tag_options.
172
+
173
+ ## License
174
+
175
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/setup'
4
+
5
+ require 'bundler/gem_tasks'
6
+ require 'rake/testtask'
7
+
8
+ Rake::TestTask.new(:test) do |t|
9
+ t.libs << 'test'
10
+ t.pattern = 'test/**/*_test.rb'
11
+ t.verbose = false
12
+ end
13
+
14
+ task default: :test
@@ -0,0 +1,140 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'active_support/core_ext/string'
4
+ require 'forwardable'
5
+
6
+ module TagOptions
7
+ class Hash
8
+ extend Forwardable
9
+
10
+ def_delegators :@data, :inspect, :to_s, :stringify_keys, :<, :<=, :==, :>, :>=
11
+
12
+ # Hashes passed into the initializer are automatically flattened, with nested keys seperated by dashes. For example,
13
+ # `data: { controller: 'dropdown' }`` becomes `'data-controller': 'dropdown'`.
14
+ def initialize(hash={})
15
+ @data = {}
16
+ flatten_hash(hash).each do |key, value|
17
+ self[key] = value
18
+ end
19
+ end
20
+
21
+ # []
22
+ # Underscores in a key name is automatically coverted to dashes. Keys can be specified as strings or symbols, both
23
+ # return the same value.
24
+ def [](key)
25
+ @data[normalize_key(key)]
26
+ end
27
+
28
+ # []=
29
+ # Hashes assigned to a key are automatically flatten, with nested keys seperated by dashes. Underscores in a key
30
+ # name is automatically converted to dashes. Keys can be specified as strings or symbols, both will assign the value
31
+ # to the same key.
32
+ def []=(key, value)
33
+ if value.is_a?(::Hash)
34
+ flatten_hash({ key => value }).each do |flat_key, flat_value|
35
+ @data[normalize_key(flat_key)] = flat_value
36
+ end
37
+ else
38
+ @data[normalize_key(key)] = value
39
+ end
40
+ end
41
+
42
+ # combine_with!
43
+ # Allows you to combine values with multiple HTML attributes in one operation. Passed keys should be the HTML
44
+ # attributes to combine the values with. The values can be passed as single value (e.g. `class: 'flex'`) or as an
45
+ # argument array (e.g. `class: ['flex', 'mt-2', 'flex-col': layout_column?]`). Hashes in an argument array have
46
+ # their keys combined only their value is true. Nested keys will automatically be flattened and combine with the
47
+ # associated key (e.g. `data: { controller: 'dropdown' }` would be combined with `data-controller`).
48
+ #
49
+ # #combine_with!(
50
+ # class: ['flex', 'mt-2', 'flex-col': layout_column?],
51
+ # data: {
52
+ # controller: ['dropdown', 'navbar': navbar?]
53
+ # }
54
+ # )
55
+ #
56
+ # TagOptions::Hash also responses to combine_with_<name>!, where `<name>` is the name of the HTML attribute to
57
+ # combine the passed argument array with. If `<name>` is specified with a value containing underscores, the HTML
58
+ # attribute is converted to dashes, for example: `combine_with_data_controller!` will result in the argument array
59
+ # being combined with existing values in `data-controller`.
60
+ def combine_with!(hash={})
61
+ flatten_hash(hash).each do |key, args|
62
+ self[key] = combine_values(self[key], *args)
63
+ end
64
+ self
65
+ end
66
+
67
+ # override!
68
+ # Allows you to override values on multiple HTML attributes in one operation. Passed keys should be the HTML
69
+ # attributes to override the values of. The values can be passed as single string (e.g. `class: 'flex'`) or as an
70
+ # argument array (e.g. `class: ['flex', 'mt-2', 'flex-col': layout_column?]`). Hashes in an argument array have
71
+ # their keys added only if their value is true. Nested keys will automatically be flattened and override the value
72
+ # at the associated key (e.g. `data: { controller: 'dropdown' }` would override values at `data-controller`).
73
+ #
74
+ # #override!(
75
+ # class: ['flex', 'mt-2', 'flex-col': layout_column?],
76
+ # data: {
77
+ # controller: ['dropdown', 'navbar': navbar?]
78
+ # }
79
+ # )
80
+ #
81
+ # TagOptions::Hash also responses to override_<name>!, where `<name>` is the name of the HTML attribute to override
82
+ # the passed argument array on. If `<name>` is specified with a value containing underscores, the resulting HTML
83
+ # attribute is automatically nested, for example `override_data_controller!` will result in the argument array
84
+ # overriding the existing values in `data-controller`.
85
+ def override!(hash={})
86
+ flatten_hash(hash).each do |key, args|
87
+ self[key] = combine_values(*args)
88
+ end
89
+ self
90
+ end
91
+
92
+ def to_h
93
+ @data.transform_values { |value| value.is_a?(::TagOptions::Hash) ? value.to_h : value }
94
+ end
95
+ alias to_hash to_h
96
+
97
+ private
98
+
99
+ def action_matcher
100
+ /\A(?<action>combine_with|override)_(?<key>.*)!\z/
101
+ end
102
+
103
+ def combine_values(*values, **conditions)
104
+ [*values, *resolve_conditions(conditions.to_h)].map { |v| v.to_s.split }.flatten.compact.uniq.join(' ')
105
+ end
106
+
107
+ def flatten_hash(hash)
108
+ hash.each_with_object({}) do |(key, value), result|
109
+ if value.is_a?(::Hash)
110
+ flatten_hash(value).map do |nested_key, nested_value|
111
+ result["#{key}-#{nested_key}".to_sym] = nested_value
112
+ end
113
+ else
114
+ result[key] = value
115
+ end
116
+ end
117
+ end
118
+
119
+ def method_missing(method_name, *args, &block)
120
+ match_data = action_matcher.match(method_name.to_s)
121
+ if match_data
122
+ public_send("#{match_data['action']}!", { match_data['key'] => args }, &block)
123
+ else
124
+ super
125
+ end
126
+ end
127
+
128
+ def normalize_key(key)
129
+ key.to_s.downcase.dasherize.to_sym
130
+ end
131
+
132
+ def resolve_conditions(conditions)
133
+ conditions.select { |_key, value| value }.keys
134
+ end
135
+
136
+ def respond_to_missing?(method_name, include_private=false)
137
+ action_matcher.match?(method_name.to_s) || super
138
+ end
139
+ end
140
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails/railtie'
4
+
5
+ module TagOptions
6
+ class Railtie < ::Rails::Railtie
7
+ end
8
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TagOptions
4
+ VERSION = '0.9.0'
5
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'tag_options/hash'
4
+ require 'tag_options/railtie'
5
+ require 'tag_options/version'
metadata ADDED
@@ -0,0 +1,194 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: tag_options
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.9.0
5
+ platform: ruby
6
+ authors:
7
+ - Alex Monroe
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2021-11-04 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: debug
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
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
+ description: Simple library for manipulating options passed to various Rails tag helpers.
154
+ email:
155
+ - alex@monroepost.com
156
+ executables: []
157
+ extensions: []
158
+ extra_rdoc_files: []
159
+ files:
160
+ - CHANGELOG.md
161
+ - MIT-LICENSE
162
+ - README.md
163
+ - Rakefile
164
+ - lib/tag_options.rb
165
+ - lib/tag_options/hash.rb
166
+ - lib/tag_options/railtie.rb
167
+ - lib/tag_options/version.rb
168
+ homepage: https://github.com/wamonroe/tag_options
169
+ licenses:
170
+ - MIT
171
+ metadata:
172
+ homepage_uri: https://github.com/wamonroe/tag_options
173
+ source_code_uri: https://github.com/wamonroe/tag_options
174
+ changelog_uri: https://github.com/wamonroe/tag_options/blob/main/CHANGELOG.md
175
+ post_install_message:
176
+ rdoc_options: []
177
+ require_paths:
178
+ - lib
179
+ required_ruby_version: !ruby/object:Gem::Requirement
180
+ requirements:
181
+ - - ">="
182
+ - !ruby/object:Gem::Version
183
+ version: 2.7.0
184
+ required_rubygems_version: !ruby/object:Gem::Requirement
185
+ requirements:
186
+ - - ">="
187
+ - !ruby/object:Gem::Version
188
+ version: '0'
189
+ requirements: []
190
+ rubygems_version: 3.1.6
191
+ signing_key:
192
+ specification_version: 4
193
+ summary: Simple library for manipulating options passed to various Rails tag helpers.
194
+ test_files: []