reform 2.2.4 → 2.3.0.rc1
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.
- 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
|
[](https://gitter.im/trailblazer/chat)
|
4
4
|
[](http://trailblazer.to/newsletter/)
|
5
5
|
[](https://travis-ci.org/trailblazer/reform)
|
7
7
|
[](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
|