mayak 0.0.14 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/LICENSE +21 -0
- data/README.md +235 -2
- data/lib/mayak/function.rb +5 -0
- data/lib/mayak/lazy.rb +307 -0
- data/lib/mayak/validations/rule.rb +273 -0
- data/lib/mayak/validations/validation.rb +65 -0
- data/lib/mayak/version.rb +1 -1
- data/lib/mayak.rb +1 -0
- data/mayak.gemspec +1 -1
- metadata +6 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: eb1722eed3175033b058ab2e87589e45d31fb701f402f51978758663d0ad3c82
|
4
|
+
data.tar.gz: 3b2aa6f45f79aa848bd017e208f4568aef6ecdc9f3f80fb18eae8b5053fee551
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9ea0826e78b1cf81e74fae2df74d42f3842e19fa05c5b9bfcdd95955221efb8cb161bcd72dd8623e55defd8b1b1677745edea195b9bf4c5c644eadb575f47d92
|
7
|
+
data.tar.gz: d20145430d27b269422d1c18a81256704969535c7a9616ad92da9008a4fb3ca63a46c5d24b103473232ab5a3de513f91b455d77213a75ff06c54df93d91f4b1f
|
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2024 Даниил Бобер
|
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 all
|
13
|
+
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 THE
|
21
|
+
SOFTWARE.
|
data/README.md
CHANGED
@@ -9,11 +9,17 @@ Mayak is a library which aims to provide abstractions for well typed programming
|
|
9
9
|
In order to use the library, add the following line to your `Gemfile`:
|
10
10
|
|
11
11
|
```ruby
|
12
|
-
gem
|
12
|
+
gem "mayak"
|
13
13
|
```
|
14
14
|
or install it via the following command:
|
15
15
|
```ruby
|
16
|
-
gem install
|
16
|
+
gem install "mayak"
|
17
|
+
```
|
18
|
+
|
19
|
+
If you are using tapioca, add following line into tapioca's `require.rb` before generating rbi's for the gem:
|
20
|
+
|
21
|
+
```ruby
|
22
|
+
require "mayak"
|
17
23
|
```
|
18
24
|
|
19
25
|
### Documentation
|
@@ -34,6 +40,233 @@ Mayak consists from separate classes and interfaces as well as separate modules
|
|
34
40
|
|
35
41
|
#### Miscellaneous
|
36
42
|
|
43
|
+
##### Lazy
|
44
|
+
|
45
|
+
`Lazy` classs represents a value that evaluates only during it's access, and evaluates only once
|
46
|
+
during the first access. Basically, `Lazy` wraps a block of code (thunk) that returns a value (`Lazy` has single type parameter of a value), and executes only when the value accessed for the first time
|
47
|
+
and then stores it afterward.
|
48
|
+
|
49
|
+
In order to build `Lazy` a type parameter of value holded should be provided as well as a block that computes a value of the type.
|
50
|
+
Note that the block is not executed right away.
|
51
|
+
|
52
|
+
```ruby
|
53
|
+
lazy1 = ::Mayak::Lazy[Integer].new { 1 }
|
54
|
+
|
55
|
+
buffer = []
|
56
|
+
lazy2 = ::Mayak::Lazy[Integer].new do
|
57
|
+
buffer << 1
|
58
|
+
1
|
59
|
+
end
|
60
|
+
buffer
|
61
|
+
#> []
|
62
|
+
```
|
63
|
+
|
64
|
+
To access the value call `#value`. If the value is not yet computed, provided block will be executed and its result will be stored. Further invokations
|
65
|
+
of this method won't execute the block again.
|
66
|
+
|
67
|
+
```ruby
|
68
|
+
buffer = []
|
69
|
+
lazy = ::Mayak::Lazy[Integer].new do
|
70
|
+
buffer << 1
|
71
|
+
1
|
72
|
+
end
|
73
|
+
buffer
|
74
|
+
#> []
|
75
|
+
|
76
|
+
# Will execute the block and return the computed value.
|
77
|
+
lazy.value
|
78
|
+
#> 1
|
79
|
+
buffer
|
80
|
+
#> [1]
|
81
|
+
|
82
|
+
# Will return the memoized value, but won't call the block again
|
83
|
+
lazy.value
|
84
|
+
#> 1
|
85
|
+
buffer
|
86
|
+
#> [1]
|
87
|
+
```
|
88
|
+
|
89
|
+
`Lazy` can be used in situations, when we want to inject some dependency into some class or method, but it may not be used, and the computation or aacquisition of the dependency may be cosftul. In this cases, it's acquisitation may be wrapped in lazy.
|
90
|
+
|
91
|
+
In more imperative style
|
92
|
+
```ruby
|
93
|
+
sig { params(env_variable: String, file_content: ::Mayak::Lazy[String], default: String).returns(String) }
|
94
|
+
def fetch_config(env_variable, file_content, default)
|
95
|
+
from_environment = ENV[env_variable]
|
96
|
+
if env.empty?
|
97
|
+
file_config = ::Core::Json.parse(file_content.value).success_or({})
|
98
|
+
from_file = file_config["configuration"]
|
99
|
+
if from_file.empty?
|
100
|
+
default
|
101
|
+
else
|
102
|
+
from_file
|
103
|
+
end
|
104
|
+
else
|
105
|
+
from_environment
|
106
|
+
end
|
107
|
+
end
|
108
|
+
```
|
109
|
+
|
110
|
+
Using Mayak monads:
|
111
|
+
```ruby
|
112
|
+
include ::Mayak::Monads::Maybe::Mixin
|
113
|
+
|
114
|
+
sig { params(env_variable: String, file_content: ::Mayak::Lazy[String], default: String).returns(String) }
|
115
|
+
def fetch_config(env_variable, file_content, default)
|
116
|
+
Maybe(ENV[env_variable])
|
117
|
+
.recover_with_maybe(::Core::Json.parse(file_content.value).to_maybe)
|
118
|
+
.flat_map { |json| Maybe(json["configuration"]) }
|
119
|
+
.value_or(default)
|
120
|
+
end
|
121
|
+
```
|
122
|
+
|
123
|
+
This method receives name of environment variable, and file content as lazy value. The method
|
124
|
+
tries to read the environment variable, and if it's not present and reads the file content to find the configuration.
|
125
|
+
`Lazy` allows to incapsulate behaviour of reading from file, so it can be passed as dependency, method `#fetch_config` doesn't
|
126
|
+
know anything about reading from file, but because of usage of `lazy` we can postpone it's execution thus avoiding unnecessary work.
|
127
|
+
|
128
|
+
`Lazy` can be transformed via methods `#map` and `#flat_map`.
|
129
|
+
|
130
|
+
Method `#map` allows to transform value inside `Lazy` without triggering executing. Note that `#map` returns
|
131
|
+
a new instance without mutating previous `Lazy`.
|
132
|
+
```ruby
|
133
|
+
int_lazy = ::Mayak::Lazy[Integer].new do
|
134
|
+
puts("On initialize")
|
135
|
+
1
|
136
|
+
end
|
137
|
+
string_lazy = int_lazy.map do |int|
|
138
|
+
puts("On mapping")
|
139
|
+
int.to_s
|
140
|
+
end
|
141
|
+
int_lazy.value # 1
|
142
|
+
#> On initialize
|
143
|
+
|
144
|
+
string_lazy.value # "1"
|
145
|
+
#> On initialize
|
146
|
+
#> On mapping
|
147
|
+
|
148
|
+
sig { params(file_content: ::Mayak::Lazy[String]).returns(::Mayak::Lazy[Maybe[String]]) }
|
149
|
+
def file_content_config(file_content)
|
150
|
+
file_content.map do |file_content|
|
151
|
+
::Core::Json
|
152
|
+
.parse(file_content.value)
|
153
|
+
.to_maybe
|
154
|
+
.flat_map { |json| Maybe(json["configuration"]) }
|
155
|
+
end
|
156
|
+
end
|
157
|
+
```
|
158
|
+
|
159
|
+
Method `#flat_map` allows to chain lazy computations. It receives a block, that builds a new `Lazy` value from the value of original
|
160
|
+
`Lazy` and returns a new instance of `Lazy`.
|
161
|
+
|
162
|
+
```ruby
|
163
|
+
sig { params(env_name: String).returns(::Mayak::Lazy[String]) }
|
164
|
+
def lazy_env(env_name)
|
165
|
+
::Mayak::Lazy[String].new { ENV[env_name] }
|
166
|
+
end
|
167
|
+
|
168
|
+
env_variable_name = ::Mayak::Lazy[String].new { "VARIABLE" }
|
169
|
+
env_variable = env_variable_name.flat_map { |env_name| lazy_env(env_name) }
|
170
|
+
```
|
171
|
+
|
172
|
+
This may be useful when want to perform a lazy computation based on result of some other lazy computation without enforcing the evaluation.
|
173
|
+
|
174
|
+
For example we have a file that contains list of file names. We can build a lazy computation that read all lines from this code.
|
175
|
+
```ruby
|
176
|
+
sig { params(file_name: String).returns(::Mayak::Lazy[T::Array[String]]) }
|
177
|
+
def read_file_lines(file_name)
|
178
|
+
::Mayak::Lazy[T::Array[String]].new { File.read(file_name).split }
|
179
|
+
end
|
180
|
+
```
|
181
|
+
|
182
|
+
Let's we want to read all filenames from the root file, and then read the first file lazily. In this cases, the lazy computation can be chained via `#flat_map`:
|
183
|
+
|
184
|
+
```ruby
|
185
|
+
sig { params(file_name: String).returns(::Mayak::Lazy[T::Array[String]]) }
|
186
|
+
def read_first_file(file_name)
|
187
|
+
read_file_lines(file_name).flat_map do |file_names|
|
188
|
+
Maybe(file_names.first)
|
189
|
+
.filter(&:empty?)
|
190
|
+
.map { |file| read_file_lines(file) }
|
191
|
+
.value_or(::Mayak::Lazy[T::Array[String]].new { [] })
|
192
|
+
end
|
193
|
+
end
|
194
|
+
```
|
195
|
+
|
196
|
+
In order to combine two lazies of different types into a single one, method `#combine` can be used.
|
197
|
+
This method receives another lazy (it can be lazy of different type), and a block
|
198
|
+
and returns a lazy containing result of applying passed blocked to values calculated by lazies.
|
199
|
+
|
200
|
+
```ruby
|
201
|
+
class ConfigFiles < T::Struct
|
202
|
+
const :database_config_file, ::File
|
203
|
+
const :server_config_file, ::File
|
204
|
+
end
|
205
|
+
|
206
|
+
sig { returns(::Mayak::Lazy[File]) }
|
207
|
+
def database_config_file
|
208
|
+
::Mayak::Lazy[File].new { File.new(DATABASE_CONFIG_FILE_NAME, "r") }
|
209
|
+
end
|
210
|
+
|
211
|
+
sig { returns(::Mayak::Lazy[File]) }
|
212
|
+
def server_config_file
|
213
|
+
::Mayak::Lazy[File].new { File.new(SERVER_CONFIG_FILE_NAME, "r") }
|
214
|
+
end
|
215
|
+
|
216
|
+
sig { returns(::Mayak::Lazy[ConfigFiles]) }
|
217
|
+
def config_files
|
218
|
+
database_config_file.combine(server_config_file) do |db_file, server_file|
|
219
|
+
ConfigFiles.new(
|
220
|
+
database_config_file: database_config_file,
|
221
|
+
server_config_file: server_file
|
222
|
+
)
|
223
|
+
end
|
224
|
+
end
|
225
|
+
```
|
226
|
+
|
227
|
+
The same behaviour can be achieved with a method `.combine_two`:
|
228
|
+
|
229
|
+
```ruby
|
230
|
+
sig { returns(::Mayak::Lazy[ConfigFiles]) }
|
231
|
+
def config_files
|
232
|
+
::Mayak::Lazy.combine_two(database_config_file, server_config_file) do |db_file, server_file|
|
233
|
+
ConfigFiles.new(
|
234
|
+
database_config_file: database_config_file,
|
235
|
+
server_config_file: server_file
|
236
|
+
)
|
237
|
+
end
|
238
|
+
end
|
239
|
+
```
|
240
|
+
|
241
|
+
There are also methods `.combine_three`, `.combine_four` upto `.combine_sevel` to combine multiple lazies of diffent types.
|
242
|
+
|
243
|
+
If you need to combined multiple lazies containing the same value, you can use `.combine_many`. It works
|
244
|
+
as `Array#reduce`: receives an array of lazies containing the same type, initial value of result type, and a block
|
245
|
+
receiving accumulator value of result type, and value of next lazy.
|
246
|
+
|
247
|
+
```ruby
|
248
|
+
sig { returns(::Mayak::Lazy[Integer]) }
|
249
|
+
def lazy
|
250
|
+
::Mayak::Lazy.combine_many(
|
251
|
+
[::Mayak::Lazy[Integer].new(1), ::Mayak::Lazy[Integer].new(2), ::Mayak::Lazy[Integer].new(3)],
|
252
|
+
0
|
253
|
+
) { |acc, value| acc + value }
|
254
|
+
end
|
255
|
+
|
256
|
+
lazy.value # 10
|
257
|
+
```
|
258
|
+
|
259
|
+
If you need to transform array of lazies of some value into lazy of array of the value, you can use `.sequence` method.
|
260
|
+
|
261
|
+
```ruby
|
262
|
+
sig { returns(::Mayak::Lazy[T::Array[Integer]]) }
|
263
|
+
def lazy
|
264
|
+
::Mayak::Lazy.sequence([::Mayak::Lazy[Integer].new(1), ::Mayak::Lazy[Integer].new(2), ::Mayak::Lazy[Integer].new(3)])
|
265
|
+
end
|
266
|
+
|
267
|
+
lazy.value # [1, 2, 3]
|
268
|
+
```
|
269
|
+
|
37
270
|
##### Function
|
38
271
|
In some situations Sorbet can not infer a type of proc passed:
|
39
272
|
|
data/lib/mayak/function.rb
CHANGED
@@ -32,6 +32,11 @@ module Mayak
|
|
32
32
|
::Mayak::Function[T.type_parameter(:Input), T.type_parameter(:Output)].new { |input| proc.call(input) }
|
33
33
|
end
|
34
34
|
|
35
|
+
sig { returns(T.proc.params(arg0: Input).returns(Output)) }
|
36
|
+
def to_proc
|
37
|
+
-> (input) { call(input) }
|
38
|
+
end
|
39
|
+
|
35
40
|
sig { params(input: Input).returns(Output) }
|
36
41
|
def call(input)
|
37
42
|
blk.call(input)
|
data/lib/mayak/lazy.rb
ADDED
@@ -0,0 +1,307 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# typed: strict
|
3
|
+
|
4
|
+
require "json"
|
5
|
+
|
6
|
+
module Mayak
|
7
|
+
class Lazy
|
8
|
+
extend T::Sig
|
9
|
+
extend T::Generic
|
10
|
+
|
11
|
+
Value = type_member
|
12
|
+
|
13
|
+
sig { params(blk: T.proc.returns(Value)).void }
|
14
|
+
def initialize(&blk)
|
15
|
+
@thunk = T.let(blk, T.proc.returns(Value))
|
16
|
+
@value = T.let(nil, T.nilable(Value))
|
17
|
+
@forced = T.let(false, T::Boolean)
|
18
|
+
end
|
19
|
+
|
20
|
+
sig { returns(Value) }
|
21
|
+
def value
|
22
|
+
if @forced
|
23
|
+
T.must(@value)
|
24
|
+
else
|
25
|
+
@forced = true
|
26
|
+
@value = @thunk.call
|
27
|
+
@value
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
sig {
|
32
|
+
type_parameters(
|
33
|
+
:NewValue
|
34
|
+
).params(
|
35
|
+
blk: T.proc.params(arg0: Value).returns(T.type_parameter(:NewValue))
|
36
|
+
).returns(
|
37
|
+
::Mayak::Lazy[T.type_parameter(:NewValue)]
|
38
|
+
)
|
39
|
+
}
|
40
|
+
def map(&blk)
|
41
|
+
::Mayak::Lazy.new { blk.call(value) }
|
42
|
+
end
|
43
|
+
|
44
|
+
sig {
|
45
|
+
type_parameters(
|
46
|
+
:NewValue
|
47
|
+
).params(
|
48
|
+
blk: T.proc.params(arg0: Value).returns(::Mayak::Lazy[T.type_parameter(:NewValue)])
|
49
|
+
).returns(
|
50
|
+
::Mayak::Lazy[T.type_parameter(:NewValue)]
|
51
|
+
)
|
52
|
+
}
|
53
|
+
def flat_map(&blk)
|
54
|
+
::Mayak::Lazy.new { blk.call(value).value }
|
55
|
+
end
|
56
|
+
|
57
|
+
sig {
|
58
|
+
type_parameters(
|
59
|
+
:AnotherValue,
|
60
|
+
:NewValue
|
61
|
+
).params(
|
62
|
+
another: ::Mayak::Lazy[T.type_parameter(:AnotherValue)],
|
63
|
+
blk: T.proc.params(arg0: Value, arg1: T.type_parameter(:AnotherValue)).returns(T.type_parameter(:NewValue))
|
64
|
+
).returns(
|
65
|
+
::Mayak::Lazy[T.type_parameter(:NewValue)]
|
66
|
+
)
|
67
|
+
}
|
68
|
+
def combine(another, &blk)
|
69
|
+
::Mayak::Lazy[T.type_parameter(:NewValue)].new do
|
70
|
+
blk.call(value, another.value)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
sig {
|
75
|
+
type_parameters(
|
76
|
+
:Value
|
77
|
+
).params(
|
78
|
+
lazies: T::Array[::Mayak::Lazy[T.type_parameter(:Value)]]
|
79
|
+
).returns(
|
80
|
+
::Mayak::Lazy[T::Array[T.type_parameter(:Value)]]
|
81
|
+
)
|
82
|
+
}
|
83
|
+
def self.sequence(lazies)
|
84
|
+
::Mayak::Lazy[T::Array[T.type_parameter(:Value)]].new { lazies.map(&:value) }
|
85
|
+
end
|
86
|
+
|
87
|
+
sig {
|
88
|
+
type_parameters(
|
89
|
+
:FirstValue,
|
90
|
+
:SecondValue,
|
91
|
+
:ResultValue
|
92
|
+
).params(
|
93
|
+
first: ::Mayak::Lazy[T.type_parameter(:FirstValue)],
|
94
|
+
second: ::Mayak::Lazy[T.type_parameter(:SecondValue)],
|
95
|
+
blk: T.proc.params(
|
96
|
+
arg0: T.type_parameter(:FirstValue),
|
97
|
+
arg1: T.type_parameter(:SecondValue)
|
98
|
+
).returns(
|
99
|
+
T.type_parameter(:ResultValue)
|
100
|
+
)
|
101
|
+
).returns(
|
102
|
+
::Mayak::Lazy[T.type_parameter(:ResultValue)]
|
103
|
+
)
|
104
|
+
}
|
105
|
+
def self.combine_two(first, second, &blk)
|
106
|
+
::Mayak::Lazy[T.type_parameter(:ResultValue)].new do
|
107
|
+
blk.call(first.value, second.value)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
sig {
|
112
|
+
type_parameters(
|
113
|
+
:FirstValue,
|
114
|
+
:SecondValue,
|
115
|
+
:ThirdValue,
|
116
|
+
:ResultValue
|
117
|
+
).params(
|
118
|
+
first: ::Mayak::Lazy[T.type_parameter(:FirstValue)],
|
119
|
+
second: ::Mayak::Lazy[T.type_parameter(:SecondValue)],
|
120
|
+
third: ::Mayak::Lazy[T.type_parameter(:ThirdValue)],
|
121
|
+
blk: T.proc.params(
|
122
|
+
arg0: T.type_parameter(:FirstValue),
|
123
|
+
arg1: T.type_parameter(:SecondValue),
|
124
|
+
arg2: T.type_parameter(:ThirdValue)
|
125
|
+
).returns(
|
126
|
+
T.type_parameter(:ResultValue)
|
127
|
+
)
|
128
|
+
).returns(
|
129
|
+
::Mayak::Lazy[T.type_parameter(:ResultValue)]
|
130
|
+
)
|
131
|
+
}
|
132
|
+
def self.combine_three(first, second, third, &blk)
|
133
|
+
::Mayak::Lazy[T.type_parameter(:ResultValue)].new do
|
134
|
+
blk.call(first.value, second.value, third.value)
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
sig {
|
139
|
+
type_parameters(
|
140
|
+
:FirstValue,
|
141
|
+
:SecondValue,
|
142
|
+
:ThirdValue,
|
143
|
+
:FourthValue,
|
144
|
+
:ResultValue
|
145
|
+
).params(
|
146
|
+
first: ::Mayak::Lazy[T.type_parameter(:FirstValue)],
|
147
|
+
second: ::Mayak::Lazy[T.type_parameter(:SecondValue)],
|
148
|
+
third: ::Mayak::Lazy[T.type_parameter(:ThirdValue)],
|
149
|
+
fourth: ::Mayak::Lazy[T.type_parameter(:FourthValue)],
|
150
|
+
blk: T.proc.params(
|
151
|
+
arg0: T.type_parameter(:FirstValue),
|
152
|
+
arg1: T.type_parameter(:SecondValue),
|
153
|
+
arg2: T.type_parameter(:ThirdValue),
|
154
|
+
arg3: T.type_parameter(:FourthValue)
|
155
|
+
).returns(
|
156
|
+
T.type_parameter(:ResultValue)
|
157
|
+
)
|
158
|
+
).returns(
|
159
|
+
::Mayak::Lazy[T.type_parameter(:ResultValue)]
|
160
|
+
)
|
161
|
+
}
|
162
|
+
def self.combine_four(first, second, third, fourth, &blk)
|
163
|
+
::Mayak::Lazy[T.type_parameter(:ResultValue)].new do
|
164
|
+
blk.call(first.value, second.value, third.value, fourth.value)
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
sig {
|
169
|
+
type_parameters(
|
170
|
+
:FirstValue,
|
171
|
+
:SecondValue,
|
172
|
+
:ThirdValue,
|
173
|
+
:FourthValue,
|
174
|
+
:FifthValue,
|
175
|
+
:ResultValue
|
176
|
+
).params(
|
177
|
+
first: ::Mayak::Lazy[T.type_parameter(:FirstValue)],
|
178
|
+
second: ::Mayak::Lazy[T.type_parameter(:SecondValue)],
|
179
|
+
third: ::Mayak::Lazy[T.type_parameter(:ThirdValue)],
|
180
|
+
fourth: ::Mayak::Lazy[T.type_parameter(:FourthValue)],
|
181
|
+
fifth: ::Mayak::Lazy[T.type_parameter(:FifthValue)],
|
182
|
+
blk: T.proc.params(
|
183
|
+
arg0: T.type_parameter(:FirstValue),
|
184
|
+
arg1: T.type_parameter(:SecondValue),
|
185
|
+
arg2: T.type_parameter(:ThirdValue),
|
186
|
+
arg3: T.type_parameter(:FourthValue),
|
187
|
+
arg4: T.type_parameter(:FifthValue)
|
188
|
+
).returns(
|
189
|
+
T.type_parameter(:ResultValue)
|
190
|
+
)
|
191
|
+
).returns(
|
192
|
+
::Mayak::Lazy[T.type_parameter(:ResultValue)]
|
193
|
+
)
|
194
|
+
}
|
195
|
+
def self.combine_five(first, second, third, fourth, fifth, &blk)
|
196
|
+
::Mayak::Lazy[T.type_parameter(:ResultValue)].new do
|
197
|
+
blk.call(first.value, second.value, third.value, fourth.value, fifth.value)
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
sig {
|
202
|
+
type_parameters(
|
203
|
+
:FirstValue,
|
204
|
+
:SecondValue,
|
205
|
+
:ThirdValue,
|
206
|
+
:FourthValue,
|
207
|
+
:FifthValue,
|
208
|
+
:SixthValue,
|
209
|
+
:ResultValue
|
210
|
+
).params(
|
211
|
+
first: ::Mayak::Lazy[T.type_parameter(:FirstValue)],
|
212
|
+
second: ::Mayak::Lazy[T.type_parameter(:SecondValue)],
|
213
|
+
third: ::Mayak::Lazy[T.type_parameter(:ThirdValue)],
|
214
|
+
fourth: ::Mayak::Lazy[T.type_parameter(:FourthValue)],
|
215
|
+
fifth: ::Mayak::Lazy[T.type_parameter(:FifthValue)],
|
216
|
+
sixth: ::Mayak::Lazy[T.type_parameter(:SixthValue)],
|
217
|
+
blk: T.proc.params(
|
218
|
+
arg0: T.type_parameter(:FirstValue),
|
219
|
+
arg1: T.type_parameter(:SecondValue),
|
220
|
+
arg2: T.type_parameter(:ThirdValue),
|
221
|
+
arg3: T.type_parameter(:FourthValue),
|
222
|
+
arg4: T.type_parameter(:FifthValue),
|
223
|
+
arg5: T.type_parameter(:SixthValue)
|
224
|
+
).returns(
|
225
|
+
T.type_parameter(:ResultValue)
|
226
|
+
)
|
227
|
+
).returns(
|
228
|
+
::Mayak::Lazy[T.type_parameter(:ResultValue)]
|
229
|
+
)
|
230
|
+
}
|
231
|
+
def self.combine_six(first, second, third, fourth, fifth, sixth, &blk)
|
232
|
+
::Mayak::Lazy[T.type_parameter(:ResultValue)].new do
|
233
|
+
blk.call(first.value, second.value, third.value, fourth.value, fifth.value, sixth.value)
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
237
|
+
sig {
|
238
|
+
type_parameters(
|
239
|
+
:FirstValue,
|
240
|
+
:SecondValue,
|
241
|
+
:ThirdValue,
|
242
|
+
:FourthValue,
|
243
|
+
:FifthValue,
|
244
|
+
:SixthValue,
|
245
|
+
:SeventhValue,
|
246
|
+
:ResultValue
|
247
|
+
).params(
|
248
|
+
first: ::Mayak::Lazy[T.type_parameter(:FirstValue)],
|
249
|
+
second: ::Mayak::Lazy[T.type_parameter(:SecondValue)],
|
250
|
+
third: ::Mayak::Lazy[T.type_parameter(:ThirdValue)],
|
251
|
+
fourth: ::Mayak::Lazy[T.type_parameter(:FourthValue)],
|
252
|
+
fifth: ::Mayak::Lazy[T.type_parameter(:FifthValue)],
|
253
|
+
sixth: ::Mayak::Lazy[T.type_parameter(:SixthValue)],
|
254
|
+
seventh: ::Mayak::Lazy[T.type_parameter(:SeventhValue)],
|
255
|
+
blk: T.proc.params(
|
256
|
+
arg0: T.type_parameter(:FirstValue),
|
257
|
+
arg1: T.type_parameter(:SecondValue),
|
258
|
+
arg2: T.type_parameter(:ThirdValue),
|
259
|
+
arg3: T.type_parameter(:FourthValue),
|
260
|
+
arg4: T.type_parameter(:FifthValue),
|
261
|
+
arg5: T.type_parameter(:SixthValue),
|
262
|
+
arg6: T.type_parameter(:SeventhValue),
|
263
|
+
).returns(
|
264
|
+
T.type_parameter(:ResultValue)
|
265
|
+
)
|
266
|
+
).returns(
|
267
|
+
::Mayak::Lazy[T.type_parameter(:ResultValue)]
|
268
|
+
)
|
269
|
+
}
|
270
|
+
def self.combine_seven(first, second, third, fourth, fifth, sixth, seventh, &blk)
|
271
|
+
::Mayak::Lazy[T.type_parameter(:ResultValue)].new do
|
272
|
+
blk.call(first.value, second.value, third.value, fourth.value, fifth.value, sixth.value, seventh.value)
|
273
|
+
end
|
274
|
+
end
|
275
|
+
|
276
|
+
sig {
|
277
|
+
type_parameters(
|
278
|
+
:Value,
|
279
|
+
:Result
|
280
|
+
).params(
|
281
|
+
lazies: T::Array[::Mayak::Lazy[T.type_parameter(:Value)]],
|
282
|
+
initial: T.type_parameter(:Result),
|
283
|
+
blk: T.proc.params(arg0: T.type_parameter(:Result), arg1: T.type_parameter(:Value)).returns(T.type_parameter(:Result))
|
284
|
+
).returns(
|
285
|
+
::Mayak::Lazy[T.type_parameter(:Result)]
|
286
|
+
)
|
287
|
+
}
|
288
|
+
def self.combine_many(lazies, initial, &blk)
|
289
|
+
::Mayak::Lazy[T.type_parameter(:Result)].new do
|
290
|
+
lazies.reduce(initial) { |acc, element| blk.call(acc, element.value) }
|
291
|
+
end
|
292
|
+
end
|
293
|
+
|
294
|
+
sig {
|
295
|
+
type_parameters(
|
296
|
+
:Value
|
297
|
+
).params(
|
298
|
+
lazies: T::Array[::Mayak::Lazy[T.type_parameter(:Value)]]
|
299
|
+
).returns(
|
300
|
+
::Mayak::Lazy[T::Array[T.type_parameter(:Value)]]
|
301
|
+
)
|
302
|
+
}
|
303
|
+
def self.sequence(lazies)
|
304
|
+
combine_many(lazies, []) { |acc, element| acc.concat([element]) }
|
305
|
+
end
|
306
|
+
end
|
307
|
+
end
|
@@ -0,0 +1,273 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# typed: strict
|
3
|
+
|
4
|
+
module Mayak
|
5
|
+
module Validations
|
6
|
+
class Rule
|
7
|
+
extend T::Sig
|
8
|
+
extend T::Helpers
|
9
|
+
extend T::Generic
|
10
|
+
|
11
|
+
Value = type_member
|
12
|
+
Error = type_member
|
13
|
+
|
14
|
+
sig {
|
15
|
+
params(
|
16
|
+
blk: T.proc.params(arg0: Value).returns(::Mayak::ValidationResult[Error])
|
17
|
+
).void
|
18
|
+
}
|
19
|
+
def initialize(&blk)
|
20
|
+
@blk = T.let(@blk, T.proc.params(arg0: Value).returns(::Mayak::ValidationResult[Error]))
|
21
|
+
end
|
22
|
+
|
23
|
+
sig { params(value: Value).returns(::Mayak::ValidationResult[Error]) }
|
24
|
+
def check(value)
|
25
|
+
@blk.call(value)
|
26
|
+
end
|
27
|
+
|
28
|
+
sig {
|
29
|
+
type_parameters(:NewError)
|
30
|
+
.params(blk: T.proc.params(arg0: Value).returns(T.type_parameter(:NewError)))
|
31
|
+
.returns(Rule[Value, T.type_parameter(:NewError)])
|
32
|
+
}
|
33
|
+
def error_from_value(&blk)
|
34
|
+
Rule[Value, T.type_parameter(:NewError)].new do |checked|
|
35
|
+
result = check(checked)
|
36
|
+
|
37
|
+
case result
|
38
|
+
when ::Mayak::ValidationResult::Valid
|
39
|
+
::Mayak::ValidationResult::Valid[T.type_parameter(:NewError)].new
|
40
|
+
when ::Mayak::ValidationResult::Invalid
|
41
|
+
::Mayak::ValidationResult::Invalid[T.type_parameter(:NewError)].new(errors: [blk.call(checked)])
|
42
|
+
else
|
43
|
+
T.absurd(result)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
sig {
|
49
|
+
type_parameters(:NewError)
|
50
|
+
.params(new_error: T.type_parameter(:NewError))
|
51
|
+
.returns(Rule[Value, T.type_parameter(:NewError)])
|
52
|
+
}
|
53
|
+
def error(new_error)
|
54
|
+
error_from_value { |_| new_error }
|
55
|
+
end
|
56
|
+
|
57
|
+
sig {
|
58
|
+
params(another: Rule[Value, Error]).returns(Rule[Value, Error])
|
59
|
+
}
|
60
|
+
def any(another)
|
61
|
+
Rule[Value, Error].new do |checked|
|
62
|
+
first_result = check(checked)
|
63
|
+
case first_result
|
64
|
+
when ::Mayak::ValidationResult::Valid
|
65
|
+
another.check(checked)
|
66
|
+
when ::Mayak::ValidationResult::Invalid
|
67
|
+
first_result
|
68
|
+
else
|
69
|
+
T.absurd(first_result)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
alias | any
|
75
|
+
|
76
|
+
sig {
|
77
|
+
params(another: Rule[Value, Error]).returns(Rule[Value, Error])
|
78
|
+
}
|
79
|
+
def both(another)
|
80
|
+
Rule[Value, Error].new do |checked|
|
81
|
+
first_result = check(checked)
|
82
|
+
case first_result
|
83
|
+
when ::Mayak::ValidationResult::Valid
|
84
|
+
another.check(checked)
|
85
|
+
when ::Mayak::ValidationResult::Invalid
|
86
|
+
second_result = another.check(checked)
|
87
|
+
case second_result
|
88
|
+
when ::Mayak::ValidationResult::Valid
|
89
|
+
first_result
|
90
|
+
when ::Mayak::ValidationResult::Invalid
|
91
|
+
::Mayak::ValidationResult::Invalid.new(errors: first_result.errors + second_result.errors)
|
92
|
+
else
|
93
|
+
T.absurd(first_result)
|
94
|
+
end
|
95
|
+
else
|
96
|
+
T.absurd(first_result)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
alias & both
|
102
|
+
|
103
|
+
sig { params(key: Symbol).returns(Rule[Value, [Symbol, Error]]) }
|
104
|
+
def with_key(key)
|
105
|
+
Rule[Value, [Symbol, Error]].new do |checked|
|
106
|
+
result = check(checked)
|
107
|
+
case result
|
108
|
+
when ::Mayak::ValidationResult::Valid
|
109
|
+
::Mayak::ValidationResult::Valid[[Symbol, Error]].new
|
110
|
+
when ::Mayak::ValidationResult::Invalid
|
111
|
+
::Mayak::ValidationResult::Invalid[[Symbol, Error]].new(
|
112
|
+
errors: result.errors.map { |error| [key, error] }
|
113
|
+
)
|
114
|
+
else
|
115
|
+
T.absurd(result)
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
|
121
|
+
sig {
|
122
|
+
params(
|
123
|
+
value: T.any(Float, Integer)
|
124
|
+
).returns(Rule[T.any(Float, Integer), String])
|
125
|
+
}
|
126
|
+
def self.greater_than(value)
|
127
|
+
Rule[T.any(Float, Integer), String].new do |checked|
|
128
|
+
if checked > value
|
129
|
+
::Mayak::ValidationResult::Valid.new
|
130
|
+
else
|
131
|
+
::Mayak::ValidationResult::Invalid.new(
|
132
|
+
errors: ["Value #{checked} should be greater than the #{value}"]
|
133
|
+
)
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
sig {
|
139
|
+
params(
|
140
|
+
value: T.any(Float, Integer)
|
141
|
+
).returns(Rule[T.any(Float, Integer), String])
|
142
|
+
}
|
143
|
+
def self.less_than(value)
|
144
|
+
Rule[T.any(Float, Integer), String].new do |checked|
|
145
|
+
if checked < value
|
146
|
+
::Mayak::ValidationResult::Valid.new
|
147
|
+
else
|
148
|
+
::Mayak::ValidationResult::Invalid.new(
|
149
|
+
errors: ["Value #{checked} should be less than the #{value}"]
|
150
|
+
)
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
sig {
|
156
|
+
params(
|
157
|
+
value: T.any(Float, Integer)
|
158
|
+
).returns(Rule[T.any(Float, Integer), String])
|
159
|
+
}
|
160
|
+
def self.equal_to(value)
|
161
|
+
Rule[T.any(Float, Integer), String].new do |checked|
|
162
|
+
if checked == value
|
163
|
+
::Mayak::ValidationResult::Valid.new
|
164
|
+
else
|
165
|
+
::Mayak::ValidationResult::Invalid.new(
|
166
|
+
errors: ["Value #{checked} should equal to #{value}"]
|
167
|
+
)
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
sig {
|
173
|
+
params(
|
174
|
+
value: T.any(Float, Integer)
|
175
|
+
).returns(Rule[T.any(Float, Integer), String])
|
176
|
+
}
|
177
|
+
def self.greater_than_or_equal_to(value)
|
178
|
+
(greater_than(value) | equal_to(value)).error_from_value do |checked|
|
179
|
+
"Value #{checked} should greater than or equal to #{value}"
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
sig {
|
184
|
+
params(
|
185
|
+
value: T.any(Float, Integer)
|
186
|
+
).returns(Rule[T.any(Float, Integer), String])
|
187
|
+
}
|
188
|
+
def self.less_than_or_equal_to(value)
|
189
|
+
(less_than(value) | equal_to(value)).error_from_value do |checked|
|
190
|
+
"Value #{checked} should less than or equal to #{value}"
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
sig {
|
195
|
+
params(
|
196
|
+
value: T.any(Float, Integer)
|
197
|
+
).returns(Rule[T.any(Float, Integer), String])
|
198
|
+
}
|
199
|
+
def self.positive(value)
|
200
|
+
greater_than(0)
|
201
|
+
end
|
202
|
+
|
203
|
+
sig {
|
204
|
+
params(
|
205
|
+
value: T.any(Float, Integer)
|
206
|
+
).returns(Rule[T.any(Float, Integer), String])
|
207
|
+
}
|
208
|
+
def self.negative(value)
|
209
|
+
less_than(0)
|
210
|
+
end
|
211
|
+
|
212
|
+
sig {
|
213
|
+
returns(Rule[T.any(String, T::Array[T.anything], T::Hash[T.anything, T.anything], String), String])
|
214
|
+
}
|
215
|
+
def self.not_empty
|
216
|
+
Rule[T.any(String, Array, Hash, String), String].new do |checked|
|
217
|
+
if checked.empty?
|
218
|
+
::Mayak::ValidationResult::Invalid.new(
|
219
|
+
errors: ["Value #{checked} should not be empty equal"]
|
220
|
+
)
|
221
|
+
else
|
222
|
+
::Mayak::ValidationResult::Valid.new
|
223
|
+
end
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
227
|
+
sig {
|
228
|
+
type_parameters(:Value, :Error)
|
229
|
+
.params(rule: Rule[T.type_parameter(:Value), T.type_parameter(:Error)])
|
230
|
+
.returns(Rule[T.nilable(T.type_parameter(:Value)), T.type_parameter(:Error)])
|
231
|
+
}
|
232
|
+
def self.not_nil(rule)
|
233
|
+
Rule[T.nilable(T.type_parameter(:Value)), T.type_parameter(:Error)].new do |checked|
|
234
|
+
case checked
|
235
|
+
when NilClass
|
236
|
+
::Mayak::ValidationResult::Invalid.new(errors: ["Should not be nil"])
|
237
|
+
else
|
238
|
+
rule.check(checked)
|
239
|
+
end
|
240
|
+
end
|
241
|
+
end
|
242
|
+
|
243
|
+
sig {
|
244
|
+
type_parameters(:Value, :Error)
|
245
|
+
.params(rule: Rule[T.type_parameter(:Value), [Symbol, T.type_parameter(:Error)]])
|
246
|
+
.returns(Rule[T.type_parameter(:Value), T::Hash[Symbol, T.type_parameter(:Error)]])
|
247
|
+
}
|
248
|
+
def self.with_keys_aggregated(rule)
|
249
|
+
Rule[T.type_parameter(:Value), T::Hash[Symbol, T.type_parameter(:Error)]].new do |checked|
|
250
|
+
result = rule.check(checked)
|
251
|
+
case result
|
252
|
+
when ::Mayak::ValidationResult::Valid
|
253
|
+
::Mayak::ValidationResult::Valid[T::Hash[Symbol, T.type_parameter(:Error)]].new
|
254
|
+
when ::Mayak::ValidationResult::Invalid
|
255
|
+
accumulated = result.errors.reduce({}) do |acc, tuple|
|
256
|
+
key, error = tuple
|
257
|
+
if acc.key?(key)
|
258
|
+
acc[key] << error
|
259
|
+
else
|
260
|
+
acc[key] = [error]
|
261
|
+
end
|
262
|
+
end
|
263
|
+
::Mayak::ValidationResult::Invalid[T::Hash[Symbol, T.type_parameter(:Error)]].new(
|
264
|
+
accumulated
|
265
|
+
)
|
266
|
+
else
|
267
|
+
T.absurd(result)
|
268
|
+
end
|
269
|
+
end
|
270
|
+
end
|
271
|
+
end
|
272
|
+
end
|
273
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# typed: strict
|
3
|
+
|
4
|
+
module Mayak
|
5
|
+
module Validations
|
6
|
+
class Contract
|
7
|
+
extend T::Sig
|
8
|
+
extend T::Generic
|
9
|
+
|
10
|
+
Value = type_member
|
11
|
+
Error = type_member
|
12
|
+
|
13
|
+
sig { returns(T::Set[Rule[Value, [Symbol, Error]]]) }
|
14
|
+
attr_reader :rule_set
|
15
|
+
|
16
|
+
sig { params(rule_set: T::Set[Rule[Value, [Symbol, Error]]]).void }
|
17
|
+
def initialize(rule_set = Set.new)
|
18
|
+
@rule_set = T.let(rule_set, T::Set[Rule[Value, [Symbol, Error]]])
|
19
|
+
end
|
20
|
+
|
21
|
+
sig {
|
22
|
+
type_parameters(:MappedValue)
|
23
|
+
.params(
|
24
|
+
rule: Rule[T.type_parameter(:MappedValue), Error],
|
25
|
+
key: Symbol,
|
26
|
+
blk: T.proc.params(arg0: Value).returns(T.type_parameter(:MappedValue))
|
27
|
+
).returns(Contract[Value, Error])
|
28
|
+
}
|
29
|
+
def validate(rule, key:, &blk)
|
30
|
+
rule = Rule[Value, Error].new do |checked|
|
31
|
+
rule.check(blk.call(checked))
|
32
|
+
end
|
33
|
+
Contract.new(rule_set.add(rule.with_key(key)))
|
34
|
+
end
|
35
|
+
|
36
|
+
sig { params(value: Value).returns(::Mayak::ValidationResult[T::Hash[Symbol, Error]]) }
|
37
|
+
def check(value)
|
38
|
+
initial = T.let(
|
39
|
+
::Mayak::ValidationResult::Valid[T::Hash[Symbol, Error]].new,
|
40
|
+
::Mayak::ValidationResult[T::Hash[Symbol, Error]]
|
41
|
+
)
|
42
|
+
rule_set.reduce(initial) do |aggreated_result, rule|
|
43
|
+
current_result = Rule.with_keys_aggregated(rule).check(value)
|
44
|
+
case aggreated_result
|
45
|
+
when ::Mayak::ValidationResult::Valid
|
46
|
+
current_result
|
47
|
+
when ::Mayak::ValidationResult::Invalid
|
48
|
+
case current_result
|
49
|
+
when ::Mayak::ValidationResult::Valid
|
50
|
+
aggreated_result
|
51
|
+
when ::Mayak::ValidationResult::Invalid
|
52
|
+
::Mayak::ValidationResult::Invalid[T::Hash[Symbol, Error]].new(errors: [ ])
|
53
|
+
else
|
54
|
+
T.absurd(current_result)
|
55
|
+
end
|
56
|
+
else
|
57
|
+
T.absurd(aggreated_result)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
|
data/lib/mayak/version.rb
CHANGED
data/lib/mayak.rb
CHANGED
@@ -16,6 +16,7 @@ require_relative 'mayak/weak_ref'
|
|
16
16
|
require_relative 'mayak/decoder'
|
17
17
|
require_relative 'mayak/encoder'
|
18
18
|
require_relative 'mayak/hash_serializable'
|
19
|
+
require_relative 'mayak/lazy'
|
19
20
|
|
20
21
|
require_relative 'mayak/caching/unbounded_cache'
|
21
22
|
require_relative 'mayak/caching/lru_cache'
|
data/mayak.gemspec
CHANGED
@@ -4,7 +4,7 @@
|
|
4
4
|
|
5
5
|
Gem::Specification.new do |spec|
|
6
6
|
spec.name = "mayak"
|
7
|
-
spec.version = "0.0
|
7
|
+
spec.version = "0.1.0"
|
8
8
|
spec.summary = "Set of fully typed utility classes and interfaces integrated with Sorbet."
|
9
9
|
spec.description = spec.summary
|
10
10
|
spec.authors = ["Daniil Bober"]
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mayak
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Daniil Bober
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-06-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: sorbet-runtime
|
@@ -100,6 +100,7 @@ executables: []
|
|
100
100
|
extensions: []
|
101
101
|
extra_rdoc_files: []
|
102
102
|
files:
|
103
|
+
- LICENSE
|
103
104
|
- README.md
|
104
105
|
- lib/mayak.rb
|
105
106
|
- lib/mayak/cache.rb
|
@@ -124,6 +125,7 @@ files:
|
|
124
125
|
- lib/mayak/http/verb.rb
|
125
126
|
- lib/mayak/json.rb
|
126
127
|
- lib/mayak/json/encoder.rb
|
128
|
+
- lib/mayak/lazy.rb
|
127
129
|
- lib/mayak/monads/README.md
|
128
130
|
- lib/mayak/monads/maybe.rb
|
129
131
|
- lib/mayak/monads/result.rb
|
@@ -133,6 +135,8 @@ files:
|
|
133
135
|
- lib/mayak/predicates/rule.rb
|
134
136
|
- lib/mayak/random.rb
|
135
137
|
- lib/mayak/validation_result.rb
|
138
|
+
- lib/mayak/validations/rule.rb
|
139
|
+
- lib/mayak/validations/validation.rb
|
136
140
|
- lib/mayak/version.rb
|
137
141
|
- lib/mayak/weak_ref.rb
|
138
142
|
- mayak.gemspec
|