outbox 0.0.1 → 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.
- data/.gitignore +1 -0
- data/README.md +83 -2
- data/lib/outbox.rb +19 -2
- data/lib/outbox/accessor.rb +71 -0
- data/lib/outbox/clients/base.rb +39 -0
- data/lib/outbox/clients/mail_client.rb +40 -0
- data/lib/outbox/clients/test_client.rb +20 -0
- data/lib/outbox/errors.rb +5 -0
- data/lib/outbox/message.rb +47 -0
- data/lib/outbox/message_clients.rb +70 -0
- data/lib/outbox/message_fields.rb +209 -0
- data/lib/outbox/message_types.rb +62 -0
- data/lib/outbox/messages/base.rb +46 -0
- data/lib/outbox/messages/email.rb +77 -0
- data/lib/outbox/version.rb +1 -1
- data/outbox.gemspec +3 -2
- data/spec/outbox/accessor_spec.rb +58 -0
- data/spec/outbox/clients/base_spec.rb +29 -0
- data/spec/outbox/clients/mail_client_spec.rb +43 -0
- data/spec/outbox/clients/test_client_spec.rb +26 -0
- data/spec/outbox/message_spec.rb +103 -0
- data/spec/outbox/messages/base_spec.rb +212 -0
- data/spec/outbox/messages/email_spec.rb +135 -0
- data/spec/outbox_spec.rb +0 -4
- data/spec/spec_helper.rb +9 -0
- metadata +48 -8
data/.gitignore
CHANGED
data/README.md
CHANGED
@@ -1,7 +1,10 @@
|
|
1
1
|
Outbox
|
2
2
|
======
|
3
3
|
|
4
|
-
|
4
|
+
[](http://badge.fury.io/rb/outbox)
|
5
|
+
|
6
|
+
Outbox is a factory for creating notifications in a variety of protocols, including: email, SMS, and push notifications. Each protocol is built as a generic interface where the actual delivery method or service can be configured independently of the message itself.
|
7
|
+
|
5
8
|
|
6
9
|
Installation
|
7
10
|
------------
|
@@ -24,10 +27,88 @@ Or install it yourself as:
|
|
24
27
|
$ gem install outbox
|
25
28
|
```
|
26
29
|
|
30
|
+
Support
|
31
|
+
-------
|
32
|
+
|
33
|
+
This gem is still in early development with plans to support email, SMS, and push notificaitons. As protocols and services are added, this support table will be updated:
|
34
|
+
|
35
|
+
### Email
|
36
|
+
|
37
|
+
| Service | Alias | Client |
|
38
|
+
|-------------------------------------------|---------|------------|
|
39
|
+
| [Mail gem](https://github.com/mikel/mail) | `:mail` | MailClient |
|
40
|
+
|
41
|
+
### SMS
|
42
|
+
|
43
|
+
TODO…
|
44
|
+
|
45
|
+
### Push
|
46
|
+
|
47
|
+
TODO…
|
48
|
+
|
27
49
|
Usage
|
28
50
|
-----
|
29
51
|
|
30
|
-
|
52
|
+
Outbox is inspired by [Mail's](https://github.com/mikel/mail) syntax for creating emails.
|
53
|
+
|
54
|
+
### Making a Message
|
55
|
+
|
56
|
+
An Outbox message is actually a factory for creating many different types of messages with the same **topic**. For example: a **topic** could be an event reminder in a calendar application. You want to send out essentially the same content (the reminder) as an email, SMS, and/or push notifications depending on user preferences:
|
57
|
+
|
58
|
+
``` ruby
|
59
|
+
message = Outbox::Message.new do
|
60
|
+
email do
|
61
|
+
from 'noreply@myapp.com'
|
62
|
+
subject 'You have an upcoming event!'
|
63
|
+
end
|
64
|
+
|
65
|
+
sms do
|
66
|
+
from '+15557654321'
|
67
|
+
end
|
68
|
+
|
69
|
+
ios_push do
|
70
|
+
badget '+1'
|
71
|
+
sound 'default'
|
72
|
+
end
|
73
|
+
|
74
|
+
body "Don't forget, you have an upcoming event on 8/15/2013."
|
75
|
+
end
|
76
|
+
|
77
|
+
# This will deliver the message to User's given contact points.
|
78
|
+
message.deliver email: 'user@gmail.com', sms: '+15551234567', ios_push: 'FE66489F304DC75B8D6E8200DFF8A456E8DAEACEC428B427E9518741C92C6660'
|
79
|
+
```
|
80
|
+
|
81
|
+
### Making an email
|
82
|
+
|
83
|
+
Making just an email is done just how you would using the [Mail gem](https://github.com/mikel/mail), so look there for in-depth examples. Here's a simple one to get you started:
|
84
|
+
|
85
|
+
``` ruby
|
86
|
+
email = Outbox::Messages::Email.new do
|
87
|
+
to 'user@gmail.com'
|
88
|
+
from 'noreply@myapp.com'
|
89
|
+
subject 'You have an upcoming event!'
|
90
|
+
|
91
|
+
text_part do
|
92
|
+
body "Don't forget, you have an upcoming event on 8/15/2013."
|
93
|
+
end
|
94
|
+
|
95
|
+
html_part do
|
96
|
+
body "<h1>Event Reminder</h1>..."
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
# Configure the client. If you use the MailClient, you can specify
|
101
|
+
# the actual delivery method:
|
102
|
+
email.client :mail, delivery_method: :smtp, smtp_settings: {}
|
103
|
+
|
104
|
+
# And deliver using the specified client
|
105
|
+
email.deliver
|
106
|
+
```
|
107
|
+
|
108
|
+
Configuration
|
109
|
+
-------------
|
110
|
+
|
111
|
+
TODO...
|
31
112
|
|
32
113
|
Contributing
|
33
114
|
------------
|
data/lib/outbox.rb
CHANGED
@@ -1,4 +1,21 @@
|
|
1
|
-
require 'outbox/version'
|
2
|
-
|
3
1
|
module Outbox
|
2
|
+
require 'outbox/errors'
|
3
|
+
require 'outbox/version'
|
4
|
+
|
5
|
+
autoload 'Accessor', 'outbox/accessor'
|
6
|
+
autoload 'Message', 'outbox/message'
|
7
|
+
autoload 'MessageClients', 'outbox/message_clients'
|
8
|
+
autoload 'MessageFields', 'outbox/message_fields'
|
9
|
+
autoload 'MessageTypes', 'outbox/message_types'
|
10
|
+
|
11
|
+
module Clients
|
12
|
+
autoload 'Base', 'outbox/clients/base'
|
13
|
+
autoload 'MailClient', 'outbox/clients/mail_client'
|
14
|
+
autoload 'TestClient', 'outbox/clients/test_client'
|
15
|
+
end
|
16
|
+
|
17
|
+
module Messages
|
18
|
+
autoload 'Base', 'outbox/messages/base'
|
19
|
+
autoload 'Email', 'outbox/messages/email'
|
20
|
+
end
|
4
21
|
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
module Outbox
|
2
|
+
# Accessor is a simple object for wrapping access to either a hash's keys
|
3
|
+
# or an object's properties. You can arbitrarily get/set either. Note that
|
4
|
+
# with hashes, the keys are symbolized and a new hash is created - so if you
|
5
|
+
# set properties you'll need to get the resulting hash from the #object
|
6
|
+
# method.
|
7
|
+
#
|
8
|
+
# Example:
|
9
|
+
#
|
10
|
+
# hash = { :a => 1, 'b' => 2 }
|
11
|
+
# hash_accessor = Outbox::Accessor.new(hash)
|
12
|
+
# hash_accessor[:a] #=> 1
|
13
|
+
# hash_accessor[:b] #=> 2
|
14
|
+
# hash_accessor[:c] #=> nil
|
15
|
+
# hash_accessor[:c] = 3
|
16
|
+
# hash_accessor.object[:c] #=> 3
|
17
|
+
# hash_accessor.object #=> { a: 1, b: 2, c: 3 }
|
18
|
+
#
|
19
|
+
# object = OpenStruct.new
|
20
|
+
# object.a = 1
|
21
|
+
# object.b = 2
|
22
|
+
# object_accessor = Outbox::Accessor.new(object)
|
23
|
+
# object_accessor[:a] #=> 1
|
24
|
+
# object_accessor[:b] #=> 2
|
25
|
+
# object_accessor[:c] #=> nil
|
26
|
+
# object_accessor[:c] = 3
|
27
|
+
# object_accessor.object.c #=> 3
|
28
|
+
class Accessor
|
29
|
+
attr_reader :object
|
30
|
+
|
31
|
+
def initialize(object)
|
32
|
+
if object.instance_of? Hash
|
33
|
+
@object = convert_keys(object)
|
34
|
+
else
|
35
|
+
@object = object
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def []=(key, value)
|
40
|
+
setter = "#{key}="
|
41
|
+
if @object.respond_to?(setter)
|
42
|
+
@object.public_send(setter, value)
|
43
|
+
elsif @object.respond_to? :[]=
|
44
|
+
@object[convert_key(key)] = value
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def [](key)
|
49
|
+
key = convert_key(key)
|
50
|
+
if @object.respond_to?(key)
|
51
|
+
@object.public_send(key)
|
52
|
+
elsif @object.respond_to? :[]
|
53
|
+
@object[key]
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
protected
|
58
|
+
|
59
|
+
def convert_keys(hash)
|
60
|
+
result = {}
|
61
|
+
hash.each_key do |key|
|
62
|
+
result[convert_key(key)] = hash[key]
|
63
|
+
end
|
64
|
+
result
|
65
|
+
end
|
66
|
+
|
67
|
+
def convert_key(key)
|
68
|
+
key.to_sym rescue key
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module Outbox
|
2
|
+
module Clients
|
3
|
+
class Base
|
4
|
+
attr_reader :settings
|
5
|
+
|
6
|
+
# Sets default settings for the client.
|
7
|
+
#
|
8
|
+
# MailClient.defaults delivery_method: :sendmail
|
9
|
+
# client = MailClient.new
|
10
|
+
# client.settings[:delivery_method] #=> :sendmail
|
11
|
+
def self.defaults(defaults = nil)
|
12
|
+
@defaults ||= {}
|
13
|
+
|
14
|
+
if defaults.nil?
|
15
|
+
@defaults
|
16
|
+
else
|
17
|
+
@defaults.merge!(defaults)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
# Creates a new client instance. Settings can be configured per
|
22
|
+
# instance by passing in a hash.
|
23
|
+
#
|
24
|
+
# client = MailClient.new delivery_method: :sendmail
|
25
|
+
# client.settings[:delivery_method] #=> :sendmail
|
26
|
+
def initialize(settings = nil)
|
27
|
+
@settings = self.class.defaults.dup
|
28
|
+
@settings.merge! settings if settings
|
29
|
+
end
|
30
|
+
|
31
|
+
# Delivers the given message.
|
32
|
+
#
|
33
|
+
# Subclasses must provide an implementation of this method.
|
34
|
+
def deliver(message)
|
35
|
+
raise NotImplementedError, 'Subclasses must implement a deliver method'
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module Outbox
|
2
|
+
module Clients
|
3
|
+
class MailClient < Base
|
4
|
+
defaults delivery_method: :smtp
|
5
|
+
|
6
|
+
# Returns the configured delivery method.
|
7
|
+
def delivery_method
|
8
|
+
settings[:delivery_method]
|
9
|
+
end
|
10
|
+
|
11
|
+
# Returns the configured delivery method settings. This will also check
|
12
|
+
# the Rails-style #{delivery_method}_settings key as well.
|
13
|
+
#
|
14
|
+
# client = Outbox::Clients::MailClient.new delivery_method: :sendmail, delivery_method_settings: {
|
15
|
+
# location: '/usr/bin/sendmail'
|
16
|
+
# }
|
17
|
+
# client.delivery_method_settings #=> { location: '/usr/bin/sendmail' }
|
18
|
+
#
|
19
|
+
# client = Outbox::Clients::MailClient.new delivery_method: :sendmail, sendmail_settings: {
|
20
|
+
# location: '/usr/bin/sendmail'
|
21
|
+
# }
|
22
|
+
# client.delivery_method_settings #=> { location: '/usr/bin/sendmail' }
|
23
|
+
def delivery_method_settings
|
24
|
+
settings[:delivery_method_settings] || settings[:"#{delivery_method}_settings"]
|
25
|
+
end
|
26
|
+
|
27
|
+
def deliver(email)
|
28
|
+
message = create_message_from_email(email)
|
29
|
+
message.delivery_method(delivery_method, delivery_method_settings)
|
30
|
+
message.deliver
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def create_message_from_email(email)
|
36
|
+
email.message_object.dup
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Outbox
|
2
|
+
module Clients
|
3
|
+
# The TestClient is a bare bones client that does nothing. It is useful
|
4
|
+
# when you are testing.
|
5
|
+
#
|
6
|
+
# It also provides a template of the minimum methods required to make
|
7
|
+
# a custom client.
|
8
|
+
class TestClient < Base
|
9
|
+
# Provides a store of all the message sent with the TestClient so you
|
10
|
+
# can check them.
|
11
|
+
def self.deliveries
|
12
|
+
@@deliveries ||= []
|
13
|
+
end
|
14
|
+
|
15
|
+
def deliver(message)
|
16
|
+
self.class.deliveries << message
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module Outbox
|
2
|
+
class Message
|
3
|
+
include MessageTypes
|
4
|
+
|
5
|
+
register_message_type :email, Outbox::Messages::Email
|
6
|
+
|
7
|
+
# Make a new message. Every message can be created using a hash,
|
8
|
+
# block, or direct assignment.
|
9
|
+
#
|
10
|
+
# message = Message.new do
|
11
|
+
# email do
|
12
|
+
# subject 'Subject'
|
13
|
+
# end
|
14
|
+
# end
|
15
|
+
# message = Message.new email: { subject: 'Subject' }
|
16
|
+
# message = Message.new
|
17
|
+
# message.email = Email.new subject: 'Subject'
|
18
|
+
def initialize(message_type_values = nil, &block)
|
19
|
+
if block_given?
|
20
|
+
instance_eval(&block)
|
21
|
+
else
|
22
|
+
assign_message_type_values(message_type_values) unless message_type_values.nil?
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# Delivers all of the messages to the given 'audience'. An 'audience' object
|
27
|
+
# can be a hash or an object that responds to the current message types. Only
|
28
|
+
# the message types specified in the 'audience' object will be sent to.
|
29
|
+
#
|
30
|
+
# message.deliver email: 'hello@example.com', sms: '+15555555555'
|
31
|
+
# audience = OpenStruct.new
|
32
|
+
# audience.email = 'hello@example.com'
|
33
|
+
# audience.sms = '+15555555555'
|
34
|
+
# message.deliver(audience)
|
35
|
+
def deliver(audience)
|
36
|
+
audience = Outbox::Accessor.new(audience)
|
37
|
+
|
38
|
+
self.class.message_types.each_key do |message_type|
|
39
|
+
message = self.public_send(message_type)
|
40
|
+
next if message.nil?
|
41
|
+
|
42
|
+
recipient = audience[message_type]
|
43
|
+
message.deliver(recipient) if recipient
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
module Outbox
|
2
|
+
module MessageClients
|
3
|
+
def self.included(base)
|
4
|
+
base.extend ClassMethods
|
5
|
+
end
|
6
|
+
|
7
|
+
module ClassMethods
|
8
|
+
# Returns the default client for the message type.
|
9
|
+
#
|
10
|
+
# Email.default_client #=> #<Outbox::Clients::Mail>
|
11
|
+
#
|
12
|
+
# Also allows you to set the default client using an alias, with optoins.
|
13
|
+
#
|
14
|
+
# Email.default_client :test, option: 'foo'
|
15
|
+
# Email.default_client #=> #<Outbox::Clients::TestClient>
|
16
|
+
def default_client(client = nil, options = nil)
|
17
|
+
if client.nil?
|
18
|
+
@default_client
|
19
|
+
else
|
20
|
+
@default_client = get_client(client, options)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# Registers a client class with an alias.
|
25
|
+
#
|
26
|
+
# Email.register_client_alias :mandrill, MandrillClient
|
27
|
+
# Email.default_client :mandrill, mandrill_option: 'foo'
|
28
|
+
def register_client_alias(name, client)
|
29
|
+
registered_client_aliases[name.to_sym] = client
|
30
|
+
end
|
31
|
+
|
32
|
+
# Returns a hash of client aliases, where the key is the alias and
|
33
|
+
# the value is client class.
|
34
|
+
def registered_client_aliases
|
35
|
+
@registered_client_aliases ||= { test: Outbox::Clients::TestClient }
|
36
|
+
end
|
37
|
+
|
38
|
+
protected
|
39
|
+
|
40
|
+
def get_client(client, options = nil)
|
41
|
+
case client
|
42
|
+
when Symbol, String
|
43
|
+
client = registered_client_aliases[client.to_sym]
|
44
|
+
end
|
45
|
+
|
46
|
+
if client.instance_of?(Class)
|
47
|
+
client.new(options)
|
48
|
+
else
|
49
|
+
client
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
# Returns the message's client.
|
55
|
+
#
|
56
|
+
# message.client #=> #<Outbox::Clients::Mail>
|
57
|
+
#
|
58
|
+
# Also allows you set the instance's client using an alias, with options.
|
59
|
+
#
|
60
|
+
# message.client :test, option: 'foo'
|
61
|
+
# message.client #=> #<Outbox::Clients::TestClient>
|
62
|
+
def client(client = nil, options = nil)
|
63
|
+
if client.nil?
|
64
|
+
@client
|
65
|
+
else
|
66
|
+
@client = self.class.send(:get_client, client, options)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,209 @@
|
|
1
|
+
module Outbox
|
2
|
+
module MessageFields
|
3
|
+
def self.included(base)
|
4
|
+
base.extend ClassMethods
|
5
|
+
end
|
6
|
+
|
7
|
+
module ClassMethods
|
8
|
+
# Sets default values for defined fields.
|
9
|
+
#
|
10
|
+
# Email.defaults from: 'bob@example.com'
|
11
|
+
# message = Email.new
|
12
|
+
# message.from #=> 'bob@example.com'
|
13
|
+
def defaults(defaults = nil)
|
14
|
+
@defaults ||= {}
|
15
|
+
|
16
|
+
if defaults.nil?
|
17
|
+
@defaults
|
18
|
+
else
|
19
|
+
@defaults.merge!(defaults)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
# Returns the defined fields for this message type.
|
24
|
+
#
|
25
|
+
# class SomeMessageType < Outbox::Messages::Base
|
26
|
+
# field :to
|
27
|
+
# field :from
|
28
|
+
# end
|
29
|
+
#
|
30
|
+
# SomeMessageType.fields #=> [:to, :from]
|
31
|
+
#
|
32
|
+
# Also allows you to define multiple fields at once.
|
33
|
+
#
|
34
|
+
# class SomeMessageType < Outbox::Messages::Base
|
35
|
+
# fields :to, :from, required: true
|
36
|
+
# end
|
37
|
+
#
|
38
|
+
# message = SomeMessageType.new do
|
39
|
+
# to 'Bob'
|
40
|
+
# from 'John'
|
41
|
+
# end
|
42
|
+
# message.to #=> 'Bob'
|
43
|
+
# message.from #=> 'John'
|
44
|
+
# message.from = nil
|
45
|
+
# message.validate_fields #=> raises Outbox::MissingRequiredFieldError
|
46
|
+
def fields(*names)
|
47
|
+
if names.empty?
|
48
|
+
@fields ||= []
|
49
|
+
else
|
50
|
+
options = names.last.is_a?(Hash) ? names.pop : {}
|
51
|
+
names.flatten.each do |name|
|
52
|
+
field(name, options)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
# Defines a 'field' which is a point of data for this type of data.
|
58
|
+
# Optionally you can set it to be required, or wether or not you want
|
59
|
+
# accessors defined for you. If you define your own accessors, make
|
60
|
+
# sure the reader also accepts a value that can be set, so it'll work
|
61
|
+
# with the block definition.
|
62
|
+
#
|
63
|
+
# class SomeMessageType < Outbox::Messages::base
|
64
|
+
# field :to, required: true
|
65
|
+
# field :body, accessor: false
|
66
|
+
#
|
67
|
+
# def body(value = nil)
|
68
|
+
# value ? self.body = value : @body
|
69
|
+
# end
|
70
|
+
#
|
71
|
+
# def body=(value)
|
72
|
+
# @body = parse_body(value)
|
73
|
+
# end
|
74
|
+
# end
|
75
|
+
#
|
76
|
+
# message = SomeMessageType.new do
|
77
|
+
# to 'Bob'
|
78
|
+
# end
|
79
|
+
# message.to #=> 'Bob'
|
80
|
+
# message.to = 'John'
|
81
|
+
# message.to #=> 'John'
|
82
|
+
# message.to = nil
|
83
|
+
# message.validate_fields #=> raises Outbox::MissingRequiredFieldError
|
84
|
+
def field(name, options = {})
|
85
|
+
name = name.to_sym
|
86
|
+
options = Outbox::Accessor.new(options)
|
87
|
+
|
88
|
+
fields.push(name)
|
89
|
+
required_fields.push(name) if options[:required]
|
90
|
+
|
91
|
+
unless options[:accessor] == false
|
92
|
+
define_field_reader(name) unless options[:reader] == false
|
93
|
+
define_field_writer(name) unless options[:writer] == false
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
# Returns an array of the required fields for a message type.
|
98
|
+
#
|
99
|
+
# class SomeMessageType < Outbox::Messages::Base
|
100
|
+
# field :to, required: true
|
101
|
+
# fields :from, :subject
|
102
|
+
# end
|
103
|
+
# SomeMessageType.required_fields #=> [:to]
|
104
|
+
#
|
105
|
+
# Also can be used an alias for defining fields that are required.
|
106
|
+
#
|
107
|
+
# class SomeMessageType < Outbox::Messages::Base
|
108
|
+
# required_fields :to, :from
|
109
|
+
# end
|
110
|
+
# SomeMessageType.required_fields #=> [:to, :from]
|
111
|
+
def required_fields(*names)
|
112
|
+
if names.empty?
|
113
|
+
@required_fields ||= []
|
114
|
+
else
|
115
|
+
options = names.last.is_a?(Hash) ? names.pop : {}
|
116
|
+
options[:required] = true
|
117
|
+
names << options
|
118
|
+
fields(*names)
|
119
|
+
end
|
120
|
+
end
|
121
|
+
alias :required_field :required_fields
|
122
|
+
|
123
|
+
protected
|
124
|
+
|
125
|
+
def define_field_reader(name)
|
126
|
+
define_method(name) do |value = nil|
|
127
|
+
if value.nil?
|
128
|
+
@fields[name]
|
129
|
+
else
|
130
|
+
@fields[name] = value
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
def define_field_writer(name)
|
136
|
+
define_method("#{name}=") do |value|
|
137
|
+
@fields[name] = value
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
# Read an arbitrary field.
|
143
|
+
#
|
144
|
+
# Example:
|
145
|
+
#
|
146
|
+
# message['foo'] = '1234'
|
147
|
+
# message['foo'] #=> '1234'
|
148
|
+
def [](name)
|
149
|
+
@fields[name.to_sym]
|
150
|
+
end
|
151
|
+
|
152
|
+
# Add an arbitray field.
|
153
|
+
#
|
154
|
+
# Example:
|
155
|
+
#
|
156
|
+
# message['foo'] = '1234'
|
157
|
+
# message['foo'] #=> '1234'
|
158
|
+
def []=(name, value)
|
159
|
+
@fields[name.to_sym] = value
|
160
|
+
end
|
161
|
+
|
162
|
+
# Returns a hash of the defined fields.
|
163
|
+
#
|
164
|
+
# class SomeMessageType < Outbox::Messages::Base
|
165
|
+
# fields :to, :from
|
166
|
+
# end
|
167
|
+
# message = SomeMessageType.new to: 'Bob'
|
168
|
+
# message.from 'John'
|
169
|
+
# message.fields #=> { to: 'Bob', from: 'John' }
|
170
|
+
#
|
171
|
+
# Also allows you to set fields if you pass in a hash.
|
172
|
+
#
|
173
|
+
# message.fields to: 'Bob', from: 'Sally'
|
174
|
+
# message.fields #=> { to: 'Bob', from: 'Sally' }
|
175
|
+
def fields(new_fields = nil)
|
176
|
+
if new_fields.nil?
|
177
|
+
fields = {}
|
178
|
+
self.class.fields.each do |field|
|
179
|
+
fields[field] = self.public_send(field)
|
180
|
+
end
|
181
|
+
fields
|
182
|
+
else
|
183
|
+
self.fields = new_fields
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
# Assigns the values of the given hash.
|
188
|
+
#
|
189
|
+
# message.to = 'Bob'
|
190
|
+
# message.fields = { from: 'Sally' }
|
191
|
+
# message.fields #=> { to: 'Bob', from: 'Sally' }
|
192
|
+
def fields=(new_fields)
|
193
|
+
new_fields.each do |field, value|
|
194
|
+
self.public_send(field, value) if self.respond_to?(field)
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
# Checks the current values of the fields and raises errors for any
|
199
|
+
# validation issues.
|
200
|
+
def validate_fields
|
201
|
+
self.class.required_fields.each do |field|
|
202
|
+
value = self.public_send(field)
|
203
|
+
if value.nil? || value.respond_to?(:empty?) && value.empty?
|
204
|
+
raise Outbox::MissingRequiredFieldError.new("Missing required field: #{field}")
|
205
|
+
end
|
206
|
+
end
|
207
|
+
end
|
208
|
+
end
|
209
|
+
end
|