noticed 1.1.0 → 1.2.4

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: b8ce628657c8b6011616fbcf075869fe902ad33f19569acadf88e52aef89fb79
4
- data.tar.gz: f92330969818566ce0d4080341f19631be41fd5bb4c45f94dfb3ab5714c3c663
3
+ metadata.gz: 2936d217d3d881874888d8dd68280ecc9888f41fc1edf3f195e713bf863d2233
4
+ data.tar.gz: a73fba77cb4eebead7c3d343c501cbe7ca5b19db5a24b11b6d33e6674c41a1f9
5
5
  SHA512:
6
- metadata.gz: 8945414df8ed4cdf89bbf654171e686b8c655ae91542177207f134052d0d09794df146192694775f9e755a3b0a65fafbe180130d41590f186b53837c9f114961
7
- data.tar.gz: c78d5048f9fb95b6982dc44edd7fa03d8f2cf8cf093884d059668fb2aed3258d9f2992b84b2843ac61e39d3e3ce42818fc48c583520d2097cb89bf8260b1aa30
6
+ metadata.gz: 67f055f8a05d3418caf3c21c2a3938341705752e6154284bbe596ac31563fd715c7d29d5651f690ce310433d762b7dca05e99ec8326b93d477a85db91cddfd10
7
+ data.tar.gz: 3fbaf13b4dd6f7f3fa9f50a52849ef0ff112268c730cdca202f2e421fd7f66cdc797147c549911addb2161ed2c40d7738d6d85e5d420427f46658eaef5b13b81
data/README.md CHANGED
@@ -1,37 +1,78 @@
1
- # Noticed - Notifications for your Ruby on Rails app.
1
+ <p align="center">
2
+ <h1>Noticed</h1>
3
+ </p>
2
4
 
3
- [![Build Status](https://github.com/excid3/noticed/workflows/Tests/badge.svg)](https://github.com/excid3/noticed/actions)
5
+ ### 🎉 Notifications for your Ruby on Rails app.
6
+
7
+ [![Build Status](https://github.com/excid3/noticed/workflows/Tests/badge.svg)](https://github.com/excid3/noticed/actions) [![Gem Version](https://badge.fury.io/rb/noticed.svg)](https://badge.fury.io/rb/noticed)
4
8
 
5
9
  Currently, we support these notification delivery methods out of the box:
6
10
 
7
11
  * Database
8
12
  * Email
9
- * Websocket (realtime)
13
+ * ActionCable channels
14
+ * Slack
10
15
  * Twilio (SMS)
11
16
  * Vonage / Nexmo (SMS)
12
17
 
13
18
  And you can easily add new notification types for any other delivery methods.
14
19
 
15
- ## Installation
16
- Add this line to your application's Gemfile:
20
+ ## 🎬 Screencast
21
+
22
+ <div style="width:50%">
23
+ <a href="https://www.youtube.com/watch?v=Scffi4otlFc"><img src="https://i.imgur.com/UvVKWwD.png" title="How to add Notifications to Rails with Noticed" /></a>
24
+ </div>
25
+
26
+ [Watch Screencast](https://www.youtube.com/watch?v=Scffi4otlFc)
27
+
28
+ ## 🚀 Installation
29
+ Run the following command to add Noticed to your Gemfile
17
30
 
18
31
  ```ruby
19
- gem 'noticed'
32
+ bundle add "noticed"
20
33
  ```
21
34
 
22
- And then execute:
23
- ```bash
24
- $ bundle
35
+ To save notifications to your database, use the following command to generate a Notification model.
36
+
37
+ ```ruby
38
+ rails generate noticed:model
25
39
  ```
26
40
 
27
- Or install it yourself as:
28
- ```bash
29
- $ gem install noticed
41
+ This will generate a Notification model and instructions for associating User models with the notifications table.
42
+
43
+ ## 📝 Usage
44
+
45
+ To generate a notification object, simply run:
46
+
47
+ `rails generate noticed:notification CommentNotification`
48
+
49
+ #### Sending Notifications
50
+
51
+ To send a notification to a user:
52
+
53
+ ```ruby
54
+ # Instantiate a new notification
55
+ notification = CommentNotification.with(comment: @comment)
56
+
57
+ # Deliver notification in background job
58
+ notification.deliver_later(@comment.post.author)
59
+
60
+ # Deliver notification immediately
61
+ notification.deliver(@comment.post.author)
62
+
63
+ # Deliver notification to multiple recipients
64
+ notification.deliver_later(User.all)
30
65
  ```
31
66
 
32
- ## Usage
67
+ This will instantiate a new notification with the `comment` stored in the notification's params.
33
68
 
34
- You can define a Notification as a class that inherits from Noticed::Base. To add delivery methods, simply `include` the module for the delivery methods you would like to use.
69
+ Each delivery method is able to transform this metadata that's best for the format. For example, the database may simply store the comment so it can be linked when rendering in the navbar. The websocket mechanism may transform this into a browser notification or insert it into the navbar.
70
+
71
+ #### Notification Objects
72
+
73
+ Notifications inherit from `Noticed::Base`. This provides all their functionality and allows them to be delivered.
74
+
75
+ To add delivery methods, simply `include` the module for the delivery methods you would like to use.
35
76
 
36
77
  ```ruby
37
78
  class CommentNotification < Noticed::Base
@@ -39,36 +80,38 @@ class CommentNotification < Noticed::Base
39
80
  deliver_by :action_cable
40
81
  deliver_by :email, if: :email_notifications?
41
82
 
83
+ # I18n helpers
84
+ def message
85
+ t(".message")
86
+ end
87
+
88
+ # URL helpers are accessible in notifications
89
+ def url
90
+ post_path(params[:post])
91
+ end
92
+
42
93
  def email_notifications?
43
94
  !!recipient.preferences[:email]
44
95
  end
45
-
96
+
46
97
  after_deliver do
47
98
  # Anything you want
48
99
  end
49
100
  end
50
101
  ```
51
102
 
52
- To send a notification to a user:
53
-
54
- ```ruby
55
- notification = CommentNotification.with(comment: @comment.to_gid)
56
-
57
- # Deliver notification in background job
58
- notification.deliver_later(@comment.post.author)
103
+ **Shared Options**
59
104
 
60
- # Deliver notification immediately
61
- notification.deliver(@comment.post.author)
62
- ```
105
+ * `if: :method_name` - Calls `method_name`and cancels delivery method if `false` is returned
106
+ * `unless: :method_name` - Calls `method_name`and cancels delivery method if `true` is returned
63
107
 
64
- This will instantiate a new notification with the `comment` global ID stored in the metadata.
108
+ ##### Helper Methods
65
109
 
66
- Each delivery method is able to transfrom this metadata that's best for the format. For example, the database may simply store the comment so it can be linked when rendering in the navbar. The websocket mechanism may transform this into a browser notification or insert it into the navbar.
110
+ You can define helper methods inside your Notification object to make it easier to render.
67
111
 
68
- **Shared Options**
112
+ ##### URL Helpers
69
113
 
70
- * `if: :method_name` - Calls `method_name`and cancels delivery method if `false` is returned
71
- * `unless: :method_name` - Calls `method_name`and cancels delivery method if `true` is returned
114
+ Rails url helpers are included in notification classes by default so you have full access to them just like you would in your controllers and views.
72
115
 
73
116
  **Callbacks**
74
117
 
@@ -78,11 +121,11 @@ Like ActiveRecord, notifications have several different types of callbacks.
78
121
  class CommentNotification < Noticed::Base
79
122
  deliver_by :database
80
123
  deliver_by :email
81
-
124
+
82
125
  # Callbacks for the entire delivery
83
126
  before_deliver :whatever
84
127
  around_deliver :whatever
85
- after_deliver :whatever
128
+ after_deliver :whatever
86
129
 
87
130
  # Callbacks for each delivery method
88
131
  before_database :whatever
@@ -99,9 +142,33 @@ When using `deliver_later` callbacks will be run around queuing the delivery met
99
142
 
100
143
  Defining custom delivery methods allows you to add callbacks that run inside the background job as each individual delivery is executed. See the Custom Delivery Methods section for more information.
101
144
 
102
- ## Delivery Methods
145
+ ##### Translations
146
+
147
+ We've added `translate` and `t` helpers like Rails has to provide an easy way of scoping translations. If the key starts with a period, it will automatically scope the key under `notifications` and the underscored name of the notification class it is used in.
148
+
149
+ For example:
150
+
151
+ `t(".message")` looks up `en.notifications.new_comment.message`
103
152
 
104
- The delivery methods are designed to be overriden so that you can customi1ze the notification for each medium.
153
+ ##### User Preferences
154
+
155
+ You can use the `if:` and `unless: ` options on your delivery methods to check the user's preferences and skip processing if they have disabled that type of notification.
156
+
157
+ For example:
158
+
159
+ ```ruby
160
+ class CommentNotification < Noticed::Base
161
+ deliver_by :email, if: :email_notifications?
162
+
163
+ def email_notifications?
164
+ recipient.email_notifications?
165
+ end
166
+ end
167
+ ```
168
+
169
+ ## 🚛 Delivery Methods
170
+
171
+ The delivery methods are designed to be modular so you can customize the way each type gets delivered.
105
172
 
106
173
  For example, emails will require a subject, body, and email address while an SMS requires a phone number and simple message. You can define the formats for each of these in your Notification and the delivery method will handle the processing of it.
107
174
 
@@ -113,6 +180,16 @@ Writes notification to the database.
113
180
 
114
181
  **Note:** Database notifications are special in that they will run before the other delivery methods. We do this so you can reference the database record ID in other delivery methods.
115
182
 
183
+ ##### Options
184
+
185
+ * `association` - *Optional*
186
+
187
+ The name of the database association to use. Defaults to `:notifications`
188
+
189
+ * `format: :format_for_database` - *Optional*
190
+
191
+ Use a custom method to define the attributes saved to the database
192
+
116
193
  ### Email
117
194
 
118
195
  Sends an email notification. Emails will always be sent with `deliver_later`
@@ -129,6 +206,10 @@ Sends an email notification. Emails will always be sent with `deliver_later`
129
206
 
130
207
  Used to customize the method on the mailer that is called
131
208
 
209
+ * `format: :format_for_email` - *Optional*
210
+
211
+ Use a custom method to define the params sent to the mailer. `recipient` will be merged into the params.
212
+
132
213
  ### ActionCable
133
214
 
134
215
  Sends a notification to the browser via websockets (ActionCable channel by default).
@@ -201,7 +282,7 @@ Sends an SMS notification via Twilio.
201
282
 
202
283
  ### Vonage SMS
203
284
 
204
- Sends an SMS notification vai Vonage / Nexmo.
285
+ Sends an SMS notification via Vonage / Nexmo.
205
286
 
206
287
  `deliver_by :vonage`
207
288
 
@@ -228,23 +309,7 @@ Sends an SMS notification vai Vonage / Nexmo.
228
309
  }
229
310
  ```
230
311
 
231
- ### User Preferences
232
-
233
- Each delivery method implements a `deliver_with_#{name}` method that receives the recipient as the first argument. You can override this method to check the user's preferences and skip processing if they have disabled that type of notification.
234
-
235
- For example:
236
-
237
- ```ruby
238
- class CommentNotification < Noticed::Base
239
- deliver_by :email, if: :email_notifications?
240
-
241
- def email_notifications?
242
- recipient.email_notifications?
243
- end
244
- end
245
- ```
246
-
247
- ### Custom Delivery Methods
312
+ ### 🚚 Custom Delivery Methods
248
313
 
249
314
  You can define a custom delivery method easily by adding a `deliver_by` line with a unique name and class option. The class will be instantiated and should inherit from `Noticed::DeliveryMethods::Base`.
250
315
 
@@ -297,8 +362,48 @@ For Rails 6.0 and earlier, you must pass strings of the class names in the `deli
297
362
 
298
363
  We recommend the Rails 6.0 compatible options to prevent confusion.
299
364
 
300
- ## Contributing
301
- Contribution directions go here.
365
+ ### 📦 Database Model
366
+
367
+ The Notification database model includes several helpful features to make working with database notifications easier.
368
+
369
+ #### Class methods
370
+
371
+ Sorting notifications by newest first:
372
+
373
+ ```ruby
374
+ user.notifications.newest_first
375
+ ```
376
+
377
+ Marking all notifications as read:
378
+
379
+ ```ruby
380
+ user.notifications.mark_as_read!
381
+ ```
382
+
383
+ #### Instance methods
384
+
385
+ Convert back into a Noticed notification object:
386
+
387
+ ```ruby
388
+ @notification.to_notification
389
+ ```
390
+
391
+ Mark notification as read:
392
+
393
+ ```ruby
394
+ @notification.mark_as_read!
395
+ ```
396
+
397
+ Check if read / unread:
398
+
399
+ ```ruby
400
+ @notification.read?
401
+ @notification.unread?
402
+ ```
403
+
404
+ ## 🙏 Contributing
405
+
406
+ This project uses [Standard](https://github.com/testdouble/standard) for formatting Ruby code. Please make sure to run `standardrb` before submitting pull requests.
302
407
 
303
- ## License
408
+ ## 📝 License
304
409
  The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rails/generators/named_base"
4
+
5
+ module Noticed
6
+ module Generators
7
+ class ModelGenerator < Rails::Generators::NamedBase
8
+ include Rails::Generators::ResourceHelpers
9
+
10
+ source_root File.expand_path("../templates", __FILE__)
11
+
12
+ desc "Generates a Notification model for storing notifications."
13
+
14
+ argument :name, type: :string, default: "Notification", banner: "Notification"
15
+ argument :attributes, type: :array, default: [], banner: "field:type field:type"
16
+
17
+ def generate_notification
18
+ generate :model, name, "recipient:references{polymorphic}", "type", "params:text", "read_at:datetime", *attributes
19
+ end
20
+
21
+ def add_noticed_model
22
+ inject_into_class model_path, class_name, " include Noticed::Model\n"
23
+ end
24
+
25
+ def done
26
+ readme "README" if behavior == :invoke
27
+ end
28
+
29
+ private
30
+
31
+ def model_path
32
+ @model_path ||= File.join("app", "models", "#{file_path}.rb")
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rails/generators/named_base"
4
+
5
+ module Noticed
6
+ module Generators
7
+ class NotificationGenerator < Rails::Generators::NamedBase
8
+ include Rails::Generators::ResourceHelpers
9
+
10
+ source_root File.expand_path("../templates", __FILE__)
11
+
12
+ desc "Generates a notification with the given NAME."
13
+
14
+ def generate_notification
15
+ template "notification.rb", "app/notifications/#{singular_name}.rb"
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,7 @@
1
+
2
+ 🚚 Your notifications database model has been generated!
3
+
4
+ Next steps:
5
+ 1. Run "rails db:migrate"
6
+ 2. Add "has_many :notifications, as: :recipient" to your User model(s).
7
+ 3. Generate notifications with "rails g noticed:notification"
@@ -0,0 +1,27 @@
1
+ # To deliver this notification:
2
+ #
3
+ # <%= class_name %>.with(post: @post).deliver_later(current_user)
4
+ # <%= class_name %>.with(post: @post).deliver(current_user)
5
+
6
+ class <%= class_name %> < Noticed::Base
7
+ # Add your delivery methods
8
+ #
9
+ # deliver_by :database
10
+ # deliver_by :email, mailer: "UserMailer"
11
+ # deliver_by :slack
12
+ # deliver_by :custom, class: "MyDeliveryMethod"
13
+
14
+ # Add required params
15
+ #
16
+ # param :post
17
+
18
+ # Define helper methods to make rendering easier.
19
+ #
20
+ # def message
21
+ # t(".message")
22
+ # end
23
+ #
24
+ # def url
25
+ # post_path(params[:post])
26
+ # end
27
+ end
@@ -1,9 +1,12 @@
1
+ require "active_job/arguments"
1
2
  require "http"
2
3
  require "noticed/engine"
3
4
 
4
5
  module Noticed
5
6
  autoload :Base, "noticed/base"
6
7
  autoload :Coder, "noticed/coder"
8
+ autoload :Model, "noticed/model"
9
+ autoload :Translation, "noticed/translation"
7
10
 
8
11
  module DeliveryMethods
9
12
  autoload :Base, "noticed/delivery_methods/base"
@@ -1,12 +1,16 @@
1
1
  module Noticed
2
2
  class Base
3
+ include Translation
4
+ include Rails.application.routes.url_helpers
5
+
3
6
  extend ActiveModel::Callbacks
4
7
  define_model_callbacks :deliver
5
8
 
6
9
  class_attribute :delivery_methods, instance_writer: false, default: []
7
10
  class_attribute :param_names, instance_writer: false, default: []
8
11
 
9
- attr_accessor :record
12
+ # Gives notifications access to the record and recipient when formatting for delivery
13
+ attr_accessor :record, :recipient
10
14
 
11
15
  class << self
12
16
  def deliver_by(name, options = {})
@@ -34,14 +38,24 @@ module Noticed
34
38
  @params = params
35
39
  end
36
40
 
37
- def deliver(recipient)
41
+ def deliver(recipients)
38
42
  validate!
39
- run_delivery(recipient, enqueue: false)
43
+
44
+ run_callbacks :deliver do
45
+ Array.wrap(recipients).uniq.each do |recipient|
46
+ run_delivery(recipient, enqueue: false)
47
+ end
48
+ end
40
49
  end
41
50
 
42
- def deliver_later(recipient)
51
+ def deliver_later(recipients)
43
52
  validate!
44
- run_delivery(recipient, enqueue: true)
53
+
54
+ run_callbacks :deliver do
55
+ Array.wrap(recipients).uniq.each do |recipient|
56
+ run_delivery(recipient, enqueue: true)
57
+ end
58
+ end
45
59
  end
46
60
 
47
61
  def params
@@ -52,18 +66,16 @@ module Noticed
52
66
 
53
67
  # Runs all delivery methods for a notification
54
68
  def run_delivery(recipient, enqueue: true)
55
- run_callbacks :deliver do
56
- delivery_methods = self.class.delivery_methods.dup
69
+ delivery_methods = self.class.delivery_methods.dup
57
70
 
58
- # Run database delivery inline first if it exists so other methods have access to the record
59
- if (index = delivery_methods.find_index { |m| m[:name] == :database })
60
- delivery_method = delivery_methods.delete_at(index)
61
- @record = run_delivery_method(delivery_method, recipient: recipient, enqueue: false)
62
- end
71
+ # Run database delivery inline first if it exists so other methods have access to the record
72
+ if (index = delivery_methods.find_index { |m| m[:name] == :database })
73
+ delivery_method = delivery_methods.delete_at(index)
74
+ @record = run_delivery_method(delivery_method, recipient: recipient, enqueue: false)
75
+ end
63
76
 
64
- delivery_methods.each do |delivery_method|
65
- run_delivery_method(delivery_method, recipient: recipient, enqueue: enqueue)
66
- end
77
+ delivery_methods.each do |delivery_method|
78
+ run_delivery_method(delivery_method, recipient: recipient, enqueue: enqueue)
67
79
  end
68
80
  end
69
81
 
@@ -4,15 +4,17 @@ module Noticed
4
4
  extend ActiveModel::Callbacks
5
5
  define_model_callbacks :deliver
6
6
 
7
- attr_reader :notification, :options, :recipient
7
+ attr_reader :notification, :options, :recipient, :record
8
8
 
9
9
  def perform(notification_class:, options:, params:, recipient:, record:)
10
10
  @notification = notification_class.constantize.new(params)
11
11
  @options = options
12
12
  @recipient = recipient
13
+ @record = record
13
14
 
14
- # Keep track of the database record for rendering
15
+ # Make notification aware of database record and recipient during delivery
15
16
  @notification.record = record
17
+ @notification.recipient = recipient
16
18
 
17
19
  run_callbacks :deliver do
18
20
  deliver
@@ -3,11 +3,15 @@ module Noticed
3
3
  class Database < Base
4
4
  # Must return the database record
5
5
  def deliver
6
- recipient.notifications.create(attributes)
6
+ recipient.send(association_name).create!(attributes)
7
7
  end
8
8
 
9
9
  private
10
10
 
11
+ def association_name
12
+ options[:association] || :notifications
13
+ end
14
+
11
15
  def attributes
12
16
  if (method = options[:format])
13
17
  notification.send(method)
@@ -2,7 +2,7 @@ module Noticed
2
2
  module DeliveryMethods
3
3
  class Email < Base
4
4
  def deliver
5
- mailer.with(notification.params).send(method.to_sym).deliver_later
5
+ mailer.with(format).send(method.to_sym).deliver_later
6
6
  end
7
7
 
8
8
  private
@@ -14,6 +14,17 @@ module Noticed
14
14
  def method
15
15
  options[:method] || notification.class.name.underscore
16
16
  end
17
+
18
+ def format
19
+ if (method = options[:format])
20
+ notification.send(method)
21
+ else
22
+ notification.params.merge(
23
+ recipient: recipient,
24
+ record: record
25
+ )
26
+ end
27
+ end
17
28
  end
18
29
  end
19
30
  end
@@ -0,0 +1,42 @@
1
+ module Noticed
2
+ module Model
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ self.inheritance_column = nil
7
+
8
+ serialize :params, Noticed::Coder
9
+
10
+ belongs_to :recipient, polymorphic: true
11
+
12
+ scope :newest_first, -> { order(created_at: :desc) }
13
+ end
14
+
15
+ module ClassMethods
16
+ def mark_as_read!
17
+ update_all(read_at: Time.current, updated_at: Time.current)
18
+ end
19
+ end
20
+
21
+ # Rehydrate the database notification into the Notification object for rendering
22
+ def to_notification
23
+ @_notification ||= begin
24
+ instance = type.constantize.with(params)
25
+ instance.record = self
26
+ instance
27
+ end
28
+ end
29
+
30
+ def mark_as_read!
31
+ update(read_at: Time.current)
32
+ end
33
+
34
+ def unread?
35
+ !read?
36
+ end
37
+
38
+ def read?
39
+ read_at?
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,21 @@
1
+ module Translation
2
+ extend ActiveSupport::Concern
3
+
4
+ # Returns the +i18n_scope+ for the class. Overwrite if you want custom lookup.
5
+ def i18n_scope
6
+ :notifications
7
+ end
8
+
9
+ def translate(key, **options)
10
+ I18n.translate(scope_translation_key(key), **options)
11
+ end
12
+ alias t translate
13
+
14
+ def scope_translation_key(key)
15
+ if key.to_s.start_with?(".")
16
+ "notifications.#{self.class.name.underscore}#{key}"
17
+ else
18
+ key
19
+ end
20
+ end
21
+ end
@@ -1,3 +1,3 @@
1
1
  module Noticed
2
- VERSION = "1.1.0"
2
+ VERSION = "1.2.4"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: noticed
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0
4
+ version: 1.2.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chris Oliver
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-08-03 00:00:00.000000000 Z
11
+ date: 2020-08-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -92,6 +92,10 @@ files:
92
92
  - README.md
93
93
  - Rakefile
94
94
  - app/channels/noticed/notification_channel.rb
95
+ - lib/generators/noticed/model_generator.rb
96
+ - lib/generators/noticed/notification_generator.rb
97
+ - lib/generators/noticed/templates/README
98
+ - lib/generators/noticed/templates/notification.rb.tt
95
99
  - lib/noticed.rb
96
100
  - lib/noticed/base.rb
97
101
  - lib/noticed/coder.rb
@@ -104,6 +108,8 @@ files:
104
108
  - lib/noticed/delivery_methods/twilio.rb
105
109
  - lib/noticed/delivery_methods/vonage.rb
106
110
  - lib/noticed/engine.rb
111
+ - lib/noticed/model.rb
112
+ - lib/noticed/translation.rb
107
113
  - lib/noticed/version.rb
108
114
  - lib/tasks/noticed_tasks.rake
109
115
  homepage: https://github.com/excid3/noticed