Last active
April 15, 2021 21:35
-
-
Save pootsbook/35feac04cb8b708b9f3a2432b20d9723 to your computer and use it in GitHub Desktop.
An attempt at rendering form fields in a generic way from a form representation as data.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require "scrivener" | |
require "hypertext" | |
require "hypertext/dsl" | |
class RegistrationForm < Scrivener | |
attr_accessor :name | |
attr_accessor :email | |
attr_accessor :message | |
def validate | |
assert_present :name | |
assert_present :email | |
assert_present :message | |
assert_email :email | |
end | |
def form | |
{ | |
action: "/contact", | |
method: "post", | |
errors: errors, | |
fields: attributes.keys.map do |attr| | |
{ | |
"label" => { | |
for: "#{attr}_field", | |
text: attr.capitalize.to_s | |
}, | |
tag_mapping[attr] => { | |
type: type_mapping[attr], | |
name: attr, | |
id: "#{attr}_field", | |
value: send(attr), | |
attribute: attr | |
}.tap do |f| | |
f[:text] = send(attr) if tag_mapping[attr] == "textarea" | |
end | |
} | |
end.push({ | |
"input" => { | |
type: :submit, | |
value: "send" | |
} | |
}) | |
} | |
end | |
def tag_mapping | |
{ | |
name: "input", | |
email: "input", | |
message: "textarea" | |
} | |
end | |
def type_mapping | |
{ | |
name: :text, | |
email: :email, | |
} | |
end | |
end | |
class Template < Hypertext::DSL | |
ATTRS = { | |
"input" => %i(type name id value), | |
"label" => %i(for), | |
"textarea" => %i(id name rows cols) | |
} | |
def initialize(site) | |
site.each_pair do |key, val| | |
instance_variable_set(sprintf("@%s", key), val) | |
end | |
@ht = Hypertext.new | |
render_form @form | |
end | |
def render(string) | |
instance_eval string | |
end | |
def render_form(f) | |
form f.slice(:action, :method) do | |
f[:fields].each do |ff| | |
render_field(ff) | |
end | |
end | |
end | |
def render_field(f) | |
f.each do |tag, att| | |
if att[:text] | |
public_send tag, att.slice(*ATTRS.fetch(tag)) do | |
text att[:text] | |
end | |
else | |
public_send tag, att.slice(*ATTRS.fetch(tag)) | |
end | |
end | |
end | |
end | |
validator = RegistrationForm.new(message: "Hello, World!") | |
template = Template.new(form: validator.form) | |
puts template.to_s | |
# => | |
# <form action="/contact" method="post"> | |
# <label for="email_field"> | |
# </label> | |
# <input type="email" name="email" id="email_field" value="" /> | |
# <label for="name_field"> | |
# Name | |
# </label> | |
# <input type="text" name="name" id="name_field" value="" /> | |
# <label for="message_field"> | |
# Message | |
# </label> | |
# <textarea id="message_field" name="message"> | |
# Hello, World! | |
# </textarea> | |
# <input type="submit" value="send" /> | |
# </form> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment