validator_fn 0.1.6 → 0.2.8
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +2 -2
- data/README.md +86 -23
- data/lib/validator_fn/error.rb +29 -0
- data/lib/validator_fn/version.rb +1 -1
- data/lib/validator_fn.rb +15 -26
- metadata +4 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: cecd9880750c518fcd26fd705b76ffeaf4604fb90af4bd60719ecf37a387d8ee
|
4
|
+
data.tar.gz: d04d0ef810ab4ac5ea7b8914690c1995ffdf913c8ad4a40c5bfa85ce5ce8a817
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 52647b99fdac1ff9dcf399b96d4b5a5becac6748270795cb47f0caa11e1735217239108450418781bf933dabdc0accf3ef3eaf7c9b8feb9fc1bd5f3deabe34d9
|
7
|
+
data.tar.gz: 5c16a63c7a8f261cf8cf76af633dbc448975dd77cbe08074abf2dd8f77cca95b42baa3ce876c08d2f3186d52eee68edd1a94abea6b33440263e617364732d6a3
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
validator_fn (0.1.
|
4
|
+
validator_fn (0.1.8)
|
5
5
|
fn_reader
|
6
6
|
|
7
7
|
GEM
|
@@ -9,7 +9,7 @@ GEM
|
|
9
9
|
specs:
|
10
10
|
coderay (1.1.3)
|
11
11
|
diff-lcs (1.4.4)
|
12
|
-
fn_reader (0.
|
12
|
+
fn_reader (0.2.0)
|
13
13
|
method_source (0.9.2)
|
14
14
|
pry (0.12.2)
|
15
15
|
coderay (~> 1.1.0)
|
data/README.md
CHANGED
@@ -1,9 +1,10 @@
|
|
1
1
|
# ValidatorFn
|
2
2
|
|
3
|
-
ValidatorFn is a collection of very simple lambdas that can be used for validating/transforming
|
4
|
-
data structures.
|
5
|
-
DSL. To help you understand the concepts
|
3
|
+
ValidatorFn is a collection of very simple lambdas that can be used for validating/transforming
|
4
|
+
data structures. It makes use of currying to provide a very composable
|
5
|
+
DSL. To help you understand the concepts, I strongly advise reading [this blog post.](http://blog.martinosis.com/blog/simple-functional-strong-params-in-ruby/).
|
6
6
|
|
7
|
+
It can be very useful for validating structures that come from input, such as configuration files, JSON APIs, test results.
|
7
8
|
|
8
9
|
## Installation
|
9
10
|
|
@@ -23,30 +24,30 @@ Or install it yourself as:
|
|
23
24
|
|
24
25
|
## Usage
|
25
26
|
|
26
|
-
```
|
27
|
+
```ruby
|
27
28
|
require 'validator_fn'
|
28
29
|
include ValidatorFn
|
29
30
|
```
|
30
31
|
|
31
|
-
You can start validating type of an object.
|
32
|
+
You can start validating the type of an object.
|
32
33
|
|
33
|
-
```
|
34
|
+
```ruby
|
34
35
|
is_a.(String).(3)
|
35
36
|
```
|
36
37
|
|
37
|
-
Note that parameters are curried. The first param of `is_a` is the Ruby class
|
38
|
-
In the previous example,
|
38
|
+
Note that parameters are curried. The first param of `is_a` is the Ruby class you want to check the last parameter against.
|
39
|
+
In the previous example, a `ValidatorFn::Error`exception will be raised.
|
39
40
|
|
40
|
-
However
|
41
|
+
However, setting a valid entry as the second parameter will return that last parameter.
|
41
42
|
|
42
|
-
```
|
43
|
+
```ruby
|
43
44
|
is_a.(String).("Joe")
|
44
45
|
# => "Joe"
|
45
46
|
```
|
46
47
|
|
47
48
|
This allows chaining lambdas:
|
48
49
|
|
49
|
-
```
|
50
|
+
```ruby
|
50
51
|
to_int = is_a.(String) >> -> a { Integer(a) }
|
51
52
|
|
52
53
|
to_int.("12")
|
@@ -56,25 +57,91 @@ to_int.("asdf") # will raise an exception
|
|
56
57
|
|
57
58
|
You can validate a hash:
|
58
59
|
|
59
|
-
```
|
60
|
+
```ruby
|
60
61
|
user = hash_of.({name: is_a.(String), age: to_int})
|
61
62
|
user.({name: "", age: "234"})
|
62
63
|
```
|
63
64
|
|
64
|
-
Since we are using curried lambdas, you can compose validators as you which.
|
65
|
+
Since we are using curried lambdas, you can compose validators as you which.
|
65
66
|
|
66
|
-
```
|
67
|
-
postal_code = -> a {
|
67
|
+
```ruby
|
68
|
+
postal_code = -> a {
|
68
69
|
invalid.("Invalid postal code: #{a}") unless a =~ /[a-z]\d[a-z]\s*\d[a-z]\d/i
|
69
70
|
a
|
70
71
|
}
|
71
|
-
contact = hash_of.(user: user,
|
72
|
-
address: hash_of.({ street_number: is_a.(Integer),
|
72
|
+
contact = hash_of.(user: user,
|
73
|
+
address: hash_of.({ street_number: is_a.(Integer),
|
73
74
|
postal_code: postal_code}))
|
74
75
|
```
|
75
76
|
|
76
|
-
This
|
77
|
-
|
77
|
+
This very simple library (100 lines of code) can be extended easily by creating new lambdas.
|
78
|
+
|
79
|
+
## Casting
|
80
|
+
|
81
|
+
You can also apply converter functions to the structure.
|
82
|
+
|
83
|
+
```ruby
|
84
|
+
user = { name: "Joe", created_at: "2020-01-03" }
|
85
|
+
to_date = ->str { Date.parse(str) }
|
86
|
+
user_validator = hash_of.(name: is_a.(String),
|
87
|
+
created_at: is_a.(String) >> to_date)
|
88
|
+
|
89
|
+
user_validator.(user)
|
90
|
+
# => {:name=>"Joe", :created_at=>#<Date: 2020-01-03 ((2458852j,0s,0n),+0s,2299161j)>}
|
91
|
+
```
|
92
|
+
|
93
|
+
This makes it very useful for processing JSON payloads.
|
94
|
+
|
95
|
+
## Code generation
|
96
|
+
|
97
|
+
You can generate validator code from existing structure:
|
98
|
+
|
99
|
+
```ruby
|
100
|
+
require 'openuri'
|
101
|
+
require "json"
|
102
|
+
struct = JSON.parse(URI.open("https://api.github.com/users/defunkt").read)
|
103
|
+
|
104
|
+
require "validator_fn"
|
105
|
+
|
106
|
+
# Generate unformatted code
|
107
|
+
code = ValidatorFn.generate_validator.(struct)
|
108
|
+
|
109
|
+
# You can reformat it using a code formatter
|
110
|
+
require "rufo"
|
111
|
+
puts Rufo.format(code)
|
112
|
+
hash_of.({ "login" => is_a.(String),
|
113
|
+
"id" => is_a.(Integer),
|
114
|
+
"node_id" => is_a.(String),
|
115
|
+
"avatar_url" => is_a.(String),
|
116
|
+
"gravatar_id" => is_a.(String),
|
117
|
+
"url" => is_a.(String),
|
118
|
+
"html_url" => is_a.(String),
|
119
|
+
"followers_url" => is_a.(String),
|
120
|
+
"following_url" => is_a.(String),
|
121
|
+
"gists_url" => is_a.(String),
|
122
|
+
"starred_url" => is_a.(String),
|
123
|
+
"subscriptions_url" => is_a.(String),
|
124
|
+
"organizations_url" => is_a.(String),
|
125
|
+
"repos_url" => is_a.(String),
|
126
|
+
"events_url" => is_a.(String),
|
127
|
+
"received_events_url" => is_a.(String),
|
128
|
+
"type" => is_a.(String),
|
129
|
+
"site_admin" => is_a_bool,
|
130
|
+
"name" => is_a.(String),
|
131
|
+
"company" => any,
|
132
|
+
"blog" => is_a.(String),
|
133
|
+
"location" => any,
|
134
|
+
"email" => any,
|
135
|
+
"hireable" => any,
|
136
|
+
"bio" => is_a.(String),
|
137
|
+
"twitter_username" => any,
|
138
|
+
"public_repos" => is_a.(Integer),
|
139
|
+
"public_gists" => is_a.(Integer),
|
140
|
+
"followers" => is_a.(Integer),
|
141
|
+
"following" => is_a.(Integer),
|
142
|
+
"created_at" => is_a.(String),
|
143
|
+
"updated_at" => is_a.(String) })
|
144
|
+
```
|
78
145
|
|
79
146
|
## Development
|
80
147
|
|
@@ -86,7 +153,6 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
|
|
86
153
|
|
87
154
|
Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/validator_fn. 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/[USERNAME]/validator_fn/blob/master/CODE_OF_CONDUCT.md).
|
88
155
|
|
89
|
-
|
90
156
|
## License
|
91
157
|
|
92
158
|
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
@@ -94,6 +160,3 @@ The gem is available as open source under the terms of the [MIT License](https:/
|
|
94
160
|
## Code of Conduct
|
95
161
|
|
96
162
|
Everyone interacting in the ValidatorFn project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/[USERNAME]/validator_fn/blob/master/CODE_OF_CONDUCT.md).
|
97
|
-
Everyone interacting in the ValidatorFn project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/[USERNAME]/validator_fn/blob/master/CODE_OF_CONDUCT.md).
|
98
|
-
Everyone interacting in the ValidatorFn project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/[USERNAME]/validator_fn/blob/master/CODE_OF_CONDUCT.md).
|
99
|
-
Everyone interacting in the ValidatorFn project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/[USERNAME]/validator_fn/blob/master/CODE_OF_CONDUCT.md).
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module ValidatorFn
|
2
|
+
class Error < StandardError
|
3
|
+
attr_reader :my_msg
|
4
|
+
|
5
|
+
def initialize(msg)
|
6
|
+
@my_msg = msg
|
7
|
+
super(msg)
|
8
|
+
end
|
9
|
+
|
10
|
+
def message(indent = 0)
|
11
|
+
if cause
|
12
|
+
cause_msg = if cause.kind_of?(Error)
|
13
|
+
cause.message(indent + 1)
|
14
|
+
else
|
15
|
+
cause.message
|
16
|
+
end
|
17
|
+
my_msg + "\n" + (" " * (indent + 1)) + cause_msg
|
18
|
+
else
|
19
|
+
my_msg
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
class MissingKey < Error
|
25
|
+
def initialize(key)
|
26
|
+
super("Missing field #{key}")
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
data/lib/validator_fn/version.rb
CHANGED
data/lib/validator_fn.rb
CHANGED
@@ -1,33 +1,10 @@
|
|
1
1
|
require "validator_fn/version"
|
2
|
+
require "validator_fn/error"
|
2
3
|
require "fn_reader"
|
3
4
|
|
4
5
|
module ValidatorFn
|
5
|
-
class Error < StandardError; end
|
6
|
-
|
7
6
|
fn_reader :something, :matches, :either, :array_of, :any, :is_nil,
|
8
|
-
:maybe, :present, :is_a, :int, :hash_of, :invalid, :generate_validator, :handle_error, :error_str, :apply
|
9
|
-
|
10
|
-
class Error < StandardError
|
11
|
-
attr_reader :my_msg
|
12
|
-
|
13
|
-
def initialize(msg)
|
14
|
-
@my_msg = msg
|
15
|
-
super(msg)
|
16
|
-
end
|
17
|
-
|
18
|
-
def message(indent = 0)
|
19
|
-
if cause
|
20
|
-
cause_msg = if cause.kind_of?(Error)
|
21
|
-
cause.message(indent + 1)
|
22
|
-
else
|
23
|
-
cause.message
|
24
|
-
end
|
25
|
-
my_msg + "\n" + (" " * (indent + 1)) + cause_msg
|
26
|
-
else
|
27
|
-
my_msg
|
28
|
-
end
|
29
|
-
end
|
30
|
-
end
|
7
|
+
:maybe, :present, :is_a, :is_a_bool, :int, :hash_of, :invalid, :generate_validator, :handle_error, :error_str, :apply
|
31
8
|
|
32
9
|
@@apply = ->fn, a {
|
33
10
|
begin
|
@@ -59,11 +36,19 @@ module ValidatorFn
|
|
59
36
|
@@is_nil = ->a { invalid.("Should be nil but was #{a}") unless a.nil?; a }
|
60
37
|
@@maybe = either.(is_nil)
|
61
38
|
@@is_a = ->klass, a { invalid.("Expected type #{klass}, got #{a.inspect}") unless a.is_a?(klass); a }.curry
|
39
|
+
@@is_a_bool = ->a { invalid.("Expected bool, got #{a.inspect}") unless a == true || a == false; a }.curry
|
62
40
|
@@hash_of = ->fields, hash {
|
63
41
|
hash ||= {}
|
64
42
|
fields.reduce({}) do |memo, (key, fn)|
|
65
|
-
|
43
|
+
value = hash.fetch(key, :missing_field)
|
44
|
+
if value == :missing_field
|
45
|
+
raise MissingKey.new(key)
|
46
|
+
else
|
47
|
+
memo[key] = fn.(hash[key]) if hash[key]
|
48
|
+
end
|
66
49
|
memo
|
50
|
+
rescue MissingKey => e
|
51
|
+
raise
|
67
52
|
rescue Error => e
|
68
53
|
invalid.("Invalid value for #{key.inspect} key.")
|
69
54
|
end
|
@@ -97,6 +82,10 @@ module ValidatorFn
|
|
97
82
|
"hash_of.({ #{inner} })"
|
98
83
|
when Array
|
99
84
|
"array_of.( #{generate_validator.(a.first)} )"
|
85
|
+
when TrueClass
|
86
|
+
"is_a_bool"
|
87
|
+
when FalseClass
|
88
|
+
"is_a_bool"
|
100
89
|
else
|
101
90
|
"is_a.(#{a.class})"
|
102
91
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: validator_fn
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.8
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Martin Chabot
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2022-06-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: fn_reader
|
@@ -43,6 +43,7 @@ files:
|
|
43
43
|
- bin/console
|
44
44
|
- bin/setup
|
45
45
|
- lib/validator_fn.rb
|
46
|
+
- lib/validator_fn/error.rb
|
46
47
|
- lib/validator_fn/version.rb
|
47
48
|
- validator_fn.gemspec
|
48
49
|
homepage: https://github.com/martinos/validator_fn
|
@@ -66,7 +67,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
66
67
|
- !ruby/object:Gem::Version
|
67
68
|
version: '0'
|
68
69
|
requirements: []
|
69
|
-
rubygems_version: 3.1.
|
70
|
+
rubygems_version: 3.1.2
|
70
71
|
signing_key:
|
71
72
|
specification_version: 4
|
72
73
|
summary: Series of lambdas for validating Ruby structures
|