html_attrs 1.0.0 → 1.1.1

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.
Files changed (5) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +1 -2
  3. data/README.md +39 -10
  4. data/lib/html_attrs.rb +64 -19
  5. metadata +2 -16
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 81f6299891fbc21d5780803b427e30dfb8e07b6280e518ff974e1e5d9f5d5bbc
4
- data.tar.gz: 58442fc06a5a775c197aba3ad445e23f15f7f68c3a9f69a07e9900b22640193f
3
+ metadata.gz: 737a5e8f52a5be75f40e73f69c877de82a91eb1819f3df87fbe0b0132e004b03
4
+ data.tar.gz: b8e415cab20c7a73a434e6ba8097631cf423d6d2bef6b1c0032cbe4c806804e7
5
5
  SHA512:
6
- metadata.gz: 4cd21bb1474c4ce8be233580048c8dd604e7249ab40d84e55e4eddbda1a3f2f1a2deb9ca7ecc74e665905a61dcab2df23f76341834845ba4ed9e7a9a3ab58e6a
7
- data.tar.gz: 492c60112a6c93c069f5e93ef43203d2a0f75b61456e40714d027c9604c45dec847dd1ea4fece6b91ceb1ae6025bac1e7ea1b2c65764299897e10ec87f141762
6
+ metadata.gz: 712b755dc31f8af3e613b492ef999a53ba1b8c0d53f2a63b9c6c81ffbe1be63c01a6d4bd2b268b68455be9f6f7b70e13ed5a49e9ff9b4a0cbcb6598abd249d05
7
+ data.tar.gz: ed08332771a5cb04194e93b5e6c3405f3d3322c15f513d865777b172de0af1140a104e6ff0920f595aa483f8fd60c091113427952ab86f9cf781097e4f4e849d
data/Gemfile.lock CHANGED
@@ -1,9 +1,8 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- html_attrs (0.1.0)
4
+ html_attrs (1.1.0)
5
5
  actionview (>= 6.0)
6
- activesupport (>= 6.0)
7
6
 
8
7
  GEM
9
8
  remote: https://rubygems.org/
data/README.md CHANGED
@@ -16,7 +16,7 @@ $ bundle add html_attrs
16
16
  ```ruby
17
17
  html_attrs = {
18
18
  class: 'bg-primary-500', data: { controller: 'popover', action: 'click->popover#toggle' }
19
- }.as_html_attrs
19
+ }
20
20
 
21
21
  html_attrs = html_attrs.smart_merge(
22
22
  class: 'border border-primary-500', data: { controller: 'slideover' }, href: '#'
@@ -28,6 +28,7 @@ html_attrs = html_attrs.smart_merge(
28
28
  data: { controller: 'popover slideover', action: 'click->popover#toggle' },
29
29
  href: '#'
30
30
  }
31
+ # Note: #smart_merge returns an HtmlAttrs object which is a subclass of Hash, so you can use it just like a hash.
31
32
  ```
32
33
 
33
34
  You can use this in helpers that accept HTML attributes as a hash, e.g:
@@ -62,7 +63,35 @@ You can also use the `to_s` method to get the string representation of the HTML
62
63
  </a>
63
64
  ```
64
65
 
66
+ Merging is done recursively:
67
+ * Strings are merged by concatenating them with a space.
68
+ * Arrays are merged with simple concatenation.
69
+ * Hashes are merged recursively using the above rules.
70
+ * Everything else is merged normally, just like with `Hash#merge`.
71
+
72
+ Super simple, but super powerful.
73
+
74
+ If one hash that has a string key and the other has a symbol key or vice-versa, we'll convert everything to whatever the first hash has.
75
+
76
+ ## Configuring mergeable attributes
77
+
78
+ By default, this gem merges `class`, `style` and `data` attributes recursively. Which should usually be more than enough. You can easily customize this by specifying `mergeable_attributes:` when calling `smart_merge`. e.g:
79
+ ```ruby
80
+ HtmlAttrs.new(class: 'bg-primary-500', id: 'test', aria_label: 'Help')
81
+ .smart_merge(aria_label: 'Another', href: '/test', mergeable_attributes: [:aria_label])
82
+ # => { class: 'bg-primary-500', id: 'test', aria_label: 'Help Another', href: '/test' }
83
+ ```
84
+
85
+ You can also just set `mergeable_attributes: :all` to merge everything. Or you can just use `smart_merge_all` which merges everything by default.
65
86
 
87
+ ```ruby
88
+ { class: 'bg-primary-500', id: 'test', aria_label: 'Help' }
89
+ .smart_merge_all(class: 'text-red-500', aria_label: 'Another', href: '/test')
90
+ # => { class: 'bg-primary-500 text-red-500', id: 'test', aria_label: 'Help Another', href: '/test' }
91
+ ```
92
+
93
+
94
+ ## Other ways to use
66
95
  Alternative, you can use the `HtmlAttrs` class directly, e.g:
67
96
  ```ruby
68
97
  HtmlAttrs.smart_merge(
@@ -81,18 +110,18 @@ html_attrs.smart_merge( id: 'test', class: 'border')
81
110
  # => { class: 'bg-primary-500 border', data: { controller: 'popover' }, id: 'test' }
82
111
  ```
83
112
 
84
- Under the hood, `HtmlAttrs` is a simple wrapper around `ActiveSupport::HashWithIndifferentAccess`, so you can use it just like any other hash. The only difference is `#smart_merge` and `to_s`.
113
+ Under the hood, `HtmlAttrs` is a simple wrapper around `Hash`, so you can use it just like any other hash. The only difference is `#smart_merge`, `#smart_merge_all` and `to_s`.
85
114
 
86
- Merging is done recursively. Strings are merged by concatenating them with a space. Arrays are merged with simple concatenation. Hashes are merged recursively using the above rules. Everything else is merged normally, just like with `Hash#merge`. Super simple, but super powerful.
115
+ <br/>
87
116
 
88
- ## Configuring mergeable attributes
117
+ ## Interested in a powerful Rails UI library?
89
118
 
90
- By default, this gem merges `class`, `style` and `data` attributes recursively. Which should usually be more than enough. You can easily customize this by specifying `mergeable_attributes:` when calling `smart_merge`. e.g:
91
- ```ruby
92
- HtmlAttrs.new(class: 'bg-primary-500', id: 'test', aria_label: 'Help')
93
- .smart_merge(aria_label: 'Another', href: '/test', mergeable_attributes: [:aria_label])
94
- # => { class: 'bg-primary-500', id: 'test', aria_label: 'Help Another', href: '/test' }
95
- ```
119
+ I am working on a super-powerful Rails UI library - components as well as templates & patterns.
120
+
121
+ [Please check this out if you're interested](https://owaiskhan.me/rails-ui-library).
122
+ <br/>
123
+ <br/>
124
+ <br/>
96
125
 
97
126
  ## Development
98
127
 
data/lib/html_attrs.rb CHANGED
@@ -1,16 +1,38 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'action_view'
4
- require 'active_support/core_ext/hash/indifferent_access'
4
+ require 'bigdecimal' # tag_options references BigDecimal. Just require it here so non autoloading environments work.
5
5
 
6
- class HtmlAttrs < HashWithIndifferentAccess
7
- VERSION = '1.0.0'
6
+ class HtmlAttrs < Hash
7
+ VERSION = '1.1.1'
8
8
  DEFAULT_MERGEABLE_ATTRIBUTES = %i[class style data].to_set
9
9
 
10
- def smart_merge(other)
11
- mergeable_attributes = other.delete(:mergeable_attributes) if other.is_a?(Hash) && other.key?(:mergeable_attributes)
10
+ def initialize(constructor = nil)
11
+ if constructor.respond_to?(:to_hash)
12
+ super()
13
+ update(constructor)
14
+
15
+ hash = constructor.is_a?(Hash) ? constructor : constructor.to_hash
16
+ self.default = hash.default if hash.default
17
+ self.default_proc = hash.default_proc if hash.default_proc
18
+ elsif constructor.nil?
19
+ super()
20
+ else
21
+ super(constructor)
22
+ end
23
+ end
24
+
25
+ def smart_merge(target)
26
+ if target.is_a?(Hash) && target.key?(:mergeable_attributes)
27
+ mergeable_attributes = target.delete(:mergeable_attributes)
28
+ end
12
29
  mergeable_attributes ||= DEFAULT_MERGEABLE_ATTRIBUTES
13
- self.class.smart_merge(self, other, mergeable_attributes: mergeable_attributes)
30
+ self.class.smart_merge(self, target, mergeable_attributes: mergeable_attributes)
31
+ end
32
+
33
+ def smart_merge_all(target)
34
+ target[:mergeable_attributes] = :all if target.is_a?(Hash)
35
+ smart_merge(target)
14
36
  end
15
37
 
16
38
  def to_s
@@ -18,37 +40,48 @@ class HtmlAttrs < HashWithIndifferentAccess
18
40
  end
19
41
 
20
42
  def self.smart_merge(other, target, mergeable_attributes: DEFAULT_MERGEABLE_ATTRIBUTES)
21
- other = other.with_indifferent_access if other.is_a?(Hash) && !other.is_a?(HashWithIndifferentAccess)
22
- target = target.with_indifferent_access if target.is_a?(Hash) && !target.is_a?(HashWithIndifferentAccess)
23
-
24
43
  return other if target.nil?
25
44
  return target if other.nil?
26
45
 
27
46
  if target.is_a?(Hash) || other.is_a?(Hash)
28
- raise 'Expected target to be a hash or nil' if !target.nil? && !target.is_a?(Hash)
29
- raise 'Expected other to be a hash or nil' if !other.nil? && !other.is_a?(Hash)
47
+ raise 'Expected target to be a hash or nil' unless target.is_a?(Hash)
48
+ raise 'Expected other to be a hash or nil' unless other.is_a?(Hash)
49
+
50
+ other = other.dup
51
+ target = target.dup
30
52
 
31
53
  target.each do |key, value|
32
- other[key] =
33
- if other.key?(key) && attribute_mergeable?(key, mergeable_attributes)
34
- smart_merge(other[key], value, mergeable_attributes: :all)
54
+ other_type_of_key = key.is_a?(Symbol) ? key.to_s : key.to_sym
55
+
56
+ key_with_value = if other.key?(key)
57
+ key
58
+ elsif other.key?(other_type_of_key)
59
+ other_type_of_key
60
+ else
61
+ nil
62
+ end
63
+
64
+ other[key_with_value || key] =
65
+ if key_with_value && attribute_mergeable?(key, mergeable_attributes)
66
+ smart_merge(other[key_with_value], value, mergeable_attributes: :all)
35
67
  else
36
68
  value
37
69
  end
38
70
  end
71
+
39
72
  return other
40
73
  end
41
74
 
42
75
  if target.is_a?(Array) || other.is_a?(Array)
43
- raise 'Expected target to be an array or nil' if !target.nil? && !target.is_a?(Array)
44
- raise 'Expected other to be an array or nil' if !other.nil? && !other.is_a?(Array)
76
+ raise 'Expected target to be an array or nil' unless target.is_a?(Array)
77
+ raise 'Expected other to be an array or nil' unless other.is_a?(Array)
45
78
 
46
- return (other || []).concat(target || [])
79
+ return (other.dup || []).concat(target.dup || [])
47
80
  end
48
81
 
49
82
  if target.is_a?(String) || other.is_a?(String)
50
- raise 'Expected target to be a string or nil' if !target.nil? && !target.is_a?(String)
51
- raise 'Expected other to be a string or nil' if !other.nil? && !other.is_a?(String)
83
+ raise 'Expected target to be a string or nil' unless target.is_a?(String)
84
+ raise 'Expected other to be a string or nil' unless other.is_a?(String)
52
85
 
53
86
  return [other.presence, target.presence].compact.join(' ')
54
87
  end
@@ -56,6 +89,10 @@ class HtmlAttrs < HashWithIndifferentAccess
56
89
  target
57
90
  end
58
91
 
92
+ def self.smart_merge_all(other, target)
93
+ smart_merge(other, target, mergeable_attributes: :all)
94
+ end
95
+
59
96
  def self.attribute_mergeable?(attribute, mergeable_attributes)
60
97
  return true if mergeable_attributes == :all
61
98
 
@@ -75,4 +112,12 @@ class Hash
75
112
  def as_html_attrs
76
113
  HtmlAttrs.new(self)
77
114
  end
115
+
116
+ def smart_merge(target)
117
+ as_html_attrs.smart_merge(target)
118
+ end
119
+
120
+ def smart_merge_all(target)
121
+ as_html_attrs.smart_merge_all(target)
122
+ end
78
123
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: html_attrs
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Owais
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-03-16 00:00:00.000000000 Z
11
+ date: 2024-03-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: actionview
@@ -24,20 +24,6 @@ dependencies:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: '6.0'
27
- - !ruby/object:Gem::Dependency
28
- name: activesupport
29
- requirement: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - ">="
32
- - !ruby/object:Gem::Version
33
- version: '6.0'
34
- type: :runtime
35
- prerelease: false
36
- version_requirements: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - ">="
39
- - !ruby/object:Gem::Version
40
- version: '6.0'
41
27
  description: A gem that provides a way to smartly merge HTML attributes
42
28
  email:
43
29
  - owaiswiz@gmail.com