notify_me 0.0.3

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: 270fa941da8f9e238d0ffaf8949e76c89c008e66
4
+ data.tar.gz: 115f8bcb85cc68c61ef4ed575ad2017d7af0ca60
5
+ SHA512:
6
+ metadata.gz: 745493d1165414e1c054566d0ca464c0c231b826fc45eb70451f992f97e8d049db8e9c19c7dea82062967a977552c1e2b730462715f92091a5978e0a3cdc0483
7
+ data.tar.gz: b360dbe5cfe10c20188962a1f0fb37ccc2ca7fe0525671686e979ce4a9af1196ef0b847648a39df06eb223070d982cd368ed07c422fb4f80de005febb51fe096
data/.gitignore ADDED
@@ -0,0 +1,2 @@
1
+ Gemfile.lock
2
+ spec/internal/db/*sqlite
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
data/LICENCE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2013 Sam Clopton
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,71 @@
1
+ # Notify Me
2
+ This is a gem that provides simple and generic notifications that can have 0
3
+ or more actions associated with them.
4
+
5
+ ## Usage:
6
+ ``` ruby
7
+ class User < ActiveRecord::Base
8
+ has_many_notifications
9
+ ...
10
+ end
11
+
12
+ class Task < ActiveRecord::Base
13
+ ...
14
+ end
15
+
16
+ class TaskSwap < ActiveRecord::Base
17
+ belongs_to :from, class_name: "User"
18
+ belongs_to :to, class_name: "User"
19
+ belongs_to :task
20
+
21
+ def accept_swap(action)
22
+ ...
23
+ end
24
+
25
+ def reject_swap(action)
26
+ ...
27
+ end
28
+ end
29
+ ```
30
+
31
+ A user wants to request a task swap
32
+
33
+ ``` ruby
34
+ swap_task = SwapTask.create(...)
35
+ notification = NotifyMe::Notification.create(message: "John Doe would like to swap tasks with you")
36
+ user.notifications << notification
37
+
38
+ notification.actions.create(notification: notification, commandable: swap_task, commandable_action: "accept_swap", name: "Accept")
39
+ notification.actions.create(notification: notification, commandable: swap_task, commandable_action: "reject_swap", name: "Reject")
40
+ ```
41
+
42
+ Likely in some controller somewhere
43
+
44
+ ``` ruby
45
+ action = Action.find(params[:id])
46
+ action.run_action() # if this was the action created above, this would call swap_task.accept_swap(action)
47
+ ```
48
+
49
+
50
+ ## Notification
51
+ * belongs_to :notifyable
52
+ * has_many :actions
53
+ * message - String
54
+ * message_details - String
55
+ * categories - String
56
+
57
+ ## Action
58
+ * belongs_to :notification
59
+ * belongs_to :commandable
60
+ * can either be an instance
61
+ * or a class (set the :commandable_type String to the class name -- I.E. "User")
62
+ * commandable_action - String
63
+ * must either be
64
+ * an action on the instance
65
+ * or an action on the class
66
+ * response_identifier - String
67
+ * not required, but if it is provided it must be unique
68
+ * has_been_processed - Boolean
69
+ * set to true after the action is processed.
70
+ * name - String
71
+ * say you want a name to display in a UI, use this field here
@@ -0,0 +1,65 @@
1
+ class NotifyMe::Action < ActiveRecord::Base
2
+ self.table_name = "notify_me_actions"
3
+
4
+ belongs_to :notification
5
+ belongs_to :commandable, :polymorphic => true
6
+
7
+ validates :notification, :presence => true
8
+ validates :commandable_type, :presence => true
9
+ validates :commandable_action, :presence => true
10
+ validate :validate_uniqness_of_unprocessed_identifiers
11
+ validate :validate_pressence_of_action
12
+
13
+ def validate_uniqness_of_unprocessed_identifiers
14
+ if self.response_identifier != nil
15
+ if NotifyMe::Action.where("response_identifier = ? AND has_been_processed = ?",
16
+ self.response_identifier, false).count > 0
17
+ errors.add(:base, "The response_identifier is not unique among unprocessed actions")
18
+ end
19
+ end
20
+ end
21
+
22
+ def validate_pressence_of_action
23
+ if self.commandable
24
+ unless self.commandable.respond_to?(self.commandable_action)
25
+ errors.add(:base, "The commandable action #{self.commandable_action} does not exist on the commandable instance")
26
+ end
27
+ else
28
+ begin
29
+ unless self.commandable_type.constantize.respond_to?(self.commandable_action)
30
+ errors.add(:base, "The commandable action #{self.commandable_action} does not exist on the commandable_type constant")
31
+ end
32
+ rescue NameError
33
+ errors.add(:base, "The commandable_type does not refer to a valid constant")
34
+ end
35
+ end
36
+ end
37
+
38
+ def self.process_by_identifier(identifier, *args)
39
+ action = self.where("response_identifier = ? AND has_been_processed = ?",
40
+ identifier, false).first
41
+
42
+ if action
43
+ {:action => action, :rval => action.run_action(*args)}
44
+ else
45
+ nil
46
+ end
47
+ end
48
+
49
+ def run_command(*args)
50
+ if self.commandable
51
+ self.commandable.send(self.commandable_action, self, *args)
52
+ else
53
+ self.commandable_type.constantize.send(self.commandable_action, self, *args)
54
+ end
55
+ end
56
+
57
+ def run_action(*args)
58
+ rval = run_command(*args)
59
+
60
+ self.has_been_processed = true
61
+ self.save!
62
+
63
+ return rval
64
+ end
65
+ end
@@ -0,0 +1,8 @@
1
+ class NotifyMe::Notification < ActiveRecord::Base
2
+ self.table_name = "notify_me_notifications"
3
+
4
+ has_many :actions, :class_name => 'NotifyMe::Action'
5
+ belongs_to :notifyable, :polymorphic => true
6
+
7
+ validates :message, :presence => true
8
+ end
data/config.ru ADDED
@@ -0,0 +1,7 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+
4
+ Bundler.require :default, :development
5
+
6
+ Combustion.initialize!
7
+ run Combustion::Application
@@ -0,0 +1,43 @@
1
+ class NotificationTables < ActiveRecord::Migration
2
+ def up
3
+ create_table :notify_me_notifications do |t|
4
+ t.integer :notifyable_id
5
+ t.string :notifyable_type
6
+
7
+ t.string :message
8
+ t.string :message_details
9
+ t.boolean :has_been_viewed, :required => true, :default => false
10
+ t.string :categories
11
+ end
12
+
13
+ add_index :notify_me_notifications, [:notifyable_id, :notifyable_type],
14
+ :name => 'index_notifications_on_note_id_and_note_type'
15
+ add_index :notify_me_notifications, [:notifyable_id, :notifyable_type, :categories],
16
+ :name => 'index_notifications_on_note_id_and_note_type_and_categories'
17
+
18
+ create_table :notify_me_actions do |t|
19
+ t.integer :notification_id
20
+ t.integer :commandable_id
21
+ t.string :commandable_type
22
+ t.string :commandable_action
23
+ t.string :response_identifier
24
+ t.boolean :has_been_processed, :required => true, :default => false
25
+ end
26
+
27
+ add_index :notify_me_actions, :notification_id
28
+ add_index :notify_me_actions, :response_identifier
29
+ add_index :notify_me_actions, [:notification_id, :response_identifier],
30
+ :name => 'index_notifications_on_note_id_and_resp_ident'
31
+ add_index :notify_me_actions, [:commandable_id, :commandable_type, :notification_id],
32
+ :name => "index_actions_on_comm_id_and_comm_type_and_note_id"
33
+ add_index :notify_me_actions, [:commandable_id, :commandable_type, :response_identifier],
34
+ :name => "index_actions_on_comm_id_and_comm_type_and_resp_ident"
35
+ add_index :notify_me_actions, [:commandable_id, :commandable_type, :notification_id, :response_identifier],
36
+ :unique => true, :name => 'unique_actions'
37
+ end
38
+
39
+ def down
40
+ drop_table :notify_me_notifications
41
+ drop_table :notify_me_actions
42
+ end
43
+ end
@@ -0,0 +1,9 @@
1
+ class ActionName < ActiveRecord::Migration
2
+ def up
3
+ add_column :notify_me_actions, :name, :string
4
+ end
5
+
6
+ def down
7
+ remove_column :notify_me_actions, :name
8
+ end
9
+ end
@@ -0,0 +1,15 @@
1
+ class TimeStamps < ActiveRecord::Migration
2
+ def up
3
+ add_column :notify_me_actions, :created_at, :datetime
4
+ add_column :notify_me_actions, :updated_at, :datetime
5
+ add_column :notify_me_notifications, :created_at, :datetime
6
+ add_column :notify_me_notifications, :updated_at, :datetime
7
+ end
8
+
9
+ def down
10
+ remove_column :notify_me_actions, :created_at
11
+ remove_column :notify_me_actions, :updated_at
12
+ remove_column :notify_me_notifications, :created_at
13
+ remove_column :notify_me_notifications, :updated_at
14
+ end
15
+ end
@@ -0,0 +1,12 @@
1
+ require 'active_support/concern'
2
+
3
+ module NotifyMe::ActiveRecord
4
+ extend ActiveSupport::Concern
5
+
6
+ module ClassMethods
7
+ def has_many_notifications
8
+ has_many :notifications, :as => :notifyable, :class_name => 'NotifyMe::Notification'
9
+ has_many :actions, :class_name => 'NotifyMe::Action', :through => :notifications
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,15 @@
1
+ require 'active_support/configurable'
2
+
3
+ module NotifyMe
4
+ def self.configure(&block)
5
+ yield @config ||= NotifyMe::Configuration.new
6
+ end
7
+
8
+ def self.config
9
+ @config
10
+ end
11
+
12
+ class Configuration
13
+ include ActiveSupport::Configurable
14
+ end
15
+ end
@@ -0,0 +1,9 @@
1
+ require 'rails/engine'
2
+
3
+ class NotifyMe::Engine < Rails::Engine
4
+ engine_name :notify_me
5
+
6
+ ActiveSupport.on_load :active_record do
7
+ include NotifyMe::ActiveRecord
8
+ end
9
+ end
@@ -0,0 +1,3 @@
1
+ module NotifyMe
2
+ VERSION = '0.0.3'
3
+ end
data/lib/notify_me.rb ADDED
@@ -0,0 +1,6 @@
1
+ module NotifyMe
2
+ #
3
+ end
4
+
5
+ require 'notify_me/active_record'
6
+ require 'notify_me/engine'
data/notify_me.gemspec ADDED
@@ -0,0 +1,25 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ lib = File.expand_path('../lib', __FILE__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+ require 'notify_me/version'
6
+
7
+ Gem::Specification.new do |s|
8
+ s.name = 'notify_me'
9
+ s.version = NotifyMe::VERSION
10
+ s.authors = ['Sam Clopton']
11
+ s.email = ['samsinite@gmail.com']
12
+ s.homepage = 'https://github.com/samsinite/notify_me'
13
+ s.summary = 'Notfy Me'
14
+ s.description = 'This friendly library gives you generic notifications in your Rails app.'
15
+ s.license = 'MIT'
16
+
17
+ s.files = `git ls-files`.split("\n")
18
+ s.test_files = `git ls-files -- {spec}/*`.split("\n")
19
+ s.require_paths = ['lib']
20
+
21
+ s.add_runtime_dependency 'activerecord', '>= 3.2.0'
22
+ s.add_development_dependency 'combustion', '~> 0.5.1'
23
+ s.add_development_dependency 'rspec-rails', '~> 2.13'
24
+ s.add_development_dependency 'sqlite3', '~> 1.3.7'
25
+ end
@@ -0,0 +1,112 @@
1
+ require 'spec_helper'
2
+
3
+ describe NotifyMe::Action do
4
+ let(:user) { User.create(username: "Test") }
5
+ let(:message_notification) { NotifyMe::Notification.create(message: "This is a test msg") }
6
+
7
+ it "can belong to a notification" do
8
+ action = NotifyMe::Action.new(:notification => message_notification,
9
+ :commandable => user,
10
+ :commandable_action => "view_notification")
11
+ action.should be_valid
12
+ end
13
+
14
+ it "must belong to a notification" do
15
+ action = NotifyMe::Action.new(:commandable => user,
16
+ :commandable_action => "view_notification")
17
+ action.should_not be_valid
18
+ end
19
+
20
+ it "can belong to a commandable instance" do
21
+ action = NotifyMe::Action.new(:notification => message_notification,
22
+ :commandable => user,
23
+ :commandable_action => "view_notification")
24
+
25
+ action.should be_valid
26
+ end
27
+
28
+ it "can belong to a commandable constant" do
29
+ action = NotifyMe::Action.new(:notification => message_notification,
30
+ :commandable_type => "User",
31
+ :commandable_action => "do_something")
32
+
33
+ action.should be_valid
34
+ end
35
+
36
+ it "must belong to a existing commandable instance or a commandable constant" do
37
+ action = NotifyMe::Action.new(:notification => message_notification)
38
+
39
+ action.should_not be_valid
40
+ end
41
+
42
+ it "if it belongs to a commandable instance, it must belong to an existing instance" do
43
+ action = NotifyMe::Action.new(:notification => message_notification,
44
+ :commandable_type => "User",
45
+ :commandable_id => 2,
46
+ :commandable_action => "view_notification")
47
+
48
+ action.should_not be_valid
49
+ end
50
+
51
+ it "if it belongs to a valid commandable instance, it must be able to process the action" do
52
+ action = NotifyMe::Action.new(:notification => message_notification,
53
+ :commandable_type => "User",
54
+ :commandable_id => 1,
55
+ :commandable_action => "fail_please")
56
+
57
+ action.should_not be_valid
58
+ end
59
+
60
+ it "if it belongs to a valid commandable constant, it must be able to process the action" do
61
+ action = NotifyMe::Action.new(:notification => message_notification,
62
+ :commandable_type => "User",
63
+ :commandable_action => "fail_please")
64
+
65
+ action.should_not be_valid
66
+ end
67
+ end
68
+
69
+ describe "Adding and removing actions" do
70
+ let(:user) { User.create(username: "Test") }
71
+ let(:message_notification) { NotifyMe::Notification.create(:message => "This is a test msg") }
72
+
73
+ it "stores new actions" do
74
+ action = message_notification.actions.create(:notification => message_notification,
75
+ :commandable => user,
76
+ :commandable_action => "view_notification")
77
+
78
+ message_notification.actions.reload.should == [action]
79
+ end
80
+
81
+ it "removes existing actions" do
82
+ action = message_notification.actions.create(:notification => message_notification,
83
+ :commandable => user,
84
+ :commandable_action => "view_notification")
85
+ message_notification.actions.delete action
86
+
87
+ user.notifications.reload.should == []
88
+ end
89
+ end
90
+
91
+ describe "Processing actions" do
92
+ let(:user) { User.create(username: "Test") }
93
+ let(:message_notification) { NotifyMe::Notification.create(:message => "This is a test msg") }
94
+
95
+ it "runs existing actions" do
96
+ action = message_notification.actions.create(:notification => message_notification,
97
+ :commandable => user,
98
+ :commandable_action => "view_notification")
99
+ action.run_action
100
+
101
+ message_notification.has_been_viewed.should be_true
102
+ end
103
+
104
+ it "marks ran actions as processed" do
105
+ action = message_notification.actions.create(:notification => message_notification,
106
+ :commandable => user,
107
+ :commandable_action => "view_notification")
108
+ action.run_action
109
+
110
+ action.has_been_processed.should be_true
111
+ end
112
+ end
@@ -0,0 +1,19 @@
1
+ require 'spec_helper'
2
+
3
+ describe "Adding and removing notifications" do
4
+ let(:user) { User.create(username: "Test") }
5
+ let(:message_notification) { NotifyMe::Notification.create(:message => "This is a test msg")}
6
+
7
+ it "stores new notifications" do
8
+ user.notifications << message_notification
9
+
10
+ user.notifications.reload.should == [message_notification]
11
+ end
12
+
13
+ it "removes existing notifications" do
14
+ user.notifications << message_notification
15
+ user.notifications.delete message_notification
16
+
17
+ user.notifications.reload.should == []
18
+ end
19
+ end
@@ -0,0 +1,14 @@
1
+ class User < ActiveRecord::Base
2
+ has_many_notifications
3
+
4
+ def view_notification(action)
5
+ action.notification.has_been_viewed = true
6
+ action.notification.save!
7
+
8
+ true
9
+ end
10
+
11
+ def self.do_something(action)
12
+ puts "TADA!"
13
+ end
14
+ end
@@ -0,0 +1,3 @@
1
+ test:
2
+ adapter: sqlite3
3
+ database: db/combustion_test.sqlite
@@ -0,0 +1,6 @@
1
+ ActiveRecord::Schema.define do
2
+ create_table :users, :force => true do |t|
3
+ t.string :username
4
+ t.timestamps
5
+ end
6
+ end
@@ -0,0 +1 @@
1
+ *.log
@@ -0,0 +1,13 @@
1
+ require 'rubygems'
2
+ require 'bundler/setup'
3
+ require 'combustion'
4
+
5
+ Bundler.require :default, :development
6
+
7
+ Combustion.initialize! :active_record
8
+
9
+ require 'rspec/rails'
10
+
11
+ RSpec.configure do |config|
12
+ config.use_transactional_fixtures = true
13
+ end
metadata ADDED
@@ -0,0 +1,123 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: notify_me
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.3
5
+ platform: ruby
6
+ authors:
7
+ - Sam Clopton
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-11-19 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activerecord
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '>='
18
+ - !ruby/object:Gem::Version
19
+ version: 3.2.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '>='
25
+ - !ruby/object:Gem::Version
26
+ version: 3.2.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: combustion
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: 0.5.1
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: 0.5.1
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec-rails
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ~>
46
+ - !ruby/object:Gem::Version
47
+ version: '2.13'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: '2.13'
55
+ - !ruby/object:Gem::Dependency
56
+ name: sqlite3
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: 1.3.7
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ~>
67
+ - !ruby/object:Gem::Version
68
+ version: 1.3.7
69
+ description: This friendly library gives you generic notifications in your Rails app.
70
+ email:
71
+ - samsinite@gmail.com
72
+ executables: []
73
+ extensions: []
74
+ extra_rdoc_files: []
75
+ files:
76
+ - .gitignore
77
+ - Gemfile
78
+ - LICENCE
79
+ - README.md
80
+ - app/models/notify_me/action.rb
81
+ - app/models/notify_me/notification.rb
82
+ - config.ru
83
+ - db/migrate/1_notification_tables.rb
84
+ - db/migrate/2_action_name.rb
85
+ - db/migrate/3_timestamps.rb
86
+ - lib/notify_me.rb
87
+ - lib/notify_me/active_record.rb
88
+ - lib/notify_me/config.rb
89
+ - lib/notify_me/engine.rb
90
+ - lib/notify_me/version.rb
91
+ - notify_me.gemspec
92
+ - spec/acceptance/actions_spec.rb
93
+ - spec/acceptance/notifications_spec.rb
94
+ - spec/internal/app/models/user.rb
95
+ - spec/internal/config/database.yml
96
+ - spec/internal/db/schema.rb
97
+ - spec/internal/log/.gitignore
98
+ - spec/spec_helper.rb
99
+ homepage: https://github.com/samsinite/notify_me
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.0.3
120
+ signing_key:
121
+ specification_version: 4
122
+ summary: Notfy Me
123
+ test_files: []