evnt 2.1.0 → 2.1.1

Sign up to get free protection for your applications and to get access to all the features.
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