harbinger 0.0.1.pre → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gitignore +3 -0
- data/.hound.yml +818 -0
- data/.travis.yml +20 -0
- data/Gemfile +23 -3
- data/README.md +8 -27
- data/Rakefile +47 -1
- data/app/controllers/harbinger/messages_controller.rb +24 -0
- data/app/models/harbinger/database_channel_message.rb +51 -0
- data/app/models/harbinger/database_channel_message_element.rb +19 -0
- data/app/views/harbinger/messages/index.html.erb +43 -0
- data/app/views/harbinger/messages/show.html.erb +24 -0
- data/config/routes.rb +3 -0
- data/db/migrate/20140310185338_create_harbinger_database_channel_message.rb +11 -0
- data/db/migrate/20140310185339_create_harbinger_database_channel_message_elements.rb +14 -0
- data/gemfiles/rails4.1.gemfile +12 -0
- data/gemfiles/rails4.gemfile +13 -0
- data/harbinger.gemspec +22 -7
- data/lib/generators/harbinger/install/install_generator.rb +23 -0
- data/lib/generators/harbinger/install/templates/harbinger_initializer.rb.erb +6 -0
- data/lib/harbinger.rb +100 -1
- data/lib/harbinger/channels.rb +25 -0
- data/lib/harbinger/channels/database_channel.rb +15 -0
- data/lib/harbinger/channels/logger_channel.rb +31 -0
- data/lib/harbinger/channels/null_channel.rb +7 -0
- data/lib/harbinger/configuration.rb +58 -0
- data/lib/harbinger/engine.rb +8 -1
- data/lib/harbinger/exceptions.rb +4 -0
- data/lib/harbinger/message.rb +20 -0
- data/lib/harbinger/reporters.rb +34 -0
- data/lib/harbinger/reporters/exception_reporter.rb +26 -0
- data/lib/harbinger/reporters/null_reporter.rb +14 -0
- data/lib/harbinger/reporters/request_reporter.rb +20 -0
- data/lib/harbinger/reporters/user_reporter.rb +20 -0
- data/lib/harbinger/version.rb +1 -1
- data/run_each_spec_in_isolation +9 -0
- data/script/fast_specs +20 -0
- data/spec/controllers/harbinger/messages_controller_spec.rb +26 -0
- data/spec/features/end_to_end_exception_handling_spec.rb +39 -0
- data/spec/lib/harbinger/channels/database_channel_spec.rb +18 -0
- data/spec/lib/harbinger/channels/logger_channel_spec.rb +21 -0
- data/spec/lib/harbinger/channels/null_channel_spec.rb +8 -0
- data/spec/lib/harbinger/channels_spec.rb +40 -0
- data/spec/lib/harbinger/configuration_spec.rb +53 -0
- data/spec/lib/harbinger/message_spec.rb +15 -0
- data/spec/lib/harbinger/reporters/exception_reporter_spec.rb +24 -0
- data/spec/lib/harbinger/reporters/null_reporter_spec.rb +21 -0
- data/spec/lib/harbinger/reporters/request_reporter_spec.rb +23 -0
- data/spec/lib/harbinger/reporters/user_reporter_spec.rb +17 -0
- data/spec/lib/harbinger/reporters_spec.rb +46 -0
- data/spec/lib/harbinger_spec.rb +60 -0
- data/spec/models/harbinger/database_channel_message_element_spec.rb +16 -0
- data/spec/models/harbinger/database_channel_message_spec.rb +68 -0
- data/spec/routing/harbinger/messages_routing_spec.rb +16 -0
- data/spec/spec_active_record_helper.rb +41 -0
- data/spec/spec_fast_helper.rb +70 -0
- data/spec/spec_slow_helper.rb +57 -0
- data/spec/spec_view_helper.rb +38 -0
- data/spec/test_app_templates/lib/generators/test_app_generator.rb +13 -0
- data/spec/views/harbinger/messages/index.html.erb_spec.rb +31 -0
- data/spec/views/harbinger/messages/show.html.erb_spec.rb +36 -0
- metadata +205 -20
- data/MIT-LICENSE +0 -20
data/.travis.yml
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
language: ruby
|
2
|
+
rvm:
|
3
|
+
- "2.0.0"
|
4
|
+
- "2.1.1"
|
5
|
+
- "2.1.2"
|
6
|
+
|
7
|
+
gemfile:
|
8
|
+
- gemfiles/rails4.gemfile
|
9
|
+
- gemfiles/rails4.1.gemfile
|
10
|
+
|
11
|
+
env:
|
12
|
+
global:
|
13
|
+
- NOKOGIRI_USE_SYSTEM_LIBRARIES=true
|
14
|
+
|
15
|
+
script: 'COVERAGE=true rake spec:travis'
|
16
|
+
|
17
|
+
bundler_args: --without headless debug
|
18
|
+
|
19
|
+
before_install:
|
20
|
+
- gem install bundler
|
data/Gemfile
CHANGED
@@ -3,12 +3,32 @@ source "https://rubygems.org"
|
|
3
3
|
# Declare your gem's dependencies in harbinger.gemspec.
|
4
4
|
# Bundler will treat runtime dependencies like base dependencies, and
|
5
5
|
# development dependencies will be added by default to the :development group.
|
6
|
-
gemspec
|
6
|
+
gemspec path: File.expand_path('..', __FILE__)
|
7
7
|
|
8
8
|
# Declare any dependencies that are still in development here instead of in
|
9
9
|
# your gemspec. These might include edge Rails or gems from your path or
|
10
10
|
# Git. Remember to move these dependencies to your gemspec before releasing
|
11
11
|
# your gem to rubygems.org.
|
12
12
|
|
13
|
-
|
14
|
-
|
13
|
+
gem 'capybara', require: false
|
14
|
+
gem 'coveralls', require: false
|
15
|
+
if ! ENV['TRAVIS']
|
16
|
+
gem 'simplecov', require: false
|
17
|
+
gem 'guard-rspec'
|
18
|
+
gem 'guard-bundler'
|
19
|
+
gem 'guard-rails'
|
20
|
+
gem 'rb-fsevent'
|
21
|
+
gem 'terminal-notifier-guard'
|
22
|
+
gem 'sexp_processor'
|
23
|
+
gem 'ruby_parser'
|
24
|
+
gem 'pry', '~> 0.9.7'
|
25
|
+
gem 'pry-nav'
|
26
|
+
gem 'byebug'
|
27
|
+
end
|
28
|
+
|
29
|
+
file = File.expand_path("Gemfile", ENV['ENGINE_CART_DESTINATION'] || ENV['RAILS_ROOT'] || File.expand_path("../spec/internal", __FILE__))
|
30
|
+
|
31
|
+
if File.exists?(file)
|
32
|
+
puts "Loading #{file} ..." if $DEBUG # `ruby -d` or `bundle -v`
|
33
|
+
instance_eval File.read(file)
|
34
|
+
end
|
data/README.md
CHANGED
@@ -1,29 +1,10 @@
|
|
1
1
|
# Harbinger
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
And then execute:
|
12
|
-
|
13
|
-
$ bundle
|
14
|
-
|
15
|
-
Or install it yourself as:
|
16
|
-
|
17
|
-
$ gem install harbinger
|
18
|
-
|
19
|
-
## Usage
|
20
|
-
|
21
|
-
TODO: Write usage instructions here
|
22
|
-
|
23
|
-
## Contributing
|
24
|
-
|
25
|
-
1. Fork it ( http://github.com/<my-github-username>/harbinger/fork )
|
26
|
-
2. Create your feature branch (`git checkout -b my-new-feature`)
|
27
|
-
3. Commit your changes (`git commit -am 'Add some feature'`)
|
28
|
-
4. Push to the branch (`git push origin my-new-feature`)
|
29
|
-
5. Create new Pull Request
|
3
|
+
[](http://badge.fury.io/rb/harbinger)
|
4
|
+
[](https://travis-ci.org/ndlib/harbinger)
|
5
|
+
[](https://codeclimate.com/github/ndlib/harbinger)
|
6
|
+
[](https://coveralls.io/r/ndlib/harbinger)
|
7
|
+
[](http://rubydoc.info/github/ndlib/harbinger/master/frames/)
|
8
|
+
[](./LICENSE)
|
9
|
+
|
10
|
+
A Rails engine for arbitrary message creation and delivery.
|
data/Rakefile
CHANGED
@@ -1 +1,47 @@
|
|
1
|
-
|
1
|
+
begin
|
2
|
+
require 'bundler/setup'
|
3
|
+
rescue LoadError
|
4
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
5
|
+
end
|
6
|
+
|
7
|
+
Bundler::GemHelper.install_tasks
|
8
|
+
|
9
|
+
begin
|
10
|
+
APP_RAKEFILE = File.expand_path('../spec/internal/Rakefile', __FILE__)
|
11
|
+
load 'rails/tasks/engine.rake'
|
12
|
+
rescue LoadError
|
13
|
+
puts "Unable to load all app tasks for #{APP_RAKEFILE}"
|
14
|
+
end
|
15
|
+
|
16
|
+
require 'engine_cart/rake_task'
|
17
|
+
# http://stackoverflow.com/questions/23165506/rails-spring-breaking-generators
|
18
|
+
# https://github.com/cbeer/engine_cart/issues/15
|
19
|
+
EngineCart.rails_options = '--skip-spring'
|
20
|
+
require 'rspec/core/rake_task'
|
21
|
+
|
22
|
+
namespace :spec do
|
23
|
+
RSpec::Core::RakeTask.new(:all) do
|
24
|
+
ENV['COVERAGE'] = 'true'
|
25
|
+
end
|
26
|
+
|
27
|
+
desc 'Run the Travis CI specs'
|
28
|
+
task :travis do
|
29
|
+
ENV['RAILS_ENV'] = 'test'
|
30
|
+
spec_helper = File.expand_path('../spec/spec_slow_helper.rb', __FILE__)
|
31
|
+
ENV['SPEC_OPTS'] = "--profile 20 --require #{spec_helper}"
|
32
|
+
Rake::Task['engine_cart:clean'].invoke
|
33
|
+
Rake::Task['engine_cart:generate'].invoke
|
34
|
+
Rake::Task['spec:all'].invoke
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
begin
|
39
|
+
Rake::Task['default'].clear
|
40
|
+
rescue RuntimeError
|
41
|
+
puts 'Unable to find :default rake task; No worries.'
|
42
|
+
end
|
43
|
+
|
44
|
+
Rake::Task['spec'].clear
|
45
|
+
|
46
|
+
task spec: 'spec:all'
|
47
|
+
task default: 'spec:travis'
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Harbinger
|
2
|
+
class MessagesController < ActionController::Base
|
3
|
+
|
4
|
+
def index
|
5
|
+
messages
|
6
|
+
end
|
7
|
+
|
8
|
+
def show
|
9
|
+
message
|
10
|
+
end
|
11
|
+
|
12
|
+
protected
|
13
|
+
|
14
|
+
def messages
|
15
|
+
@messages ||= DatabaseChannelMessage.search(q: params[:q])
|
16
|
+
end
|
17
|
+
|
18
|
+
def message
|
19
|
+
@message ||= DatabaseChannelMessage.find(params[:id])
|
20
|
+
end
|
21
|
+
|
22
|
+
helper_method :message, :messages
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'active_record'
|
2
|
+
require 'harbinger/database_channel_message_element'
|
3
|
+
|
4
|
+
module Harbinger
|
5
|
+
class DatabaseChannelMessage < ActiveRecord::Base
|
6
|
+
self.table_name = 'harbinger_messages'
|
7
|
+
has_many :elements, class_name: 'Harbinger::DatabaseChannelMessageElement', foreign_key: :message_id
|
8
|
+
|
9
|
+
def contexts=(values)
|
10
|
+
super(Array.wrap(values).join(','))
|
11
|
+
end
|
12
|
+
|
13
|
+
def contexts
|
14
|
+
super.split(',')
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.store_message(message, storage = new)
|
18
|
+
storage.contexts = message.contexts
|
19
|
+
storage.state = 'new'
|
20
|
+
message.attributes.each do |key, value|
|
21
|
+
storage.elements.build(key: key, value: value)
|
22
|
+
end
|
23
|
+
storage.save!
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.search(params = {})
|
27
|
+
search_text(params[:q]).
|
28
|
+
search_state(params[:state]).
|
29
|
+
ordered
|
30
|
+
end
|
31
|
+
|
32
|
+
# Search the message and its elements for the matching text.
|
33
|
+
scope :search_text, lambda { |text|
|
34
|
+
if text
|
35
|
+
where(
|
36
|
+
arel_table[:contexts].matches("#{text}%").
|
37
|
+
or(
|
38
|
+
arel_table[:id].
|
39
|
+
in(Arel::SqlLiteral.new(DatabaseChannelMessageElement.search_text(text).select(:message_id).to_sql))
|
40
|
+
)
|
41
|
+
)
|
42
|
+
else
|
43
|
+
all
|
44
|
+
end
|
45
|
+
}
|
46
|
+
|
47
|
+
scope :search_state, ->(state) { state ? where(arel_table[:state].eq(state)) : all }
|
48
|
+
|
49
|
+
scope :ordered, -> { order(arel_table[:created_at].desc) }
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'active_record'
|
2
|
+
require 'harbinger/database_channel_message'
|
3
|
+
|
4
|
+
module Harbinger
|
5
|
+
class DatabaseChannelMessageElement < ActiveRecord::Base
|
6
|
+
self.table_name = 'harbinger_message_elements'
|
7
|
+
belongs_to :message, class_name: 'Harbinger::DatabaseChannelMessage', foreign_key: :message_id
|
8
|
+
serialize :value
|
9
|
+
|
10
|
+
scope :search_text, lambda { |text|
|
11
|
+
if text
|
12
|
+
# Using %text% because I am serializing the data.
|
13
|
+
where(arel_table[:value].matches("%#{text}%"))
|
14
|
+
else
|
15
|
+
self
|
16
|
+
end
|
17
|
+
}
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
<%= form_tag harbinger.messages_path, :method => :get, :class => "search-form" do %>
|
2
|
+
<fieldset>
|
3
|
+
<legend class="accessible-hidden">Search Messages</legend>
|
4
|
+
<%= label_tag :message_search, "Search Text", :class => "accessible-hidden" %>
|
5
|
+
<%= text_field_tag(
|
6
|
+
:q,
|
7
|
+
params[:q],
|
8
|
+
:class => "q search-query",
|
9
|
+
:id => "message_search",
|
10
|
+
:placeholder => "Search text of messages",
|
11
|
+
:size => "30",
|
12
|
+
:tabindex => "1",
|
13
|
+
:type => "search",
|
14
|
+
)%><button type="submit" class="search-submit btn btn-primary" id="keyword-search-submit" tabindex="2">
|
15
|
+
<i class="icon-search icon-white"></i><span class="accessible-hidden">Search</span>
|
16
|
+
</button>
|
17
|
+
</fieldset>
|
18
|
+
<% end %>
|
19
|
+
|
20
|
+
<table>
|
21
|
+
<caption>Messages</caption>
|
22
|
+
<thead>
|
23
|
+
<tr>
|
24
|
+
<th>Created At</th>
|
25
|
+
<th>Contexts</th>
|
26
|
+
<th>State</th>
|
27
|
+
<th>Actions</th>
|
28
|
+
</tr>
|
29
|
+
</thead>
|
30
|
+
<tbody>
|
31
|
+
<% messages.each do |message| %>
|
32
|
+
<tr class="message">
|
33
|
+
<td class="detail message-created-at-detail"><a href="<%= harbinger.message_path(message.to_param)%>"><time><%= message.created_at %></time></a></td>
|
34
|
+
<td>
|
35
|
+
<ul><% message.contexts.each do |context| %>
|
36
|
+
<li class="detail message-contexts-detail"><%= context %></li>
|
37
|
+
<% end %></ul>
|
38
|
+
</td>
|
39
|
+
<td class="detail message-state-detail"><%= message.state %></td>
|
40
|
+
<td class="actions"> </td>
|
41
|
+
<% end %>
|
42
|
+
</tbody>
|
43
|
+
</table>
|
@@ -0,0 +1,24 @@
|
|
1
|
+
<article class="message">
|
2
|
+
<header class="message-header">
|
3
|
+
<h2>Message</h2>
|
4
|
+
<dl>
|
5
|
+
<dt class="term message-contexts-term">Contexts</dt>
|
6
|
+
<% message.contexts.each do |context| %>
|
7
|
+
<dd class="detail message-contexts-detail"><%= context %></dd>
|
8
|
+
<% end %>
|
9
|
+
<dt class="term message-state-term">State</dt>
|
10
|
+
<dd class="detail message-state-detail"><%= message.state %></dd>
|
11
|
+
<dt class="term message-created-at-term">Created at</dt>
|
12
|
+
<dd class="detail message-created-at-detail"><time><%= message.created_at %></time></dd>
|
13
|
+
</dl>
|
14
|
+
</header>
|
15
|
+
<section class="message-body">
|
16
|
+
<dl class="message-elements">
|
17
|
+
<% message.elements.each do |element| %>
|
18
|
+
<% dom_class_prefix = element.key.gsub(/_+/, '-') %>
|
19
|
+
<dt class="term <%= dom_class_prefix %>-term"><%= element.key %></dt>
|
20
|
+
<dd class="detail <%= dom_class_prefix %>-detail"><%= element.value %></dd>
|
21
|
+
<% end %>
|
22
|
+
</dl>
|
23
|
+
</section>
|
24
|
+
</article>
|
data/config/routes.rb
CHANGED
@@ -0,0 +1,11 @@
|
|
1
|
+
class CreateHarbingerDatabaseChannelMessage < ActiveRecord::Migration
|
2
|
+
def change
|
3
|
+
create_table :harbinger_messages do |t|
|
4
|
+
t.string :contexts
|
5
|
+
t.string :state, limit: 32
|
6
|
+
t.timestamps
|
7
|
+
end
|
8
|
+
add_index :harbinger_messages, :state
|
9
|
+
add_index :harbinger_messages, :contexts
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
class CreateHarbingerDatabaseChannelMessageElements < ActiveRecord::Migration
|
2
|
+
def change
|
3
|
+
create_table :harbinger_message_elements do |t|
|
4
|
+
t.integer :message_id
|
5
|
+
t.string :key
|
6
|
+
t.text :value, limit: 2147483647
|
7
|
+
t.timestamps
|
8
|
+
end
|
9
|
+
add_index :harbinger_message_elements, :message_id
|
10
|
+
add_index :harbinger_message_elements, :key
|
11
|
+
add_index :harbinger_message_elements, [:message_id, :key]
|
12
|
+
add_index :harbinger_message_elements, [:message_id, :value]
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
source 'http://rubygems.org'
|
2
|
+
|
3
|
+
file = File.expand_path("../../Gemfile", __FILE__)
|
4
|
+
|
5
|
+
if File.exists?(file)
|
6
|
+
puts "Loading #{file} ..." if $DEBUG # `ruby -d` or `bundle -v`
|
7
|
+
instance_eval File.read(file)
|
8
|
+
end
|
9
|
+
gem 'sass', '~> 3.2.15'
|
10
|
+
gem 'sprockets', '~> 2.11.0'
|
11
|
+
|
12
|
+
gem 'rails', '4.1.0'
|
@@ -0,0 +1,13 @@
|
|
1
|
+
source 'http://rubygems.org'
|
2
|
+
|
3
|
+
file = File.expand_path("../../Gemfile", __FILE__)
|
4
|
+
|
5
|
+
if File.exists?(file)
|
6
|
+
puts "Loading #{file} ..." if $DEBUG # `ruby -d` or `bundle -v`
|
7
|
+
instance_eval File.read(file)
|
8
|
+
end
|
9
|
+
|
10
|
+
gem 'sass', '~> 3.2.15'
|
11
|
+
gem 'sprockets', '~> 2.11.0'
|
12
|
+
|
13
|
+
gem 'rails', '4.0.3'
|
data/harbinger.gemspec
CHANGED
@@ -6,18 +6,33 @@ require 'harbinger/version'
|
|
6
6
|
Gem::Specification.new do |spec|
|
7
7
|
spec.name = "harbinger"
|
8
8
|
spec.version = Harbinger::VERSION
|
9
|
-
spec.authors = [
|
10
|
-
|
11
|
-
|
12
|
-
spec.
|
13
|
-
|
9
|
+
spec.authors = [
|
10
|
+
"Jeremy Friesen"
|
11
|
+
]
|
12
|
+
spec.email = [
|
13
|
+
"jeremy.n.friesen@gmail.com"
|
14
|
+
]
|
15
|
+
spec.summary = %q{A Rails engine for arbitrary message creation and delivery.}
|
16
|
+
spec.description = %q{A Rails engine for arbitrary message creation and delivery.}
|
17
|
+
spec.homepage = "https://github.com/ndlib/harbinger"
|
14
18
|
spec.license = "Apache2"
|
15
19
|
|
16
20
|
spec.files = `git ls-files -z`.split("\x0")
|
17
|
-
spec.executables = spec.files.grep(%r{^bin/})
|
21
|
+
spec.executables = spec.files.grep(%r{^bin/}) do |f|
|
22
|
+
f == 'bin/rails' ? nil : File.basename(f)
|
23
|
+
end.compact
|
18
24
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
25
|
spec.require_paths = ["lib"]
|
20
26
|
|
21
27
|
spec.add_development_dependency "bundler", "~> 1.5"
|
22
|
-
spec.add_development_dependency "rake"
|
28
|
+
spec.add_development_dependency "rake", '~> 10.3'
|
29
|
+
spec.add_development_dependency "rspec-given", '~> 3.5'
|
30
|
+
spec.add_development_dependency 'rspec-rails', '~> 3.0'
|
31
|
+
spec.add_development_dependency 'rspec-html-matchers', '~>0.6'
|
32
|
+
spec.add_development_dependency "engine_cart", '~> 0.3'
|
33
|
+
spec.add_development_dependency "rails", "~> 4.0"
|
34
|
+
spec.add_development_dependency 'sqlite3', '~> 1.3'
|
35
|
+
spec.add_development_dependency 'database_cleaner', '~> 1.3'
|
36
|
+
spec.add_development_dependency 'capybara', '~> 2.4'
|
37
|
+
|
23
38
|
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'rails/generators'
|
2
|
+
module Harbinger
|
3
|
+
class InstallGenerator < Rails::Generators::Base
|
4
|
+
source_root File.expand_path('../templates', __FILE__)
|
5
|
+
|
6
|
+
class_option :skip_database_channel, default: false, type: :boolean
|
7
|
+
|
8
|
+
def install_database_channel
|
9
|
+
if ! options[:skip_database_channel]
|
10
|
+
rake 'harbinger:install:migrations'
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def install_configuration_file
|
15
|
+
template "harbinger_initializer.rb.erb", "config/initializers/harbinger_initializer.rb"
|
16
|
+
end
|
17
|
+
|
18
|
+
def install_routes
|
19
|
+
route 'mount Harbinger::Engine => "/harbinger"'
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|