turbo-rails 2.0.0 → 2.0.2

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.
@@ -1,4 +1,4 @@
1
- # Provides the broadcast actions in synchronous and asynchrous form for the <tt>Turbo::StreamsChannel</tt>.
1
+ # Provides the broadcast actions in synchronous and asynchronous form for the <tt>Turbo::StreamsChannel</tt>.
2
2
  # See <tt>Turbo::Broadcastable</tt> for the user-facing API that invokes these methods with most of the paperwork filled out already.
3
3
  #
4
4
  # Can be used directly using something like <tt>Turbo::StreamsChannel.broadcast_remove_to :entries, target: 1</tt>.
@@ -5,7 +5,7 @@
5
5
  # When that header is detected by the controller, we substitute our own minimal layout in place of the
6
6
  # application-supplied layout (since we're only working on an in-page frame, thus can skip the weight of the layout). We
7
7
  # use a minimal layout, rather than avoid the layout entirely, so that it's still possible to render content into the
8
- # <tt>head<tt>.
8
+ # <tt>head</tt>.
9
9
  #
10
10
  # Accordingly, we ensure that the etag for the page is changed, such that a cache for a minimal-layout request isn't
11
11
  # served on a normal request and vice versa.
@@ -33,6 +33,6 @@ module Turbo::Frames::FrameRequest
33
33
  end
34
34
 
35
35
  def turbo_frame_request_id
36
- request.headers["Turbo-Frame"]
36
+ request&.headers["Turbo-Frame"]
37
37
  end
38
38
  end
@@ -15,29 +15,32 @@ module Turbo::Native::Navigation
15
15
  request.user_agent.to_s.match?(/Turbo Native/)
16
16
  end
17
17
 
18
- # Tell the Turbo Native app to dismiss a modal (if presented) or pop a screen off of the navigation stack.
18
+ # Tell the Turbo Native app to dismiss a modal (if presented) or pop a screen off of the navigation stack. Otherwise redirect to the given URL if Turbo Native is not present.
19
19
  def recede_or_redirect_to(url, **options)
20
20
  turbo_native_action_or_redirect url, :recede, :to, options
21
21
  end
22
22
 
23
- # Tell the Turbo Native app to ignore this navigation.
23
+ # Tell the Turbo Native app to ignore this navigation, otherwise redirect to the given URL if Turbo Native is not present.
24
24
  def resume_or_redirect_to(url, **options)
25
25
  turbo_native_action_or_redirect url, :resume, :to, options
26
26
  end
27
27
 
28
- # Tell the Turbo Native app to refresh the current screen.
28
+ # Tell the Turbo Native app to refresh the current screen, otherwise redirect to the given URL if Turbo Native is not present.
29
29
  def refresh_or_redirect_to(url, **options)
30
30
  turbo_native_action_or_redirect url, :refresh, :to, options
31
31
  end
32
32
 
33
+ # Same as <tt>recede_or_redirect_to</tt> but redirects to the previous page or provided fallback location if the Turbo Native app is not present.
33
34
  def recede_or_redirect_back_or_to(url, **options)
34
35
  turbo_native_action_or_redirect url, :recede, :back, options
35
36
  end
36
37
 
38
+ # Same as <tt>resume_or_redirect_to</tt> but redirects to the previous page or provided fallback location if the Turbo Native app is not present.
37
39
  def resume_or_redirect_back_or_to(url, **options)
38
40
  turbo_native_action_or_redirect url, :resume, :back, options
39
41
  end
40
42
 
43
+ # Same as <tt>refresh_or_redirect_to</tt> but redirects to the previous page or provided fallback location if the Turbo Native app is not present.
41
44
  def refresh_or_redirect_back_or_to(url, **options)
42
45
  turbo_native_action_or_redirect url, :refresh, :back, options
43
46
  end
@@ -1,22 +1,21 @@
1
+ # Helpers to configure Turbo Drive via meta directives. They come in two
2
+ # variants:
3
+ #
4
+ # The recommended option is to include +yield :head+ in the +<head>+ section
5
+ # of the layout. Then you can use the helpers in any view.
6
+ #
7
+ # ==== Example
8
+ #
9
+ # # app/views/application.html.erb
10
+ # <html><head><%= yield :head %></head><body><%= yield %></html>
11
+ #
12
+ # # app/views/trays/index.html.erb
13
+ # <% turbo_exempts_page_from_cache %>
14
+ # <p>Page that shouldn't be cached by Turbo</p>
15
+ #
16
+ # Alternatively, you can use the +_tag+ variant of the helpers to only get the
17
+ # HTML for the meta directive.
1
18
  module Turbo::DriveHelper
2
- # Helpers to configure Turbo Drive via meta directives. They come in two
3
- # variants:
4
- #
5
- # The recommended option is to include +yield :head+ in the +<head>+ section
6
- # of the layout. Then you can use the helpers in any view.
7
- #
8
- # ==== Example
9
- #
10
- # # app/views/application.html.erb
11
- # <html><head><%= yield :head %></head><body><%= yield %></html>
12
- #
13
- # # app/views/trays/index.html.erb
14
- # <% turbo_exempts_page_from_cache %>
15
- # <p>Page that shouldn't be cached by Turbo</p>
16
- #
17
- # Alternatively, you can use the +_tag+ variant of the helpers to only get the
18
- # HTML for the meta directive.
19
-
20
19
  # Pages that are more likely than not to be a cache miss can skip turbo cache to avoid visual jitter.
21
20
  # Cannot be used along with +turbo_exempts_page_from_preview+.
22
21
  def turbo_exempts_page_from_cache
@@ -2,7 +2,7 @@ module Turbo::FramesHelper
2
2
  # Returns a frame tag that can either be used simply to encapsulate frame content or as a lazy-loading container that starts empty but
3
3
  # fetches the URL supplied in the +src+ attribute.
4
4
  #
5
- # === Examples
5
+ # ==== Examples
6
6
  #
7
7
  # <%= turbo_frame_tag "tray", src: tray_path(tray) %>
8
8
  # # => <turbo-frame id="tray" src="http://example.com/trays/1"></turbo-frame>
@@ -27,17 +27,14 @@ module Turbo::FramesHelper
27
27
  # <%= turbo_frame_tag [user_id, "tray"], src: tray_path(tray) %>
28
28
  # # => <turbo-frame id="1_tray" src="http://example.com/trays/1"></turbo-frame>
29
29
  #
30
- # The `turbo_frame_tag` helper will convert the arguments it receives to their
31
- # `dom_id` if applicable to easily generate unique ids for Turbo Frames:
30
+ # The +turbo_frame_tag+ helper will convert the arguments it receives to their
31
+ # +dom_id+ if applicable to easily generate unique ids for Turbo Frames:
32
32
  #
33
33
  # <%= turbo_frame_tag(Article.find(1)) %>
34
34
  # # => <turbo-frame id="article_1"></turbo-frame>
35
35
  #
36
36
  # <%= turbo_frame_tag(Article.find(1), "comments") %>
37
- # # => <turbo-frame id="article_1_comments"></turbo-frame>
38
- #
39
- # <%= turbo_frame_tag(Article.find(1), Comment.new) %>
40
- # # => <turbo-frame id="article_1_new_comment"></turbo-frame>
37
+ # # => <turbo-frame id="comments_article_1"></turbo-frame>
41
38
  def turbo_frame_tag(*ids, src: nil, target: nil, **attributes, &block)
42
39
  id = ids.first.respond_to?(:to_key) ? ActionView::RecordIdentifier.dom_id(*ids) : ids.join('_')
43
40
  src = url_for(src) if src.present?
@@ -22,7 +22,6 @@ module Turbo::Streams::ActionHelper
22
22
  # message = Message.find(1)
23
23
  # turbo_stream_action_tag "remove", target: [message, :special]
24
24
  # # => <turbo-stream action="remove" target="special_message_1"></turbo-stream>
25
- #
26
25
  def turbo_stream_action_tag(action, target: nil, targets: nil, template: nil, **attributes)
27
26
  template = action.to_sym.in?(%i[ remove refresh ]) ? "" : tag.template(template.to_s.html_safe)
28
27
 
@@ -35,6 +34,10 @@ module Turbo::Streams::ActionHelper
35
34
  end
36
35
  end
37
36
 
37
+ # Creates a `turbo-stream` tag with an `action="refresh"` attribute. Example:
38
+ #
39
+ # turbo_stream_refresh_tag
40
+ # # => <turbo-stream action="refresh"></turbo-stream>
38
41
  def turbo_stream_refresh_tag(request_id: Turbo.current_request_id, **attributes)
39
42
  turbo_stream_action_tag(:refresh, **{ "request-id": request_id }.compact, **attributes)
40
43
  end
@@ -48,7 +48,6 @@ module Turbo::StreamsHelper
48
48
  # It is also possible to pass additional parameters to the channel by passing them through `data` attributes:
49
49
  #
50
50
  # <%= turbo_stream_from "room", channel: RoomChannel, data: {room_name: "room #1"} %>
51
- #
52
51
  def turbo_stream_from(*streamables, **attributes)
53
52
  attributes[:channel] = attributes[:channel]&.to_s || "Turbo::StreamsChannel"
54
53
  attributes[:"signed-stream-name"] = Turbo::StreamsChannel.signed_stream_name(streamables)
@@ -14,8 +14,8 @@
14
14
  # end
15
15
  # end
16
16
  #
17
- # This is an example from [HEY](https://hey.com), and the clearance is the model that drives
18
- # [the screener](https://hey.com/features/the-screener/), which gives users the power to deny first-time senders (petitioners)
17
+ # This is an example from {HEY}[https://hey.com], and the clearance is the model that drives
18
+ # {the screener}[https://hey.com/features/the-screener/], which gives users the power to deny first-time senders (petitioners)
19
19
  # access to their attention (as the examiner). When a new clearance is created upon receipt of an email from a first-time
20
20
  # sender, that'll trigger the call to broadcast_later, which in turn invokes <tt>broadcast_prepend_later_to</tt>.
21
21
  #
@@ -27,7 +27,7 @@
27
27
  # (which is derived by default from the plural model name of the model, but can be overwritten).
28
28
  #
29
29
  # You can also choose to render html instead of a partial inside of a broadcast
30
- # you do this by passing the `html:` option to any broadcast method that accepts the **rendering argument. Example:
30
+ # you do this by passing the +html:+ option to any broadcast method that accepts the **rendering argument. Example:
31
31
  #
32
32
  # class Message < ApplicationRecord
33
33
  # belongs_to :user
@@ -40,8 +40,8 @@
40
40
  # end
41
41
  # end
42
42
  #
43
- # If you want to render a template instead of a partial, e.g. ('messages/index' or 'messages/show'), you can use the `template:` option.
44
- # Again, only to any broadcast method that accepts the `**rendering` argument. Example:
43
+ # If you want to render a template instead of a partial, e.g. ('messages/index' or 'messages/show'), you can use the +template:+ option.
44
+ # Again, only to any broadcast method that accepts the +**rendering+ argument. Example:
45
45
  #
46
46
  # class Message < ApplicationRecord
47
47
  # belongs_to :user
@@ -54,7 +54,7 @@
54
54
  # end
55
55
  # end
56
56
  #
57
- # If you want to render a renderable object you can use the `renderable:` option.
57
+ # If you want to render a renderable object you can use the +renderable:+ option.
58
58
  #
59
59
  # class Message < ApplicationRecord
60
60
  # belongs_to :user
@@ -67,15 +67,74 @@
67
67
  # end
68
68
  # end
69
69
  #
70
- # There are four basic actions you can broadcast: <tt>remove</tt>, <tt>replace</tt>, <tt>append</tt>, and
71
- # <tt>prepend</tt>. As a rule, you should use the <tt>_later</tt> versions of everything except for remove when broadcasting
70
+ # There are seven basic actions you can broadcast: <tt>after</tt>, <tt>append</tt>, <tt>before</tt>,
71
+ # <tt>prepend</tt>, <tt>remove</tt>, <tt>replace</tt>, and
72
+ # <tt>update</tt>. As a rule, you should use the <tt>_later</tt> versions of everything except for remove when broadcasting
72
73
  # within a real-time path, like a controller or model, since all those updates require a rendering step, which can slow down
73
74
  # execution. You don't need to do this for remove, since only the dom id for the model is used.
74
75
  #
75
- # In addition to the four basic actions, you can also use <tt>broadcast_render</tt>,
76
+ # In addition to the seven basic actions, you can also use <tt>broadcast_render</tt>,
76
77
  # <tt>broadcast_render_to</tt> <tt>broadcast_render_later</tt>, and <tt>broadcast_render_later_to</tt>
77
78
  # to render a turbo stream template with multiple actions.
78
79
  #
80
+ # == Page refreshes
81
+ #
82
+ # You can broadcast "page refresh" stream actions. This will make subscribed clients reload the
83
+ # page. For pages that configure morphing and scroll preservation, this will translate into smooth
84
+ # updates when it only updates the content that changed.
85
+
86
+ # This approach is an alternative to fine-grained stream actions targeting specific DOM elements. It
87
+ # offers good fidelity with a much simpler programming model. As a tradeoff, the fidelity you can reach
88
+ # is often not as high as with targeted stream actions since it renders the entire page again.
89
+ #
90
+ # The +broadcast_refreshes+ class method configures the model to broadcast a "page refresh" on creates,
91
+ # updates, and destroys to a stream name derived at runtime by the <tt>stream</tt> symbol invocation. Examples
92
+ #
93
+ # class Board < ApplicationRecord
94
+ # broadcast_refreshes
95
+ # end
96
+ #
97
+ # In this example, when a board is created, updated, or destroyed, a Turbo Stream for a
98
+ # page refresh will be broadcasted to all clients subscribed to the "boards" stream.
99
+ #
100
+ # This works great in hierarchical structures, where the child record touches parent records automatically
101
+ # to invalidate the cache:
102
+ #
103
+ # class Column < ApplicationRecord
104
+ # belongs_to :board, touch: true # +Board+ will trigger a page refresh on column changes
105
+ # end
106
+ #
107
+ # You can also specify the streamable declaratively by passing a symbol to the +broadcast_refreshes_to+ method:
108
+ #
109
+ # class Column < ApplicationRecord
110
+ # belongs_to :board
111
+ # broadcast_refreshes_to :board
112
+ # end
113
+ #
114
+ # For more granular control, you can also broadcast a "page refresh" to a stream name derived
115
+ # from the passed <tt>streamables</tt> by using the instance-level methods <tt>broadcast_refresh_to</tt> or
116
+ # <tt>broadcast_refresh_later_to</tt>. These methods are particularly useful when you want to trigger
117
+ # a page refresh for more specific scenarios. Example:
118
+ #
119
+ # class Clearance < ApplicationRecord
120
+ # belongs_to :petitioner, class_name: "Contact"
121
+ # belongs_to :examiner, class_name: "User"
122
+ #
123
+ # after_create_commit :broadcast_refresh_later
124
+ #
125
+ # private
126
+ # def broadcast_refresh_later
127
+ # broadcast_refresh_later_to examiner.identity, :clearances
128
+ # end
129
+ # end
130
+ #
131
+ # In this example, a "page refresh" is broadcast to the stream named "identity:<identity-id>:clearances"
132
+ # after a new clearance is created. All clients subscribed to this stream will refresh the page to reflect
133
+ # the changes.
134
+ #
135
+ # When broadcasting page refreshes, Turbo will automatically debounce multiple calls in a row to only broadcast the last one.
136
+ # This is meant for scenarios where you process records in mass. Because of the nature of such signals, it makes no sense to
137
+ # broadcast them repeatedly and individually.
79
138
  # == Suppressing broadcasts
80
139
  #
81
140
  # Sometimes, you need to disable broadcasts in certain scenarios. You can use <tt>.suppressing_turbo_broadcasts</tt> to create
@@ -136,7 +195,17 @@ module Turbo::Broadcastable
136
195
  end
137
196
 
138
197
  # Configures the model to broadcast a "page refresh" on creates, updates, and destroys to a stream
139
- # name derived at runtime by the <tt>stream</tt> symbol invocation.
198
+ # name derived at runtime by the <tt>stream</tt> symbol invocation. Examples:
199
+ #
200
+ # class Message < ApplicationRecord
201
+ # belongs_to :board
202
+ # broadcasts_refreshes_to :board
203
+ # end
204
+ #
205
+ # class Message < ApplicationRecord
206
+ # belongs_to :board
207
+ # broadcasts_refreshes_to ->(message) { [ message.board, :messages ] }
208
+ # end
140
209
  def broadcasts_refreshes_to(stream)
141
210
  after_commit -> { broadcast_refresh_later_to(stream.try(:call, self) || send(stream)) }
142
211
  end
@@ -293,10 +362,15 @@ module Turbo::Broadcastable
293
362
  broadcast_prepend_to self, target: target, **rendering
294
363
  end
295
364
 
365
+ # Broadcast a "page refresh" to the stream name identified by the passed <tt>streamables</tt>. Example:
366
+ #
367
+ # # Sends <turbo-stream action="refresh"></turbo-stream> to the stream named "identity:2:clearances"
368
+ # clearance.broadcast_refresh_to examiner.identity, :clearances
296
369
  def broadcast_refresh_to(*streamables)
297
370
  Turbo::StreamsChannel.broadcast_refresh_to(*streamables) unless suppressed_turbo_broadcasts?
298
371
  end
299
372
 
373
+ # Same as <tt>#broadcast_refresh_to</tt>, but the designated stream is automatically set to the current model.
300
374
  def broadcast_refresh
301
375
  broadcast_refresh_to self
302
376
  end
@@ -315,7 +389,6 @@ module Turbo::Broadcastable
315
389
  broadcast_action_to self, action: action, target: target, attributes: attributes, **rendering
316
390
  end
317
391
 
318
-
319
392
  # Same as <tt>broadcast_replace_to</tt> but run asynchronously via a <tt>Turbo::Streams::BroadcastJob</tt>.
320
393
  def broadcast_replace_later_to(*streamables, **rendering)
321
394
  Turbo::StreamsChannel.broadcast_replace_later_to(*streamables, target: self, **broadcast_rendering_with_defaults(rendering)) unless suppressed_turbo_broadcasts?
@@ -356,10 +429,12 @@ module Turbo::Broadcastable
356
429
  broadcast_prepend_later_to self, target: target, **rendering
357
430
  end
358
431
 
432
+ # Same as <tt>broadcast_refresh_to</tt> but run asynchronously via a <tt>Turbo::Streams::BroadcastJob</tt>.
359
433
  def broadcast_refresh_later_to(*streamables)
360
434
  Turbo::StreamsChannel.broadcast_refresh_later_to(*streamables, request_id: Turbo.current_request_id) unless suppressed_turbo_broadcasts?
361
435
  end
362
436
 
437
+ # Same as <tt>#broadcast_refresh_later_to</tt>, but the designated stream is automatically set to the current model.
363
438
  def broadcast_refresh_later
364
439
  broadcast_refresh_later_to self
365
440
  end
@@ -390,7 +465,7 @@ module Turbo::Broadcastable
390
465
  #
391
466
  # Note that rendering inline via this method will cause template rendering to happen synchronously. That is usually not
392
467
  # desireable for model callbacks, certainly not if those callbacks are inside of a transaction. Most of the time you should
393
- # be using `broadcast_render_later`, unless you specifically know why synchronous rendering is needed.
468
+ # be using +broadcast_render_later+, unless you specifically know why synchronous rendering is needed.
394
469
  def broadcast_render(**rendering)
395
470
  broadcast_render_to self, **rendering
396
471
  end
@@ -400,12 +475,12 @@ module Turbo::Broadcastable
400
475
  #
401
476
  # Note that rendering inline via this method will cause template rendering to happen synchronously. That is usually not
402
477
  # desireable for model callbacks, certainly not if those callbacks are inside of a transaction. Most of the time you should
403
- # be using `broadcast_render_later_to`, unless you specifically know why synchronous rendering is needed.
478
+ # be using +broadcast_render_later_to+, unless you specifically know why synchronous rendering is needed.
404
479
  def broadcast_render_to(*streamables, **rendering)
405
480
  Turbo::StreamsChannel.broadcast_render_to(*streamables, **broadcast_rendering_with_defaults(rendering)) unless suppressed_turbo_broadcasts?
406
481
  end
407
482
 
408
- # Same as <tt>broadcast_action_to</tt> but run asynchronously via a <tt>Turbo::Streams::BroadcastJob</tt>.
483
+ # Same as <tt>broadcast_render_to</tt> but run asynchronously via a <tt>Turbo::Streams::BroadcastJob</tt>.
409
484
  def broadcast_render_later(**rendering)
410
485
  broadcast_render_later_to self, **rendering
411
486
  end
@@ -416,7 +491,6 @@ module Turbo::Broadcastable
416
491
  Turbo::StreamsChannel.broadcast_render_later_to(*streamables, **broadcast_rendering_with_defaults(rendering)) unless suppressed_turbo_broadcasts?
417
492
  end
418
493
 
419
-
420
494
  private
421
495
  def broadcast_target_default
422
496
  self.class.broadcast_target_default
@@ -11,14 +11,14 @@ module Turbo
11
11
 
12
12
  # Asserts that `<turbo-stream>` elements were broadcast over Action Cable
13
13
  #
14
- # === Arguments
14
+ # ==== Arguments
15
15
  #
16
16
  # * <tt>stream_name_or_object</tt> the objects used to generate the
17
17
  # channel Action Cable name, or the name itself
18
18
  # * <tt>&block</tt> optional block executed before the
19
19
  # assertion
20
20
  #
21
- # === Options
21
+ # ==== Options
22
22
  #
23
23
  # * <tt>count:</tt> the number of `<turbo-stream>` elements that are
24
24
  # expected to be broadcast
@@ -70,7 +70,7 @@ module Turbo
70
70
 
71
71
  # Asserts that no `<turbo-stream>` elements were broadcast over Action Cable
72
72
  #
73
- # === Arguments
73
+ # ==== Arguments
74
74
  #
75
75
  # * <tt>stream_name_or_object</tt> the objects used to generate the
76
76
  # channel Action Cable name, or the name itself
@@ -113,7 +113,7 @@ module Turbo
113
113
 
114
114
  # Captures any `<turbo-stream>` elements that were broadcast over Action Cable
115
115
  #
116
- # === Arguments
116
+ # ==== Arguments
117
117
  #
118
118
  # * <tt>stream_name_or_object</tt> the objects used to generate the
119
119
  # channel Action Cable name, or the name itself
data/lib/turbo/engine.rb CHANGED
@@ -84,6 +84,7 @@ module Turbo
84
84
  require "turbo/broadcastable/test_helper"
85
85
 
86
86
  include Turbo::TestAssertions
87
+ include Turbo::Broadcastable::TestHelper
87
88
  end
88
89
 
89
90
  ActiveSupport.on_load(:action_dispatch_integration_test) do
@@ -4,7 +4,7 @@ module Turbo
4
4
  # Assert that the Turbo Stream request's response body's HTML contains a
5
5
  # `<turbo-stream>` element.
6
6
  #
7
- # === Options
7
+ # ==== Options
8
8
  #
9
9
  # * <tt>:status</tt> [Integer, Symbol] the HTTP response status
10
10
  # * <tt>:action</tt> [String] matches the element's <tt>[action]</tt>
@@ -47,7 +47,7 @@ module Turbo
47
47
  # Assert that the Turbo Stream request's response body's HTML does not
48
48
  # contain a `<turbo-stream>` element.
49
49
  #
50
- # === Options
50
+ # ==== Options
51
51
  #
52
52
  # * <tt>:status</tt> [Integer, Symbol] the HTTP response status
53
53
  # * <tt>:action</tt> [String] matches the element's <tt>[action]</tt>
@@ -10,7 +10,7 @@ module Turbo
10
10
  # Assert that the rendered fragment of HTML contains a `<turbo-stream>`
11
11
  # element.
12
12
  #
13
- # === Options
13
+ # ==== Options
14
14
  #
15
15
  # * <tt>:action</tt> [String] matches the element's <tt>[action]</tt>
16
16
  # attribute
@@ -55,7 +55,7 @@ module Turbo
55
55
  # Assert that the rendered fragment of HTML does not contain a `<turbo-stream>`
56
56
  # element.
57
57
  #
58
- # === Options
58
+ # ==== Options
59
59
  #
60
60
  # * <tt>:action</tt> [String] matches the element's <tt>[action]</tt>
61
61
  # attribute
data/lib/turbo/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Turbo
2
- VERSION = "2.0.0"
2
+ VERSION = "2.0.2"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: turbo-rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.0
4
+ version: 2.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sam Stephenson
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2024-02-07 00:00:00.000000000 Z
13
+ date: 2024-02-09 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: activejob