formalist 0.3.0 → 0.4.0

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 (49) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +7 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +21 -0
  5. data/.yardopts +1 -0
  6. data/CHANGELOG.md +62 -0
  7. data/Gemfile +1 -2
  8. data/bin/console +13 -0
  9. data/formalist.gemspec +33 -0
  10. data/lib/formalist/definition.rb +65 -0
  11. data/lib/formalist/element/class_interface.rb +7 -59
  12. data/lib/formalist/element.rb +37 -19
  13. data/lib/formalist/elements/attr.rb +8 -20
  14. data/lib/formalist/elements/compound_field.rb +5 -4
  15. data/lib/formalist/elements/field.rb +5 -12
  16. data/lib/formalist/elements/group.rb +6 -5
  17. data/lib/formalist/elements/many.rb +28 -29
  18. data/lib/formalist/elements/section.rb +6 -10
  19. data/lib/formalist/elements/standard/multi_upload_field.rb +8 -0
  20. data/lib/formalist/elements/standard/rich_text_area.rb +40 -0
  21. data/lib/formalist/elements/standard/search_multi_selection_field.rb +20 -0
  22. data/lib/formalist/elements/standard/search_selection_field.rb +20 -0
  23. data/lib/formalist/elements/standard/tags_field.rb +16 -0
  24. data/lib/formalist/elements/standard/upload_field.rb +8 -0
  25. data/lib/formalist/elements/standard.rb +4 -0
  26. data/lib/formalist/form/validity_check.rb +54 -0
  27. data/lib/formalist/form.rb +49 -17
  28. data/lib/formalist/rich_text/embedded_form_compiler.rb +86 -0
  29. data/lib/formalist/rich_text/embedded_forms_container/mixin.rb +42 -0
  30. data/lib/formalist/rich_text/embedded_forms_container/registration.rb +30 -0
  31. data/lib/formalist/rich_text/embedded_forms_container.rb +9 -0
  32. data/lib/formalist/rich_text/rendering/embedded_form_renderer.rb +25 -0
  33. data/lib/formalist/rich_text/rendering/html_compiler.rb +100 -0
  34. data/lib/formalist/rich_text/rendering/html_renderer.rb +186 -0
  35. data/lib/formalist/rich_text/validity_check.rb +48 -0
  36. data/lib/formalist/types.rb +8 -7
  37. data/lib/formalist/version.rb +1 -1
  38. metadata +54 -31
  39. data/Gemfile.lock +0 -105
  40. data/lib/formalist/element/definition.rb +0 -55
  41. data/lib/formalist/element/permitted_children.rb +0 -46
  42. data/lib/formalist/form/definition_context.rb +0 -69
  43. data/lib/formalist/form/result.rb +0 -24
  44. data/spec/examples.txt +0 -8
  45. data/spec/integration/dependency_injection_spec.rb +0 -54
  46. data/spec/integration/form_spec.rb +0 -104
  47. data/spec/spec_helper.rb +0 -109
  48. data/spec/support/constants.rb +0 -11
  49. data/spec/unit/elements/standard/check_box_spec.rb +0 -33
@@ -1,69 +0,0 @@
1
- require "formalist/element/definition"
2
-
3
- module Formalist
4
- class Form
5
- class DefinitionContext
6
- DuplicateDefinitionError = Class.new(StandardError)
7
-
8
- attr_reader :elements
9
- attr_reader :container
10
- attr_reader :permissions
11
-
12
- def initialize(options = {})
13
- @elements = []
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
66
- end
67
- end
68
- end
69
- end
@@ -1,24 +0,0 @@
1
- module Formalist
2
- class Form
3
- class Result
4
- # @api private
5
- attr_reader :input
6
-
7
- # @api private
8
- attr_reader :messages
9
-
10
- # @api private
11
- attr_reader :elements
12
-
13
- def initialize(input, messages, elements)
14
- @input = input
15
- @messages = messages
16
- @elements = elements.map { |el| el.(input, messages) }
17
- end
18
-
19
- def to_ast
20
- elements.map(&:to_ast)
21
- end
22
- end
23
- end
24
- end
data/spec/examples.txt DELETED
@@ -1,8 +0,0 @@
1
- example_id | status | run_time |
2
- -------------------------------------------------------- | ------ | --------------- |
3
- ./spec/integration/dependency_injection_spec.rb[1:1] | passed | 0.00073 seconds |
4
- ./spec/integration/form_spec.rb[1:1] | passed | 0.0141 seconds |
5
- ./spec/unit/elements/standard/check_box_spec.rb[1:1:1:1] | passed | 0.00029 seconds |
6
- ./spec/unit/elements/standard/check_box_spec.rb[1:1:2:1] | passed | 0.00044 seconds |
7
- ./spec/unit/elements/standard/check_box_spec.rb[1:1:3:1] | passed | 0.00254 seconds |
8
- ./spec/unit/elements/standard/check_box_spec.rb[1:1:4:1] | passed | 0.00028 seconds |
@@ -1,54 +0,0 @@
1
- require "dry-auto_inject"
2
- require "formalist/elements/standard"
3
-
4
- RSpec.describe "Dependency injection" do
5
- let(:schema) {
6
- Dry::Validation.Schema do
7
- key(:status).required
8
- end
9
- }
10
-
11
- subject(:form) {
12
- Class.new(Formalist::Form) do
13
- include Test::HashImport["fetch_options"]
14
-
15
- define do
16
- select_box :status, options: dep(:status_options)
17
- end
18
-
19
- def status_options
20
- fetch_options.map { |option| [option, option.capitalize] }
21
- end
22
- end.new
23
- }
24
-
25
- before do
26
- Test::Container = Class.new do
27
- extend Dry::Container::Mixin
28
- end
29
-
30
- Test::Container.register :fetch_options, -> { %w[draft published] }
31
-
32
- auto_inject = Dry::AutoInject(Test::Container)
33
- Test::HashImport = -> *keys do
34
- auto_inject.hash[*keys]
35
- end
36
- end
37
-
38
- it "supports dependency injection via the initializer's options hash" do
39
- expect(form.build.to_ast).to eql [
40
- [:field, [
41
- :status,
42
- :select_box,
43
- nil,
44
- [],
45
- [:object, [
46
- [:options, [:array, [
47
- [:array, [[:value, ["draft"]], [:value, ["Draft"]]]],
48
- [:array, [[:value, ["published"]], [:value, ["Published"]]]]
49
- ]]]
50
- ]]
51
- ]]
52
- ]
53
- end
54
- end
@@ -1,104 +0,0 @@
1
- RSpec.describe Formalist::Form do
2
- let(:schema) {
3
- Dry::Validation.Schema do
4
- key(:title).required
5
- key(:rating).required(:int?)
6
-
7
- key(:reviews).each do
8
- key(:summary).required
9
- key(:rating).required(:int?, gteq?: 1, lteq?: 10)
10
- end
11
-
12
- key(:meta).schema do
13
- key(:pages).required(:int?, gteq?: 1)
14
- end
15
- end
16
- }
17
-
18
- subject(:form) {
19
- Class.new(Formalist::Form) do
20
- define do
21
- compound_field do
22
- field :title, validate: {filled: true}
23
- field :rating, validate: {filled: true}
24
- end
25
-
26
- many :reviews do
27
- field :summary, validate: {filled: true}
28
- field :rating, validate: {filled: true}
29
- end
30
-
31
- attr :meta do
32
- field :pages, validate: {filled: true}
33
- end
34
- end
35
- end.new
36
- }
37
-
38
- it "outputs an AST" do
39
- input = {
40
- title: "Aurora",
41
- rating: "10",
42
- reviews: [
43
- {
44
- summary: "",
45
- rating: 10
46
- },
47
- {
48
- summary: "Great!",
49
- rating: 0
50
- }
51
- ],
52
- meta: {
53
- pages: 0
54
- }
55
- }
56
-
57
- result = schema.(input)
58
-
59
- expect(form.build(result.output, result.messages).to_ast).to eq [
60
- [:compound_field, [
61
- :compound_field,
62
- [:object, []],
63
- [
64
- [:field, [:title, :field, "Aurora", [], [:object, []]]],
65
- [:field, [:rating, :field, "10", ["must be an integer"], [:object, []]]]
66
- ]
67
- ]],
68
- [:many, [
69
- :reviews,
70
- :many,
71
- [],
72
- [:object, [
73
- [:allow_create, [:value, [true]]],
74
- [:allow_update, [:value, [true]]],
75
- [:allow_destroy, [:value, [true]]],
76
- [:allow_reorder, [:value, [true]]]
77
- ]],
78
- [
79
- [:field, [:summary, :field, nil, [], [:object, []]]],
80
- [:field, [:rating, :field, nil, [], [:object, []]]]
81
- ],
82
- [
83
- [
84
- [:field, [:summary, :field, "", ["must be filled"], [:object, []]]],
85
- [:field, [:rating, :field, 10, [], [:object, []]]]
86
- ],
87
- [
88
- [:field, [:summary, :field, "Great!", [], [:object, []]]],
89
- [:field, [:rating, :field, 0, ["must be greater than or equal to 1"], [:object, []]]]
90
- ]
91
- ]
92
- ]],
93
- [:attr, [
94
- :meta,
95
- :attr,
96
- [],
97
- [:object, []],
98
- [
99
- [:field, [:pages, :field, 0, ["must be greater than or equal to 1"], [:object, []]]]
100
- ]
101
- ]]
102
- ]
103
- end
104
- end
data/spec/spec_helper.rb DELETED
@@ -1,109 +0,0 @@
1
- if RUBY_ENGINE == "ruby"
2
- require "codeclimate-test-reporter"
3
- CodeClimate::TestReporter.start
4
-
5
- require "simplecov"
6
- SimpleCov.start do
7
- add_filter "/spec/"
8
- end
9
- end
10
-
11
- begin
12
- require "byebug"
13
- rescue LoadError; end
14
-
15
- require "formalist"
16
- require "dry-validation"
17
-
18
- # Requires supporting ruby files with custom matchers and macros, etc, in
19
- # spec/support/ and its subdirectories. Files matching `spec/**/*_spec.rb` are
20
- # run as spec files by default. This means that files in spec/support that end
21
- # in _spec.rb will both be required and run as specs, causing the specs to be
22
- # run twice. It is recommended that you do not name files matching this glob to
23
- # end with _spec.rb. You can configure this pattern with the --pattern
24
- # option on the command line or in ~/.rspec, .rspec or `.rspec-local`.
25
- #
26
- # The following line is provided for convenience purposes. It has the downside
27
- # of increasing the boot-up time by auto-requiring all files in the support
28
- # directory. Alternatively, in the individual `*_spec.rb` files, manually
29
- # require only the support files necessary.
30
- Dir[File.join(File.dirname(__FILE__), "support/**/*.rb")].each do |f| require f end
31
-
32
- # This file was generated by the `rspec --init` command. Conventionally, all
33
- # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
34
- # The generated `.rspec` file contains `--require spec_helper` which will cause
35
- # this file to always be loaded, without a need to explicitly require it in any
36
- # files.
37
- #
38
- # Given that it is always loaded, you are encouraged to keep this file as
39
- # light-weight as possible. Requiring heavyweight dependencies from this file
40
- # will add to the boot time of your test suite on EVERY test run, even for an
41
- # individual file that may not need all of that loaded. Instead, consider making
42
- # a separate helper file that requires the additional dependencies and performs
43
- # the additional setup, and require it from the spec files that actually need
44
- # it.
45
- #
46
- # The `.rspec` file also contains a few flags that are not defaults but that
47
- # users commonly want.
48
- #
49
- # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
50
- RSpec.configure do |config|
51
- # rspec-expectations config goes here. You can use an alternate
52
- # assertion/expectation library such as wrong or the stdlib/minitest
53
- # assertions if you prefer.
54
- config.expect_with :rspec do |expectations|
55
- # This option will default to `true` in RSpec 4. It makes the `description`
56
- # and `failure_message` of custom matchers include text for helper methods
57
- # defined using `chain`, e.g.:
58
- # be_bigger_than(2).and_smaller_than(4).description
59
- # # => "be bigger than 2 and smaller than 4"
60
- # ...rather than:
61
- # # => "be bigger than 2"
62
- expectations.include_chain_clauses_in_custom_matcher_descriptions = true
63
- end
64
-
65
- # rspec-mocks config goes here. You can use an alternate test double
66
- # library (such as bogus or mocha) by changing the `mock_with` option here.
67
- config.mock_with :rspec do |mocks|
68
- # Prevents you from mocking or stubbing a method that does not exist on
69
- # a real object. This is generally recommended, and will default to
70
- # `true` in RSpec 4.
71
- mocks.verify_partial_doubles = true
72
- end
73
-
74
- # Allows RSpec to persist some state between runs in order to support
75
- # the `--only-failures` and `--next-failure` CLI options. We recommend
76
- # you configure your source control system to ignore this file.
77
- config.example_status_persistence_file_path = "spec/examples.txt"
78
-
79
- # Limits the available syntax to the non-monkey patched syntax that is
80
- # recommended.
81
- config.disable_monkey_patching!
82
-
83
- # This setting enables warnings. It's recommended, but in some cases may
84
- # be too noisy due to issues in dependencies.
85
- # config.warnings = true
86
- config.warnings = false
87
-
88
- # Many RSpec users commonly either run the entire suite or an individual
89
- # file, and it's useful to allow more verbose output when running an
90
- # individual spec file.
91
- if config.files_to_run.one?
92
- # Use the documentation formatter for detailed output,
93
- # unless a formatter has already been configured
94
- # (e.g. via a command-line flag).
95
- config.default_formatter = "doc"
96
- end
97
-
98
- # Run specs in random order to surface order dependencies. If you find an
99
- # order dependency and want to debug it, you can fix the order by providing
100
- # the seed, which is printed after each run.
101
- # --seed 1234
102
- config.order = :random
103
-
104
- # Seed global randomization in this process using the `--seed` CLI option.
105
- # Setting this allows you to use `--seed` to deterministically reproduce
106
- # test failures related to randomization by passing the same `--seed` value
107
- # as the one that triggered the failure.
108
- Kernel.srand config.seed
109
- end
@@ -1,11 +0,0 @@
1
- module Test
2
- def self.remove_constants
3
- constants.each(&method(:remove_const))
4
- end
5
- end
6
-
7
- RSpec.configure do |config|
8
- config.after do
9
- Test.remove_constants
10
- end
11
- end
@@ -1,33 +0,0 @@
1
- require "spec_helper"
2
- require "formalist/elements/standard/check_box"
3
-
4
- RSpec.describe Formalist::Elements::CheckBox do
5
- subject(:check_box) {
6
- Formalist::Elements::CheckBox.new(:published, attributes, [], {published: input}, errors)
7
- }
8
-
9
- let(:attributes) { {} }
10
- let(:input) { nil }
11
- let(:errors) { {} }
12
-
13
- describe "input" do
14
- context "is nil" do
15
- specify { expect(check_box.input).to eql false }
16
- end
17
-
18
- context "is false" do
19
- let(:input) { false }
20
- specify { expect(check_box.input).to eql false }
21
- end
22
-
23
- context "is true" do
24
- let(:input) { true }
25
- specify { expect(check_box.input).to eql true }
26
- end
27
-
28
- context "is any other value" do
29
- let(:input) { "something" }
30
- specify { expect(check_box.input).to eql true }
31
- end
32
- end
33
- end