Created
June 29, 2013 22:30
-
-
Save plexus/5892947 to your computer and use it in GitHub Desktop.
This file contains 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 'hexp' | |
class FormBuilder | |
# All the ones that Drupal's form API implements | |
# https://api.drupal.org/api/drupal/developer!topics!forms_api_reference.html/7 | |
# TYPES = %w[checkbox checkboxes date fieldset file machine_name managed_file | |
# password password_confirm radio radios select tableselect text_format | |
# textarea textfield vertical_tabs weight].map(&:to_sym) | |
TYPES = %w[select textfield].map(&:to_sym) | |
attr_reader :elements | |
def initialize(&blk) | |
@elements = [] | |
instance_eval(&blk) | |
end | |
TYPES.each do |type| | |
define_method type do |name, opts = {}, &blk| | |
@elements << [type, name, opts] | |
end | |
end | |
def form_class | |
Class.new(Form).tap do |klz| | |
klz.elements = @elements | |
end | |
end | |
end | |
class Form | |
include Hexp | |
class << self | |
attr_accessor :elements | |
end | |
def self.build(&blk) | |
raise unless blk | |
FormBuilder.new(&blk).form_class | |
end | |
attr_reader :values | |
def initialize(model_or_params) | |
@values = Hash[ | |
self.class.elements.map do |type, name, opts| | |
value = model_or_params[name] | |
options = element_opts(name) | |
if options | |
value = nil | |
options.each do |option_value, text| | |
if option_value.to_s == model_or_params[name].to_s | |
value = option_value | |
break | |
end | |
end | |
end | |
[name, value] | |
end | |
] | |
end | |
def element_opts(element_name) | |
self.class.elements.select do |type, name, opts| | |
element_name == name | |
end[2] | |
end | |
def to_hexp | |
H[:form, elements] | |
end | |
def elements | |
self.class.elements.map do |type, name, opts| | |
H[:div, [ | |
H[:label, {for: name}, opts[:title]], | |
self.send(type, name, opts).attr('name', name) | |
] | |
] | |
end | |
end | |
def textfield(name, opts) | |
H[:input, {type: "text", value: @values[name]}] | |
end | |
def select(name, opts) | |
H[:select, opts[:options].map do |value, text| | |
H[:option, {value: value}, text] | |
end | |
] | |
end | |
def select_option(name, value, text) | |
attrs = {value: value} | |
attrs[:selected] = 'selected' if @value[name] == value | |
H[:option, attrs, text] | |
end | |
end |
This file contains 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
source 'https://rubygems.org' | |
gem 'hexp', path: '/home/arne/github/hexp' | |
gem 'virtus', github: 'solnic/virtus' | |
gem 'sinatra' | |
gem 'active_support' | |
gem 'debugger' |
This file contains 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
#!/usr/bin/env ruby | |
require 'hexp' | |
require 'virtus' | |
require 'sinatra' | |
require 'pstore' | |
require 'active_support/core_ext/hash/slice' | |
require_relative 'form_builder' | |
require_relative 'issue_repo' | |
class Issue | |
include Virtus | |
STATES = [:open, :closed] | |
PRIORITIES = {:high => "High", :medium => "Medium", :low => "Low"} | |
attribute :id, Integer | |
attribute :title, String | |
attribute :state, Symbol | |
attribute :priority, Symbol | |
def priority_str | |
PRIORITIES[priority] | |
end | |
end | |
IssueForm = Form.build do | |
textfield :title, title: "Title" | |
select :priority, title: "Priority", | |
options: Issue::PRIORITIES | |
end | |
class IssueList | |
include Hexp | |
attr_reader :issues | |
def initialize(issues) | |
@issues = issues | |
end | |
def to_hexp | |
H[:table, [ | |
H[:thead, H[:tr, [ H[:th, "Title"], H[:th, "Priority"] ]]], | |
H[:tbody, issues.map {|issue| H[:tr, [ H[:td, issue.title], H[:td, issue.priority_str]]] }] | |
] | |
] | |
end | |
end | |
class App < Sinatra::Base | |
def repo | |
@repo ||= IssueRepo.new | |
end | |
get '/' do | |
begin | |
IssueList.new(repo.all).to_html | |
rescue | |
IssueRepo.new.all.inspect | |
end | |
end | |
get '/new' do | |
IssueForm.new(Issue.new).attrs(method: "POST", action: "/create").to_html | |
end | |
post '/create' do | |
form = IssueForm.new(params) | |
repo.store(Issue.new(form.values)) | |
redirect "/" | |
end | |
end | |
App.run! if __FILE__ == $0 |
This file contains 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
class IssueRepo | |
def repo | |
@repo ||= PStore.new('issues.pstore') | |
end | |
def find(id) | |
read { repo[id] } | |
end | |
def store(issue) | |
unless issue.id | |
issue.id = next_id | |
end | |
write { repo[issue.id] = issue } | |
end | |
def next_id | |
max = read { repo.roots }.max | |
(max || 0) + 1 | |
end | |
def all | |
read do | |
repo.roots.map {|i| repo[i]} | |
end | |
end | |
private | |
def read(&blk) | |
repo.transaction true, &blk | |
end | |
def write(&blk) | |
repo.transaction &blk | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment