lifeform 0.5 → 0.7

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: b554a393fe6d14365108e97b9da374e73da67f0d6728b8605f6d2ddea2f3e3f5
4
- data.tar.gz: 5749f82de0a38dd41d7fd75245ed1cab66b0b2550bdabc722620e70c2345bf37
3
+ metadata.gz: 0bd913233e25c58ae11c6e356383384f4fd995a35a530f62525524abbb3902f2
4
+ data.tar.gz: a9cbb5ec298a1e291486fe993f14c69a6aff0ef35baf1ec061d9e9bc93e87b78
5
5
  SHA512:
6
- metadata.gz: 86f68d5c0673570a0e549c2f68afb731b749ab305fb9a3a2f2013820389985cd3468b56263ec738ee113a90c49889cc755efd93427c985788af84e37b83b2d56
7
- data.tar.gz: d6f72691ee444c44f78a8b8c1bfb7f93c10105398d77f4be6c593e96d85bf58ee031c7fe30f572a133ebeffdd3791aaed2b99438848e27e51431e4da048690a5
6
+ metadata.gz: 144a5f5b14116f6471acd45c66fb369119d2256a6da724a83df428819d694d3ff017f539c0a2fd7b0ff9f94237d57216116efdd60aac8524e11b3fdb93f801b2
7
+ data.tar.gz: 892413ee58661eb72851f2fbd0ffc1b4a831cbab406eac8f61d17a03ced7c06e59c5b5716659d5e0df5b90c15ab65569e2819fbf3ccd3be30dcf0a2607a09751
data/.rubocop.yml CHANGED
@@ -1,11 +1,22 @@
1
+ require:
2
+ - rubocop-minitest
3
+ - rubocop-rake
4
+
1
5
  AllCops:
2
6
  TargetRubyVersion: 2.7
3
7
  NewCops: enable
4
8
 
9
+ Lint/MissingSuper:
10
+ Enabled: false
11
+
5
12
  Metrics/AbcSize:
6
13
  Exclude:
7
14
  - test/**/*.rb
8
15
 
16
+ Metrics/ClassLength:
17
+ Exclude:
18
+ - test/**/*.rb
19
+
9
20
  Metrics/MethodLength:
10
21
  Max: 20
11
22
  Exclude:
data/CHANGELOG.md CHANGED
@@ -2,6 +2,10 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [0.7.0] - 2022-09-30
6
+
7
+ - Rearchitect library to be built on top of the Phlex view library
8
+
5
9
  ## [0.5.0] - 2022-06-10
6
10
 
7
11
  ## [0.4.0] - 2022-06-08
data/Gemfile CHANGED
@@ -8,6 +8,7 @@ gemspec
8
8
  gem "rake", "~> 13.0"
9
9
 
10
10
  gem "minitest", "~> 5.0"
11
+ gem "minitest-reporters", "~> 1.5"
11
12
 
12
13
  gem "rubocop", "~> 1.21"
13
14
 
data/Gemfile.lock CHANGED
@@ -1,69 +1,75 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- lifeform (0.5)
4
+ lifeform (0.7)
5
5
  activesupport (>= 6.0)
6
- papercraft (~> 0.24)
6
+ phlex (~> 0.3)
7
7
  zeitwerk (~> 2.5)
8
8
 
9
9
  GEM
10
10
  remote: https://rubygems.org/
11
11
  specs:
12
- activesupport (7.0.3)
12
+ activesupport (7.0.4)
13
13
  concurrent-ruby (~> 1.0, >= 1.0.2)
14
14
  i18n (>= 1.6, < 2)
15
15
  minitest (>= 5.1)
16
16
  tzinfo (~> 2.0)
17
+ ansi (1.5.0)
17
18
  ast (2.4.2)
18
19
  backport (1.2.0)
19
20
  benchmark (0.2.0)
21
+ builder (3.2.4)
20
22
  concurrent-ruby (1.1.10)
21
23
  diff-lcs (1.5.0)
22
24
  e2mmap (0.1.0)
23
- escape_utils (1.2.1)
24
- i18n (1.10.0)
25
+ i18n (1.12.0)
25
26
  concurrent-ruby (~> 1.0)
26
27
  jaro_winkler (1.5.4)
27
- kramdown (2.3.2)
28
+ json (2.6.2)
29
+ kramdown (2.4.0)
28
30
  rexml
29
31
  kramdown-parser-gfm (1.1.0)
30
32
  kramdown (~> 2.0)
31
- minitest (5.15.0)
32
- nokogiri (1.13.6-arm64-darwin)
33
+ minitest (5.16.3)
34
+ minitest-reporters (1.5.0)
35
+ ansi
36
+ builder
37
+ minitest (>= 5.0)
38
+ ruby-progressbar
39
+ nokogiri (1.13.8-arm64-darwin)
33
40
  racc (~> 1.4)
34
- nokogiri (1.13.6-x86_64-linux)
41
+ nokogiri (1.13.8-x86_64-linux)
35
42
  racc (~> 1.4)
36
- papercraft (0.24)
37
- escape_utils (~> 1.2.1)
38
- kramdown (~> 2.3.1)
39
- kramdown-parser-gfm (~> 1.1.0)
40
- rouge (~> 3.27.0)
41
43
  parallel (1.22.1)
42
- parser (3.1.2.0)
44
+ parser (3.1.2.1)
43
45
  ast (~> 2.4.1)
46
+ phlex (0.3.1)
47
+ syntax_tree (~> 3.6)
48
+ zeitwerk (~> 2.6)
49
+ prettier_print (0.1.0)
44
50
  racc (1.6.0)
45
51
  rails-dom-testing (2.0.3)
46
52
  activesupport (>= 4.2.0)
47
53
  nokogiri (>= 1.6)
48
54
  rainbow (3.1.1)
49
55
  rake (13.0.6)
50
- regexp_parser (2.5.0)
56
+ regexp_parser (2.6.0)
51
57
  reverse_markdown (2.1.1)
52
58
  nokogiri
53
59
  rexml (3.2.5)
54
- rouge (3.27.0)
55
- rubocop (1.30.0)
60
+ rubocop (1.36.0)
61
+ json (~> 2.3)
56
62
  parallel (~> 1.10)
57
- parser (>= 3.1.0.0)
63
+ parser (>= 3.1.2.1)
58
64
  rainbow (>= 2.2.2, < 4.0)
59
65
  regexp_parser (>= 1.8, < 3.0)
60
66
  rexml (>= 3.2.5, < 4.0)
61
- rubocop-ast (>= 1.18.0, < 2.0)
67
+ rubocop-ast (>= 1.20.1, < 2.0)
62
68
  ruby-progressbar (~> 1.7)
63
69
  unicode-display_width (>= 1.4.0, < 3.0)
64
- rubocop-ast (1.18.0)
70
+ rubocop-ast (1.21.0)
65
71
  parser (>= 3.1.1.0)
66
- rubocop-minitest (0.20.0)
72
+ rubocop-minitest (0.20.1)
67
73
  rubocop (>= 0.90, < 2.0)
68
74
  rubocop-rake (0.6.0)
69
75
  rubocop (~> 1.0)
@@ -83,15 +89,17 @@ GEM
83
89
  thor (~> 1.0)
84
90
  tilt (~> 2.0)
85
91
  yard (~> 0.9, >= 0.9.24)
92
+ syntax_tree (3.6.1)
93
+ prettier_print
86
94
  thor (1.2.1)
87
- tilt (2.0.10)
88
- tzinfo (2.0.4)
95
+ tilt (2.0.11)
96
+ tzinfo (2.0.5)
89
97
  concurrent-ruby (~> 1.0)
90
- unicode-display_width (2.1.0)
98
+ unicode-display_width (2.3.0)
91
99
  webrick (1.7.0)
92
- yard (0.9.27)
100
+ yard (0.9.28)
93
101
  webrick (~> 1.7.0)
94
- zeitwerk (2.5.4)
102
+ zeitwerk (2.6.0)
95
103
 
96
104
  PLATFORMS
97
105
  arm64-darwin-21
@@ -100,6 +108,7 @@ PLATFORMS
100
108
  DEPENDENCIES
101
109
  lifeform!
102
110
  minitest (~> 5.0)
111
+ minitest-reporters (~> 1.5)
103
112
  rails-dom-testing (~> 2.0)
104
113
  rake (~> 13.0)
105
114
  rubocop (~> 1.21)
data/README.md CHANGED
@@ -55,7 +55,7 @@ You get the following HTML output:
55
55
 
56
56
  Nested names based on models (aka `profile[name]`) and inferred action paths are supported as well.
57
57
 
58
- Multiple component libraries and input types—and easy customizability via [Papercraft](https://github.com/digital-fabric/papercraft) templates—are a fundamental aspect of the architecture of Lifeform.
58
+ 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
59
 
60
60
  ### Automatic Field Rendering
61
61
 
@@ -0,0 +1,17 @@
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
+ 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
data/lib/lifeform/form.rb CHANGED
@@ -6,7 +6,8 @@ module Lifeform
6
6
  FieldDefinition = Struct.new(:type, :library, :parameters)
7
7
 
8
8
  # A form object which stores field definitions and can be rendered as a component
9
- class Form # rubocop:todo Metrics/ClassLength
9
+ class Form < Phlex::View # rubocop:todo Metrics/ClassLength
10
+ include CapturingRenderable
10
11
  MODEL_PATH_HELPER = :polymorphic_path
11
12
 
12
13
  class << self
@@ -43,34 +44,35 @@ module Lifeform
43
44
  @library ||= :default
44
45
  end
45
46
 
46
- def escape_value(value)
47
+ def process_value(key, value)
48
+ return value if key == :if
49
+
47
50
  case value
48
- when TrueClass, FalseClass
49
- value
51
+ when TrueClass
52
+ key.to_s
53
+ when FalseClass
54
+ nil
55
+ when Symbol, Integer
56
+ value.to_s
50
57
  else
51
- EscapeUtils.escape_html(value.to_s)
58
+ value
52
59
  end
53
60
  end
54
61
 
55
62
  # @param kwargs [Hash]
56
63
  def parameters_to_attributes(kwargs)
57
- previous_value = EscapeUtils.html_secure
58
- EscapeUtils.html_secure = false
59
-
60
64
  attributes = {}
61
65
  kwargs.each do |key, value|
62
66
  case value
63
67
  when Hash
64
68
  value.each do |inner_key, inner_value|
65
- attributes[:"#{key}_#{inner_key}"] = escape_value(inner_value)
69
+ attributes[:"#{key}_#{inner_key}"] = process_value(inner_key, inner_value)
66
70
  end
67
71
  else
68
- attributes[key] = escape_value(value) unless value.nil?
72
+ attributes[key] = process_value(key, value) unless value.nil?
69
73
  end
70
74
  end
71
75
 
72
- EscapeUtils.html_secure = previous_value
73
-
74
76
  attributes
75
77
  end
76
78
 
@@ -120,20 +122,27 @@ module Lifeform
120
122
  def verify_method
121
123
  return if %w[get post].include?(parameters[:method].to_s.downcase)
122
124
 
123
- @method_tag = Papercraft.html do |method_name|
124
- input type: "hidden", name: "_method", value: method_name, autocomplete: "off"
125
- end.render(parameters[:method].to_s.downcase)
125
+ @method_tag = Class.new(Phlex::View) do # TODO: break this out into a real component
126
+ def initialize(method:)
127
+ @method = method
128
+ end
129
+
130
+ def template
131
+ input type: "hidden", name: "_method", value: @method, autocomplete: "off"
132
+ end
133
+ end.new(method: @parameters[:method].to_s.downcase)
134
+
126
135
  parameters[:method] = :post
127
136
  end
128
137
 
129
- def add_authenticity_token(view_context) # rubocop:disable Metrics/AbcSize
130
- if view_context.respond_to?(:token_tag, true) # Rails
131
- view_context.send(:token_tag, nil, form_options: {
132
- action: parameters[:action].to_s,
133
- method: parameters[:method].to_s.downcase
134
- })
135
- elsif view_context.respond_to?(:csrf_tag, true) # Roda
136
- view_context.send(:csrf_tag, action: parameters[:action].to_s, method: parameters[:method].to_s)
138
+ def add_authenticity_token # rubocop:disable Metrics/AbcSize
139
+ if helpers.respond_to?(:token_tag, true) # Rails
140
+ helpers.send(:token_tag, nil, form_options: {
141
+ action: parameters[:action].to_s,
142
+ method: parameters[:method].to_s.downcase
143
+ })
144
+ elsif helpers.respond_to?(:csrf_tag, true) # Roda
145
+ helpers.send(:csrf_tag, action: parameters[:action].to_s, method: parameters[:method].to_s)
137
146
  else
138
147
  raise Lifeform::Error, "Missing token tag helper. Override `add_authenticity_token' in your Form object"
139
148
  end
@@ -161,30 +170,19 @@ module Lifeform
161
170
  )
162
171
  end
163
172
 
164
- def render_in(view_context, &block) # rubocop:disable Metrics
173
+ def template(&block) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity
165
174
  form_tag = library::FORM_TAG
166
- parameters[:action] ||= url || (model ? view_context.send(self.class.const_get(:MODEL_PATH_HELPER), model) : nil)
167
-
168
- content = if block
169
- view_context.capture(self, &block)
170
- else
171
- self.class.fields.map { |k, _v| field(k).render_in(self) }.join.then do |renderings|
172
- renderings.respond_to?(:html_safe) ? renderings.html_safe : renderings
173
- end
174
- end
175
-
176
- return content unless emit_form_tag
175
+ parameters[:action] ||= url || (model ? helpers.send(self.class.const_get(:MODEL_PATH_HELPER), model) : nil)
177
176
 
178
- content = add_authenticity_token(view_context) + content.to_s unless parameters[:method].to_s.downcase == "get"
179
- content = @method_tag + content.to_s if @method_tag
180
-
181
- # if @hidden_submit_button
182
- # content += %(\n<button type="submit" style="position: absolute; left: -9999px"></button>).html_safe
183
- # end
177
+ send(form_tag, **attributes) do
178
+ raw(add_authenticity_token) unless parameters[:method].to_s.downcase == "get"
179
+ raw @method_tag&.() || ""
180
+ block ? yield_content(&block) : auto_render_fields
181
+ end
182
+ end
184
183
 
185
- Papercraft.html do |attr|
186
- send(form_tag, **attr) { emit content }
187
- end.render(attributes)
184
+ def auto_render_fields
185
+ self.class.fields.map { |k, _v| render(field(k)) }
188
186
  end
189
187
  end
190
188
  end
@@ -3,48 +3,40 @@
3
3
  module Lifeform
4
4
  module Libraries
5
5
  class Default
6
- class Button
6
+ class Button < Phlex::View
7
+ include CapturingRenderable
8
+
7
9
  attr_reader :form, :field_definition, :attributes
8
10
 
9
11
  WRAPPER_TAG = :form_button
10
12
  BUTTON_TAG = :button
11
13
 
14
+ register_element WRAPPER_TAG
15
+
12
16
  def initialize(form, field_definition, **attributes)
13
17
  @form = form
14
18
  @field_definition = field_definition
15
19
  @attributes = Lifeform::Form.parameters_to_attributes(field_definition.parameters).merge(attributes)
16
20
  @if = @attributes.delete(:if)
17
21
  @label = @attributes.delete(:label) || "Unlabeled Button"
18
- @attributes[:type] ||= :button
22
+ @attributes[:type] ||= "button"
19
23
  end
20
24
 
21
- def render_in(view_context, &block)
22
- @view_context = view_context
23
- @content = block
24
- return "" if !@if.nil? && !@if
25
+ def template(&block)
26
+ return if !@if.nil? && !@if
25
27
 
26
- template
27
- end
28
+ wrapper_tag = self.class.const_get(:WRAPPER_TAG)
29
+ button_tag = self.class.const_get(:BUTTON_TAG)
30
+
31
+ field_body = proc {
32
+ send(button_tag, **@attributes) do
33
+ raw(@label.to_s) unless block
34
+ yield_content(&block)
35
+ end
36
+ }
37
+ return field_body.() unless wrapper_tag
28
38
 
29
- def template # rubocop:disable Metrics/AbcSize
30
- Papercraft.html do |wrapper_tag:, button_tag:, attributes:, field_data:|
31
- field_body = proc {
32
- send(button_tag, **attributes) do
33
- emit field_data[:content] || field_data[:label]
34
- end
35
- }
36
- next field_body.call unless wrapper_tag
37
-
38
- send wrapper_tag, name: attributes[:name], &field_body
39
- end.render(
40
- wrapper_tag: self.class.const_get(:WRAPPER_TAG),
41
- button_tag: self.class.const_get(:BUTTON_TAG),
42
- attributes: attributes,
43
- field_data: {
44
- label: @label,
45
- content: @content && @view_context.capture(&@content)
46
- }
47
- )
39
+ send wrapper_tag, name: @attributes[:name], &field_body
48
40
  end
49
41
  end
50
42
  end
@@ -3,11 +3,15 @@
3
3
  module Lifeform
4
4
  module Libraries
5
5
  class Default
6
- class Input
6
+ class Input < Phlex::View
7
+ include CapturingRenderable
8
+
7
9
  attr_reader :form, :field_definition, :attributes
8
10
 
9
- INPUT_TAG = :input
10
11
  WRAPPER_TAG = :form_field
12
+ INPUT_TAG = :input
13
+
14
+ register_element WRAPPER_TAG
11
15
 
12
16
  def initialize(form, field_definition, **attributes)
13
17
  @form = form
@@ -40,44 +44,30 @@ module Lifeform
40
44
  end
41
45
 
42
46
  def handle_labels
43
- Papercraft.html do |label_text, name|
44
- label label_text, for: name
45
- end.render(
46
- attributes[:label].to_s,
47
- (attributes[:id] || attributes[:name]).to_s
48
- ).tap do
49
- @attributes = attributes.filter_map { |k, v| [k, v] unless k == :label }.to_h
50
- end
51
- end
47
+ label_text = attributes[:label].to_s
48
+ label_name = (attributes[:id] || attributes[:name]).to_s
52
49
 
53
- def render_in(view_context, &block)
54
- @view_context = view_context
55
- @content = block
56
- return "" if !@if.nil? && !@if
50
+ @attributes = attributes.filter_map { |k, v| [k, v] unless k == :label }.to_h
57
51
 
58
- template
52
+ proc {
53
+ label(for: label_name) { raw label_text }
54
+ }
59
55
  end
60
56
 
61
- def template # rubocop:disable Metrics/AbcSize
62
- Papercraft.html do |wrapper_tag:, input_tag:, attributes:, field_data:|
63
- field_body = proc {
64
- emit(field_data[:label]) if field_data[:label]
65
- send input_tag, type: field_data[:type], **attributes
66
- emit(field_data[:content]) if field_data[:content]
67
- }
68
- next field_body.call unless wrapper_tag
69
-
70
- send wrapper_tag, name: attributes[:name], &field_body
71
- end.render(
72
- wrapper_tag: self.class.const_get(:WRAPPER_TAG),
73
- input_tag: self.class.const_get(:INPUT_TAG),
74
- attributes: attributes,
75
- field_data: {
76
- type: @field_type,
77
- label: @label,
78
- content: @content && @view_context.capture(&@content)
79
- }
80
- )
57
+ def template(&block)
58
+ return if !@if.nil? && !@if
59
+
60
+ wrapper_tag = self.class.const_get(:WRAPPER_TAG)
61
+ input_tag = self.class.const_get(:INPUT_TAG)
62
+
63
+ field_body = proc {
64
+ @label&.()
65
+ send input_tag, type: @field_type.to_s, **@attributes
66
+ yield_content(&block)
67
+ }
68
+ return field_body.() unless wrapper_tag
69
+
70
+ send wrapper_tag, name: @attributes[:name], &field_body
81
71
  end
82
72
  end
83
73
  end
@@ -6,7 +6,7 @@ module Lifeform
6
6
  class SubmitButton < Button
7
7
  def initialize(form, field_definition, **attributes)
8
8
  attributes[:name] ||= "commit"
9
- attributes[:type] = :submit
9
+ attributes[:type] = "submit"
10
10
 
11
11
  super
12
12
  end
@@ -6,6 +6,8 @@ module Lifeform
6
6
  class Input < Default::Input
7
7
  INPUT_TAG = :sl_input
8
8
 
9
+ register_element :sl_input
10
+
9
11
  # no-op
10
12
  def handle_labels; end
11
13
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Lifeform
4
- VERSION = "0.5"
4
+ VERSION = "0.7"
5
5
  end
data/lib/lifeform.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "papercraft"
3
+ require "phlex"
4
+ require "active_support/core_ext/string/output_safety"
4
5
 
5
6
  require "zeitwerk"
6
7
  loader = Zeitwerk::Loader.for_gem
data/lifeform.gemspec CHANGED
@@ -25,6 +25,6 @@ Gem::Specification.new do |spec|
25
25
 
26
26
  # Uncomment to register a new dependency of your gem
27
27
  spec.add_dependency "activesupport", ">= 6.0"
28
- spec.add_dependency "papercraft", "~> 0.24"
28
+ spec.add_dependency "phlex", "~> 0.3"
29
29
  spec.add_dependency "zeitwerk", "~> 2.5"
30
30
  end
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.5'
4
+ version: '0.7'
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-06-11 00:00:00.000000000 Z
11
+ date: 2022-09-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -25,19 +25,19 @@ dependencies:
25
25
  - !ruby/object:Gem::Version
26
26
  version: '6.0'
27
27
  - !ruby/object:Gem::Dependency
28
- name: papercraft
28
+ name: phlex
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '0.24'
33
+ version: '0.3'
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '0.24'
40
+ version: '0.3'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: zeitwerk
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -72,6 +72,7 @@ files:
72
72
  - bin/rubocop
73
73
  - bin/setup
74
74
  - lib/lifeform.rb
75
+ - lib/lifeform/capturing_renderable.rb
75
76
  - lib/lifeform/form.rb
76
77
  - lib/lifeform/libraries/default.rb
77
78
  - lib/lifeform/libraries/default/button.rb