lifeform 0.10.0 → 0.12.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: fef99043fb289f536c1a3b6986a48675dc741854ffef6e99c596c5d9abca303a
4
- data.tar.gz: 61821150d087888c5b243e2c52916534f7fc8b4fb8a14ced79692d3bb1ed1f45
3
+ metadata.gz: b73201515b3b27e577ed299923e2e2b0dbe4e8597761947c47d4c67eb3d2a8c0
4
+ data.tar.gz: 47f7c3d4bb4eb9f82c1f02ebd70066f2509cc1b0b685cd11f88377fb4ef2b7d4
5
5
  SHA512:
6
- metadata.gz: 8b64f7550a79f0e7667ac422a9cecb364943c544e9583f724842326d4cb9b28b74ae0dee19427be1121fcfd4e9b1a9e5e7878ff1cc8a2e22ee65dd734a0c69e1
7
- data.tar.gz: adec1d8e7d8a800f667953ef4e91f90935878a9e1dc6095a82536625bf675ee9f1be74ee3ed31f1857807c9ee75dcd3b36f95a42c32ba79aa10cca0395240dc8
6
+ metadata.gz: 2ce0937077dbae812e9c88707f40c22815e3f72c95afa3d85717cc8957fb024f311f123cc487d2107fba117129f756198e2aea346b1d6ff46e03afede3f4d574
7
+ data.tar.gz: 53b27483e4125eec6c6e9f5ca44f56702c9f2b2913523981f8ec94eae01726441288716e91381a545bd392fbe49d1bb85697955e7b59a02dd43a861be3076d63
data/.rubocop.yml CHANGED
@@ -1,14 +1,31 @@
1
1
  require:
2
+ - rubocop-bridgetown
2
3
  - rubocop-minitest
3
4
  - rubocop-rake
4
5
 
6
+ inherit_gem:
7
+ rubocop-bridgetown: .rubocop.yml
8
+
5
9
  AllCops:
6
- TargetRubyVersion: 2.7
10
+ TargetRubyVersion: 3.0
7
11
  NewCops: enable
12
+
8
13
  Exclude:
9
- - lib/lifeform/phlex_renderable.rb
14
+ - .gitignore
15
+ - .rubocop.yml
16
+ - "*.gemspec"
17
+
18
+ - Gemfile.lock
19
+ - CHANGELOG.md
20
+ - LICENSE.txt
21
+ - README.md
22
+ - Rakefile
23
+
24
+ - bin/**/*
25
+ - test/fixtures/**/*
26
+ - vendor/**/*
10
27
 
11
- Lint/MissingSuper:
28
+ Layout/MultilineBlockLayout:
12
29
  Enabled: false
13
30
 
14
31
  Metrics/AbcSize:
@@ -20,32 +37,8 @@ Metrics/ClassLength:
20
37
  - test/**/*.rb
21
38
 
22
39
  Metrics/MethodLength:
23
- Max: 20
24
40
  Exclude:
25
41
  - test/**/*.rb
26
42
 
27
- Style/Documentation:
28
- Enabled: false
29
-
30
- Style/Lambda:
31
- Enabled: false
32
-
33
- Style/LambdaCall:
34
- Enabled: false
35
-
36
- Style/MultilineBlockChain:
37
- Enabled: false
38
-
39
- Style/StringLiterals:
40
- Enabled: true
41
- EnforcedStyle: double_quotes
42
-
43
- Style/StringLiteralsInInterpolation:
44
- Enabled: true
45
- EnforcedStyle: double_quotes
46
-
47
- Style/ParallelAssignment:
48
- Enabled: false
49
-
50
43
  Layout/LineLength:
51
44
  Max: 120
data/CHANGELOG.md CHANGED
@@ -2,6 +2,12 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [0.11.0] - 2023-06-22
6
+
7
+ - Upgrade to Phlex 1.7+, Ruby 3.0+
8
+ - Provide a form-wide configuration object
9
+ - Allow field definitions to be added via `fields` block (useful for when you need to reference runtime configuration)
10
+
5
11
  ## [0.10.0] - 2022-12-23
6
12
 
7
13
  - Support Phlex 1.0 and conditional `render_in` support for Bridgetown
data/Gemfile CHANGED
@@ -11,6 +11,7 @@ gem "minitest", "~> 5.0"
11
11
  gem "minitest-reporters", "~> 1.5"
12
12
 
13
13
  gem "rubocop", "~> 1.21"
14
+ gem "rubocop-bridgetown", "~> 0.4"
14
15
 
15
16
  gem "solargraph", "~> 0.45.0"
16
17
 
data/Gemfile.lock CHANGED
@@ -1,77 +1,106 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- lifeform (0.10.0)
5
- activesupport (>= 6.0)
6
- phlex (~> 1.0)
4
+ lifeform (0.12.0)
5
+ hash_with_dot_access (>= 1.2)
6
+ sequel (>= 5.72)
7
+ streamlined (>= 0.2.0)
7
8
  zeitwerk (~> 2.5)
8
9
 
9
10
  GEM
10
11
  remote: https://rubygems.org/
11
12
  specs:
12
- activesupport (7.0.4)
13
+ activesupport (7.1.1)
14
+ base64
15
+ bigdecimal
13
16
  concurrent-ruby (~> 1.0, >= 1.0.2)
17
+ connection_pool (>= 2.2.5)
18
+ drb
14
19
  i18n (>= 1.6, < 2)
15
20
  minitest (>= 5.1)
21
+ mutex_m
16
22
  tzinfo (~> 2.0)
17
23
  ansi (1.5.0)
18
24
  ast (2.4.2)
19
25
  backport (1.2.0)
26
+ base64 (0.1.1)
20
27
  benchmark (0.2.1)
28
+ bigdecimal (3.1.4)
21
29
  builder (3.2.4)
22
- concurrent-ruby (1.1.10)
30
+ concurrent-ruby (1.2.2)
31
+ connection_pool (2.4.1)
23
32
  diff-lcs (1.5.0)
33
+ drb (2.1.1)
34
+ ruby2_keywords
24
35
  e2mmap (0.1.0)
25
- i18n (1.12.0)
36
+ erubi (1.12.0)
37
+ hash_with_dot_access (1.2.0)
38
+ activesupport (>= 5.0.0, < 8.0)
39
+ i18n (1.14.1)
26
40
  concurrent-ruby (~> 1.0)
27
- jaro_winkler (1.5.4)
41
+ jaro_winkler (1.5.6)
28
42
  json (2.6.3)
29
43
  kramdown (2.4.0)
30
44
  rexml
31
45
  kramdown-parser-gfm (1.1.0)
32
46
  kramdown (~> 2.0)
33
- minitest (5.16.3)
34
- minitest-reporters (1.5.0)
47
+ language_server-protocol (3.17.0.3)
48
+ minitest (5.20.0)
49
+ minitest-reporters (1.6.1)
35
50
  ansi
36
51
  builder
37
52
  minitest (>= 5.0)
38
53
  ruby-progressbar
39
- nokogiri (1.13.10-arm64-darwin)
54
+ mutex_m (0.1.2)
55
+ nokogiri (1.15.4-arm64-darwin)
40
56
  racc (~> 1.4)
41
- nokogiri (1.13.10-x86_64-linux)
57
+ nokogiri (1.15.4-x86_64-linux)
42
58
  racc (~> 1.4)
43
- parallel (1.22.1)
44
- parser (3.1.3.0)
59
+ parallel (1.23.0)
60
+ parser (3.2.2.4)
45
61
  ast (~> 2.4.1)
46
- phlex (1.0.0)
47
- zeitwerk (~> 2.6)
48
- racc (1.6.1)
49
- rails-dom-testing (2.0.3)
50
- activesupport (>= 4.2.0)
62
+ racc
63
+ racc (1.7.3)
64
+ rails-dom-testing (2.2.0)
65
+ activesupport (>= 5.0.0)
66
+ minitest
51
67
  nokogiri (>= 1.6)
52
68
  rainbow (3.1.1)
53
- rake (13.0.6)
54
- regexp_parser (2.6.1)
69
+ rake (13.1.0)
70
+ regexp_parser (2.8.2)
55
71
  reverse_markdown (2.1.1)
56
72
  nokogiri
57
- rexml (3.2.5)
58
- rubocop (1.40.0)
73
+ rexml (3.2.6)
74
+ rubocop (1.57.2)
59
75
  json (~> 2.3)
76
+ language_server-protocol (>= 3.17.0)
60
77
  parallel (~> 1.10)
61
- parser (>= 3.1.2.1)
78
+ parser (>= 3.2.2.4)
62
79
  rainbow (>= 2.2.2, < 4.0)
63
80
  regexp_parser (>= 1.8, < 3.0)
64
81
  rexml (>= 3.2.5, < 4.0)
65
- rubocop-ast (>= 1.23.0, < 2.0)
82
+ rubocop-ast (>= 1.28.1, < 2.0)
66
83
  ruby-progressbar (~> 1.7)
67
- unicode-display_width (>= 1.4.0, < 3.0)
68
- rubocop-ast (1.24.0)
69
- parser (>= 3.1.1.0)
84
+ unicode-display_width (>= 2.4.0, < 3.0)
85
+ rubocop-ast (1.30.0)
86
+ parser (>= 3.2.1.0)
87
+ rubocop-bridgetown (0.4.0)
88
+ rubocop (~> 1.23)
89
+ rubocop-performance (~> 1.12)
70
90
  rubocop-minitest (0.20.1)
71
91
  rubocop (>= 0.90, < 2.0)
92
+ rubocop-performance (1.19.1)
93
+ rubocop (>= 1.7.0, < 2.0)
94
+ rubocop-ast (>= 0.4.0)
72
95
  rubocop-rake (0.6.0)
73
96
  rubocop (~> 1.0)
74
- ruby-progressbar (1.11.0)
97
+ ruby-progressbar (1.13.0)
98
+ ruby2_keywords (0.0.5)
99
+ sequel (5.74.0)
100
+ bigdecimal
101
+ serbea (2.1.0)
102
+ erubi (>= 1.10)
103
+ tilt (~> 2.0)
75
104
  solargraph (0.45.0)
76
105
  backport (~> 1.2)
77
106
  benchmark
@@ -87,15 +116,16 @@ GEM
87
116
  thor (~> 1.0)
88
117
  tilt (~> 2.0)
89
118
  yard (~> 0.9, >= 0.9.24)
90
- thor (1.2.1)
91
- tilt (2.0.11)
92
- tzinfo (2.0.5)
119
+ streamlined (0.2.0)
120
+ serbea (>= 2.1)
121
+ zeitwerk (~> 2.5)
122
+ thor (1.3.0)
123
+ tilt (2.3.0)
124
+ tzinfo (2.0.6)
93
125
  concurrent-ruby (~> 1.0)
94
- unicode-display_width (2.3.0)
95
- webrick (1.7.0)
96
- yard (0.9.28)
97
- webrick (~> 1.7.0)
98
- zeitwerk (2.6.6)
126
+ unicode-display_width (2.5.0)
127
+ yard (0.9.34)
128
+ zeitwerk (2.6.12)
99
129
 
100
130
  PLATFORMS
101
131
  arm64-darwin-21
@@ -108,6 +138,7 @@ DEPENDENCIES
108
138
  rails-dom-testing (~> 2.0)
109
139
  rake (~> 13.0)
110
140
  rubocop (~> 1.21)
141
+ rubocop-bridgetown (~> 0.4)
111
142
  rubocop-minitest (~> 0.20.0)
112
143
  rubocop-rake (~> 0.6.0)
113
144
  solargraph (~> 0.45.0)
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Lifeform
2
2
 
3
- Component-centric form object rendering for Ruby. Powered by [Phlex](https://www.phlex.fun)
3
+ Component-centric form object rendering for Ruby. Rails and Bridgetown both supported.
4
4
 
5
5
  ## Installation
6
6
 
@@ -10,8 +10,6 @@ Add Lifeform to your application's Gemfile by running:
10
10
  bundle add lifeform
11
11
  ```
12
12
 
13
- If you're in a Rails app, you'll want to `bundle add phlex-rails` as well for Action View rendering support.
14
-
15
13
  ## Usage
16
14
 
17
15
  Full documentation coming as the library begins to mature. TL;DR:
@@ -38,17 +36,6 @@ And a template rendering of:
38
36
  <% end %>
39
37
  ```
40
38
 
41
- ```rb
42
- # Or Phlex:
43
- def template
44
- render TestForm.new(url: "/path") do |f|
45
- render f.field(:occupation)
46
- render f.field(:age, value: 47)
47
- render f.field(:submit)
48
- end
49
- end
50
- ```
51
-
52
39
  You get the following HTML output:
53
40
 
54
41
  ```html
@@ -69,7 +56,7 @@ You get the following HTML output:
69
56
 
70
57
  Nested names based on models (aka `profile[name]`) and inferred action paths are supported as well.
71
58
 
72
- Multiple component libraries and input types—and easy customizability via [Phlex](https://github.com/joeldrapper/phlex) templates—are a fundamental aspect of the architecture of Lifeform.
59
+ Multiple component libraries and input types—and easy customizability using string interpolation templates and helpers—are a fundamental aspect of the architecture of Lifeform. Until further docs have been written, you can look in `lib/lifeform/libraries` to see how some initial field types were constructed.
73
60
 
74
61
  ### Automatic Field Rendering
75
62
 
data/lib/lifeform/form.rb CHANGED
@@ -1,13 +1,17 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "active_support/core_ext/string/inflections"
3
+ require "hash_with_dot_access"
4
+ require "sequel/model/default_inflections"
5
+ require "sequel/model/inflections"
4
6
 
5
7
  module Lifeform
6
8
  FieldDefinition = Struct.new(:type, :library, :parameters)
7
9
 
8
10
  # A form object which stores field definitions and can be rendered as a component
9
- class Form < Phlex::HTML # rubocop:todo Metrics/ClassLength
10
- include CapturingRenderable
11
+ class Form
12
+ include Streamlined::Renderable
13
+ extend Sequel::Inflections
14
+
11
15
  MODEL_PATH_HELPER = :polymorphic_path
12
16
 
13
17
  class << self
@@ -17,22 +21,30 @@ module Lifeform
17
21
  end
18
22
 
19
23
  # Helper to point to `I18n.t` method
20
- def t(...)
21
- I18n.t(...)
22
- end
24
+ def t(...) = I18n.t(...)
23
25
 
26
+ def configuration = @configuration ||= HashWithDotAccess::Hash.new
27
+
28
+ # @param block [Proc, nil]
24
29
  # @return [Hash<Symbol, FieldDefinition>]
25
- def fields
30
+ def fields(&block)
26
31
  @fields ||= {}
32
+ @fields_setup_block = block if block
33
+
34
+ @fields
27
35
  end
28
36
 
29
- def subforms
30
- @subforms ||= {}
37
+ def initialize_field_definitions!
38
+ return unless @fields_setup_block
39
+
40
+ @fields_setup_block.(configuration)
31
41
  end
32
42
 
43
+ def subforms = @subforms ||= {}
44
+
33
45
  def field(name, type: :text, library: self.library, **parameters)
34
46
  parameters[:name] = name.to_sym
35
- fields[name] = FieldDefinition.new(type, Libraries.const_get(library.to_s.classify), parameters)
47
+ fields[name] = FieldDefinition.new(type, Libraries.const_get(camelize(library)), parameters)
36
48
  end
37
49
 
38
50
  def subform(name, klass, parent_name: nil)
@@ -83,19 +95,15 @@ module Lifeform
83
95
  model.to_model.model_name.param_key
84
96
  else
85
97
  # Or just use basic underscore
86
- model.class.name.underscore.tr("/", "_")
98
+ underscore(model.class.name).tr("/", "_")
87
99
  end
88
100
  end
89
101
 
90
102
  # @return [Array<Symbol>]
91
- def param_keys
92
- fields.keys
93
- end
103
+ def param_keys = fields.keys
94
104
 
95
105
  # @return [Array<String>]
96
- def param_string_keys
97
- fields.keys.map(&:to_s)
98
- end
106
+ def param_string_keys = fields.keys.map(&:to_s)
99
107
  end
100
108
 
101
109
  # @return [Object]
@@ -121,9 +129,11 @@ module Lifeform
121
129
  )
122
130
  @model, @url, @library_name, @parameters, @emit_form_tag, @parent_name =
123
131
  model, url, library, parameters, emit_form_tag, parent_name
124
- @library = Libraries.const_get(@library_name.to_s.classify)
132
+ @library = Libraries.const_get(self.class.send(:camelize, @library_name))
125
133
  @subform_instances = {}
126
134
 
135
+ self.class.initialize_field_definitions!
136
+
127
137
  @method = parameters[:method] ||= model.respond_to?(:persisted?) && model.persisted? ? :patch : :post
128
138
  parameters[:accept_charset] ||= "UTF-8"
129
139
  verify_method
@@ -132,25 +142,23 @@ module Lifeform
132
142
  def verify_method
133
143
  return if %w[get post].include?(parameters[:method].to_s.downcase)
134
144
 
135
- @method_tag = Class.new(Phlex::HTML) do # TODO: break this out into a real component
136
- def initialize(method:)
137
- @method = method
138
- end
145
+ method_value = @parameters[:method].to_s.downcase
139
146
 
140
- def template
141
- input type: "hidden", name: "_method", value: @method, autocomplete: "off"
142
- end
143
- end.new(method: @parameters[:method].to_s.downcase)
147
+ @method_tag = -> {
148
+ <<~HTML
149
+ <input type="hidden" name="_method" value="#{text -> { method_value }}" autocomplete="off">
150
+ HTML
151
+ }
144
152
 
145
153
  parameters[:method] = :post
146
154
  end
147
155
 
148
- def add_authenticity_token # rubocop:disable Metrics/AbcSize
156
+ def add_authenticity_token
149
157
  if helpers.respond_to?(:token_tag, true) # Rails
150
158
  helpers.send(:token_tag, nil, form_options: {
151
- action: parameters[:action].to_s,
152
- method: parameters[:method].to_s.downcase
153
- })
159
+ action: parameters[:action].to_s,
160
+ method: parameters[:method].to_s.downcase,
161
+ })
154
162
  elsif helpers.respond_to?(:csrf_tag, true) # Roda
155
163
  helpers.send(:csrf_tag, parameters[:action].to_s, @method.to_s)
156
164
  else
@@ -184,15 +192,20 @@ module Lifeform
184
192
  form_tag = library::FORM_TAG
185
193
  parameters[:action] ||= url || (model ? helpers.send(self.class.const_get(:MODEL_PATH_HELPER), model) : nil)
186
194
 
187
- send(form_tag, **attributes) do
188
- unsafe_raw(add_authenticity_token) unless parameters[:method].to_s.downcase == "get"
189
- unsafe_raw @method_tag&.() || ""
190
- block ? yield_content(&block) : auto_render_fields
191
- end
195
+ html -> { <<~HTML # rubocop:disable Bridgetown/HTMLEscapedHeredoc
196
+ <#{form_tag} #{html_attributes attributes}>
197
+ #{add_authenticity_token unless parameters[:method].to_s.casecmp("get").zero?}
198
+ #{@method_tag&.() || ""}
199
+ #{block ? capture(self, &block) : auto_render_fields}
200
+ </#{form_tag}>
201
+ HTML
202
+ }
192
203
  end
193
204
 
194
- def auto_render_fields
195
- self.class.fields.map { |k, _v| render(field(k)) }
205
+ def auto_render_fields = html_map(self.class.fields) { |k, _v| render(field(k)) }
206
+
207
+ def render(field_object)
208
+ field_object.render_in(helpers || self)
196
209
  end
197
210
  end
198
211
  end
@@ -3,17 +3,14 @@
3
3
  module Lifeform
4
4
  module Libraries
5
5
  class Default
6
- class Button < Phlex::HTML
7
- using RefineProcToString
8
- include CapturingRenderable
6
+ class Button
7
+ include Streamlined::Renderable
9
8
 
10
9
  attr_reader :form, :field_definition, :attributes
11
10
 
12
11
  WRAPPER_TAG = :form_button
13
12
  BUTTON_TAG = :button
14
13
 
15
- register_element WRAPPER_TAG
16
-
17
14
  def initialize(form, field_definition, **attributes)
18
15
  @form = form
19
16
  @field_definition = field_definition
@@ -24,20 +21,24 @@ module Lifeform
24
21
  end
25
22
 
26
23
  def template(&block)
27
- return if !@if.nil? && !@if
24
+ return "" if !@if.nil? && !@if
25
+
26
+ wrapper_tag = dashed self.class.const_get(:WRAPPER_TAG)
27
+ button_tag = dashed self.class.const_get(:BUTTON_TAG)
28
28
 
29
- wrapper_tag = self.class.const_get(:WRAPPER_TAG)
30
- button_tag = self.class.const_get(:BUTTON_TAG)
29
+ label_text = block ? capture(self, &block) : @label.is_a?(Proc) ? @label.pipe : @label # rubocop:disable Style/NestedTernaryOperator
31
30
 
32
- field_body = proc {
33
- send(button_tag, **@attributes) do
34
- unsafe_raw(@label.to_s) unless block
35
- yield_content(&block)
36
- end
31
+ field_body = html -> { <<~HTML # rubocop:disable Bridgetown/HTMLEscapedHeredoc
32
+ <#{button_tag}#{html_attributes @attributes, prefix_space: true}>#{text -> { label_text }}</#{button_tag}>
33
+ HTML
37
34
  }
38
- return field_body.() unless wrapper_tag
39
35
 
40
- send wrapper_tag, name: @attributes[:name], &field_body
36
+ return field_body unless wrapper_tag
37
+
38
+ html -> { <<~HTML # rubocop:disable Bridgetown/HTMLEscapedHeredoc
39
+ <#{wrapper_tag} #{html_attributes name: @attributes[:name]}>#{field_body}</#{wrapper_tag}>
40
+ HTML
41
+ }
41
42
  end
42
43
  end
43
44
  end
@@ -3,17 +3,14 @@
3
3
  module Lifeform
4
4
  module Libraries
5
5
  class Default
6
- class Input < Phlex::HTML
7
- using RefineProcToString
8
- include CapturingRenderable
6
+ class Input
7
+ include Streamlined::Renderable
9
8
 
10
9
  attr_reader :form, :field_definition, :attributes
11
10
 
12
11
  WRAPPER_TAG = :form_field
13
12
  INPUT_TAG = :input
14
13
 
15
- register_element WRAPPER_TAG
16
-
17
14
  def initialize(form, field_definition, **attributes)
18
15
  @form = form
19
16
  @field_definition = field_definition
@@ -30,7 +27,8 @@ module Lifeform
30
27
  @if = attributes.delete(:if)
31
28
  attributes[:value] ||= value_for_model if form.model
32
29
  attributes[:name] = "#{model_name}[#{attributes[:name]}]" if @model
33
- attributes[:id] ||= attributes[:name].parameterize(separator: "_")
30
+ # TODO: validate if this is enough
31
+ attributes[:id] ||= attributes[:name].tr("[]", "_").gsub("__", "_").chomp("_") if attributes[:name]
34
32
  @label = handle_labels if attributes[:label]
35
33
  end
36
34
 
@@ -40,35 +38,42 @@ module Lifeform
40
38
  form.parent_name ? "#{form.parent_name}[#{name_of_model}]" : name_of_model
41
39
  end
42
40
 
43
- def value_for_model
44
- @model.send(attributes[:name])
45
- end
41
+ def value_for_model = @model.send(attributes[:name])
46
42
 
47
43
  def handle_labels
48
- label_text = attributes[:label].to_s
44
+ label_text = attributes[:label].is_a?(Proc) ? attributes[:label].pipe : attributes[:label]
49
45
  label_name = (attributes[:id] || attributes[:name]).to_s
50
46
 
51
47
  @attributes = attributes.filter_map { |k, v| [k, v] unless k == :label }.to_h
52
48
 
53
- proc {
54
- label(for: label_name) { unsafe_raw label_text }
49
+ -> { <<~HTML
50
+ <label for="#{text -> { label_name }}">#{text -> { label_text }}</label>
51
+ HTML
55
52
  }
56
53
  end
57
54
 
58
- def template(&block)
59
- return if !@if.nil? && !@if
55
+ def template(&block) # rubocop:disable Metrics/AbcSize
56
+ return "" if !@if.nil? && !@if
60
57
 
61
- wrapper_tag = self.class.const_get(:WRAPPER_TAG)
62
- input_tag = self.class.const_get(:INPUT_TAG)
58
+ wrapper_tag = dashed self.class.const_get(:WRAPPER_TAG)
59
+ input_tag = dashed self.class.const_get(:INPUT_TAG)
60
+ closing_tag = input_tag != "input"
63
61
 
64
- field_body = proc {
65
- @label&.()
66
- send input_tag, type: @field_type.to_s, **@attributes
67
- yield_content(&block)
62
+ field_body = html -> { <<~HTML # rubocop:disable Bridgetown/HTMLEscapedHeredoc
63
+ #{html(@label || -> {}).to_s.strip}
64
+ <#{input_tag} #{html_attributes type: @field_type.to_s, **@attributes}>#{
65
+ "</#{input_tag}>" if closing_tag
66
+ }
67
+ #{html -> { capture(self, &block) } if block}
68
+ HTML
68
69
  }
69
- return field_body.() unless wrapper_tag
70
70
 
71
- send wrapper_tag, name: @attributes[:name], &field_body
71
+ return field_body unless wrapper_tag
72
+
73
+ html -> { <<~HTML # rubocop:disable Bridgetown/HTMLEscapedHeredoc
74
+ <#{wrapper_tag} #{html_attributes name: @attributes[:name]}>#{field_body.to_s.strip}</#{wrapper_tag}>
75
+ HTML
76
+ }
72
77
  end
73
78
  end
74
79
  end
@@ -10,7 +10,7 @@ module Lifeform
10
10
  # @param attributes [Hash]
11
11
  # @return [Input]
12
12
  def self.object_for_field_definition(form, field_definition, attributes)
13
- type_classname = field_definition[:type].to_s.classify
13
+ type_classname = Lifeform::Form.send(:camelize, field_definition[:type])
14
14
  if const_defined?(type_classname)
15
15
  const_get(type_classname)
16
16
  else
@@ -5,8 +5,6 @@ module Lifeform
5
5
  class Shoelace
6
6
  class Button < Default::Button
7
7
  BUTTON_TAG = :sl_button
8
-
9
- register_element BUTTON_TAG
10
8
  end
11
9
  end
12
10
  end
@@ -6,8 +6,6 @@ module Lifeform
6
6
  class Input < Default::Input
7
7
  INPUT_TAG = :sl_input
8
8
 
9
- register_element :sl_input
10
-
11
9
  # no-op
12
10
  def handle_labels; end
13
11
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Lifeform
4
- VERSION = "0.10.0"
4
+ VERSION = "0.12.0"
5
5
  end
data/lib/lifeform.rb CHANGED
@@ -1,22 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "phlex"
4
- require "active_support/core_ext/string/output_safety"
5
-
3
+ require "streamlined"
6
4
  require "zeitwerk"
7
5
  loader = Zeitwerk::Loader.for_gem
8
6
  loader.setup
9
7
 
10
8
  module Lifeform
11
9
  class Error < StandardError; end
12
-
13
- module RefineProcToString
14
- refine Proc do
15
- def to_s
16
- call.to_s
17
- end
18
- end
19
- end
20
10
  end
21
11
 
22
12
  if defined?(Bridgetown)
@@ -24,6 +14,5 @@ if defined?(Bridgetown)
24
14
  raise "The Lifeform support for Bridgetown requires v1.2 or newer" if Bridgetown::VERSION.to_f < 1.2
25
15
 
26
16
  Bridgetown.initializer :lifeform do # |config|
27
- require "lifeform/phlex_renderable" unless Phlex::HTML.instance_methods.include?(:render_in)
28
17
  end
29
18
  end
data/lifeform.gemspec CHANGED
@@ -11,7 +11,7 @@ Gem::Specification.new do |spec|
11
11
  spec.summary = "Component-centric form object rendering for Ruby"
12
12
  spec.homepage = "https://github.com/bridgetownrb/lifeform"
13
13
  spec.license = "MIT"
14
- spec.required_ruby_version = ">= 2.7"
14
+ spec.required_ruby_version = ">= 3.0"
15
15
  spec.metadata["rubygems_mfa_required"] = "true"
16
16
 
17
17
  # Specify which files should be added to the gem when it is released.
@@ -23,8 +23,8 @@ Gem::Specification.new do |spec|
23
23
  end
24
24
  spec.require_paths = ["lib"]
25
25
 
26
- # Uncomment to register a new dependency of your gem
27
- spec.add_dependency "activesupport", ">= 6.0"
28
- spec.add_dependency "phlex", "~> 1.0"
26
+ spec.add_dependency "hash_with_dot_access", ">= 1.2"
27
+ spec.add_dependency "sequel", ">= 5.72"
28
+ spec.add_dependency "streamlined", ">= 0.2.0"
29
29
  spec.add_dependency "zeitwerk", "~> 2.5"
30
30
  end
metadata CHANGED
@@ -1,43 +1,57 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lifeform
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.10.0
4
+ version: 0.12.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: 2022-12-23 00:00:00.000000000 Z
11
+ date: 2023-11-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: activesupport
14
+ name: hash_with_dot_access
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: '6.0'
19
+ version: '1.2'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: '6.0'
26
+ version: '1.2'
27
27
  - !ruby/object:Gem::Dependency
28
- name: phlex
28
+ name: sequel
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - "~>"
31
+ - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: '1.0'
33
+ version: '5.72'
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - "~>"
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '5.72'
41
+ - !ruby/object:Gem::Dependency
42
+ name: streamlined
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: 0.2.0
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
39
53
  - !ruby/object:Gem::Version
40
- version: '1.0'
54
+ version: 0.2.0
41
55
  - !ruby/object:Gem::Dependency
42
56
  name: zeitwerk
43
57
  requirement: !ruby/object:Gem::Requirement
@@ -72,7 +86,6 @@ files:
72
86
  - bin/rubocop
73
87
  - bin/setup
74
88
  - lib/lifeform.rb
75
- - lib/lifeform/capturing_renderable.rb
76
89
  - lib/lifeform/form.rb
77
90
  - lib/lifeform/libraries/default.rb
78
91
  - lib/lifeform/libraries/default/button.rb
@@ -82,7 +95,6 @@ files:
82
95
  - lib/lifeform/libraries/shoelace/button.rb
83
96
  - lib/lifeform/libraries/shoelace/input.rb
84
97
  - lib/lifeform/libraries/shoelace/submit_button.rb
85
- - lib/lifeform/phlex_renderable.rb
86
98
  - lib/lifeform/version.rb
87
99
  - lifeform.gemspec
88
100
  homepage: https://github.com/bridgetownrb/lifeform
@@ -98,7 +110,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
98
110
  requirements:
99
111
  - - ">="
100
112
  - !ruby/object:Gem::Version
101
- version: '2.7'
113
+ version: '3.0'
102
114
  required_rubygems_version: !ruby/object:Gem::Requirement
103
115
  requirements:
104
116
  - - ">="
@@ -1,17 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Lifeform
4
- module CapturingRenderable
5
- # NOTE: the previous `with_output_buffer` stuff is for some reason incompatible with Serbea.
6
- # So we'll use a simpler capture.
7
- def render_in(view_context, &block)
8
- if block
9
- call(view_context: view_context) do |*args, **kwargs|
10
- unsafe_raw(view_context.capture(*args, **kwargs, &block))
11
- end.html_safe
12
- else
13
- call(view_context: view_context).html_safe
14
- end
15
- end
16
- end
17
- end
@@ -1,75 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # Bridgetown-specific workaround that got copied over from the phlex-rails gem (for now)
4
- module Lifeform
5
- module PhlexRenderable
6
- def helpers
7
- @_view_context
8
- end
9
-
10
- def render(renderable, *args, **kwargs, &block)
11
- return super if renderable.is_a?(Phlex::HTML)
12
- return super if renderable.is_a?(Class) && renderable < Phlex::HTML
13
-
14
- @_target << @_view_context.render(renderable, *args, **kwargs, &block)
15
-
16
- nil
17
- end
18
-
19
- def render_in(view_context, &block)
20
- if block_given?
21
- call(view_context: view_context) do |*args|
22
- view_context.with_output_buffer(self) do
23
- original_length = @_target.length
24
- output = yield(*args)
25
- unchanged = (original_length == @_target.length)
26
-
27
- if unchanged
28
- if output.is_a?(ActiveSupport::SafeBuffer)
29
- unsafe_raw(output)
30
- else
31
- text(output)
32
- end
33
- end
34
- end
35
- end.html_safe
36
- else
37
- call(view_context: view_context).html_safe
38
- end
39
- end
40
-
41
- def safe_append=(value)
42
- return unless value
43
-
44
- @_target << case value
45
- when String then value
46
- when Symbol then value.name
47
- else value.to_s
48
- end
49
- end
50
-
51
- def append=(value)
52
- return unless value
53
-
54
- if value.html_safe?
55
- self.safe_append = value
56
- else
57
- @_target << case value
58
- when String then ERB::Util.html_escape(value)
59
- when Symbol then ERB::Util.html_escape(value.name)
60
- else ERB::Util.html_escape(value.to_s)
61
- end
62
- end
63
- end
64
-
65
- def capture
66
- super.html_safe
67
- end
68
-
69
- # Trick ViewComponent into thinking we're a ViewComponent to fix rendering output
70
- def set_original_view_context(view_context)
71
- end
72
- end
73
- end
74
-
75
- Phlex::HTML.prepend(Lifeform::PhlexRenderable)