evnt 2.1.0 → 2.1.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 925a6536209233a9ceb61eb39c74c54af602a092
4
- data.tar.gz: 737caa953fd925d6bbb1b10cf30c3f4f761b0ea9
3
+ metadata.gz: b87af903c38d1e3c2e654750badc4eac551177f0
4
+ data.tar.gz: 435ae2a3ba9288673f3773a7cdec993117eba6a6
5
5
  SHA512:
6
- metadata.gz: fd4b06d8b794027913273a7c89971f8c45f877c80e8dc520a06dbd409230cc1e60ad014c2482392f320717250d4f50b32289bff14f99c4afb69ee4debf086447
7
- data.tar.gz: 8c9ea6e51c7650f2496edfd3d8f7c5851ae2ccd45126742db83febe6b17ab940255e796bd87bdf9ca897a90f15288c9347488e4b323445f684d499fce82c0272
6
+ metadata.gz: 77fa759d80d7357d7f597fe1d1e8987f3f0155af567bbb39eb2ac1fd4514b2a247e7e27cb2d41dc6e2c9135ee7bf16221d4ec388247fd487098d07e9e8e38a32
7
+ data.tar.gz: 69125321d1a8de3c3a48a9fe92539c9fb632f62f562d5a88dc62ba72d61380682ab213960f5b83f7965b835e1e36e2011334757747eb42641331bc538a6d51c5
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2017 Ideo SRL
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,319 @@
1
+ # Evnt
2
+
3
+ CQRS and Event Driven Development architecture for Ruby projects.
4
+
5
+ - [Installation](#installation)
6
+ - [Structure](#structure)
7
+ - [Command](#command)
8
+ - [Event](#event)
9
+ - [Handler](#handler)
10
+ - [Rails integration](#rails-integration)
11
+ - [Development](#development)
12
+
13
+ Full documentation here: https://ideonetwork.github.io/ruby-evnt/
14
+
15
+ ## Installation
16
+
17
+ To use the gem you need to add it on your Gemfile
18
+
19
+ ```ruby
20
+ gem 'evnt'
21
+ ```
22
+
23
+ ## Structure
24
+
25
+ Evnt is developed to be used over all kinds of projects and frameworks (like Ruby on Rails or Sinatra), so it contains only three types of entities:
26
+
27
+ - Command
28
+ - Event
29
+ - Handler
30
+
31
+ ### Command
32
+
33
+ Commands are used to run single tasks on the system. It's like a controller on an MVC architecture without the communication with the client.
34
+
35
+ Every command has three steps to execute:
36
+
37
+ - The params validation which validates the parameters used to run the command.
38
+ - The logic validation which checks the command can be executed in compliance with the system rules.
39
+ - The event intialization which initializes an event object used to save the command.
40
+
41
+ An example of command should be:
42
+
43
+ ```ruby
44
+ class CreateOrderCommand < Evnt::Command
45
+
46
+ to_validate_params do
47
+ # check params presence
48
+ err 'User should be present' if params[:user_id].blank?
49
+ err 'Product should be present' if params[:product_id].blank?
50
+ err 'Quantity should be present' if params[:quantity].blank?
51
+ end
52
+
53
+ to_validate_logic do
54
+ @user = User.find_by(id: params[:user_id])
55
+ @product = Product.find_by(id: params[:product_id])
56
+
57
+ # check user exist
58
+ unless @user
59
+ err 'The user does not exist'
60
+ break
61
+ end
62
+
63
+ # check product exist
64
+ unless @product
65
+ err 'The product does not exist'
66
+ break
67
+ end
68
+
69
+ # check quantity exist for the product
70
+ err 'The requested quantity is not available' if @product.quantity < params[:quantity]
71
+
72
+ # check user has money to buy the product
73
+ err 'You do not have enought money' if @user.money < @product.price * params[:quantity]
74
+ end
75
+
76
+ to_initialize_events do
77
+ # generate order id
78
+ order_id = SecureRandom.uuid
79
+
80
+ # initialize event
81
+ begin
82
+ CreateOrderEvent.new(
83
+ order_id: order_id,
84
+ user_id: @user.id,
85
+ product_id: @product.id,
86
+ quantity: params[:quantity],
87
+ _user: @user,
88
+ _product: @product
89
+ )
90
+ rescue
91
+ err 'Sorry, there was an error', code: 500
92
+ end
93
+ end
94
+
95
+ end
96
+ ```
97
+
98
+ An example of command usage should be:
99
+
100
+ ```ruby
101
+ command = CreateOrderCommand.new(
102
+ user_id: 128,
103
+ product_id: 534,
104
+ quantity: 10
105
+ )
106
+
107
+ if command.completed?
108
+ puts 'Command completed'
109
+ puts command.params # -> { user_id: 128, product_id: 534, quantity: 10 }
110
+ else
111
+ puts command.errors # array of hashes with a { message, code } structure
112
+ puts command.error_messages # array of error messages
113
+ puts command.error_codes # array of error codes
114
+ end
115
+ ```
116
+
117
+ It's also possible to use err method inside the command to raise an exception with the option **exception: true**. An example of usage should be:
118
+
119
+ ```ruby
120
+ begin
121
+ command = CreateOrderCommand.new(
122
+ user_id: 128,
123
+ product_id: 534,
124
+ quantity: 10,
125
+ _options: {
126
+ excption: true
127
+ }
128
+ )
129
+ rescue => e
130
+ puts e
131
+ end
132
+ ```
133
+
134
+ Some validations are similar for every command (like presence or paramter type), so you can also use general validations instead of **to_validate_params** block. An example of general validations should be:
135
+
136
+ ```ruby
137
+
138
+ class CreateOrderCommand < Evnt::Command
139
+
140
+ validates :user_id, type: :integer, presence: true
141
+ validates :product_id, type: :integer, presence: true
142
+ validates :quantity, type: :integer, presence: true
143
+
144
+ # ...
145
+
146
+ end
147
+
148
+ ```
149
+
150
+ ### Event
151
+
152
+ Events are used to save on a persistent data structure what happends on the system.
153
+
154
+ Every event has three informations:
155
+
156
+ - The **name** is an unique identifier of the event.
157
+ - The **attributes** are the list of attributes required from the event to be saved.
158
+ - The **handlers** are a list of handler objects which will be notified when the event is completed.
159
+
160
+ Every event has also a single function used to write the event information on the data structure.
161
+
162
+ An example of event should be:
163
+
164
+ ```ruby
165
+ class CreateOrderEvent < Evnt::Event
166
+
167
+ name_is :create_order
168
+
169
+ attributes_are :order_id, :user_id, :product_id, :quantity
170
+
171
+ handlers_are [
172
+ ProductHandler.new,
173
+ UserNotifierHandler.new
174
+ ]
175
+
176
+ to_write_event do
177
+ # save event on database
178
+ Event.create(name: name, payload: payload)
179
+ end
180
+
181
+ end
182
+ ```
183
+
184
+ An example of event usage should be:
185
+
186
+ ```ruby
187
+ event = CreateOrderEvent.new(
188
+ order_id: order_id,
189
+ user_id: @user.id,
190
+ product_id: @product.id,
191
+ quantity: params[:quantity]
192
+ )
193
+
194
+ puts event.name # -> :create_order
195
+ puts event.attributes # -> [:order_id, :user_id, :product_id, :quantity]
196
+ puts event.payload # -> { order_id: 1, user_id: 128, product_id: 534, quantity: 10, evnt: { timestamp: 2017010101, name: 'create_order' } }
197
+ ```
198
+
199
+ The event payload should contain all event attributes and a reserver attributes "evnt" used to store the event timestamp and the event name.
200
+
201
+ It's also possible to give datas to the event without save them on the event payload, to do this you shuld only use a key with "_" as first character. An example should be:
202
+
203
+ ```ruby
204
+ event = CreateOrderEvent.new(
205
+ order_id: order_id,
206
+ user_id: @user.id,
207
+ product_id: @product.id,
208
+ quantity: params[:quantity],
209
+ _total_price: params[:quantity] * @product.price
210
+ )
211
+
212
+ puts event.payload # -> { order_id: 1, user_id: 128, product_id: 534, quantity: 10, evnt: { timestamp: 2017010101, name: 'create_order' } }
213
+ puts event.extras # -> { _total_price: 50 }
214
+ ```
215
+
216
+ After the execution of the **to_write_event** block the event object should notify all its handlers.
217
+
218
+ Sometimes you need to reload an old event to notify handlers to re-build queries from events. To initialize a new event object with the payload of an old event you can pass the old event payload to the event constructor:
219
+
220
+ ```ruby
221
+ events = Event.where(name: 'create_order')
222
+ reloaded_event = CreateOrderEvent.new(events.sample.payload)
223
+
224
+ puts reloaded_event.reloaded? # -> true
225
+ ```
226
+
227
+ ### Handler
228
+
229
+ Handlers are used to listen one or more events and run tasks after their execution.
230
+
231
+ Every handler event management has two steps to execute:
232
+
233
+ - The queries update which updates temporary data structures used to read datas.
234
+ - The manage event code which run other tasks like mailers, parallel executions ecc.
235
+
236
+ An example of handler shuould be:
237
+
238
+ ```ruby
239
+ class ProductHandler < Evnt::Handler
240
+
241
+ on :create_order do
242
+
243
+ to_update_queries do
244
+ # update product quantity
245
+ product = event.extras[:_product]
246
+ product.update(quantity: product.quantity - event.payload[:quantity])
247
+ end
248
+
249
+ to_manage_event do
250
+ # this block is called only for not reloaded events
251
+ end
252
+
253
+ end
254
+
255
+ end
256
+ ```
257
+
258
+ The execution of **to_update_queries** block runs after every events initialization.
259
+ The execution of **to_manage_event** block runs only for not reloaded events initialization.
260
+
261
+ Sometimes you need to run some code to manage only reloaded events. To run code only for reloaded events you can use the **to_manage_reloaded_event** block:
262
+
263
+ ```ruby
264
+ class ProductHandler < Evnt::Handler
265
+
266
+ on :create_order do
267
+
268
+ to_manage_reloaded_event do
269
+ # this block is called only for reloaded events
270
+ end
271
+
272
+ end
273
+
274
+ end
275
+ ```
276
+
277
+ ## Rails integration
278
+
279
+ Evnt can be used with Ruby on Rails to extends the MVC pattern.
280
+
281
+ To use the gem with Rails you need to create three folders inside the ./app project's path:
282
+
283
+ - **./app/commands**
284
+ - **./app/events**
285
+ - **./app/handlers**
286
+
287
+ You also need to require all files from these folders. To do this you need to edit the ./config/application.rb file like this example:
288
+
289
+ ```ruby
290
+
291
+ require_relative 'boot'
292
+
293
+ require 'rails/all'
294
+
295
+ # Require the gems listed in Gemfile, including any gems
296
+ # you've limited to :test, :development, or :production.
297
+ Bundler.require(*Rails.groups)
298
+
299
+ module MyApplicationName
300
+ class Application < Rails::Application
301
+
302
+ config.autoload_paths << Rails.root.join('app/commands')
303
+ config.autoload_paths << Rails.root.join('app/events')
304
+ config.autoload_paths << Rails.root.join('app/handlers')
305
+
306
+ end
307
+ end
308
+
309
+ ```
310
+
311
+ ## Development
312
+
313
+ To update the documentation run:
314
+
315
+ ```console
316
+
317
+ rdoc --op docs
318
+
319
+ ```
data/lib/evnt.rb ADDED
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'evnt/version'
4
+ require 'evnt/command'
5
+ require 'evnt/event'
6
+ require 'evnt/handler'
7
+ require 'evnt/validator'
8
+
9
+ ##
10
+ # Evnt is a gem developed to integrate a test driven development
11
+ # and CQRS pattern inside a ruby project.
12
+ # Evnt is developed to be used over all kinds of projects and
13
+ # frameworks (like Ruby on Rails or Sinatra), so it contains
14
+ # only three types of entities:
15
+ #
16
+ # - Command
17
+ # - Event
18
+ # - Handler
19
+ ##
20
+ module Evnt; end
@@ -0,0 +1,178 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Evnt
4
+
5
+ ##
6
+ # Commands are used to run single tasks on the system.
7
+ # It's like a controller on an MVC architecture without the
8
+ # communication with the client.
9
+ ##
10
+ class Command
11
+
12
+ ##
13
+ # Attribute containings the list of command parameters.
14
+ ##
15
+ attr_reader :params
16
+
17
+ ##
18
+ # The constructor is used to run a new command.
19
+ #
20
+ # ==== Attributes
21
+ #
22
+ # * +params+ - The list of parameters for the command.
23
+ # * +_options+ - The list of options for the command.
24
+ #
25
+ # ==== Options
26
+ #
27
+ # * +exceptions+ - Boolean value used to activate the throw of excetions.
28
+ ##
29
+ def initialize(params, _options: {})
30
+ _init_command_data(params, _options)
31
+ _run_command_steps
32
+ end
33
+
34
+ # Public functions:
35
+ ############################################################################
36
+
37
+ ##
38
+ # This function returns the list of errors of the command.
39
+ # The returned object should be an array of hashes with a message and
40
+ # a code value.
41
+ # The code value of hashes should be nil if code is not defined using
42
+ # the stop() function.
43
+ ##
44
+ def errors
45
+ @state[:errors]
46
+ end
47
+
48
+ ##
49
+ # This function returns the list of error messages of the command.
50
+ # The returned object should be an array of strings.
51
+ ##
52
+ def error_messages
53
+ @state[:errors].map { |e| e[:message] }
54
+ end
55
+
56
+ ##
57
+ # This function returns the list of error codes of the command.
58
+ # The returned object should be an array of integers.
59
+ ##
60
+ def error_codes
61
+ @state[:errors].map { |e| e[:code] }
62
+ end
63
+
64
+ ##
65
+ # This function tells if the command is completed or not.
66
+ # The returned object should be a boolean value.
67
+ ##
68
+ def completed?
69
+ @state[:result]
70
+ end
71
+
72
+ # Protected functions:
73
+ ############################################################################
74
+
75
+ protected
76
+
77
+ ##
78
+ # This function can be used to stop the command execution and
79
+ # add a new error.
80
+ # Using err inside a callback should not stop the execution but
81
+ # should avoid the call of the next callback.
82
+ # Every time you call this function, a new error should be added
83
+ # to the errors list.
84
+ # If the exceptions option is active, it should raise a new error.
85
+ #
86
+ # ==== Attributes
87
+ #
88
+ # * +message+ - The message string of the error.
89
+ # * +code+ - The error code.
90
+ ##
91
+ def err(message, code: nil)
92
+ @state[:result] = false
93
+ @state[:errors].push(
94
+ message: message,
95
+ code: code
96
+ )
97
+
98
+ # raise error if command needs exceptions
99
+ raise error if @options[:exceptions]
100
+ end
101
+
102
+ # Private functions:
103
+ ############################################################################
104
+
105
+ private
106
+
107
+ # This function initializes the command required data.
108
+ def _init_command_data(params, options)
109
+ # set state
110
+ @state = {
111
+ result: true,
112
+ errors: []
113
+ }
114
+
115
+ # set options
116
+ @options = {
117
+ exceptions: options[:exceptions] || false
118
+ }
119
+
120
+ # set other data
121
+ @params = params.freeze
122
+ end
123
+
124
+ # This function calls requested steps (callback) for the command.
125
+ def _run_command_steps
126
+ _validate_single_params
127
+ _validate_params if @state[:result] && defined?(_validate_params)
128
+ _validate_logic if @state[:result] && defined?(_validate_logic)
129
+ _initialize_events if @state[:result] && defined?(_initialize_events)
130
+ end
131
+
132
+ # This function validates the single parameters sets with the "validates" method.
133
+ def _validate_single_params
134
+ return if self.class._validations.nil? || self.class._validations.empty?
135
+ self.class._validations.each do |val|
136
+ result = Evnt::Validator.validates(params[val[:param]], val[:options])
137
+ unless result
138
+ err "#{val[:param].capitalize} value not accepted"
139
+ break
140
+ end
141
+ end
142
+ end
143
+
144
+ # Class functions:
145
+ ############################################################################
146
+
147
+ # This class contain the list of settings for the command.
148
+ class << self
149
+
150
+ attr_accessor :_validations
151
+
152
+ # This function sets the single validation request for a command parameter.
153
+ def validates(param, options)
154
+ validations = instance_variable_get(:@_validations) || []
155
+ validations.push(param: param, options: options)
156
+ instance_variable_set(:@_validations, validations)
157
+ end
158
+
159
+ # This function sets the validate params function for the command.
160
+ def to_validate_params(&block)
161
+ define_method('_validate_params', &block)
162
+ end
163
+
164
+ # This function sets the validate logic function for the command.
165
+ def to_validate_logic(&block)
166
+ define_method('_validate_logic', &block)
167
+ end
168
+
169
+ # This function sets the intitialize events function for the command.
170
+ def to_initialize_events(&block)
171
+ define_method('_initialize_events', &block)
172
+ end
173
+
174
+ end
175
+
176
+ end
177
+
178
+ end
data/lib/evnt/event.rb ADDED
@@ -0,0 +1,151 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'time'
4
+
5
+ module Evnt
6
+
7
+ ##
8
+ # Events are used to save on a persistent data structure what
9
+ # happends on the system.
10
+ ##
11
+ class Event
12
+
13
+ ##
14
+ # Attribute containings the name of the event.
15
+ ##
16
+ attr_reader :name
17
+
18
+ ##
19
+ # Attribute containings the list of attributes of the event.
20
+ ##
21
+ attr_reader :attributes
22
+
23
+ ##
24
+ # Attribute containings the payload of the event.
25
+ ##
26
+ attr_reader :payload
27
+
28
+ ##
29
+ # Attribute containings the extra parameters of the event.
30
+ ##
31
+ attr_reader :extras
32
+
33
+ ##
34
+ # The constructor is used to initialize a new event.
35
+ # The parameters are validated and added to the payload
36
+ # of the event. The parameters with the _ in their name
37
+ # are not saved on the payload.
38
+ #
39
+ # ==== Attributes
40
+ #
41
+ # * +params+ - The list of parameters for the command.
42
+ ##
43
+ def initialize(params)
44
+ _init_event_data(params)
45
+ _validate_payload
46
+ _run_event_steps
47
+ _notify_handlers
48
+ end
49
+
50
+ # Public functions:
51
+ ############################################################################
52
+
53
+ ##
54
+ # This function tells if the event is reloaded or not.
55
+ # The returned object should be a boolean value corresponding to the
56
+ # presence of evnt value inside the event params.
57
+ ##
58
+ def reloaded?
59
+ @state[:reloaded]
60
+ end
61
+
62
+ # Private functions:
63
+ ############################################################################
64
+
65
+ private
66
+
67
+ # This function initializes the event required data.
68
+ def _init_event_data(params)
69
+ # set state
70
+ @state = {
71
+ reloaded: !params[:evnt].nil?
72
+ }
73
+
74
+ # set payload
75
+ payload = params.reject { |k, _v| k[0] == '_' }
76
+ @payload = @state[:reloaded] ? payload : _generate_payload(payload)
77
+
78
+ # set other datas
79
+ @name = self.class._name
80
+ @attributes = self.class._attributes
81
+ @extras = params.select { |k, _v| k[0] == '_' }
82
+ end
83
+
84
+ # This function generates the complete event payload.
85
+ def _generate_payload(params)
86
+ # add evnt informations
87
+ params[:evnt] = {
88
+ timestamp: Time.now.to_i,
89
+ name: self.class._name
90
+ }
91
+ # return payload
92
+ params
93
+ end
94
+
95
+ # This function validates all payload and check they are completed.
96
+ def _validate_payload
97
+ return unless self.class._attributes
98
+
99
+ # check all attributes are present
100
+ check_attr = (@payload.keys - [:evnt]) == self.class._attributes
101
+ raise 'Event parameters are not correct' unless check_attr
102
+ end
103
+
104
+ # This function calls requested steps for the event.
105
+ def _run_event_steps
106
+ _write_event if defined?(_write_event)
107
+ end
108
+
109
+ # This function notify all handlers for the event.
110
+ def _notify_handlers
111
+ return unless self.class._handlers
112
+
113
+ # notify every handler
114
+ self.class._handlers.each do |handler|
115
+ handler.notify(self)
116
+ end
117
+ end
118
+
119
+ # Class functions:
120
+ ############################################################################
121
+
122
+ # This class contain the list of settings for the event.
123
+ class << self
124
+
125
+ attr_accessor :_name, :_attributes, :_handlers
126
+
127
+ # This function sets the name for the event.
128
+ def name_is(event_name)
129
+ instance_variable_set(:@_name, event_name)
130
+ end
131
+
132
+ # This function sets the list of attributes for the event.
133
+ def attributes_are(*attributes)
134
+ instance_variable_set(:@_attributes, attributes)
135
+ end
136
+
137
+ # This function sets the list of handlers for the event.
138
+ def handlers_are(handlers)
139
+ instance_variable_set(:@_handlers, handlers)
140
+ end
141
+
142
+ # This function sets the write event function for the event.
143
+ def to_write_event(&block)
144
+ define_method('_write_event', &block)
145
+ end
146
+
147
+ end
148
+
149
+ end
150
+
151
+ end
@@ -0,0 +1,90 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Evnt
4
+
5
+ ##
6
+ # Handlers are used to listen one or more events and run tasks after their execution.
7
+ ##
8
+ class Handler
9
+
10
+ ##
11
+ # Attribute containings the event that notify the handler.
12
+ ##
13
+ attr_reader :event
14
+
15
+ ##
16
+ # This function is called from an event to notify an handler.
17
+ #
18
+ # ==== Attributes
19
+ #
20
+ # * +event+ - The event object that call the function.
21
+ ##
22
+ def notify(event)
23
+ _init_handler_data(event)
24
+ _init_handler_steps
25
+ _run_handler_steps
26
+ end
27
+
28
+ # Private functions:
29
+ ############################################################################
30
+
31
+ private
32
+
33
+ # This function initializes the handler required data.
34
+ def _init_handler_data(event)
35
+ @event = event
36
+ end
37
+
38
+ # This function init the handler steps.
39
+ def _init_handler_steps
40
+ self.class._events[@event.name].call
41
+ end
42
+
43
+ # This function calls requested steps for the handler.
44
+ def _run_handler_steps
45
+ _update_queries if defined?(_update_queries)
46
+
47
+ # manage event reloaded
48
+ if event.reloaded?
49
+ _manage_reloaded_event if defined?(_manage_reloaded_event)
50
+ return
51
+ end
52
+
53
+ # manage normal event
54
+ _manage_event if defined?(_manage_event)
55
+ end
56
+
57
+ # Class functions:
58
+ ############################################################################
59
+
60
+ # This class contain the list of settings for the handler.
61
+ class << self
62
+
63
+ attr_accessor :_events
64
+
65
+ # This function sets the blocks executed for a specific event.
66
+ def on(event_name, &block)
67
+ instance_variable_set(:@_events, {}) unless @_events
68
+ @_events[event_name] = block
69
+ end
70
+
71
+ # This function sets the update queries function for the event.
72
+ def to_update_queries(&block)
73
+ define_method('_update_queries', &block)
74
+ end
75
+
76
+ # This function sets the manage event function for the event.
77
+ def to_manage_event(&block)
78
+ define_method('_manage_event', &block)
79
+ end
80
+
81
+ # This function sets the manage reloaded event function for the event.
82
+ def to_manage_reloaded_event(&block)
83
+ define_method('_manage_reloaded_event', &block)
84
+ end
85
+
86
+ end
87
+
88
+ end
89
+
90
+ end
@@ -0,0 +1,206 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Evnt
4
+
5
+ ##
6
+ # Validator is a class used to validates params and attributes automatically.
7
+ ##
8
+ class Validator
9
+
10
+ # Class functions:
11
+ ############################################################################
12
+
13
+ class << self
14
+
15
+ ##
16
+ # This function is used to validates a parameter with some validation
17
+ # options.
18
+ #
19
+ # ==== Attributes
20
+ #
21
+ # * +param+ - The parameter to be validated.
22
+ # * +options+ - The list of options for the validations.
23
+ #
24
+ # ==== Options
25
+ #
26
+ # * +type+ - Symbol value used to tells the correct parameter type.
27
+ # * +presence+ - Boolean value used to tells if the presence is required.
28
+ ##
29
+ def validates(param, options)
30
+ options.each do |key, value|
31
+ return false unless validate_option(param, key, value)
32
+ end
33
+
34
+ true
35
+ rescue StandardError => e
36
+ puts e
37
+ false
38
+ end
39
+
40
+ ##
41
+ # This function calls the correct validate function for a specific option.
42
+ #
43
+ # ==== Attributes
44
+ #
45
+ # * +param+ - The parameter to be validated.
46
+ # * +option_key+ - The key of the option that should be used.
47
+ # * +option_value+ - The value of the option that should be used.
48
+ ##
49
+ def validate_option(param, option_key, option_value)
50
+ case option_key
51
+ when :type
52
+ validate_type(param, option_value)
53
+ when :presence
54
+ validate_presence(param, option_value)
55
+ when :blank
56
+ validate_blank(param, option_value)
57
+ when :numeric
58
+ validate_numeric(param, option_value)
59
+ else
60
+ raise 'Validator option not accepted'
61
+ end
62
+ rescue StandardError => e
63
+ puts e
64
+ false
65
+ end
66
+
67
+ ##
68
+ # This function validates the type of the parameter.
69
+ #
70
+ # ==== Attributes
71
+ #
72
+ # * +param+ - The parameter to be validated.
73
+ # * +value+ - The value of the type option that should be used.
74
+ ##
75
+ def validate_type(param, value)
76
+ return true if param.nil?
77
+
78
+ if value.instance_of?(Symbol)
79
+ validate_type_general(param, value)
80
+ elsif value.instance_of?(String)
81
+ validate_type_custom(param, value)
82
+ else
83
+ raise 'Validator type option not accepted'
84
+ end
85
+ rescue StandardError => e
86
+ puts e
87
+ false
88
+ end
89
+
90
+ ##
91
+ # This function validates the presence of the prameter.
92
+ # A parameter is present when its value is not nil.
93
+ #
94
+ # ==== Attributes
95
+ #
96
+ # * +param+ - The parameter to be validated.
97
+ # * +value+ - The value of the presence option that should be used.
98
+ ##
99
+ def validate_presence(param, value)
100
+ is_nil = param.nil?
101
+ value ? !is_nil : is_nil
102
+ rescue StandardError => e
103
+ puts e
104
+ false
105
+ end
106
+
107
+ ##
108
+ # This function validates the blank of the prameter.
109
+ # A parameter is blank when its value is nil, false, or empty.
110
+ #
111
+ # ==== Attributes
112
+ #
113
+ # * +param+ - The parameter to be validated.
114
+ # * +value+ - The value of the presence option that should be used.
115
+ ##
116
+ def validate_blank(param, value)
117
+ blank = (!param || param.empty?)
118
+ value ? blank : !blank
119
+ rescue StandardError => e
120
+ puts e
121
+ false
122
+ end
123
+
124
+ ##
125
+ # This function validates some numeric options for the parameter.
126
+ #
127
+ # ==== Attributes
128
+ #
129
+ # * +param+ - The parameter to be validated.
130
+ # * +value+ - The value object with validation specs.
131
+ ##
132
+ def validate_numeric(param, value)
133
+ # TODO: Continue
134
+ rescue StandardError => e
135
+ puts e
136
+ false
137
+ end
138
+
139
+ # Private functions:
140
+ ##########################################################################
141
+
142
+ private
143
+
144
+ # Types validations:
145
+ ##########################################################################
146
+
147
+ # This function validates a param type for general types.
148
+ def validate_type_general(param, value)
149
+ case value
150
+ when :boolean
151
+ validate_type_boolean(param)
152
+ when :string
153
+ validate_type_string(param)
154
+ when :integer
155
+ validate_type_integer(param)
156
+ when :symbol
157
+ validate_type_symbol(param)
158
+ when :float
159
+ validates_type_float(param)
160
+ when :hash
161
+ validates_type_hash(param)
162
+ when :array
163
+ validates_type_array(param)
164
+ else
165
+ raise 'Validator type option not accepted'
166
+ end
167
+ end
168
+
169
+ # This function validates a param type for custom types.
170
+ def validate_type_custom(param, value)
171
+ param.instance_of?(Object.const_get(value))
172
+ end
173
+
174
+ def validate_type_boolean(param)
175
+ param.instance_of?(TrueClass) || param.instance_of?(FalseClass)
176
+ end
177
+
178
+ def validate_type_string(param)
179
+ param.instance_of?(String)
180
+ end
181
+
182
+ def validate_type_integer(param)
183
+ param.instance_of?(Integer)
184
+ end
185
+
186
+ def validate_type_symbol(param)
187
+ param.instance_of?(Symbol)
188
+ end
189
+
190
+ def validates_type_float(param)
191
+ param.instance_of?(Float)
192
+ end
193
+
194
+ def validates_type_hash(param)
195
+ param.instance_of?(Hash)
196
+ end
197
+
198
+ def validates_type_array(param)
199
+ param.instance_of?(Array)
200
+ end
201
+
202
+ end
203
+
204
+ end
205
+
206
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Evnt
4
+
5
+ ##
6
+ # Constant containing the current gem version.
7
+ ##
8
+ VERSION = '2.1.1'
9
+
10
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: evnt
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.0
4
+ version: 2.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ideonetwork
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-10-27 00:00:00.000000000 Z
11
+ date: 2017-11-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -25,40 +25,48 @@ dependencies:
25
25
  - !ruby/object:Gem::Version
26
26
  version: '1.0'
27
27
  - !ruby/object:Gem::Dependency
28
- name: rspec
28
+ name: rdoc
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '3.0'
33
+ version: '5.0'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '3.0'
40
+ version: '5.0'
41
41
  - !ruby/object:Gem::Dependency
42
- name: rdoc
42
+ name: rspec
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: '5.0'
47
+ version: '3.0'
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: '5.0'
54
+ version: '3.0'
55
55
  description: CQRS and Event Driven Development architecture for Ruby
56
56
  email:
57
57
  - dev@ideonetwork.it
58
58
  executables: []
59
59
  extensions: []
60
60
  extra_rdoc_files: []
61
- files: []
61
+ files:
62
+ - MIT-LICENSE
63
+ - README.md
64
+ - lib/evnt.rb
65
+ - lib/evnt/command.rb
66
+ - lib/evnt/event.rb
67
+ - lib/evnt/handler.rb
68
+ - lib/evnt/validator.rb
69
+ - lib/evnt/version.rb
62
70
  homepage: http://ideonetwork.it/
63
71
  licenses:
64
72
  - MIT
@@ -79,7 +87,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
79
87
  version: '0'
80
88
  requirements: []
81
89
  rubyforge_project:
82
- rubygems_version: 2.6.12
90
+ rubygems_version: 2.6.14
83
91
  signing_key:
84
92
  specification_version: 4
85
93
  summary: CQRS and Event Driven Development architecture for Ruby