formalist 0.3.0 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.gitignore +7 -0
- data/.rspec +2 -0
- data/.travis.yml +21 -0
- data/.yardopts +1 -0
- data/CHANGELOG.md +62 -0
- data/Gemfile +1 -2
- data/bin/console +13 -0
- data/formalist.gemspec +33 -0
- data/lib/formalist/definition.rb +65 -0
- data/lib/formalist/element/class_interface.rb +7 -59
- data/lib/formalist/element.rb +37 -19
- data/lib/formalist/elements/attr.rb +8 -20
- data/lib/formalist/elements/compound_field.rb +5 -4
- data/lib/formalist/elements/field.rb +5 -12
- data/lib/formalist/elements/group.rb +6 -5
- data/lib/formalist/elements/many.rb +28 -29
- data/lib/formalist/elements/section.rb +6 -10
- data/lib/formalist/elements/standard/multi_upload_field.rb +8 -0
- data/lib/formalist/elements/standard/rich_text_area.rb +40 -0
- data/lib/formalist/elements/standard/search_multi_selection_field.rb +20 -0
- data/lib/formalist/elements/standard/search_selection_field.rb +20 -0
- data/lib/formalist/elements/standard/tags_field.rb +16 -0
- data/lib/formalist/elements/standard/upload_field.rb +8 -0
- data/lib/formalist/elements/standard.rb +4 -0
- data/lib/formalist/form/validity_check.rb +54 -0
- data/lib/formalist/form.rb +49 -17
- data/lib/formalist/rich_text/embedded_form_compiler.rb +86 -0
- data/lib/formalist/rich_text/embedded_forms_container/mixin.rb +42 -0
- data/lib/formalist/rich_text/embedded_forms_container/registration.rb +30 -0
- data/lib/formalist/rich_text/embedded_forms_container.rb +9 -0
- data/lib/formalist/rich_text/rendering/embedded_form_renderer.rb +25 -0
- data/lib/formalist/rich_text/rendering/html_compiler.rb +100 -0
- data/lib/formalist/rich_text/rendering/html_renderer.rb +186 -0
- data/lib/formalist/rich_text/validity_check.rb +48 -0
- data/lib/formalist/types.rb +8 -7
- data/lib/formalist/version.rb +1 -1
- metadata +54 -31
- data/Gemfile.lock +0 -105
- data/lib/formalist/element/definition.rb +0 -55
- data/lib/formalist/element/permitted_children.rb +0 -46
- data/lib/formalist/form/definition_context.rb +0 -69
- data/lib/formalist/form/result.rb +0 -24
- data/spec/examples.txt +0 -8
- data/spec/integration/dependency_injection_spec.rb +0 -54
- data/spec/integration/form_spec.rb +0 -104
- data/spec/spec_helper.rb +0 -109
- data/spec/support/constants.rb +0 -11
- 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
|
data/spec/support/constants.rb
DELETED
@@ -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
|