formalist 0.2.2 → 0.2.3

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