event-pub-sub 1.1.6

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 73f22c5c6e9637d5795f7d8730690d760eaca0a9
4
+ data.tar.gz: dfb2258f9b8981dacc99a8d295c6e2ac4c8a65d3
5
+ SHA512:
6
+ metadata.gz: faab525873900f49e3d36ef61d949a4c0c8fe742bd30d6e5d7592425816d2299797b26f2b8130e3dba643f8101a84115e14b2b66395d9be6e1c19da2f1765dac
7
+ data.tar.gz: 5f2051b5550451e5b5ead0c7a01b2da6bf5f0e91a5f528f6cd8b622226dd9f0b6d9d4c40965397dc0daa8a1ad038d65076af020bdc980d1be6e09be57426cdf2
data/.gitignore ADDED
@@ -0,0 +1,64 @@
1
+ *.rbc
2
+ capybara-*.html
3
+ /log
4
+ /tmp
5
+ /db/*.sqlite3
6
+ /public/system
7
+ /coverage/
8
+ /spec/tmp
9
+ run_test.sh
10
+ **.orig
11
+ rerun.txt
12
+ pickle-email-*.html
13
+
14
+ # TODO Comment out these rules if you are OK with secrets being uploaded to the repo
15
+ config/initializers/secret_token.rb
16
+ config/secrets.yml
17
+
18
+ ## Environment normalisation:
19
+ /.bundle
20
+ /vendor/bundle
21
+
22
+ # these should all be checked in to normalise the environment:
23
+ # Gemfile.lock, .ruby-version, .ruby-gemset
24
+
25
+ # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
26
+ .rvmrc
27
+
28
+ # if using bower-rails ignore default bower_components path bower.json files
29
+ /vendor/assets/bower_components
30
+ *.bowerrc
31
+ bower.json
32
+ # See https://help.github.com/articles/ignoring-files for more about ignoring files.
33
+ #
34
+ # If you find yourself ignoring temporary files generated by your text editor
35
+ # or operating system, you probably want to add a global ignore instead:
36
+ # git config --global core.excludesfile '~/.gitignore_global'
37
+
38
+ # Ignore bundler config.
39
+ /.bundle
40
+
41
+ # Ignore the default SQLite database.
42
+ /db/*.sqlite3
43
+ /db/*.sqlite3-journal
44
+
45
+ # Ignore all logfiles and tempfiles.
46
+ /log/*
47
+ !/log/.keep
48
+ /tmp
49
+
50
+ *.swp
51
+ *.swo
52
+ *.swn
53
+
54
+ # Ignore redis dump file
55
+ dump.rdb
56
+
57
+ # .ruby-gemset e .ruby-version nas engines
58
+ engines/**/.ruby-*
59
+
60
+ .editorconfig
61
+ tags
62
+ .byebug_history
63
+
64
+ .idea
data/.rspec ADDED
@@ -0,0 +1,4 @@
1
+ --color
2
+ --require spec_helper
3
+ --drb
4
+ --format doc
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in event.gemspec
4
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,94 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ event-pub-sub (1.1.6)
5
+ activesupport (= 4.2.5.2)
6
+ bunny (= 2.3.0)
7
+
8
+ GEM
9
+ remote: https://rubygems.org/
10
+ specs:
11
+ activesupport (4.2.5.2)
12
+ i18n (~> 0.7)
13
+ json (~> 1.7, >= 1.7.7)
14
+ minitest (~> 5.1)
15
+ thread_safe (~> 0.3, >= 0.3.4)
16
+ tzinfo (~> 1.1)
17
+ amq-protocol (2.0.1)
18
+ bunny (2.3.0)
19
+ amq-protocol (>= 2.0.1)
20
+ byebug (8.2.1)
21
+ celluloid (0.16.0)
22
+ timers (~> 4.0.0)
23
+ coderay (1.1.0)
24
+ diff-lcs (1.2.5)
25
+ ffi (1.9.6)
26
+ formatador (0.2.5)
27
+ guard (2.11.1)
28
+ formatador (>= 0.2.4)
29
+ listen (~> 2.7)
30
+ lumberjack (~> 1.0)
31
+ nenv (~> 0.1)
32
+ notiffany (~> 0.0)
33
+ pry (>= 0.9.12)
34
+ shellany (~> 0.0)
35
+ thor (>= 0.18.1)
36
+ guard-compat (1.2.1)
37
+ guard-rspec (4.5.0)
38
+ guard (~> 2.1)
39
+ guard-compat (~> 1.1)
40
+ rspec (>= 2.99.0, < 4.0)
41
+ hitimes (1.2.2)
42
+ i18n (0.7.0)
43
+ json (1.8.3)
44
+ listen (2.8.5)
45
+ celluloid (>= 0.15.2)
46
+ rb-fsevent (>= 0.9.3)
47
+ rb-inotify (>= 0.9)
48
+ lumberjack (1.0.9)
49
+ method_source (0.8.2)
50
+ minitest (5.8.4)
51
+ nenv (0.2.0)
52
+ notiffany (0.0.3)
53
+ nenv (~> 0.1)
54
+ shellany (~> 0.0)
55
+ pry (0.10.1)
56
+ coderay (~> 1.1.0)
57
+ method_source (~> 0.8.1)
58
+ slop (~> 3.4)
59
+ rake (10.4.2)
60
+ rb-fsevent (0.9.4)
61
+ rb-inotify (0.9.5)
62
+ ffi (>= 0.5.0)
63
+ rspec (3.2.0)
64
+ rspec-core (~> 3.2.0)
65
+ rspec-expectations (~> 3.2.0)
66
+ rspec-mocks (~> 3.2.0)
67
+ rspec-core (3.2.0)
68
+ rspec-support (~> 3.2.0)
69
+ rspec-expectations (3.2.0)
70
+ diff-lcs (>= 1.2.0, < 2.0)
71
+ rspec-support (~> 3.2.0)
72
+ rspec-mocks (3.2.0)
73
+ diff-lcs (>= 1.2.0, < 2.0)
74
+ rspec-support (~> 3.2.0)
75
+ rspec-support (3.2.1)
76
+ shellany (0.0.1)
77
+ slop (3.6.0)
78
+ thor (0.19.1)
79
+ thread_safe (0.3.5)
80
+ timers (4.0.1)
81
+ hitimes
82
+ tzinfo (1.2.2)
83
+ thread_safe (~> 0.1)
84
+
85
+ PLATFORMS
86
+ ruby
87
+
88
+ DEPENDENCIES
89
+ bundler (~> 1.7)
90
+ byebug (= 8.2.1)
91
+ event-pub-sub!
92
+ guard-rspec (= 4.5.0)
93
+ rake (~> 10.0)
94
+ rspec (= 3.2.0)
data/Guardfile ADDED
@@ -0,0 +1,51 @@
1
+ # A sample Guardfile
2
+ # More info at https://github.com/guard/guard#readme
3
+
4
+ ## Uncomment and set this to only include directories you want to watch
5
+ #directories %w(lib config spec)
6
+
7
+ ## Uncomment to clear the screen before every task
8
+ # clearing :on
9
+
10
+ ## Guard internally checks for changes in the Guardfile and exits.
11
+ ## If you want Guard to automatically start up again, run guard in a
12
+ ## shell loop, e.g.:
13
+ ##
14
+ ## $ while bundle exec guard; do echo "Restarting Guard..."; done
15
+ ##
16
+ ## Note: if you are using the `directories` clause above and you are not
17
+ ## watching the project directory ('.'), the you will want to move the Guardfile
18
+ ## to a watched dir and symlink it back, e.g.
19
+ #
20
+ # $ mkdir config
21
+ # $ mv Guardfile config/
22
+ # $ ln -s config/Guardfile .
23
+ #
24
+ # and, you'll have to watch "config/Guardfile" instead of "Guardfile"
25
+
26
+ # Note: The cmd option is now required due to the increasing number of ways
27
+ # rspec may be run, below are examples of the most common uses.
28
+ # * bundler: 'bundle exec rspec'
29
+ # * bundler binstubs: 'bin/rspec'
30
+ # * spring: 'bin/rspec' (This will use spring if running and you have
31
+ # installed the spring binstubs per the docs)
32
+ # * zeus: 'zeus rspec' (requires the server to be started separately)
33
+ # * 'just' rspec: 'rspec'
34
+
35
+ guard :rspec, cmd: "bundle exec rspec" do
36
+ watch(%r{^lib/(.+)\.rb$}) do |m|
37
+ [
38
+ "spec/unit/#{m[1]}_spec.rb",
39
+ "spec/integration/#{m[1]}_spec.rb"
40
+ ]
41
+ end
42
+ #models
43
+ watch(%r{^lib/event/(.+)\.rb$}) do |m|
44
+ [
45
+ "spec/unit/#{m[1]}_spec.rb",
46
+ "spec/integration/#{m[1]}_spec.rb"
47
+ ]
48
+ end
49
+
50
+ watch(%r{^spec/.+_spec\.rb$})
51
+ end
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2015 Sergio Azevedo
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,167 @@
1
+ [![Build Status](https://semaphoreapp.com/api/v1/projects/3b801a94-a652-4c1d-b347-ff6006adaf43/364951/shields_badge.svg)](https://semaphoreapp.com/darkseid/event)
2
+ # Event
3
+
4
+ O objetivo desta GEM é permitir que as Engines que compõem a nova Plataforma da Estante Virutal possam se comunicar sem que estas precisem "se conhecer", garantindo assim um baixo acoplamento entre as Engines.
5
+
6
+ A solução é baseada no pattern Publish-Subscribe Channel descrito pelo Fowler em seu livro Enterprise Integration Patterns. No caso, o papel do MessageChannel será exercido pelo RabbitMQ.
7
+
8
+ ## Instalação
9
+
10
+ Como dito anteriormente, esta gem utiliza o RabbitMQ. Por isso precisamos ter esta dependência instalada. Para realizar a instalação basta seguir o passo a passo descrito neste [link](https://www.rabbitmq.com/download.html)
11
+
12
+ Depois, você precisa adicionar um novo source ao seu Gemfile. Este novo source deve ser a primeira linha do seu Gemfile:
13
+
14
+ ```ruby
15
+ source 'https://repo.fury.io/sergioazevedo'
16
+ source 'https://rubygems.org'
17
+ ```
18
+
19
+ Se vc estiver instalando em uma Engine deve alterar o arquivo 'suaengine.gemspec' e adicionar a dependencia
20
+
21
+ ```ruby
22
+ s.add_dependency "event","~>1.0.0"
23
+ ```
24
+
25
+ Caso seja um projeto Ruby normal ou uma Rails app adicione a linha abaixo no seu Gemfile:
26
+
27
+ ```ruby
28
+ gem "event","~>1.0.0"
29
+ ```
30
+
31
+ E executar:
32
+ $ bundle
33
+
34
+ ## Configuração
35
+ Os arquivos abaixo são necessários para se configurar esta gem.
36
+ ```
37
+ config/event.yml
38
+ config/initializes/setup_event.rb
39
+ ```
40
+
41
+ Para gerá-los basta rodar a rake task: ```rake app:event:install```.
42
+
43
+ ####config/event.yml
44
+ Neste arquivo você deve fornecer as configuracoes para conexão com o Broker RabbitMQ.
45
+ Mas este arquivo contém uma configuração muito importante, e está na chave: **base_routing_key**. Você **precisa** usar nesta chave o nome da sua engine _(ou algo semelhante, que identifique o módulo)_.
46
+ Exemplo:
47
+ Imagine o modulo de Ecommerce
48
+
49
+ ```yaml
50
+ development:
51
+ base_routing_key: ecommerce
52
+ broker:
53
+ ip: localhost
54
+ port: 5672
55
+ username: guest
56
+ password: guest
57
+ ```
58
+
59
+ ####config/initializers/setup_event.rb
60
+ Você só vai precisar alterar este arquivo no caso de querer "assinar" algum evento.
61
+
62
+ ## Utilização
63
+
64
+ ### Publicando Eventos / Enviando mensagens
65
+ Publicar eventos é muito fácil, basta usar Event.pubish.
66
+
67
+ ```ruby
68
+ Event.publish(:sku_added, name: 'Caneta Azul', price: 1.99, qty: 10 )
69
+ ```
70
+ No exempo acima o nome do evento é **:sku_added** e os dados do evento estão no hash: **{name: 'Caneta Azul', price: 1.99, qty: 10}**
71
+
72
+ ###Sobre os Eventos
73
+ Eventos são sempre coisas que já aconteceram, por este motivo é de boa prática que os nomes dos eventos descrevam claramente que fato ocorreu e com quem. Exemplos abaixo:
74
+ - Um produto novo sku foi adicionado - :new_product_added
75
+ - Um sku novo foi adicionado - :new_sku_added
76
+ - Um sku foi vendido - :sku_saled
77
+ - Produto teve seu preço alterado - product_price_updated
78
+
79
+ Sobre os dados do evento, isto fica a cargo de quem publica o evento. Mas em geral é bacana enviar informações sobre o contexto do evento.
80
+
81
+ Exemplo:
82
+
83
+ - Um sku foi vendido
84
+ ```ruby
85
+ Event.publish(:sku_saled, sku_id: 10 )
86
+ ```
87
+ - Preço de um sku foi alterado
88
+ ```ruby
89
+ Event.publish(:sku_price_changed, sku_id: 10, old_price: 1.99, new_price: 2.87 )
90
+ ```
91
+
92
+ ### Assinando os Eventos / Recebendo mensagens
93
+
94
+ Assinar eventos é um processo de duas etapas:
95
+
96
+ 1. Escrever uma classe Listener para o evento desejado
97
+ 2. Registrar o Listener para o evento desejado em config/initializes/setup_event.rb
98
+
99
+ ####1. Escrever uma classe Listener para o evento desejado
100
+ Como dito antes você vai precisar escrever uma classe para cada listener que desejar.
101
+ Esta classe não precisa herdar de nada, basta que ela tenha os métodos **#initialize** e **notify**. O Listener é como um [Observer _GoF_](http://en.wikipedia.org/wiki/Observer_pattern).
102
+
103
+ Atenção, o listener deve receber toda a informação necessária para sua excução no método de inicialização (new), ou seja, os dados do evento/mensagem.
104
+
105
+ Exemplo de Listener:
106
+
107
+ Considere a mensagem abaixo:
108
+
109
+ ```ruby
110
+ Event.publish(:sku_price_changed, sku_id: 10, old_price: 1.99, new_price: 2.87 )
111
+ ```
112
+
113
+
114
+ ```ruby
115
+ class SkuPriceChangedListener
116
+ def initialize(data={})
117
+ @sku_id = data[:sku_id]
118
+ @old_price = data[:old_price]
119
+ @new_price = data[:new_price]
120
+ end
121
+
122
+ def notify
123
+ #aqui vai o seu código.
124
+ #vc pode, e em geral vai acontecer isso, instanciar um UseCase e executa-lo.
125
+ end
126
+ end
127
+ ````
128
+
129
+ ##### As Operações executadas por um listener devem ser Idempotentes sempre!!!
130
+ Por razões de segurança, e para garantia da consistencia dos nossos dados, as operações realizadas por um Listener deve ser idempontentes.
131
+
132
+ >Idempotente quer dizer que múltiplas requisições ao mesmo recurso usando o método devem ter o mesmo resultado que teria uma requisição apenas. A título de curiosidade, idempotente é a propriedade de um número que, multiplicado por ele mesmo, tem ele mesmo como resultado (n x n = n), em termos de números reais, apenas 0 e 1 têm essa propriedade. Em termos de métodos de requisição HTTP, os métodos GET, HEAD, PUT e DELETE são os que possuem a propriedade de ser idempotentes
133
+ - <cite>[Dicionario Informal](http://www.dicionarioinformal.com.br/idempotente/)</cite>
134
+
135
+ ##### Onde colocar meus listeners
136
+ Em geral, costuma-se criar dentro de app/ uma pasta chamada listeners ou event_listeners.
137
+
138
+ ####2. Registrar o Listener para o evento
139
+ No arquivo setup_events.rb existe uma seção dedicada ao registro dos listeners.
140
+ Esta seção vem toda comentada por padrão, veja:
141
+ ```ruby
142
+ # Register your listeners Here!!!! Example:
143
+ # Event.register_listeners do |config|
144
+ # config.add_listeners(:event_name, ['EventNameListener'])
145
+ # config.add_listeners(:another_event_name, ['AnotherEventListener1', 'Listner2'])
146
+ # end
147
+ ```
148
+ Basta descomentar e seguir como no exemplo. Imaginando que queremos registrar o nosso SkuPriceChangedListener, esta configuracao ficaria assim:
149
+
150
+ ```ruby
151
+ # Register your listeners Here!!!! Example:
152
+ Event.register_listeners do |config|
153
+ config.add_listeners(:sku_price_changed, ['SkuPriceChanged'])
154
+ end
155
+ ```
156
+
157
+ **Note que você sempre deve fornecer o nome do Listener com uma String dentro de um Array.**
158
+
159
+ **Observação:** Como este arquivo setup_events.rb é carregado na inicialização da aplicação, toda vez que você registrar um evento novo vai precisar reinicar a app.
160
+
161
+
162
+ ## Contributing
163
+ 1. Fork it ( https://github.com/[my-github-username]/event/fork )
164
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
165
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
166
+ 4. Push to the branch (`git push origin my-new-feature`)
167
+ 5. Create a new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+
@@ -0,0 +1,30 @@
1
+ # encoding: utf-8
2
+ # coding: utf-8
3
+ lib = File.expand_path('../lib', __FILE__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+ require 'event_pub_sub/version'
6
+
7
+ Gem::Specification.new do |spec|
8
+ spec.name = 'event-pub-sub'
9
+ spec.version = EventPubSub::VERSION
10
+ spec.authors = ['Estante Virutal']
11
+ spec.email = ['equipe_ti@estantevirtual.com.br']
12
+ spec.summary = %q{Pub/Sub de Eventos baseado em RabbitMQ.}
13
+ spec.description = %q{Pub/Sub de Eventos baseado em RabbitMQ.}
14
+ spec.homepage = 'http://www.estantevirtual.com.br'
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ['lib']
20
+
21
+ spec.add_dependency 'bunny', '2.3.0'
22
+ spec.add_dependency 'activesupport', '4.2.5.2'
23
+
24
+ spec.add_development_dependency 'bundler', '~> 1.7'
25
+ spec.add_development_dependency 'rake', '~> 10.0'
26
+ spec.add_development_dependency 'rspec', '3.2.0'
27
+ spec.add_development_dependency 'guard-rspec', '4.5.0'
28
+ spec.add_development_dependency 'byebug', '8.2.1'
29
+
30
+ end
@@ -0,0 +1,31 @@
1
+ development:
2
+ base_routing_key: module_name
3
+ broker:
4
+ ip: localhost
5
+ port: 5672
6
+ username: guest
7
+ password: guest
8
+
9
+ test:
10
+ base_routing_key: module_name
11
+ broker:
12
+ ip: localhost
13
+ port: 5672
14
+ username: guest
15
+ password: guest
16
+
17
+ staging:
18
+ base_routing_key: module_name
19
+ broker:
20
+ ip: <%=ENV['BROKER_IP'] %>
21
+ port: <%=ENV['BROKER_PORT'] %>
22
+ username: <%=ENV['BROKER_USERNAME'] %>
23
+ password: <%=ENV['BROKER_PASSWORD'] %>
24
+
25
+ production:
26
+ base_routing_key: module_name
27
+ broker:
28
+ ip: <%=ENV['BROKER_IP'] %>
29
+ port: <%=ENV['BROKER_PORT'] %>
30
+ username: <%=ENV['BROKER_USERNAME'] %>
31
+ password: <%=ENV['BROKER_PASSWORD'] %>
@@ -0,0 +1,26 @@
1
+ # require 'event'
2
+ # require 'yaml'
3
+
4
+ # module YourModuleNameHere
5
+ # class Event
6
+ # broker_data = File.read( File.expand_path('../../event.yml',__FILE__) )
7
+ # broker_config = YAML.load(ERB.new(broker_data).result).with_indifferent_access
8
+ # @@message_producer = ::Event::MessageProducer.new(broker_config[Rails.env], Rails.logger)
9
+
10
+ # if !Rails.env.test?
11
+ # listener_data = File.read( File.expand_path('../../listeners.yml',__FILE__) )
12
+ # listeners = YAML.load(listener_data).with_indifferent_access
13
+
14
+ # if listeners.any?
15
+ # Thread.new do
16
+ # consumer = ::Event::MessageConsumer.new(broker_config[Rails.env], Rails.logger)
17
+ # consumer.execute(listeners)
18
+ # end
19
+ # end
20
+ # end
21
+
22
+ # def self.publish(event_name, data={})
23
+ # @@message_producer.publish(event_name.to_sym, data)
24
+ # end
25
+ # end
26
+ # end
@@ -0,0 +1,7 @@
1
+ #event: ['ClassName']
2
+ #event: ['Module::ClassName']
3
+ ### - Se vc tiver um caso onde um ou mais listeners precisam ser executados para qualquer evento,
4
+ ### ou seja, se indepentende do evento que aconteceu vc quer que aquele listener rode use a sintaxe abaixo:
5
+ #any_event: [ClassName]
6
+
7
+ ##PS: as sintaxes acimma nao são excludentes, vc pode usar as duas em conjunto
@@ -0,0 +1,14 @@
1
+ require 'time'
2
+ require 'bunny'
3
+ require 'logger'
4
+ require "event_pub_sub/version"
5
+ require 'event_pub_sub/broker_handler'
6
+ require 'event_pub_sub/message_producer'
7
+ require 'event_pub_sub/message_consumer'
8
+ require 'event_pub_sub/listener'
9
+ require 'json'
10
+ require 'securerandom'
11
+
12
+ module EventPubSub
13
+
14
+ end
@@ -0,0 +1,65 @@
1
+ module EventPubSub
2
+ class BrokerHandler
3
+
4
+ def initialize(config, logger)
5
+ raise ArgumentError, "missing broker ip" unless config[:ip]
6
+ raise ArgumentError, "missing broker port" unless config[:port]
7
+ raise ArgumentError, "missing broker username" unless config[:username]
8
+ raise ArgumentError, "missing broker password" unless config[:password]
9
+ @config = config
10
+ @logger = logger
11
+ end
12
+
13
+ def start_connection
14
+ @connection = build_connection
15
+ @connection.start
16
+ rescue => e
17
+ @logger.error "#{e.message} - #{e.class}\n #{e.backtrace.join("\n")}"
18
+ end
19
+
20
+ def close_connection
21
+ @connection.close
22
+ end
23
+
24
+ def publish(message, routing_key)
25
+ topic.publish( message, persistent: true, routing_key: routing_key )
26
+ end
27
+
28
+ def setup_queue(queue_name)
29
+ @queue = channel.queue(queue_name, durable: true, auto_delete: false)
30
+ @queue.bind(topic, routing_key: '#')
31
+ end
32
+
33
+ def subscribe(consumer_name, params={ack: true, block: true}, &block)
34
+ params[:consumer_tag] = consumer_name
35
+ @queue.subscribe(params) do |delivery_info, properties, payload|
36
+ begin
37
+ block.call(delivery_info, properties, payload)
38
+ channel.ack(delivery_info.delivery_tag)
39
+ rescue => e
40
+ channel.nack(delivery_info.delivery_tag, false, true)
41
+ raise e
42
+ end
43
+ end
44
+ end
45
+
46
+ private
47
+ def build_connection
48
+ Bunny.new(
49
+ host: @config[:ip],
50
+ port: @config[:port],
51
+ user: @config[:username],
52
+ pass: @config[:password]
53
+ )
54
+ end
55
+
56
+ def topic
57
+ @topic ||= channel.topic('topic_events', durable: true)
58
+ end
59
+
60
+
61
+ def channel
62
+ @channel ||= @connection.create_channel
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,7 @@
1
+ module EventPubSub
2
+ class Listener
3
+ def notify
4
+ fail NotImplementedError, "You must implement notify method in #{self.class}"
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,65 @@
1
+ module EventPubSub
2
+ class MessageConsumer
3
+ def initialize(config, logger)
4
+ raise ArgumentError, "missing module base_routing_key " unless config[:base_routing_key]
5
+ @queue_name = config[:base_routing_key]
6
+ @logger = logger
7
+ @broker_handler = BrokerHandler.new(config[:broker], @logger)
8
+ @logger.info '[MessageConsumer] - Starting Connection'
9
+ @broker_handler.start_connection
10
+ @broker_handler.setup_queue(@queue_name)
11
+ end
12
+
13
+ def execute(all_listeners)
14
+ @logger.info '[MessageConsumer] - Waiting Messages...'
15
+ consumer_name = "#{@queue_name}_event_consumer"
16
+ @broker_handler.subscribe(consumer_name) do |delivery_info, properties, payload|
17
+ message = JSON.parse(payload).with_indifferent_access
18
+ event_name = message['event_name']
19
+ @logger.debug "[MessageConsumer] - Message Received: #{event_name}"
20
+ listeners_to_execute = get_listeners_of(event_name, all_listeners)
21
+ fire_listeners(listeners_to_execute, message)
22
+ end
23
+ end
24
+
25
+ def close_connection
26
+ @logger.info '[MessageConsumer] - Closing Connection'
27
+ @broker_handler.close_conection
28
+ end
29
+
30
+ def get_listeners_of(event_name, listeners_definitions)
31
+ listeners = listeners_definitions[event_name.to_sym] || []
32
+ if has_mappings_for_any_event?(listeners_definitions)
33
+ listeners.concat get_listeners_for_any_event(listeners_definitions)
34
+ end
35
+
36
+ listeners
37
+ end
38
+
39
+ private
40
+ def fire_listeners(listeners_to_execute, data)
41
+ if listeners_to_execute
42
+ listeners_to_execute.each do |listener_klass_name|
43
+ @logger.info "[Event Handling] - using listener class '#{listener_klass_name}'"
44
+ @logger.debug "[Event Handling] - notify event '#{@event_name}' using listener class '#{listener_klass_name}' with args '#{data}'"
45
+ begin
46
+ listener_klass = Object.const_get(listener_klass_name)
47
+ listener_klass.new(data).notify
48
+ rescue => e
49
+ @logger.error "[Event Handling] - #{e} \n #{e.backtrace.join("\n")}"
50
+ raise e
51
+ end
52
+ end
53
+ end
54
+ end
55
+
56
+ def has_mappings_for_any_event?(listeners_definitions)
57
+ listeners_definitions[:any_event] && listeners_definitions[:any_event].any?
58
+ end
59
+
60
+ def get_listeners_for_any_event(listeners_definitions)
61
+ listeners_definitions[:any_event]
62
+ end
63
+
64
+ end
65
+ end
@@ -0,0 +1,36 @@
1
+ module EventPubSub
2
+ class MessageProducer
3
+ def initialize(config, logger)
4
+ raise ArgumentError, "missing module base_routing_key " unless config[:base_routing_key]
5
+ @base_routing_key = config[:base_routing_key]
6
+ @logger = logger
7
+
8
+ @broker_handler = BrokerHandler.new(config[:broker], @logger)
9
+ @logger.info '[MessageProducer] - Starting Connection'
10
+ @broker_handler.start_connection
11
+ end
12
+
13
+ def publish(event_name, msg={})
14
+ key = routing_key(event_name)
15
+ enrich_message(event_name, msg)
16
+ @logger.info "[MessageProducer] - Sending event: #{event_name}"
17
+ @logger.debug "[MessageProducer] - Sending event: #{event_name} with data: #{msg.inspect} using as routing_key: #{key}"
18
+ @broker_handler.publish( JSON.generate(msg), key )
19
+ end
20
+
21
+ private
22
+ def routing_key(event_name)
23
+ "#{@base_routing_key}.#{event_name}"
24
+ end
25
+
26
+ def enrich_message(event_name, msg)
27
+ msg[:event_id] = SecureRandom.uuid
28
+ msg[:event_name] = event_name
29
+ if defined?(Rails)
30
+ msg[:event_date] = Time.zone.now
31
+ else
32
+ msg[:event_date] = Time.now.utc
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,11 @@
1
+ require 'event'
2
+ require 'rails'
3
+ module EventPubSub
4
+ class Railtie < Rails::Railtie
5
+ railtie_name :event_bus
6
+
7
+ rake_tasks do
8
+ load "tasks/event_tasks.rake"
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,3 @@
1
+ module EventPubSub
2
+ VERSION = "1.1.6"
3
+ end
@@ -0,0 +1,21 @@
1
+ require 'fileutils'
2
+ namespace :event do
3
+ desc "Installs required stuff to event"
4
+ task :install do
5
+ Rails.logger = Logger.new(STDOUT)
6
+ source = File.join(Gem.loaded_specs["event"].full_gem_path, "lib/config", "event.yml")
7
+ target = File.join("config", "event.yml")
8
+ Rails.logger.info "Creating file #{target}"
9
+ FileUtils.cp_r(source, target)
10
+
11
+ source = File.join(Gem.loaded_specs["event"].full_gem_path, "lib/config", "listeners.yml")
12
+ target = File.join("config", "listeners.yml")
13
+ Rails.logger.info "Creating file #{target}"
14
+ FileUtils.cp_r(source, target)
15
+
16
+ source = File.join(Gem.loaded_specs["event"].full_gem_path, "lib/config/initializers", "setup_event.rb")
17
+ target = File.join("config/initializers", "setup_event.rb")
18
+ Rails.logger.info "Creating file #{target}"
19
+ FileUtils.cp_r(source, target)
20
+ end
21
+ end
@@ -0,0 +1,72 @@
1
+ require 'spec_helper'
2
+ module EventPubSub
3
+ describe BrokerHandler do
4
+ let(:logger){ double('logger', debug: true)}
5
+ let(:running_server_config) do
6
+ {
7
+ ip: "localhost",
8
+ port: "5672",
9
+ username: "guest",
10
+ password: "guest",
11
+ }
12
+ end
13
+
14
+ let(:stopped_server_config) do
15
+ {
16
+ ip: "localhost",
17
+ port: "4000",
18
+ username: "guest",
19
+ password: "guest",
20
+ }
21
+ end
22
+
23
+ describe "#start_connection" do
24
+ context "given a up and running RabbitMQ server at localhost:5672" do
25
+ subject{ BrokerHandler.new(running_server_config, logger) }
26
+ it "stabilish connection" do
27
+ expect{subject.start_connection}.to_not raise_error
28
+ end
29
+ end
30
+
31
+ context "given a stoped RabbitMQ server" do
32
+ subject{ BrokerHandler.new(stopped_server_config, logger) }
33
+ it "raise error" do
34
+ expect{ subject.start_connection }.to raise_error
35
+ end
36
+ end
37
+ end
38
+
39
+ describe "#close_connection" do
40
+ context "given a up and running RabbitMQ server at localhost:5672" do
41
+ subject{ BrokerHandler.new(running_server_config, logger) }
42
+
43
+ it "closes connection" do
44
+ subject.start_connection
45
+ expect{subject.close_connection}.to_not raise_error
46
+ end
47
+
48
+ it "closes the channel" do
49
+ channel = subject.start_connection
50
+ expect(channel).to receive(:close).once
51
+ subject.close_connection
52
+ end
53
+ end
54
+ end
55
+
56
+ describe "#publish" do
57
+ context "given a up and running RabbitMQ server at localhost:5672" do
58
+ subject do
59
+ bus = BrokerHandler.new(running_server_config, logger)
60
+ bus.start_connection
61
+
62
+ bus
63
+ end
64
+ it "publish the event using base_routing_key" do
65
+ expect{ subject.publish( "'data': 'sample data'", 'routing.key') }.to_not raise_error
66
+ end
67
+ end
68
+ end
69
+
70
+ end
71
+ end
72
+
@@ -0,0 +1,6 @@
1
+ $LOAD_PATH.unshift File.expand_path("../lib", __FILE__)
2
+ require 'bundler'
3
+ Bundler.setup(:default, :test)
4
+ require 'event_pub_sub'
5
+ require 'pry'
6
+ require 'byebug'
@@ -0,0 +1,102 @@
1
+ require 'spec_helper'
2
+
3
+ module EventPubSub
4
+ describe BrokerHandler do
5
+ let(:logger) { double(:log, debug: true) }
6
+ let(:config) do
7
+ {
8
+ ip: "localhost",
9
+ port: "5672",
10
+ username: "guest",
11
+ password: "guest"
12
+ }
13
+ end
14
+
15
+ describe "API" do
16
+ subject{ BrokerHandler.new(config, logger)}
17
+ it { should respond_to :start_connection }
18
+ it { should respond_to :publish }
19
+ it { should respond_to :close_connection }
20
+ end
21
+
22
+ describe "initialize" do
23
+ it "raise Argument Error when no config is given" do
24
+ expect{BrokerHandler.new}.to raise_error ArgumentError
25
+ end
26
+
27
+ it "raise ArgumentError error with a invalid config" do
28
+ expect{BrokerHandler.new('aaaaa')}.to raise_error ArgumentError
29
+ end
30
+
31
+ it "raise ArgumentError error with a incomplete config" do
32
+ expect{BrokerHandler.new({})}.to raise_error ArgumentError
33
+ expect{BrokerHandler.new({ip: 1})}.to raise_error ArgumentError
34
+ expect{BrokerHandler.new({ip: 1, port: 2})}.to raise_error ArgumentError
35
+ expect{BrokerHandler.new({ip: 1, port: 2, username: 'a'})}.to raise_error ArgumentError
36
+ end
37
+
38
+ it "not raise error with a valid config" do
39
+ expect{BrokerHandler.new(config, logger)}.to_not raise_error
40
+ end
41
+ end
42
+
43
+ describe "#start_connection" do
44
+ context "Given a RabbitMQ Broker and a BrokerHandler with valid configuration" do
45
+ let(:mocked_rabbitmq_lib){double}
46
+ let(:connection){ double }
47
+ subject{ BrokerHandler.new(config, logger) }
48
+
49
+ it "returns a RabbitMQ Connection" do
50
+ expect(subject).to receive(:build_connection).once.and_return(mocked_rabbitmq_lib)
51
+ expect(mocked_rabbitmq_lib).to receive(:start).once.and_return(connection)
52
+ expect(subject.start_connection).to be connection
53
+ end
54
+ end
55
+ end
56
+
57
+ describe "#close_connection" do
58
+ context "Given BrokerHandler with a open connection" do
59
+ let(:mocked_rabbitmq_lib){double}
60
+ let(:connection){ double }
61
+
62
+ before do
63
+ allow(subject).to receive(:build_connection).and_return(mocked_rabbitmq_lib)
64
+ allow(mocked_rabbitmq_lib).to receive(:start).once.and_return(connection)
65
+ end
66
+
67
+ subject{ BrokerHandler.new(config, logger) }
68
+
69
+ it "closes a RabbitMQ Connection" do
70
+ subject.start_connection
71
+ expect(mocked_rabbitmq_lib).to receive(:close).once
72
+ subject.close_connection
73
+ end
74
+ end
75
+ end
76
+
77
+ describe "#publish" do
78
+ context "given a up and running RabbitMQ server at localhost:5672" do
79
+ let(:mocked_rabbitmq_lib){double(:bunny_mock)}
80
+ let(:channel){double(:channel, topic: true)}
81
+ let(:connection){double(:connection_mock)}
82
+ let(:topic){double(:topic_mock)}
83
+ before do
84
+ allow(subject).to receive(:build_connection).and_return(mocked_rabbitmq_lib)
85
+ allow(mocked_rabbitmq_lib).to receive(:start).once.and_return(connection)
86
+ allow(mocked_rabbitmq_lib).to receive(:create_channel).and_return(channel)
87
+ allow(channel).to receive(:topic).and_return(topic)
88
+ end
89
+ subject{ BrokerHandler.new(config, logger) }
90
+
91
+ it "publish the event using base_routing_key" do
92
+ subject.start_connection
93
+ expect(topic).to receive(:publish).once
94
+ subject.publish('message', 'routing.key')
95
+ end
96
+ end
97
+ end
98
+
99
+
100
+ end
101
+ end
102
+
@@ -0,0 +1,16 @@
1
+ require 'spec_helper'
2
+
3
+ module EventPubSub
4
+ describe Listener do
5
+ describe "api" do
6
+ it { is_expected.to respond_to :notify }
7
+ end
8
+
9
+ describe "#notify" do
10
+ it "raises NotImplementedError in order to remember the developer to override this operation on subclasses" do
11
+ expect{suject.notify}.to raise_error
12
+ end
13
+ end
14
+ end
15
+ end
16
+
@@ -0,0 +1,85 @@
1
+ require 'spec_helper'
2
+
3
+ module EventPubSub
4
+
5
+ describe MessageConsumer do
6
+ let(:logger) { double(:log, debug: true, info: true) }
7
+ let(:config) do
8
+ { broker: {
9
+ ip: "localhost",
10
+ port: "5672",
11
+ username: "guest",
12
+ password: "guest"
13
+ },
14
+ base_routing_key: "module_name"
15
+ }
16
+ end
17
+
18
+ describe "API" do
19
+ subject{ MessageConsumer.new(config, logger) }
20
+ it { should respond_to(:execute) }
21
+ it { should respond_to(:get_listeners_of) }
22
+ end
23
+
24
+ describe ".initialize" do
25
+ it "raise ArgumentError when no config was given" do
26
+ expect{ MessageConsumer.new }.to raise_error(ArgumentError)
27
+ end
28
+
29
+ it "raise ArgumentError if invalid config was given" do
30
+ expect{ MessageConsumer.new({}) }.to raise_error(ArgumentError)
31
+ end
32
+
33
+ it "no raise error if a valid config was given" do
34
+ expect{ MessageConsumer.new(config, logger) }.to_not raise_error
35
+ end
36
+ end
37
+
38
+ describe "#get_listeners_of" do
39
+ context "Given a event called new_sku_added with ExampleListener class associated" do
40
+ let(:listener_definitions) do
41
+ { new_sku_added: ["ExampleListenerClass"] }
42
+ end
43
+
44
+ subject{ MessageConsumer.new(config, logger) }
45
+
46
+ it "returns [ExampleListenerClass]" do
47
+ result = subject.get_listeners_of('new_sku_added', listener_definitions)
48
+ expect(result).to eql ['ExampleListenerClass']
49
+ end
50
+ end
51
+
52
+ context "Given a listener called AllEventsListener mapped for any event" do
53
+ let(:listener_definitions) do
54
+ { any_event: ["AllEventListenerClass"] }
55
+ end
56
+
57
+ subject{ MessageConsumer.new(config, logger) }
58
+
59
+ it "returns [AllEventListenerClass]" do
60
+ result = subject.get_listeners_of('foo_bar_updated', listener_definitions)
61
+ expect(result).to eql ['AllEventListenerClass']
62
+ end
63
+ end
64
+
65
+ context "Given a listener called AllEventsListener mapped for any event and new_sku_added mapped to ExampleListener" do
66
+ let(:listener_definitions) do
67
+ { new_sku_added: ["ExampleListenerClass"], any_event: ["AllEventListenerClass"] }
68
+ end
69
+
70
+ subject{ MessageConsumer.new(config, logger) }
71
+
72
+ it "for 'new_sku_added' event returns [ExampleListenerClass, AllEventListenerClass]" do
73
+ result = subject.get_listeners_of('new_sku_added', listener_definitions)
74
+ expect(result).to eql ['ExampleListenerClass', 'AllEventListenerClass']
75
+ end
76
+
77
+ it "for 'product_selled' event returns [AllEventListenerClass]" do
78
+ result = subject.get_listeners_of('product_selled', listener_definitions)
79
+ expect(result).to eql ['AllEventListenerClass']
80
+ end
81
+ end
82
+ end
83
+ end
84
+ end
85
+
@@ -0,0 +1,65 @@
1
+ require 'spec_helper'
2
+ module EventPubSub
3
+ describe MessageProducer do
4
+ let(:logger) { double(:log, debug: true, info: true) }
5
+ let(:config) do
6
+ {
7
+ broker: {
8
+ ip: "localhost",
9
+ port: "5672",
10
+ username: "guest",
11
+ password: "guest"
12
+ },
13
+ base_routing_key: "module_name"
14
+ }
15
+ end
16
+
17
+ describe "API" do
18
+ subject{ MessageProducer.new(config, logger)}
19
+ it { should respond_to :publish }
20
+ end
21
+
22
+ describe "initialize" do
23
+ it "raise Argument Error when no config is given" do
24
+ expect{MessageProducer.new}.to raise_error ArgumentError
25
+ end
26
+
27
+ it "raise ArgumentError error with a invalid config" do
28
+ expect{MessageProducer.new('aaaaa')}.to raise_error ArgumentError
29
+ end
30
+
31
+ it "raise ArgumentError error with a incomplete config" do
32
+ expect{MessageProducer.new({})}.to raise_error ArgumentError
33
+ expect{MessageProducer.new({ip: 1})}.to raise_error ArgumentError
34
+ expect{MessageProducer.new({ip: 1, port: 2})}.to raise_error ArgumentError
35
+ expect{MessageProducer.new({ip: 1, port: 2, username: 'a'})}.to raise_error ArgumentError
36
+ expect{MessageProducer.new({ip: 1, port: 2, username: 'a', password: "123"})}.to raise_error ArgumentError
37
+ end
38
+
39
+ it "not raise error with a valid config" do
40
+ expect{MessageProducer.new(config, logger)}.to_not raise_error
41
+ end
42
+ end
43
+
44
+ describe "#publish" do
45
+ context "Given a event named 'sku_created' with data => {code: 10, price: 20.87, product_id: 2}" do
46
+ let(:event_name){ :sku_created }
47
+ let(:event_data) do
48
+ { code: 10, price: 20.87, product_id: 2, event_name: 'sku_created' }
49
+ end
50
+ let(:expected_message){ JSON.generate(event_data) }
51
+ let(:fake_broker){double('broker', start_connection: true )}
52
+
53
+ subject{ MessageProducer.new(config, logger)}
54
+
55
+ it "calls BrokerHandler#publish with message => {code: 10, price: 20.87, product_id: 2} and routing_key => module_name.sku_created" do
56
+ allow(BrokerHandler).to receive(:new).and_return fake_broker
57
+ expect(fake_broker).to receive(:publish).once
58
+ subject.publish(event_name, event_data)
59
+ end
60
+ end
61
+ end
62
+
63
+ end
64
+ end
65
+
metadata ADDED
@@ -0,0 +1,173 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: event-pub-sub
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.1.6
5
+ platform: ruby
6
+ authors:
7
+ - Estante Virutal
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-03-10 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bunny
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '='
18
+ - !ruby/object:Gem::Version
19
+ version: 2.3.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '='
25
+ - !ruby/object:Gem::Version
26
+ version: 2.3.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: activesupport
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '='
32
+ - !ruby/object:Gem::Version
33
+ version: 4.2.5.2
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '='
39
+ - !ruby/object:Gem::Version
40
+ version: 4.2.5.2
41
+ - !ruby/object:Gem::Dependency
42
+ name: bundler
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.7'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.7'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '10.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '10.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rspec
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - '='
74
+ - !ruby/object:Gem::Version
75
+ version: 3.2.0
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - '='
81
+ - !ruby/object:Gem::Version
82
+ version: 3.2.0
83
+ - !ruby/object:Gem::Dependency
84
+ name: guard-rspec
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - '='
88
+ - !ruby/object:Gem::Version
89
+ version: 4.5.0
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - '='
95
+ - !ruby/object:Gem::Version
96
+ version: 4.5.0
97
+ - !ruby/object:Gem::Dependency
98
+ name: byebug
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - '='
102
+ - !ruby/object:Gem::Version
103
+ version: 8.2.1
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - '='
109
+ - !ruby/object:Gem::Version
110
+ version: 8.2.1
111
+ description: Pub/Sub de Eventos baseado em RabbitMQ.
112
+ email:
113
+ - equipe_ti@estantevirtual.com.br
114
+ executables: []
115
+ extensions: []
116
+ extra_rdoc_files: []
117
+ files:
118
+ - ".gitignore"
119
+ - ".rspec"
120
+ - Gemfile
121
+ - Gemfile.lock
122
+ - Guardfile
123
+ - LICENSE.txt
124
+ - README.md
125
+ - Rakefile
126
+ - event_pub_sub.gemspec
127
+ - lib/config/event.yml
128
+ - lib/config/initializers/setup_event.rb
129
+ - lib/config/listeners.yml
130
+ - lib/event_pub_sub.rb
131
+ - lib/event_pub_sub/broker_handler.rb
132
+ - lib/event_pub_sub/listener.rb
133
+ - lib/event_pub_sub/message_consumer.rb
134
+ - lib/event_pub_sub/message_producer.rb
135
+ - lib/event_pub_sub/railtie.rb
136
+ - lib/event_pub_sub/version.rb
137
+ - lib/tasks/event_tasks.rake
138
+ - spec/integration/broker_handler_spec.rb
139
+ - spec/spec_helper.rb
140
+ - spec/unit/broker_handler_spec.rb
141
+ - spec/unit/listener_spec.rb
142
+ - spec/unit/message_consumer_spec.rb
143
+ - spec/unit/message_producer_spec.rb
144
+ homepage: http://www.estantevirtual.com.br
145
+ licenses: []
146
+ metadata: {}
147
+ post_install_message:
148
+ rdoc_options: []
149
+ require_paths:
150
+ - lib
151
+ required_ruby_version: !ruby/object:Gem::Requirement
152
+ requirements:
153
+ - - ">="
154
+ - !ruby/object:Gem::Version
155
+ version: '0'
156
+ required_rubygems_version: !ruby/object:Gem::Requirement
157
+ requirements:
158
+ - - ">="
159
+ - !ruby/object:Gem::Version
160
+ version: '0'
161
+ requirements: []
162
+ rubyforge_project:
163
+ rubygems_version: 2.4.6
164
+ signing_key:
165
+ specification_version: 4
166
+ summary: Pub/Sub de Eventos baseado em RabbitMQ.
167
+ test_files:
168
+ - spec/integration/broker_handler_spec.rb
169
+ - spec/spec_helper.rb
170
+ - spec/unit/broker_handler_spec.rb
171
+ - spec/unit/listener_spec.rb
172
+ - spec/unit/message_consumer_spec.rb
173
+ - spec/unit/message_producer_spec.rb