maitredee 0.8.2 → 0.8.3

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
  SHA256:
3
- metadata.gz: 61c90edbaf57c2a995ee3f92ee780235bb8af4421a446fa9bd10286101c80949
4
- data.tar.gz: d118a9ee6cf0d03b22e46bdb8d271930ec444806a6aac071e27d496b1d952d22
3
+ metadata.gz: 52dd1ef33db5eadd01dc66f0c26f37a7ac8b5d19bfe865ec0cae03535900fedb
4
+ data.tar.gz: d0b9a43bb7eab1208fd2ff3ba5668a65d2fb870d755cbd61fb41d84274e53521
5
5
  SHA512:
6
- metadata.gz: 024331eff27c916156ad6d878647e527a8fa50da23b451f8fe853b18e4b73b481bb6e65cf0dbd385dfd151b9b7d0f15c2d194a2c4ec16b36f6c3d59566b93334
7
- data.tar.gz: 28b6af8d263162cb2ea0eff4bccb46671f5ccd173d7251fa2429c3d637aaec9ce643f993f1678d9c70738c71a78a6b20182327f879eb0d36c39d336a2c122185
6
+ metadata.gz: 24dd10b8944d88da64c2386e3660aa1cb1263523aa7e8ed0fa5ccfd430af698b787c49de230b8a8e9f402330a74e5de284bf5b9abb2fb5773e04a87f4136283d
7
+ data.tar.gz: 6e4ee09a3a305a2640bfb354031ae0000a121dba80c3bc303e7f8d68898ad234231757a3d7e1d6eb87afba2417e377e4547f66c5bc13de933f38aa1c76c4c15c
data/.circleci/config.yml CHANGED
@@ -51,11 +51,23 @@ jobs:
51
51
  - run:
52
52
  name: run rspec tests
53
53
  command: |
54
- bundle exec rspec --format progress
54
+ mkdir /tmp/test-results
55
+ bundle exec rspec \
56
+ --profile 10 \
57
+ --format progress
55
58
  - run:
56
59
  name: run sns/sqs tests
57
60
  command: |
58
61
  INTEGRATION_TEST=sns_sqs bundle exec rspec --format progress
62
+ - run:
63
+ name: run doctests
64
+ command: bundle exec goodread-rb README.md
65
+ # Collect reports
66
+ - store_test_results:
67
+ path: /tmp/test-results
68
+ - store_artifacts:
69
+ path: /tmp/test-results
70
+ destination: test-results
59
71
  workflows:
60
72
  version: 2
61
73
  build_and_test:
data/.yardopts ADDED
@@ -0,0 +1 @@
1
+ --markup=markdown
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- maitredee (0.8.2)
4
+ maitredee (0.8.3)
5
5
  activesupport
6
6
  aws-sdk-sns
7
7
  aws-sdk-sqs
@@ -34,8 +34,8 @@ GEM
34
34
  minitest (~> 5.1)
35
35
  tzinfo (~> 1.1)
36
36
  aws-eventstream (1.0.1)
37
- aws-partitions (1.122.0)
38
- aws-sdk-core (3.44.0)
37
+ aws-partitions (1.127.0)
38
+ aws-sdk-core (3.44.1)
39
39
  aws-eventstream (~> 1.0)
40
40
  aws-partitions (~> 1.0)
41
41
  aws-sigv4 (~> 1.0)
@@ -50,6 +50,7 @@ GEM
50
50
  builder (3.2.3)
51
51
  byebug (10.0.2)
52
52
  coderay (1.1.2)
53
+ colorize (0.8.1)
53
54
  concurrent-ruby (1.1.3)
54
55
  crass (1.0.4)
55
56
  diff-lcs (1.3)
@@ -57,8 +58,12 @@ GEM
57
58
  ecma-re-validator (0.2.0)
58
59
  regexp_parser (~> 1.2)
59
60
  erubi (1.7.1)
61
+ gemoji (3.0.0)
60
62
  globalid (0.4.1)
61
63
  activesupport (>= 4.2.0)
64
+ goodread (0.3.2)
65
+ colorize (~> 0.8)
66
+ gemoji (~> 3.0)
62
67
  hana (1.3.4)
63
68
  i18n (1.1.1)
64
69
  concurrent-ruby (~> 1.0)
@@ -128,6 +133,7 @@ DEPENDENCIES
128
133
  activejob
129
134
  bundler (~> 1.17)
130
135
  dotenv
136
+ goodread
131
137
  maitredee!
132
138
  pry
133
139
  pry-byebug
@@ -137,4 +143,4 @@ DEPENDENCIES
137
143
  rspec-mocks (~> 3.0)
138
144
 
139
145
  BUNDLED WITH
140
- 1.17.1
146
+ 1.17.2
data/README.md CHANGED
@@ -1,8 +1,26 @@
1
1
  # Maitredee
2
2
 
3
- Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/maitredee`. To experiment with that code, run `bin/console` for an interactive prompt.
3
+ An opinionated pub/sub framework.
4
4
 
5
- TODO: Delete this and the text above, and describe your gem
5
+ ## Table of Contents
6
+ - [Overview](#overview)
7
+ - [Installation](#installation)
8
+ - [Configuration](#configuration)
9
+ - [Publisher](#publisher)
10
+ - [Subscriber](#subscriber)
11
+ - [Validation schema](#validation-schema)
12
+ - [Misc](#misc)
13
+ - [Development](#development)
14
+ - [Contributing](#contributing)
15
+ - [License](#license)
16
+ - [Code of Conduct](#code-of-conduct)
17
+
18
+ ## Overview
19
+ We made maitredee to simplify publishing and subscribing to events for our junior developers. We tried using kafka but ordered eventing was too complicated.
20
+
21
+ We tried to have zero setup required to get this up and running and make it work as simply as sidekiq.
22
+
23
+ We hope in the future to add more adapters beyond sns/sqs.
6
24
 
7
25
  ## Installation
8
26
 
@@ -20,30 +38,169 @@ Or install it yourself as:
20
38
 
21
39
  $ gem install maitredee
22
40
 
23
- ## Usage
41
+ ## Configuration
42
+
43
+ Required Configuration
44
+ ```ruby
45
+ Maitredee.namespace = "plated-production"
46
+ Maitredee.schema_path = Rails.root.join("your/path").to_s
47
+ Maitredee.client = :sns_sqs
48
+ ```
49
+
50
+ These namespace can also be set with the environment variable `MAITREDEE_NAMESPACE`
51
+
52
+ ### Available clients
53
+
54
+ Maitredee currently supports the following clients:
55
+
56
+ #### SNS/SQS :sns_sqs
57
+ You can set the AWS parameters in a variety of ways.
58
+ Either environment variables or explicitly.
59
+ Supported environment variables are `MAITREDEE_AWS_ACCESS_KEY_ID`, `MAITREDEE_AWS_SECRET_ACCESS_KEY`, `MAITREDEE_AWS_REGION` and then falls back to default AWS keys.
60
+
61
+ if you wish to set it explicitly:
62
+ ```ruby
63
+ Maitredee.set_client(
64
+ :sns_sqs,
65
+ access_key_id: "",
66
+ secret_access_key: "",
67
+ region: ""
68
+ )
69
+ ```
70
+
71
+ #### Test :test
72
+
73
+ This is used for testing.
74
+
75
+ ```ruby
76
+ Maitredee.client = :test
77
+ ```
78
+
79
+ When you pubish anything through Maitredee it will be logged in the test client for test verification.
80
+
81
+ You should reset the client at the beginning of every test with `Maitredee.client.reset`
82
+
83
+ ## Publisher
84
+
85
+ Create a publisher class for your topic and inherit from `Maitredee::Publisher`
86
+ Optionally define the default topic, event_name, or validation schema with `publish_defaults`
87
+ Maitredee will call `process` on your publisher when it is called. Define a method `process` that calls `publish` with the parameters of your choosing. `Publish` will default the `topic`, `event_name`, and `schema_name` from your publish_defaults if not given.
88
+
89
+ ```ruby goodread
90
+ require "maitredee"
91
+
92
+ class MyPublisher < Maitredee::Publisher
93
+ publish_defaults(
94
+ topic_name: :your_default_topic,
95
+ event_name: :your_default_event_name,
96
+ schema_name: :your_default_schema
97
+ )
98
+
99
+ attr_reader :model
100
+
101
+ def initialize(model)
102
+ @model = model
103
+ end
104
+
105
+ def process
106
+ publish(
107
+ topic_name: :my_topic,
108
+ event_name: :event_name_is_optional,
109
+ schema_name: :schema_name,
110
+ primary_key: "optionalKey",
111
+ body: {
112
+ id: model.id,
113
+ name: model.name
114
+ }
115
+ )
116
+ end
117
+ end
118
+ ```
119
+
120
+
121
+ ### Publishing a message
122
+ To publish a message, simply call `call` on your publisher:
123
+ ```ruby
124
+ MyPublisher.call(model)
125
+ ```
126
+
127
+ Publish will first validate your schema before publishing the message.
128
+
129
+ If you have ActiveJob you can also `#call_later` and it will be called asyncronously
130
+
131
+ ## Subscriber
132
+
133
+ ```ruby
134
+ class RecipeSubscriber < Maitredee::Subscriber
135
+ # this is the topic name
136
+ subscribe_to :recipes do
24
137
 
25
- TODO: Write usage instructions here
138
+ # this is the event name optionally say which method to use to process
139
+ event(:create, to: create)
26
140
 
27
- ## Todo
141
+ # event_name will be used as the method name if it is a valid method name, otherwise to: must be set
142
+ event(:delete)
143
+
144
+ # for empty event name just use nil
145
+ event(nil, to: :process)
146
+
147
+ # you can specify a catch all route
148
+ default_event to: :process
149
+ end
150
+
151
+ def create
152
+ Recipe.create!(message.body)
153
+ end
154
+
155
+ def process
156
+ Recipe.find(message.body[:id]).update(message.body)
157
+ end
158
+
159
+ def delete
160
+ Recipe.find(message.body[:id]).destroy
161
+ end
162
+ end
163
+ ```
164
+
165
+ ## Validating Schemas
166
+ Maitredee validates your message body schemas using JSON schema ([JSON-schemer] (https://github.com/davishmcclurg/json_schemer)) for both publishing and consuming messages. [Configure] (#configuration) the location of your schemas and provide a JSON file for each of your schemas.
167
+
168
+ Example `recipe_v1.json`:
169
+ ```json
170
+ {
171
+ "type": "object",
172
+ "required": ["id", "name", "servings"],
173
+ "properties": {
174
+ "id": {
175
+ "type": "string"
176
+ },
177
+ "name": {
178
+ "type": "string"
179
+ },
180
+ "servings": {
181
+ "type": "number"
182
+ }
183
+ }
184
+ }
185
+
186
+ ```
28
187
 
29
- * split into publisher/subscriber sub gems with monorepo
30
- * subscriber schema validation
31
- * maitredee/test helper methods for subscribers
188
+ ## Misc
32
189
 
33
- ## Development
190
+ ### Development
34
191
 
35
192
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
36
193
 
37
194
  To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
38
195
 
39
- ## Contributing
196
+ ### Contributing
40
197
 
41
- Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/maitredee. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
198
+ Bug reports and pull requests are welcome on GitHub at https://github.com/plated/maitredee. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
42
199
 
43
- ## License
200
+ ### License
44
201
 
45
202
  The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
46
203
 
47
- ## Code of Conduct
204
+ ### Code of Conduct
48
205
 
49
- Everyone interacting in the Maitredee project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/[USERNAME]/maitredee/blob/master/CODE_OF_CONDUCT.md).
206
+ Everyone interacting in the Maitredee project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/plated/maitredee/blob/master/CODE_OF_CONDUCT.md).
data/lib/maitredee.rb CHANGED
@@ -9,15 +9,34 @@ require "pathname"
9
9
  require "maitredee/publisher"
10
10
  require "maitredee/subscriber"
11
11
  require "maitredee/version"
12
+ require "maitredee/adapters/base_adapter"
12
13
  require "maitredee/adapters/sns_sqs_adapter"
13
14
  require "maitredee/railtie" if defined? ::Rails::Railtie
14
15
 
15
16
  module Maitredee
16
17
  class << self
17
- attr_accessor :resource_name_suffix, :schema_path
18
+
19
+ # allows you to add a suffix to all your resource names, mostly used for testing but could be useful in other occassions.
20
+ # @return [String] string appended to all resource names
21
+ attr_accessor :resource_name_suffix
22
+
23
+ # this is the path of the folder in which validation_schema will try to do a lookup. This folder should contain json schemas.
24
+ # @return [String] path to folder
25
+ attr_accessor :schema_path
26
+
27
+ # the client we use for publishing and setting up workers
28
+ # @return [Maitredee::Adapters::AbstractAdapter]
18
29
  attr_reader :client
19
- attr_writer :app_name, :namespace
20
30
 
31
+ # publishes messages using configured adapter
32
+ #
33
+ # @param topic [String] topic name
34
+ # @param body [Hash, Array, String] Any valid json data that can be validated by json-schema
35
+ # @param schema_name [String] A valid schema name for publishing data
36
+ # @param event_name [String, nil] Event name for subscriber routing
37
+ # @param primary_key [#to_s, nil] Key to be used for resource identification
38
+ #
39
+ # @return [PublisherMessage] published message
21
40
  def publish(
22
41
  topic_name:,
23
42
  body:,
@@ -44,15 +63,26 @@ module Maitredee
44
63
  message
45
64
  end
46
65
 
66
+ # configure the adapter, must be executed before loading subscribers
67
+ #
68
+ # @param slug [#to_s] name of adapter
69
+ # @param args [] options to send to the adapter
47
70
  def set_client(slug, *args)
48
71
  raise "No client set for Maitredee" if slug.nil?
49
72
  @client = "::Maitredee::Adapters::#{slug.to_s.camelize}Adapter".constantize.new(*args)
50
73
  end
51
74
 
75
+ # set a client without parameters
76
+ #
77
+ # @param slug [#to_s] name of adapter
52
78
  def client=(slug)
53
79
  set_client(slug)
54
80
  end
55
81
 
82
+ # build topic resource name from topic name
83
+ #
84
+ # @param topic_name [#to_s] topic name
85
+ # @return [String]
56
86
  def topic_resource_name(topic_name)
57
87
  [
58
88
  namespace,
@@ -61,6 +91,11 @@ module Maitredee
61
91
  ].compact.join("--")
62
92
  end
63
93
 
94
+ # build queue resource name from queue name and topic name
95
+ #
96
+ # @param topic_name [#to_s] topic name
97
+ # @param queue_name [#to_s] queue name
98
+ # @return [String]
64
99
  def queue_resource_name(topic_name, queue_name)
65
100
  [
66
101
  namespace,
@@ -75,6 +110,13 @@ module Maitredee
75
110
  end
76
111
  end
77
112
 
113
+ # validate a body given a schema name
114
+ #
115
+ # @param body [Array, Hash, String] data to send with message
116
+ # @param schema [String] string key to look up schema to validate against
117
+ #
118
+ # @raise [ValidationError] if validation fails
119
+ # @return [nil]
78
120
  def validate!(body, schema)
79
121
  errors = schemas[schema].validate(body.as_json)
80
122
  properties = errors.map do |error|
@@ -86,6 +128,9 @@ module Maitredee
86
128
  end
87
129
  end
88
130
 
131
+ # hash to look up schema based of schema_path
132
+ #
133
+ # @return Hash[JSONSchemer::Schema::Draft7]
89
134
  def schemas
90
135
  @schemas ||= Hash.new do |hash, key|
91
136
  path = Pathname.new(schema_path).join("#{key}.json")
@@ -93,6 +138,10 @@ module Maitredee
93
138
  end
94
139
  end
95
140
 
141
+ # fetch configured app name or automatically fetch from Rails or from ENV["MAITREDEE_APP_NAME"]
142
+ # used for generating queue_resource_name
143
+ #
144
+ # @return [String]
96
145
  def app_name
97
146
  @app_name ||=
98
147
  begin
@@ -106,11 +155,24 @@ module Maitredee
106
155
  end
107
156
  end
108
157
 
158
+ # set app_name instead of using default
159
+ # @param [String]
160
+ attr_writer :app_name
161
+
162
+
163
+ # fetch configured namespace or automatically fetch from ENV["MAITREDEE_NAMESPACE"]
164
+ # @return [String]
109
165
  def namespace
110
166
  @namespace ||=
111
167
  ENV["MAITREDEE_NAMESPACE"] || raise("must set namespace for maitredee")
112
168
  end
113
169
 
170
+ # set namespace instead of using default
171
+ # @param [String]
172
+ attr_writer :namespace
173
+
174
+ # idempotently configures broker to create topics, queues and subscribe queues to topics
175
+ # nothing will eveer be deleted or cleaned up
114
176
  def configure_broker
115
177
  hash_array = Hash.new { |hash, key| hash[key] = [] }
116
178
  topics_and_queues =
@@ -121,11 +183,13 @@ module Maitredee
121
183
  client.configure_broker(topics_and_queues)
122
184
  end
123
185
 
186
+ # @api private
124
187
  def register_subscriber(klass)
125
188
  client.add_worker(klass)
126
189
  subscriber_registry.add(klass)
127
190
  end
128
191
 
192
+ # @api private
129
193
  def subscriber_registry
130
194
  @subscriber_registry ||= Set.new
131
195
  end
@@ -14,6 +14,16 @@ module Maitredee
14
14
  subclass::PublisherJob.service_class = subclass
15
15
  end
16
16
 
17
+ # Uses ActieJob to async the publishing
18
+ # @example To configure the specific async job open PublisherJob
19
+ # class RecipePublisher < Maitredee::Publisher
20
+ # class PublisherJob
21
+ # queue_as :low
22
+ # end
23
+ # end
24
+ #
25
+ # RecipePublisher.call_later(Recipe.find(1))
26
+ #
17
27
  def call_later(*args)
18
28
  self::PublisherJob.perform_later(*args)
19
29
  end
@@ -0,0 +1,18 @@
1
+ module Maitredee
2
+ module Adapters
3
+ class BaseAdapter
4
+ def publish(message)
5
+ raise NotImplementedError
6
+ end
7
+
8
+ def add_worker(subscriber_class)
9
+ raise NotImplementedError
10
+ end
11
+
12
+ def reset
13
+ raise NotImplementedError
14
+ end
15
+ end
16
+ end
17
+ end
18
+
@@ -3,9 +3,15 @@ require "aws-sdk-sqs"
3
3
 
4
4
  module Maitredee
5
5
  module Adapters
6
- class SnsSqsAdapter
6
+ class SnsSqsAdapter < BaseAdapter
7
7
  attr_reader :access_key_id, :secret_access_key, :region
8
8
 
9
+ # @param access_key_id [String] if `nil` will look in `ENV["MAITREDEE_AWS_ACCESS_KEY_ID"]`
10
+ # @param secret_access_key [String] if `nil` will look in `ENV["MAITREDEE_AWS_SECRET_ACCESS_KEY"]`
11
+ # @param region [String] if `nil` will look in `ENV["MAITREDEE_AWS_REGION"]`
12
+ # @param default_shoryuken_options [Hash] default options of the shoryuken job listening to the queues
13
+ # defaults to `{ body_parser: :json, auto_delete: true }`
14
+
9
15
  def initialize(access_key_id: nil, secret_access_key: nil, region: nil, default_shoryuken_options: nil)
10
16
  @access_key_id = access_key_id || ENV["MAITREDEE_AWS_ACCESS_KEY_ID"]
11
17
  @secret_access_key = secret_access_key || ENV["MAITREDEE_AWS_SECRET_ACCESS_KEY"]
@@ -15,6 +21,8 @@ module Maitredee
15
21
  Shoryuken.sqs_client = sqs_client
16
22
  end
17
23
 
24
+ # publishes message to SNS
25
+ # @param message [PublisherMessage]
18
26
  def publish(message)
19
27
  message_attributes = {
20
28
  message_id: message.message_id,
@@ -32,6 +40,8 @@ module Maitredee
32
40
  )
33
41
  end
34
42
 
43
+ # creates topics from keys and queues from values, and subscribes queues to topics
44
+ # @param config [Hash{String => Array<String>}]
35
45
  def configure_broker(config)
36
46
  config.each do |topic_resource_name, queue_resource_names|
37
47
  queue_resource_names.each do |queue_resource_name|
@@ -43,6 +53,7 @@ module Maitredee
43
53
  end
44
54
  end
45
55
 
56
+ # @api private
46
57
  def topics
47
58
  @topics ||= Hash.new do |hash, key|
48
59
  topic = sns_client.create_topic(
@@ -52,6 +63,7 @@ module Maitredee
52
63
  end
53
64
  end
54
65
 
66
+ # @api private
55
67
  def queues
56
68
  @queues ||= Hash.new do |hash, key|
57
69
  queue_url = sqs_client.create_queue(queue_name: key).queue_url
@@ -59,10 +71,14 @@ module Maitredee
59
71
  end
60
72
  end
61
73
 
74
+ # @api private
62
75
  def subscriptions
63
76
  @subscriptions ||= {}
64
77
  end
65
78
 
79
+ # subscribes a queue to a topic
80
+ # @param queue_resource_name [String]
81
+ # @param topic_resource_name [String]
66
82
  def subscribe(queue_resource_name:, topic_resource_name:)
67
83
  topic = topics[topic_resource_name]
68
84
  queue = queues[queue_resource_name]
@@ -102,6 +118,7 @@ module Maitredee
102
118
  worker_class
103
119
  end
104
120
 
121
+ # @api private
105
122
  def default_shoryuken_options
106
123
  @default_shoryuken_options ||= {
107
124
  body_parser: :json,
@@ -109,6 +126,8 @@ module Maitredee
109
126
  }
110
127
  end
111
128
 
129
+ # deletes all topics, queues, and subscriptions
130
+ # @api private
112
131
  def reset
113
132
  [topics, queues, subscriptions].each do |resource|
114
133
  resource.values.each(&:delete)
@@ -1,17 +1,21 @@
1
1
  module Maitredee
2
2
  module Adapters
3
- class TestAdapter
3
+ class TestAdapter < BaseAdapter
4
+ # logs message published
4
5
  def publish(message)
5
6
  messages << message
6
7
  end
7
8
 
9
+ # returns all messages that have been published since last #reset
8
10
  def messages
9
11
  @messages ||= []
10
12
  end
11
13
 
14
+ # no-op
12
15
  def add_worker(subscriber_class)
13
16
  end
14
17
 
18
+ # resets messages logged
15
19
  def reset
16
20
  messages.clear
17
21
  end
@@ -1,12 +1,37 @@
1
1
  module Maitredee
2
+ ##
3
+ # Inherit from this class to easily publish messages:
4
+ #
5
+ # class RecipePublisher < Maitredee::Publisher
6
+ #
7
+ # def initialize(recipe)
8
+ # @recipe = recipe
9
+ # end
10
+ #
11
+ # def process
12
+ # # do some work
13
+ # end
14
+ # end
15
+ #
16
+ # Then in your Rails app, you can do this:
17
+ #
18
+ # RecipePublisher.call(1, 2, 3)
19
+ #
20
+ # Note that `call` is a class method, `process` is an instance method.
2
21
  class Publisher
3
22
  class << self
23
+ # call #process and return publishes messages
24
+ # @param args [] arguments passed to #initialize
4
25
  def call(*args)
5
26
  publisher = new(*args)
6
27
  publisher.process
7
28
  publisher.published_messages
8
29
  end
9
30
 
31
+ # set publish defaults
32
+ # @param topic_name [#to_s, nil]
33
+ # @param event_name [#to_s, nil]
34
+ # @param schema_name [#to_s, nil]
10
35
  def publish_defaults(topic_name: nil, event_name: nil, schema_name: nil)
11
36
  @publish_defaults = {
12
37
  topic_name: topic_name,
@@ -20,10 +45,18 @@ module Maitredee
20
45
  end
21
46
  end
22
47
 
48
+ # array of messages published in this instance
49
+ # @return [Array<PublisherMessage>]
23
50
  def published_messages
24
51
  @published_messages ||= []
25
52
  end
26
53
 
54
+ # publish a message with defaults
55
+ # @param topic_name [#to_s, nil]
56
+ # @param event_name [#to_s, nil]
57
+ # @param schema_name [#to_s, nil]
58
+ # @param primary_key [#to_s, nil]
59
+ # @param body [#to_json]
27
60
  def publish(topic_name: nil, event_name: nil, schema_name: nil, primary_key: nil, body:)
28
61
  defaults = self.class.get_publish_defaults
29
62
  published_messages << Maitredee.publish(
@@ -1,11 +1,28 @@
1
1
  require "shoryuken"
2
2
 
3
3
  module Maitredee
4
+ ##
5
+ # Inherit from this class to easily subscrive to messages:
6
+ #
7
+ # class RecipeSubscriber < Maitredee::Subscriber
8
+ # subscribe_to :recipes do
9
+ # event(:update) # by default this calls the event_name, #delete
10
+ # end
11
+ #
12
+ # def update
13
+ # # do some work
14
+ # end
15
+ # end
16
+ #
17
+ # If you want to process a message manually
18
+ #
19
+ # RecipePublisher.process()
20
+ #
21
+ # Note that `call` is a class method, `process` is an instance method.
4
22
  class Subscriber
5
23
  EventConfig = Struct.new(
6
24
  :action,
7
25
  :event_name,
8
- :minimum_schema,
9
26
  keyword_init: true
10
27
  )
11
28
 
@@ -16,25 +33,33 @@ module Maitredee
16
33
  @subscriber = subscriber
17
34
  end
18
35
 
19
- def event(event_name, to: nil, minimum_schema: nil)
36
+ # configure subscriber to listen to event_name
37
+ # @param event_name [nil, #to_s]
38
+ # @param to [#to_s] must be valid method name
39
+ def event(event_name, to: nil)
20
40
  if event_name.nil? && to.nil?
21
41
  raise ArgumentError, "event_name and to: cannot both be nil"
22
42
  end
23
43
 
44
+ if event_name.present? && /[@$"]/ =~ event_name.to_sym.inspect && to.nil?
45
+ raise ArgumentError, "'#{event_name}' is not a valid method name, you must set the 'to' parameter"
46
+ end
47
+
24
48
  event_config = EventConfig.new(
25
49
  event_name: event_name.to_s,
26
- action: (to || event_name).to_s,
27
- minimum_schema: minimum_schema
50
+ action: (to || event_name).to_s
28
51
  )
29
52
 
30
53
  subscriber.event_configs[event_config.event_name] = event_config
31
54
  end
32
55
 
33
- def default_event(to:, minimum_schema: nil)
56
+ # configure a default method to be called if not specifically configured to be listened to
57
+ # @param event_name [#to_s]
58
+ # @param to [#to_sym] must be valid method name
59
+ def default_event(to:)
34
60
  subscriber.event_configs.default = EventConfig.new(
35
61
  event_name: nil,
36
- action: to.to_s,
37
- minimum_schema: minimum_schema
62
+ action: to.to_s
38
63
  )
39
64
  end
40
65
  end
@@ -42,6 +67,30 @@ module Maitredee
42
67
  class << self
43
68
  attr_reader :topic_name
44
69
 
70
+ # configures Subscriber to which topic it should listen to and lets you configure events in the block
71
+ # @example subscribe to a topic
72
+ # class RecipeSubscriber < Maitredee::Subscriber
73
+ # subscribe_to :recipes do
74
+ # event(:delete) # by default this calls the event_name, #delete
75
+ # event(:update, to: :process) # events can be routed to different methods though
76
+ # event(nil, to: :process) # subscribe without event names
77
+ #
78
+ # default_event(to: :process) # this will default a catch all route
79
+ # end
80
+ #
81
+ # def delete
82
+ # # do some work
83
+ # end
84
+ #
85
+ # def process
86
+ # # do some work
87
+ # end
88
+ # end
89
+ #
90
+ # @see SubscriberProxy
91
+ # @param topic_name [#to_s]
92
+ # @param queue_name [#to_s] overide default generation from class name
93
+ # @param queue_resource_name [#to_s] overide default generation from queue_name and topic_name
45
94
  def subscribe_to(topic_name, queue_name: nil, queue_resource_name: nil, &block)
46
95
  @topic_name = topic_name
47
96
  @queue_name = queue_name if queue_name
@@ -57,18 +106,24 @@ module Maitredee
57
106
  Maitredee.register_subscriber(self)
58
107
  end
59
108
 
109
+ # @api private
60
110
  def event_configs
61
111
  @event_configs ||= {}
62
112
  end
63
113
 
114
+ # returns the queue_name set in .subscribe_to or is generated off the class name without `Subscriber`
64
115
  def queue_name
65
116
  @queue_name ||= name.chomp(Subscriber.name.demodulize).underscore.dasherize
66
117
  end
67
118
 
119
+ # Returns the resource name of the queue depending on the adapter
120
+ # @return [String]
68
121
  def queue_resource_name
69
122
  @queue_resource_name ||= Maitredee.queue_resource_name(topic_name, queue_name)
70
123
  end
71
124
 
125
+ # takes message and routes it based off SubscriberMessage#event_name
126
+ # @param message [SubscriberMessage]
72
127
  def process(message)
73
128
  event_config = event_configs[message.event_name.to_s]
74
129
  if event_config
@@ -77,8 +132,10 @@ module Maitredee
77
132
  end
78
133
  end
79
134
 
135
+ # @return [SubscriberMessage]
80
136
  attr_reader :message
81
137
 
138
+ # @param message [SubscriberMessage]
82
139
  def initialize(message)
83
140
  @message = message
84
141
  end
@@ -1,3 +1,3 @@
1
1
  module Maitredee
2
- VERSION = "0.8.2"
2
+ VERSION = "0.8.3"
3
3
  end
data/maitredee.gemspec CHANGED
@@ -32,6 +32,7 @@ Gem::Specification.new do |spec|
32
32
 
33
33
  spec.add_development_dependency "bundler", "~> 1.17"
34
34
  spec.add_development_dependency "dotenv"
35
+ spec.add_development_dependency "goodread"
35
36
  spec.add_development_dependency "pry"
36
37
  spec.add_development_dependency "pry-byebug"
37
38
  spec.add_development_dependency "rake", "~> 10.0"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: maitredee
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.2
4
+ version: 0.8.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Plated Devs
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-12-10 00:00:00.000000000 Z
11
+ date: 2018-12-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -122,6 +122,20 @@ dependencies:
122
122
  - - ">="
123
123
  - !ruby/object:Gem::Version
124
124
  version: '0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: goodread
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
125
139
  - !ruby/object:Gem::Dependency
126
140
  name: pry
127
141
  requirement: !ruby/object:Gem::Requirement
@@ -232,6 +246,7 @@ files:
232
246
  - ".gitignore"
233
247
  - ".rspec"
234
248
  - ".ruby-version"
249
+ - ".yardopts"
235
250
  - CODE_OF_CONDUCT.md
236
251
  - Gemfile
237
252
  - Gemfile.lock
@@ -243,6 +258,7 @@ files:
243
258
  - exe/maitredee
244
259
  - lib/maitredee.rb
245
260
  - lib/maitredee/active_job.rb
261
+ - lib/maitredee/adapters/base_adapter.rb
246
262
  - lib/maitredee/adapters/sns_sqs_adapter.rb
247
263
  - lib/maitredee/adapters/test_adapter.rb
248
264
  - lib/maitredee/cli/runner.rb
@@ -271,7 +287,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
271
287
  version: '0'
272
288
  requirements: []
273
289
  rubyforge_project:
274
- rubygems_version: 2.7.8
290
+ rubygems_version: 2.7.6
275
291
  signing_key:
276
292
  specification_version: 4
277
293
  summary: Opinionated pub/sub framework