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.
Files changed (69) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +7 -3
  3. data/Gemfile.lock +36 -38
  4. data/README.md +8 -4
  5. data/Rakefile +0 -7
  6. data/lib/formalist/element/attributes.rb +54 -0
  7. data/lib/formalist/element/class_interface.rb +133 -0
  8. data/lib/formalist/element/definition.rb +55 -0
  9. data/lib/formalist/element/permitted_children.rb +46 -0
  10. data/lib/formalist/element.rb +51 -0
  11. data/lib/formalist/elements/attr.rb +74 -0
  12. data/lib/formalist/elements/compound_field.rb +49 -0
  13. data/lib/formalist/elements/field.rb +73 -0
  14. data/lib/formalist/elements/group.rb +50 -0
  15. data/lib/formalist/elements/many.rb +125 -0
  16. data/lib/formalist/elements/section.rb +58 -0
  17. data/lib/formalist/elements/standard/check_box.rb +20 -0
  18. data/lib/formalist/elements/standard/date_field.rb +12 -0
  19. data/lib/formalist/elements/standard/date_time_field.rb +12 -0
  20. data/lib/formalist/elements/standard/hidden_field.rb +11 -0
  21. data/lib/formalist/elements/standard/multi_selection_field.rb +16 -0
  22. data/lib/formalist/elements/standard/number_field.rb +17 -0
  23. data/lib/formalist/elements/standard/radio_buttons.rb +13 -0
  24. data/lib/formalist/elements/standard/select_box.rb +13 -0
  25. data/lib/formalist/elements/standard/selection_field.rb +16 -0
  26. data/lib/formalist/elements/standard/text_area.rb +15 -0
  27. data/lib/formalist/elements/standard/text_field.rb +14 -0
  28. data/lib/formalist/elements/standard.rb +11 -0
  29. data/lib/formalist/elements.rb +20 -0
  30. data/lib/formalist/form/definition_context.rb +58 -4
  31. data/lib/formalist/form/result.rb +5 -27
  32. data/lib/formalist/form.rb +15 -35
  33. data/lib/formalist/types.rb +30 -0
  34. data/lib/formalist/version.rb +1 -1
  35. data/lib/formalist.rb +0 -20
  36. data/spec/examples.txt +8 -7
  37. data/spec/integration/dependency_injection_spec.rb +54 -0
  38. data/spec/integration/form_spec.rb +86 -13
  39. data/spec/spec_helper.rb +12 -5
  40. data/spec/support/constants.rb +11 -0
  41. data/spec/unit/elements/standard/check_box_spec.rb +33 -0
  42. metadata +36 -63
  43. data/lib/formalist/definition_compiler.rb +0 -61
  44. data/lib/formalist/display_adapters/default.rb +0 -9
  45. data/lib/formalist/display_adapters/radio.rb +0 -19
  46. data/lib/formalist/display_adapters/select.rb +0 -19
  47. data/lib/formalist/display_adapters/textarea.rb +0 -14
  48. data/lib/formalist/display_adapters.rb +0 -16
  49. data/lib/formalist/form/definition/attr.rb +0 -20
  50. data/lib/formalist/form/definition/component.rb +0 -31
  51. data/lib/formalist/form/definition/field.rb +0 -29
  52. data/lib/formalist/form/definition/group.rb +0 -31
  53. data/lib/formalist/form/definition/many.rb +0 -41
  54. data/lib/formalist/form/definition/section.rb +0 -23
  55. data/lib/formalist/form/definition.rb +0 -37
  56. data/lib/formalist/form/result/attr.rb +0 -82
  57. data/lib/formalist/form/result/component.rb +0 -51
  58. data/lib/formalist/form/result/field.rb +0 -77
  59. data/lib/formalist/form/result/group.rb +0 -51
  60. data/lib/formalist/form/result/many.rb +0 -123
  61. data/lib/formalist/form/result/section.rb +0 -54
  62. data/lib/formalist/form/validated_result.rb +0 -35
  63. data/lib/formalist/output_compiler.rb +0 -43
  64. data/lib/formalist/validation/collection_rules_compiler.rb +0 -77
  65. data/lib/formalist/validation/predicate_list_compiler.rb +0 -73
  66. data/lib/formalist/validation/value_rules_compiler.rb +0 -96
  67. data/spec/integration/display_adapters_spec.rb +0 -55
  68. data/spec/integration/validation_spec.rb +0 -86
  69. data/spec/unit/output_compiler_spec.rb +0 -70
@@ -1,16 +0,0 @@
1
- require "dry-container"
2
- require "formalist/display_adapters/default"
3
- require "formalist/display_adapters/radio"
4
- require "formalist/display_adapters/select"
5
- require "formalist/display_adapters/textarea"
6
-
7
- module Formalist
8
- class DisplayAdapters
9
- extend Dry::Container::Mixin
10
-
11
- register DEFAULT_DISPLAY_ADAPTER, Default.new
12
- register "radio", Radio.new
13
- register "select", Select.new
14
- register "textarea", Textarea.new
15
- end
16
- end
@@ -1,20 +0,0 @@
1
- require "formalist/form/result/attr"
2
-
3
- module Formalist
4
- class Form
5
- module Definition
6
- class Attr
7
- attr_reader :name, :children
8
-
9
- def initialize(name, children)
10
- @name = name
11
- @children = children
12
- end
13
-
14
- def call(input, rules, errors)
15
- Result::Attr.new(self, input, rules, errors)
16
- end
17
- end
18
- end
19
- end
20
- end
@@ -1,31 +0,0 @@
1
- require "formalist/form/result/component"
2
-
3
- module Formalist
4
- class Form
5
- module Definition
6
- class Component
7
- ALLOWED_CHILDREN = %w[field].freeze
8
-
9
- attr_reader :config
10
- attr_reader :children
11
-
12
- def initialize(config = {}, children = [])
13
- unless children.all? { |c| ALLOWED_CHILDREN.include?(Inflecto.underscore(c.class.name).split("/").last) }
14
- raise ArgumentError, "children must be +#{ALLOWED_CHILDREN.join(', ')}+"
15
- end
16
-
17
- @config = config
18
- @children = children
19
- end
20
-
21
- def with(new_config = {})
22
- self.class.new(config.merge(new_config), children)
23
- end
24
-
25
- def call(input, rules, errors)
26
- Result::Component.new(self, input, rules, errors)
27
- end
28
- end
29
- end
30
- end
31
- end
@@ -1,29 +0,0 @@
1
- require "formalist/form/result/field"
2
-
3
- module Formalist
4
- class Form
5
- module Definition
6
- class Field
7
- attr_reader :name
8
- attr_reader :type
9
- attr_reader :display_variant
10
- attr_reader :config
11
-
12
- def initialize(name, type, display_variant, config)
13
- @name = name
14
- @type = type
15
- @display_variant = display_variant
16
- @config = config
17
- end
18
-
19
- def to_display_variant(display_variant, new_config = {})
20
- self.class.new(name, type, display_variant, config.merge(new_config))
21
- end
22
-
23
- def call(input, rules, errors)
24
- Result::Field.new(self, input, rules, errors)
25
- end
26
- end
27
- end
28
- end
29
- end
@@ -1,31 +0,0 @@
1
- require "formalist/form/result/group"
2
-
3
- module Formalist
4
- class Form
5
- module Definition
6
- class Group
7
- ALLOWED_CHILDREN = %w[
8
- attr
9
- component
10
- field
11
- many
12
- ].freeze
13
-
14
- attr_reader :config, :children
15
-
16
- def initialize(config = {}, children = [])
17
- unless children.all? { |c| ALLOWED_CHILDREN.include?(Inflecto.underscore(c.class.name).split("/").last) }
18
- raise ArgumentError, "children must be +#{ALLOWED_CHILDREN.join(', ')}+"
19
- end
20
-
21
- @config = config
22
- @children = children
23
- end
24
-
25
- def call(input, rules, errors)
26
- Result::Group.new(self, input, rules, errors)
27
- end
28
- end
29
- end
30
- end
31
- end
@@ -1,41 +0,0 @@
1
- require "formalist/form/result/many"
2
-
3
- module Formalist
4
- class Form
5
- module Definition
6
- class Many
7
- ALLOWED_CHILDREN = %w[
8
- attr
9
- component
10
- group
11
- field
12
- ].freeze
13
-
14
- DEFAULT_CONFIG = {
15
- allow_create: true,
16
- allow_update: true,
17
- allow_destroy: true,
18
- allow_reorder: true
19
- }.freeze
20
-
21
- attr_reader :name
22
- attr_reader :config
23
- attr_reader :children
24
-
25
- def initialize(name, config = {}, children = [])
26
- unless children.all? { |c| ALLOWED_CHILDREN.include?(Inflecto.underscore(c.class.name).split("/").last) }
27
- raise ArgumentError, "children must be +#{ALLOWED_CHILDREN.join(', ')}+"
28
- end
29
-
30
- @name = name
31
- @config = DEFAULT_CONFIG.merge(config)
32
- @children = children
33
- end
34
-
35
- def call(input, rules, errors)
36
- Result::Many.new(self, input, rules, errors)
37
- end
38
- end
39
- end
40
- end
41
- end
@@ -1,23 +0,0 @@
1
- require "formalist/form/result/section"
2
-
3
- module Formalist
4
- class Form
5
- module Definition
6
- class Section
7
- attr_reader :name
8
- attr_reader :config
9
- attr_reader :children
10
-
11
- def initialize(name, config = {}, children = [])
12
- @name = name
13
- @config = config
14
- @children = children
15
- end
16
-
17
- def call(input, rules, errors)
18
- Result::Section.new(self, input, rules, errors)
19
- end
20
- end
21
- end
22
- end
23
- end
@@ -1,37 +0,0 @@
1
- require "formalist/form/definition_context"
2
-
3
- module Formalist
4
- class Form
5
- module Definition
6
- def attr(name, &block)
7
- elements << [:attr, [name, define_children(&block)]]
8
- end
9
-
10
- def component(display: DEFAULT_DISPLAY_ADAPTER, **config, &block)
11
- elements << [:component, [display, config, define_children(&block)]]
12
- end
13
-
14
- def field(name, type:, display: DEFAULT_DISPLAY_ADAPTER, **config)
15
- elements << [:field, [name, type, display, config]]
16
- end
17
-
18
- def group(**config, &block)
19
- elements << [:group, [config, define_children(&block)]]
20
- end
21
-
22
- def many(name, **config, &block)
23
- elements << [:many, [name, config, define_children(&block)]]
24
- end
25
-
26
- def section(name, **config, &block)
27
- elements << [:section, [name, config, define_children(&block)]]
28
- end
29
-
30
- private
31
-
32
- def define_children(&block)
33
- block ? DefinitionContext.new(&block).elements : []
34
- end
35
- end
36
- end
37
- end
@@ -1,82 +0,0 @@
1
- require "formalist/validation/collection_rules_compiler"
2
- require "formalist/validation/value_rules_compiler"
3
- require "formalist/validation/predicate_list_compiler"
4
-
5
- module Formalist
6
- class Form
7
- class Result
8
- class Attr
9
- attr_reader :definition, :input, :value_rules, :value_predicates, :collection_rules, :errors
10
- attr_reader :children
11
-
12
- def initialize(definition, input, rules, errors)
13
- value_rules_compiler = Validation::ValueRulesCompiler.new(definition.name)
14
- value_predicates_compiler = Validation::PredicateListCompiler.new
15
- collection_rules_compiler = Validation::CollectionRulesCompiler.new(definition.name)
16
-
17
- @definition = definition
18
- @input = input.fetch(definition.name, {})
19
- @value_rules = value_rules_compiler.(rules)
20
- @value_predicates = value_predicates_compiler.(@value_rules)
21
- @collection_rules = collection_rules_compiler.(rules)
22
- @errors = errors.fetch(definition.name, [])[0] || []
23
- @children = build_children
24
- end
25
-
26
- # Converts the attribute into an array format for including in a
27
- # form's abstract syntax tree.
28
- #
29
- # The array takes the following format:
30
- #
31
- # ```
32
- # [:attr, [params]]
33
- # ```
34
- #
35
- # With the following parameters:
36
- #
37
- # 1. Attribute name
38
- # 1. Validation rules (if any)
39
- # 1. Validation error messages (if any)
40
- # 1. Child form elements
41
- #
42
- # @example "metadata" attr
43
- # attr.to_ast # =>
44
- # # [:attr, [
45
- # # :metadata,
46
- # # [
47
- # # [:predicate, [:hash?, []]],
48
- # # ],
49
- # # ["metadata is missing"],
50
- # # [
51
- # # ...child elements...
52
- # # ]
53
- # # ]]
54
- #
55
- # @return [Array] the attribute as an array.
56
- def to_ast
57
- # Errors, if the attr hash is present and its members have errors:
58
- # {:meta=>[[{:pages=>[["pages is missing"], nil]}], {}]}
59
-
60
- # Errors, if the attr hash hasn't been provided
61
- # {:meta=>[["meta is missing"], nil]}
62
-
63
- local_errors = errors[0].is_a?(Hash) ? [] : errors
64
-
65
- [:attr, [
66
- definition.name,
67
- value_predicates,
68
- local_errors,
69
- children.map(&:to_ast),
70
- ]]
71
- end
72
-
73
- private
74
-
75
- def build_children
76
- child_errors = errors[0].is_a?(Hash) ? errors[0] : {}
77
- definition.children.map { |el| el.(input, collection_rules, child_errors) }
78
- end
79
- end
80
- end
81
- end
82
- end
@@ -1,51 +0,0 @@
1
- module Formalist
2
- class Form
3
- class Result
4
- class Component
5
- attr_reader :definition, :input, :rules, :errors
6
- attr_reader :children
7
-
8
- def initialize(definition, input, rules, errors)
9
- @definition = definition
10
- @input = input
11
- @rules = rules
12
- @errors = errors
13
- @children = definition.children.map { |el| el.(input, rules, errors) }
14
- end
15
-
16
- # Converts the component into an array format for including in a
17
- # form's abstract syntax tree.
18
- #
19
- # The array takes the following format:
20
- #
21
- # ```
22
- # [:component, [params]]
23
- # ```
24
- #
25
- # With the following parameters:
26
- #
27
- # 1. Component configuration
28
- # 1. Child form elements
29
- #
30
- # @example
31
- # component.to_ast # =>
32
- # # [:component, [
33
- # # [
34
- # # [:some_config_name, :some_config_value]
35
- # # ],
36
- # # [
37
- # # ...child elements...
38
- # # ]
39
- # # ]]
40
- #
41
- # @return [Array] the component as an array.
42
- def to_ast
43
- [:component, [
44
- definition.config.to_a,
45
- children.map(&:to_ast),
46
- ]]
47
- end
48
- end
49
- end
50
- end
51
- end
@@ -1,77 +0,0 @@
1
- require "formalist/validation/value_rules_compiler"
2
- require "formalist/validation/predicate_list_compiler"
3
-
4
- module Formalist
5
- class Form
6
- class Result
7
- class Field
8
- attr_reader :definition, :input, :rules, :predicates, :errors
9
-
10
- def initialize(definition, input, rules, errors)
11
- rules_compiler = Validation::ValueRulesCompiler.new(definition.name)
12
- predicates_compiler = Validation::PredicateListCompiler.new
13
-
14
- @definition = definition
15
- @input = input[definition.name]
16
- @rules = rules_compiler.(rules)
17
- @predicates = predicates_compiler.(@rules)
18
- @errors = errors[definition.name].to_a[0] || []
19
- end
20
-
21
- # Converts the field into an array format for including in a form's
22
- # abstract syntax tree.
23
- #
24
- # The array takes the following format:
25
- #
26
- # ```
27
- # [:field, [params]]
28
- # ```
29
- #
30
- # With the following parameters:
31
- #
32
- # 1. Field name
33
- # 1. Field type
34
- # 1. Display variant name
35
- # 1. Input data
36
- # 1. Validation rules (if any)
37
- # 1. Validation error messages (if any)
38
- # 1. Field configuration
39
- #
40
- # @example "email" field
41
- # field.to_ast # =>
42
- # # [:field, [
43
- # # :email,
44
- # # "string",
45
- # # "default",
46
- # # "invalid email value",
47
- # # [
48
- # # [:and, [
49
- # # [:predicate, [:filled?, []]],
50
- # # [:predicate, [:format?, [/\s+@\s+\.\s+/]]]
51
- # # ]]
52
- # # ],
53
- # # ["email is in invalid format"],
54
- # # [
55
- # # [:some_config_name, :some_config_value]
56
- # # ]
57
- # # ]]
58
- #
59
- # @return [Array] the field as an array.
60
- def to_ast
61
- # errors looks like this
62
- # {:field_name => [["pages is missing", "another error message"], nil]}
63
-
64
- [:field, [
65
- definition.name,
66
- definition.type,
67
- definition.display_variant,
68
- input,
69
- predicates,
70
- errors,
71
- definition.config.to_a,
72
- ]]
73
- end
74
- end
75
- end
76
- end
77
- end
@@ -1,51 +0,0 @@
1
- module Formalist
2
- class Form
3
- class Result
4
- class Group
5
- attr_reader :definition, :input, :errors
6
- attr_reader :children
7
-
8
- def initialize(definition, input, rules, errors)
9
- @definition = definition
10
- @input = input
11
- @rules = rules
12
- @errors = errors
13
- @children = definition.children.map { |el| el.(input, rules, errors) }
14
- end
15
-
16
- # Converts the group into an array format for including in a form's
17
- # abstract syntax tree.
18
- #
19
- # The array takes the following format:
20
- #
21
- # ```
22
- # [:group, [params]]
23
- # ```
24
- #
25
- # With the following parameters:
26
- #
27
- # 1. Group configuration
28
- # 1. Child form elements
29
- #
30
- # @example
31
- # group.to_ast # =>
32
- # # [:group, [
33
- # # [
34
- # # [:some_config_name, :some_config_value]
35
- # # ],
36
- # # [
37
- # # ...child elements...
38
- # # ]
39
- # # ]]
40
- #
41
- # @return [Array] the group as an array.
42
- def to_ast
43
- [:group, [
44
- definition.config.to_a,
45
- children.map(&:to_ast),
46
- ]]
47
- end
48
- end
49
- end
50
- end
51
- end
@@ -1,123 +0,0 @@
1
- require "formalist/validation/collection_rules_compiler"
2
- require "formalist/validation/value_rules_compiler"
3
- require "formalist/validation/predicate_list_compiler"
4
-
5
- module Formalist
6
- class Form
7
- class Result
8
- class Many
9
- attr_reader :definition, :input, :value_rules, :value_predicates, :collection_rules, :errors
10
- attr_reader :child_template, :children
11
-
12
- def initialize(definition, input, rules, errors)
13
- value_rules_compiler = Validation::ValueRulesCompiler.new(definition.name)
14
- value_predicates_compiler = Validation::PredicateListCompiler.new
15
- collection_rules_compiler = Validation::CollectionRulesCompiler.new(definition.name)
16
-
17
- @definition = definition
18
- @input = input.fetch(definition.name, [])
19
- @value_rules = value_rules_compiler.(rules)
20
- @value_predicates = value_predicates_compiler.(@value_rules)
21
- @collection_rules = collection_rules_compiler.(rules)
22
- @errors = errors.fetch(definition.name, [])[0] || []
23
- @child_template = build_child_template
24
- @children = build_children
25
- end
26
-
27
- # Converts a collection of "many" repeating elements into an array
28
- # format for including in a form's abstract syntax tree.
29
- #
30
- # The array takes the following format:
31
- #
32
- # ```
33
- # [:many, [params]]
34
- # ```
35
- #
36
- # With the following parameters:
37
- #
38
- # 1. Collection array name
39
- # 1. Collection validation rules (if any)
40
- # 1. Collection error messages (if any)
41
- # 1. Collection configuration
42
- # 1. Child element "template" (i.e. the form elements comprising a
43
- # single entry in the collection of "many" elements, without any
44
- # user data associated)
45
- # 1. Child elements, one for each of the entries in the input data (or
46
- # none, if there is no or empty input data)
47
- #
48
- # @example "locations" collection
49
- # many.to_ast # =>
50
- # # [:many, [
51
- # # :locations,
52
- # # [[:predicate, [:min_size?, [3]]]],
53
- # # ["locations size cannot be less than 3"],
54
- # # [
55
- # # [:allow_create, true],
56
- # # [:allow_update, true],
57
- # # [:allow_destroy, true],
58
- # # [:allow_reorder, true]
59
- # # ],
60
- # # [
61
- # # [:field, [:name, "string", "default", nil, [], [], []]],
62
- # # [:field, [:address, "string", "default", nil, [], [], []]]
63
- # # [
64
- # # [
65
- # # [:field, [:name, "string", "default", "Icelab Canberra", [], [], []]],
66
- # # [:field, [:address, "string", "default", "Canberra, ACT, Australia", [], [], []]]
67
- # # ],
68
- # # [
69
- # # [:field, [:name, "string", "default", "Icelab Melbourne", [], [], []]],
70
- # # [:field, [:address, "string", "default", "Melbourne, VIC, Australia", [], [], []]]
71
- # # ]
72
- # # ]
73
- # # ]]
74
- #
75
- # @return [Array] the collection as an array.
76
- def to_ast
77
- local_errors = errors.select { |e| e.is_a?(String) }
78
-
79
- [:many, [
80
- definition.name,
81
- value_predicates,
82
- local_errors,
83
- definition.config.to_a,
84
- child_template.map(&:to_ast),
85
- children.map { |el_list| el_list.map(&:to_ast) },
86
- ]]
87
- end
88
-
89
- private
90
-
91
- def build_child_template
92
- template_input = {}
93
- template_errors = {}
94
-
95
- definition.children.map { |el| el.(template_input, collection_rules, template_errors)}
96
- end
97
-
98
- def build_children
99
- # child errors looks like this:
100
- # [
101
- # {:rating=>[["rating must be greater than or equal to 1"], 0]},
102
- # {:summary=>"Great", :rating=>0},
103
- # {:summary=>[["summary must be filled"], ""]},
104
- # {:summary=>"", :rating=>1}
105
- # ]
106
- #
107
- # or local errors:
108
- # {:links=>[["links is missing"], nil]}
109
-
110
- child_errors = errors.each_slice(2).to_a
111
-
112
- input.map { |child_input|
113
- local_child_errors = child_errors.select { |e|
114
- e[1] == child_input
115
- }.to_a.dig(0, 0) || {}
116
-
117
- definition.children.map { |el| el.(child_input, collection_rules, local_child_errors) }
118
- }
119
- end
120
- end
121
- end
122
- end
123
- end
@@ -1,54 +0,0 @@
1
- module Formalist
2
- class Form
3
- class Result
4
- class Section
5
- attr_reader :definition, :input, :rules, :errors
6
- attr_reader :children
7
-
8
- def initialize(definition, input, rules, errors)
9
- @definition = definition
10
- @input = input
11
- @rules = rules
12
- @errors = errors
13
- @children = definition.children.map { |el| el.(input, rules, errors) }
14
- end
15
-
16
- # Converts the section into an array format for including in a form's
17
- # abstract syntax tree.
18
- #
19
- # The array takes the following format:
20
- #
21
- # ```
22
- # [:section, [params]]
23
- # ```
24
- #
25
- # With the following parameters:
26
- #
27
- # 1. Section name
28
- # 1. Section configuration
29
- # 1. Child form elements
30
- #
31
- # @example "content" section
32
- # section.to_ast # =>
33
- # # [:section, [
34
- # # :content,
35
- # # [
36
- # # [:some_config_name, :some_config_value]
37
- # # ],
38
- # # [
39
- # # ...child elements...
40
- # # ]
41
- # # ]]
42
- #
43
- # @return [Array] the section as an array.
44
- def to_ast
45
- [:section, [
46
- definition.name,
47
- definition.config.to_a,
48
- children.map(&:to_ast),
49
- ]]
50
- end
51
- end
52
- end
53
- end
54
- end