lifeform 0.16.0 → 0.17.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: a757ed6ce30cf3a892760a6b9c3c9ba3699475cc8502a90e9de07b56a7a3fb2a
4
- data.tar.gz: e17f65492dbc44c4a1e874f56b3a336941db2b914986cecce64006119ff71383
3
+ metadata.gz: 283c7f42b6108a032fe1ba52472eeaedac36cc0b07e70eb061f23b931724b729
4
+ data.tar.gz: 8640ba714e28cf0a0eb0a5dd7c7f48aaac37e75d2b0c6170a135983570abb4ee
5
5
  SHA512:
6
- metadata.gz: 3a607e2b89f5c52e5ae900b60b53009e5b59f8591ab1ff08b27378eff829cc3eaaa0436561d39caaa0d69583501919132b50856098747f979389c5125d3d2316
7
- data.tar.gz: badaefd5cd10695da7730f2441cbccaa5e439c6be23e3e77a3d0121dc6be12aecaa0fca28710b65d5990c4359d8c1033f9f56ef7daf3bb44cace089b7958552f
6
+ metadata.gz: 05eb1d7fbc094ae6e3450906da2671e4f4604f7f0fd8da0acdf734a9e445d129c7796c1cb8cb0a703787cbd4d7f43589dbdf56c0af7f4f4ce73076d561eaeb27
7
+ data.tar.gz: f6a208d9430d77c6bb8087f7331b197fc76bdb0d7f88d3ef72f9406d8e00823a7bb36c49838c682961aee50934e40b795389086655221fba2bb70b870a0941d8
data/.rubocop.yml CHANGED
@@ -7,7 +7,7 @@ inherit_gem:
7
7
  rubocop-bridgetown: .rubocop.yml
8
8
 
9
9
  AllCops:
10
- TargetRubyVersion: 3.0
10
+ TargetRubyVersion: 3.2
11
11
  NewCops: enable
12
12
 
13
13
  Exclude:
@@ -28,10 +28,20 @@ AllCops:
28
28
  Layout/MultilineBlockLayout:
29
29
  Enabled: false
30
30
 
31
+ Layout/SpaceBeforeFirstArg:
32
+ Enabled: false
33
+
34
+ Layout/SpaceBeforeBlockBraces:
35
+ Enabled: false
36
+
31
37
  Metrics/AbcSize:
32
38
  Exclude:
33
39
  - test/**/*.rb
34
40
 
41
+ Metrics/BlockLength:
42
+ Exclude:
43
+ - test/**/*.rb
44
+
35
45
  Metrics/ClassLength:
36
46
  Exclude:
37
47
  - test/**/*.rb
@@ -42,3 +52,7 @@ Metrics/MethodLength:
42
52
 
43
53
  Layout/LineLength:
44
54
  Max: 120
55
+
56
+ Lint/Void:
57
+ Exclude:
58
+ - test/**/*.rb
data/.ruby-version CHANGED
@@ -1 +1 @@
1
- ruby-3.1.4
1
+ ruby-3.2.6
data/.solargraph.yml ADDED
@@ -0,0 +1,13 @@
1
+ include:
2
+ - "**/*.rb"
3
+ exclude:
4
+ - vendor/**/*
5
+ - ".bundle/**/*"
6
+ require:
7
+ - "bridgetown-foundation"
8
+ - "streamlined"
9
+ domains: []
10
+ reporters:
11
+ - rubocop
12
+ - require_not_found
13
+ max_files: 5000
data/CHANGELOG.md CHANGED
@@ -7,6 +7,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ .
11
+
12
+ ## [0.17.0] - 2025-12-16
13
+
14
+ - Add `fragment` "field" type for adding arbitrary HTML sections to forms
15
+ - Allow disabling csrf protection
16
+ - Convert tests to spec style and add "Intuitive Expectations"
17
+ - remove rails-dom-testing
18
+ - bump minimum Ruby to 3.2
19
+
10
20
  ## [0.16.0] - 2025-09-11
11
21
 
12
22
  - Migrate repo to Codeberg
data/Gemfile CHANGED
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- source "https://rubygems.org"
3
+ source "https://gem.coop"
4
4
 
5
5
  # Specify your gem's dependencies in lifeform.gemspec
6
6
  gemspec
@@ -12,10 +12,10 @@ gem "minitest-reporters", "~> 1.5"
12
12
 
13
13
  gem "rubocop", "~> 1.21"
14
14
  gem "rubocop-bridgetown", "~> 0.4"
15
-
16
- gem "solargraph", "~> 0.45.0"
17
-
18
- gem "rails-dom-testing", "~> 2.0"
19
-
20
15
  gem "rubocop-minitest", "~> 0.20.0"
21
16
  gem "rubocop-rake", "~> 0.6.0"
17
+
18
+ gem "solargraph", "~> 0.50"
19
+
20
+ gem "bridgetown-foundation", "~> 2.0.4"
21
+ gem "nokolexbor", "~> 0.6.2"
data/Gemfile.lock CHANGED
@@ -1,144 +1,148 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- lifeform (0.16.0)
4
+ lifeform (0.17.0)
5
5
  hash_with_dot_access (>= 1.2)
6
6
  sequel (>= 5.72)
7
7
  streamlined (>= 0.2.0)
8
8
  zeitwerk (~> 2.5)
9
9
 
10
10
  GEM
11
- remote: https://rubygems.org/
11
+ remote: https://gem.coop/
12
12
  specs:
13
- activesupport (7.1.3.2)
14
- base64
15
- bigdecimal
16
- concurrent-ruby (~> 1.0, >= 1.0.2)
17
- connection_pool (>= 2.2.5)
18
- drb
19
- i18n (>= 1.6, < 2)
20
- minitest (>= 5.1)
21
- mutex_m
22
- tzinfo (~> 2.0)
23
13
  ansi (1.5.0)
24
- ast (2.4.2)
14
+ ast (2.4.3)
25
15
  backport (1.2.0)
26
- base64 (0.2.0)
27
- benchmark (0.3.0)
28
- bigdecimal (3.1.7)
29
- builder (3.2.4)
30
- concurrent-ruby (1.2.3)
31
- connection_pool (2.4.1)
32
- diff-lcs (1.5.1)
33
- drb (2.2.1)
34
- e2mmap (0.1.0)
16
+ benchmark (0.5.0)
17
+ bigdecimal (3.3.1)
18
+ bridgetown-foundation (2.0.4)
19
+ hash_with_dot_access (~> 2.0)
20
+ inclusive (~> 1.0)
21
+ zeitwerk (~> 2.5)
22
+ builder (3.3.0)
23
+ diff-lcs (1.6.2)
35
24
  erubi (1.13.1)
36
25
  hash_with_dot_access (2.2.0)
37
- i18n (1.14.4)
38
- concurrent-ruby (~> 1.0)
39
- jaro_winkler (1.5.6)
40
- json (2.7.2)
41
- kramdown (2.4.0)
42
- rexml
26
+ inclusive (1.1.0)
27
+ jaro_winkler (1.6.1)
28
+ json (2.16.0)
29
+ kramdown (2.5.1)
30
+ rexml (>= 3.3.9)
43
31
  kramdown-parser-gfm (1.1.0)
44
32
  kramdown (~> 2.0)
45
- language_server-protocol (3.17.0.3)
46
- minitest (5.22.3)
47
- minitest-reporters (1.6.1)
33
+ language_server-protocol (3.17.0.5)
34
+ lint_roller (1.1.0)
35
+ logger (1.7.0)
36
+ minitest (5.26.0)
37
+ minitest-reporters (1.7.1)
48
38
  ansi
49
39
  builder
50
40
  minitest (>= 5.0)
51
41
  ruby-progressbar
52
- mutex_m (0.2.0)
53
- nokogiri (1.16.4-arm64-darwin)
42
+ nokogiri (1.18.10-arm64-darwin)
54
43
  racc (~> 1.4)
55
- nokogiri (1.16.4-x86_64-linux)
44
+ nokogiri (1.18.10-x86_64-linux-gnu)
56
45
  racc (~> 1.4)
57
- parallel (1.24.0)
58
- parser (3.3.0.5)
46
+ nokolexbor (0.6.2-x86_64-linux)
47
+ observer (0.1.2)
48
+ ostruct (0.6.3)
49
+ parallel (1.27.0)
50
+ parser (3.3.10.0)
59
51
  ast (~> 2.4.1)
60
52
  racc
61
- racc (1.7.3)
62
- rails-dom-testing (2.2.0)
63
- activesupport (>= 5.0.0)
64
- minitest
65
- nokogiri (>= 1.6)
53
+ prism (1.6.0)
54
+ racc (1.8.1)
66
55
  rainbow (3.1.1)
67
- rake (13.2.1)
68
- regexp_parser (2.9.0)
69
- reverse_markdown (2.1.1)
56
+ rake (13.3.1)
57
+ rbs (3.9.5)
58
+ logger
59
+ regexp_parser (2.11.3)
60
+ reverse_markdown (3.0.0)
70
61
  nokogiri
71
- rexml (3.2.6)
72
- rubocop (1.63.2)
62
+ rexml (3.4.4)
63
+ rubocop (1.81.7)
73
64
  json (~> 2.3)
74
- language_server-protocol (>= 3.17.0)
65
+ language_server-protocol (~> 3.17.0.2)
66
+ lint_roller (~> 1.1.0)
75
67
  parallel (~> 1.10)
76
68
  parser (>= 3.3.0.2)
77
69
  rainbow (>= 2.2.2, < 4.0)
78
- regexp_parser (>= 1.8, < 3.0)
79
- rexml (>= 3.2.5, < 4.0)
80
- rubocop-ast (>= 1.31.1, < 2.0)
70
+ regexp_parser (>= 2.9.3, < 3.0)
71
+ rubocop-ast (>= 1.47.1, < 2.0)
81
72
  ruby-progressbar (~> 1.7)
82
- unicode-display_width (>= 2.4.0, < 3.0)
83
- rubocop-ast (1.31.2)
84
- parser (>= 3.3.0.4)
85
- rubocop-bridgetown (0.5.0)
86
- rubocop (~> 1.23)
87
- rubocop-performance (~> 1.12)
73
+ unicode-display_width (>= 2.4.0, < 4.0)
74
+ rubocop-ast (1.47.1)
75
+ parser (>= 3.3.7.2)
76
+ prism (~> 1.4)
77
+ rubocop-bridgetown (0.7.0)
78
+ rubocop (~> 1.72)
79
+ rubocop-performance (~> 1.24)
88
80
  rubocop-minitest (0.20.1)
89
81
  rubocop (>= 0.90, < 2.0)
90
- rubocop-performance (1.21.0)
91
- rubocop (>= 1.48.1, < 2.0)
92
- rubocop-ast (>= 1.31.1, < 2.0)
82
+ rubocop-performance (1.26.1)
83
+ lint_roller (~> 1.1)
84
+ rubocop (>= 1.75.0, < 2.0)
85
+ rubocop-ast (>= 1.47.1, < 2.0)
93
86
  rubocop-rake (0.6.0)
94
87
  rubocop (~> 1.0)
95
88
  ruby-progressbar (1.13.0)
96
- sequel (5.96.0)
89
+ sequel (5.98.0)
97
90
  bigdecimal
98
- serbea (2.3.0)
99
- erubi (>= 1.11)
100
- tilt (>= 2.1)
101
- solargraph (0.45.0)
91
+ serbea (2.4.0)
92
+ erubi (>= 1.13)
93
+ tilt (>= 2.6)
94
+ solargraph (0.57.0)
102
95
  backport (~> 1.2)
103
- benchmark
104
- bundler (>= 1.17.2)
96
+ benchmark (~> 0.4)
97
+ bundler (~> 2.0)
105
98
  diff-lcs (~> 1.4)
106
- e2mmap
107
- jaro_winkler (~> 1.5)
99
+ jaro_winkler (~> 1.6, >= 1.6.1)
108
100
  kramdown (~> 2.3)
109
101
  kramdown-parser-gfm (~> 1.1)
102
+ logger (~> 1.6)
103
+ observer (~> 0.1)
104
+ ostruct (~> 0.6)
110
105
  parser (~> 3.0)
111
- reverse_markdown (>= 1.0.5, < 3)
112
- rubocop (>= 0.52)
106
+ prism (~> 1.4)
107
+ rbs (>= 3.6.1, <= 4.0.0.dev.4)
108
+ reverse_markdown (~> 3.0)
109
+ rubocop (~> 1.76)
113
110
  thor (~> 1.0)
114
111
  tilt (~> 2.0)
115
112
  yard (~> 0.9, >= 0.9.24)
116
- streamlined (0.6.1)
113
+ yard-activesupport-concern (~> 0.0)
114
+ yard-solargraph (~> 0.1)
115
+ streamlined (0.6.2)
117
116
  serbea (>= 2.1)
118
117
  zeitwerk (~> 2.5)
119
- thor (1.3.1)
120
- tilt (2.3.0)
121
- tzinfo (2.0.6)
122
- concurrent-ruby (~> 1.0)
123
- unicode-display_width (2.5.0)
124
- yard (0.9.36)
125
- zeitwerk (2.6.18)
118
+ thor (1.4.0)
119
+ tilt (2.6.1)
120
+ unicode-display_width (3.2.0)
121
+ unicode-emoji (~> 4.1)
122
+ unicode-emoji (4.1.0)
123
+ yard (0.9.37)
124
+ yard-activesupport-concern (0.0.1)
125
+ yard (>= 0.8)
126
+ yard-solargraph (0.1.0)
127
+ yard (~> 0.9)
128
+ zeitwerk (2.7.3)
126
129
 
127
130
  PLATFORMS
128
131
  arm64-darwin-21
129
132
  x86_64-linux
130
133
 
131
134
  DEPENDENCIES
135
+ bridgetown-foundation (~> 2.0.4)
132
136
  lifeform!
133
137
  minitest (~> 5.0)
134
138
  minitest-reporters (~> 1.5)
135
- rails-dom-testing (~> 2.0)
139
+ nokolexbor (~> 0.6.2)
136
140
  rake (~> 13.0)
137
141
  rubocop (~> 1.21)
138
142
  rubocop-bridgetown (~> 0.4)
139
143
  rubocop-minitest (~> 0.20.0)
140
144
  rubocop-rake (~> 0.6.0)
141
- solargraph (~> 0.45.0)
145
+ solargraph (~> 0.50)
142
146
 
143
147
  BUNDLED WITH
144
148
  2.3.3
data/Rakefile CHANGED
@@ -14,4 +14,4 @@ require "rubocop/rake_task"
14
14
 
15
15
  RuboCop::RakeTask.new
16
16
 
17
- task default: %i[test rubocop]
17
+ task default: %i[rubocop test]
data/lib/lifeform/form.rb CHANGED
@@ -9,8 +9,9 @@ module Lifeform
9
9
 
10
10
  # A form object which stores field definitions and can be rendered as a component
11
11
  class Form
12
- include Streamlined::Renderable
12
+ extend Streamlined::Helpers
13
13
  extend Sequel::Inflections
14
+ include Streamlined::Renderable
14
15
 
15
16
  MODEL_PATH_HELPER = :polymorphic_path
16
17
 
@@ -30,6 +31,8 @@ module Lifeform
30
31
 
31
32
  def configuration = @configuration ||= HashWithDotAccess::Hash.new
32
33
 
34
+ def disable_csrf_protection! = configuration.disable_csrf_protection = true
35
+
33
36
  # @param block [Proc, nil]
34
37
  # @return [Hash<Symbol, FieldDefinition>]
35
38
  def fields(&block)
@@ -52,6 +55,26 @@ module Lifeform
52
55
  fields[name] = FieldDefinition.new(type, Libraries.const_get(camelize(library)), parameters)
53
56
  end
54
57
 
58
+ # Add an HTML fragment which will be auto-rendered or manually rendered like any field.
59
+ # Use Streamlined helpers inside a squiggly heredoc passed via the block which will be
60
+ # executed within the view context (requires it have `include Streamlined::Helpers`)
61
+ #
62
+ # @example
63
+ # fragment :footer do |form| <<~HTML
64
+ # <form-footer>
65
+ # <p>
66
+ # <img src="#{text->{ asset_path("thanks.png") }} />
67
+ # Thanks for filling out our form!
68
+ # </p>
69
+ # #{render form.field(:submit, label: t("users.sign_up"))}
70
+ # </form-footer>
71
+ # HTML
72
+ # end
73
+ #
74
+ # @param name [Symbol]
75
+ # @yieldparam form [Lifeform::Form] - instance of the form being rendered
76
+ def fragment(name, &block) = field(:"__#{name}", library: :default, type: :html, body: block)
77
+
55
78
  def subform(name, klass, parent_name: nil)
56
79
  subforms[name.to_sym] = { class: klass, parent_name: parent_name }
57
80
  end
@@ -130,12 +153,19 @@ module Lifeform
130
153
  attr_reader :parent_name
131
154
 
132
155
  def initialize( # rubocop:disable Metrics/ParameterLists
133
- model = nil, url: nil, library: self.class.library, emit_form_tag: true, parent_name: nil, **parameters
156
+ model = nil,
157
+ url: nil,
158
+ library: self.class.library,
159
+ emit_form_tag: true,
160
+ parent_name: nil,
161
+ view_context: nil,
162
+ **parameters
134
163
  )
135
164
  @model, @url, @library_name, @parameters, @emit_form_tag, @parent_name =
136
165
  model, url, library, parameters, emit_form_tag, parent_name
137
166
  @library = Libraries.const_get(self.class.send(:camelize, @library_name))
138
167
  @subform_instances = {}
168
+ @_view_context = view_context
139
169
 
140
170
  self.class.initialize_field_definitions!
141
171
 
@@ -144,6 +174,8 @@ module Lifeform
144
174
  verify_method
145
175
  end
146
176
 
177
+ def configuration = self.class.configuration
178
+
147
179
  def verify_method
148
180
  return if %w[get post].include?(parameters[:method].to_s.downcase)
149
181
 
@@ -171,6 +203,8 @@ module Lifeform
171
203
  end
172
204
  end
173
205
 
206
+ def include_authenticity_token? = !configuration.disable_csrf_protection
207
+
174
208
  def attributes
175
209
  @attributes ||= self.class.parameters_to_attributes(parameters)
176
210
  end
@@ -185,21 +219,25 @@ module Lifeform
185
219
  )
186
220
  end
187
221
 
222
+ def fragment(name, **) = field(:"__#{name}", **)
223
+
188
224
  def subform(name, model = nil)
189
225
  @subform_instances[name.to_sym] ||= self.class.subforms[name.to_sym][:class].new(
190
226
  model,
191
227
  emit_form_tag: false,
192
- parent_name: self.class.subforms[name.to_sym][:parent_name] || self.class.name_of_model(self.model)
228
+ parent_name: self.class.subforms[name.to_sym][:parent_name] || self.class.name_of_model(self.model),
229
+ view_context: helpers
193
230
  )
194
231
  end
195
232
 
196
- def template(&block) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity
233
+ def template(&block) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
197
234
  form_tag = library::FORM_TAG
198
235
  parameters[:action] ||= url || (model ? helpers.send(self.class.const_get(:MODEL_PATH_HELPER), model) : nil)
236
+ output_token = include_authenticity_token? && parameters[:method].to_s.casecmp("get").zero?.!
199
237
 
200
238
  html -> { <<~HTML # rubocop:disable Bridgetown/InsecureHeredoc
201
239
  <#{form_tag} #{html_attributes attributes}>
202
- #{add_authenticity_token unless parameters[:method].to_s.casecmp("get").zero?}
240
+ #{add_authenticity_token if output_token}
203
241
  #{@method_tag&.() || ""}
204
242
  #{block ? capture(self, &block) : auto_render_fields}
205
243
  </#{form_tag}>
@@ -210,7 +248,7 @@ module Lifeform
210
248
  def auto_render_fields = html_map(self.class.fields) { |k, _v| render(field(k)) }
211
249
 
212
250
  def render(field_object)
213
- field_object.render_in(helpers || self)
251
+ field_object.render_in(helpers)
214
252
  end
215
253
  end
216
254
  end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Lifeform
4
+ module Libraries
5
+ class Default
6
+ class Html
7
+ include Streamlined::Renderable
8
+
9
+ attr_reader :form, :field_definition, :body
10
+
11
+ def initialize(form, field_definition, **attributes)
12
+ @form = form
13
+ @field_definition = field_definition
14
+
15
+ @attributes =
16
+ Lifeform::Form.parameters_to_attributes(field_definition.parameters).merge(attributes)
17
+ @body = @attributes[:body]
18
+ end
19
+
20
+ def template
21
+ html->{ helpers.instance_exec(form, &body) }
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Lifeform
4
- VERSION = "0.16.0"
4
+ VERSION = "0.17.0"
5
5
  end
data/lib/lifeform.rb CHANGED
@@ -9,7 +9,7 @@ module Lifeform
9
9
  class Error < StandardError; end
10
10
  end
11
11
 
12
- if defined?(Bridgetown)
12
+ if defined?(Bridgetown) && Bridgetown.respond_to?(:initializer)
13
13
  Bridgetown.initializer :lifeform do |config|
14
14
  config.hook :authtown, :initialized do |rodauth|
15
15
  Lifeform::Form.rodauth = rodauth
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lifeform
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.16.0
4
+ version: 0.17.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bridgetown Team
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-09-12 00:00:00.000000000 Z
11
+ date: 2025-12-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: hash_with_dot_access
@@ -74,6 +74,7 @@ extra_rdoc_files: []
74
74
  files:
75
75
  - ".rubocop.yml"
76
76
  - ".ruby-version"
77
+ - ".solargraph.yml"
77
78
  - CHANGELOG.md
78
79
  - CODE_OF_CONDUCT.md
79
80
  - Gemfile
@@ -89,6 +90,7 @@ files:
89
90
  - lib/lifeform/form.rb
90
91
  - lib/lifeform/libraries/default.rb
91
92
  - lib/lifeform/libraries/default/button.rb
93
+ - lib/lifeform/libraries/default/html.rb
92
94
  - lib/lifeform/libraries/default/input.rb
93
95
  - lib/lifeform/libraries/default/submit_button.rb
94
96
  - lib/lifeform/libraries/shoelace.rb
@@ -117,7 +119,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
117
119
  - !ruby/object:Gem::Version
118
120
  version: '0'
119
121
  requirements: []
120
- rubygems_version: 3.3.26
122
+ rubygems_version: 3.4.19
121
123
  signing_key:
122
124
  specification_version: 4
123
125
  summary: Component-centric form object rendering for Ruby