yaaf 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.github/workflows/ci.yml +42 -0
- data/.gitignore +14 -0
- data/.reek.yml +128 -0
- data/.rspec +4 -0
- data/.rubocop.yml +85 -0
- data/.ruby-version +1 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/CONTRIBUTING.md +42 -0
- data/Gemfile +5 -0
- data/LICENSE.txt +21 -0
- data/README.md +272 -0
- data/Rakefile +6 -0
- data/bin/console +15 -0
- data/bin/setup +8 -0
- data/docs/README.md +15 -0
- data/docs/recipes/simple_form.md +117 -0
- data/lib/yaaf.rb +10 -0
- data/lib/yaaf/form.rb +64 -0
- data/lib/yaaf/version.rb +5 -0
- data/yaaf.gemspec +39 -0
- metadata +204 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 897bfdef28cdce5ee405763d213d28c7b2e011a661c4a7106f52100786110f6d
|
4
|
+
data.tar.gz: 3bd98b7cc8a9fcd78e982844a311ea56b7dd1dacbebc0d8c3c0d5f879a1c13fd
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: f073c7fa7d30bd7bfdafd4169dedc1af11cb4ad186c22f25237011cd23a7f19e628c1d5a6ac33d4b2318456800398a65e039a0cc8d74b517194c3852716b545c
|
7
|
+
data.tar.gz: 94851b76f07a37e0c8f339e9e76e3a0576fadd0797ce0b5c53ddf307b9650016728e6ac99efb8adfcb1cf9857c0c14b851e66627159b7c1c36c3720887c1a0c1
|
@@ -0,0 +1,42 @@
|
|
1
|
+
name: CI
|
2
|
+
|
3
|
+
on: [push]
|
4
|
+
|
5
|
+
jobs:
|
6
|
+
build:
|
7
|
+
if: "! contains(toJSON(github.event.commits.*.message), '[skip-ci]')"
|
8
|
+
runs-on: ubuntu-latest
|
9
|
+
strategy:
|
10
|
+
matrix:
|
11
|
+
gemfile: [rails_4.0.0.gemfile, rails_5.0.0.gemfile, rails_5.2.3.gemfile, rails_6.0.0.gemfile, rails_master.gemfile]
|
12
|
+
ruby_version: [2.4.x, 2.5.x, 2.6.x, 2.7.x]
|
13
|
+
exclude:
|
14
|
+
- gemfile: rails_master.gemfile
|
15
|
+
ruby_version: 2.4.x
|
16
|
+
- gemfile: rails_6.0.0.gemfile
|
17
|
+
ruby_version: 2.4.x
|
18
|
+
steps:
|
19
|
+
- uses: actions/checkout@v2
|
20
|
+
- name: Setup Ruby
|
21
|
+
uses: actions/setup-ruby@v1
|
22
|
+
with:
|
23
|
+
ruby-version: ${{ matrix.ruby_version }}
|
24
|
+
- name: Update rubygems when testing with Ruby 2.4.x
|
25
|
+
if: startsWith(matrix.ruby_version, '2.4')
|
26
|
+
run: |
|
27
|
+
gem update --system --no-document
|
28
|
+
- name: Before build
|
29
|
+
run: |
|
30
|
+
sudo apt-get install libsqlite3-dev
|
31
|
+
curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
|
32
|
+
chmod +x ./cc-test-reporter
|
33
|
+
./cc-test-reporter before-build
|
34
|
+
env:
|
35
|
+
CC_TEST_REPORTER_ID: aff2c7b9e07e54d5fc9e5588d2e2a8bab4f69950d35000edc2b6250bbaba477d
|
36
|
+
- name: Build and test with Rake
|
37
|
+
run: |
|
38
|
+
gem install bundler:1.17.3
|
39
|
+
bundle _1.17.3_ update
|
40
|
+
bundle _1.17.3_ install --gemfile spec/gemfiles/${{ matrix.gemfile }} --jobs 4 --retry 3
|
41
|
+
bundle _1.17.3_ exec rake code_analysis
|
42
|
+
bundle _1.17.3_ exec rspec
|
data/.gitignore
ADDED
data/.reek.yml
ADDED
@@ -0,0 +1,128 @@
|
|
1
|
+
detectors:
|
2
|
+
Attribute:
|
3
|
+
enabled: false
|
4
|
+
exclude: []
|
5
|
+
BooleanParameter:
|
6
|
+
enabled: true
|
7
|
+
exclude: []
|
8
|
+
ClassVariable:
|
9
|
+
enabled: false
|
10
|
+
exclude: []
|
11
|
+
ControlParameter:
|
12
|
+
enabled: true
|
13
|
+
exclude: []
|
14
|
+
DataClump:
|
15
|
+
enabled: true
|
16
|
+
exclude: []
|
17
|
+
max_copies: 2
|
18
|
+
min_clump_size: 2
|
19
|
+
DuplicateMethodCall:
|
20
|
+
enabled: true
|
21
|
+
exclude: []
|
22
|
+
max_calls: 1
|
23
|
+
allow_calls: []
|
24
|
+
FeatureEnvy:
|
25
|
+
enabled: true
|
26
|
+
exclude: []
|
27
|
+
InstanceVariableAssumption:
|
28
|
+
enabled: false
|
29
|
+
IrresponsibleModule:
|
30
|
+
enabled: false
|
31
|
+
exclude: []
|
32
|
+
LongParameterList:
|
33
|
+
enabled: true
|
34
|
+
exclude: []
|
35
|
+
max_params: 4
|
36
|
+
overrides:
|
37
|
+
initialize:
|
38
|
+
max_params: 5
|
39
|
+
LongYieldList:
|
40
|
+
enabled: true
|
41
|
+
exclude: []
|
42
|
+
max_params: 3
|
43
|
+
ManualDispatch:
|
44
|
+
enabled: true
|
45
|
+
exclude: []
|
46
|
+
MissingSafeMethod:
|
47
|
+
enabled: false
|
48
|
+
exclude: []
|
49
|
+
ModuleInitialize:
|
50
|
+
enabled: true
|
51
|
+
exclude: []
|
52
|
+
NestedIterators:
|
53
|
+
enabled: true
|
54
|
+
exclude: []
|
55
|
+
max_allowed_nesting: 2
|
56
|
+
ignore_iterators: []
|
57
|
+
NilCheck:
|
58
|
+
enabled: false
|
59
|
+
exclude: []
|
60
|
+
RepeatedConditional:
|
61
|
+
enabled: true
|
62
|
+
exclude: []
|
63
|
+
max_ifs: 3
|
64
|
+
SubclassedFromCoreClass:
|
65
|
+
enabled: true
|
66
|
+
exclude: []
|
67
|
+
TooManyConstants:
|
68
|
+
enabled: true
|
69
|
+
exclude: []
|
70
|
+
max_constants: 5
|
71
|
+
TooManyInstanceVariables:
|
72
|
+
enabled: true
|
73
|
+
exclude: []
|
74
|
+
max_instance_variables: 9
|
75
|
+
TooManyMethods:
|
76
|
+
enabled: true
|
77
|
+
exclude: []
|
78
|
+
max_methods: 25
|
79
|
+
TooManyStatements:
|
80
|
+
enabled: true
|
81
|
+
exclude:
|
82
|
+
- initialize
|
83
|
+
max_statements: 12
|
84
|
+
UncommunicativeMethodName:
|
85
|
+
enabled: true
|
86
|
+
exclude: []
|
87
|
+
reject:
|
88
|
+
- "/^[a-z]$/"
|
89
|
+
- "/[0-9]$/"
|
90
|
+
- "/[A-Z]/"
|
91
|
+
accept: []
|
92
|
+
UncommunicativeModuleName:
|
93
|
+
enabled: true
|
94
|
+
exclude: []
|
95
|
+
reject:
|
96
|
+
- "/^.$/"
|
97
|
+
- "/[0-9]$/"
|
98
|
+
accept:
|
99
|
+
- Inline::C
|
100
|
+
- "/V[0-9]/"
|
101
|
+
UncommunicativeParameterName:
|
102
|
+
enabled: true
|
103
|
+
exclude: []
|
104
|
+
reject:
|
105
|
+
- "/^.$/"
|
106
|
+
- "/[0-9]$/"
|
107
|
+
- "/[A-Z]/"
|
108
|
+
accept: []
|
109
|
+
UncommunicativeVariableName:
|
110
|
+
enabled: true
|
111
|
+
exclude:
|
112
|
+
- YAAF::Form#save_in_transaction
|
113
|
+
reject:
|
114
|
+
- "/^.$/"
|
115
|
+
- "/[0-9]$/"
|
116
|
+
- "/[A-Z]/"
|
117
|
+
accept:
|
118
|
+
- _
|
119
|
+
UnusedParameters:
|
120
|
+
enabled: true
|
121
|
+
exclude: []
|
122
|
+
UnusedPrivateMethod:
|
123
|
+
enabled: false
|
124
|
+
UtilityFunction:
|
125
|
+
enabled: false
|
126
|
+
|
127
|
+
exclude_paths:
|
128
|
+
- config
|
data/.rspec
ADDED
data/.rubocop.yml
ADDED
@@ -0,0 +1,85 @@
|
|
1
|
+
Layout/LineLength:
|
2
|
+
Max: 100
|
3
|
+
# To make it possible to copy or click on URIs in the code, we allow lines
|
4
|
+
# containing a URI to be longer than Max.
|
5
|
+
AllowURI: true
|
6
|
+
URISchemes:
|
7
|
+
- http
|
8
|
+
- https
|
9
|
+
|
10
|
+
Layout/SpaceBeforeFirstArg:
|
11
|
+
Exclude:
|
12
|
+
|
13
|
+
Lint/AmbiguousBlockAssociation:
|
14
|
+
Exclude:
|
15
|
+
- spec/**/*
|
16
|
+
|
17
|
+
Lint/RescueException:
|
18
|
+
Exclude:
|
19
|
+
- lib/yaaf/form.rb
|
20
|
+
|
21
|
+
Metrics/AbcSize:
|
22
|
+
# The ABC size is a calculated magnitude, so this number can be an Integer or
|
23
|
+
# a Float.
|
24
|
+
Max: 15
|
25
|
+
|
26
|
+
Metrics/BlockLength:
|
27
|
+
CountComments: false # count full line comments?
|
28
|
+
Max: 25
|
29
|
+
Exclude:
|
30
|
+
- 'yaaf.gemspec'
|
31
|
+
- config/**/*
|
32
|
+
- spec/**/*
|
33
|
+
ExcludedMethods:
|
34
|
+
- class_methods
|
35
|
+
|
36
|
+
Metrics/BlockNesting:
|
37
|
+
Max: 4
|
38
|
+
|
39
|
+
Metrics/ClassLength:
|
40
|
+
CountComments: false # count full line comments?
|
41
|
+
Max: 200
|
42
|
+
|
43
|
+
# Avoid complex methods.
|
44
|
+
Metrics/CyclomaticComplexity:
|
45
|
+
Max: 7
|
46
|
+
|
47
|
+
Metrics/MethodLength:
|
48
|
+
CountComments: false # count full line comments?
|
49
|
+
Max: 24
|
50
|
+
|
51
|
+
Metrics/ModuleLength:
|
52
|
+
CountComments: false # count full line comments?
|
53
|
+
Max: 200
|
54
|
+
|
55
|
+
Metrics/ParameterLists:
|
56
|
+
Max: 5
|
57
|
+
CountKeywordArgs: true
|
58
|
+
|
59
|
+
Metrics/PerceivedComplexity:
|
60
|
+
Max: 12
|
61
|
+
|
62
|
+
Style/Documentation:
|
63
|
+
Enabled: false
|
64
|
+
|
65
|
+
Style/FrozenStringLiteralComment:
|
66
|
+
Enabled: false
|
67
|
+
|
68
|
+
Style/HashEachMethods:
|
69
|
+
Enabled: true
|
70
|
+
|
71
|
+
Style/HashTransformKeys:
|
72
|
+
Enabled: true
|
73
|
+
|
74
|
+
Style/HashTransformValues:
|
75
|
+
Enabled: true
|
76
|
+
|
77
|
+
Style/ModuleFunction:
|
78
|
+
Enabled: false
|
79
|
+
|
80
|
+
Style/RescueModifier:
|
81
|
+
Exclude:
|
82
|
+
- spec/**/*
|
83
|
+
|
84
|
+
Naming/PredicateName:
|
85
|
+
Enabled: false
|
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
2.7.0
|
data/CODE_OF_CONDUCT.md
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
# Contributor Covenant Code of Conduct
|
2
|
+
|
3
|
+
## Our Pledge
|
4
|
+
|
5
|
+
In the interest of fostering an open and welcoming environment, we as
|
6
|
+
contributors and maintainers pledge to making participation in our project and
|
7
|
+
our community a harassment-free experience for everyone, regardless of age, body
|
8
|
+
size, disability, ethnicity, gender identity and expression, level of experience,
|
9
|
+
nationality, personal appearance, race, religion, or sexual identity and
|
10
|
+
orientation.
|
11
|
+
|
12
|
+
## Our Standards
|
13
|
+
|
14
|
+
Examples of behavior that contributes to creating a positive environment
|
15
|
+
include:
|
16
|
+
|
17
|
+
* Using welcoming and inclusive language
|
18
|
+
* Being respectful of differing viewpoints and experiences
|
19
|
+
* Gracefully accepting constructive criticism
|
20
|
+
* Focusing on what is best for the community
|
21
|
+
* Showing empathy towards other community members
|
22
|
+
|
23
|
+
Examples of unacceptable behavior by participants include:
|
24
|
+
|
25
|
+
* The use of sexualized language or imagery and unwelcome sexual attention or
|
26
|
+
advances
|
27
|
+
* Trolling, insulting/derogatory comments, and personal or political attacks
|
28
|
+
* Public or private harassment
|
29
|
+
* Publishing others' private information, such as a physical or electronic
|
30
|
+
address, without explicit permission
|
31
|
+
* Other conduct which could reasonably be considered inappropriate in a
|
32
|
+
professional setting
|
33
|
+
|
34
|
+
## Our Responsibilities
|
35
|
+
|
36
|
+
Project maintainers are responsible for clarifying the standards of acceptable
|
37
|
+
behavior and are expected to take appropriate and fair corrective action in
|
38
|
+
response to any instances of unacceptable behavior.
|
39
|
+
|
40
|
+
Project maintainers have the right and responsibility to remove, edit, or
|
41
|
+
reject comments, commits, code, wiki edits, issues, and other contributions
|
42
|
+
that are not aligned to this Code of Conduct, or to ban temporarily or
|
43
|
+
permanently any contributor for other behaviors that they deem inappropriate,
|
44
|
+
threatening, offensive, or harmful.
|
45
|
+
|
46
|
+
## Scope
|
47
|
+
|
48
|
+
This Code of Conduct applies both within project spaces and in public spaces
|
49
|
+
when an individual is representing the project or its community. Examples of
|
50
|
+
representing a project or community include using an official project e-mail
|
51
|
+
address, posting via an official social media account, or acting as an appointed
|
52
|
+
representative at an online or offline event. Representation of a project may be
|
53
|
+
further defined and clarified by project maintainers.
|
54
|
+
|
55
|
+
## Enforcement
|
56
|
+
|
57
|
+
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
58
|
+
reported by contacting the project team at juan.ramallo[at]rootstrap.com or santiago.bartesaghi[at]rootstrap.com. All
|
59
|
+
complaints will be reviewed and investigated and will result in a response that
|
60
|
+
is deemed necessary and appropriate to the circumstances. The project team is
|
61
|
+
obligated to maintain confidentiality with regard to the reporter of an incident.
|
62
|
+
Further details of specific enforcement policies may be posted separately.
|
63
|
+
|
64
|
+
Project maintainers who do not follow or enforce the Code of Conduct in good
|
65
|
+
faith may face temporary or permanent repercussions as determined by other
|
66
|
+
members of the project's leadership.
|
67
|
+
|
68
|
+
## Attribution
|
69
|
+
|
70
|
+
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
|
71
|
+
available at [https://contributor-covenant.org/version/1/4][version]
|
72
|
+
|
73
|
+
[homepage]: https://contributor-covenant.org
|
74
|
+
[version]: https://contributor-covenant.org/version/1/4/
|
data/CONTRIBUTING.md
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
## Contributing ##
|
2
|
+
|
3
|
+
You can contribute to this repo if you have an issue, found a bug or think there's some functionality required that would add value to the gem. To do so, please check if there's not already an [issue](https://github.com/rootstrap/yaaf/issues) for that, if you find there's not, create a new one with as much detail as possible.
|
4
|
+
|
5
|
+
If you want to contribute with code as well, please follow the next steps:
|
6
|
+
|
7
|
+
1. Read, understand and agree to our [code of conduct](https://github.com/rootstrap/yaaf/blob/master/CODE_OF_CONDUCT.md)
|
8
|
+
2. [Fork the repo](https://help.github.com/articles/about-forks/)
|
9
|
+
3. Clone the project into your machine:
|
10
|
+
`$ git clone git@github.com:rootstrap/yaaf.git`
|
11
|
+
4. Access the repo:
|
12
|
+
`$ cd yaaf`
|
13
|
+
5. Create your feature/bugfix branch:
|
14
|
+
`$ git checkout -b your_new_feature`
|
15
|
+
or
|
16
|
+
`$ git checkout -b fix/your_fix` in case of a bug fix
|
17
|
+
(if your PR is to address an existing issue, it would be good to name the branch after the issue, for example: if you are trying to solve issue 182, then a good idea for the branch name would be `182_your_new_feature`)
|
18
|
+
6. Write tests for your changes (feature/bug)
|
19
|
+
7. Code your (feature/bugfix)
|
20
|
+
8. Run the code analysis tool by doing:
|
21
|
+
`$ rake code_analysis`
|
22
|
+
9. Run the tests:
|
23
|
+
`$ bundle exec rspec`
|
24
|
+
All tests must pass. If all tests (both code analysis and rspec) do pass, then you are ready to go to the next step:
|
25
|
+
10. Commit your changes:
|
26
|
+
`$ git commit -m 'Your feature or bugfix title'`
|
27
|
+
11. Push to the branch `$ git push origin your_new_feature`
|
28
|
+
12. Create a new [pull request](https://help.github.com/articles/creating-a-pull-request/)
|
29
|
+
|
30
|
+
Some helpful guides that will help you know how we work:
|
31
|
+
1. [Code review](https://github.com/rootstrap/tech-guides/tree/master/code-review)
|
32
|
+
2. [GIT workflow](https://github.com/rootstrap/tech-guides/tree/master/git)
|
33
|
+
3. [Ruby style guide](https://github.com/rootstrap/tech-guides/tree/master/ruby)
|
34
|
+
4. [Rails style guide](https://github.com/rootstrap/tech-guides/blob/master/ruby/rails.md)
|
35
|
+
5. [RSpec style guide](https://github.com/rootstrap/tech-guides/blob/master/ruby/rspec/README.md)
|
36
|
+
|
37
|
+
For more information or guides like the ones mentioned above, please check our [tech guides](https://github.com/rootstrap/tech-guides). Keep in mind that the more you know about these guides, the easier it will be for your code to get approved and merged.
|
38
|
+
|
39
|
+
Note: We work with one commit per pull request, so if you make your commit and realize you were missing something or want to add something more to it, don't create a new commit with the changes, but use `$ git commit --amend` instead. This same principle also applies for when changes are requested on an open pull request.
|
40
|
+
|
41
|
+
|
42
|
+
Thank you very much for your time and for considering helping in this project.
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2020 Rootstrap
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,272 @@
|
|
1
|
+
# YAAF
|
2
|
+
|
3
|
+
![CI](https://github.com/rootstrap/yaaf/workflows/CI/badge.svg)
|
4
|
+
[![Maintainability](https://api.codeclimate.com/v1/badges/c3dea064e1003b700260/maintainability)](https://codeclimate.com/github/rootstrap/yaaf/maintainability)
|
5
|
+
[![Test Coverage](https://api.codeclimate.com/v1/badges/c3dea064e1003b700260/test_coverage)](https://codeclimate.com/github/rootstrap/yaaf/test_coverage)
|
6
|
+
|
7
|
+
YAAF (Yet Another Active Form) is a gem that let you create form objects in an easy and Rails friendly way. It makes use of `ActiveRecord` and `ActiveModel` features in order to provide you with a form object that behaves pretty much like a Rails model, and still be completely configurable.
|
8
|
+
|
9
|
+
We were going to name this gem `ActiveForm` to follow Rails naming conventions but given there are a lot of form object gems named like that we preferred to go with `YAAF`.
|
10
|
+
|
11
|
+
## Table of Contents
|
12
|
+
|
13
|
+
- [Motivation](#motivation)
|
14
|
+
- [Installation](#installation)
|
15
|
+
- [Usage](#usage)
|
16
|
+
- [Setting up a form object](#setting-up-a-form-object)
|
17
|
+
- [#initialize](#initialize)
|
18
|
+
- [#valid?](#valid?)
|
19
|
+
- [#invalid?](#invalid?)
|
20
|
+
- [#errors](#errors)
|
21
|
+
- [#save](#save)
|
22
|
+
- [#save!](#save!)
|
23
|
+
- [Validations](#validations)
|
24
|
+
- [Callbacks](#callbacks)
|
25
|
+
- [Sample app](#sample-app)
|
26
|
+
- [Links](#links)
|
27
|
+
- [Development](#development)
|
28
|
+
- [Contributing](#contributing)
|
29
|
+
- [License](#license)
|
30
|
+
- [Code of Conduct](#code-of-conduct)
|
31
|
+
- [Credits](#credits)
|
32
|
+
|
33
|
+
## Motivation
|
34
|
+
|
35
|
+
Form Objects is a design pattern that allows us to:
|
36
|
+
1. Keep views, models and controllers clean
|
37
|
+
2. Create/update multiple models at the same time
|
38
|
+
3. Keep business logic validations out of models
|
39
|
+
|
40
|
+
There are some other form objects gems but we felt none of them provided us all the features that we expected:
|
41
|
+
1. Form objects that behaves like Rails models
|
42
|
+
2. Simple to use and to understand the implementation (no magic)
|
43
|
+
3. Easy to customize
|
44
|
+
4. Gem is well tested and maintained
|
45
|
+
|
46
|
+
For this reason we decided to build our own Form Object implementation. After several months in production without issues we decided to extract it into a gem to share it with the community.
|
47
|
+
|
48
|
+
If you want to learn more about Form Objects you can check out [these great articles](#links).
|
49
|
+
|
50
|
+
## Installation
|
51
|
+
|
52
|
+
Add this line to your application's Gemfile:
|
53
|
+
|
54
|
+
```ruby
|
55
|
+
gem 'yaaf'
|
56
|
+
```
|
57
|
+
|
58
|
+
And then execute:
|
59
|
+
|
60
|
+
$ bundle install
|
61
|
+
|
62
|
+
Or install it yourself as:
|
63
|
+
|
64
|
+
$ gem install yaaf
|
65
|
+
|
66
|
+
## Usage
|
67
|
+
|
68
|
+
In the following sections we explain some basic usage and the API provided by the gem. You can also find some recipes [here](https://rootstrap.github.io/yaaf).
|
69
|
+
|
70
|
+
### Setting up a form object
|
71
|
+
|
72
|
+
In order to use a `YAAF` form object, you need to inherit from `YAAF::Form` and define the `@models` of the form, for example:
|
73
|
+
```ruby
|
74
|
+
# app/forms/registration_form.rb
|
75
|
+
|
76
|
+
class RegistrationForm < YAAF::Form
|
77
|
+
attr_accessor :user_attributes
|
78
|
+
|
79
|
+
def initialize(attributes)
|
80
|
+
super(attributes)
|
81
|
+
@models = [user]
|
82
|
+
end
|
83
|
+
|
84
|
+
def user
|
85
|
+
@user ||= User.new(user_attributes)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
```
|
89
|
+
|
90
|
+
By doing that you can work with your form object in your controller such as you'd do with a model.
|
91
|
+
```ruby
|
92
|
+
# app/controllers/registrations_controller.rb
|
93
|
+
|
94
|
+
class RegistrationsController < ApplicationController
|
95
|
+
def create
|
96
|
+
registration_form = RegistrationForm.new(user_attributes: user_params)
|
97
|
+
|
98
|
+
if registration_form.save
|
99
|
+
redirect_to registration.user
|
100
|
+
else
|
101
|
+
render :new
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
private
|
106
|
+
|
107
|
+
def user_params
|
108
|
+
params.require(:user).permit(:email, :password, :password_confirmation)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
```
|
112
|
+
|
113
|
+
Form objects supports calls to [valid?](#valid?), [invalid?](#invalid?), [errors](#errors), [save](#save), [save!](#save!), such as any `ActiveModel` model. The return values match the corresponding `ActiveModel` methods.
|
114
|
+
|
115
|
+
When saving or validating a form object, it will automatically validate all its models and promote the error to the form object itself, so they are accessible to you directly from the form object.
|
116
|
+
|
117
|
+
Form objects can also define validations like:
|
118
|
+
```ruby
|
119
|
+
# app/forms/registration_form.rb
|
120
|
+
|
121
|
+
class RegistrationForm < YAAF::Form
|
122
|
+
validates :phone, presence: true
|
123
|
+
validate :a_custom_validation
|
124
|
+
|
125
|
+
# ...
|
126
|
+
|
127
|
+
def a_custom_validation
|
128
|
+
# ...
|
129
|
+
end
|
130
|
+
end
|
131
|
+
```
|
132
|
+
|
133
|
+
Validations can be skipped the same way as for `ActiveModel` models:
|
134
|
+
```ruby
|
135
|
+
# app/controllers/registrations_controller.rb
|
136
|
+
|
137
|
+
class RegistrationsController < ApplicationController
|
138
|
+
def create
|
139
|
+
registration_form = RegistrationForm.new(user_attributes: user_params)
|
140
|
+
|
141
|
+
registration_form.save!(validate: false)
|
142
|
+
end
|
143
|
+
|
144
|
+
private
|
145
|
+
|
146
|
+
def user_params
|
147
|
+
params.require(:user).permit(:email, :password, :password_confirmation)
|
148
|
+
end
|
149
|
+
end
|
150
|
+
```
|
151
|
+
|
152
|
+
Form objects support the saving of multiple models at the same time, to prevent leaving the system in a bad state all the models are saved within a DB transaction.
|
153
|
+
|
154
|
+
A good practice would be to create an empty `ApplicationForm` and make your form objects inherit from it. This way you have a centralized place to customize any `YAAF` default behavior you would like.
|
155
|
+
|
156
|
+
```ruby
|
157
|
+
class ApplicationForm < YAAF::Form
|
158
|
+
# Customized behavior
|
159
|
+
end
|
160
|
+
```
|
161
|
+
|
162
|
+
### #initialize
|
163
|
+
|
164
|
+
The `.new` method should be called with the arguments that the form object needs.
|
165
|
+
|
166
|
+
When initializing a `YAAF` form object, there are two things to keep in mind
|
167
|
+
1. You need to define the `@models` instance variables to be an array of all the models that you want to be validated/saved within the form object.
|
168
|
+
2. To leverage `ActiveModel`'s features, you can call `super` to automatically make the attributes be stored in instance variables. If you use it, make sure to also add `attr_accessor`s, otherwise `ActiveModel` will fail.
|
169
|
+
|
170
|
+
### #valid?
|
171
|
+
|
172
|
+
The `#valid?` method will perform both the form object validations and the models validations. It will return `true` or `false` and store the errors in the form object.
|
173
|
+
|
174
|
+
By default `YAAF` form objects will store model errors in the form object under the same key. For example if a model has an `email` attribute that had an error, the form object will provide an error under the `email` key (e.g. `form_object.errors[:email]`).
|
175
|
+
|
176
|
+
### #invalid?
|
177
|
+
|
178
|
+
The `#invalid?` method is exactly the same as the `.valid?` method but will return the opposite boolean value.
|
179
|
+
|
180
|
+
### #errors
|
181
|
+
|
182
|
+
The `#errors` method will return an `ActiveModel::Errors` object such as any other `ActiveModel` model.
|
183
|
+
|
184
|
+
### #save
|
185
|
+
|
186
|
+
The `#save` method will run validations. If it's invalid it will return `false`, otherwise it will save all the models within a DB transaction and return `true`.
|
187
|
+
|
188
|
+
Defined callbacks will be called in the following order:
|
189
|
+
- `before_validation`
|
190
|
+
- `after_validation`
|
191
|
+
- `before_save`
|
192
|
+
- `after_save`
|
193
|
+
- `after_commit/after_rollback`
|
194
|
+
|
195
|
+
Options:
|
196
|
+
- If `validate: false` is send as options to the `save` call, it will skip validations.
|
197
|
+
|
198
|
+
### #save!
|
199
|
+
|
200
|
+
The `#save!` method is exactly the same as the `.save` method, just that if it is invalid it will raise an exception.
|
201
|
+
|
202
|
+
### Validations
|
203
|
+
|
204
|
+
`YAAF` form objects support validations the same way as `ActiveModel` models. For example:
|
205
|
+
|
206
|
+
```ruby
|
207
|
+
class RegistrationForm < YAAF::Form
|
208
|
+
validates :email, presence: true
|
209
|
+
validate :some_custom_validation
|
210
|
+
|
211
|
+
# ...
|
212
|
+
end
|
213
|
+
```
|
214
|
+
|
215
|
+
### Callbacks
|
216
|
+
|
217
|
+
`YAAF` form objects support validations the same way as `ActiveModel` models. For example:
|
218
|
+
|
219
|
+
```ruby
|
220
|
+
class RegistrationForm < YAAF::Form
|
221
|
+
before_validation :normalize_attributes
|
222
|
+
after_commit :send_confirmation_email
|
223
|
+
|
224
|
+
# ...
|
225
|
+
end
|
226
|
+
```
|
227
|
+
|
228
|
+
Available callbacks are (listed in execution order):
|
229
|
+
- `before_validation`
|
230
|
+
- `after_validation`
|
231
|
+
- `before_save`
|
232
|
+
- `after_save`
|
233
|
+
- `after_commit/after_rollback`
|
234
|
+
|
235
|
+
## Sample app
|
236
|
+
|
237
|
+
You can find a sample app making use of the gem [here](https://yaaf-examples.herokuapp.com). Its code is also open source, and you can find it [here](https://github.com/rootstrap/yaaf-examples).
|
238
|
+
|
239
|
+
## Links
|
240
|
+
|
241
|
+
- [How to improve maintainability in Rails applications using patterns. Part I](https://www.rootstrap.com/blog/2020/02/14/how-to-improve-maintainability-in-rails-applications-using-patterns-part-i/)
|
242
|
+
- [7 Patterns to Refactor Fat ActiveRecord Models](https://codeclimate.com/blog/7-ways-to-decompose-fat-activerecord-models/)
|
243
|
+
- [ActiveModel Form Objects](https://thoughtbot.com/blog/activemodel-form-objects)
|
244
|
+
- [Form Objects Design Pattern](https://gorails.com/episodes/form-objects-design-pattern)
|
245
|
+
- [Form Object from Railscasts](https://makandracards.com/alexander-m/42271-form-object-from-railscasts)
|
246
|
+
- [Validating Form Objects](https://revs.runtime-revolution.com/validating-form-objects-8058fefc7b89)
|
247
|
+
- [Disciplined Rails: Form Object Techniques & Patterns — Part 1](https://medium.com/@jaryl/disciplined-rails-form-object-techniques-patterns-part-1-23cfffcaf429)
|
248
|
+
- [Complex form objects with Rails](https://www.codementor.io/@victor_hazbun/complex-form-objects-in-rails-qval6b8kt)
|
249
|
+
|
250
|
+
## Development
|
251
|
+
|
252
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `bundle exec rspec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
253
|
+
|
254
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
255
|
+
|
256
|
+
## Contributing
|
257
|
+
|
258
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/rootstrap/yaaf. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/rootstrap/yaaf/blob/master/CODE_OF_CONDUCT.md).
|
259
|
+
|
260
|
+
## License
|
261
|
+
|
262
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
263
|
+
|
264
|
+
## Code of Conduct
|
265
|
+
|
266
|
+
Everyone interacting in the YAAF project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/rootstrap/yaaf/blob/master/CODE_OF_CONDUCT.md).
|
267
|
+
|
268
|
+
## Credits
|
269
|
+
|
270
|
+
YAAF is maintained by [Rootstrap](http://www.rootstrap.com) with the help of our [contributors](https://github.com/rootstrap/yaaf/contributors).
|
271
|
+
|
272
|
+
[<img src="https://s3-us-west-1.amazonaws.com/rootstrap.com/img/rs.png" width="100"/>](http://www.rootstrap.com)
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'bundler/setup'
|
5
|
+
require 'yaaf'
|
6
|
+
|
7
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
8
|
+
# with your gem easier. You can also use a different console, if you like.
|
9
|
+
|
10
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
11
|
+
# require "pry"
|
12
|
+
# Pry.start
|
13
|
+
|
14
|
+
require 'irb'
|
15
|
+
IRB.start(__FILE__)
|
data/bin/setup
ADDED
data/docs/README.md
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
# 📖 Documentation
|
2
|
+
|
3
|
+
## Usage
|
4
|
+
|
5
|
+
[Check usage section in the main README](https://github.com/rootstrap/yaaf/blob/master/README.md#usage)
|
6
|
+
|
7
|
+
## Recipes
|
8
|
+
|
9
|
+
- [YAAF with Simple Form](recipes/simple_form.md)
|
10
|
+
|
11
|
+
## Credits
|
12
|
+
|
13
|
+
YAAF is maintained by [Rootstrap](http://www.rootstrap.com) with the help of our [contributors](https://github.com/rootstrap/yaaf/contributors).
|
14
|
+
|
15
|
+
[<img src="https://s3-us-west-1.amazonaws.com/rootstrap.com/img/rs.png" width="100"/>](http://www.rootstrap.com)
|
@@ -0,0 +1,117 @@
|
|
1
|
+
# Using YAAF with Simple Form
|
2
|
+
|
3
|
+
[Simple Form](https://github.com/heartcombo/simple_form) is a gem to create visual forms in an easy and flexible manner.
|
4
|
+
|
5
|
+
## Usage
|
6
|
+
|
7
|
+
Pass a `YAAF::Form` object instance to the `simple_form_for` helper method.
|
8
|
+
|
9
|
+
For example, in a library management system (a pretty miminal one), the form to create books will look like this:
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
# app/forms/book_form.rb
|
13
|
+
|
14
|
+
class BookForm < YAAF::Form
|
15
|
+
attr_accessor :name, :isbn
|
16
|
+
|
17
|
+
def initialize(attributes)
|
18
|
+
super(attributes)
|
19
|
+
|
20
|
+
@models = [book]
|
21
|
+
end
|
22
|
+
|
23
|
+
def book
|
24
|
+
@book ||= Book.new(name: name, isbn: isbn)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
```
|
28
|
+
|
29
|
+
|
30
|
+
```ruby
|
31
|
+
# app/controllers/books_controller.rb
|
32
|
+
|
33
|
+
class BooksController < ApplicationController
|
34
|
+
def new
|
35
|
+
@book = BookForm.new
|
36
|
+
end
|
37
|
+
end
|
38
|
+
```
|
39
|
+
|
40
|
+
```erb
|
41
|
+
<%# app/views/books/new.html.erb %>
|
42
|
+
|
43
|
+
<%= simple_form_for(@book, method: :post, url: books_path) do |f| %>
|
44
|
+
<%= f.input :name %>
|
45
|
+
<%= f.input :isbn %>
|
46
|
+
|
47
|
+
<%= f.submit 'Create Book' %>
|
48
|
+
<% end %>
|
49
|
+
```
|
50
|
+
|
51
|
+
## I18n
|
52
|
+
|
53
|
+
In order to make use of translations correctly, we should pass an `as` value to the `simple_form_for` helper method.
|
54
|
+
|
55
|
+
```erb
|
56
|
+
<%# app/views/books/new.html.erb %>
|
57
|
+
|
58
|
+
<%= simple_form_for(@book, as: :book, ...) do |f| %>
|
59
|
+
...
|
60
|
+
```
|
61
|
+
|
62
|
+
So you now can write your translations as:
|
63
|
+
|
64
|
+
```yaml
|
65
|
+
# app/config/locales/simple_form.en.yml
|
66
|
+
|
67
|
+
en:
|
68
|
+
simple_form:
|
69
|
+
...
|
70
|
+
|
71
|
+
labels:
|
72
|
+
book:
|
73
|
+
name: Book Name
|
74
|
+
isbn: International Standard Book Number
|
75
|
+
```
|
76
|
+
|
77
|
+
When using the `f.submit` helper method from Simple Form, the method `model_name` will be used to display the
|
78
|
+
button's text. If this is not defined it will display: "Create Book Form".
|
79
|
+
You can use a translation directly in the view to avoid overriding this method.
|
80
|
+
|
81
|
+
```ruby
|
82
|
+
# app/forms/book_form.rb
|
83
|
+
|
84
|
+
...
|
85
|
+
|
86
|
+
def model_name
|
87
|
+
Book.model_name
|
88
|
+
end
|
89
|
+
|
90
|
+
...
|
91
|
+
```
|
92
|
+
|
93
|
+
More info about how Simple Form translates forms [here](https://github.com/heartcombo/simple_form#i18n).
|
94
|
+
|
95
|
+
## Persisted?
|
96
|
+
|
97
|
+
Define the `persisted?` method in your form object to let Simple Form know if the object is being created or upated.
|
98
|
+
|
99
|
+
```ruby
|
100
|
+
# app/forms/book_form.rb
|
101
|
+
|
102
|
+
...
|
103
|
+
|
104
|
+
def persisted?
|
105
|
+
book.persisted? # Or you can directly make it return false
|
106
|
+
end
|
107
|
+
|
108
|
+
...
|
109
|
+
```
|
110
|
+
|
111
|
+
## Got questions?
|
112
|
+
|
113
|
+
Feel free to [create an issue](https://github.com/rootstrap/yaaf/issues) and we'll discuss about it.
|
114
|
+
|
115
|
+
YAAF is maintained by [Rootstrap](http://www.rootstrap.com) with the help of our [contributors](https://github.com/rootstrap/yaaf/contributors).
|
116
|
+
|
117
|
+
[<img src="https://s3-us-west-1.amazonaws.com/rootstrap.com/img/rs.png" width="100"/>](http://www.rootstrap.com)
|
data/lib/yaaf.rb
ADDED
data/lib/yaaf/form.rb
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module YAAF
|
4
|
+
# Parent class for form objects
|
5
|
+
class Form
|
6
|
+
include ::ActiveModel::Model
|
7
|
+
include ::ActiveModel::Validations::Callbacks
|
8
|
+
include ::ActiveRecord::Transactions
|
9
|
+
define_model_callbacks :save
|
10
|
+
|
11
|
+
validate :validate_models
|
12
|
+
|
13
|
+
def save(options = {})
|
14
|
+
unless options[:validate] == false
|
15
|
+
return false if invalid?
|
16
|
+
end
|
17
|
+
|
18
|
+
run_callbacks :commit do
|
19
|
+
save_in_transaction(options)
|
20
|
+
end
|
21
|
+
|
22
|
+
true
|
23
|
+
end
|
24
|
+
|
25
|
+
def save!(options = {})
|
26
|
+
save(options) || raise(ActiveRecord::RecordNotSaved.new('Failed to save the form', self))
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
attr_accessor :models
|
32
|
+
|
33
|
+
def promote_errors(model)
|
34
|
+
model.errors.each do |attribute, message|
|
35
|
+
errors.add(attribute, message)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def save_in_transaction(options)
|
40
|
+
::ActiveRecord::Base.transaction do
|
41
|
+
run_callbacks :save do
|
42
|
+
save_models(options)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
rescue Exception => e
|
46
|
+
handle_transaction_rollback(e)
|
47
|
+
end
|
48
|
+
|
49
|
+
def save_models(options)
|
50
|
+
models.map { |model| model.save!(options) }
|
51
|
+
end
|
52
|
+
|
53
|
+
def validate_models
|
54
|
+
models.each do |model|
|
55
|
+
promote_errors(model) if model.invalid?
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def handle_transaction_rollback(exception)
|
60
|
+
run_callbacks :rollback
|
61
|
+
raise exception
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
data/lib/yaaf/version.rb
ADDED
data/yaaf.gemspec
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'lib/yaaf/version'
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = 'yaaf'
|
7
|
+
spec.version = YAAF::VERSION
|
8
|
+
spec.authors = ['Juan Manuel Ramallo', 'Santiago Bartesaghi']
|
9
|
+
spec.email = ['juan.ramallo@rootstrap.com']
|
10
|
+
|
11
|
+
spec.summary = 'Easing the form object pattern in Rails applications.'
|
12
|
+
spec.homepage = 'https://github.com/rootstrap/yaaf'
|
13
|
+
spec.license = 'MIT'
|
14
|
+
spec.required_ruby_version = Gem::Requirement.new('>= 2.3.0')
|
15
|
+
|
16
|
+
spec.metadata['homepage_uri'] = spec.homepage
|
17
|
+
spec.metadata['source_code_uri'] = 'https://github.com/rootstrap/yaaf'
|
18
|
+
|
19
|
+
# Specify which files should be added to the gem when it is released.
|
20
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
21
|
+
spec.files = Dir.chdir(File.expand_path(__dir__)) do
|
22
|
+
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
23
|
+
end
|
24
|
+
spec.bindir = 'exe'
|
25
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
26
|
+
spec.require_paths = ['lib']
|
27
|
+
|
28
|
+
# # Production dependencies
|
29
|
+
spec.add_dependency 'activemodel', ['>= 4', '< 7']
|
30
|
+
spec.add_dependency 'activerecord', ['>= 4', '< 7']
|
31
|
+
|
32
|
+
spec.add_development_dependency 'database_cleaner-active_record', '~> 1.8.0'
|
33
|
+
spec.add_development_dependency 'rake', '~> 13.0.1'
|
34
|
+
spec.add_development_dependency 'reek', '~> 5.6.0'
|
35
|
+
spec.add_development_dependency 'rspec', '~> 3.9.0'
|
36
|
+
spec.add_development_dependency 'rubocop', '~> 0.80.0'
|
37
|
+
spec.add_development_dependency 'simplecov', '~> 0.17.1'
|
38
|
+
spec.add_development_dependency 'sqlite3', '~> 1.4.2'
|
39
|
+
end
|
metadata
ADDED
@@ -0,0 +1,204 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: yaaf
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Juan Manuel Ramallo
|
8
|
+
- Santiago Bartesaghi
|
9
|
+
autorequire:
|
10
|
+
bindir: exe
|
11
|
+
cert_chain: []
|
12
|
+
date: 2020-04-07 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: activemodel
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
requirements:
|
18
|
+
- - ">="
|
19
|
+
- !ruby/object:Gem::Version
|
20
|
+
version: '4'
|
21
|
+
- - "<"
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: '7'
|
24
|
+
type: :runtime
|
25
|
+
prerelease: false
|
26
|
+
version_requirements: !ruby/object:Gem::Requirement
|
27
|
+
requirements:
|
28
|
+
- - ">="
|
29
|
+
- !ruby/object:Gem::Version
|
30
|
+
version: '4'
|
31
|
+
- - "<"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '7'
|
34
|
+
- !ruby/object:Gem::Dependency
|
35
|
+
name: activerecord
|
36
|
+
requirement: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '4'
|
41
|
+
- - "<"
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '7'
|
44
|
+
type: :runtime
|
45
|
+
prerelease: false
|
46
|
+
version_requirements: !ruby/object:Gem::Requirement
|
47
|
+
requirements:
|
48
|
+
- - ">="
|
49
|
+
- !ruby/object:Gem::Version
|
50
|
+
version: '4'
|
51
|
+
- - "<"
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '7'
|
54
|
+
- !ruby/object:Gem::Dependency
|
55
|
+
name: database_cleaner-active_record
|
56
|
+
requirement: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - "~>"
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: 1.8.0
|
61
|
+
type: :development
|
62
|
+
prerelease: false
|
63
|
+
version_requirements: !ruby/object:Gem::Requirement
|
64
|
+
requirements:
|
65
|
+
- - "~>"
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: 1.8.0
|
68
|
+
- !ruby/object:Gem::Dependency
|
69
|
+
name: rake
|
70
|
+
requirement: !ruby/object:Gem::Requirement
|
71
|
+
requirements:
|
72
|
+
- - "~>"
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
version: 13.0.1
|
75
|
+
type: :development
|
76
|
+
prerelease: false
|
77
|
+
version_requirements: !ruby/object:Gem::Requirement
|
78
|
+
requirements:
|
79
|
+
- - "~>"
|
80
|
+
- !ruby/object:Gem::Version
|
81
|
+
version: 13.0.1
|
82
|
+
- !ruby/object:Gem::Dependency
|
83
|
+
name: reek
|
84
|
+
requirement: !ruby/object:Gem::Requirement
|
85
|
+
requirements:
|
86
|
+
- - "~>"
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
version: 5.6.0
|
89
|
+
type: :development
|
90
|
+
prerelease: false
|
91
|
+
version_requirements: !ruby/object:Gem::Requirement
|
92
|
+
requirements:
|
93
|
+
- - "~>"
|
94
|
+
- !ruby/object:Gem::Version
|
95
|
+
version: 5.6.0
|
96
|
+
- !ruby/object:Gem::Dependency
|
97
|
+
name: rspec
|
98
|
+
requirement: !ruby/object:Gem::Requirement
|
99
|
+
requirements:
|
100
|
+
- - "~>"
|
101
|
+
- !ruby/object:Gem::Version
|
102
|
+
version: 3.9.0
|
103
|
+
type: :development
|
104
|
+
prerelease: false
|
105
|
+
version_requirements: !ruby/object:Gem::Requirement
|
106
|
+
requirements:
|
107
|
+
- - "~>"
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: 3.9.0
|
110
|
+
- !ruby/object:Gem::Dependency
|
111
|
+
name: rubocop
|
112
|
+
requirement: !ruby/object:Gem::Requirement
|
113
|
+
requirements:
|
114
|
+
- - "~>"
|
115
|
+
- !ruby/object:Gem::Version
|
116
|
+
version: 0.80.0
|
117
|
+
type: :development
|
118
|
+
prerelease: false
|
119
|
+
version_requirements: !ruby/object:Gem::Requirement
|
120
|
+
requirements:
|
121
|
+
- - "~>"
|
122
|
+
- !ruby/object:Gem::Version
|
123
|
+
version: 0.80.0
|
124
|
+
- !ruby/object:Gem::Dependency
|
125
|
+
name: simplecov
|
126
|
+
requirement: !ruby/object:Gem::Requirement
|
127
|
+
requirements:
|
128
|
+
- - "~>"
|
129
|
+
- !ruby/object:Gem::Version
|
130
|
+
version: 0.17.1
|
131
|
+
type: :development
|
132
|
+
prerelease: false
|
133
|
+
version_requirements: !ruby/object:Gem::Requirement
|
134
|
+
requirements:
|
135
|
+
- - "~>"
|
136
|
+
- !ruby/object:Gem::Version
|
137
|
+
version: 0.17.1
|
138
|
+
- !ruby/object:Gem::Dependency
|
139
|
+
name: sqlite3
|
140
|
+
requirement: !ruby/object:Gem::Requirement
|
141
|
+
requirements:
|
142
|
+
- - "~>"
|
143
|
+
- !ruby/object:Gem::Version
|
144
|
+
version: 1.4.2
|
145
|
+
type: :development
|
146
|
+
prerelease: false
|
147
|
+
version_requirements: !ruby/object:Gem::Requirement
|
148
|
+
requirements:
|
149
|
+
- - "~>"
|
150
|
+
- !ruby/object:Gem::Version
|
151
|
+
version: 1.4.2
|
152
|
+
description:
|
153
|
+
email:
|
154
|
+
- juan.ramallo@rootstrap.com
|
155
|
+
executables: []
|
156
|
+
extensions: []
|
157
|
+
extra_rdoc_files: []
|
158
|
+
files:
|
159
|
+
- ".github/workflows/ci.yml"
|
160
|
+
- ".gitignore"
|
161
|
+
- ".reek.yml"
|
162
|
+
- ".rspec"
|
163
|
+
- ".rubocop.yml"
|
164
|
+
- ".ruby-version"
|
165
|
+
- CODE_OF_CONDUCT.md
|
166
|
+
- CONTRIBUTING.md
|
167
|
+
- Gemfile
|
168
|
+
- LICENSE.txt
|
169
|
+
- README.md
|
170
|
+
- Rakefile
|
171
|
+
- bin/console
|
172
|
+
- bin/setup
|
173
|
+
- docs/README.md
|
174
|
+
- docs/recipes/simple_form.md
|
175
|
+
- lib/yaaf.rb
|
176
|
+
- lib/yaaf/form.rb
|
177
|
+
- lib/yaaf/version.rb
|
178
|
+
- yaaf.gemspec
|
179
|
+
homepage: https://github.com/rootstrap/yaaf
|
180
|
+
licenses:
|
181
|
+
- MIT
|
182
|
+
metadata:
|
183
|
+
homepage_uri: https://github.com/rootstrap/yaaf
|
184
|
+
source_code_uri: https://github.com/rootstrap/yaaf
|
185
|
+
post_install_message:
|
186
|
+
rdoc_options: []
|
187
|
+
require_paths:
|
188
|
+
- lib
|
189
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
190
|
+
requirements:
|
191
|
+
- - ">="
|
192
|
+
- !ruby/object:Gem::Version
|
193
|
+
version: 2.3.0
|
194
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
195
|
+
requirements:
|
196
|
+
- - ">="
|
197
|
+
- !ruby/object:Gem::Version
|
198
|
+
version: '0'
|
199
|
+
requirements: []
|
200
|
+
rubygems_version: 3.0.3
|
201
|
+
signing_key:
|
202
|
+
specification_version: 4
|
203
|
+
summary: Easing the form object pattern in Rails applications.
|
204
|
+
test_files: []
|