ph_model 0.0.1
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 +7 -0
- data/.codeclimate.yml +10 -0
- data/.gitignore +8 -0
- data/.hound.yml +2 -0
- data/.reek +10 -0
- data/.rubocop.hound.yml +261 -0
- data/.rubocop.yml +55 -0
- data/.travis.yml +7 -0
- data/CHANGELOG.md +0 -0
- data/DEPLOYING.md +25 -0
- data/Gemfile +3 -0
- data/LICENSE.txt +12 -0
- data/README.md +48 -0
- data/Rakefile +46 -0
- data/lib/active_model/validations/collection_items_validator/array_attribute_getter.rb +42 -0
- data/lib/active_model/validations/collection_items_validator/array_attribute_reader.rb +15 -0
- data/lib/active_model/validations/collection_items_validator/inner_validator_builder.rb +48 -0
- data/lib/active_model/validations/collection_items_validator.rb +56 -0
- data/lib/active_model/validations/type_validator.rb +26 -0
- data/lib/ph_model/concerns/validated_factory.rb +25 -0
- data/lib/ph_model/concerns.rb +7 -0
- data/lib/ph_model/validation_failed.rb +5 -0
- data/lib/ph_model/version.rb +4 -0
- data/lib/ph_model.rb +45 -0
- data/ph_model.gemspec +36 -0
- metadata +235 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA1:
|
|
3
|
+
metadata.gz: 72c97b1d45c2bffecce992988d661288f985e781
|
|
4
|
+
data.tar.gz: fb1daf87242301f9a6390beaeee59c0668fee155
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: a1a90cd481163e0288594665b53e01a8aa72202f219f787b35c6b1c7bef33b3745f930a3858d777782ce5183bbf0dc2f761ff119b438004282a98c4f65d0e17c
|
|
7
|
+
data.tar.gz: 6b14a99582e733abc6553750e5d90d0469f82c759b5b49eb4ad828bcd914a2c6c97326b683fb55c8e5d84daa68e40a2adf942e4df940e13197f91916cf1d4963
|
data/.codeclimate.yml
ADDED
data/.gitignore
ADDED
data/.hound.yml
ADDED
data/.reek
ADDED
data/.rubocop.hound.yml
ADDED
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
# this is the default from hound's github, do not modify
|
|
2
|
+
AllCops:
|
|
3
|
+
Exclude:
|
|
4
|
+
- db/schema.rb
|
|
5
|
+
|
|
6
|
+
AccessorMethodName:
|
|
7
|
+
Enabled: false
|
|
8
|
+
|
|
9
|
+
ActionFilter:
|
|
10
|
+
Enabled: false
|
|
11
|
+
|
|
12
|
+
Alias:
|
|
13
|
+
Enabled: false
|
|
14
|
+
|
|
15
|
+
ArrayJoin:
|
|
16
|
+
Enabled: false
|
|
17
|
+
|
|
18
|
+
AsciiComments:
|
|
19
|
+
Enabled: false
|
|
20
|
+
|
|
21
|
+
AsciiIdentifiers:
|
|
22
|
+
Enabled: false
|
|
23
|
+
|
|
24
|
+
Attr:
|
|
25
|
+
Enabled: false
|
|
26
|
+
|
|
27
|
+
BlockNesting:
|
|
28
|
+
Enabled: false
|
|
29
|
+
|
|
30
|
+
CaseEquality:
|
|
31
|
+
Enabled: false
|
|
32
|
+
|
|
33
|
+
CharacterLiteral:
|
|
34
|
+
Enabled: false
|
|
35
|
+
|
|
36
|
+
ClassAndModuleChildren:
|
|
37
|
+
Enabled: false
|
|
38
|
+
|
|
39
|
+
ClassLength:
|
|
40
|
+
Enabled: false
|
|
41
|
+
|
|
42
|
+
ClassVars:
|
|
43
|
+
Enabled: false
|
|
44
|
+
|
|
45
|
+
CollectionMethods:
|
|
46
|
+
PreferredMethods:
|
|
47
|
+
find: detect
|
|
48
|
+
reduce: inject
|
|
49
|
+
collect: map
|
|
50
|
+
find_all: select
|
|
51
|
+
|
|
52
|
+
ColonMethodCall:
|
|
53
|
+
Enabled: false
|
|
54
|
+
|
|
55
|
+
CommentAnnotation:
|
|
56
|
+
Enabled: false
|
|
57
|
+
|
|
58
|
+
CyclomaticComplexity:
|
|
59
|
+
Enabled: false
|
|
60
|
+
|
|
61
|
+
Delegate:
|
|
62
|
+
Enabled: false
|
|
63
|
+
|
|
64
|
+
DeprecatedHashMethods:
|
|
65
|
+
Enabled: false
|
|
66
|
+
|
|
67
|
+
Documentation:
|
|
68
|
+
Enabled: false
|
|
69
|
+
|
|
70
|
+
DotPosition:
|
|
71
|
+
EnforcedStyle: trailing
|
|
72
|
+
|
|
73
|
+
DoubleNegation:
|
|
74
|
+
Enabled: false
|
|
75
|
+
|
|
76
|
+
EachWithObject:
|
|
77
|
+
Enabled: false
|
|
78
|
+
|
|
79
|
+
EmptyLiteral:
|
|
80
|
+
Enabled: false
|
|
81
|
+
|
|
82
|
+
Encoding:
|
|
83
|
+
Enabled: false
|
|
84
|
+
|
|
85
|
+
EvenOdd:
|
|
86
|
+
Enabled: false
|
|
87
|
+
|
|
88
|
+
FileName:
|
|
89
|
+
Enabled: false
|
|
90
|
+
|
|
91
|
+
FlipFlop:
|
|
92
|
+
Enabled: false
|
|
93
|
+
|
|
94
|
+
FormatString:
|
|
95
|
+
Enabled: false
|
|
96
|
+
|
|
97
|
+
GlobalVars:
|
|
98
|
+
Enabled: false
|
|
99
|
+
|
|
100
|
+
GuardClause:
|
|
101
|
+
Enabled: false
|
|
102
|
+
|
|
103
|
+
IfUnlessModifier:
|
|
104
|
+
Enabled: false
|
|
105
|
+
|
|
106
|
+
IfWithSemicolon:
|
|
107
|
+
Enabled: false
|
|
108
|
+
|
|
109
|
+
InlineComment:
|
|
110
|
+
Enabled: false
|
|
111
|
+
|
|
112
|
+
Lambda:
|
|
113
|
+
Enabled: false
|
|
114
|
+
|
|
115
|
+
LambdaCall:
|
|
116
|
+
Enabled: false
|
|
117
|
+
|
|
118
|
+
LineEndConcatenation:
|
|
119
|
+
Enabled: false
|
|
120
|
+
|
|
121
|
+
LineLength:
|
|
122
|
+
Max: 120
|
|
123
|
+
AllowURI: true
|
|
124
|
+
|
|
125
|
+
MethodLength:
|
|
126
|
+
Enabled: false
|
|
127
|
+
|
|
128
|
+
ModuleFunction:
|
|
129
|
+
Enabled: false
|
|
130
|
+
|
|
131
|
+
NegatedIf:
|
|
132
|
+
Enabled: false
|
|
133
|
+
|
|
134
|
+
NegatedWhile:
|
|
135
|
+
Enabled: false
|
|
136
|
+
|
|
137
|
+
Next:
|
|
138
|
+
Enabled: false
|
|
139
|
+
|
|
140
|
+
NilComparison:
|
|
141
|
+
Enabled: false
|
|
142
|
+
|
|
143
|
+
Not:
|
|
144
|
+
Enabled: false
|
|
145
|
+
|
|
146
|
+
NumericLiterals:
|
|
147
|
+
Enabled: false
|
|
148
|
+
|
|
149
|
+
OneLineConditional:
|
|
150
|
+
Enabled: false
|
|
151
|
+
|
|
152
|
+
OpMethod:
|
|
153
|
+
Enabled: false
|
|
154
|
+
|
|
155
|
+
ParameterLists:
|
|
156
|
+
Enabled: false
|
|
157
|
+
|
|
158
|
+
PercentLiteralDelimiters:
|
|
159
|
+
Enabled: false
|
|
160
|
+
|
|
161
|
+
PerlBackrefs:
|
|
162
|
+
Enabled: false
|
|
163
|
+
|
|
164
|
+
PredicateName:
|
|
165
|
+
NamePrefixBlacklist:
|
|
166
|
+
- is_
|
|
167
|
+
|
|
168
|
+
Proc:
|
|
169
|
+
Enabled: false
|
|
170
|
+
|
|
171
|
+
RaiseArgs:
|
|
172
|
+
Enabled: false
|
|
173
|
+
|
|
174
|
+
RegexpLiteral:
|
|
175
|
+
Enabled: false
|
|
176
|
+
|
|
177
|
+
SelfAssignment:
|
|
178
|
+
Enabled: false
|
|
179
|
+
|
|
180
|
+
SingleLineBlockParams:
|
|
181
|
+
Enabled: false
|
|
182
|
+
|
|
183
|
+
SingleLineMethods:
|
|
184
|
+
Enabled: false
|
|
185
|
+
|
|
186
|
+
SignalException:
|
|
187
|
+
Enabled: false
|
|
188
|
+
|
|
189
|
+
SpecialGlobalVars:
|
|
190
|
+
Enabled: false
|
|
191
|
+
|
|
192
|
+
StringLiterals:
|
|
193
|
+
EnforcedStyle: double_quotes
|
|
194
|
+
|
|
195
|
+
VariableInterpolation:
|
|
196
|
+
Enabled: false
|
|
197
|
+
|
|
198
|
+
TrailingComma:
|
|
199
|
+
Enabled: false
|
|
200
|
+
|
|
201
|
+
TrivialAccessors:
|
|
202
|
+
Enabled: false
|
|
203
|
+
|
|
204
|
+
VariableInterpolation:
|
|
205
|
+
Enabled: false
|
|
206
|
+
|
|
207
|
+
WhenThen:
|
|
208
|
+
Enabled: false
|
|
209
|
+
|
|
210
|
+
WhileUntilModifier:
|
|
211
|
+
Enabled: false
|
|
212
|
+
|
|
213
|
+
WordArray:
|
|
214
|
+
Enabled: false
|
|
215
|
+
|
|
216
|
+
# Lint
|
|
217
|
+
|
|
218
|
+
AmbiguousOperator:
|
|
219
|
+
Enabled: false
|
|
220
|
+
|
|
221
|
+
AmbiguousRegexpLiteral:
|
|
222
|
+
Enabled: false
|
|
223
|
+
|
|
224
|
+
AssignmentInCondition:
|
|
225
|
+
Enabled: false
|
|
226
|
+
|
|
227
|
+
ConditionPosition:
|
|
228
|
+
Enabled: false
|
|
229
|
+
|
|
230
|
+
DeprecatedClassMethods:
|
|
231
|
+
Enabled: false
|
|
232
|
+
|
|
233
|
+
ElseLayout:
|
|
234
|
+
Enabled: false
|
|
235
|
+
|
|
236
|
+
HandleExceptions:
|
|
237
|
+
Enabled: false
|
|
238
|
+
|
|
239
|
+
InvalidCharacterLiteral:
|
|
240
|
+
Enabled: false
|
|
241
|
+
|
|
242
|
+
LiteralInCondition:
|
|
243
|
+
Enabled: false
|
|
244
|
+
|
|
245
|
+
LiteralInInterpolation:
|
|
246
|
+
Enabled: false
|
|
247
|
+
|
|
248
|
+
Loop:
|
|
249
|
+
Enabled: false
|
|
250
|
+
|
|
251
|
+
ParenthesesAsGroupedExpression:
|
|
252
|
+
Enabled: false
|
|
253
|
+
|
|
254
|
+
RequireParentheses:
|
|
255
|
+
Enabled: false
|
|
256
|
+
|
|
257
|
+
UnderscorePrefixedVariableName:
|
|
258
|
+
Enabled: false
|
|
259
|
+
|
|
260
|
+
Void:
|
|
261
|
+
Enabled: false
|
data/.rubocop.yml
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
inherit_from:
|
|
2
|
+
- .rubocop.hound.yml
|
|
3
|
+
|
|
4
|
+
AllCops:
|
|
5
|
+
TargetRubyVersion: 2.1
|
|
6
|
+
Exclude:
|
|
7
|
+
- '*.gemspec'
|
|
8
|
+
- 'Gemfile'
|
|
9
|
+
|
|
10
|
+
Style/EmptyLinesAroundClassBody:
|
|
11
|
+
Enabled: false
|
|
12
|
+
|
|
13
|
+
Style/EmptyLinesAroundModuleBody:
|
|
14
|
+
Enabled: false
|
|
15
|
+
|
|
16
|
+
Style/EmptyLinesAroundMethodBody:
|
|
17
|
+
Enabled: false
|
|
18
|
+
|
|
19
|
+
Style/ClassCheck:
|
|
20
|
+
Enabled: false
|
|
21
|
+
# we don't care about kind_of? vs is_a?
|
|
22
|
+
|
|
23
|
+
Style/StringLiterals:
|
|
24
|
+
Enabled: false
|
|
25
|
+
|
|
26
|
+
Style/FileName:
|
|
27
|
+
Enabled: false
|
|
28
|
+
|
|
29
|
+
Style/RedundantException:
|
|
30
|
+
Enabled: false
|
|
31
|
+
|
|
32
|
+
Style/SignalException:
|
|
33
|
+
Enabled: false
|
|
34
|
+
|
|
35
|
+
Style/BlockDelimiters:
|
|
36
|
+
Enabled: false
|
|
37
|
+
|
|
38
|
+
Style/CollectionMethods:
|
|
39
|
+
PreferredMethods:
|
|
40
|
+
detect: find
|
|
41
|
+
|
|
42
|
+
# Github's PR width is 120 characters
|
|
43
|
+
Metrics/LineLength:
|
|
44
|
+
Max: 120
|
|
45
|
+
AllowURI: true
|
|
46
|
+
|
|
47
|
+
# Align with the style guide, we don't prefer anything
|
|
48
|
+
Style/CollectionMethods:
|
|
49
|
+
Enabled: false
|
|
50
|
+
|
|
51
|
+
Metrics/AbcSize:
|
|
52
|
+
Description: A calculated magnitude based on number of assignments, branches, and
|
|
53
|
+
conditions.
|
|
54
|
+
Enabled: true
|
|
55
|
+
Max: 30
|
data/.travis.yml
ADDED
data/CHANGELOG.md
ADDED
|
File without changes
|
data/DEPLOYING.md
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
## Setup
|
|
2
|
+
|
|
3
|
+
In order to deploy a new version of the gem into the wild ...
|
|
4
|
+
|
|
5
|
+
You will need to configure your github api token for the changelog.
|
|
6
|
+
|
|
7
|
+
Generate a new token for changelogs [here](https://github.com/settings/tokens/new).
|
|
8
|
+
|
|
9
|
+
add:
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
export CHANGELOG_GITHUB_TOKEN=YOUR_CHANGELOG_API_TOKEN
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
somewhere in your shell init. (ie .zshrc or simillar)
|
|
16
|
+
|
|
17
|
+
## Deploying
|
|
18
|
+
|
|
19
|
+
1. Update `lib/ph_model/version.rb`
|
|
20
|
+
2. Commit the changed files with the version number eg: `1.8.0`
|
|
21
|
+
3. Push this to git
|
|
22
|
+
4. Run `rake release`
|
|
23
|
+
5. Run `rake changelog` (has to be ran after release since its based on github tagging)
|
|
24
|
+
6. Commit the changed changelog named something like `changelog for 1.8.0`
|
|
25
|
+
7. Push this to git
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
|
|
2
|
+
documentation files (the "Software"), to deal in the Software without restriction, including without limitation
|
|
3
|
+
the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
|
4
|
+
and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
5
|
+
|
|
6
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of
|
|
7
|
+
the Software.
|
|
8
|
+
|
|
9
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
|
|
10
|
+
THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
|
|
11
|
+
OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
|
12
|
+
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# ph_model
|
|
2
|
+
|
|
3
|
+
* [Homepage](https://rubygems.org/gems/ph_model)
|
|
4
|
+
* [Documentation](http://rubydoc.info/gems/ph_model/frames)
|
|
5
|
+
* [Email](mailto:piotr.banasik at gmail.com)
|
|
6
|
+
|
|
7
|
+
## Description
|
|
8
|
+
|
|
9
|
+
[](https://travis-ci.org/payrollhero/ph_model)
|
|
10
|
+
[](https://codeclimate.com/github/payrollhero/ph_model)
|
|
11
|
+
[](https://codeclimate.com/github/payrollhero/ph_model)
|
|
12
|
+
[](https://gemnasium.com/payrollhero/ph_model)
|
|
13
|
+
|
|
14
|
+
This Gem basically marries ActiveModel and ActiveAttr is a nice package.
|
|
15
|
+
|
|
16
|
+
The general format for this is that you make classes mixing in PhModel, and then you can use them easier
|
|
17
|
+
as data objects.
|
|
18
|
+
|
|
19
|
+
Eg:
|
|
20
|
+
```ruby
|
|
21
|
+
class MyModel
|
|
22
|
+
include PhModel
|
|
23
|
+
|
|
24
|
+
attribute :name, type: String
|
|
25
|
+
attribute :age, type: Fixnum
|
|
26
|
+
|
|
27
|
+
validates :name, presence: true
|
|
28
|
+
validates :age, presence: true
|
|
29
|
+
end
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
And then .. you're meant to build these things via `.build` to ensure that they're valid when constructed.
|
|
33
|
+
|
|
34
|
+
Eg:
|
|
35
|
+
```ruby
|
|
36
|
+
model = MyModel.build(name: "John", age: 21)
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
And if you were to try to construct it invalid, you'd get:
|
|
40
|
+
|
|
41
|
+
```ruby
|
|
42
|
+
model = MyModel.build(name: "John")
|
|
43
|
+
# Raises: PhModel::ValidationFailed: MyModel is invalid: Age can't be blank
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Copyright
|
|
47
|
+
|
|
48
|
+
Copyright (c) 2015 PayrollHero
|
data/Rakefile
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
require 'bundler/gem_tasks'
|
|
2
|
+
|
|
3
|
+
require 'rubygems/tasks'
|
|
4
|
+
Gem::Tasks.new(release: false)
|
|
5
|
+
|
|
6
|
+
require 'rspec/core/rake_task'
|
|
7
|
+
RSpec::Core::RakeTask.new
|
|
8
|
+
|
|
9
|
+
task :test do
|
|
10
|
+
sh "rspec"
|
|
11
|
+
sh "reek"
|
|
12
|
+
sh "rubocop"
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
task default: :spec
|
|
16
|
+
|
|
17
|
+
desc "copy in PayrollHero's current style config files"
|
|
18
|
+
task :styleguide do
|
|
19
|
+
require 'faraday'
|
|
20
|
+
require 'pry'
|
|
21
|
+
base = "https://raw.githubusercontent.com/payrollhero/styleguide/master/"
|
|
22
|
+
files = %w{
|
|
23
|
+
.rubocop.hound.yml
|
|
24
|
+
.rubocop.yml
|
|
25
|
+
.reek
|
|
26
|
+
.codeclimate.yml
|
|
27
|
+
}
|
|
28
|
+
files.each do |file|
|
|
29
|
+
puts "Fetching #{file} ..."
|
|
30
|
+
url = "#{base}#{file}"
|
|
31
|
+
rsp = Faraday.get(url)
|
|
32
|
+
unless rsp.status == 200
|
|
33
|
+
$stderr.puts "failing fetching: #{url}"
|
|
34
|
+
$stderr.puts " response: #{rsp.status}: #{rsp.body}"
|
|
35
|
+
exit 1
|
|
36
|
+
end
|
|
37
|
+
File.open(file, "w") do |fh|
|
|
38
|
+
fh.write(rsp.body)
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
desc "Updates the changelog"
|
|
44
|
+
task :changelog do
|
|
45
|
+
sh "github_changelog_generator payrollhero/ph_model --simple-list"
|
|
46
|
+
end
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
module ActiveModel
|
|
2
|
+
module Validations
|
|
3
|
+
# Decides how to get the value from array or other type of attribute.
|
|
4
|
+
class CollectionItemsValidator::ArrayAttributeGetter
|
|
5
|
+
class << self
|
|
6
|
+
def get(attribute, when_array:, when_normal:)
|
|
7
|
+
new(attribute, when_array: when_array, when_normal: when_normal).get
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def initialize(attribute, when_array:, when_normal:)
|
|
12
|
+
@attribute = attribute
|
|
13
|
+
@when_array = when_array
|
|
14
|
+
@when_normal = when_normal
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def get
|
|
18
|
+
if match_data
|
|
19
|
+
when_array.call attibute_name, index
|
|
20
|
+
else
|
|
21
|
+
when_normal.call
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
private
|
|
26
|
+
|
|
27
|
+
attr_reader :attribute, :when_array, :when_normal
|
|
28
|
+
|
|
29
|
+
def match_data
|
|
30
|
+
@match_data ||= /\A(.*)\[\d*\]\Z/.match(attribute)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def attibute_name
|
|
34
|
+
match_data[1].to_sym
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def index
|
|
38
|
+
match_data[2].to_i
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
module ActiveModel
|
|
2
|
+
module Validations
|
|
3
|
+
# Adds support for validation to read attribute names like foo[0].
|
|
4
|
+
# Mainly used to validate collections.
|
|
5
|
+
module CollectionItemsValidator::ArrayAttributeReader
|
|
6
|
+
def read_attribute_for_validation(attribute)
|
|
7
|
+
CollectionItemsValidator::ArrayAttributeGetter.get(
|
|
8
|
+
attribute,
|
|
9
|
+
when_array: -> (attribute_name, index) { super(attribute_name)[index] },
|
|
10
|
+
when_normal: -> { super }
|
|
11
|
+
)
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
module ActiveModel
|
|
2
|
+
module Validations
|
|
3
|
+
# Builds the inner validators for the collection items validator
|
|
4
|
+
class CollectionItemsValidator::InnerValidatorBuilder
|
|
5
|
+
class << self
|
|
6
|
+
def build(validator_name, options)
|
|
7
|
+
new(validator_name, options).build
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def initialize(validator_name, options)
|
|
12
|
+
@validator_name = validator_name
|
|
13
|
+
@options = options
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def build
|
|
17
|
+
validator_class.new inner_options.merge(attributes: [:base])
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
private
|
|
21
|
+
|
|
22
|
+
attr_reader :validator_name, :options
|
|
23
|
+
|
|
24
|
+
def validator_class
|
|
25
|
+
name = "#{validator_name.to_s.camelize}Validator"
|
|
26
|
+
|
|
27
|
+
begin
|
|
28
|
+
name.include?("::") ? name.constantize : ActiveModel::Validations.const_get(name)
|
|
29
|
+
rescue NameError
|
|
30
|
+
raise ArgumentError, "Unknown validator: '#{validator_name}'"
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def inner_options
|
|
35
|
+
case options
|
|
36
|
+
when TrueClass
|
|
37
|
+
{}
|
|
38
|
+
when Hash
|
|
39
|
+
options
|
|
40
|
+
when Range, Array
|
|
41
|
+
{ in: options }
|
|
42
|
+
else
|
|
43
|
+
{ with: options }
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
module ActiveModel
|
|
2
|
+
module Validations
|
|
3
|
+
# Adds collection items validation to ActiveModel::Model.
|
|
4
|
+
#
|
|
5
|
+
# Usage:
|
|
6
|
+
# @example
|
|
7
|
+
# class FooBar
|
|
8
|
+
# include ActiveModel::Model
|
|
9
|
+
#
|
|
10
|
+
# attr_accessor :kinds
|
|
11
|
+
#
|
|
12
|
+
# validates :kinds, collection_items { type: Symbol, inclusion: { in: [:foo, :bar] } }
|
|
13
|
+
# end
|
|
14
|
+
class CollectionItemsValidator < ActiveModel::EachValidator
|
|
15
|
+
extend ActiveSupport::Autoload
|
|
16
|
+
|
|
17
|
+
autoload :ArrayAttributeReader
|
|
18
|
+
autoload :ArrayAttributeGetter
|
|
19
|
+
autoload :InnerValidatorBuilder
|
|
20
|
+
|
|
21
|
+
def initialize(*)
|
|
22
|
+
super.tap { set_inner_validators }
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def validate_each(record, attribute, value)
|
|
26
|
+
if value.kind_of? Enumerable
|
|
27
|
+
validate_collection(record, attribute, value)
|
|
28
|
+
else
|
|
29
|
+
record.errors.add attribute, 'must be a collection'
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
private
|
|
34
|
+
|
|
35
|
+
attr_reader :inner_validators
|
|
36
|
+
|
|
37
|
+
def set_inner_validators
|
|
38
|
+
inner_validation_options = options.except(:class)
|
|
39
|
+
@inner_validators = inner_validation_options.map do |validator_name, inner_options|
|
|
40
|
+
InnerValidatorBuilder.build validator_name, inner_options
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def validator_value_pairs_for(value)
|
|
45
|
+
inner_validators.product(value.each_with_index.to_a)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def validate_collection(record, attribute, value)
|
|
49
|
+
record.extend ArrayAttributeReader
|
|
50
|
+
validator_value_pairs_for(value).each do |validator, (item, index)|
|
|
51
|
+
validator.validate_each record, :"#{attribute}[#{index}]", item
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
module ActiveModel
|
|
2
|
+
module Validations
|
|
3
|
+
# Adds type validation to ActiveModel::Model.
|
|
4
|
+
#
|
|
5
|
+
# Usage:
|
|
6
|
+
# @example
|
|
7
|
+
# class FooBar
|
|
8
|
+
# include ActiveModel::Model
|
|
9
|
+
#
|
|
10
|
+
# attr_accessor :date
|
|
11
|
+
#
|
|
12
|
+
# validates :date, type: Date
|
|
13
|
+
# end
|
|
14
|
+
class TypeValidator < ActiveModel::EachValidator
|
|
15
|
+
def validate_each(record, attribute, value)
|
|
16
|
+
classes = Array(options[:with] || options[:in])
|
|
17
|
+
unless classes.any? { |klass| value.is_a? klass }
|
|
18
|
+
allowed_classes = classes.to_sentence two_words_connector: " or ",
|
|
19
|
+
last_word_connector: ", or "
|
|
20
|
+
|
|
21
|
+
record.errors[attribute] << (options[:message] || "must be a #{allowed_classes}")
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
module PhModel
|
|
2
|
+
module Concerns
|
|
3
|
+
# Validates factories.
|
|
4
|
+
module ValidatedFactory
|
|
5
|
+
extend ActiveSupport::Concern
|
|
6
|
+
|
|
7
|
+
included do |model|
|
|
8
|
+
class << model
|
|
9
|
+
private :new
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# Validates factories.
|
|
14
|
+
module ClassMethods
|
|
15
|
+
def build(*args)
|
|
16
|
+
new(*args).tap do |model|
|
|
17
|
+
unless model.valid?
|
|
18
|
+
raise ValidationFailed, "#{name} is invalid: #{model.errors.full_messages.join("\n")}"
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
data/lib/ph_model.rb
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
require 'active_support/all'
|
|
2
|
+
require 'active_model'
|
|
3
|
+
require 'active_attr'
|
|
4
|
+
|
|
5
|
+
ActiveModel::Validations # ensure its loaded since we're patching it
|
|
6
|
+
|
|
7
|
+
module ActiveModel
|
|
8
|
+
module Validations
|
|
9
|
+
extend ActiveSupport::Autoload
|
|
10
|
+
autoload :TypeValidator
|
|
11
|
+
autoload :CollectionItemsValidator
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# PayrollHero's mashup of ActiveModel and ActiveAttr with some of our own twists
|
|
16
|
+
module PhModel
|
|
17
|
+
extend ActiveSupport::Concern
|
|
18
|
+
extend ActiveSupport::Autoload
|
|
19
|
+
|
|
20
|
+
include ActiveAttr::BasicModel
|
|
21
|
+
include ActiveAttr::AttributeDefaults
|
|
22
|
+
include ActiveAttr::QueryAttributes
|
|
23
|
+
include ActiveAttr::MassAssignment
|
|
24
|
+
|
|
25
|
+
# Monkey patch #assign_attributes inside ActiveAttr::MassAssignment
|
|
26
|
+
# so that it doesn't blindly ignore attempting to assign attributes which do not
|
|
27
|
+
# exist
|
|
28
|
+
#
|
|
29
|
+
# TODO: try to submit something upstream to deal with this
|
|
30
|
+
def assign_attributes(new_attributes, options = {})
|
|
31
|
+
sanitized_new_attributes = sanitize_for_mass_assignment_if_sanitizer new_attributes, options
|
|
32
|
+
|
|
33
|
+
sanitized_new_attributes.each do |name, value|
|
|
34
|
+
writer = "#{name}="
|
|
35
|
+
# originally:
|
|
36
|
+
# send writer, value if respond_to? writer
|
|
37
|
+
send writer, value
|
|
38
|
+
end if sanitized_new_attributes
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
autoload :Concerns
|
|
42
|
+
autoload :ValidationFailed
|
|
43
|
+
|
|
44
|
+
include Concerns::ValidatedFactory
|
|
45
|
+
end
|
data/ph_model.gemspec
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
require File.expand_path('../lib/ph_model/version', __FILE__)
|
|
4
|
+
|
|
5
|
+
Gem::Specification.new do |gem|
|
|
6
|
+
gem.name = 'ph_model'
|
|
7
|
+
gem.version = PhModel::VERSION
|
|
8
|
+
gem.authors = ['Piotr Banasik']
|
|
9
|
+
gem.email = 'piotr@payrollhero.com'
|
|
10
|
+
|
|
11
|
+
gem.summary = 'ph-model -- active_model, active_attr brought together at last'
|
|
12
|
+
gem.description = 'Because why do less if you can do more with non db models'
|
|
13
|
+
gem.homepage = 'https://github.com/payrollhero/ph_model'
|
|
14
|
+
gem.license = 'MIT'
|
|
15
|
+
|
|
16
|
+
gem.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
|
17
|
+
gem.bindir = 'exe'
|
|
18
|
+
gem.executables = gem.files.grep(%r{^bin/}).map { |f| File.basename(f) }
|
|
19
|
+
gem.require_paths = ['lib']
|
|
20
|
+
|
|
21
|
+
gem.add_runtime_dependency 'activesupport', '> 3.2'
|
|
22
|
+
gem.add_runtime_dependency 'activemodel', '> 3.2'
|
|
23
|
+
gem.add_runtime_dependency 'active_attr', '~> 0.8'
|
|
24
|
+
|
|
25
|
+
gem.add_development_dependency 'faraday'
|
|
26
|
+
gem.add_development_dependency 'bundler', '~> 1.0'
|
|
27
|
+
gem.add_development_dependency 'rake', '~> 10.0'
|
|
28
|
+
gem.add_development_dependency 'rspec', '~> 3.0'
|
|
29
|
+
gem.add_development_dependency 'rubygems-tasks', '~> 0.2'
|
|
30
|
+
gem.add_development_dependency 'pry', '> 0'
|
|
31
|
+
gem.add_development_dependency 'github_changelog_generator', '~> 1.6'
|
|
32
|
+
|
|
33
|
+
# static analysis gems
|
|
34
|
+
gem.add_development_dependency 'rubocop', '~> 0.36.0'
|
|
35
|
+
gem.add_development_dependency 'reek', '~> 3.10'
|
|
36
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: ph_model
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.0.1
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Piotr Banasik
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: exe
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2016-02-03 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: activesupport
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - ">"
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '3.2'
|
|
20
|
+
type: :runtime
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - ">"
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: '3.2'
|
|
27
|
+
- !ruby/object:Gem::Dependency
|
|
28
|
+
name: activemodel
|
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - ">"
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: '3.2'
|
|
34
|
+
type: :runtime
|
|
35
|
+
prerelease: false
|
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
+
requirements:
|
|
38
|
+
- - ">"
|
|
39
|
+
- !ruby/object:Gem::Version
|
|
40
|
+
version: '3.2'
|
|
41
|
+
- !ruby/object:Gem::Dependency
|
|
42
|
+
name: active_attr
|
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
|
44
|
+
requirements:
|
|
45
|
+
- - "~>"
|
|
46
|
+
- !ruby/object:Gem::Version
|
|
47
|
+
version: '0.8'
|
|
48
|
+
type: :runtime
|
|
49
|
+
prerelease: false
|
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
51
|
+
requirements:
|
|
52
|
+
- - "~>"
|
|
53
|
+
- !ruby/object:Gem::Version
|
|
54
|
+
version: '0.8'
|
|
55
|
+
- !ruby/object:Gem::Dependency
|
|
56
|
+
name: faraday
|
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
|
58
|
+
requirements:
|
|
59
|
+
- - ">="
|
|
60
|
+
- !ruby/object:Gem::Version
|
|
61
|
+
version: '0'
|
|
62
|
+
type: :development
|
|
63
|
+
prerelease: false
|
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
65
|
+
requirements:
|
|
66
|
+
- - ">="
|
|
67
|
+
- !ruby/object:Gem::Version
|
|
68
|
+
version: '0'
|
|
69
|
+
- !ruby/object:Gem::Dependency
|
|
70
|
+
name: bundler
|
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
|
72
|
+
requirements:
|
|
73
|
+
- - "~>"
|
|
74
|
+
- !ruby/object:Gem::Version
|
|
75
|
+
version: '1.0'
|
|
76
|
+
type: :development
|
|
77
|
+
prerelease: false
|
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
79
|
+
requirements:
|
|
80
|
+
- - "~>"
|
|
81
|
+
- !ruby/object:Gem::Version
|
|
82
|
+
version: '1.0'
|
|
83
|
+
- !ruby/object:Gem::Dependency
|
|
84
|
+
name: rake
|
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
|
86
|
+
requirements:
|
|
87
|
+
- - "~>"
|
|
88
|
+
- !ruby/object:Gem::Version
|
|
89
|
+
version: '10.0'
|
|
90
|
+
type: :development
|
|
91
|
+
prerelease: false
|
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
93
|
+
requirements:
|
|
94
|
+
- - "~>"
|
|
95
|
+
- !ruby/object:Gem::Version
|
|
96
|
+
version: '10.0'
|
|
97
|
+
- !ruby/object:Gem::Dependency
|
|
98
|
+
name: rspec
|
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
|
100
|
+
requirements:
|
|
101
|
+
- - "~>"
|
|
102
|
+
- !ruby/object:Gem::Version
|
|
103
|
+
version: '3.0'
|
|
104
|
+
type: :development
|
|
105
|
+
prerelease: false
|
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
107
|
+
requirements:
|
|
108
|
+
- - "~>"
|
|
109
|
+
- !ruby/object:Gem::Version
|
|
110
|
+
version: '3.0'
|
|
111
|
+
- !ruby/object:Gem::Dependency
|
|
112
|
+
name: rubygems-tasks
|
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
|
114
|
+
requirements:
|
|
115
|
+
- - "~>"
|
|
116
|
+
- !ruby/object:Gem::Version
|
|
117
|
+
version: '0.2'
|
|
118
|
+
type: :development
|
|
119
|
+
prerelease: false
|
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
121
|
+
requirements:
|
|
122
|
+
- - "~>"
|
|
123
|
+
- !ruby/object:Gem::Version
|
|
124
|
+
version: '0.2'
|
|
125
|
+
- !ruby/object:Gem::Dependency
|
|
126
|
+
name: pry
|
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
|
128
|
+
requirements:
|
|
129
|
+
- - ">"
|
|
130
|
+
- !ruby/object:Gem::Version
|
|
131
|
+
version: '0'
|
|
132
|
+
type: :development
|
|
133
|
+
prerelease: false
|
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
135
|
+
requirements:
|
|
136
|
+
- - ">"
|
|
137
|
+
- !ruby/object:Gem::Version
|
|
138
|
+
version: '0'
|
|
139
|
+
- !ruby/object:Gem::Dependency
|
|
140
|
+
name: github_changelog_generator
|
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
|
142
|
+
requirements:
|
|
143
|
+
- - "~>"
|
|
144
|
+
- !ruby/object:Gem::Version
|
|
145
|
+
version: '1.6'
|
|
146
|
+
type: :development
|
|
147
|
+
prerelease: false
|
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
149
|
+
requirements:
|
|
150
|
+
- - "~>"
|
|
151
|
+
- !ruby/object:Gem::Version
|
|
152
|
+
version: '1.6'
|
|
153
|
+
- !ruby/object:Gem::Dependency
|
|
154
|
+
name: rubocop
|
|
155
|
+
requirement: !ruby/object:Gem::Requirement
|
|
156
|
+
requirements:
|
|
157
|
+
- - "~>"
|
|
158
|
+
- !ruby/object:Gem::Version
|
|
159
|
+
version: 0.36.0
|
|
160
|
+
type: :development
|
|
161
|
+
prerelease: false
|
|
162
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
163
|
+
requirements:
|
|
164
|
+
- - "~>"
|
|
165
|
+
- !ruby/object:Gem::Version
|
|
166
|
+
version: 0.36.0
|
|
167
|
+
- !ruby/object:Gem::Dependency
|
|
168
|
+
name: reek
|
|
169
|
+
requirement: !ruby/object:Gem::Requirement
|
|
170
|
+
requirements:
|
|
171
|
+
- - "~>"
|
|
172
|
+
- !ruby/object:Gem::Version
|
|
173
|
+
version: '3.10'
|
|
174
|
+
type: :development
|
|
175
|
+
prerelease: false
|
|
176
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
177
|
+
requirements:
|
|
178
|
+
- - "~>"
|
|
179
|
+
- !ruby/object:Gem::Version
|
|
180
|
+
version: '3.10'
|
|
181
|
+
description: Because why do less if you can do more with non db models
|
|
182
|
+
email: piotr@payrollhero.com
|
|
183
|
+
executables: []
|
|
184
|
+
extensions: []
|
|
185
|
+
extra_rdoc_files: []
|
|
186
|
+
files:
|
|
187
|
+
- ".codeclimate.yml"
|
|
188
|
+
- ".gitignore"
|
|
189
|
+
- ".hound.yml"
|
|
190
|
+
- ".reek"
|
|
191
|
+
- ".rubocop.hound.yml"
|
|
192
|
+
- ".rubocop.yml"
|
|
193
|
+
- ".travis.yml"
|
|
194
|
+
- CHANGELOG.md
|
|
195
|
+
- DEPLOYING.md
|
|
196
|
+
- Gemfile
|
|
197
|
+
- LICENSE.txt
|
|
198
|
+
- README.md
|
|
199
|
+
- Rakefile
|
|
200
|
+
- lib/active_model/validations/collection_items_validator.rb
|
|
201
|
+
- lib/active_model/validations/collection_items_validator/array_attribute_getter.rb
|
|
202
|
+
- lib/active_model/validations/collection_items_validator/array_attribute_reader.rb
|
|
203
|
+
- lib/active_model/validations/collection_items_validator/inner_validator_builder.rb
|
|
204
|
+
- lib/active_model/validations/type_validator.rb
|
|
205
|
+
- lib/ph_model.rb
|
|
206
|
+
- lib/ph_model/concerns.rb
|
|
207
|
+
- lib/ph_model/concerns/validated_factory.rb
|
|
208
|
+
- lib/ph_model/validation_failed.rb
|
|
209
|
+
- lib/ph_model/version.rb
|
|
210
|
+
- ph_model.gemspec
|
|
211
|
+
homepage: https://github.com/payrollhero/ph_model
|
|
212
|
+
licenses:
|
|
213
|
+
- MIT
|
|
214
|
+
metadata: {}
|
|
215
|
+
post_install_message:
|
|
216
|
+
rdoc_options: []
|
|
217
|
+
require_paths:
|
|
218
|
+
- lib
|
|
219
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
220
|
+
requirements:
|
|
221
|
+
- - ">="
|
|
222
|
+
- !ruby/object:Gem::Version
|
|
223
|
+
version: '0'
|
|
224
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
225
|
+
requirements:
|
|
226
|
+
- - ">="
|
|
227
|
+
- !ruby/object:Gem::Version
|
|
228
|
+
version: '0'
|
|
229
|
+
requirements: []
|
|
230
|
+
rubyforge_project:
|
|
231
|
+
rubygems_version: 2.4.5.1
|
|
232
|
+
signing_key:
|
|
233
|
+
specification_version: 4
|
|
234
|
+
summary: ph-model -- active_model, active_attr brought together at last
|
|
235
|
+
test_files: []
|