hot-glue 0.7.8 → 0.8

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: 0e4491ce711db972625af0df18b41705f69a87451b34237a1a3ab1c565fc4729
4
- data.tar.gz: 13799e4f92016ccf6156abf90a85cd5bda7418b1287ce3d7c112112b853ff92f
3
+ metadata.gz: 555bc8c92663c9e6797856debce6569ef5532f1d8f0536d862f1226b08b3e297
4
+ data.tar.gz: 2cc566882dc10083d857ebf8e254a126cf2842cde280509ff56ce37a86c4766e
5
5
  SHA512:
6
- metadata.gz: 32a835125c53bd4aa3d14080ac048c17d556db3b6db7716ce4a21eefba18db38fe33f76403e16f5e8a2f9415d6591430412d0a33029d0634ec65118f8363d345
7
- data.tar.gz: 55a21a7aba9909332640275d0b6cb24dcfb0784323eb9ca7e8248db70143ec4a6520f4c1537aa39c25ca36c4ac3f844ec42eab20e3345db3298915569c203897
6
+ metadata.gz: 9592d760df6d8b79e41fdd71bb8e8a89f62745056c512b56cf1d31bed0174e9169146531febdec68dfb7ca2017e26e048f52055718ab04279e444c2742016482
7
+ data.tar.gz: c4e5ab6b7289ba6ac225eb4f40267bd2bb5b0163b1dc029ba43b55161552255ae4e541028a89aa4b988f6a83ea8123da7102216d4afe52a226dead4ca0e71c98
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- hot-glue (0.7.7)
4
+ hot-glue (0.7.9)
5
5
  ffaker (~> 2.16)
6
6
  rails (> 5.1)
7
7
 
@@ -134,7 +134,7 @@ GEM
134
134
  net-protocol
135
135
  net-pop (0.1.2)
136
136
  net-protocol
137
- net-protocol (0.2.2)
137
+ net-protocol (0.3.0)
138
138
  timeout
139
139
  net-smtp (0.5.1)
140
140
  net-protocol
data/README.md CHANGED
@@ -1096,8 +1096,6 @@ The effect will be that the fields will be stacked together into nicely fit colu
1096
1096
 
1097
1097
  **If your customer is used to Excel, this feature will confuse them.**
1098
1098
 
1099
- Also, this feature will **probably not** be supported by the SORTING (not yet implemented). (You will be forced to choose between the two which I think makes sense.)
1100
-
1101
1099
  The layout builder works from right-to-left and starts with 12, the number of Bootstrap's columns.
1102
1100
 
1103
1101
  It reserves 2 columns for the default buttons. Then +1 additional column for **each magic button** you have specified.
@@ -2000,6 +1998,17 @@ _Notice that Stimulus requires object registration when used in a Node environme
2000
1998
  Instead, use the generator and the registry will be updated for you automatically.
2001
1999
 
2002
2000
 
2001
+ ## Sorting
2002
+
2003
+ #### `--sortable` (true of flagged; false otherwise; does not take an argument)
2004
+ To add sorting to your columns add `--sortable` to your build
2005
+ sortable fields are integers, floats, string, text, datetime, time, dates excluding anything that is a foreign key, not UUIDs
2006
+
2007
+ #### `--sort-fields=`
2008
+ List of field names (separated by commas)
2009
+ Leave off (do not specify) to sort by all sort-eligible fields
2010
+
2011
+
2003
2012
  ## Attachments
2004
2013
 
2005
2014
  #### `--attachments=` Long form syntax with 1st and 2nd parameters
@@ -2489,6 +2498,20 @@ These automatic pickups for partials are detected at build time. This means that
2489
2498
 
2490
2499
  # VERSION HISTORY
2491
2500
 
2501
+ #### 2026-08-30 - v0.8
2502
+ - `--sortable` (true of flagged; false otherwise; does not take an argument)
2503
+ To add sorting to your columns add `--sortable` to your build
2504
+ sortable fields are integers, floats, string, text, datetime, time, dates excluding anything that is a foreign key, not UUIDs
2505
+ - `--sort-fields=`
2506
+ List of field names (separated by commas)
2507
+ Leave off (do not specify) to sort by all sort-eligible fields
2508
+
2509
+
2510
+ #### 2026-08-29 - v0.7.9
2511
+ -  Render float fields as type="number" step="any" for HTML5 validation; float fields should not be correctly validated on input
2512
+
2513
+ - switching 'feature' specs to be 'system' specs, switch to spec/system with shared DB connection, headless=new Chrome, and whole-example retry via rspec-retry; should address race conditions in specs
2514
+
2492
2515
  #### 2026-08-22 - v0.7.8
2493
2516
  - fix for time field output when no user is present (in gd mode)
2494
2517
  - in new builds, create and edit will now interact as turbo-stream interactions (except for big edit); this is to remove a race condition in the capy spec; note that your old edit.erb and new.erb will get deleted if you rebuild
@@ -2518,12 +2541,13 @@ for example, if we have a `thing` that can belong (via parent_id and parent_type
2518
2541
 
2519
2542
  Hot glue wil convert the spaces to commas when writing the controller code.
2520
2543
 
2521
- A child controller to with a polymorphic parent:
2522
- - This special case assume that that the parent being build is not actually a polymoprh, it is a real object, but its children have foreign keys to it which are polymorphic.
2544
+ A child controller with a polymorphic parent:
2545
+
2546
+ - This special case assumes that that the parent being build is not actually a polymoprh, it is a real object, but its children have foreign keys to it which are polymorphic.
2523
2547
 
2524
- `--nested=abc(parent) `
2548
+ `--nested=abc(parent)`
2525
2549
 
2526
- Example: In my data model, targets have a polymorphic parent (parent_id and parent_type) and can belong to either Companies or Schools. Here, we are building the Companies view with a child to Targets, but notice for these targets we are using polymorphism and also using a controller prefix, so tha this child controller will be built as CompanyTargets. In the companies build, we downnest `company_targets(targets)` (`company_targets` is the name of the child controller, but it is acting on an object called `targets`, as seen in the downnest specification.)
2550
+ Example: In my data model, targets have a polymorphic parent (parent_id and parent_type) and can belong to either Companies or Schools. Here, we are building the Companies view with a child to Targets, but notice for these targets we are using polymorphism and also using a controller prefix, so that this child controller will be built as CompanyTargets. In the companies build, we downnest `company_targets(targets)` (`company_targets` is the name of the child controller, but it is acting on an object called `targets`, as seen in the downnest specification.)
2527
2551
 
2528
2552
  ```
2529
2553
  bin/rails generate hot_glue:scaffold Company --namespace='account_dashboard' --nested='account' --downnest='company_targets(targets)'
@@ -10,4 +10,36 @@ module HotGlueHelper
10
10
  def enum_to_collection_select(hash)
11
11
  hash.collect{|k,v| KVObject.new(key: k, value: v)}
12
12
  end
13
+
14
+ def sort_link(field, label)
15
+ field = field.to_s
16
+ active = params[:sort] == field
17
+ direction = active ? params[:direction] : nil
18
+
19
+ next_direction =
20
+ if !active
21
+ 'asc'
22
+ elsif direction == 'asc'
23
+ 'desc'
24
+ else
25
+ nil
26
+ end
27
+
28
+ new_params = request.query_parameters.except('sort', 'direction', 'page')
29
+ if next_direction
30
+ new_params['sort'] = field
31
+ new_params['direction'] = next_direction
32
+ end
33
+
34
+ arrow =
35
+ if active && direction == 'asc'
36
+ ' ▲'
37
+ elsif active && direction == 'desc'
38
+ ' ▼'
39
+ else
40
+ ''
41
+ end
42
+
43
+ link_to (label + arrow).html_safe, "#{request.path}?#{new_params.to_query}".chomp('?'), style: 'white-space: nowrap', 'data-turbo-action': 'advance'
44
+ end
13
45
  end
@@ -33,6 +33,10 @@ class AssociationField < Field
33
33
 
34
34
  end
35
35
 
36
+ def sortable?
37
+ false
38
+ end
39
+
36
40
  def assoc_name
37
41
  assoc
38
42
  end
@@ -52,6 +52,10 @@ class Field
52
52
  @name
53
53
  end
54
54
 
55
+ def sortable?
56
+ true
57
+ end
58
+
55
59
  def form_field_output
56
60
  raise "superclass must implement"
57
61
  end
@@ -171,13 +175,13 @@ class Field
171
175
  res
172
176
  end
173
177
 
174
- def field_output(type = nil, width )
178
+ def field_output(type = nil, width, step: nil)
175
179
  if modify_as && modify_as[:timezone]
176
180
  "<%= f.time_zone_select :#{name}, ActiveSupport::TimeZone.all, {}, {class: 'form-control'} %>"
177
181
  else
178
182
  parts = name.split('_')
179
183
  camelcase_name = parts.first + parts[1..].map(&:capitalize).join
180
- " <%= f.text_field :#{name}, value: #{singular}.#{name}, autocomplete: 'off', size: #{width}, class: 'form-control', type: '#{type}'" + (form_placeholder_labels ? ", placeholder: '#{name.to_s.humanize}'" : "") + (stimmify ? ", 'data-#{@stimmify}-target': '#{camelcase_name}' " : "") + " %>\n " + "\n"
184
+ " <%= f.text_field :#{name}, value: #{singular}.#{name}, autocomplete: 'off', size: #{width}, class: 'form-control', type: '#{type}'" + (step ? ", step: '#{step}'" : "") + (form_placeholder_labels ? ", placeholder: '#{name.to_s.humanize}'" : "") + (stimmify ? ", 'data-#{@stimmify}-target': '#{camelcase_name}' " : "") + " %>\n " + "\n"
181
185
  end
182
186
  end
183
187
 
@@ -11,7 +11,7 @@ class FloatField < Field
11
11
  end
12
12
 
13
13
  def form_field_output
14
- field_output(nil, 5)
14
+ field_output('number', 5, step: 'any')
15
15
  end
16
16
 
17
17
  # def line_field_output
@@ -56,6 +56,17 @@ module HotGlue
56
56
 
57
57
 
58
58
 
59
+ begin
60
+ gemfile_contents = File.read("Gemfile")
61
+ if !gemfile_contents.include?("rspec-retry")
62
+ gemfile_contents.gsub!(/^group :test do/, "group :test do\n gem \"rspec-retry\"")
63
+ File.write("Gemfile", gemfile_contents)
64
+ puts " HOTGLUE --> added to Gemfile: `gem \"rspec-retry\"` -- run `bundle install` "
65
+ end
66
+ rescue StandardError => e
67
+ puts "WARNING: error writing to Gemfile --- #{e.message}"
68
+ end
69
+
59
70
  begin
60
71
  rails_helper_contents = File.read("#{filepath_prefix}spec/rails_helper.rb")
61
72
  if !rails_helper_contents.include?("Capybara.default_driver =")
@@ -63,6 +74,11 @@ module HotGlue
63
74
  puts " HOTGLUE --> added to spec/rails_helper.rb: `Capybara.default_driver = :selenium_chrome_headless` "
64
75
  end
65
76
 
77
+ if !rails_helper_contents.include?("Capybara.default_max_wait_time")
78
+ rails_helper_contents << "\n\n# Default of 2s is too tight for headless Chrome + Devise + Turbo page\n# renders under load, causing sporadic false-negative waits.\nCapybara.default_max_wait_time = 5\n"
79
+ puts " HOTGLUE --> added to spec/rails_helper.rb: `Capybara.default_max_wait_time = 5` "
80
+ end
81
+
66
82
  if !rails_helper_contents.include?("include FactoryBot::Syntax::Methods")
67
83
  rails_helper_contents.gsub!("RSpec.configure do |config|", "RSpec.configure do |config| \n
68
84
  config.include FactoryBot::Syntax::Methods
@@ -70,9 +86,46 @@ module HotGlue
70
86
  puts " HOTGLUE --> added to #{filepath_prefix}spec/rails_helper.rb: `config.include FactoryBot::Syntax::Methods` "
71
87
  end
72
88
 
89
+ if !rails_helper_contents.include?("type: :system) do")
90
+ rails_helper_contents.gsub!("RSpec.configure do |config|", "RSpec.configure do |config| \n
91
+ # spec/system specs run through ActionDispatch::SystemTestCase, which shares
92
+ # the DB connection between the test thread and the in-process Puma server
93
+ # thread. Plain :feature specs with a real Selenium driver don't get this,
94
+ # which causes intermittent \"record not visible to the server thread\"
95
+ # failures (e.g. login appearing to fail right after the user was created).
96
+ #
97
+ # We use :chrome (not Rails' :headless_chrome) because
98
+ # ActionDispatch::SystemTesting::Browser hardcodes the legacy `--headless`
99
+ # flag. Legacy headless Chrome runs a materially different rendering/input
100
+ # pipeline than real Chrome and has known bugs where a native click never
101
+ # reaches the page. `--headless=new` (Chrome 109+) doesn't have this problem.
102
+ config.before(:each, type: :system) do
103
+ driven_by :selenium, using: :chrome, screen_size: [1366, 1200] do |options|
104
+ options.add_argument(\"--headless=new\")
105
+ end
106
+ end
107
+
108
+ # Real-browser system specs still hit transient, infrastructure-level
109
+ # flakiness that has nothing to do with application correctness (a click
110
+ # occasionally dropped by the browser, a Turbo navigation racing a
111
+ # Capybara content read into an error Capybara doesn't retry on its own).
112
+ # Retrying the whole example -- rather than chasing each transient error
113
+ # class individually -- is the standard fix for this. rspec-retry
114
+ # re-instantiates the example group on retry so `let`/`let!` factories
115
+ # actually re-run instead of reusing stale memoized state.
116
+ config.verbose_retry = true
117
+ config.default_retry_count = 3
118
+ config.retry_callback = proc { Capybara.reset_sessions! }
119
+ config.around(:each, type: :system) do |example|
120
+ example.run_with_retry retry: 3
121
+ end
122
+ ")
123
+ puts " HOTGLUE --> added to #{filepath_prefix}spec/rails_helper.rb: `config.before(:each, type: :system) { driven_by :selenium, using: :chrome, --headless=new }` and rspec-retry config "
124
+ end
125
+
73
126
  if ! rails_helper_contents.include?("require 'support/capybara_login.rb'")
74
- rails_helper_contents.gsub!("require 'rspec/rails'","require 'rspec/rails' \nrequire 'support/capybara_login.rb'")
75
- puts " HOTGLUE --> added to spec/rails_helper.rb: `require 'support/capybara_login.rb'` "
127
+ rails_helper_contents.gsub!("require 'rspec/rails'","require 'rspec/rails' \nrequire 'rspec/retry' \nrequire 'support/capybara_login.rb'")
128
+ puts " HOTGLUE --> added to spec/rails_helper.rb: `require 'rspec/retry'` and `require 'support/capybara_login.rb'` "
76
129
  end
77
130
  File.write("#{filepath_prefix}spec/rails_helper.rb", rails_helper_contents)
78
131
 
@@ -138,6 +191,7 @@ module HotGlue
138
191
  rescue StandardError => e
139
192
  puts "WARNING: error writing to #{Rails.env.test? ? 'spec/dummmy/' : ''}spec/support/capybara_login.rb --- #{e.message}"
140
193
  end
194
+
141
195
  end
142
196
  end
143
197
  end
@@ -13,7 +13,7 @@ module HotGlue
13
13
  :form_path, :layout_object, :search_clear_button, :search_autosearch,
14
14
  :stimmify, :stimmify_camel, :hidden_create, :hidden_update, :invisible_create,
15
15
  :invisible_update, :plural, :phantom_search, :pagination_style,
16
- :namespace, :controller_build_folder
16
+ :namespace, :controller_build_folder, :sortable, :sortable_fields
17
17
 
18
18
 
19
19
  def initialize(singular:, singular_class: ,
@@ -27,9 +27,12 @@ module HotGlue
27
27
  search_clear_button:, search_autosearch:, layout_object:,
28
28
  form_path: , stimmify: , stimmify_camel:, hidden_create:, hidden_update: ,
29
29
  invisible_create:, invisible_update: , plural: , phantom_search:,
30
- pagination_style:, namespace: nil, controller_build_folder: nil )
30
+ pagination_style:, namespace: nil, controller_build_folder: nil,
31
+ sortable: false, sortable_fields: [] )
31
32
 
32
33
 
34
+ @sortable = sortable
35
+ @sortable_fields = sortable_fields
33
36
  @form_path = form_path
34
37
  @search = search
35
38
  @search_fields = search_fields
@@ -106,7 +109,11 @@ module HotGlue
106
109
  "<div class='#{layout_strategy.column_classes_for_column_headings(size)} hg-heading-row heading--#{singular}--#{column.join("-")}' " + col_style + ">" +
107
110
  column.map(&:to_s).map{|col_name|
108
111
  unless col_name.starts_with?("**")
109
- the_output = "#{col_name.humanize}"
112
+ if @sortable && @sortable_fields.collect(&:to_s).include?(col_name)
113
+ the_output = "<%= sort_link(:#{col_name}, '#{col_name.humanize}') %>"
114
+ else
115
+ the_output = "#{col_name.humanize}"
116
+ end
110
117
  else
111
118
  the_output = ""
112
119
  end
@@ -34,7 +34,8 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
34
34
  :search_clear_button, :search_autosearch, :include_object_names,
35
35
  :stimmify, :stimmify_camel, :hidden_create, :hidden_update,
36
36
  :invisible_create, :invisible_update, :phantom_create_params,
37
- :phantom_update_params, :lazy, :back_link_to_parent, :polymorphic_parents
37
+ :phantom_update_params, :lazy, :back_link_to_parent, :polymorphic_parents,
38
+ :sortable, :sortable_fields
38
39
 
39
40
  # important: using an attr_accessor called :namespace indirectly causes a conflict with Rails class_name method
40
41
  # so we use namespace_value instead
@@ -144,6 +145,10 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
144
145
 
145
146
  class_option :phantom_search, default: nil
146
147
 
148
+ # SORT OPTIONS
149
+ class_option :sortable, type: :boolean, default: false
150
+ class_option :sort_fields, default: nil # comma separated whitelist; defaults to all sortable-type fields
151
+
147
152
 
148
153
 
149
154
  def initialize(*meta_args)
@@ -752,6 +757,27 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
752
757
  @columns_map[col] = this_column_object.field
753
758
  end
754
759
 
760
+ @sortable = options['sortable']
761
+
762
+ if @sortable
763
+ if options['sort_fields']
764
+ @sortable_fields = options['sort_fields'].split(',').collect(&:to_sym)
765
+ @sortable_fields.each do |field|
766
+ if !@columns_map[field]
767
+ raise "You specified a sort field for #{field} but that field is not in the list of columns"
768
+ elsif !@columns_map[field].sortable?
769
+ raise "You specified a sort field for #{field} but that field type cannot be sorted (e.g. an association or a UUID)"
770
+ end
771
+ end
772
+ else
773
+ @sortable_fields = @columns_map.select { |col, field| field.sortable? }.keys
774
+ end
775
+
776
+ warn_about_unindexed_sortable_fields
777
+ else
778
+ @sortable_fields = []
779
+ end
780
+
755
781
 
756
782
  @columns_map.each do |key, field|
757
783
  if field.is_a?(AssociationField)
@@ -928,7 +954,9 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
928
954
  phantom_search: @phantom_search,
929
955
  pagination_style: @pagination_style,
930
956
  namespace: @namespace,
931
- controller_build_folder: @controller_build_folder
957
+ controller_build_folder: @controller_build_folder,
958
+ sortable: @sortable,
959
+ sortable_fields: @sortable_fields
932
960
  )
933
961
  elsif @markup == "slim"
934
962
  raise(HotGlue::Error, "SLIM IS NOT IMPLEMENTED")
@@ -1265,7 +1293,7 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
1265
1293
  end
1266
1294
 
1267
1295
  unless @no_specs
1268
- dest_file = File.join("#{filepath_prefix}spec/features#{namespace_with_dash}", "#{plural}_behavior_spec.rb")
1296
+ dest_file = File.join("#{filepath_prefix}spec/system#{namespace_with_dash}", "#{plural}_behavior_spec.rb")
1269
1297
 
1270
1298
  if File.exist?(dest_file)
1271
1299
  existing_file = File.open(dest_file)
@@ -1997,6 +2025,17 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
1997
2025
  end
1998
2026
 
1999
2027
 
2028
+ def warn_about_unindexed_sortable_fields
2029
+ indexed_columns = @the_object.connection.indexes(@the_object.table_name).collect { |index| index.columns.first }
2030
+ unindexed = @sortable_fields.reject { |field| indexed_columns.include?(field.to_s) }
2031
+ return if unindexed.empty?
2032
+
2033
+ puts "********************"
2034
+ puts "WARNING: The following fields are sortable but have no database index, which may cause slow queries as the table grows: #{unindexed.join(', ')}"
2035
+ puts "Consider adding indexes, e.g.: " + unindexed.collect { |field| "add_index :#{plural}, :#{field}" }.join("; ")
2036
+ puts "********************"
2037
+ end
2038
+
2000
2039
  def load_all_code
2001
2040
  # the inner method definition of the load_all_* method
2002
2041
  res = +""
@@ -2068,6 +2107,12 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
2068
2107
  res << "\n"
2069
2108
  end
2070
2109
 
2110
+ if @sortable
2111
+ res << "\n"
2112
+ res << " if SORTABLE_FIELDS.include?(params[:sort]) && %w[asc desc].include?(params[:direction])\n"
2113
+ res << " @#{plural} = @#{plural}.order(params[:sort] => params[:direction].to_sym)\n"
2114
+ res << " end"
2115
+ end
2071
2116
 
2072
2117
  if @pagination_style == "kaminari"
2073
2118
  res << " @#{plural} = @#{plural}.page(params[:page])#{ ".per(per)" if @paginate_per_page_selector }"
@@ -6,10 +6,5 @@ def login_as(user)
6
6
  end
7
7
  click_button 'Log in'
8
8
 
9
- # headless Chrome/Selenium occasionally drops this click without submitting
10
- # the form at all (confirmed via server log: no POST /users/sign_in received).
11
- # Retry once before failing for real.
12
- click_button 'Log in' unless page.has_content?('Signed in successfully', wait: 3)
13
-
14
9
  expect(page).to have_content("Signed in successfully")
15
10
  end
@@ -77,6 +77,8 @@ class <%= controller_class_name %> < <%= controller_descends_from %>
77
77
  params[:per] || 10
78
78
  end<% end %>
79
79
  <% unless @no_list %>
80
+ <% if @sortable %> SORTABLE_FIELDS = %w[<%= @sortable_fields.join(' ') %>].freeze
81
+ <% end %>
80
82
  def load_all_<%= plural %><% if @search == "set" %>
81
83
  @q = params[:q] || <%= search_default %> <% end %>
82
84
  <%= load_all_code %>
@@ -1,5 +1,5 @@
1
1
  module HotGlue
2
2
  class Version
3
- CURRENT = '0.7.8'
3
+ CURRENT = '0.8'
4
4
  end
5
5
  end
@@ -19,6 +19,7 @@ rm -rf dummy/app/views/humans/*
19
19
  rm -rf dummy/app/views/pets/*
20
20
 
21
21
  /bin/rm -rf dummy/spec/features/
22
+ /bin/rm -rf dummy/spec/system/
22
23
 
23
24
 
24
25
  # !("application_controller.rb"|"welcome_controller.rb")
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hot-glue
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.8
4
+ version: '0.8'
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jason Fleetwood-Boldt
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-08-22 00:00:00.000000000 Z
11
+ date: 2026-08-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails