Skip to content

Instantly share code, notes, and snippets.

@pootsbook
Last active April 15, 2021 21:35
Show Gist options
  • Save pootsbook/35feac04cb8b708b9f3a2432b20d9723 to your computer and use it in GitHub Desktop.
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.
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">
# Email
# </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