formalist 0.2.2 → 0.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Gemfile +7 -3
- data/Gemfile.lock +36 -38
- data/README.md +8 -4
- data/Rakefile +0 -7
- data/lib/formalist/element/attributes.rb +54 -0
- data/lib/formalist/element/class_interface.rb +133 -0
- data/lib/formalist/element/definition.rb +55 -0
- data/lib/formalist/element/permitted_children.rb +46 -0
- data/lib/formalist/element.rb +51 -0
- data/lib/formalist/elements/attr.rb +74 -0
- data/lib/formalist/elements/compound_field.rb +49 -0
- data/lib/formalist/elements/field.rb +73 -0
- data/lib/formalist/elements/group.rb +50 -0
- data/lib/formalist/elements/many.rb +125 -0
- data/lib/formalist/elements/section.rb +58 -0
- data/lib/formalist/elements/standard/check_box.rb +20 -0
- data/lib/formalist/elements/standard/date_field.rb +12 -0
- data/lib/formalist/elements/standard/date_time_field.rb +12 -0
- data/lib/formalist/elements/standard/hidden_field.rb +11 -0
- data/lib/formalist/elements/standard/multi_selection_field.rb +16 -0
- data/lib/formalist/elements/standard/number_field.rb +17 -0
- data/lib/formalist/elements/standard/radio_buttons.rb +13 -0
- data/lib/formalist/elements/standard/select_box.rb +13 -0
- data/lib/formalist/elements/standard/selection_field.rb +16 -0
- data/lib/formalist/elements/standard/text_area.rb +15 -0
- data/lib/formalist/elements/standard/text_field.rb +14 -0
- data/lib/formalist/elements/standard.rb +11 -0
- data/lib/formalist/elements.rb +20 -0
- data/lib/formalist/form/definition_context.rb +58 -4
- data/lib/formalist/form/result.rb +5 -27
- data/lib/formalist/form.rb +15 -35
- data/lib/formalist/types.rb +30 -0
- data/lib/formalist/version.rb +1 -1
- data/lib/formalist.rb +0 -20
- data/spec/examples.txt +8 -7
- data/spec/integration/dependency_injection_spec.rb +54 -0
- data/spec/integration/form_spec.rb +86 -13
- data/spec/spec_helper.rb +12 -5
- data/spec/support/constants.rb +11 -0
- data/spec/unit/elements/standard/check_box_spec.rb +33 -0
- metadata +36 -63
- data/lib/formalist/definition_compiler.rb +0 -61
- data/lib/formalist/display_adapters/default.rb +0 -9
- data/lib/formalist/display_adapters/radio.rb +0 -19
- data/lib/formalist/display_adapters/select.rb +0 -19
- data/lib/formalist/display_adapters/textarea.rb +0 -14
- data/lib/formalist/display_adapters.rb +0 -16
- data/lib/formalist/form/definition/attr.rb +0 -20
- data/lib/formalist/form/definition/component.rb +0 -31
- data/lib/formalist/form/definition/field.rb +0 -29
- data/lib/formalist/form/definition/group.rb +0 -31
- data/lib/formalist/form/definition/many.rb +0 -41
- data/lib/formalist/form/definition/section.rb +0 -23
- data/lib/formalist/form/definition.rb +0 -37
- data/lib/formalist/form/result/attr.rb +0 -82
- data/lib/formalist/form/result/component.rb +0 -51
- data/lib/formalist/form/result/field.rb +0 -77
- data/lib/formalist/form/result/group.rb +0 -51
- data/lib/formalist/form/result/many.rb +0 -123
- data/lib/formalist/form/result/section.rb +0 -54
- data/lib/formalist/form/validated_result.rb +0 -35
- data/lib/formalist/output_compiler.rb +0 -43
- data/lib/formalist/validation/collection_rules_compiler.rb +0 -77
- data/lib/formalist/validation/predicate_list_compiler.rb +0 -73
- data/lib/formalist/validation/value_rules_compiler.rb +0 -96
- data/spec/integration/display_adapters_spec.rb +0 -55
- data/spec/integration/validation_spec.rb +0 -86
- data/spec/unit/output_compiler_spec.rb +0 -70
@@ -0,0 +1,73 @@
|
|
1
|
+
require "formalist/element"
|
2
|
+
require "formalist/types"
|
3
|
+
|
4
|
+
module Formalist
|
5
|
+
class Elements
|
6
|
+
class Field < Element
|
7
|
+
permitted_children :none
|
8
|
+
|
9
|
+
# @api private
|
10
|
+
attr_reader :name
|
11
|
+
|
12
|
+
attribute :label, Types::String
|
13
|
+
attribute :hint, Types::String
|
14
|
+
attribute :placeholder, Types::String
|
15
|
+
attribute :inline, Types::Bool
|
16
|
+
attribute :validation, Types::Validation
|
17
|
+
|
18
|
+
# @api private
|
19
|
+
attr_reader :predicates
|
20
|
+
|
21
|
+
# @api private
|
22
|
+
def initialize(*args, attributes, children, input, errors)
|
23
|
+
super
|
24
|
+
|
25
|
+
@name = Types::ElementName.(args.first)
|
26
|
+
@input = input[@name] if input
|
27
|
+
@errors = errors[@name].to_a
|
28
|
+
end
|
29
|
+
|
30
|
+
# Converts the field into an abstract syntax tree.
|
31
|
+
#
|
32
|
+
# It takes the following format:
|
33
|
+
#
|
34
|
+
# ```
|
35
|
+
# [:field, [params]]
|
36
|
+
# ```
|
37
|
+
#
|
38
|
+
# With the following parameters:
|
39
|
+
#
|
40
|
+
# 1. Field name
|
41
|
+
# 2. Custom form element type (or `:field` otherwise)
|
42
|
+
# 3. Associated form input data
|
43
|
+
# 4. Error messages
|
44
|
+
# 5. Form element attributes
|
45
|
+
#
|
46
|
+
# @see Formalist::Element::Attributes#to_ast "Form element attributes" structure
|
47
|
+
#
|
48
|
+
# @example "email" field
|
49
|
+
# field.to_ast
|
50
|
+
# # => [:field, [
|
51
|
+
# :email,
|
52
|
+
# :field,
|
53
|
+
# "jane@doe.org",
|
54
|
+
# [],
|
55
|
+
# [:object, []],
|
56
|
+
# ]]
|
57
|
+
#
|
58
|
+
# @return [Array] the field as an abstract syntax tree.
|
59
|
+
def to_ast
|
60
|
+
# errors looks like this
|
61
|
+
# {:field_name => [["pages is missing", "another error message"], nil]}
|
62
|
+
|
63
|
+
[:field, [
|
64
|
+
name,
|
65
|
+
type,
|
66
|
+
input,
|
67
|
+
errors,
|
68
|
+
Element::Attributes.new(attributes).to_ast,
|
69
|
+
]]
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require "formalist/element"
|
2
|
+
require "formalist/types"
|
3
|
+
|
4
|
+
module Formalist
|
5
|
+
class Elements
|
6
|
+
class Group < Element
|
7
|
+
permitted_children :attr, :compound_field, :field, :many
|
8
|
+
|
9
|
+
attribute :label, Types::String
|
10
|
+
|
11
|
+
def initialize(*args, attributes, children, input, errors)
|
12
|
+
super
|
13
|
+
@children = children.map { |definition| definition.(input, errors) }
|
14
|
+
end
|
15
|
+
|
16
|
+
# Converts the group into an abstract syntax tree.
|
17
|
+
#
|
18
|
+
# It takes the following format:
|
19
|
+
#
|
20
|
+
# ```
|
21
|
+
# [:group, [params]]
|
22
|
+
# ```
|
23
|
+
#
|
24
|
+
# With the following parameters:
|
25
|
+
#
|
26
|
+
# 1. Custom form element type (or `:group` otherwise)
|
27
|
+
# 2. Form element attributes
|
28
|
+
# 3. Child form elements
|
29
|
+
#
|
30
|
+
# @see Formalist::Element::Attributes#to_ast "Form element attributes" structure
|
31
|
+
#
|
32
|
+
# @example
|
33
|
+
# group.to_ast
|
34
|
+
# # => [:group, [
|
35
|
+
# :group,
|
36
|
+
# [:object, []],
|
37
|
+
# [...child elements...]
|
38
|
+
# ]]
|
39
|
+
#
|
40
|
+
# @return [Array] the group as an abstract syntax tree.
|
41
|
+
def to_ast
|
42
|
+
[:group, [
|
43
|
+
type,
|
44
|
+
Element::Attributes.new(attributes).to_ast,
|
45
|
+
children.map(&:to_ast),
|
46
|
+
]]
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,125 @@
|
|
1
|
+
require "formalist/element"
|
2
|
+
require "formalist/types"
|
3
|
+
|
4
|
+
module Formalist
|
5
|
+
class Elements
|
6
|
+
class Many < Element
|
7
|
+
permitted_children :attr, :compound_field, :group, :field
|
8
|
+
|
9
|
+
# @api private
|
10
|
+
attr_reader :name
|
11
|
+
|
12
|
+
attribute :label, Types::String
|
13
|
+
attribute :action_label, Types::String
|
14
|
+
attribute :placeholder, Types::String
|
15
|
+
attribute :validation, Types::Validation
|
16
|
+
|
17
|
+
# @api private
|
18
|
+
attr_reader :child_template
|
19
|
+
|
20
|
+
# @api private
|
21
|
+
def initialize(*args, attributes, children, input, errors)
|
22
|
+
super
|
23
|
+
|
24
|
+
@name = Types::ElementName.(args.first)
|
25
|
+
@input = input.fetch(name, [])
|
26
|
+
@errors = errors[@name]
|
27
|
+
@child_template = build_child_template(children)
|
28
|
+
@children = build_children(children)
|
29
|
+
end
|
30
|
+
|
31
|
+
# Until we can put defaults on `Types::Bool`, supply them here
|
32
|
+
# @api private
|
33
|
+
def attributes
|
34
|
+
{
|
35
|
+
allow_create: true,
|
36
|
+
allow_update: true,
|
37
|
+
allow_destroy: true,
|
38
|
+
allow_reorder: true,
|
39
|
+
}.merge(super)
|
40
|
+
end
|
41
|
+
|
42
|
+
# Converts a collection of "many" repeating elements into an abstract
|
43
|
+
# syntax tree.
|
44
|
+
#
|
45
|
+
# It takes the following format:
|
46
|
+
#
|
47
|
+
# ```
|
48
|
+
# [:many, [params]]
|
49
|
+
# ```
|
50
|
+
#
|
51
|
+
# With the following parameters:
|
52
|
+
#
|
53
|
+
# 1. Collection name
|
54
|
+
# 2. Custom form element type (or `:many` otherwise)
|
55
|
+
# 3. Collection-level error messages
|
56
|
+
# 4. Form element attributes
|
57
|
+
# 5. Child element "template" (i.e. the form elements comprising a
|
58
|
+
# single entry in the collection of "many" elements, without any user
|
59
|
+
# data associated)
|
60
|
+
# 6. Child elements, one for each of the entries in the input data (or
|
61
|
+
# none, if there is no or empty input data)
|
62
|
+
#
|
63
|
+
# @see Formalist::Element::Attributes#to_ast "Form element attributes" structure
|
64
|
+
#
|
65
|
+
# @example "locations" collection
|
66
|
+
# many.to_ast
|
67
|
+
# # => [:many, [
|
68
|
+
# :locations,
|
69
|
+
# :many,
|
70
|
+
# ["locations size cannot be less than 3"],
|
71
|
+
# [:object, [
|
72
|
+
# [:allow_create, [:value, [true]]],
|
73
|
+
# [:allow_update, [:value, [true]]],
|
74
|
+
# [:allow_destroy, [:value, [true]]],
|
75
|
+
# [:allow_reorder, [:value, [true]]]
|
76
|
+
# ]],
|
77
|
+
# [
|
78
|
+
# [:field, [:name, :field, nil, [], [], [:object, []]]],
|
79
|
+
# [:field, [:address, :field, nil, [], [], [:object, []]]]
|
80
|
+
# ],
|
81
|
+
# [
|
82
|
+
# [
|
83
|
+
# [:field, [:name, :field, "Icelab Canberra", [], [], [:object, []]]],
|
84
|
+
# [:field, [:address, :field, "Canberra, ACT, Australia", [], [], [:object, []]]]
|
85
|
+
# ],
|
86
|
+
# [
|
87
|
+
# [:field, [:name, :field, "Icelab Melbourne", [], [], [:object, []]]],
|
88
|
+
# [:field, [:address, :field, "Melbourne, VIC, Australia", [], [], [:object, []]]]
|
89
|
+
# ]
|
90
|
+
# ]
|
91
|
+
# ]]
|
92
|
+
#
|
93
|
+
# @return [Array] the collection as an abstract syntax tree.
|
94
|
+
def to_ast
|
95
|
+
local_errors = errors.is_a?(Array) ? errors : []
|
96
|
+
|
97
|
+
[:many, [
|
98
|
+
name,
|
99
|
+
type,
|
100
|
+
local_errors,
|
101
|
+
Element::Attributes.new(attributes).to_ast,
|
102
|
+
child_template.map(&:to_ast),
|
103
|
+
children.map { |el_list| el_list.map(&:to_ast) },
|
104
|
+
]]
|
105
|
+
end
|
106
|
+
|
107
|
+
private
|
108
|
+
|
109
|
+
def build_child_template(definitions)
|
110
|
+
definitions.map { |el| el.({}, {})}
|
111
|
+
end
|
112
|
+
|
113
|
+
def build_children(definitions)
|
114
|
+
# Child errors look like this: {0=>{:summary=>["must be filled"]}
|
115
|
+
child_errors = errors.is_a?(Hash) ? errors : {}
|
116
|
+
|
117
|
+
input.each_with_index.map { |child_input, index|
|
118
|
+
errors = child_errors.fetch(index, {})
|
119
|
+
|
120
|
+
definitions.map { |el| el.(child_input, errors) }
|
121
|
+
}
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require "formalist/element"
|
2
|
+
require "formalist/types"
|
3
|
+
|
4
|
+
module Formalist
|
5
|
+
class Elements
|
6
|
+
class Section < Element
|
7
|
+
permitted_children :all
|
8
|
+
|
9
|
+
# @api private
|
10
|
+
attr_reader :name
|
11
|
+
|
12
|
+
attribute :label, Types::String
|
13
|
+
|
14
|
+
def initialize(*args, attributes, children, input, errors)
|
15
|
+
super
|
16
|
+
|
17
|
+
@name = Types::ElementName.(args.first)
|
18
|
+
@children = children.map { |definition| definition.(input, errors) }
|
19
|
+
end
|
20
|
+
|
21
|
+
# Converts the section into an abstract syntax tree.
|
22
|
+
#
|
23
|
+
# It takes the following format:
|
24
|
+
#
|
25
|
+
# ```
|
26
|
+
# [:section, [params]]
|
27
|
+
# ```
|
28
|
+
#
|
29
|
+
# With the following parameters:
|
30
|
+
#
|
31
|
+
# 1. Section name
|
32
|
+
# 2. Custom form element type (or `:section` otherwise)
|
33
|
+
# 3. Form element attributes
|
34
|
+
# 4. Child form elements
|
35
|
+
#
|
36
|
+
# @see Formalist::Element::Attributes#to_ast "Form element attributes" structure
|
37
|
+
#
|
38
|
+
# @example "content" section
|
39
|
+
# section.to_ast
|
40
|
+
# # => [:section, [
|
41
|
+
# :content,
|
42
|
+
# :section,
|
43
|
+
# [:object, []],
|
44
|
+
# [...child elements...]
|
45
|
+
# ]]
|
46
|
+
#
|
47
|
+
# @return [Array] the section as an abstract syntax tree.
|
48
|
+
def to_ast
|
49
|
+
[:section, [
|
50
|
+
name,
|
51
|
+
type,
|
52
|
+
Element::Attributes.new(attributes).to_ast,
|
53
|
+
children.map(&:to_ast),
|
54
|
+
]]
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require "formalist/element"
|
2
|
+
require "formalist/elements"
|
3
|
+
require "formalist/types"
|
4
|
+
|
5
|
+
module Formalist
|
6
|
+
class Elements
|
7
|
+
class CheckBox < Field
|
8
|
+
attribute :question_text, Types::String
|
9
|
+
|
10
|
+
def initialize(*)
|
11
|
+
super
|
12
|
+
|
13
|
+
# Ensure value is a boolean (also: default to false for nil values)
|
14
|
+
@input = !!@input
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
register :check_box, CheckBox
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require "formalist/element"
|
2
|
+
require "formalist/elements"
|
3
|
+
require "formalist/types"
|
4
|
+
|
5
|
+
module Formalist
|
6
|
+
class Elements
|
7
|
+
class MultiSelectionField < Field
|
8
|
+
attribute :options, Types::SelectionsList
|
9
|
+
attribute :selector_label, Types::String
|
10
|
+
attribute :render_option_as, Types::String
|
11
|
+
attribute :render_selection_as, Types::String
|
12
|
+
end
|
13
|
+
|
14
|
+
register :multi_selection_field, MultiSelectionField
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require "formalist/element"
|
2
|
+
require "formalist/elements"
|
3
|
+
require "formalist/types"
|
4
|
+
|
5
|
+
module Formalist
|
6
|
+
class Elements
|
7
|
+
class NumberField < Field
|
8
|
+
Number = Types::Int | Types::Float
|
9
|
+
|
10
|
+
attribute :step, Number
|
11
|
+
attribute :min, Number
|
12
|
+
attribute :max, Number
|
13
|
+
end
|
14
|
+
|
15
|
+
register :number_field, NumberField
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require "formalist/element"
|
2
|
+
require "formalist/elements"
|
3
|
+
require "formalist/types"
|
4
|
+
|
5
|
+
module Formalist
|
6
|
+
class Elements
|
7
|
+
class RadioButtons < Field
|
8
|
+
attribute :options, Types::OptionsList
|
9
|
+
end
|
10
|
+
|
11
|
+
register :radio_buttons, RadioButtons
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require "formalist/element"
|
2
|
+
require "formalist/elements"
|
3
|
+
require "formalist/types"
|
4
|
+
|
5
|
+
module Formalist
|
6
|
+
class Elements
|
7
|
+
class SelectionField < Field
|
8
|
+
attribute :options, Types::SelectionsList
|
9
|
+
attribute :selector_label, Types::String
|
10
|
+
attribute :render_option_as, Types::String
|
11
|
+
attribute :render_selection_as, Types::String
|
12
|
+
end
|
13
|
+
|
14
|
+
register :selection_field, SelectionField
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require "formalist/element"
|
2
|
+
require "formalist/elements"
|
3
|
+
require "formalist/types"
|
4
|
+
|
5
|
+
module Formalist
|
6
|
+
class Elements
|
7
|
+
class TextArea < Field
|
8
|
+
attribute :text_size, Types::String.enum("xsmall", "small", "normal", "large", "xlarge"), default: "normal"
|
9
|
+
attribute :box_size, Types::String.enum("single", "small", "normal", "large", "xlarge"), default: "normal"
|
10
|
+
attribute :code, Types::Bool
|
11
|
+
end
|
12
|
+
|
13
|
+
register :text_area, TextArea
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require "formalist/element"
|
2
|
+
require "formalist/elements"
|
3
|
+
require "formalist/types"
|
4
|
+
|
5
|
+
module Formalist
|
6
|
+
class Elements
|
7
|
+
class TextField < Field
|
8
|
+
attribute :password, Types::Bool
|
9
|
+
attribute :code, Types::Bool
|
10
|
+
end
|
11
|
+
|
12
|
+
register :text_field, TextField
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
require "formalist/elements/standard/check_box"
|
2
|
+
require "formalist/elements/standard/date_field"
|
3
|
+
require "formalist/elements/standard/date_time_field"
|
4
|
+
require "formalist/elements/standard/hidden_field"
|
5
|
+
require "formalist/elements/standard/multi_selection_field"
|
6
|
+
require "formalist/elements/standard/number_field"
|
7
|
+
require "formalist/elements/standard/radio_buttons"
|
8
|
+
require "formalist/elements/standard/select_box"
|
9
|
+
require "formalist/elements/standard/selection_field"
|
10
|
+
require "formalist/elements/standard/text_area"
|
11
|
+
require "formalist/elements/standard/text_field"
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require "dry-container"
|
2
|
+
require "formalist/elements/attr"
|
3
|
+
require "formalist/elements/compound_field"
|
4
|
+
require "formalist/elements/field"
|
5
|
+
require "formalist/elements/group"
|
6
|
+
require "formalist/elements/many"
|
7
|
+
require "formalist/elements/section"
|
8
|
+
|
9
|
+
module Formalist
|
10
|
+
class Elements
|
11
|
+
extend Dry::Container::Mixin
|
12
|
+
|
13
|
+
register :attr, Attr
|
14
|
+
register :compound_field, CompoundField
|
15
|
+
register :field, Field
|
16
|
+
register :group, Group
|
17
|
+
register :many, Many
|
18
|
+
register :section, Section
|
19
|
+
end
|
20
|
+
end
|
@@ -1,14 +1,68 @@
|
|
1
|
+
require "formalist/element/definition"
|
2
|
+
|
1
3
|
module Formalist
|
2
4
|
class Form
|
3
|
-
# @api private
|
4
5
|
class DefinitionContext
|
5
|
-
|
6
|
+
DuplicateDefinitionError = Class.new(StandardError)
|
6
7
|
|
7
8
|
attr_reader :elements
|
9
|
+
attr_reader :container
|
10
|
+
attr_reader :permissions
|
8
11
|
|
9
|
-
def initialize(
|
12
|
+
def initialize(options = {})
|
10
13
|
@elements = []
|
11
|
-
|
14
|
+
@container = options.fetch(:container)
|
15
|
+
@permissions = options.fetch(:permissions)
|
16
|
+
end
|
17
|
+
|
18
|
+
def with(options = {})
|
19
|
+
%i[container permissions].each do |attr|
|
20
|
+
options[attr] ||= send(attr)
|
21
|
+
end
|
22
|
+
|
23
|
+
self.class.new(options)
|
24
|
+
end
|
25
|
+
|
26
|
+
def call(&block)
|
27
|
+
instance_eval(&block) if block
|
28
|
+
self
|
29
|
+
end
|
30
|
+
|
31
|
+
def dep(name)
|
32
|
+
Element::Definition::Deferred.new(name)
|
33
|
+
end
|
34
|
+
|
35
|
+
def method_missing(name, *args, &block)
|
36
|
+
return add_element(name, *args, &block) if element_type_exists?(name)
|
37
|
+
super
|
38
|
+
end
|
39
|
+
|
40
|
+
def respond_to_missing?(name)
|
41
|
+
element_type_exists?(name)
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def element_type_exists?(type)
|
47
|
+
container.key?(type)
|
48
|
+
end
|
49
|
+
|
50
|
+
def add_element(element_type, *args, &block)
|
51
|
+
type = container[element_type]
|
52
|
+
raise ArgumentError, "element +#{element_type}+ is not permitted in this context" unless permissions.permitted?(type)
|
53
|
+
|
54
|
+
# Work with top-level args and a trailing attributes hash
|
55
|
+
args = args.dup
|
56
|
+
attributes = args.last.is_a?(Hash) ? args.pop : {}
|
57
|
+
|
58
|
+
children = with(permissions: type.permitted_children).call(&block).elements
|
59
|
+
definition = Element::Definition.new(type, *args, attributes, children)
|
60
|
+
|
61
|
+
if elements.any? { |el| el == definition }
|
62
|
+
raise DuplicateDefinitionError, "element +#{element_type} #{args.map(&:inspect).join(', ')}+ is already defined in this context"
|
63
|
+
end
|
64
|
+
|
65
|
+
elements << definition
|
12
66
|
end
|
13
67
|
end
|
14
68
|
end
|
@@ -1,5 +1,3 @@
|
|
1
|
-
require "formalist/form/validated_result"
|
2
|
-
|
3
1
|
module Formalist
|
4
2
|
class Form
|
5
3
|
class Result
|
@@ -7,39 +5,19 @@ module Formalist
|
|
7
5
|
attr_reader :input
|
8
6
|
|
9
7
|
# @api private
|
10
|
-
attr_reader :
|
8
|
+
attr_reader :messages
|
11
9
|
|
12
10
|
# @api private
|
13
11
|
attr_reader :elements
|
14
12
|
|
15
|
-
|
16
|
-
attr_reader :validation
|
17
|
-
|
18
|
-
def initialize(schema, elements, input)
|
13
|
+
def initialize(input, messages, elements)
|
19
14
|
@input = input
|
20
|
-
@
|
21
|
-
@elements = elements
|
22
|
-
@validation = schema.(input)
|
23
|
-
end
|
24
|
-
|
25
|
-
def output
|
26
|
-
validation.output
|
27
|
-
end
|
28
|
-
|
29
|
-
def success?
|
30
|
-
true
|
31
|
-
end
|
32
|
-
|
33
|
-
def messages
|
34
|
-
{}
|
15
|
+
@messages = messages
|
16
|
+
@elements = elements.map { |el| el.(input, messages) }
|
35
17
|
end
|
36
18
|
|
37
19
|
def to_ast
|
38
|
-
elements.map
|
39
|
-
end
|
40
|
-
|
41
|
-
def validate
|
42
|
-
ValidatedResult.new(self)
|
20
|
+
elements.map(&:to_ast)
|
43
21
|
end
|
44
22
|
end
|
45
23
|
end
|