validator_fn 0.1.4 → 0.1.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 +125 -4
- data/lib/validator_fn/error.rb +23 -0
- data/lib/validator_fn/version.rb +1 -1
- data/lib/validator_fn.rb +9 -27
- 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: dbf0665436aeda62b487528bb8f8f85777c45a357c4cf34884600a14273f289d
|
4
|
+
data.tar.gz: 0ba29a6cf3b5d453f3561f8e9c3f205c060d088226c83f494ff7a269dc672734
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: de5d94c98746fd64ecb55f05e658ec434f57c8e518d16bb817ef39e4c56b53cd7130c52ab3ee69dddd5d8b853830dd271374d29c4ac6573576b9cdaf9287c80b
|
7
|
+
data.tar.gz: cfd9b2aab1a51bae15f335fc74e0970bf406d16f0e522ce3eb239176e0814a59bf0be37f13c4753bb0e2193c828634c7e6de7aeda7f323eb92eede177c3ad8ce
|
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,8 +1,11 @@
|
|
1
1
|
# ValidatorFn
|
2
2
|
|
3
|
-
|
3
|
+
ValidatorFn is a collection of very simple lambdas that can be used for validating/transforming
|
4
|
+
data structures. It makes use of currying in order to provide a very composable
|
5
|
+
DSL. To help you understand the concepts it is stongly advised to read [this blog post.](http://blog.martinosis.com/blog/simple-functional-strong-params-in-ruby/).
|
4
6
|
|
5
|
-
|
7
|
+
It can be very useful for validating structures that comes from input, such as configuration files,
|
8
|
+
JSON apis, test result.
|
6
9
|
|
7
10
|
## Installation
|
8
11
|
|
@@ -22,7 +25,125 @@ Or install it yourself as:
|
|
22
25
|
|
23
26
|
## Usage
|
24
27
|
|
25
|
-
|
28
|
+
```
|
29
|
+
require 'validator_fn'
|
30
|
+
include ValidatorFn
|
31
|
+
```
|
32
|
+
|
33
|
+
You can start validating type of an object.
|
34
|
+
|
35
|
+
```
|
36
|
+
is_a.(String).(3)
|
37
|
+
```
|
38
|
+
|
39
|
+
Note that parameters are curried. The first param of `is_a` is the Ruby class that you want to check the last parameter against.
|
40
|
+
In the previous example, aValidatorFn::Error`exception will be raised.
|
41
|
+
|
42
|
+
However if you send a valid entry as the second parameter, it will return that last parameter.
|
43
|
+
|
44
|
+
```
|
45
|
+
is_a.(String).("Joe")
|
46
|
+
# => "Joe"
|
47
|
+
```
|
48
|
+
|
49
|
+
This allows chaining lambdas:
|
50
|
+
|
51
|
+
```
|
52
|
+
to_int = is_a.(String) >> -> a { Integer(a) }
|
53
|
+
|
54
|
+
to_int.("12")
|
55
|
+
# => 12
|
56
|
+
to_int.("asdf") # will raise an exception
|
57
|
+
```
|
58
|
+
|
59
|
+
You can validate a hash:
|
60
|
+
|
61
|
+
```
|
62
|
+
user = hash_of.({name: is_a.(String), age: to_int})
|
63
|
+
user.({name: "", age: "234"})
|
64
|
+
```
|
65
|
+
|
66
|
+
Since we are using curried lambdas, you can compose validators as you which.
|
67
|
+
|
68
|
+
```
|
69
|
+
postal_code = -> a {
|
70
|
+
invalid.("Invalid postal code: #{a}") unless a =~ /[a-z]\d[a-z]\s*\d[a-z]\d/i
|
71
|
+
a
|
72
|
+
}
|
73
|
+
contact = hash_of.(user: user,
|
74
|
+
address: hash_of.({ street_number: is_a.(Integer),
|
75
|
+
postal_code: postal_code}))
|
76
|
+
```
|
77
|
+
|
78
|
+
This is a very simple library (100 lines of code) that can be extended as you which by
|
79
|
+
creating your own lambdas.
|
80
|
+
|
81
|
+
## Casting
|
82
|
+
|
83
|
+
You can also apply converter functions to the structure.
|
84
|
+
|
85
|
+
```ruby
|
86
|
+
user = { name: "Joe", created_at: "2020-01-03" }
|
87
|
+
to_date = ->str { Date.parse(str) }
|
88
|
+
user_validator = hash_of.(name: is_a.(String),
|
89
|
+
created_at: is_a.(String) >> to_date)
|
90
|
+
|
91
|
+
user_validator.(user)
|
92
|
+
# => {:name=>"Joe", :created_at=>#<Date: 2020-01-03 ((2458852j,0s,0n),+0s,2299161j)>}
|
93
|
+
```
|
94
|
+
|
95
|
+
This makes it very useful processing JSON payloads.
|
96
|
+
|
97
|
+
## Code generation
|
98
|
+
|
99
|
+
You can generate validator code from existing structure:
|
100
|
+
|
101
|
+
```
|
102
|
+
require 'openuri'
|
103
|
+
require "json"
|
104
|
+
struct = JSON.parse(URI.open("https://api.github.com/users/defunkt").read)
|
105
|
+
|
106
|
+
require_relative "validator_fn"
|
107
|
+
|
108
|
+
# Generate unformatted code
|
109
|
+
code = ValidatorFn.generate_validator.(struct)
|
110
|
+
|
111
|
+
# You can reformat it using a code formatter
|
112
|
+
require "rufo"
|
113
|
+
puts Rufo.format(code)
|
114
|
+
hash_of.({ "login" => is_a.(String),
|
115
|
+
"id" => is_a.(Integer),
|
116
|
+
"node_id" => is_a.(String),
|
117
|
+
"avatar_url" => is_a.(String),
|
118
|
+
"gravatar_id" => is_a.(String),
|
119
|
+
"url" => is_a.(String),
|
120
|
+
"html_url" => is_a.(String),
|
121
|
+
"followers_url" => is_a.(String),
|
122
|
+
"following_url" => is_a.(String),
|
123
|
+
"gists_url" => is_a.(String),
|
124
|
+
"starred_url" => is_a.(String),
|
125
|
+
"subscriptions_url" => is_a.(String),
|
126
|
+
"organizations_url" => is_a.(String),
|
127
|
+
"repos_url" => is_a.(String),
|
128
|
+
"events_url" => is_a.(String),
|
129
|
+
"received_events_url" => is_a.(String),
|
130
|
+
"type" => is_a.(String),
|
131
|
+
"site_admin" => is_a_bool,
|
132
|
+
"name" => is_a.(String),
|
133
|
+
"company" => any,
|
134
|
+
"blog" => is_a.(String),
|
135
|
+
"location" => any,
|
136
|
+
"email" => any,
|
137
|
+
"hireable" => any,
|
138
|
+
"bio" => is_a.(String),
|
139
|
+
"twitter_username" => any,
|
140
|
+
"public_repos" => is_a.(Integer),
|
141
|
+
"public_gists" => is_a.(Integer),
|
142
|
+
"followers" => is_a.(Integer),
|
143
|
+
"following" => is_a.(Integer),
|
144
|
+
"created_at" => is_a.(String),
|
145
|
+
"updated_at" => is_a.(String) })
|
146
|
+
```
|
26
147
|
|
27
148
|
## Development
|
28
149
|
|
@@ -34,7 +155,6 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
|
|
34
155
|
|
35
156
|
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).
|
36
157
|
|
37
|
-
|
38
158
|
## License
|
39
159
|
|
40
160
|
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
@@ -42,3 +162,4 @@ The gem is available as open source under the terms of the [MIT License](https:/
|
|
42
162
|
## Code of Conduct
|
43
163
|
|
44
164
|
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).
|
165
|
+
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,23 @@
|
|
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
|
+
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
|
@@ -56,9 +33,10 @@ module ValidatorFn
|
|
56
33
|
end
|
57
34
|
}.curry
|
58
35
|
@@any = ->a { a }
|
59
|
-
@@is_nil = ->a { invalid.("Should be nil") unless a.nil?; a }
|
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)|
|
@@ -92,11 +70,15 @@ module ValidatorFn
|
|
92
70
|
"any"
|
93
71
|
when Hash
|
94
72
|
inner = a.map do |k, v|
|
95
|
-
%{
|
73
|
+
%{#{k.inspect} => #{generate_validator.(v)}}
|
96
74
|
end.join(",\n ")
|
97
75
|
"hash_of.({ #{inner} })"
|
98
76
|
when Array
|
99
77
|
"array_of.( #{generate_validator.(a.first)} )"
|
78
|
+
when TrueClass
|
79
|
+
"is_a_bool"
|
80
|
+
when FalseClass
|
81
|
+
"is_a_bool"
|
100
82
|
else
|
101
83
|
"is_a.(#{a.class})"
|
102
84
|
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.1.
|
4
|
+
version: 0.1.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-02-13 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
|