Skip to content

Instantly share code, notes, and snippets.

@pootsbook
Created April 17, 2021 19:57
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pootsbook/cb02dce23509ec4044e43095fb5f6806 to your computer and use it in GitHub Desktop.
Save pootsbook/cb02dce23509ec4044e43095fb5f6806 to your computer and use it in GitHub Desktop.
Form Representation as Data 3 (select and options)
require "scrivener"
require "hypertext"
require "hypertext/dsl"
class RegistrationForm < Scrivener
attr_accessor :name
attr_accessor :email
attr_accessor :message
attr_accessor :enquiry
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"
f[:options] = send("#{attr}_options") if tag_mapping[attr] == "select"
end
}
end.push({
"input" => {
type: :submit,
value: "send"
}
})
}
end
def enquiry_options
[
{
"option" => {
value: "uninterested",
text: "I’m just having a look around."
}
},
{
"option" => {
value: "interested",
text: "I’d really like to buy something"
}
}
]
end
def tag_mapping
{
name: "input",
email: "input",
message: "textarea",
enquiry: "select"
}
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),
"select" => %i(id name),
"option" => %i(value)
}
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
elsif att.has_key? :options
public_send tag, att.slice(*ATTRS.fetch(tag)) do
att[:options].each do |option|
render_field(option)
end
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>
+ <label for="enquiry_field">
+ Enquiry
+ </label>
+ <select id="enquiry_field" name="enquiry">
+ <option value="uninterested">
+ I’m just having a look around.
+ </option>
+ <option value="interested">
+ I’d really like to buy something
+ </option>
+ </select>
+ <input type="submit" value="send" />
+ </form>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment