phlexible 2.2.0 → 3.0.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.
@@ -0,0 +1,14 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "appraisal"
6
+ gem "combustion"
7
+ gem "debug"
8
+ gem "rake", "~> 13.0"
9
+ gem "rubocop", "~> 1.55"
10
+ gem "sus"
11
+ gem "phlex", ">= 2.1.0", "< 3.0.0"
12
+ gem "phlex-rails", ">= 2.1.0", "< 3.0.0"
13
+
14
+ gemspec path: "../"
@@ -0,0 +1,254 @@
1
+ PATH
2
+ remote: ..
3
+ specs:
4
+ phlexible (2.2.0)
5
+ phlex (>= 1.10.0, < 3.0.0)
6
+ phlex-rails (>= 1.2.0, < 3.0.0)
7
+ rails (>= 7.2.0, < 9.0.0)
8
+ zeitwerk (~> 2.7.2)
9
+
10
+ GEM
11
+ remote: https://rubygems.org/
12
+ specs:
13
+ actioncable (8.0.2)
14
+ actionpack (= 8.0.2)
15
+ activesupport (= 8.0.2)
16
+ nio4r (~> 2.0)
17
+ websocket-driver (>= 0.6.1)
18
+ zeitwerk (~> 2.6)
19
+ actionmailbox (8.0.2)
20
+ actionpack (= 8.0.2)
21
+ activejob (= 8.0.2)
22
+ activerecord (= 8.0.2)
23
+ activestorage (= 8.0.2)
24
+ activesupport (= 8.0.2)
25
+ mail (>= 2.8.0)
26
+ actionmailer (8.0.2)
27
+ actionpack (= 8.0.2)
28
+ actionview (= 8.0.2)
29
+ activejob (= 8.0.2)
30
+ activesupport (= 8.0.2)
31
+ mail (>= 2.8.0)
32
+ rails-dom-testing (~> 2.2)
33
+ actionpack (8.0.2)
34
+ actionview (= 8.0.2)
35
+ activesupport (= 8.0.2)
36
+ nokogiri (>= 1.8.5)
37
+ rack (>= 2.2.4)
38
+ rack-session (>= 1.0.1)
39
+ rack-test (>= 0.6.3)
40
+ rails-dom-testing (~> 2.2)
41
+ rails-html-sanitizer (~> 1.6)
42
+ useragent (~> 0.16)
43
+ actiontext (8.0.2)
44
+ actionpack (= 8.0.2)
45
+ activerecord (= 8.0.2)
46
+ activestorage (= 8.0.2)
47
+ activesupport (= 8.0.2)
48
+ globalid (>= 0.6.0)
49
+ nokogiri (>= 1.8.5)
50
+ actionview (8.0.2)
51
+ activesupport (= 8.0.2)
52
+ builder (~> 3.1)
53
+ erubi (~> 1.11)
54
+ rails-dom-testing (~> 2.2)
55
+ rails-html-sanitizer (~> 1.6)
56
+ activejob (8.0.2)
57
+ activesupport (= 8.0.2)
58
+ globalid (>= 0.3.6)
59
+ activemodel (8.0.2)
60
+ activesupport (= 8.0.2)
61
+ activerecord (8.0.2)
62
+ activemodel (= 8.0.2)
63
+ activesupport (= 8.0.2)
64
+ timeout (>= 0.4.0)
65
+ activestorage (8.0.2)
66
+ actionpack (= 8.0.2)
67
+ activejob (= 8.0.2)
68
+ activerecord (= 8.0.2)
69
+ activesupport (= 8.0.2)
70
+ marcel (~> 1.0)
71
+ activesupport (8.0.2)
72
+ base64
73
+ benchmark (>= 0.3)
74
+ bigdecimal
75
+ concurrent-ruby (~> 1.0, >= 1.3.1)
76
+ connection_pool (>= 2.2.5)
77
+ drb
78
+ i18n (>= 1.6, < 2)
79
+ logger (>= 1.4.2)
80
+ minitest (>= 5.1)
81
+ securerandom (>= 0.3)
82
+ tzinfo (~> 2.0, >= 2.0.5)
83
+ uri (>= 0.13.1)
84
+ appraisal (2.5.0)
85
+ bundler
86
+ rake
87
+ thor (>= 0.14.0)
88
+ ast (2.4.3)
89
+ base64 (0.2.0)
90
+ benchmark (0.4.0)
91
+ bigdecimal (3.1.9)
92
+ builder (3.3.0)
93
+ combustion (1.5.0)
94
+ activesupport (>= 3.0.0)
95
+ railties (>= 3.0.0)
96
+ thor (>= 0.14.6)
97
+ concurrent-ruby (1.3.5)
98
+ connection_pool (2.5.1)
99
+ crass (1.0.6)
100
+ date (3.4.1)
101
+ debug (1.10.0)
102
+ irb (~> 1.10)
103
+ reline (>= 0.3.8)
104
+ drb (2.2.1)
105
+ erubi (1.13.1)
106
+ globalid (1.2.1)
107
+ activesupport (>= 6.1)
108
+ i18n (1.14.7)
109
+ concurrent-ruby (~> 1.0)
110
+ io-console (0.8.0)
111
+ irb (1.15.2)
112
+ pp (>= 0.6.0)
113
+ rdoc (>= 4.0.0)
114
+ reline (>= 0.4.2)
115
+ json (2.10.2)
116
+ language_server-protocol (3.17.0.4)
117
+ lint_roller (1.1.0)
118
+ logger (1.7.0)
119
+ loofah (2.24.0)
120
+ crass (~> 1.0.2)
121
+ nokogiri (>= 1.12.0)
122
+ mail (2.8.1)
123
+ mini_mime (>= 0.1.1)
124
+ net-imap
125
+ net-pop
126
+ net-smtp
127
+ marcel (1.0.4)
128
+ mini_mime (1.1.5)
129
+ minitest (5.25.5)
130
+ net-imap (0.5.7)
131
+ date
132
+ net-protocol
133
+ net-pop (0.1.2)
134
+ net-protocol
135
+ net-protocol (0.2.2)
136
+ timeout
137
+ net-smtp (0.5.1)
138
+ net-protocol
139
+ nio4r (2.7.4)
140
+ nokogiri (1.18.8-arm64-darwin)
141
+ racc (~> 1.4)
142
+ nokogiri (1.18.8-x86_64-linux-gnu)
143
+ racc (~> 1.4)
144
+ parallel (1.27.0)
145
+ parser (3.3.8.0)
146
+ ast (~> 2.4.1)
147
+ racc
148
+ phlex (2.2.1)
149
+ zeitwerk (~> 2.7)
150
+ phlex-rails (2.2.0)
151
+ phlex (~> 2.2.1)
152
+ railties (>= 7.1, < 9)
153
+ pp (0.6.2)
154
+ prettyprint
155
+ prettyprint (0.2.0)
156
+ prism (1.4.0)
157
+ psych (5.2.3)
158
+ date
159
+ stringio
160
+ racc (1.8.1)
161
+ rack (3.1.13)
162
+ rack-session (2.1.0)
163
+ base64 (>= 0.1.0)
164
+ rack (>= 3.0.0)
165
+ rack-test (2.2.0)
166
+ rack (>= 1.3)
167
+ rackup (2.2.1)
168
+ rack (>= 3)
169
+ rails (8.0.2)
170
+ actioncable (= 8.0.2)
171
+ actionmailbox (= 8.0.2)
172
+ actionmailer (= 8.0.2)
173
+ actionpack (= 8.0.2)
174
+ actiontext (= 8.0.2)
175
+ actionview (= 8.0.2)
176
+ activejob (= 8.0.2)
177
+ activemodel (= 8.0.2)
178
+ activerecord (= 8.0.2)
179
+ activestorage (= 8.0.2)
180
+ activesupport (= 8.0.2)
181
+ bundler (>= 1.15.0)
182
+ railties (= 8.0.2)
183
+ rails-dom-testing (2.2.0)
184
+ activesupport (>= 5.0.0)
185
+ minitest
186
+ nokogiri (>= 1.6)
187
+ rails-html-sanitizer (1.6.2)
188
+ loofah (~> 2.21)
189
+ nokogiri (>= 1.15.7, != 1.16.7, != 1.16.6, != 1.16.5, != 1.16.4, != 1.16.3, != 1.16.2, != 1.16.1, != 1.16.0.rc1, != 1.16.0)
190
+ railties (8.0.2)
191
+ actionpack (= 8.0.2)
192
+ activesupport (= 8.0.2)
193
+ irb (~> 1.13)
194
+ rackup (>= 1.0.0)
195
+ rake (>= 12.2)
196
+ thor (~> 1.0, >= 1.2.2)
197
+ zeitwerk (~> 2.6)
198
+ rainbow (3.1.1)
199
+ rake (13.2.1)
200
+ rdoc (6.13.1)
201
+ psych (>= 4.0.0)
202
+ regexp_parser (2.10.0)
203
+ reline (0.6.1)
204
+ io-console (~> 0.5)
205
+ rubocop (1.75.3)
206
+ json (~> 2.3)
207
+ language_server-protocol (~> 3.17.0.2)
208
+ lint_roller (~> 1.1.0)
209
+ parallel (~> 1.10)
210
+ parser (>= 3.3.0.2)
211
+ rainbow (>= 2.2.2, < 4.0)
212
+ regexp_parser (>= 2.9.3, < 3.0)
213
+ rubocop-ast (>= 1.44.0, < 2.0)
214
+ ruby-progressbar (~> 1.7)
215
+ unicode-display_width (>= 2.4.0, < 4.0)
216
+ rubocop-ast (1.44.1)
217
+ parser (>= 3.3.7.2)
218
+ prism (~> 1.4)
219
+ ruby-progressbar (1.13.0)
220
+ securerandom (0.4.1)
221
+ stringio (3.1.7)
222
+ sus (0.32.0)
223
+ thor (1.3.2)
224
+ timeout (0.4.3)
225
+ tzinfo (2.0.6)
226
+ concurrent-ruby (~> 1.0)
227
+ unicode-display_width (3.1.4)
228
+ unicode-emoji (~> 4.0, >= 4.0.4)
229
+ unicode-emoji (4.0.4)
230
+ uri (1.0.3)
231
+ useragent (0.16.11)
232
+ websocket-driver (0.7.7)
233
+ base64
234
+ websocket-extensions (>= 0.1.0)
235
+ websocket-extensions (0.1.5)
236
+ zeitwerk (2.7.2)
237
+
238
+ PLATFORMS
239
+ arm64-darwin-24
240
+ x86_64-linux
241
+
242
+ DEPENDENCIES
243
+ appraisal
244
+ combustion
245
+ debug
246
+ phlex (>= 2.1.0, < 3.0.0)
247
+ phlex-rails (>= 2.1.0, < 3.0.0)
248
+ phlexible!
249
+ rake (~> 13.0)
250
+ rubocop (~> 1.55)
251
+ sus
252
+
253
+ BUNDLED WITH
254
+ 2.4.1
@@ -4,8 +4,14 @@ module Phlexible
4
4
  module Rails
5
5
  # Calls `url_for` for the `href` attribute.
6
6
  module AElement
7
+ extend ActiveSupport::Concern
8
+
9
+ included do
10
+ include Phlex::Rails::Helpers::URLFor
11
+ end
12
+
7
13
  def a(href:, **, &)
8
- super(href: helpers.url_for(href), **, &)
14
+ super(href: url_for(href), **, &)
9
15
  end
10
16
  end
11
17
  end
@@ -15,119 +15,6 @@
15
15
  # - :params - Hash of parameters to be rendered as hidden fields within the form.
16
16
  module Phlexible
17
17
  module Rails
18
- module ButtonToConcerns
19
- BUTTON_TAG_METHOD_VERBS = %w[patch put delete].freeze
20
- DEFAULT_OPTIONS = { method: 'post', form_class: 'button_to', params: {} }.freeze
21
-
22
- def initialize(url, options = nil)
23
- @url = url
24
- @options = options
25
- end
26
-
27
- def view_template(&block) # rubocop:disable Metrics/AbcSize
28
- action = helpers.url_for(@url)
29
- @options = DEFAULT_OPTIONS.merge((@options || {}).symbolize_keys)
30
-
31
- method = (@options.delete(:method).presence || method_for_options(@options)).to_s
32
- form_method = method == 'get' ? 'get' : 'post'
33
-
34
- form action: action, method: form_method, **form_attributes do
35
- method_tag method
36
- form_method == 'post' && token_input(action, method.empty? ? 'post' : method)
37
- param_inputs
38
-
39
- block_given? ? button(**button_attrs, &block) : button(**button_attrs) { @name }
40
- end
41
- end
42
-
43
- private
44
-
45
- def form_attributes
46
- {
47
- class: @options.delete(:form_class), # @deprecated
48
- **(@options.delete(:form_attributes) || {})
49
- }
50
- end
51
-
52
- def button_attrs
53
- {
54
- type: 'submit',
55
- **@options
56
- }
57
- end
58
-
59
- def method_for_options(options)
60
- if options.is_a?(Array)
61
- method_for_options(options.last)
62
- elsif options.respond_to?(:persisted?)
63
- options.persisted? ? :patch : :post
64
- elsif options.respond_to?(:to_model)
65
- method_for_options(options.to_model)
66
- end
67
- end
68
-
69
- def token_input(action, method)
70
- return unless helpers.protect_against_forgery?
71
-
72
- name = helpers.request_forgery_protection_token.to_s
73
- value = helpers.form_authenticity_token(form_options: { action: action, method: method })
74
-
75
- input type: 'hidden', name: name, value: value, autocomplete: 'off'
76
- end
77
-
78
- def method_tag(method)
79
- return unless BUTTON_TAG_METHOD_VERBS.include?(method)
80
-
81
- input type: 'hidden', name: '_method', value: method.to_s, autocomplete: 'off'
82
- end
83
-
84
- def param_inputs
85
- return unless (params = @options.delete(:params))
86
-
87
- to_form_params(params).each do |param|
88
- input type: 'hidden', name: param[:name], value: param[:value], autocomplete: 'off'
89
- end
90
- end
91
-
92
- # Returns an array of hashes each containing :name and :value keys suitable for use as the
93
- # names and values of form input fields:
94
- #
95
- # to_form_params(name: 'David', nationality: 'Danish')
96
- # # => [{name: 'name', value: 'David'}, {name: 'nationality', value: 'Danish'}]
97
- #
98
- # to_form_params(country: { name: 'Denmark' })
99
- # # => [{name: 'country[name]', value: 'Denmark'}]
100
- #
101
- # to_form_params(countries: ['Denmark', 'Sweden']})
102
- # # => [{name: 'countries[]', value: 'Denmark'}, {name: 'countries[]', value: 'Sweden'}]
103
- #
104
- # An optional namespace can be passed to enclose key names:
105
- #
106
- # to_form_params({ name: 'Denmark' }, 'country')
107
- # # => [{name: 'country[name]', value: 'Denmark'}]
108
- def to_form_params(attribute, namespace = nil)
109
- attribute = attribute.to_h if attribute.respond_to?(:permitted?)
110
-
111
- params = []
112
- case attribute
113
- when Hash
114
- attribute.each do |key, value|
115
- prefix = namespace ? "#{namespace}[#{key}]" : key
116
- params.push(*to_form_params(value, prefix))
117
- end
118
- when Array
119
- array_prefix = "#{namespace}[]"
120
- attribute.each do |value|
121
- params.push(*to_form_params(value, array_prefix))
122
- end
123
- else
124
- params << { name: namespace.to_s, value: attribute.to_param }
125
- end
126
-
127
- params.sort_by { |pair| pair[:name] }
128
- end
129
- end
130
-
131
18
  class ButtonTo < Phlex::HTML
132
19
  include ButtonToConcerns
133
20
  end
@@ -0,0 +1,140 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Generates a form containing a single button that submits to the URL created by the set of options.
4
+ # Similar to Rails `button_to` helper.
5
+ #
6
+ # The form submits a POST request by default. You can specify a different HTTP verb via the :method
7
+ # option.
8
+ #
9
+ # Additional arguments are passed through to the button element, with a few exceptions:
10
+ # - :method - Symbol of HTTP verb. Supported verbs are :post, :get, :delete, :patch, and :put.
11
+ # Default is :post.
12
+ # - :form_attributes - Hash of HTML attributes to be rendered on the form tag.
13
+ # - :form_class - This controls the class of the form within which the submit button will be placed.
14
+ # Default is 'button_to'. @deprecated: use :form_attributes instead if you want to override this.
15
+ # - :params - Hash of parameters to be rendered as hidden fields within the form.
16
+ module Phlexible
17
+ module Rails
18
+ module ButtonToConcerns
19
+ extend ActiveSupport::Concern
20
+
21
+ included do
22
+ include Phlex::Rails::Helpers::URLFor
23
+ register_value_helper :protect_against_forgery?
24
+ register_value_helper :request_forgery_protection_token
25
+ register_value_helper :form_authenticity_token
26
+ end
27
+
28
+ BUTTON_TAG_METHOD_VERBS = %w[patch put delete].freeze
29
+ DEFAULT_OPTIONS = { method: 'post', form_class: 'button_to', params: {} }.freeze
30
+
31
+ def initialize(url, options = nil)
32
+ @url = url
33
+ @options = options
34
+ end
35
+
36
+ def view_template(&block)
37
+ action = url_for(@url)
38
+ @options = DEFAULT_OPTIONS.merge((@options || {}).symbolize_keys)
39
+
40
+ method = (@options.delete(:method).presence || method_for_options(@options)).to_s
41
+ form_method = method == 'get' ? 'get' : 'post'
42
+
43
+ form action: action, method: form_method, **form_attributes do
44
+ method_tag method
45
+ form_method == 'post' && token_input(action, method.empty? ? 'post' : method)
46
+ param_inputs
47
+
48
+ block_given? ? button(**button_attrs, &block) : button(**button_attrs) { @name }
49
+ end
50
+ end
51
+
52
+ private
53
+
54
+ def form_attributes
55
+ {
56
+ class: @options.delete(:form_class), # @deprecated
57
+ **(@options.delete(:form_attributes) || {})
58
+ }
59
+ end
60
+
61
+ def button_attrs
62
+ {
63
+ type: 'submit',
64
+ **@options
65
+ }
66
+ end
67
+
68
+ def method_for_options(options)
69
+ if options.is_a?(Array)
70
+ method_for_options(options.last)
71
+ elsif options.respond_to?(:persisted?)
72
+ options.persisted? ? :patch : :post
73
+ elsif options.respond_to?(:to_model)
74
+ method_for_options(options.to_model)
75
+ end
76
+ end
77
+
78
+ def token_input(action, method)
79
+ return unless protect_against_forgery?
80
+
81
+ name = request_forgery_protection_token.to_s
82
+ value = form_authenticity_token(form_options: { action: action, method: method })
83
+
84
+ input type: 'hidden', name: name, value: value, autocomplete: 'off'
85
+ end
86
+
87
+ def method_tag(method)
88
+ return unless BUTTON_TAG_METHOD_VERBS.include?(method)
89
+
90
+ input type: 'hidden', name: '_method', value: method.to_s, autocomplete: 'off'
91
+ end
92
+
93
+ def param_inputs
94
+ return unless (params = @options.delete(:params))
95
+
96
+ to_form_params(params).each do |param|
97
+ input type: 'hidden', name: param[:name], value: param[:value], autocomplete: 'off'
98
+ end
99
+ end
100
+
101
+ # Returns an array of hashes each containing :name and :value keys suitable for use as the
102
+ # names and values of form input fields:
103
+ #
104
+ # to_form_params(name: 'David', nationality: 'Danish')
105
+ # # => [{name: 'name', value: 'David'}, {name: 'nationality', value: 'Danish'}]
106
+ #
107
+ # to_form_params(country: { name: 'Denmark' })
108
+ # # => [{name: 'country[name]', value: 'Denmark'}]
109
+ #
110
+ # to_form_params(countries: ['Denmark', 'Sweden']})
111
+ # # => [{name: 'countries[]', value: 'Denmark'}, {name: 'countries[]', value: 'Sweden'}]
112
+ #
113
+ # An optional namespace can be passed to enclose key names:
114
+ #
115
+ # to_form_params({ name: 'Denmark' }, 'country')
116
+ # # => [{name: 'country[name]', value: 'Denmark'}]
117
+ def to_form_params(attribute, namespace = nil)
118
+ attribute = attribute.to_h if attribute.respond_to?(:permitted?)
119
+
120
+ params = []
121
+ case attribute
122
+ when Hash
123
+ attribute.each do |key, value|
124
+ prefix = namespace ? "#{namespace}[#{key}]" : key
125
+ params.push(*to_form_params(value, prefix))
126
+ end
127
+ when Array
128
+ array_prefix = "#{namespace}[]"
129
+ attribute.each do |value|
130
+ params.push(*to_form_params(value, array_prefix))
131
+ end
132
+ else
133
+ params << { name: namespace.to_s, value: attribute.to_param }
134
+ end
135
+
136
+ params.sort_by { |pair| pair[:name] }
137
+ end
138
+ end
139
+ end
140
+ end
@@ -23,6 +23,8 @@
23
23
  module Phlexible
24
24
  module Rails
25
25
  module ControllerVariables
26
+ include ViewAssigns
27
+
26
28
  def self.included(klass)
27
29
  klass.class_attribute :__controller_variables__, instance_predicate: false, default: Set.new
28
30
  klass.extend ClassMethods
@@ -40,10 +42,10 @@ module Phlexible
40
42
 
41
43
  private
42
44
 
43
- def define_controller_variables # rubocop:disable Metrics
45
+ def define_controller_variables
44
46
  return unless respond_to?(:__controller_variables__)
45
47
 
46
- view_assigns = helpers.controller.view_assigns
48
+ view_assigns = view_assigns()
47
49
  view = @view
48
50
 
49
51
  vars = (view&.__controller_variables__ || Set.new) + __controller_variables__
@@ -62,7 +64,8 @@ module Phlexible
62
64
  end
63
65
 
64
66
  module ClassMethods
65
- def controller_variable(*names, **kwargs) # rubocop:disable Metrics/*
67
+ # /*
68
+ def controller_variable(*names, **kwargs)
66
69
  if names.empty? && kwargs.empty?
67
70
  raise ArgumentError, 'You must provide at least one variable name and/or a hash of ' \
68
71
  'variable names and options.'
@@ -3,8 +3,10 @@
3
3
  module Phlexible
4
4
  module Rails
5
5
  class MetaTagsComponent < Phlex::HTML
6
+ include ViewAssigns
7
+
6
8
  def view_template
7
- helpers.controller.view_assigns['meta_tags']&.each do |name, content|
9
+ view_assigns['meta_tags']&.each do |name, content|
8
10
  meta name: name, content: content.is_a?(String) ? content : content.to_json
9
11
  end
10
12
  end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Phlexible
4
+ module Rails
5
+ module ViewAssigns
6
+ def view_assigns
7
+ if respond_to?(:view_context)
8
+ # Phlex 2
9
+ view_context.controller.view_assigns
10
+ else
11
+ # Phlex 1
12
+ helpers.controller.view_assigns
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Phlexible
4
- VERSION = '2.2.0'
4
+ VERSION = '3.0.0'
5
5
  end
data/lib/phlexible.rb CHANGED
@@ -1,11 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative 'phlexible/version'
4
- require 'phlex'
4
+ require 'zeitwerk'
5
+ require 'rails'
6
+ require 'phlex-rails'
7
+
8
+ loader = Zeitwerk::Loader.for_gem
9
+ loader.setup
5
10
 
6
11
  module Phlexible
7
- autoload :AliasView, 'phlexible/alias_view'
8
- autoload :PageTitle, 'phlexible/page_title'
9
- autoload :Callbacks, 'phlexible/callbacks'
10
- autoload :Rails, 'phlexible/rails'
11
12
  end
data/phlexible.gemspec CHANGED
@@ -30,6 +30,8 @@ Gem::Specification.new do |spec|
30
30
  spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
31
31
  spec.require_paths = ['lib']
32
32
 
33
- spec.add_dependency 'phlex', '>= 1.10.0', '< 2.0.0'
34
- spec.add_dependency 'phlex-rails', '>= 1.2.1', '< 2.0.0'
33
+ spec.add_dependency 'phlex', '>= 1.10.0', '< 3.0.0'
34
+ spec.add_dependency 'phlex-rails', '>= 1.2.0', '< 3.0.0'
35
+ spec.add_dependency 'rails', '>= 7.2.0', '< 9.0.0'
36
+ spec.add_dependency 'zeitwerk', '~> 2.7.2'
35
37
  end