form_template.rb

 1# frozen_string_literal: true
 2
 3require "blather"
 4
 5class FormTemplate
 6	def initialize(template, filename="template", **kwargs)
 7		@args = kwargs
 8		@template = template
 9		@filename = filename
10		freeze
11	end
12
13	def self.render(path, **kwargs)
14		full_path = File.dirname(__dir__) + "/forms/#{path}.rb"
15		new(File.read(full_path), full_path, **kwargs).render
16	end
17
18	def render(**kwargs)
19		one = OneRender.new(**@args.merge(kwargs))
20		one.instance_eval(@template, @filename)
21		one.form
22	end
23
24	class OneRender
25		def initialize(**kwargs)
26			kwargs.each do |k, v|
27				instance_variable_set("@#{k}", v)
28			end
29			@__form = Blather::Stanza::X.new
30			@__builder = Nokogiri::XML::Builder.with(@__form)
31		end
32
33		def form!
34			@__type_set = true
35			@__form.type = :form
36		end
37
38		def result!
39			@__type_set = true
40			@__form.type = :result
41		end
42
43		def title(s)
44			@__form.title = s
45		end
46
47		def instructions(s)
48			@__form.instructions = s
49		end
50
51		def validate(field, datatype: nil, **kwargs)
52			Nokogiri::XML::Builder.with(field) do |xml|
53				xml.validate(
54					xmlns: "http://jabber.org/protocol/xdata-validate",
55					datatype: datatype || "xs:string"
56				) do
57					xml.basic unless validation_type(xml, **kwargs)
58				end
59			end
60		end
61
62		def validation_type(xml, open: false, regex: nil, range: nil)
63			xml.open if open
64			xml.range(min: range.first, max: range.last) if range
65			xml.regex(regex.source) if regex
66			open || regex || range
67		end
68
69		def field(datatype: nil, open: false, regex: nil, range: nil, **kwargs)
70			f = Blather::Stanza::X::Field.new(kwargs)
71			if datatype || open || regex || range
72				validate(f, datatype: datatype, open: open, regex: regex, range: range)
73			end
74			@__form.fields += [f]
75		end
76
77		def xml
78			@__builder
79		end
80
81		def form
82			raise "Type never set" unless @__type_set
83
84			@__form
85		end
86	end
87end