hot-glue 0.6.26.1 → 0.6.28

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: 077bb2e61017931d3db8f961922f3af0d4440bfd9900cc56f86bfa26aeb2e188
4
- data.tar.gz: 3feecb2d560274cab61e7cb5f673175cf426fd6d7cef09112612e72f88e74038
3
+ metadata.gz: 139de0a1f6e85c50561d3b69a74618abe2fc808908b7d217adefcd23bf1ee569
4
+ data.tar.gz: 547d675591fbf331fb2019fc29ddb5bebb080cdd97f523f4c5b8c9ca703739f1
5
5
  SHA512:
6
- metadata.gz: e2add6dcc569806f8953976332a63f29ea4cfa309ced3b8fdeb97b5c9108d030711d01a39fde8029bbfcacdde8fd7b0229861647258a40e340d1deeacfed13f8
7
- data.tar.gz: 0c36945b6007e22bd672822bd206f842a1cd7eea54e819652fce71d613c66d8791b3902c51cb7c177f1c743a6e7a7241679b19e274e34e12bafe1dd06acbc187
6
+ metadata.gz: 565d6cc9513225395e67015b00b7ef669be883fed53777d0a737328018241a7e2982dc2783bca48962ec7c0eb469ed816ca624b0c444d28f392b103b234364f6
7
+ data.tar.gz: 1ab45d51300b844444206c685b8ac068dc9b5e22e5399691d342173a5c00c9e0a238673b599a326a8f5919b6e6df78b4f3937fe6fcaf89a328701957cd36626c
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- hot-glue (0.6.26)
4
+ hot-glue (0.6.27)
5
5
  ffaker (~> 2.16)
6
6
  kaminari (~> 1.2)
7
7
  rails (> 5.1)
data/README.md CHANGED
@@ -1680,7 +1680,7 @@ Within each option is a label and ruby scope, separated by a colon (:).
1680
1680
 
1681
1681
  The label comes before the colon the ruby scope. The ruby scope should be specified here without a dot. Each ruby scope must be defined on your model. If there is no scope specified, we assume "all", but we still need to specify a label for "All", which is why in the example above "All" has no colon after it.
1682
1682
 
1683
- example
1683
+ #### Radio Example
1684
1684
 
1685
1685
  `--phantom-search='radio_status[Pending:pending|Rejected:rejected|Accepted:accepted|All]'`
1686
1686
 
@@ -1702,10 +1702,33 @@ This produces a search interface with four options listed as radio buttons:
1702
1702
 
1703
1703
  The pending, approved, and rejected options will return search results with the corresponding scopes applied. The 'All' option will behave as a no-op, leaving the root search intact (giving all of the other modifications that Hot glue provides in different functionality).
1704
1704
 
1705
- #### Predicate Search
1706
- NOT IMPLEMENTED YET
1707
- TODO: implement me
1705
+ ##### Checkboxes example
1706
+
1707
+ `rails generate hot_glue:scaffold Invoice --gd --phantom-search='checkboxes_AAA[With Paid:not_paid:|Hide free accounts::without_free_accounts]'`
1708
+
1709
+
1710
+ The syntax is similiar to the radio buttons except that each choice (within `[...]`, separated by `|`) is required to have THREE options, separated by colons `:`
1711
+ 1) the label
1712
+ 2) the OFF case (checkbox is unchecked)
1713
+ 3) the ON case (checkbox is checked)
1714
+
1715
+ The scope definition between the `:` characters **may be empty**, in which case this is interprested as "all"
1716
+
1717
+ Since checkboxes start as off (unchecked) by default, you can create layouts that show the normal case with the checkboxes off, but show special cases with the checkboxes on.
1718
+ (This can either exclude or include depending on your preference.)
1719
+
1720
+ In this Invoice scaffold, we have two scopes, searching for fields on our invoice model:
1721
+
1722
+ `scope :not_paid, -> {where(paid_at: nil)}`
1723
+ `scope :without_free_accounts, -> {where(free_account: false)}`
1708
1724
 
1725
+ In the checkboxes phantom search we build above, notice by default:
1726
+
1727
+ - the PAID invoices do not appear in the search result (the scope `.not_paid` is applied as the OFF scope for the "With Paid" choice. So when you load the page, you see only unpaid invoices. If you check "With Paid" checkbox, there is no scope specified "all" is used indicating not modification is applied and all records are shown.
1728
+ - both free & non-free accounts (which are simply tracked by a boolean `free_account`) are shown by default, but when you use the "Hide free accounts" checkbox, the scope `.without_free_accounts` is applied, thus hiding the free accounts.
1729
+
1730
+ Remember, unlike radio choices which apply exclusively (since the user can select only 1 radio choice at time), checkboxes create
1731
+ combined search criteria. These combine with all of the other search criteria within the search set, making one big "AND ... AND ... AND" query.
1709
1732
 
1710
1733
  ### `--stimmify` or `--stimmify=xyz`
1711
1734
 
@@ -2210,6 +2233,18 @@ These automatic pickups for partials are detected at build time. This means that
2210
2233
 
2211
2234
 
2212
2235
  # VERSION HISTORY
2236
+
2237
+ #### 2025-09-26 - v.0.6.28
2238
+ - Checkboxes option for Phantom Search (previously phantom searches only supported radio).
2239
+ See "Checkboxes example" under the docs for `--phantom-search` above
2240
+
2241
+ #### 2025-09-24 - v0.6.27
2242
+ - Fixes to namespaced models (this is when the model file has a namespace); it now correctly does not namespace the route (fix to plurality)
2243
+
2244
+ - Fixes timezone awareness on **time field** inputs; your current_user must have a timezone (string) object
2245
+ This jerry-rigs a timezone (based on the current user's timezone & daylight savings time) onto the time object, storing it as-if it is in UTC (even though time fields are not associated with a timezone)
2246
+
2247
+
2213
2248
  #### 2025-09-16 - v0.6.26
2214
2249
  • Phantom Searching
2215
2250
  `--phantom-search='{type}_{name}[All|choice A:scope_a|choice B:scope_b],radio_yyyy[choice C:scope_c|]`
@@ -45,9 +45,7 @@ module HotGlue
45
45
  # returns a TimeZone (https://apidock.com/rails/TimeZone) object
46
46
  if defined?(current_user)
47
47
  if current_user.try(:timezone)
48
- current_user.timezone
49
-
50
- # Time.now.in_time_zone(current_user.timezone.to_i).zone
48
+ ActiveSupport::TimeZone[current_user.timezone]
51
49
  else
52
50
  Rails.application.config.time_zone
53
51
  # Time.zone.name
@@ -58,6 +56,49 @@ module HotGlue
58
56
  end
59
57
  end
60
58
 
59
+ def formatted_time_display(object, method, current_user)
60
+ tz = ActiveSupport::TimeZone[current_user.timezone]
61
+
62
+ t = object.public_send(method)
63
+
64
+ # Build UTC datetime for today + stored time
65
+ utc_datetime = Time.utc(
66
+ Time.now.year,
67
+ Time.now.month,
68
+ Time.now.day,
69
+ t.hour,
70
+ t.min,
71
+ t.sec
72
+ )
73
+
74
+ # Convert to user's timezone (DST-aware)
75
+ local_time = utc_datetime.in_time_zone(tz)
76
+
77
+ local_time.strftime('%-l:%M %p %Z')
78
+ end
79
+
80
+ def formatted_time_field(object, method, current_user)
81
+ tz = ActiveSupport::TimeZone[current_user.timezone]
82
+
83
+ t = object.public_send(method)
84
+
85
+ # Build UTC datetime from the stored time
86
+ utc_datetime = Time.utc(
87
+ Time.now.year,
88
+ Time.now.month,
89
+ Time.now.day,
90
+ t.hour,
91
+ t.min,
92
+ t.sec
93
+ )
94
+
95
+ # Convert to user's timezone (DST-aware)
96
+ local_time = utc_datetime.in_time_zone(tz)
97
+
98
+ # Format for HTML5 <input type="time"> (24h clock, HH:MM)
99
+ local_time.strftime('%H:%M')
100
+ end
101
+
61
102
  def date_to_current_timezone(date, timezone = nil)
62
103
  # used for displaying when in EDIT mode
63
104
  # (this format is how the browser expectes to receive the value='' of the input field)
@@ -79,71 +120,112 @@ module HotGlue
79
120
  "#{sign}#{hour_abs}#{minute_str}"
80
121
  end
81
122
 
82
- def modify_date_inputs_on_params(modified_params, current_user_object = nil, field_list = {})
83
-
84
- use_timezone = if current_user_object.try(:timezone)
85
- (ActiveSupport::TimeZone[current_user_object.timezone])
86
- else
87
- Time.zone
88
- end
123
+ # def modify_date_inputs_on_params(modified_params, current_user_object = nil, field_list = {})
124
+ #
125
+ # use_timezone = if current_user_object.try(:timezone)
126
+ # (ActiveSupport::TimeZone[current_user_object.timezone])
127
+ # else
128
+ # Time.zone
129
+ # end
130
+ #
131
+ #
132
+ # uses_dst = (current_user_object.try(:locale_uses_dst)) || false
133
+ #
134
+ # modified_params = modified_params.tap do |params|
135
+ # params.keys.each{|k|
136
+ # if field_list.is_a?(Hash)
137
+ # include_me = field_list[k.to_sym].present?
138
+ # elsif field_list.is_a?(Array)
139
+ # field_list.include?(k.to_sym)
140
+ # end
141
+ #
142
+ # parsables = {
143
+ # datetime: "%Y-%m-%d %H:%M %z",
144
+ # time: "%H:%M %z"
145
+ # }
146
+ #
147
+ #
148
+ # if include_me && params[k].present?
149
+ # input_value = params[k].gsub("T", " ") # e.g. "2025-09-24 14:00" or "14:00"
150
+ #
151
+ # if field_list.is_a?(Array)
152
+ # # Datetime inputs (e.g. datetime-local)
153
+ # parsed_time = Time.strptime(input_value, "%Y-%m-%d %H:%M")
154
+ # parsed_time = parsed_time.utc.change(sec: 0)
155
+ # else
156
+ # case field_list[k.to_sym]
157
+ # when :datetime
158
+ # parsed_time = Time.strptime(input_value, "%Y-%m-%d %H:%M")
159
+ # parsed_time = parsed_time.utc.change(sec: 0)
160
+ # when :time
161
+ #
162
+ # Rails.logger.info("input_value: #{input_value}")
163
+ # # Parse as hour/minute only, no zone
164
+ # t = Time.strptime(input_value, "%H:%M")
165
+ #
166
+ # # Build a UTC time with today's date
167
+ # parsed_time = Time.utc(Time.now.year, Time.now.month, Time.now.day, t.hour, t.min, 0)
168
+ # # Convert back to a plain "time of day" (for DB `time` column)
169
+ # parsed_time = parsed_time.to_time.change(sec: 0)
170
+ # Rails.logger.info("parsed_time: #{parsed_time}")
171
+ #
172
+ # else
173
+ # raise "Unsupported field type: #{field_list[k.to_sym]}"
174
+ # end
175
+ # end
176
+ #
177
+ # Rails.logger.info "parsed_time #{parsed_time}"
178
+ # params[k] = parsed_time
179
+ # end
180
+ # }
181
+ # end
182
+ # modified_params
183
+ # end
89
184
 
185
+ def modify_date_inputs_on_params(modified_params, current_user_object = nil, field_list = {})
186
+ use_timezone =
187
+ if current_user_object.try(:timezone)
188
+ ActiveSupport::TimeZone[current_user_object.timezone]
189
+ else
190
+ Time.zone
191
+ end
90
192
 
91
- uses_dst = (current_user_object.try(:locale_uses_dst)) || false
193
+ modified_params.tap do |params|
194
+ params.keys.each do |k|
195
+ include_me =
196
+ if field_list.is_a?(Hash)
197
+ field_list[k.to_sym].present?
198
+ elsif field_list.is_a?(Array)
199
+ field_list.include?(k.to_sym)
200
+ end
92
201
 
93
- modified_params = modified_params.tap do |params|
94
- params.keys.each{|k|
95
- if field_list.is_a?(Hash)
96
- include_me = field_list[k.to_sym].present?
97
- elsif field_list.is_a?(Array)
98
- field_list.include?(k.to_sym)
202
+ next unless include_me && params[k].present?
203
+
204
+ input_value = params[k].gsub("T", " ") # "13:00" or "2025-09-24 13:00"
205
+
206
+ case field_list[k.to_sym]
207
+ when :datetime
208
+ # Interpret input as in user's local time zone
209
+ local_time = use_timezone.strptime(input_value, "%Y-%m-%d %H:%M")
210
+ # Convert to UTC for storage
211
+ parsed_time = local_time.utc.change(sec: 0)
212
+ when :time
213
+ # Parse as HH:MM (local wall clock time)
214
+ t = Time.strptime(input_value, "%H:%M")
215
+ # Interpret in user's timezone, with today's date
216
+ local_time = use_timezone.local(Time.now.year, Time.now.month, Time.now.day, t.hour, t.min, 0)
217
+ # Convert to UTC for storage
218
+ parsed_time = local_time.utc
219
+ else
220
+ next
99
221
  end
100
222
 
101
- parsables = {
102
- datetime: "%Y-%m-%d %H:%M %z",
103
- time: "%H:%M %z"
104
- }
105
-
106
-
107
- if include_me && params[k].present?
108
- if use_timezone
109
- natural_offset = use_timezone.formatted_offset
110
- hour = natural_offset.split(":").first.to_i
111
- min = natural_offset.split(":").last.to_i
112
-
113
- hour = hour + 1 if uses_dst && is_dst_now?
114
-
115
- use_offset = format_timezone_offset(hour, min)
116
- parse_date = "#{params[k].gsub("T", " ")} #{use_offset}"
117
-
223
+ Rails.logger.info "input_value: #{input_value}"
224
+ Rails.logger.info "parsed_time: #{parsed_time} (#{parsed_time.zone})"
118
225
 
119
- Rails.logger.info("use_offset: #{use_offset}")
120
-
121
- Rails.logger.info("parse_date: #{parse_date}")
122
-
123
- # note: as according to https://stackoverflow.com/questions/20111413/html5-datetime-local-control-how-to-hide-seconds
124
- # there is no way to set the seconds to 00 in the datetime-local input field
125
- # as I have implemented a "seconds don't matter" solution,
126
- # the only solution is to avoid setting any non-00 datetime values into the database
127
- # if they already exist in your database, you should zero them out
128
- # or apply .change(sec: 0) when displaying them as output in the form
129
- # this will prevent seconds from being added by the browser
130
- if field_list.is_a?(Array)
131
- parsed_time = Time.strptime(parse_date, "%Y-%m-%d %H:%M %z")
132
- else
133
- parsed_time = Time.strptime(parse_date, parsables[field_list[k.to_sym]])
134
- end
135
- Rails.logger.info "parsed_time #{parsed_time}"
136
- Rails.logger.info "Timezone: #{use_timezone.name}"
137
- Rails.logger.info "Offset: #{use_timezone.formatted_offset}"
138
- Rails.logger.info "DST? #{uses_dst} | is_dst_now? => #{is_dst_now?}"
139
- Rails.logger.info "Final offset used: #{use_offset}"
140
-
141
- params[k] = parsed_time
142
- end
143
- end
144
- }
226
+ params[k] = parsed_time
227
+ end
145
228
  end
146
- modified_params
147
229
  end
148
230
 
149
231
  def hawk_params(hawk_schema, modified_params)
@@ -5,15 +5,15 @@ class TimeField < Field
5
5
  end
6
6
 
7
7
  def form_field_output
8
- "<%= time_field_localized(f, :#{name}, #{singular}.#{name}&.in_time_zone(current_user.timezone)&.strftime('%H:%M'), label: '#{ name.to_s.humanize }') %>"
8
+ "<%= time_field_localized(f, :#{name}, formatted_time_field(#{singular}, :#{name}, current_user), label: \"#{ name.to_s.humanize } \#{ current_user.timezone }\") %>"
9
9
  end
10
10
 
11
11
  def line_field_output
12
- "<% unless #{singular}.#{name}.nil? %>
13
- <%= #{singular}.#{name}.in_time_zone(current_timezone).strftime('%l:%M %p %Z') %>
14
- <% else %>
15
- <span class=''>MISSING</span>
16
- <% end %>"
12
+ "\n <% unless #{singular}.#{name}.nil? %>
13
+ <%= formatted_time_display(#{singular}, :#{name}, current_user) %>
14
+ <% else %>
15
+ <span class=''>MISSING</span>
16
+ <% end %>\n"
17
17
  end
18
18
 
19
19
  def spec_setup_and_change_act(which_partial = nil)
@@ -149,22 +149,29 @@ module HotGlue
149
149
  # phantom searches
150
150
  @phantom_search.each_key do |search_field|
151
151
  data = @phantom_search[search_field]
152
- if data[:type] == "radio"
153
- res << "<div>"
152
+ res << "<div>"
153
+ res << "<label>#{data[:name]}</label><br />"
154
154
 
155
- res << "<label>#{data[:name]}</label><br />"
156
-
157
- data[:choices].each do |choice|
155
+ data[:choices].each do |choice|
156
+ dom_label = choice[:label].downcase.gsub(" ","_")
157
+ if data[:type] == "radio"
158
158
  res << "\n<input type='radio'
159
- id='#{search_field}_search__#{choice[:label]}'
160
- name='q[0][#{search_field}_search]' value='#{choice[:label]}'
161
- <%= 'checked' if @q['0'][:#{search_field}_search] == \"#{choice[:label]}\" %> />"
162
- res << "\n<label for='#{search_field}_search__#{choice[:label]}'>#{choice[:label]}</label> <br/>"
159
+ id='#{search_field}_search__#{dom_label}}'
160
+ name='q[0][#{search_field}_search]' value='#{dom_label}'
161
+ <%= 'checked' if @q['0'][:#{search_field}_search] == \"#{dom_label}\" %> />"
162
+ elsif data[:type] == "checkboxes"
163
+ res << "\n<input type='checkbox'
164
+ id='#{search_field}_search__#{dom_label}'
165
+ name='q[0][#{search_field}_search__#{dom_label}]'
166
+ value='1'
167
+ <%= 'checked' if @q['0'][:#{search_field}_search__#{dom_label}] %> />"
168
+
163
169
  end
170
+ res << "\n<label for='#{search_field}_search__#{dom_label}'>#{choice[:label]}</label> <br/>"
171
+ end
164
172
 
165
- res << "</div>"
173
+ res << "</div>"
166
174
 
167
- end
168
175
  end
169
176
 
170
177
 
@@ -202,18 +202,22 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
202
202
  end
203
203
 
204
204
  args = meta_args[0]
205
+
206
+
205
207
  @singular = args.first.tableize.singularize # should be in form hello_world
206
208
 
207
209
  if @singular.include?("/")
208
210
  @singular = @singular.split("/").last
209
211
  end
210
212
 
211
- @plural = (options['plural'] || args.first.tableize.singularize.pluralize) # respects what you set in inflections.rb, to override, use plural option
212
-
213
+ @plural = (options['plural'] || args.first.tableize.singularize.pluralize)
214
+ if @plural.include?("/")
215
+ @plural = @plural.split("/").last
216
+ end
217
+ # respects what you set in inflections.rb, to override, use plural option
213
218
  puts "SINGULAR: #{@singular}"
214
219
  puts "PLURAL: #{@plural}"
215
220
 
216
-
217
221
  @namespace = options['namespace'] || nil
218
222
  @namespace_value = @namespace
219
223
  use_controller_name = plural.titleize.gsub(" ", "")
@@ -727,16 +731,30 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
727
731
  }
728
732
 
729
733
  choices.each do |choice|
730
- choice_label = choice.split(":")[0]
731
- choice_scope = choice.split(":")[1]
732
- if choice_scope.nil?
734
+ if type == "radio"
735
+ choice_label = choice.split(":")[0]
736
+ choice_scope = choice.split(":")[1]
737
+ elsif type == "checkboxes"
738
+ choice_label = choice.split(":")[0]
739
+ choice_scope_negative = choice.split(":")[1]
740
+ choice_scope = choice.split(":")[2]
741
+ end
742
+
743
+ if choice_scope.nil? || choice_scope.strip.empty?
733
744
  choice_scope = "all"
734
745
  end
735
746
 
747
+ if choice_scope_negative.nil? || choice_scope_negative.strip.empty?
748
+ choice_scope_negative = "all"
749
+ end
750
+
736
751
  choice_scope = ".#{choice_scope}" if !choice_scope.start_with?(".")
752
+ choice_scope_negative = ".#{choice_scope_negative}" if !choice_scope_negative.start_with?(".")
753
+
737
754
  @phantom_search[label.to_sym][:choices] << {
738
755
  label: choice_label,
739
756
  scope: choice_scope,
757
+ scope_negative: choice_scope_negative,
740
758
  }
741
759
  end
742
760
  puts "phantom search #{@phantom_search}"
@@ -1830,11 +1848,25 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
1830
1848
  end
1831
1849
 
1832
1850
  @phantom_search.each do |phantom_key, phantom_data|
1833
- phantom_data[:choices].each do |choice|
1834
- unless choice[:scope] == ".all"
1835
- res << "\n @#{plural} = @#{plural}#{choice[:scope]} if @q['0'][:#{phantom_key}_search] == \"#{choice[:label]}\""
1851
+ if phantom_data[:type] == "radio"
1852
+ phantom_data[:choices].each do |choice|
1853
+ unless choice[:scope] == ".all"
1854
+ res << "\n @#{plural} = @#{plural}#{choice[:scope]} if @q['0'][:#{phantom_key}_search] == \"#{choice[:label]}\""
1855
+ end
1856
+ end
1857
+ elsif phantom_data[:type] == "checkboxes"
1858
+ phantom_data[:choices].each do |choice|
1859
+
1860
+ # positive case
1861
+ unless choice[:scope] == ".all"
1862
+ res << "\n @#{plural} = @#{plural}#{choice[:scope]} if @q['0'][:#{phantom_key}_search__#{choice[:label].gsub(" ", "_").downcase}] == \"1\""
1863
+ end
1864
+ unless choice[:scope_negative] == ".all"
1865
+ res << "\n @#{plural} = @#{plural}#{choice[:scope_negative]} if @q['0'][:#{phantom_key}_search___#{choice[:label].gsub(" ", "_").downcase}] != \"1\""
1866
+ end
1836
1867
  end
1837
1868
  end
1869
+
1838
1870
  res << "\n"
1839
1871
  end
1840
1872
 
@@ -1903,12 +1935,24 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
1903
1935
  }.reduce({}, :merge)
1904
1936
 
1905
1937
  phantom_search_fields = @phantom_search.collect{| k,v|
1906
- default = v[:choices][0]
1907
- {
1908
- "#{k}_match".to_sym => "",
1909
- "#{k}_search".to_sym => "#{default[:label]}"
1910
- }
1911
- }.reduce({}, :merge)
1938
+ if v[:type] == "radio"
1939
+ default = v[:choices][0]
1940
+ {
1941
+ "#{k}_match".to_sym => "",
1942
+ "#{k}_search".to_sym => "#{default[:label]}"
1943
+ }
1944
+ elsif v[:type] == "checkboxes"
1945
+ v[:choices].collect{ |c|
1946
+ {
1947
+ "#{k}_#{c[:label].gsub(" ", "_").downcase}".to_sym => ""
1948
+ }
1949
+ }
1950
+ end
1951
+ }
1952
+
1953
+ phantom_search_fields.flatten!
1954
+ phantom_search_fields = phantom_search_fields.reduce({}, :merge)
1955
+
1912
1956
  return {"0" => (default_fields.merge(phantom_search_fields))}
1913
1957
  end
1914
1958
  end
@@ -1,5 +1,5 @@
1
1
  module HotGlue
2
2
  class Version
3
- CURRENT = '0.6.26.1'
3
+ CURRENT = '0.6.28'
4
4
  end
5
5
  end
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.6.26.1
4
+ version: 0.6.28
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: 2025-09-16 00:00:00.000000000 Z
11
+ date: 2025-09-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails