htmx 2.3.0 → 2.4.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: fd7f8848ffbbb9b0dda865c24c70f45f875e34a12ddb61a85e440e40b10415c1
4
- data.tar.gz: 071faebe65dddd6017d61e27d8a9c340830983a92b892d2082bcd58dbdce3a5b
3
+ metadata.gz: ee8016cd8fd02737e4aad162cb344f30e3b2b87a86758551ef7eb8af1e95987a
4
+ data.tar.gz: e8dbf7897d7a0acf0403c8e828aac1934c63f9c95843c0c7a6e81fba458bb393
5
5
  SHA512:
6
- metadata.gz: dd59012b00b6e3e602276d0ef2915b550384bb891d18d2d5b5cde20c795dc1dfe7e6e833bd10ebcbb2c9f07c19f34404437a2e88bf7ae61a0ea30438d58c0a71
7
- data.tar.gz: 1e396b2e3ba527fe84144f17e3e72a1b2a0b0ebf8685b904c8d1cac59e488faee72bff69cb91838ff6640596c2cdf2313b9bd681b8f9fde55fa2198f9aa695af
6
+ metadata.gz: b030354b85254e808ae6dd58d87f388a428a2a1997e89912647cf3a0bcdff2335b28dc98b788dfc8aa0b17d415df6957773c1658f8826cfd60c7ffc6f2214024
7
+ data.tar.gz: bdeed94be9d9ba5c4d794955fbe289616b946eebe531518fcb91a4bbe6dca32eec0fcb64bde9eb77f3c10f51c20ae741d9a49d1b4a270c8a0e8393669110a899
checksums.yaml.gz.sig CHANGED
Binary file
data/README.adoc CHANGED
@@ -2,7 +2,7 @@
2
2
  :toclevels: 5
3
3
  :figure-caption!:
4
4
 
5
- :htmx_link: link:https://htmx.org[HTMX]
5
+ :htmx_link: link:https://htmx.org[htmx]
6
6
  :hypermedia_systems_link: link:https://hypermedia.systems[Hypermedia Systems]
7
7
  :hanami_link: link:https://hanamirb.org[Hanami]
8
8
  :roda_link: link:http://roda.jeremyevans.net[Roda]
@@ -22,14 +22,12 @@ already in hand
22
22
  ...and from {hypermedia_systems_link}:
23
23
 
24
24
  ____
25
- The goal of [HTMX] is not less JavaScript, but less code, more readable and hypermedia-friendly code.
25
+ The goal of [htmx] is not less JavaScript, but less code, more readable and hypermedia-friendly code.
26
26
  ____
27
27
 
28
28
 
29
29
  This gem provides native Ruby support for the {htmx_link} JavaScript library so you can build sophisticated web applications using pure Hypermedia REST APIs while avoiding unnecessary bloat and complexity common with the JavaScript ecosystem. By building upon the original foundations of Hypermedia REST APIs, you can build rich web applications with no additional JavaScript!
30
30
 
31
- At the moment, the functionality of this gem is still in the early stages of development but the goal of this gem is to aid with the development of {htmx_link} applications.
32
-
33
31
  💡 This is used with the {hanamismith_link} gem when building {hanami_link} applications. Even better, you can play with the link:https://github.com/bkuhlmann/hemo[Hanami demo application] to learn more. Enjoy!
34
32
 
35
33
  toc::[]
@@ -80,7 +78,7 @@ require "htmx"
80
78
 
81
79
  == Usage
82
80
 
83
- One of the first tasks you'll want to tackle, when working with the {htmx_link} library, is building HTMX specific HTML attributes. This can be accomplished by using the `.[]` method. For example, when implementing a {hanami_link} view part, you could use the following:
81
+ One of the first tasks you'll want to tackle, when working with the {htmx_link} library, is building htmx specific HTML attributes. This can be accomplished by using the `.[]` method. For example, when implementing a {hanami_link} view part, you could use the following:
84
82
 
85
83
  [source,ruby]
86
84
  ----
@@ -101,11 +99,11 @@ The above would produce the following:
101
99
  </button>
102
100
  ----
103
101
 
104
- Notice the appropriate HTMX `hx-target` and `hx-delete` attributes are built which are compatible with the {htmx_link} library while not having to manually prefix each one of these attributes with the `hx-` prefix. You can even use symbols, strings, or a mix of both as well.
102
+ Notice the appropriate htmx `hx-target` and `hx-delete` attributes are built which are compatible with the {htmx_link} library while not having to manually prefix each one of these attributes with the `hx-` prefix. You can use symbols, strings, or a mix of both as well.
105
103
 
106
104
  === HTML Attribute Prefixes
107
105
 
108
- As shown above, building HTMX attributes takes minimal effort but if you'd prefer the HTML `data-` prefix, which the {htmx_link} library supports, you can customize by using the following:
106
+ As shown above, building htmx attributes takes minimal effort but if you'd prefer the HTML `data-` prefix, which the {htmx_link} library supports, you can customize by using the following:
109
107
 
110
108
  [source,ruby]
111
109
  ----
@@ -132,7 +130,7 @@ This would then produce the following HTML code:
132
130
  </button>
133
131
  ----
134
132
 
135
- As you can see, the `data-hx-target` and `data-hx-delete` keys are used. These are definitely more verbose than the `hx-` keys. By the way, the `HTMX::Prefixer` is called when using the HTMX `.[]` as shown earlier. This means the following are equivalent:
133
+ As you can see, the `data-hx-target` and `data-hx-delete` keys are used. These are definitely more verbose than the `hx-` keys. By the way, the `HTMX::Prefixer` is called when using the htmx `.[]` as shown earlier. This means the following are equivalent:
136
134
 
137
135
  [source,ruby]
138
136
  ----
@@ -151,7 +149,7 @@ HTMX::Prefixer.new "bogus"
151
149
  # Invalid prefix: "bogus". Use: "hx" or "data-hx". (HTMX::Error)
152
150
  ----
153
151
 
154
- Some {htmx_link} attributes use dashes. For those situations, you can use strings for keys or underscored symbols to produce the correct HTMX syntax. Here's and example using both a string and symbol for keys:
152
+ Some {htmx_link} attributes use dashes. For those situations, you can use strings for keys or underscored symbols to produce the correct htmx syntax. Here's an example using both a string and symbol for keys:
155
153
 
156
154
  [source,ruby]
157
155
  ----
@@ -161,15 +159,15 @@ HTMX["swap-oob" => true, push_url: "/demo/123"]
161
159
 
162
160
  === HTTP Headers
163
161
 
164
- When working with HTTP requests/responses, especially HTTP headers, there are a few objects that can parse and make the data easier to work with. These objects are named accordingly: request and response. Here's how to use them.
162
+ When working with HTTP requests/responses, especially HTTP headers, there are a couple of methods that can parse and make the data easier to work with. Here's how to use them.
165
163
 
166
- ==== Request
164
+ ==== Requests
167
165
 
168
- The request object allows you to obtain a {data_link} object to interact with when parsing link:https://htmx.org/reference/#request_headers[HTMX HTTP request headers]. Example:
166
+ The request object allows you to obtain a {data_link} object to interact with when parsing link:https://htmx.org/reference/#request_headers[htmx HTTP request headers]. Example:
169
167
 
170
168
  [source,ruby]
171
169
  ----
172
- HTMX::Headers::Request.new
170
+ HTMX.request
173
171
 
174
172
  # <data HTMX::Headers::Request boosted=nil,
175
173
  # current_url=nil,
@@ -186,11 +184,18 @@ Notice you get a {data_link} instance where all members have the `HX-` prefix re
186
184
 
187
185
  [source,ruby]
188
186
  ----
189
- HTMX::Headers::Request.for request.env
187
+ HTMX.request "HTTP_HX_BOOSTED" => "true",
188
+ "HTTP_HX_CURRENT_URL" => "/demo",
189
+ "HTTP_HX_HISTORY_RESTORE_REQUEST" => "false",
190
+ "HTTP_HX_PROMPT" => "Yes",
191
+ "HTTP_HX_REQUEST" => "true",
192
+ "HTTP_HX_TARGET" => "demo",
193
+ "HTTP_HX_TRIGGER_NAME" => "save",
194
+ "HTTP_HX_TRIGGER" => "demo"
190
195
 
191
196
  # <data HTMX::Headers::Request boosted="true",
192
197
  # current_url="/demo",
193
- # history_restore_request=nil,
198
+ # history_restore_request="false",
194
199
  # prompt="Yes",
195
200
  # request="true",
196
201
  # target="demo",
@@ -199,15 +204,60 @@ HTMX::Headers::Request.for request.env
199
204
  # >
200
205
  ----
201
206
 
202
- With the above, the `.for` method plucks out only the HTMX specific headers which may or may not have values. Extra header keys, which are not specific to {htmx_link}, are ignored.
207
+ As you can see, this method only plucks out the htmx specific headers which may or may not have values. Extra header keys, which are not specific to {htmx_link}, are ignored.
208
+
209
+ As an added convenience, you can use predicate methods for boolean values. Example:
203
210
 
204
- ==== Response
211
+ [source,ruby]
212
+ ----
213
+ headers = HTMX.request "HTTP_HX_BOOSTED" => "true",
214
+ "HTTP_HX_CURRENT_URL" => "/demo",
215
+ "HTTP_HX_HISTORY_RESTORE_REQUEST" => "false",
216
+ "HTTP_HX_PROMPT" => "Yes",
217
+ "HTTP_HX_REQUEST" => "true",
218
+ "HTTP_HX_TARGET" => "demo",
219
+ "HTTP_HX_TRIGGER_NAME" => "save",
220
+ "HTTP_HX_TRIGGER" => "demo"
205
221
 
206
- The response object allows you to obtain a {data_link} object to interact with when parsing link:https://htmx.org/reference/#response_headers[HTMX HTTP response headers]. Example:
222
+ headers.boosted? # true
223
+ headers.confirmed? # true
224
+ headers.history_restore_request? # false
225
+ headers.request? # true
226
+ ----
227
+
228
+ Use of `#confirmed?` is the only unique predicate method since it answers a boolean based on the truthiness of the `HTTP_HX_PROMPT` header. For further details, see `String#truthy?` as provided by the link:https://alchemists.io/projects/refinements#_truthy[Refinements] gem.
229
+
230
+ Due to `HTML.request` delegating to the `HTMX::Headers::Request`, this means you can use the object directly. Specifically, you can obtain the record, key, or header depending on your needs. Example:
207
231
 
208
232
  [source,ruby]
209
233
  ----
210
- HTMX::Headers::Response.new
234
+ HTMX::Headers::Request.for(**headers) # Identical to `HTMX.request`.
235
+ HTMX::Headers::Request.key_for "HTTP_HX_CURRENT_URL" # :current_url
236
+ HTMX::Headers::Request.header_for :current_url # "HTTP_HX_CURRENT_URL"
237
+ ----
238
+
239
+ Should you not want to use `HTMX::Headers::Request`, you can use the request predicate methods instead. Example:
240
+
241
+ [source,ruby]
242
+ ----
243
+ headers = {}
244
+
245
+ HTMX.request! headers, boosted: true, prompt: "Yes"
246
+ # {"HTTP_HX_BOOSTED" => true, "HTTP_HX_PROMPT" => "Yes"}
247
+
248
+ HTMX.request? headers, :prompt, "Yes" # true
249
+ HTMX.request? headers, :prompt, "On" # false
250
+ ----
251
+
252
+ 💡 `HTMX.request!` is designed to mutate your original headers. Unknown attributes are merged as is.
253
+
254
+ ==== Responses
255
+
256
+ The response object allows you to obtain a {data_link} object to interact with when parsing link:https://htmx.org/reference/#response_headers[htmx HTTP response headers]. Example:
257
+
258
+ [source,ruby]
259
+ ----
260
+ HTMX.response
211
261
 
212
262
  # <data HTMX::Headers::Response location=nil,
213
263
  # push_url=nil,
@@ -226,7 +276,16 @@ Notice you get a {data_link} instance where all members have the `HX-` prefix re
226
276
 
227
277
  [source,ruby]
228
278
  ----
229
- HTMX::Headers::Response.for response.headers
279
+ HTMX.response "HX-Location" => "/",
280
+ "HX-Push-Url" => "/demo",
281
+ "HX-Redirect" => "/demo",
282
+ "HX-Refresh" => "true",
283
+ "HX-Replace-Url" => "/demo",
284
+ "HX-Reswap" => "none",
285
+ "HX-Retarget" => ".demo",
286
+ "HX-Trigger" => "demo",
287
+ "HX-Trigger-After-Settle" => "demo",
288
+ "HX-Trigger-After-Swap" => "demo"
230
289
 
231
290
  # <data HTMX::Headers::Response location="/",
232
291
  # push_url="/demo",
@@ -241,11 +300,44 @@ HTMX::Headers::Response.for response.headers
241
300
  # >
242
301
  ----
243
302
 
244
- With the above, the `.for` method plucks out only the HTMX specific headers which may or may not have values. Extra header keys, which are not specific to {htmx_link}, are ignored.
303
+ As you can see, this method only plucks out the htmx specific headers which may or may not have values. Extra header keys, which are not specific to {htmx_link}, are ignored.
304
+
305
+ There is also a refresh predicate method that'll answer a boolean for convenience. Example:
306
+
307
+ [source,ruby]
308
+ ----
309
+ headers = HTMX.response "HX-Refresh" => "true"
310
+
311
+ headers.refresh? # true
312
+ ----
313
+
314
+ Due to `HTML.response` delegating to the `HTMX::Headers::Response`, this means you can use the object directly. Specifically, you can obtain the record, key, or header depending on your needs. Example:
315
+
316
+ [source,ruby]
317
+ ----
318
+ HTMX::Headers::Response.for(**headers) # Identical to `HTMX.response`.
319
+ HTMX::Headers::Response.key_for "HX-Location" # :location
320
+ HTMX::Headers::Response.header_for :location # "HX-Location"
321
+ ----
322
+
323
+ Should you not want to use `HTMX::Headers::Response`, you can use the response predicate methods instead. Example:
324
+
325
+ [source,ruby]
326
+ ----
327
+ headers = {}
328
+
329
+ HTMX.response! headers, location: "/", push_url: "/test"
330
+ # {"HX-Location" => "/", "HX-Push-Url" => "/test"}
331
+
332
+ HTMX.response? headers, :push_url, "/test" # true
333
+ HTMX.response? headers, :push_url, "/other" # false
334
+ ----
335
+
336
+ 💡 `HTMX.response!` is designed to mutate your original headers. Unknown attributes are merged as is.
245
337
 
246
338
  === Errors
247
339
 
248
- As you've probably picked up by now, any/all errors issued by this gem will be an instance of the `HTMX::Error` class which inherits from `StandardError`. you can use this classification to catch and deal with these errors in your own implementation as desired.
340
+ Any/all errors issued by this gem will be an instance of the `HTMX::Error` class which inherits from `StandardError`. You can use this classification to catch and deal with these errors in your own implementation as desired.
249
341
 
250
342
  == Development
251
343
 
data/htmx.gemspec CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Gem::Specification.new do |spec|
4
4
  spec.name = "htmx"
5
- spec.version = "2.3.0"
5
+ spec.version = "2.4.0"
6
6
  spec.authors = ["Brooke Kuhlmann"]
7
7
  spec.email = ["brooke@alchemists.io"]
8
8
  spec.homepage = "https://alchemists.io/projects/htmx"
@@ -1,36 +1,20 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "refinements/string"
4
+
3
5
  module HTMX
4
6
  module Headers
5
- REQUEST_KEY_MAP = {
6
- "HTTP_HX_BOOSTED" => :boosted,
7
- "HTTP_HX_CURRENT_URL" => :current_url,
8
- "HTTP_HX_HISTORY_RESTORE_REQUEST" => :history_restore_request,
9
- "HTTP_HX_PROMPT" => :prompt,
10
- "HTTP_HX_REQUEST" => :request,
11
- "HTTP_HX_TARGET" => :target,
12
- "HTTP_HX_TRIGGER_NAME" => :trigger_name,
13
- "HTTP_HX_TRIGGER" => :trigger
14
- }.freeze
15
-
16
7
  # Models the supported HTMX request headers.
17
- Request = Data.define(
18
- :boosted,
19
- :current_url,
20
- :history_restore_request,
21
- :prompt,
22
- :request,
23
- :target,
24
- :trigger_name,
25
- :trigger
26
- ) do
27
- def self.for(key_map: REQUEST_KEY_MAP, **attributes)
8
+ Request = Data.define(*REQUEST_MAP.keys) do
9
+ using Refinements::String
10
+
11
+ def self.for(key_map: REQUEST_MAP.invert, **attributes)
28
12
  new(**attributes.slice(*key_map.keys).transform_keys!(key_map))
29
13
  end
30
14
 
31
- def self.key_for(header, key_map: REQUEST_KEY_MAP) = key_map.fetch header
15
+ def self.key_for(header, key_map: REQUEST_MAP.invert) = key_map.fetch header
32
16
 
33
- def self.header_for(key, key_map: REQUEST_KEY_MAP.invert) = key_map.fetch key
17
+ def self.header_for(key, key_map: REQUEST_MAP) = key_map.fetch key
34
18
 
35
19
  def initialize boosted: nil,
36
20
  current_url: nil,
@@ -42,6 +26,14 @@ module HTMX
42
26
  trigger: nil
43
27
  super
44
28
  end
29
+
30
+ def boosted? = boosted == "true"
31
+
32
+ def confirmed? = prompt ? prompt.truthy? : false
33
+
34
+ def history_restore_request? = history_restore_request == "true"
35
+
36
+ def request? = request == "true"
45
37
  end
46
38
  end
47
39
  end
@@ -2,39 +2,15 @@
2
2
 
3
3
  module HTMX
4
4
  module Headers
5
- RESPONSE_KEY_MAP = {
6
- "HX-Location" => :location,
7
- "HX-Push-Url" => :push_url,
8
- "HX-Redirect" => :redirect,
9
- "HX-Refresh" => :refresh,
10
- "HX-Replace-Url" => :replace_url,
11
- "HX-Reswap" => :reswap,
12
- "HX-Retarget" => :retarget,
13
- "HX-Trigger" => :trigger,
14
- "HX-Trigger-After-Settle" => :trigger_after_settle,
15
- "HX-Trigger-After-Swap" => :trigger_after_swap
16
- }.freeze
17
-
18
5
  # Models the supported HTMX response headers.
19
- Response = Data.define(
20
- :location,
21
- :push_url,
22
- :redirect,
23
- :refresh,
24
- :replace_url,
25
- :reswap,
26
- :retarget,
27
- :trigger,
28
- :trigger_after_settle,
29
- :trigger_after_swap
30
- ) do
31
- def self.for(key_map: RESPONSE_KEY_MAP, **attributes)
6
+ Response = Data.define(*RESPONSE_MAP.keys) do
7
+ def self.for(key_map: RESPONSE_MAP.invert, **attributes)
32
8
  new(**attributes.slice(*key_map.keys).transform_keys!(key_map))
33
9
  end
34
10
 
35
- def self.key_for(header, key_map: RESPONSE_KEY_MAP) = key_map.fetch header
11
+ def self.key_for(header, key_map: RESPONSE_MAP.invert) = key_map.fetch header
36
12
 
37
- def self.header_for(key, key_map: RESPONSE_KEY_MAP.invert) = key_map.fetch key
13
+ def self.header_for(key, key_map: RESPONSE_MAP) = key_map.fetch key
38
14
 
39
15
  def initialize location: nil,
40
16
  push_url: nil,
@@ -48,6 +24,8 @@ module HTMX
48
24
  trigger_after_swap: nil
49
25
  super
50
26
  end
27
+
28
+ def refresh? = refresh == "true"
51
29
  end
52
30
  end
53
31
  end
data/lib/htmx.rb CHANGED
@@ -11,6 +11,30 @@ end
11
11
 
12
12
  # Main namespace.
13
13
  module HTMX
14
+ REQUEST_MAP = {
15
+ boosted: "HTTP_HX_BOOSTED",
16
+ current_url: "HTTP_HX_CURRENT_URL",
17
+ history_restore_request: "HTTP_HX_HISTORY_RESTORE_REQUEST",
18
+ prompt: "HTTP_HX_PROMPT",
19
+ request: "HTTP_HX_REQUEST",
20
+ target: "HTTP_HX_TARGET",
21
+ trigger_name: "HTTP_HX_TRIGGER_NAME",
22
+ trigger: "HTTP_HX_TRIGGER"
23
+ }.freeze
24
+
25
+ RESPONSE_MAP = {
26
+ location: "HX-Location",
27
+ push_url: "HX-Push-Url",
28
+ redirect: "HX-Redirect",
29
+ refresh: "HX-Refresh",
30
+ replace_url: "HX-Replace-Url",
31
+ reswap: "HX-Reswap",
32
+ retarget: "HX-Retarget",
33
+ trigger: "HX-Trigger",
34
+ trigger_after_settle: "HX-Trigger-After-Settle",
35
+ trigger_after_swap: "HX-Trigger-After-Swap"
36
+ }.freeze
37
+
14
38
  def self.loader registry = Zeitwerk::Registry
15
39
  @loader ||= registry.loaders.each.find { |loader| loader.tag == File.basename(__FILE__, ".rb") }
16
40
  end
@@ -19,4 +43,18 @@ module HTMX
19
43
  @prefixer ||= Prefixer.new
20
44
  @prefixer.call(...)
21
45
  end
46
+
47
+ def self.request(**) = Headers::Request.for(**)
48
+
49
+ def self.request!(headers, **attributes) = headers.merge! attributes.transform_keys!(REQUEST_MAP)
50
+
51
+ def self.request?(headers, key, value) = headers[REQUEST_MAP[key]] == value
52
+
53
+ def self.response(**) = Headers::Response.for(**)
54
+
55
+ def self.response!(headers, **attributes)
56
+ headers.merge! attributes.transform_keys!(RESPONSE_MAP)
57
+ end
58
+
59
+ def self.response?(headers, key, value) = headers[RESPONSE_MAP[key]] == value
22
60
  end
data.tar.gz.sig CHANGED
Binary file
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: htmx
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.3.0
4
+ version: 2.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brooke Kuhlmann
@@ -104,7 +104,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
104
104
  - !ruby/object:Gem::Version
105
105
  version: '0'
106
106
  requirements: []
107
- rubygems_version: 3.6.9
107
+ rubygems_version: 3.7.1
108
108
  specification_version: 4
109
109
  summary: An augmenter and companion to the HTMX JavaScript library.
110
110
  test_files: []
metadata.gz.sig CHANGED
Binary file