formalist 0.2.2 → 0.2.3
Sign up to get free protection for your applications and to get access to all the features.
- 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
|