knowledge 0.1.0

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.
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Knowledge
4
+ #
5
+ # === Description ===
6
+ #
7
+ # This error class should be considered as the lib's standard error.
8
+ # All error classes inherit from this one.
9
+ # The goal is to be able to rescue Knowledge::Error outside the lib and catch them all.
10
+ #
11
+ # === Usage ===
12
+ #
13
+ # You have many examples behind. Just inherit from this class and it's ok.
14
+ #
15
+ # @example:
16
+ # class ::MyCustomKnowledgeError < Knowledge::Error; end
17
+ #
18
+ class Error < ::StandardError; end
19
+
20
+ #
21
+ # === Description ===
22
+ #
23
+ # This error is used when, at some point, we can't find the adapter we're looking for
24
+ #
25
+ class AdapterNotFound < Error; end
26
+
27
+ #
28
+ # === Description ===
29
+ #
30
+ # This error is used when an adapter has no #run method declared
31
+ #
32
+ class AdapterRunMethodNotImplemented < Error; end
33
+
34
+ #
35
+ # === Description ===
36
+ #
37
+ # This error is pretty generic and is meant to be used when we're not able to gather infos in order to set vars.
38
+ #
39
+ class LearnError < Error; end
40
+
41
+ #
42
+ # === Description ===
43
+ #
44
+ # This error is used when we fail registering an adapter.
45
+ #
46
+ class RegisterError < Error; end
47
+ end
@@ -0,0 +1,77 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Knowledge
4
+ #
5
+ # === Description ===
6
+ #
7
+ # We all need an initializer, here's this lib's initializer.
8
+ # Its role is to gather all informations and run the enabled adapters.
9
+ #
10
+ # === Usage ===
11
+ #
12
+ # @example:
13
+ # Knowledge::Initializer.new(adapters: adapters, params: { foo: :bar }, setter: setter, variables: variables).run
14
+ #
15
+ # Knowledge::Initializer.run(adapters: adapters, params: { foo: :bar }, setter: setter, variables: variables)
16
+ #
17
+ # === Attributes ===
18
+ #
19
+ # @attr_reader [Array<String | Symbol>] adapters
20
+ # @attr_reader [Hash] params
21
+ # @attr_reader [Class] setter
22
+ # @attr_reader [Hash] variables
23
+ #
24
+ class Initializer
25
+ # == Attributes ==================================================================================================
26
+ attr_reader :adapters, :params, :setter, :variables
27
+
28
+ # == Constructor =================================================================================================
29
+ #
30
+ # @option [Array<Class>] :adapters
31
+ # @option [Hash] :params
32
+ # @option [Class] :setter
33
+ # @option [Hash] :variables
34
+ #
35
+ def initialize(adapters:, params:, setter:, variables:)
36
+ @adapters = adapters
37
+ @params = params
38
+ @setter = setter
39
+ @variables = variables
40
+ end
41
+
42
+ # == Class methods ===============================================================================================
43
+ class << self
44
+ #
45
+ # === Description ===
46
+ #
47
+ # Instanciates the current class and runs all registered adapters.
48
+ #
49
+ # === Parameters ===
50
+ #
51
+ # @option [Hash{Symbol => Class}] :adapters
52
+ # @option [Hash] :params
53
+ # @option [Class] :setter
54
+ # @option [Hash] :variables
55
+ #
56
+ def run(adapters:, params:, setter:, variables: {})
57
+ new(adapters: adapters, params: params, setter: setter, variables: variables).run
58
+ end
59
+ end
60
+
61
+ # == Instance methods ============================================================================================
62
+ #
63
+ # === Description ===
64
+ #
65
+ # Runs all registered adapters.
66
+ #
67
+ def run
68
+ Hash(adapters).each do |name, adapter|
69
+ adapter.new(
70
+ params: params[name.to_sym] || params,
71
+ setter: setter,
72
+ variables: variables[name.to_sym] || variables
73
+ ).run
74
+ end
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,381 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'yaml'
4
+
5
+ require 'knowledge/initializer'
6
+ require 'knowledge/adapters'
7
+ require 'knowledge/setter'
8
+
9
+ module Knowledge
10
+ #
11
+ # === Description ===
12
+ #
13
+ # Knowledge is something that needs some learning.
14
+ #
15
+ # === Usage ===
16
+ #
17
+ # @example:
18
+ #
19
+ # learner = Knowledge::Learner.new
20
+ #
21
+ # === Attributes ===
22
+ #
23
+ # @attr_reader [Hash] additionnal_params
24
+ # @attr_reader [Hash{Symbol => Class}] available_adapters
25
+ # @attr_reader [Hash{Symbol => Class}] enabled_adapters
26
+ # @attr [Class] setter
27
+ # @attr_reader [Hash] variables
28
+ #
29
+ class Learner
30
+ # == Attributes ====================================================================================================
31
+ attr_accessor :setter
32
+ attr_reader :additionnal_params, :available_adapters, :enabled_adapters, :variables
33
+
34
+ # == Constructor ===================================================================================================
35
+ def initialize
36
+ @additionnal_params = {}
37
+ @available_adapters = {}
38
+ @enabled_adapters = {}
39
+ @setter = ::Knowledge::Setter.new
40
+ @variables = {}
41
+ end
42
+
43
+ # == Class methods =================================================================================================
44
+ class << self
45
+ attr_reader :adapters
46
+
47
+ def register_default_adapter(names:, klass:)
48
+ @adapters ||= {}
49
+
50
+ names.each { |name| @adapters[name.to_sym] = klass }
51
+ end
52
+ end
53
+
54
+ # == Instance methods ==============================================================================================
55
+ #
56
+ # === Description ===
57
+ #
58
+ # Gathers all the knowledge and put it into your app.
59
+ #
60
+ # === Usage ===
61
+ #
62
+ # @example:
63
+ # learner = Knowledge::Learner.new
64
+ # # Do some config (add adapters, define your setter, etc.)
65
+ # learner.gather!
66
+ #
67
+ def gather!
68
+ ::Knowledge::Initializer.new(
69
+ adapters: enabled_adapters,
70
+ params: additionnal_params,
71
+ setter: setter,
72
+ variables: variables
73
+ ).run
74
+ end
75
+
76
+ # == Adapters methods ============================================================================================
77
+ #
78
+ # === Description ===
79
+ #
80
+ # Sets additional params to be passed to the adapter through params option.
81
+ #
82
+ # === Usage ===
83
+ #
84
+ # @example:
85
+ # learner = Knowledge::Learner.new
86
+ # learner.add_adapter_param(adapter: :custom, name: :base_path, value: '/base/path')
87
+ #
88
+ # === Parameters ===
89
+ #
90
+ # @option [String | Symbol] :adapter
91
+ # @option [String | Symbol] :name
92
+ # @option [any] :value
93
+ #
94
+ def add_adapter_param(adapter:, name:, value:)
95
+ @additionnal_params[adapter.to_sym] ||= {}
96
+ @additionnal_params[adapter.to_sym][name] = value
97
+ end
98
+
99
+ #
100
+ # === Description ===
101
+ #
102
+ # Sets additional params to be passed to the adapter through params option.
103
+ #
104
+ # === Usage ===
105
+ #
106
+ # @example:
107
+ # learner = Knowledge::Learner.new
108
+ # learner.add_adapter_param(name: :base_path, value: '/base/path')
109
+ #
110
+ # === Parameters ===
111
+ #
112
+ # @option [String | Symbol] :adapter
113
+ # @option [any] :params
114
+ #
115
+ def add_adapter_params(adapter:, params:)
116
+ @additionnal_params[adapter.to_sym] = params
117
+ end
118
+
119
+ #
120
+ # === Description ===
121
+ #
122
+ # Disables an adapter.
123
+ #
124
+ # === Usage ===
125
+ #
126
+ # @example:
127
+ # learner = Knowledge::Learner.new
128
+ # learner.register_adapter(name: :my_adapter, klass: MyAdapter, enable: true)
129
+ # # Somewhere else in the code
130
+ # learner.disable_adapter(name: :my_adapter) if should_disable_custom_adapter?
131
+ #
132
+ # === Parameters ===
133
+ #
134
+ # @option [String | Symbol] :name
135
+ #
136
+ def disable_adapter(name:)
137
+ @enabled_adapters.delete(name.to_sym)
138
+ end
139
+
140
+ #
141
+ # === Description ===
142
+ #
143
+ # Enables an adapter.
144
+ #
145
+ # === Usage ===
146
+ #
147
+ # @example:
148
+ # learner = Knowledge::Learner.new
149
+ # learner.register_adapter(name: :my_adapter, klass: MyAdapter)
150
+ # learner.enable_adapter(name: :my_adapter)
151
+ #
152
+ # === Errors ===
153
+ #
154
+ # @raises [Knowledge::AdapterNotFound] if adapter is not available
155
+ #
156
+ # === Parameters ===
157
+ #
158
+ # @option [String | Symbol] :name
159
+ # @option [Hash | String | nil] :variables
160
+ #
161
+ def enable_adapter(name:, variables: nil)
162
+ _key, klass = available_adapters.find { |key, _klass| key.to_sym == name.to_sym }
163
+
164
+ raise Knowledge::AdapterNotFound, "Cannot find \"#{name}\" in available adapters" if klass.nil?
165
+
166
+ @enabled_adapters[name.to_sym] = klass
167
+ set_adapter_variables(name: name, variables: variables)
168
+ end
169
+
170
+ #
171
+ # === Description ===
172
+ #
173
+ # Registers an adapter and enable it if asked.
174
+ #
175
+ # === Usage ===
176
+ #
177
+ # @example:
178
+ # learner = Knowledge::Learner.new
179
+ # learner.register_adapter(name: :my_adapter, klass: MyAdapter, enable: true)
180
+ #
181
+ # === Parameters ===
182
+ #
183
+ # @option [String | Symbol] :name
184
+ # @option [Class] :klass
185
+ # @option [Boolean] :enable
186
+ # @option [Hash | String | nil] :variables
187
+ #
188
+ def register_adapter(name:, klass:, enable: false, variables: nil)
189
+ @available_adapters[name.to_sym] = klass
190
+ enable_adapter(name: name) if enable
191
+ set_adapter_variables(name: name, variables: variables)
192
+ end
193
+
194
+ #
195
+ # === Description ===
196
+ #
197
+ # Sets variables for a given adapter
198
+ #
199
+ # === Usage ===
200
+ #
201
+ # @example:
202
+ # learner = Knowledge::Learner.new
203
+ # learner.set_adapter_variables(name: :default, variables: { foo: :bar })
204
+ #
205
+ # === Attributes ===
206
+ #
207
+ # @option [String | Symbol] :name
208
+ # @option [Hash | nil] :variables
209
+ #
210
+ def set_adapter_variables(name:, variables: nil)
211
+ return unless variables
212
+
213
+ case variables
214
+ when Hash
215
+ set_adapter_variables_by_hash(name: name, variables: variables)
216
+ when String
217
+ set_adapter_variables(name: name, variables: yaml_content(variables))
218
+ else
219
+ raise "Unknown variables type #{variables.class}"
220
+ end
221
+ rescue StandardError => e
222
+ raise ::Knowledge::LearnError, e.message
223
+ end
224
+
225
+ #
226
+ # === Description ===
227
+ #
228
+ # Sets variables as a hash for a given adapter
229
+ #
230
+ # === Usage ===
231
+ #
232
+ # @example
233
+ # learner = Knowledge::Learner.new
234
+ # learner.set_adapter_variables_by_hash(name: :default, variables: { foo: :bar })
235
+ #
236
+ # === Attributes ===
237
+ #
238
+ # @option [String | Symbol] :name
239
+ # @option [Hash] :variables
240
+ #
241
+ def set_adapter_variables_by_hash(name:, variables:)
242
+ variables = variables[name.to_s] if variables.key?(name.to_s)
243
+ variables = variables[name.to_sym] if variables.key?(name.to_sym)
244
+ @variables[name.to_sym] = variables
245
+ end
246
+
247
+ #
248
+ # === Description ===
249
+ #
250
+ # Unregisters an adapter and disable it.
251
+ #
252
+ # === Usage ===
253
+ #
254
+ # @example:
255
+ # learner = Knowledge::Learner.new
256
+ # learner.register_adapter(name: :my_adapter, klass: MyAdapter)
257
+ # # somewhere else in the code
258
+ # learner.unregister_adapter(name: :my_adapter)
259
+ #
260
+ # === Parameters ===
261
+ #
262
+ # @option [String | Symbol] :name
263
+ #
264
+ def unregister_adapter(name:)
265
+ disable_adapter(name: name)
266
+ @available_adapters.delete(name.to_sym)
267
+ end
268
+
269
+ #
270
+ # === Description ===
271
+ #
272
+ # Registers & enables one of the lib's adapters.
273
+ #
274
+ # === Usage ===
275
+ #
276
+ # @example:
277
+ # learner = Knowledge::Learner.new
278
+ # learner.use(name: :ssm)
279
+ #
280
+ # === Parameters ===
281
+ #
282
+ # @option [String | Symbol] name
283
+ # @option [Boolean] enable
284
+ #
285
+ def use(name:, enable: true)
286
+ adapter = self.class.adapters[name.to_sym]
287
+
288
+ raise ::Knowledge::RegisterError, "Unable to register following: #{name}" if adapter.nil?
289
+
290
+ register_adapter(name: name.to_sym, klass: adapter, enable: enable)
291
+ end
292
+
293
+ # == Variables config ==============================================================================================
294
+ #
295
+ # === Description ===
296
+ #
297
+ # Setter for the variables config.
298
+ #
299
+ # === Usage ===
300
+ #
301
+ # @example:
302
+ # learner = Knowledge::Learner.new
303
+ # learner.variables = { name: 'value' }
304
+ #
305
+ # @example:
306
+ # learner = Knowledge::Learner.new
307
+ # learner.use(name: :env)
308
+ # learner.variables = { name: 'ENV_KEY' }
309
+ #
310
+ # @example:
311
+ # learner = Knowledge::Learner.new
312
+ # learner.variables = 'path/to/vars/config/file.yml'
313
+ #
314
+ # === Errors ===
315
+ #
316
+ # @raise [Knowledge::LearnError] if parameter isn't a hash or a string
317
+ #
318
+ # === Parameters
319
+ #
320
+ # @param [String | Hash] path_or_descriptor
321
+ #
322
+ def variables=(path_or_descriptor)
323
+ case path_or_descriptor
324
+ when Hash
325
+ @variables = path_or_descriptor
326
+ when String
327
+ fetch_variables_config(path_or_descriptor)
328
+ else
329
+ raise ::Knowledge::LearnError, "Unable to understand following path or descriptor: #{path_or_descriptor}"
330
+ end
331
+ end
332
+
333
+ protected
334
+
335
+ #
336
+ # === Description ===
337
+ #
338
+ # Opens the config file and sets the variable config.
339
+ #
340
+ # === Parameters ===
341
+ #
342
+ # @param [String] path
343
+ #
344
+ def fetch_variables_config(path)
345
+ descriptor = yaml_content(path)
346
+ @variables = descriptor[::Knowledge.config.environment.to_s] || descriptor
347
+ end
348
+
349
+ #
350
+ # === Description ===
351
+ #
352
+ # Loads YAML file content
353
+ #
354
+ # === Parameters ===
355
+ #
356
+ # @param [String] path
357
+ #
358
+ # @return [Hash]
359
+ #
360
+ def yaml_content(path)
361
+ ::YAML.safe_load(::File.open(path))
362
+ end
363
+ end
364
+ end
365
+
366
+ # Registering default adapters
367
+
368
+ Knowledge::Learner.register_default_adapter(
369
+ klass: Knowledge::Adapters::Environment,
370
+ names: %i[env environment env_vars]
371
+ )
372
+
373
+ Knowledge::Learner.register_default_adapter(
374
+ klass: Knowledge::Adapters::KeyValue,
375
+ names: %i[default keyval key_value]
376
+ )
377
+
378
+ Knowledge::Learner.register_default_adapter(
379
+ klass: Knowledge::Adapters::File,
380
+ names: %i[config file config_file]
381
+ )