Skip to content

Commit

Permalink
Merge pull request #34 from brianknight10/hook-generator
Browse files Browse the repository at this point in the history
Web Hook Generator
  • Loading branch information
tardate committed Nov 25, 2015
2 parents 3185d10 + e4725d6 commit b9afc94
Show file tree
Hide file tree
Showing 7 changed files with 375 additions and 9 deletions.
25 changes: 23 additions & 2 deletions README.rdoc
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ FYI, {Mandrill}[http://mandrill.com/] is the transactional email service by the
* Requires Rails >= 3.0.3 (including 3.1, 3.2 and 4).

Food for thought (upcoming features maybe)..
* some generators may be handy to avoid the manual coding to wire up web hooks
* I thought about implementing this as an engine, but the overhead did not seem appropriate. Maybe that view will change..

== The Mandrill::Rails Cookbook
Expand Down Expand Up @@ -48,7 +47,29 @@ See the section below on 'Contributing to Mandrill::Rails' for more information.

Say we have configured Mandrill to send requests to /inbox at our site (see the next recipes for how you do that).

Once we have Mandrill::Rails in our project, we just need to do two things. There's no generator to help you do this at the moment, but it is pretty simple:
Once we have Mandrill::Rails in our project, we just need to do two things. You can run a generator to do it for you, or you can configure things manually:

==== Using the generator

Run the generator and specify the name for your route and controller:

rails generate mandrill inbox

This will create a resource route and corresponding controller at /inbox.

If you need a namespaced controller, specify it in the name:

rails generate mandrill hooks/inbox

This creates an `inbox` route that points to the `Hooks:InboxController` class.

If you prefer pluralized names, that can be specified with a flag:

rails generate mandrill inbox --pluralize_names

This will create an `InboxesController` class and a resource route called `inboxes`.

==== Manual configuration

First, configure a resource route:

Expand Down
18 changes: 18 additions & 0 deletions lib/generators/templates/controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
class <%= @controller_name %>Controller < ApplicationController
include Mandrill::Rails::WebHookProcessor

# To completely ignore unhandled events (not even logging), uncomment this line
# ignore_unhandled_events!

# If you want unhandled events to raise a hard exception, uncomment this line
# unhandled_events_raise_exceptions!

# To enable authentication, uncomment this line and set your API key.
# It is recommended you pull your API keys from environment settings,
# or use some other means to avoid committing the API keys in your source code.
# authenticate_with_mandrill_keys! 'YOUR_MANDRILL_WEBHOOK_KEY'

def handle_inbound(event_payload)
head(:ok)
end
end
83 changes: 83 additions & 0 deletions lib/generators/web_hook_generator.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
require 'rails/generators/named_base'

module Mandrill
module Rails
module Generators
class WebHookGenerator < ::Rails::Generators::Base
namespace 'mandrill'
desc 'Generates a controller and routes for Mandrill web hooks.'
argument :name, type: :string
class_option :pluralize_names, aliases: '-p', type: :boolean, default: false,
desc: 'Pluralize names in route and controller'
class_option :routes, type: :boolean, default: true,
desc: 'Creates routes for web hooks'
class_option :controller, type: :boolean, default: true,
desc: 'Creates a controller for web hooks'

source_root File.expand_path("../templates", __FILE__)

def initialize(args, *options)
args[0] = args[0].dup if args[0].is_a?(String) && args[0].frozen?
super
assign_names!(self.name)
end

def add_routes
return unless options.routes?
hook_route = "resource :#{resource_name}"

controller = controller_path

hook_route << %Q(, :controller => '#{controller}')
hook_route << %Q(, :only => [:show,:create])
route hook_route
end

def add_controller
return unless options.controller?
@controller_name = class_name
template 'controller.rb', controller_destination
end

private

attr_reader :file_name

def assign_names!(name)
@class_path = name.include?('/') ? name.split('/') : name.split('::')
@class_path.map!(&:underscore)
@file_name = @class_path.pop
end

def class_name
@class_name ||= (@class_path + [resource_name]).map!(&:camelize).join('::')
end

def controller_destination
"app/controllers/#{controller_path}_controller.rb"
end

def controller_path
@controller_path ||= if class_name.include?('::')
@class_path.collect {|dname| dname }.join + "/" + resource_name
else
resource_name
end
end

def plural_name
@plural_name ||= singular_name.pluralize
end

def resource_name
return singular_name unless options.pluralize_names?
plural_name
end

def singular_name
file_name.downcase
end
end
end
end
end
1 change: 1 addition & 0 deletions mandrill-rails.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ Gem::Specification.new do |spec|
spec.add_development_dependency "bundler", "~> 1.7"
spec.add_development_dependency "rake", "~> 10.0"
spec.add_development_dependency "rspec", "~> 3.0"
spec.add_development_dependency "generator_spec", "~> 0.9"
spec.add_development_dependency "guard-rspec", "~> 4.5"
spec.add_development_dependency "rdoc"

Expand Down
246 changes: 246 additions & 0 deletions spec/generators/web_hook_generator_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,246 @@
require 'spec_helper'
require 'generator_spec'
require 'generators/web_hook_generator'

describe Mandrill::Rails::Generators::WebHookGenerator, type: :generator do
destination File.expand_path("../../tmp", __FILE__)

before do
prepare_destination
copy_routes
end

describe 'route generation' do
context 'with no pluralized option' do
context 'with simple names' do
before { run_generator %w(inbox) }

it 'creates a proper route' do
match = "resource :inbox, :controller => 'inbox', :only => [:show,:create]"
expect(destination_root).to have_structure {
directory 'config' do
file 'routes.rb' do
contains match
end
end
}
end
end

context 'with namespaced names' do
before { run_generator %w(hooks/inbox) }

it 'creates a proper route' do
match = "resource :inbox, :controller => 'hooks/inbox', :only => [:show,:create]"
expect(destination_root).to have_structure {
directory 'config' do
file 'routes.rb' do
contains match
end
end
}
end
end

context 'with capitalized names' do
before { run_generator %w(Inbox) }

it 'creates a proper route' do
match = "resource :inbox, :controller => 'inbox', :only => [:show,:create]"
expect(destination_root).to have_structure {
directory 'config' do
file 'routes.rb' do
contains match
end
end
}
end
end
end

context 'with an explicit pluralized option' do
context 'with simple names' do
before { run_generator %w(inbox --pluralize_names) }

it 'creates a proper route' do
match = "resource :inboxes, :controller => 'inboxes', :only => [:show,:create]"
expect(destination_root).to have_structure {
directory 'config' do
file 'routes.rb' do
contains match
end
end
}
end
end

context 'with namespaced names' do
before { run_generator %w(hooks/inbox --pluralize_names) }

it 'creates a proper route' do
match = "resource :inboxes, :controller => 'hooks/inboxes', :only => [:show,:create]"
expect(destination_root).to have_structure {
directory 'config' do
file 'routes.rb' do
contains match
end
end
}
end
end

context 'with capitalized names' do
before { run_generator %w(hooks/Inbox --pluralize_names) }

it 'creates a proper route' do
match = "resource :inboxes, :controller => 'hooks/inboxes', :only => [:show,:create]"
expect(destination_root).to have_structure {
directory 'config' do
file 'routes.rb' do
contains match
end
end
}
end
end
end
end

describe 'controller generation' do
context 'with controller explicitly skipped' do
before { run_generator %w(inbox --skip-controller) }

it 'does not create a controller file' do
expect(destination_root).to have_structure {
directory 'app' do
directory 'controllers' do
no_file 'inbox_controller.rb'
end
end
}
end
end

context 'with no pluralized option' do
context 'with simple names' do
before { run_generator %w(inbox) }

it 'creates a proper controller file' do
match = 'class InboxController < ApplicationController'
expect(destination_root).to have_structure {
directory 'app' do
directory 'controllers' do
file 'inbox_controller.rb' do
contains match
end
end
end
}
end
end

context 'with namespaced names' do
before { run_generator %w(hooks/inbox) }

it 'creates a proper controller file' do
match = 'class Hooks::InboxController < ApplicationController'
expect(destination_root).to have_structure {
directory 'app' do
directory 'controllers' do
directory 'hooks' do
file 'inbox_controller.rb' do
contains match
end
end
end
end
}
end
end

context 'with capitalized names' do
before { run_generator %w(hooks/Inbox) }

it 'creates a proper controller file' do
match = 'class Hooks::InboxController < ApplicationController'
expect(destination_root).to have_structure {
directory 'app' do
directory 'controllers' do
directory 'hooks' do
file 'inbox_controller.rb' do
contains match
end
end
end
end
}
end
end
end

context 'with an explicit pluralized option' do
context 'with simple names' do
before { run_generator %w(inbox --pluralize_names) }

it 'creates a proper controller file' do
match = 'class InboxesController < ApplicationController'
expect(destination_root).to have_structure {
directory 'app' do
directory 'controllers' do
file 'inboxes_controller.rb' do
contains match
end
end
end
}
end
end

context 'with namespaced names' do
before { run_generator %w(hooks/inbox --pluralize_names) }

it 'creates a proper controller file' do
match = 'class Hooks::InboxesController < ApplicationController'
expect(destination_root).to have_structure {
directory 'app' do
directory 'controllers' do
directory 'hooks' do
file 'inboxes_controller.rb' do
contains match
end
end
end
end
}
end
end

context 'with capitalized names' do
before { run_generator %w(hooks/Inboxes --pluralized_names) }

it 'creates a proper controller file' do
match = 'class Hooks::InboxesController < ApplicationController'
expect(destination_root).to have_structure {
directory 'app' do
directory 'controllers' do
directory 'hooks' do
file 'inboxes_controller.rb' do
contains match
end
end
end
end
}
end
end
end
end
end

def copy_routes
routes = File.expand_path('../../rails_app/config/routes.rb', __FILE__)
destination = File.join(destination_root, 'config')

FileUtils.mkdir_p(destination)
FileUtils.cp routes, destination
end
Loading

0 comments on commit b9afc94

Please sign in to comment.