reform 2.2.4 → 2.3.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +13 -7
- data/CHANGES.md +26 -4
- data/CONTRIBUTING.md +31 -0
- data/Gemfile +1 -12
- data/ISSUE_TEMPLATE.md +25 -0
- data/LICENSE.txt +1 -1
- data/README.md +3 -3
- data/lib/reform.rb +1 -0
- data/lib/reform/contract.rb +1 -11
- data/lib/reform/contract/validate.rb +49 -23
- data/lib/reform/errors.rb +49 -0
- data/lib/reform/form.rb +20 -5
- data/lib/reform/form/dry.rb +57 -29
- data/lib/reform/form/populator.rb +2 -16
- data/lib/reform/form/prepopulate.rb +1 -1
- data/lib/reform/form/validate.rb +10 -2
- data/lib/reform/result.rb +63 -0
- data/lib/reform/validation.rb +19 -13
- data/lib/reform/validation/groups.rb +11 -25
- data/lib/reform/version.rb +1 -1
- data/reform.gemspec +7 -6
- data/test/benchmarking.rb +39 -5
- data/test/call_test.rb +1 -1
- data/test/changed_test.rb +1 -1
- data/test/coercion_test.rb +2 -2
- data/test/composition_test.rb +47 -9
- data/test/contract_test.rb +5 -5
- data/test/default_test.rb +1 -1
- data/test/deserialize_test.rb +3 -3
- data/test/errors_test.rb +36 -21
- data/test/feature_test.rb +1 -1
- data/test/fixtures/dry_error_messages.yml +70 -23
- data/test/form_option_test.rb +3 -3
- data/test/form_test.rb +3 -3
- data/test/from_test.rb +2 -2
- data/test/inherit_test.rb +44 -51
- data/test/module_test.rb +12 -12
- data/test/parse_option_test.rb +40 -0
- data/test/parse_pipeline_test.rb +2 -2
- data/test/populate_test.rb +59 -19
- data/test/populator_skip_test.rb +9 -8
- data/test/prepopulator_test.rb +3 -3
- data/test/readable_test.rb +2 -2
- data/test/readonly_test.rb +1 -1
- data/test/reform_test.rb +16 -31
- data/test/save_test.rb +23 -8
- data/test/setup_test.rb +2 -2
- data/test/skip_if_test.rb +4 -4
- data/test/skip_setter_and_getter_test.rb +1 -1
- data/test/test_helper.rb +13 -10
- data/test/validate_test.rb +18 -18
- data/test/validation/dry_validation_test.rb +430 -117
- data/test/validation/result_test.rb +79 -0
- data/test/validation_library_provided_test.rb +16 -0
- data/test/virtual_test.rb +1 -1
- data/test/writeable_test.rb +31 -2
- metadata +42 -23
- data/gemfiles/Gemfile.disposable-0.3 +0 -6
- data/lib/reform/contract/errors.rb +0 -43
- data/lib/reform/form/mongoid.rb +0 -37
- data/lib/reform/form/orm.rb +0 -26
- data/lib/reform/mongoid.rb +0 -4
- data/test/deprecation_test.rb +0 -27
- data/test/validation/dry_test.rb +0 -60
- data/test/validation/errors.yml +0 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 833e85f6efec80dfacc227371dfb5ec4fe5d1fdd
|
4
|
+
data.tar.gz: e084df9fc8f080155d3af4398a80c78347db5b78
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: dba35a83313b4f5a2cecde6d85800b19c83f5b55553d2600e448ca042f1a8429a85b26ff3d522aa95b308bc1fadba731bb7a550cbe81e3ebab02d4c2052a4de8
|
7
|
+
data.tar.gz: cac8a4bddbbbef87379fd823bcfccce351fb9a0af36448d36d092393abaebcabc5343cc1665a68652a570bc7e765593ae0c873912033166d870e729962bddf70
|
data/.travis.yml
CHANGED
@@ -1,11 +1,17 @@
|
|
1
1
|
language: ruby
|
2
|
+
cache: bundler
|
3
|
+
bundler_args: --without benchmarks tools
|
2
4
|
rvm:
|
3
|
-
- 2.
|
4
|
-
- 2.
|
5
|
-
|
6
|
-
-
|
7
|
-
|
5
|
+
- 2.1.10
|
6
|
+
- 2.2.5
|
7
|
+
- 2.3.1
|
8
|
+
- 2.4.0
|
8
9
|
matrix:
|
9
10
|
fast_finish: true
|
10
|
-
|
11
|
-
|
11
|
+
notifications:
|
12
|
+
webhooks:
|
13
|
+
urls:
|
14
|
+
- https://webhooks.gitter.im/e/680e86d98056f2ae2fd7
|
15
|
+
on_success: change # options: [always|never|change] default: always
|
16
|
+
on_failure: always # options: [always|never|change] default: always
|
17
|
+
on_start: never # options: [always|never|change] default: always
|
data/CHANGES.md
CHANGED
@@ -1,9 +1,31 @@
|
|
1
|
+
## 3.0.0
|
2
|
+
|
3
|
+
[* Removed `Reform::Contract` ?]
|
4
|
+
[* Move Form#deserializer to Form::deserializer]
|
5
|
+
|
6
|
+
## 2.3.0
|
7
|
+
|
8
|
+
You can upgrade from 2.2.0 without worries.
|
9
|
+
|
10
|
+
* Require Representable 3.0.0 and **removed Representable 2.4 deprecation code**.
|
11
|
+
* Require Disposable 0.4.0 which fixes issues with `nil` field values, `sync {}` and dry-validation.
|
12
|
+
* Fix boolean coercion.
|
13
|
+
* Allow using `:populator` classes marked with `Uber::Callable`.
|
14
|
+
* Introduce `parse: false` as a shortcut for `deserialzer: { writeable: false}`. Thanks to @pabloh for insisting on this handy change.
|
15
|
+
* Memoize the deserializer instance on the class level via `::deserializer`. This saves the inferal of a deserializing representer and speeds up following calls by 130%.
|
16
|
+
* Deprecated positional arguments for `validation :default, options: {}`. New API: `validation name: :default, **`.
|
17
|
+
* Reform now maintains a generic `Dry::Schema` class for global schema configuration. Can be overridden via `::validation`.
|
18
|
+
* When validating with dry-validation, we now pass a symbolized hash. We also replaced `Dry::Validation::Form` with `Schema` which won't coerce values where it shouldn't.
|
19
|
+
* [private] `Group#call` API now is: `call(form, errors)`.
|
20
|
+
* Removed `Form#valid?`.
|
21
|
+
|
22
|
+
* In `:if` for validation groups, you now get a hash of result objects, not just true/false.
|
23
|
+
|
24
|
+
|
1
25
|
## 2.2.4
|
2
26
|
|
3
|
-
*
|
4
|
-
|
5
|
-
The only difference here is that `Form#sync`/`#save` with a block will include `nil` properties into the nested hash.
|
6
|
-
* Remove `uber` dependency.
|
27
|
+
* You can now use any object with `call` as a populator, no need to `include Uber::Callable` anymore. This is because we have only three types and don't need a `is_a?` or `respond_to?` check.
|
28
|
+
* Use `declarative-option` and loosen `uber` dependency.
|
7
29
|
|
8
30
|
## 2.2.3
|
9
31
|
|
data/CONTRIBUTING.md
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
## How to contribute to Reform
|
2
|
+
|
3
|
+
#### **Did you find a bug?**
|
4
|
+
|
5
|
+
* **Ensure the bug was not already reported** by searching on GitHub under [Issues](https://github.com/trailblazer/reform/issues).
|
6
|
+
|
7
|
+
* If you're unable to find an open issue addressing the problem, [open a new one](https://github.com/trailblazer/reform/issues/new). Be sure to follow the issue template.
|
8
|
+
|
9
|
+
#### **Did you write a patch that fixes a bug?**
|
10
|
+
|
11
|
+
* Open a new GitHub pull request with the patch.
|
12
|
+
|
13
|
+
* Ensure the PR description clearly describes the problem and solution. Include the relevant issue number if applicable.
|
14
|
+
|
15
|
+
* All code in pull requests is assumed to be MIT licensed. Do not submit a pull request if that isn't the case.
|
16
|
+
|
17
|
+
#### **Do you intend to add a new feature or change an existing one?**
|
18
|
+
|
19
|
+
* Suggest your change in the [Trailblazer Gitter Room](https://gitter.im/trailblazer/chat) and start writing code.
|
20
|
+
|
21
|
+
* Do not open an issue on GitHub until you have collected positive feedback about the change. GitHub issues are primarily intended for bug reports and fixes.
|
22
|
+
|
23
|
+
#### **Do you have questions using Reform?**
|
24
|
+
|
25
|
+
* Ask any questions about how to use Reform in the [Trailblazer Gitter Room](https://gitter.im/trailblazer/chat). Github issues are restricted to bug reports and fixes.
|
26
|
+
|
27
|
+
* GitHub Issues should not be used as a help forum and any such issues will be closed.
|
28
|
+
|
29
|
+
#### **Do you want to contribute to the Reform documentation?**
|
30
|
+
|
31
|
+
* Reform documentation is provided via the [Trailblazer site](http://trailblazer.to/gems/reform/) and not the repository readme. Please add your contributions to the [Trailblazer site repository](https://github.com/trailblazer/trailblazer.github.io)
|
data/Gemfile
CHANGED
@@ -2,18 +2,7 @@ source 'https://rubygems.org'
|
|
2
2
|
|
3
3
|
gemspec
|
4
4
|
|
5
|
-
|
6
|
-
# gem "representable", "2.4.0.rc5"
|
7
|
-
# gem 'representable', path: "../representable"
|
8
|
-
# # gem 'representable', github: "apotonick/representable"
|
9
|
-
# gem "disposable", path: "../disposable"
|
10
|
-
# gem "disposable", github: "apotonick/disposable"
|
11
|
-
|
12
|
-
|
13
|
-
# gem "declarative", path: "../declarative"
|
14
|
-
|
15
5
|
gem "minitest-line"
|
16
6
|
gem 'byebug'
|
7
|
+
# gem "disposable", path: "../disposable"
|
17
8
|
|
18
|
-
# gem "uber", path: "../uber"
|
19
|
-
gem "representable", ">= 3.0.1"
|
data/ISSUE_TEMPLATE.md
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
Note: If you have a question about Reform, would like help using
|
2
|
+
Reform, want to request a feature, or do anything else other than
|
3
|
+
submit a bug report, please use the Trailblazer gitter channel.
|
4
|
+
|
5
|
+
Note: Rails/ ActiveRecord/ ActiveModel support.
|
6
|
+
As of Reform 2.2.0 all Rails/ Active-* code was moved to the [reform-rails](https://github.com/trailblazer/reform-rails) gem.
|
7
|
+
Make sure you are contributing to the correct gem!
|
8
|
+
|
9
|
+
### Complete Description of Issue
|
10
|
+
|
11
|
+
|
12
|
+
### Steps to reproduce
|
13
|
+
|
14
|
+
|
15
|
+
### Expected behavior
|
16
|
+
Tell us what should happen
|
17
|
+
|
18
|
+
### Actual behavior
|
19
|
+
Tell us what happens instead
|
20
|
+
|
21
|
+
### System configuration
|
22
|
+
**Reform version**:
|
23
|
+
|
24
|
+
### Full Backtrace of Exception (if any)
|
25
|
+
|
data/LICENSE.txt
CHANGED
data/README.md
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
[![Gitter Chat](https://badges.gitter.im/trailblazer/chat.svg)](https://gitter.im/trailblazer/chat)
|
4
4
|
[![TRB Newsletter](https://img.shields.io/badge/TRB-newsletter-lightgrey.svg)](http://trailblazer.to/newsletter/)
|
5
5
|
[![Build
|
6
|
-
Status](https://travis-ci.org/
|
6
|
+
Status](https://travis-ci.org/trailblazer/reform.svg)](https://travis-ci.org/trailblazer/reform)
|
7
7
|
[![Gem Version](https://badge.fury.io/rb/reform.svg)](http://badge.fury.io/rb/reform)
|
8
8
|
|
9
9
|
_Form objects decoupled from your models._
|
@@ -296,7 +296,7 @@ Put this in an initializer or on top of your script.
|
|
296
296
|
Reform allows to map multiple models to one form. The [complete documentation](https://github.com/apotonick/disposable#composition) is here, however, this is how it works.
|
297
297
|
|
298
298
|
```ruby
|
299
|
-
class
|
299
|
+
class AlbumForm < Reform::Form
|
300
300
|
include Composition
|
301
301
|
|
302
302
|
property :id, on: :album
|
@@ -328,7 +328,7 @@ By explicitely defining the form layout using `::property` there is no more need
|
|
328
328
|
|
329
329
|
## This is not Reform 1.x!
|
330
330
|
|
331
|
-
Temporary note: This is the README and API for Reform 2. On the public API, only a few tiny things have changed. Here are the [Reform 1.2 docs](https://github.com/
|
331
|
+
Temporary note: This is the README and API for Reform 2. On the public API, only a few tiny things have changed. Here are the [Reform 1.2 docs](https://github.com/trailblazer/reform/blob/v1.2.6/README.md).
|
332
332
|
|
333
333
|
Anyway, please upgrade and _report problems_ and do not simply assume that we will magically find out what needs to get fixed. When in trouble, join us on [Gitter](https://gitter.im/trailblazer/chat).
|
334
334
|
|
data/lib/reform.rb
CHANGED
data/lib/reform/contract.rb
CHANGED
@@ -27,13 +27,12 @@ module Reform
|
|
27
27
|
super
|
28
28
|
end
|
29
29
|
|
30
|
-
# FIXME: test me.
|
31
30
|
def self.properties(*args)
|
32
31
|
options = args.last.is_a?(Hash) ? args.pop : {}
|
33
32
|
args.each { |name| property(name, options.dup) }
|
34
33
|
end
|
35
34
|
|
36
|
-
require "reform/
|
35
|
+
require "reform/result"
|
37
36
|
require 'reform/contract/validate'
|
38
37
|
include Reform::Contract::Validate
|
39
38
|
|
@@ -44,15 +43,6 @@ module Reform
|
|
44
43
|
require "disposable/twin/sync"
|
45
44
|
include Disposable::Twin::Sync
|
46
45
|
|
47
|
-
|
48
|
-
|
49
|
-
# module ValidatesWarning
|
50
|
-
# def validates(*)
|
51
|
-
# raise "[Reform] Please include either Reform::Form::ActiveModel::Validations or Reform::Form::Lotus in your form class."
|
52
|
-
# end
|
53
|
-
# end
|
54
|
-
# extend ValidatesWarning
|
55
|
-
|
56
46
|
private
|
57
47
|
# DISCUSS: separate file?
|
58
48
|
module Readonly
|
@@ -1,33 +1,59 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
1
|
+
class Reform::Contract < Disposable::Twin
|
2
|
+
module Validate
|
3
|
+
def initialize(*)
|
4
|
+
# this will be removed in Reform 3.0. we need this for the presenting form, form builders
|
5
|
+
# call the Form#errors method before validation.
|
6
|
+
super
|
7
|
+
@result = Result.new([])
|
8
|
+
end
|
6
9
|
|
7
|
-
|
10
|
+
def validate
|
11
|
+
validate!(nil).success?
|
12
|
+
end
|
8
13
|
|
9
|
-
|
10
|
-
|
14
|
+
# The #errors method will be removed in Reform 2.4/3.0 core.
|
15
|
+
def errors(*args)
|
16
|
+
Result::Errors.new(@result, self)
|
17
|
+
end
|
11
18
|
|
12
|
-
|
13
|
-
|
19
|
+
#:private:
|
20
|
+
# only used in tests so far. this will be the new API in #call, where you will get @result.
|
21
|
+
def to_result
|
22
|
+
@result
|
23
|
+
end
|
14
24
|
|
15
|
-
|
16
|
-
|
25
|
+
def validate!(name, pointers=[])
|
26
|
+
# run local validations. this could be nested schemas, too.
|
27
|
+
local_errors_by_group = Reform::Validation::Groups::Validate.(self.class.validation_groups, self).compact # TODO: discss compact
|
17
28
|
|
18
|
-
|
29
|
+
# blindly add injected pointers. will be readable via #errors.
|
30
|
+
# also, add pointers from local errors here.
|
31
|
+
pointers_for_nested = pointers + local_errors_by_group.collect { |errs| Result::Pointer.new(errs, []) }.compact
|
19
32
|
|
20
|
-
|
21
|
-
|
22
|
-
|
33
|
+
nested_errors = validate_nested!(pointers_for_nested)
|
34
|
+
|
35
|
+
# Result: unified interface #success?, #messages, etc.
|
36
|
+
@result = Result.new(local_errors_by_group + pointers, nested_errors)
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
# Recursively call validate! on nested forms.
|
42
|
+
# A pointer keeps an entire result object (e.g. Dry result) and
|
43
|
+
# the relevant path to its fragment, e.g. <Dry::result{.....} path=songs,0>
|
44
|
+
def validate_nested!(pointers)
|
45
|
+
arr = []
|
46
|
+
|
47
|
+
schema.each(twin: true) do |dfn|
|
48
|
+
# on collections, this calls validate! on each item form.
|
49
|
+
Disposable::Twin::PropertyProcessor.new(dfn, self).() { |form, i|
|
50
|
+
nested_pointers = pointers.collect { |pointer| pointer.advance(dfn[:name].to_sym, i) }.compact # pointer contains fragment for us, so go deeper
|
23
51
|
|
24
|
-
|
52
|
+
arr << form.validate!(dfn[:name], nested_pointers)
|
53
|
+
}
|
54
|
+
end
|
25
55
|
|
26
|
-
|
27
|
-
def validate_nested!(errors, prefixes)
|
28
|
-
schema.each(twin: true) do |dfn|
|
29
|
-
# recursively call valid? on nested form.
|
30
|
-
Disposable::Twin::PropertyProcessor.new(dfn, self).() { |form| form.validate!(errors, prefixes+[dfn[:name]]) }
|
56
|
+
arr
|
31
57
|
end
|
32
58
|
end
|
33
|
-
end
|
59
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# Provides the old API for Rails and friends.
|
2
|
+
# Note that this might become an optional "deprecation" gem in Reform 3.
|
3
|
+
class Reform::Contract::Result::Errors
|
4
|
+
def initialize(result, form)
|
5
|
+
@result = result # DISCUSS: we don't use this ATM?
|
6
|
+
@form = form
|
7
|
+
@dotted_errors = {} # Reform does not endorse this style of error msgs.
|
8
|
+
|
9
|
+
DottedErrors.(@form, [], @dotted_errors)
|
10
|
+
end
|
11
|
+
|
12
|
+
# PROTOTYPING. THIS WILL GO TO A SEPARATE GEM IN REFORM 2.4/3.0.
|
13
|
+
DottedErrors = ->(form, prefix, hash) do
|
14
|
+
result = form.to_result
|
15
|
+
result.messages.collect { |k,v| hash[ [*prefix, k].join(".").to_sym] = v }
|
16
|
+
|
17
|
+
form.schema.each(twin: true) { |dfn|
|
18
|
+
Disposable::Twin::PropertyProcessor.new(dfn, form).() do |frm, i|
|
19
|
+
# DottedErrors.(form.send(dfn[:name])[i], [*prefix, dfn[:name], i], hash) and next if i
|
20
|
+
DottedErrors.(form.send(dfn[:name])[i], [*prefix, dfn[:name]], hash) and next if i
|
21
|
+
DottedErrors.(form.send(dfn[:name]), [*prefix, dfn[:name]], hash)
|
22
|
+
end
|
23
|
+
}
|
24
|
+
end
|
25
|
+
|
26
|
+
def messages(*args)
|
27
|
+
@dotted_errors
|
28
|
+
end
|
29
|
+
|
30
|
+
def full_messages
|
31
|
+
@dotted_errors.collect do |path, errors|
|
32
|
+
human_field = path.to_s.gsub(/([\.\_])+/, " ").gsub(/(\b\w)+/) { |s| s.capitalize }
|
33
|
+
errors.collect { |message| "#{human_field} #{message}" }
|
34
|
+
end.flatten
|
35
|
+
end
|
36
|
+
|
37
|
+
def [](name)
|
38
|
+
@dotted_errors[name]
|
39
|
+
end
|
40
|
+
|
41
|
+
def size
|
42
|
+
messages.size
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
# Ensure that we can return Active Record compliant full messages when using dry
|
47
|
+
# we only want unique messages in our array
|
48
|
+
#
|
49
|
+
# @full_errors.add()
|
data/lib/reform/form.rb
CHANGED
@@ -16,7 +16,22 @@ module Reform
|
|
16
16
|
module Property
|
17
17
|
# Add macro logic, e.g. for :populator.
|
18
18
|
def property(name, options={}, &block)
|
19
|
-
|
19
|
+
# if composition and inherited we also need this setting
|
20
|
+
# to correctly inherit modules
|
21
|
+
if options.key?(:on) && options.key?(:inherit)
|
22
|
+
options[:_inherited] = options[:inherit]
|
23
|
+
end
|
24
|
+
|
25
|
+
if options.key?(:parse)
|
26
|
+
options[:deserializer] ||= {}
|
27
|
+
options[:deserializer][:writeable] = options.delete(:parse)
|
28
|
+
end
|
29
|
+
|
30
|
+
if options.key?(:writable)
|
31
|
+
options[:writeable] ||= options.delete(:writable)
|
32
|
+
end
|
33
|
+
|
34
|
+
definition = super # let disposable and declarative gems sort out inheriting of properties, and so on.
|
20
35
|
definition.merge!(deserializer: {}) unless definition[:deserializer] # always keep :deserializer per property.
|
21
36
|
|
22
37
|
deserializer_options = definition[:deserializer]
|
@@ -35,8 +50,8 @@ module Reform
|
|
35
50
|
# always compute a parse_pipeline for each property of the deserializer and inject it via :parse_pipeline.
|
36
51
|
# first, let representable compute the pipeline functions by invoking #parse_functions.
|
37
52
|
if definition[:nested]
|
38
|
-
parse_pipeline = ->(input,
|
39
|
-
functions =
|
53
|
+
parse_pipeline = ->(input, opts) do
|
54
|
+
functions = opts[:binding].send(:parse_functions)
|
40
55
|
pipeline = Representable::Pipeline[*functions] # Pipeline[StopOnExcluded, AssignName, ReadFragment, StopOnNotFound, OverwriteOnNil, Collect[#<Representable::Function::CreateObject:0xa6148ec>, #<Representable::Function::Decorate:0xa6148b0>, Deserialize], Set]
|
41
56
|
|
42
57
|
pipeline = Representable::Pipeline::Insert.(pipeline, external_populator, replace: Representable::CreateObject::Instance)
|
@@ -45,8 +60,8 @@ module Reform
|
|
45
60
|
pipeline = Representable::Pipeline::Insert.(pipeline, Representable::SetValue, delete: true) # FIXME: only diff to options without :populator
|
46
61
|
end
|
47
62
|
else
|
48
|
-
parse_pipeline = ->(input,
|
49
|
-
functions =
|
63
|
+
parse_pipeline = ->(input, opts) do
|
64
|
+
functions = opts[:binding].send(:parse_functions)
|
50
65
|
pipeline = Representable::Pipeline[*functions] # Pipeline[StopOnExcluded, AssignName, ReadFragment, StopOnNotFound, OverwriteOnNil, Collect[#<Representable::Function::CreateObject:0xa6148ec>, #<Representable::Function::Decorate:0xa6148b0>, Deserialize], Set]
|
51
66
|
|
52
67
|
# FIXME: this won't work with property :name, inherit: true (where there is a populator set already).
|
data/lib/reform/form/dry.rb
CHANGED
@@ -9,10 +9,6 @@ module Reform::Form::Dry
|
|
9
9
|
end
|
10
10
|
|
11
11
|
module Validations
|
12
|
-
def build_errors
|
13
|
-
Reform::Contract::Errors.new(self)
|
14
|
-
end
|
15
|
-
|
16
12
|
module ClassMethods
|
17
13
|
def validation_group_class
|
18
14
|
Group
|
@@ -23,44 +19,76 @@ module Reform::Form::Dry
|
|
23
19
|
includer.extend(ClassMethods)
|
24
20
|
end
|
25
21
|
|
22
|
+
|
26
23
|
class Group
|
27
|
-
def initialize
|
28
|
-
|
24
|
+
def initialize(options = {})
|
25
|
+
options ||= {}
|
26
|
+
schema_class = options[:schema] || Dry::Validation::Schema
|
27
|
+
@validator = Dry::Validation.Schema(schema_class, build: false)
|
28
|
+
|
29
|
+
@schema_inject_params = options[:with] || {}
|
29
30
|
end
|
30
31
|
|
31
32
|
def instance_exec(&block)
|
32
|
-
@
|
33
|
-
@validator = Builder.new(@schemas.dup).validation_graph
|
34
|
-
end
|
33
|
+
@validator = Dry::Validation.Schema(@validator, build: false, &block)
|
35
34
|
|
36
|
-
|
37
|
-
|
38
|
-
@validator.
|
39
|
-
|
40
|
-
|
35
|
+
# inject the keys into the configure block automatically
|
36
|
+
keys = @schema_inject_params.keys
|
37
|
+
@validator.class_eval do
|
38
|
+
configure do
|
39
|
+
keys.each { |k| option k }
|
41
40
|
end
|
42
41
|
end
|
43
42
|
end
|
44
43
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
end
|
44
|
+
def call(form)
|
45
|
+
dynamic_options = {}
|
46
|
+
dynamic_options[:form] = form if @schema_inject_params[:form]
|
47
|
+
inject_options = @schema_inject_params.merge(dynamic_options)
|
50
48
|
|
51
|
-
|
52
|
-
|
53
|
-
|
49
|
+
# TODO: only pass submitted values to Schema#call?
|
50
|
+
dry_result = call_schema(inject_options, input_hash(form))
|
51
|
+
# dry_messages = dry_result.messages
|
52
|
+
|
53
|
+
return dry_result
|
54
|
+
reform_errors = Reform::Contract::Errors.new(dry_result) # TODO: dry should be merged here.
|
55
|
+
end
|
54
56
|
|
57
|
+
private
|
58
|
+
def call_schema(inject_options, input)
|
59
|
+
@validator.new(@validator.rules, inject_options).(input)
|
60
|
+
end
|
55
61
|
|
56
|
-
|
62
|
+
# if dry_error is a hash rather than an array then it contains
|
63
|
+
# the messages for a nested property
|
64
|
+
# these messages need to be added to the correct collection
|
65
|
+
# objects.
|
57
66
|
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
67
|
+
# collections:
|
68
|
+
# {0=>{:name=>["must be filled"]}, 1=>{:name=>["must be filled"]}}
|
69
|
+
|
70
|
+
# Objects:
|
71
|
+
# {:name=>["must be filled"]}
|
72
|
+
# simply load up the object and attach the message to it
|
73
|
+
|
74
|
+
# we can't use to_nested_hash as it get's messed up by composition.
|
75
|
+
def input_hash(form)
|
76
|
+
hash = form.class.nested_hash_representer.new(form).to_hash
|
77
|
+
symbolize_hash(hash)
|
78
|
+
end
|
79
|
+
|
80
|
+
# dry-v needs symbolized keys
|
81
|
+
# TODO: Don't do this here... Representers??
|
82
|
+
def symbolize_hash(old_hash)
|
83
|
+
old_hash.each_with_object({}) { |(k, v), new_hash|
|
84
|
+
new_hash[k.to_sym] = if v.is_a?(Hash)
|
85
|
+
symbolize_hash(v)
|
86
|
+
elsif v.is_a?(Array)
|
87
|
+
v.map{ |h| h.is_a?(Hash) ? symbolize_hash(h) : h }
|
88
|
+
else
|
89
|
+
v
|
90
|
+
end
|
91
|
+
}
|
64
92
|
end
|
65
93
|
end
|
66
94
|
end
|