waterdrop 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 68abb1be8f0558b53ff3cc1c8f29134e786b4c1c
4
+ data.tar.gz: 0031802410a38d242c0da4bbd74473a267852b67
5
+ SHA512:
6
+ metadata.gz: 1ca70187b5b3cc6559d48b276bc228b579cee0a0938c40656dd9158f74ae2094550b6e9059b1a4774188637fcda23fa2fed439b44a37537ffea89a73562746c4
7
+ data.tar.gz: 26c374cde1d74764d2def8933211b7a856a8f032bcd891342bc35121c5c10c0c1478d581834db9a3d9c4e0b9f26e63989c4b81315d21346eb01034b79184ebaf
data/.gitignore ADDED
@@ -0,0 +1,66 @@
1
+ # bundler state
2
+ /.bundle
3
+ /vendor/bundle/
4
+ /vendor/ruby/
5
+ /ruby/
6
+ app.god
7
+
8
+ # minimal Rails specific artifacts
9
+ db/*.sqlite3
10
+ /log/*
11
+ /tmp/*
12
+ *.gem
13
+ *.~
14
+
15
+ # various artifacts
16
+ **.war
17
+ *.rbc
18
+ *.sassc
19
+ .rspec
20
+ .redcar/
21
+ .capistrano/
22
+ .sass-cache
23
+ /config/god/sidekiq.rb
24
+ /config/puma.rb
25
+ /coverage.data
26
+ /coverage/
27
+ /doc/api/
28
+ /doc/app/
29
+ /doc/yard
30
+ /doc/features.html
31
+ /doc/specs.html
32
+ /spec/tmp/*
33
+ /cache
34
+ /capybara*
35
+ /capybara-*.html
36
+ /gems
37
+ /specifications
38
+ rerun.txt
39
+ pickle-email-*.html
40
+
41
+ # If you find yourself ignoring temporary files generated by your text editor
42
+ # or operating system, you probably want to add a global ignore instead:
43
+ # git config --global core.excludesfile ~/.gitignore_global
44
+ #
45
+ # Here are some files you may want to ignore globally:
46
+
47
+ # scm revert files
48
+ **.orig
49
+
50
+ # Mac finder artifacts
51
+ .DS_Store
52
+
53
+ # Netbeans project directory
54
+ /nbproject
55
+
56
+ # RubyMine project files
57
+ .idea
58
+
59
+ # Textmate project files
60
+ /*.tmproj
61
+
62
+ # vim artifacts
63
+ **.swp
64
+
65
+ # documentation
66
+ .yardoc
data/.ruby-gemset ADDED
@@ -0,0 +1 @@
1
+ waterdrop
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ ruby-2.2.2
data/.travis.yml ADDED
@@ -0,0 +1,6 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.1.5
4
+ - 2.2.2
5
+ script:
6
+ - bundle exec rake
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+ gem 'poseidon'
3
+ gem 'aspector'
4
+ gem 'polishgeeks-dev-tools'
data/Gemfile.lock ADDED
@@ -0,0 +1,191 @@
1
+ GEM
2
+ remote: https://rubygems.org/
3
+ specs:
4
+ abstract_type (0.0.7)
5
+ activemodel (4.2.3)
6
+ activesupport (= 4.2.3)
7
+ builder (~> 3.1)
8
+ activesupport (4.2.3)
9
+ i18n (~> 0.7)
10
+ json (~> 1.7, >= 1.7.7)
11
+ minitest (~> 5.1)
12
+ thread_safe (~> 0.3, >= 0.3.4)
13
+ tzinfo (~> 1.1)
14
+ adamantium (0.2.0)
15
+ ice_nine (~> 0.11.0)
16
+ memoizable (~> 0.4.0)
17
+ aspector (0.14.0)
18
+ ast (2.1.0)
19
+ astrolabe (1.3.1)
20
+ parser (~> 2.2)
21
+ axiom-types (0.1.1)
22
+ descendants_tracker (~> 0.0.4)
23
+ ice_nine (~> 0.11.0)
24
+ thread_safe (~> 0.3, >= 0.3.1)
25
+ brakeman (3.0.5)
26
+ erubis (~> 2.6)
27
+ fastercsv (~> 1.5)
28
+ haml (>= 3.0, < 5.0)
29
+ highline (~> 1.6.20)
30
+ multi_json (~> 1.2)
31
+ ruby2ruby (~> 2.1.1)
32
+ ruby_parser (~> 3.7.0)
33
+ sass (~> 3.0)
34
+ terminal-table (~> 1.4)
35
+ bson (3.2.1)
36
+ builder (3.2.2)
37
+ coderay (1.1.0)
38
+ coercible (1.0.0)
39
+ descendants_tracker (~> 0.0.1)
40
+ concord (0.1.5)
41
+ adamantium (~> 0.2.0)
42
+ equalizer (~> 0.0.9)
43
+ connection_pool (2.2.0)
44
+ descendants_tracker (0.0.4)
45
+ thread_safe (~> 0.3, >= 0.3.1)
46
+ diff-lcs (1.2.5)
47
+ docile (1.1.5)
48
+ equalizer (0.0.11)
49
+ erubis (2.7.0)
50
+ faker (1.5.0)
51
+ i18n (~> 0.5)
52
+ fastercsv (1.5.5)
53
+ flay (2.4.0)
54
+ ruby_parser (~> 3.0)
55
+ sexp_processor (~> 4.0)
56
+ flog (4.2.1)
57
+ ruby_parser (~> 3.1, > 3.1.0)
58
+ sexp_processor (~> 4.4)
59
+ haml (4.0.7)
60
+ tilt
61
+ haml-lint (0.13.0)
62
+ haml (~> 4.0)
63
+ rubocop (>= 0.25.0)
64
+ sysexits (~> 1.1)
65
+ highline (1.6.21)
66
+ i18n (0.7.0)
67
+ ice_nine (0.11.1)
68
+ json (1.8.3)
69
+ memoizable (0.4.2)
70
+ thread_safe (~> 0.3, >= 0.3.1)
71
+ method_source (0.8.2)
72
+ minitest (5.8.0)
73
+ mongoid (4.0.2)
74
+ activemodel (~> 4.0)
75
+ moped (~> 2.0.0)
76
+ origin (~> 2.1)
77
+ tzinfo (>= 0.3.37)
78
+ mongoid-rspec (2.2.0)
79
+ mongoid (~> 4.0.0)
80
+ rake
81
+ rspec (~> 3.1)
82
+ moped (2.0.7)
83
+ bson (~> 3.0)
84
+ connection_pool (~> 2.0)
85
+ optionable (~> 0.2.0)
86
+ multi_json (1.11.2)
87
+ optionable (0.2.0)
88
+ origin (2.1.1)
89
+ parser (2.2.2.6)
90
+ ast (>= 1.1, < 3.0)
91
+ polishgeeks-dev-tools (1.0.0)
92
+ brakeman
93
+ faker
94
+ haml-lint
95
+ mongoid-rspec
96
+ pry
97
+ rspec
98
+ rubocop
99
+ rubycritic (= 1.2.1)
100
+ shoulda
101
+ simplecov
102
+ timecop
103
+ yard
104
+ poseidon (0.0.5)
105
+ powerpack (0.1.1)
106
+ procto (0.0.2)
107
+ pry (0.10.1)
108
+ coderay (~> 1.1.0)
109
+ method_source (~> 0.8.1)
110
+ slop (~> 3.4)
111
+ rainbow (2.0.0)
112
+ rake (10.4.2)
113
+ reek (1.6.3)
114
+ parser (~> 2.2.0.pre.7)
115
+ rainbow (>= 1.99, < 3.0)
116
+ unparser (~> 0.2.2)
117
+ rspec (3.3.0)
118
+ rspec-core (~> 3.3.0)
119
+ rspec-expectations (~> 3.3.0)
120
+ rspec-mocks (~> 3.3.0)
121
+ rspec-core (3.3.2)
122
+ rspec-support (~> 3.3.0)
123
+ rspec-expectations (3.3.1)
124
+ diff-lcs (>= 1.2.0, < 2.0)
125
+ rspec-support (~> 3.3.0)
126
+ rspec-mocks (3.3.2)
127
+ diff-lcs (>= 1.2.0, < 2.0)
128
+ rspec-support (~> 3.3.0)
129
+ rspec-support (3.3.0)
130
+ rubocop (0.33.0)
131
+ astrolabe (~> 1.3)
132
+ parser (>= 2.2.2.5, < 3.0)
133
+ powerpack (~> 0.1)
134
+ rainbow (>= 1.99.1, < 3.0)
135
+ ruby-progressbar (~> 1.4)
136
+ ruby-progressbar (1.7.5)
137
+ ruby2ruby (2.1.4)
138
+ ruby_parser (~> 3.1)
139
+ sexp_processor (~> 4.0)
140
+ ruby_parser (3.7.1)
141
+ sexp_processor (~> 4.1)
142
+ rubycritic (1.2.1)
143
+ flay (= 2.4.0)
144
+ flog (= 4.2.1)
145
+ parser (>= 2.2.0, < 3.0)
146
+ reek (= 1.6.3)
147
+ ruby2ruby (>= 2.1.1, < 3.0)
148
+ virtus (~> 1.0)
149
+ sass (3.4.16)
150
+ sexp_processor (4.6.0)
151
+ shoulda (3.5.0)
152
+ shoulda-context (~> 1.0, >= 1.0.1)
153
+ shoulda-matchers (>= 1.4.1, < 3.0)
154
+ shoulda-context (1.2.1)
155
+ shoulda-matchers (2.8.0)
156
+ activesupport (>= 3.0.0)
157
+ simplecov (0.10.0)
158
+ docile (~> 1.1.0)
159
+ json (~> 1.8)
160
+ simplecov-html (~> 0.10.0)
161
+ simplecov-html (0.10.0)
162
+ slop (3.6.0)
163
+ sysexits (1.2.0)
164
+ terminal-table (1.5.2)
165
+ thread_safe (0.3.5)
166
+ tilt (2.0.1)
167
+ timecop (0.8.0)
168
+ tzinfo (1.2.2)
169
+ thread_safe (~> 0.1)
170
+ unparser (0.2.4)
171
+ abstract_type (~> 0.0.7)
172
+ adamantium (~> 0.2.0)
173
+ concord (~> 0.1.5)
174
+ diff-lcs (~> 1.2.5)
175
+ equalizer (~> 0.0.9)
176
+ parser (~> 2.2.2)
177
+ procto (~> 0.0.2)
178
+ virtus (1.0.5)
179
+ axiom-types (~> 0.1)
180
+ coercible (~> 1.0)
181
+ descendants_tracker (~> 0.0, >= 0.0.3)
182
+ equalizer (~> 0.0, >= 0.0.9)
183
+ yard (0.8.7.6)
184
+
185
+ PLATFORMS
186
+ ruby
187
+
188
+ DEPENDENCIES
189
+ aspector
190
+ polishgeeks-dev-tools
191
+ poseidon
data/MIT-LICENCE ADDED
@@ -0,0 +1,18 @@
1
+ Permission is hereby granted, free of charge, to any person obtaining
2
+ a copy of this software and associated documentation files (the
3
+ "Software"), to deal in the Software without restriction, including
4
+ without limitation the rights to use, copy, modify, merge, publish,
5
+ distribute, sublicense, and/or sell copies of the Software, and to
6
+ permit persons to whom the Software is furnished to do so, subject to
7
+ the following conditions:
8
+
9
+ The above copyright notice and this permission notice shall be
10
+ included in all copies or substantial portions of the Software.
11
+
12
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
13
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
14
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
15
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
16
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
17
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
18
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,147 @@
1
+ # WaterDrop
2
+
3
+ [![Build Status](https://travis-ci.org/karafka/waterdrop.png)](https://travis-ci.org/karafka/waterdrop)
4
+ [![Code Climate](https://codeclimate.com/github/karafka/waterdrop/badges/gpa.svg)](https://codeclimate.com/github/karafka/waterdrop)
5
+
6
+ Gem used to send events to Kafka in a standard and in an aspect way.
7
+
8
+ ## Installation
9
+
10
+ ```ruby
11
+ gem install waterdrop
12
+ ```
13
+
14
+ or add this to your Gemfile:
15
+
16
+ ```ruby
17
+ gem 'waterdrop'
18
+ ```
19
+
20
+ and run
21
+
22
+ ```
23
+ bundle install
24
+ ```
25
+
26
+ ## Setup
27
+
28
+ WaterDrop has following configuration options:
29
+
30
+ | Option | Value type | Description |
31
+ |-------------------------|---------------|--------------------------------|
32
+ | send_events | Boolean | Should we send events to Kafka |
33
+ | kafka_host | String | Kafka server host |
34
+ | kafka_ports | Array<String> | Kafka server ports |
35
+ | connection_pool_size | Integer | Kafka connection pool size |
36
+ | connection_pool_timeout | Integer | Kafka connection pool timeout |
37
+
38
+ To apply this configuration, you need to use a *setup* method:
39
+
40
+ ```ruby
41
+ WaterDrop.setup do |config|
42
+ config.send_events = true
43
+ config.connection_pool_size = 20
44
+ config.connection_pool_timeout = 1
45
+ config.kafka_ports = %w( 9092 )
46
+ config.kafka_host = 'localhost'
47
+ end
48
+ ```
49
+
50
+ This configuration can be placed in *config/initializers* and can vary based on the environment:
51
+
52
+ ```ruby
53
+ WaterDrop.setup do |config|
54
+ config.send_events = Rails.env.production?
55
+ config.connection_pool_size = 20
56
+ config.connection_pool_timeout = 1
57
+ config.kafka_ports = %w( 9092 )
58
+ config.kafka_host = Rails.env.production? ? 'prod-host' : 'localhost'
59
+ end
60
+ ```
61
+
62
+ ## Usage
63
+
64
+ ### Creating and sending standard events
65
+
66
+ To send Kafka messages, you don't need to use aspects, you can create and send events directly:
67
+
68
+ ```ruby
69
+ event = WaterDrop::Event.new('topic', 'message')
70
+ event.send!
71
+ ```
72
+
73
+ message that you want to send should be either castable to string or to json. If it can be casted to both, it will be casted to json.
74
+
75
+ ### Using aspects to handle events
76
+
77
+ WaterDrop uses [Aspector](https://github.com/gcao/aspector) to allow aspect oriented events hookup. If you need extensive details about aspector usage, please refer to the [examples](https://github.com/gcao/aspector/tree/master/examples) directory of this project.
78
+
79
+ In general aspects allows adding additional behavior to existing code without modifying the code itself. This way we can create and send events, without "polluting" the business logic with it.
80
+
81
+ All the WaterDrop aspects accept following parameters:
82
+
83
+ | Option | Value type | Description |
84
+ |-------------------------|-----------------------|----------------------------------------------|
85
+ | ClassName | Class | Class to which we want to hook |
86
+ | method: :method_name | Symbol, Array<Symbol> | Method (or methods) to which we want to hook |
87
+ | topic: 'karafka_topic' | String, Symbol | Kafka topic to which we will send the event |
88
+
89
+ There also a *message*, *after_message* and *before_message* proc parameter that will be evaluated in the methods object context.
90
+
91
+ #### Before aspects hookup
92
+
93
+ ```ruby
94
+ WaterDrop::Aspects::BeforeAspect.apply(
95
+ ClassName,
96
+ method: :run,
97
+ topic: 'karafka_topic',
98
+ message: -> { any_class_name_instance_method }
99
+ )
100
+ ```
101
+
102
+ now each time before you run:
103
+
104
+ ```ruby
105
+ ClassName.new.run
106
+ ```
107
+
108
+ an event with the given message will be send to Kafka.
109
+
110
+ #### After aspects hookup
111
+
112
+ ```ruby
113
+ WaterDrop::Aspects::AfterAspect.apply(
114
+ ClassName,
115
+ method: :run,
116
+ topic: 'karafka_topic',
117
+ message: ->(result) { "This is result of method run: #{result}" }
118
+ )
119
+ ```
120
+
121
+ now each time after you run:
122
+
123
+ ```ruby
124
+ ClassName.new.run
125
+ ```
126
+
127
+ an event with the given message will be send to Kafka.
128
+
129
+ #### Around aspects hookup
130
+
131
+ ```ruby
132
+ WaterDrop::Aspects::AroundAspect.apply(
133
+ ClassName,
134
+ method: :run,
135
+ topic: 'karafka_topic',
136
+ before_message: -> { any_class_name_instance_method },
137
+ after_message: ->(result) { "This is result of method run: #{result}" }
138
+ )
139
+ ```
140
+
141
+ now each time you run:
142
+
143
+ ```ruby
144
+ ClassName.new.run
145
+ ```
146
+
147
+ an event with the given message will be send before and after the method execution.
data/Rakefile ADDED
@@ -0,0 +1,18 @@
1
+ require 'bundler'
2
+ require 'bundler/gem_tasks'
3
+ require 'rake'
4
+ require 'polishgeeks-dev-tools'
5
+
6
+ PolishGeeks::DevTools.setup do |config|
7
+ config.brakeman = false
8
+ config.haml_lint = false
9
+ end
10
+
11
+ desc 'Self check using strike-dev-tools'
12
+ task :check do
13
+ PolishGeeks::DevTools::Runner.new.execute(
14
+ PolishGeeks::DevTools::Logger.new
15
+ )
16
+ end
17
+
18
+ task default: :check
data/lib/water_drop.rb ADDED
@@ -0,0 +1,53 @@
1
+ # External components
2
+ %w(
3
+ rake
4
+ rubygems
5
+ bundler
6
+ logger
7
+ pathname
8
+ json
9
+ poseidon
10
+ aspector
11
+ forwardable
12
+ connection_pool
13
+ ).each { |lib| require lib }
14
+
15
+ # Internal components
16
+
17
+ base_path = File.dirname(__FILE__) + '/water_drop'
18
+
19
+ %w(
20
+ version
21
+ pool
22
+ config
23
+ event
24
+ logger
25
+ aspects/base_aspect
26
+ aspects/formatter
27
+ aspects/after_aspect
28
+ aspects/around_aspect
29
+ aspects/before_aspect
30
+ ).each { |lib| require "#{base_path}/#{lib}" }
31
+
32
+ # WaterDrop library
33
+ module WaterDrop
34
+ class << self
35
+ attr_writer :logger
36
+
37
+ # @return [Logger] logger that we want to use
38
+ def logger
39
+ @logger ||= Logger.new
40
+ end
41
+
42
+ # Sets up the whole configuration
43
+ # @param [Block] block configuration block
44
+ def setup(&block)
45
+ Config.setup(&block)
46
+ end
47
+
48
+ # @return [WaterDrop::Config] config instance
49
+ def config
50
+ Config.config
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,18 @@
1
+ module WaterDrop
2
+ module Aspects
3
+ # After method execution aspect
4
+ # @example Apply after aspect to a method
5
+ # WaterDrop::Aspects::AfterAspect.apply(
6
+ # ClassName,
7
+ # method: :run,
8
+ # topic: 'karafka_topic',
9
+ # message: ->(result) { "This is result of method run: #{result}" }
10
+ # )
11
+ class AfterAspect < BaseAspect
12
+ after options[:method], interception_arg: true do |interception, result, *args|
13
+ options = interception.options
14
+ interception.aspect.handle(self, options, args, options[:message], result)
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,21 @@
1
+ module WaterDrop
2
+ module Aspects
3
+ # Around method execution aspect
4
+ # @example Apply around aspect to a method
5
+ # WaterDrop::Aspects::AroundAspect.apply(
6
+ # ClassName,
7
+ # method: :run,
8
+ # topic: 'karafka_topic',
9
+ # before_message: -> { any_class_name_instance_method },
10
+ # after_message: ->(result) { "This is result of method run: #{result}" }
11
+ # )
12
+ class AroundAspect < BaseAspect
13
+ around options[:method], interception_arg: true do |interception, proxy, *args, &block|
14
+ options = interception.options
15
+ interception.aspect.handle(self, options, args, options[:before_message])
16
+ result = proxy.call(*args, &block)
17
+ interception.aspect.handle(self, options, args, options[:after_message], result)
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,37 @@
1
+ module WaterDrop
2
+ # Aspects module which include all available aspects
3
+ module Aspects
4
+ # Base class for all aspects
5
+ class BaseAspect < ::Aspector::Base
6
+ default private_methods: true
7
+
8
+ # @param this is an instance on which we execute aspect (original method caller)
9
+ # @param [Hash] options aspect options
10
+ # @param [Array] args original method arguments
11
+ # @param [Block] message block which we evaluate to get a message that we will send
12
+ # @param result original method result
13
+ def handle(this, options, args, message, *result)
14
+ formatter = Formatter.new(
15
+ options,
16
+ args,
17
+ instance_run(this, result, message)
18
+ )
19
+
20
+ Event.new(options[:topic], formatter.message).send!
21
+ end
22
+
23
+ private
24
+
25
+ # Method used to change message block binding, so it will be evaluated
26
+ # in the caller instance context
27
+ # @param this is an instance on which we execute aspect (original method caller)
28
+ # @param result original method call result
29
+ # @param [Block] message block
30
+ def instance_run(this, result, message)
31
+ return this.instance_eval(&message) if message.parameters.empty?
32
+
33
+ this.instance_exec(result, message) { |res, block| block.call(res.first) }
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,18 @@
1
+ module WaterDrop
2
+ module Aspects
3
+ # Before method execution aspect
4
+ # @example Apply before aspect to a method
5
+ # WaterDrop::Aspects::BeforeAspect.apply(
6
+ # ClassName,
7
+ # method: :run,
8
+ # topic: 'karafka_topic',
9
+ # message: -> { any_class_name_instance_method }
10
+ # )
11
+ class BeforeAspect < BaseAspect
12
+ before options[:method], interception_arg: true do |interception, *args|
13
+ options = interception.options
14
+ interception.aspect.handle(self, options, args, options[:message])
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,25 @@
1
+ module WaterDrop
2
+ module Aspects
3
+ # Class used to format message that will be send from an aspect
4
+ class Formatter
5
+ # @param [Hash] options from an aspect
6
+ # @param [Array] args original method arguments
7
+ # @param result of execution of the method
8
+ def initialize(options, args, result)
9
+ @options = options
10
+ @args = args
11
+ @result = result
12
+ end
13
+
14
+ # @return [Hash] hash with formatted message that can be send
15
+ def message
16
+ {
17
+ topic: @options[:topic],
18
+ method: @options[:method],
19
+ message: @result,
20
+ args: @args
21
+ }
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,41 @@
1
+ module WaterDrop
2
+ # Configurator for setting up all options required by WaterDrop
3
+ class Config
4
+ class << self
5
+ attr_accessor :config
6
+ end
7
+
8
+ # Available options
9
+ # @option connection_pool_size [Fixnum] The number of connections to pool.
10
+ # @option connection_pool_timeout [Fixnum] Amount of time in seconds to wait for a connection
11
+ # if none currently available.
12
+ # @option kafka_ports [Array] the ports of kafka brokers
13
+ # @option kafka_host [String] the host of kafka server
14
+ # @option send_events [Boolean] boolean value to define whether events should be sent
15
+ #
16
+ OPTIONS = %i(
17
+ connection_pool_size
18
+ connection_pool_timeout
19
+ kafka_ports
20
+ kafka_host
21
+ send_events
22
+ )
23
+
24
+ OPTIONS.each do |attr_name|
25
+ attr_accessor attr_name
26
+
27
+ # @return [Boolean] is given command enabled
28
+ define_method :"#{attr_name}?" do
29
+ public_send(attr_name) == true
30
+ end
31
+ end
32
+
33
+ # Configurating method
34
+ def self.setup(&block)
35
+ self.config = new
36
+
37
+ block.call(config)
38
+ config.freeze
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,31 @@
1
+ module WaterDrop
2
+ # Event module which encapsulate single Kafka event logic and its delivery
3
+ class Event
4
+ attr_reader :topic, :message
5
+
6
+ # @param topic [String, Symbol] a topic to which we want to send a message
7
+ # @param message [Object] any object that can be serialized to a JSON string or
8
+ # that can be casted to a string
9
+ # @return [WaterDrop::Event] WaterDrop event instance
10
+ # @example Creating a new event
11
+ # WaterDrop::Event.new(topic, message)
12
+ def initialize(topic, message)
13
+ @topic = topic.to_s
14
+ @message = message.respond_to?(:to_json) ? message.to_json : message.to_s
15
+ end
16
+
17
+ # Sents a current event to Kafka
18
+ # @note Won't send any events if send_events config flag is set to false
19
+ # @example Set a message
20
+ # WaterDrop::Event.new(topic, message).send!
21
+ def send!
22
+ return true unless ::WaterDrop.config.send_events?
23
+
24
+ Pool.with do |producer|
25
+ producer.send_messages([
26
+ Poseidon::MessageToSend.new(topic, message)
27
+ ])
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,10 @@
1
+ module WaterDrop
2
+ # Null logger for karafka
3
+ # Is used when logger is not defined
4
+ class Logger
5
+ # Returns nil for any method call
6
+ def method_missing(*_args, &_block)
7
+ nil
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,24 @@
1
+ module WaterDrop
2
+ # Raw poseidon connection pool for WaterDrop events delivery
3
+ module Pool
4
+ extend SingleForwardable
5
+ # Delegate directly to pool
6
+ def_delegators :pool, :with
7
+
8
+ class << self
9
+ # @return [::ConnectionPool] connection pool instance that we can then use
10
+ def pool
11
+ @pool ||= ConnectionPool.new(
12
+ size: ::WaterDrop.config.connection_pool_size,
13
+ timeout: ::WaterDrop.config.connection_pool_timeout
14
+ ) do
15
+ addresses = ::WaterDrop.config.kafka_ports.map do |port|
16
+ "#{::WaterDrop.config.kafka_host}:#{port}"
17
+ end
18
+
19
+ Poseidon::Producer.new(addresses, object_id.to_s)
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,5 @@
1
+ # WaterDrop library
2
+ module WaterDrop
3
+ # Current WaterDrop version
4
+ VERSION = '0.1.0'
5
+ end
data/waterdrop.gemspec ADDED
@@ -0,0 +1,25 @@
1
+ lib = File.expand_path('../lib', __FILE__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+ require 'rake'
4
+ require 'water_drop/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'waterdrop'
8
+ spec.version = ::WaterDrop::VERSION
9
+ spec.platform = Gem::Platform::RUBY
10
+ spec.authors = ['Maciej Mensfeld', 'Pavlo Vavruk']
11
+ spec.email = %w( maciej@mensfeld.pl pavlo.vavruk@gmail.com )
12
+ spec.homepage = ''
13
+ spec.summary = %q{ Kafka events with aspects made easy! }
14
+ spec.description = spec.summary
15
+ spec.license = 'MIT'
16
+
17
+ spec.add_dependency 'bundler', '~> 0'
18
+ spec.add_dependency 'rake', '~> 0'
19
+ spec.add_dependency 'aspector', '~> 0'
20
+ spec.add_dependency 'poseidon', '~> 0'
21
+
22
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(spec)/}) }
23
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
24
+ spec.require_paths = %w( lib )
25
+ end
metadata ADDED
@@ -0,0 +1,124 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: waterdrop
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Maciej Mensfeld
8
+ - Pavlo Vavruk
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2015-08-20 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: bundler
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - "~>"
19
+ - !ruby/object:Gem::Version
20
+ version: '0'
21
+ type: :runtime
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - "~>"
26
+ - !ruby/object:Gem::Version
27
+ version: '0'
28
+ - !ruby/object:Gem::Dependency
29
+ name: rake
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - "~>"
33
+ - !ruby/object:Gem::Version
34
+ version: '0'
35
+ type: :runtime
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - "~>"
40
+ - !ruby/object:Gem::Version
41
+ version: '0'
42
+ - !ruby/object:Gem::Dependency
43
+ name: aspector
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - "~>"
47
+ - !ruby/object:Gem::Version
48
+ version: '0'
49
+ type: :runtime
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - "~>"
54
+ - !ruby/object:Gem::Version
55
+ version: '0'
56
+ - !ruby/object:Gem::Dependency
57
+ name: poseidon
58
+ requirement: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - "~>"
61
+ - !ruby/object:Gem::Version
62
+ version: '0'
63
+ type: :runtime
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - "~>"
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ description: Kafka events with aspects made easy!
71
+ email:
72
+ - maciej@mensfeld.pl
73
+ - pavlo.vavruk@gmail.com
74
+ executables: []
75
+ extensions: []
76
+ extra_rdoc_files: []
77
+ files:
78
+ - ".gitignore"
79
+ - ".ruby-gemset"
80
+ - ".ruby-version"
81
+ - ".travis.yml"
82
+ - Gemfile
83
+ - Gemfile.lock
84
+ - MIT-LICENCE
85
+ - README.md
86
+ - Rakefile
87
+ - lib/water_drop.rb
88
+ - lib/water_drop/aspects/after_aspect.rb
89
+ - lib/water_drop/aspects/around_aspect.rb
90
+ - lib/water_drop/aspects/base_aspect.rb
91
+ - lib/water_drop/aspects/before_aspect.rb
92
+ - lib/water_drop/aspects/formatter.rb
93
+ - lib/water_drop/config.rb
94
+ - lib/water_drop/event.rb
95
+ - lib/water_drop/logger.rb
96
+ - lib/water_drop/pool.rb
97
+ - lib/water_drop/version.rb
98
+ - waterdrop.gemspec
99
+ homepage: ''
100
+ licenses:
101
+ - MIT
102
+ metadata: {}
103
+ post_install_message:
104
+ rdoc_options: []
105
+ require_paths:
106
+ - lib
107
+ required_ruby_version: !ruby/object:Gem::Requirement
108
+ requirements:
109
+ - - ">="
110
+ - !ruby/object:Gem::Version
111
+ version: '0'
112
+ required_rubygems_version: !ruby/object:Gem::Requirement
113
+ requirements:
114
+ - - ">="
115
+ - !ruby/object:Gem::Version
116
+ version: '0'
117
+ requirements: []
118
+ rubyforge_project:
119
+ rubygems_version: 2.4.6
120
+ signing_key:
121
+ specification_version: 4
122
+ summary: Kafka events with aspects made easy!
123
+ test_files: []
124
+ has_rdoc: