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.
Files changed (63) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +3 -0
  3. data/.hound.yml +818 -0
  4. data/.travis.yml +20 -0
  5. data/Gemfile +23 -3
  6. data/README.md +8 -27
  7. data/Rakefile +47 -1
  8. data/app/controllers/harbinger/messages_controller.rb +24 -0
  9. data/app/models/harbinger/database_channel_message.rb +51 -0
  10. data/app/models/harbinger/database_channel_message_element.rb +19 -0
  11. data/app/views/harbinger/messages/index.html.erb +43 -0
  12. data/app/views/harbinger/messages/show.html.erb +24 -0
  13. data/config/routes.rb +3 -0
  14. data/db/migrate/20140310185338_create_harbinger_database_channel_message.rb +11 -0
  15. data/db/migrate/20140310185339_create_harbinger_database_channel_message_elements.rb +14 -0
  16. data/gemfiles/rails4.1.gemfile +12 -0
  17. data/gemfiles/rails4.gemfile +13 -0
  18. data/harbinger.gemspec +22 -7
  19. data/lib/generators/harbinger/install/install_generator.rb +23 -0
  20. data/lib/generators/harbinger/install/templates/harbinger_initializer.rb.erb +6 -0
  21. data/lib/harbinger.rb +100 -1
  22. data/lib/harbinger/channels.rb +25 -0
  23. data/lib/harbinger/channels/database_channel.rb +15 -0
  24. data/lib/harbinger/channels/logger_channel.rb +31 -0
  25. data/lib/harbinger/channels/null_channel.rb +7 -0
  26. data/lib/harbinger/configuration.rb +58 -0
  27. data/lib/harbinger/engine.rb +8 -1
  28. data/lib/harbinger/exceptions.rb +4 -0
  29. data/lib/harbinger/message.rb +20 -0
  30. data/lib/harbinger/reporters.rb +34 -0
  31. data/lib/harbinger/reporters/exception_reporter.rb +26 -0
  32. data/lib/harbinger/reporters/null_reporter.rb +14 -0
  33. data/lib/harbinger/reporters/request_reporter.rb +20 -0
  34. data/lib/harbinger/reporters/user_reporter.rb +20 -0
  35. data/lib/harbinger/version.rb +1 -1
  36. data/run_each_spec_in_isolation +9 -0
  37. data/script/fast_specs +20 -0
  38. data/spec/controllers/harbinger/messages_controller_spec.rb +26 -0
  39. data/spec/features/end_to_end_exception_handling_spec.rb +39 -0
  40. data/spec/lib/harbinger/channels/database_channel_spec.rb +18 -0
  41. data/spec/lib/harbinger/channels/logger_channel_spec.rb +21 -0
  42. data/spec/lib/harbinger/channels/null_channel_spec.rb +8 -0
  43. data/spec/lib/harbinger/channels_spec.rb +40 -0
  44. data/spec/lib/harbinger/configuration_spec.rb +53 -0
  45. data/spec/lib/harbinger/message_spec.rb +15 -0
  46. data/spec/lib/harbinger/reporters/exception_reporter_spec.rb +24 -0
  47. data/spec/lib/harbinger/reporters/null_reporter_spec.rb +21 -0
  48. data/spec/lib/harbinger/reporters/request_reporter_spec.rb +23 -0
  49. data/spec/lib/harbinger/reporters/user_reporter_spec.rb +17 -0
  50. data/spec/lib/harbinger/reporters_spec.rb +46 -0
  51. data/spec/lib/harbinger_spec.rb +60 -0
  52. data/spec/models/harbinger/database_channel_message_element_spec.rb +16 -0
  53. data/spec/models/harbinger/database_channel_message_spec.rb +68 -0
  54. data/spec/routing/harbinger/messages_routing_spec.rb +16 -0
  55. data/spec/spec_active_record_helper.rb +41 -0
  56. data/spec/spec_fast_helper.rb +70 -0
  57. data/spec/spec_slow_helper.rb +57 -0
  58. data/spec/spec_view_helper.rb +38 -0
  59. data/spec/test_app_templates/lib/generators/test_app_generator.rb +13 -0
  60. data/spec/views/harbinger/messages/index.html.erb_spec.rb +31 -0
  61. data/spec/views/harbinger/messages/show.html.erb_spec.rb +36 -0
  62. metadata +205 -20
  63. data/MIT-LICENSE +0 -20
@@ -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
- # To use debugger
14
- # gem 'debugger'
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
- TODO: Write a gem description
4
-
5
- ## Installation
6
-
7
- Add this line to your application's Gemfile:
8
-
9
- gem 'harbinger'
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
+ [![Version](https://badge.fury.io/rb/harbinger.png)](http://badge.fury.io/rb/harbinger)
4
+ [![Build Status](https://travis-ci.org/ndlib/harbinger.png?branch=master)](https://travis-ci.org/ndlib/harbinger)
5
+ [![Code Climate](https://codeclimate.com/github/ndlib/harbinger.png)](https://codeclimate.com/github/ndlib/harbinger)
6
+ [![Coverage Status](https://img.shields.io/coveralls/ndlib/harbinger.svg)](https://coveralls.io/r/ndlib/harbinger)
7
+ [![API Docs](http://img.shields.io/badge/API-docs-blue.svg)](http://rubydoc.info/github/ndlib/harbinger/master/frames/)
8
+ [![APACHE 2 License](http://img.shields.io/badge/APACHE2-license-blue.svg)](./LICENSE)
9
+
10
+ A Rails engine for arbitrary message creation and delivery.
data/Rakefile CHANGED
@@ -1 +1,47 @@
1
- require "bundler/gem_tasks"
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">&nbsp;</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>
@@ -1,2 +1,5 @@
1
1
  Harbinger::Engine.routes.draw do
2
+ scope module: 'harbinger' do
3
+ resources :messages, only: [:index, :show]
4
+ end
2
5
  end
@@ -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'
@@ -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 = ["Jeremy Friesen"]
10
- spec.email = ["jeremy.n.friesen@gmail.com"]
11
- spec.summary = %q{An exception tracking Rails engine}
12
- spec.description = %q{An exception tracking Rails engine}
13
- spec.homepage = ""
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/}) { |f| File.basename(f) }
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
@@ -0,0 +1,6 @@
1
+ Harbinger.configure do |config|
2
+
3
+ # See Harbinger::Channels for more information
4
+ config.default_channels = [:logger, :database]
5
+
6
+ end