mayak 0.2.0 → 0.2.2
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 +4 -4
- data/README.md +5 -52
- data/lib/bundled_rbi/mayak.rbi +20 -0
- data/lib/mayak/encoder.rb +2 -3
- data/lib/mayak/json_codec/from_hash_serializable.rb +38 -0
- data/lib/mayak/json_codec.rb +29 -0
- data/lib/mayak.rb +3 -1
- data/mayak.gemspec +2 -1
- metadata +19 -7
- data/lib/mayak/caching/README.md +0 -100
- data/lib/mayak/http/README.md +0 -105
- data/lib/mayak/json/encoder.rb +0 -21
- data/lib/mayak/lazy/README.md +0 -226
- data/lib/mayak/monads/README.md +0 -1364
data/lib/mayak/lazy/README.md
DELETED
@@ -1,226 +0,0 @@
|
|
1
|
-
# Lazy
|
2
|
-
|
3
|
-
`Lazy` classs represents a value that evaluates only during it's access, and evaluates only once
|
4
|
-
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
|
5
|
-
and then stores it afterward.
|
6
|
-
|
7
|
-
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.
|
8
|
-
Note that the block is not executed right away.
|
9
|
-
|
10
|
-
```ruby
|
11
|
-
lazy1 = ::Mayak::Lazy[Integer].new { 1 }
|
12
|
-
|
13
|
-
buffer = []
|
14
|
-
lazy2 = ::Mayak::Lazy[Integer].new do
|
15
|
-
buffer << 1
|
16
|
-
1
|
17
|
-
end
|
18
|
-
buffer
|
19
|
-
#> []
|
20
|
-
```
|
21
|
-
|
22
|
-
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
|
23
|
-
of this method won't execute the block again.
|
24
|
-
|
25
|
-
```ruby
|
26
|
-
buffer = []
|
27
|
-
lazy = ::Mayak::Lazy[Integer].new do
|
28
|
-
buffer << 1
|
29
|
-
1
|
30
|
-
end
|
31
|
-
buffer
|
32
|
-
#> []
|
33
|
-
|
34
|
-
# Will execute the block and return the computed value.
|
35
|
-
lazy.value
|
36
|
-
#> 1
|
37
|
-
buffer
|
38
|
-
#> [1]
|
39
|
-
|
40
|
-
# Will return the memoized value, but won't call the block again
|
41
|
-
lazy.value
|
42
|
-
#> 1
|
43
|
-
buffer
|
44
|
-
#> [1]
|
45
|
-
```
|
46
|
-
|
47
|
-
`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.
|
48
|
-
|
49
|
-
In more imperative style
|
50
|
-
```ruby
|
51
|
-
sig { params(env_variable: String, file_content: ::Mayak::Lazy[String], default: String).returns(String) }
|
52
|
-
def fetch_config(env_variable, file_content, default)
|
53
|
-
from_environment = ENV[env_variable]
|
54
|
-
if env.empty?
|
55
|
-
file_config = ::Core::Json.parse(file_content.value).success_or({})
|
56
|
-
from_file = file_config["configuration"]
|
57
|
-
if from_file.empty?
|
58
|
-
default
|
59
|
-
else
|
60
|
-
from_file
|
61
|
-
end
|
62
|
-
else
|
63
|
-
from_environment
|
64
|
-
end
|
65
|
-
end
|
66
|
-
```
|
67
|
-
|
68
|
-
Using Mayak monads:
|
69
|
-
```ruby
|
70
|
-
include ::Mayak::Monads::Maybe::Mixin
|
71
|
-
|
72
|
-
sig { params(env_variable: String, file_content: ::Mayak::Lazy[String], default: String).returns(String) }
|
73
|
-
def fetch_config(env_variable, file_content, default)
|
74
|
-
Maybe(ENV[env_variable])
|
75
|
-
.recover_with_maybe(::Core::Json.parse(file_content.value).to_maybe)
|
76
|
-
.flat_map { |json| Maybe(json["configuration"]) }
|
77
|
-
.value_or(default)
|
78
|
-
end
|
79
|
-
```
|
80
|
-
|
81
|
-
This method receives name of environment variable, and file content as lazy value. The method
|
82
|
-
tries to read the environment variable, and if it's not present and reads the file content to find the configuration.
|
83
|
-
`Lazy` allows to incapsulate behaviour of reading from file, so it can be passed as dependency, method `#fetch_config` doesn't
|
84
|
-
know anything about reading from file, but because of usage of `lazy` we can postpone it's execution thus avoiding unnecessary work.
|
85
|
-
|
86
|
-
`Lazy` can be transformed via methods `#map` and `#flat_map`.
|
87
|
-
|
88
|
-
Method `#map` allows to transform value inside `Lazy` without triggering executing. Note that `#map` returns
|
89
|
-
a new instance without mutating previous `Lazy`.
|
90
|
-
```ruby
|
91
|
-
int_lazy = ::Mayak::Lazy[Integer].new do
|
92
|
-
puts("On initialize")
|
93
|
-
1
|
94
|
-
end
|
95
|
-
string_lazy = int_lazy.map do |int|
|
96
|
-
puts("On mapping")
|
97
|
-
int.to_s
|
98
|
-
end
|
99
|
-
int_lazy.value # 1
|
100
|
-
#> On initialize
|
101
|
-
|
102
|
-
string_lazy.value # "1"
|
103
|
-
#> On initialize
|
104
|
-
#> On mapping
|
105
|
-
|
106
|
-
sig { params(file_content: ::Mayak::Lazy[String]).returns(::Mayak::Lazy[Maybe[String]]) }
|
107
|
-
def file_content_config(file_content)
|
108
|
-
file_content.map do |file_content|
|
109
|
-
::Core::Json
|
110
|
-
.parse(file_content.value)
|
111
|
-
.to_maybe
|
112
|
-
.flat_map { |json| Maybe(json["configuration"]) }
|
113
|
-
end
|
114
|
-
end
|
115
|
-
```
|
116
|
-
|
117
|
-
Method `#flat_map` allows to chain lazy computations. It receives a block, that builds a new `Lazy` value from the value of original
|
118
|
-
`Lazy` and returns a new instance of `Lazy`.
|
119
|
-
|
120
|
-
```ruby
|
121
|
-
sig { params(env_name: String).returns(::Mayak::Lazy[String]) }
|
122
|
-
def lazy_env(env_name)
|
123
|
-
::Mayak::Lazy[String].new { ENV[env_name] }
|
124
|
-
end
|
125
|
-
|
126
|
-
env_variable_name = ::Mayak::Lazy[String].new { "VARIABLE" }
|
127
|
-
env_variable = env_variable_name.flat_map { |env_name| lazy_env(env_name) }
|
128
|
-
```
|
129
|
-
|
130
|
-
This may be useful when want to perform a lazy computation based on result of some other lazy computation without enforcing the evaluation.
|
131
|
-
|
132
|
-
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.
|
133
|
-
```ruby
|
134
|
-
sig { params(file_name: String).returns(::Mayak::Lazy[T::Array[String]]) }
|
135
|
-
def read_file_lines(file_name)
|
136
|
-
::Mayak::Lazy[T::Array[String]].new { File.read(file_name).split }
|
137
|
-
end
|
138
|
-
```
|
139
|
-
|
140
|
-
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`:
|
141
|
-
|
142
|
-
```ruby
|
143
|
-
sig { params(file_name: String).returns(::Mayak::Lazy[T::Array[String]]) }
|
144
|
-
def read_first_file(file_name)
|
145
|
-
read_file_lines(file_name).flat_map do |file_names|
|
146
|
-
Maybe(file_names.first)
|
147
|
-
.filter(&:empty?)
|
148
|
-
.map { |file| read_file_lines(file) }
|
149
|
-
.value_or(::Mayak::Lazy[T::Array[String]].new { [] })
|
150
|
-
end
|
151
|
-
end
|
152
|
-
```
|
153
|
-
|
154
|
-
In order to combine two lazies of different types into a single one, method `#combine` can be used.
|
155
|
-
This method receives another lazy (it can be lazy of different type), and a block
|
156
|
-
and returns a lazy containing result of applying passed blocked to values calculated by lazies.
|
157
|
-
|
158
|
-
```ruby
|
159
|
-
class ConfigFiles < T::Struct
|
160
|
-
const :database_config_file, ::File
|
161
|
-
const :server_config_file, ::File
|
162
|
-
end
|
163
|
-
|
164
|
-
sig { returns(::Mayak::Lazy[File]) }
|
165
|
-
def database_config_file
|
166
|
-
::Mayak::Lazy[File].new { File.new(DATABASE_CONFIG_FILE_NAME, "r") }
|
167
|
-
end
|
168
|
-
|
169
|
-
sig { returns(::Mayak::Lazy[File]) }
|
170
|
-
def server_config_file
|
171
|
-
::Mayak::Lazy[File].new { File.new(SERVER_CONFIG_FILE_NAME, "r") }
|
172
|
-
end
|
173
|
-
|
174
|
-
sig { returns(::Mayak::Lazy[ConfigFiles]) }
|
175
|
-
def config_files
|
176
|
-
database_config_file.combine(server_config_file) do |db_file, server_file|
|
177
|
-
ConfigFiles.new(
|
178
|
-
database_config_file: database_config_file,
|
179
|
-
server_config_file: server_file
|
180
|
-
)
|
181
|
-
end
|
182
|
-
end
|
183
|
-
```
|
184
|
-
|
185
|
-
The same behaviour can be achieved with a method `.combine_two`:
|
186
|
-
|
187
|
-
```ruby
|
188
|
-
sig { returns(::Mayak::Lazy[ConfigFiles]) }
|
189
|
-
def config_files
|
190
|
-
::Mayak::Lazy.combine_two(database_config_file, server_config_file) do |db_file, server_file|
|
191
|
-
ConfigFiles.new(
|
192
|
-
database_config_file: database_config_file,
|
193
|
-
server_config_file: server_file
|
194
|
-
)
|
195
|
-
end
|
196
|
-
end
|
197
|
-
```
|
198
|
-
|
199
|
-
There are also methods `.combine_three`, `.combine_four` upto `.combine_sevel` to combine multiple lazies of diffent types.
|
200
|
-
|
201
|
-
If you need to combined multiple lazies containing the same value, you can use `.combine_many`. It works
|
202
|
-
as `Array#reduce`: receives an array of lazies containing the same type, initial value of result type, and a block
|
203
|
-
receiving accumulator value of result type, and value of next lazy.
|
204
|
-
|
205
|
-
```ruby
|
206
|
-
sig { returns(::Mayak::Lazy[Integer]) }
|
207
|
-
def lazy
|
208
|
-
::Mayak::Lazy.combine_many(
|
209
|
-
[::Mayak::Lazy[Integer].new(1), ::Mayak::Lazy[Integer].new(2), ::Mayak::Lazy[Integer].new(3)],
|
210
|
-
0
|
211
|
-
) { |acc, value| acc + value }
|
212
|
-
end
|
213
|
-
|
214
|
-
lazy.value # 10
|
215
|
-
```
|
216
|
-
|
217
|
-
If you need to transform array of lazies of some value into lazy of array of the value, you can use `.sequence` method.
|
218
|
-
|
219
|
-
```ruby
|
220
|
-
sig { returns(::Mayak::Lazy[T::Array[Integer]]) }
|
221
|
-
def lazy
|
222
|
-
::Mayak::Lazy.sequence([::Mayak::Lazy[Integer].new(1), ::Mayak::Lazy[Integer].new(2), ::Mayak::Lazy[Integer].new(3)])
|
223
|
-
end
|
224
|
-
|
225
|
-
lazy.value # [1, 2, 3]
|
226
|
-
```
|