lifeform 0.5 → 0.7

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: 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