formalist 0.3.0 → 0.4.0

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