Find Part 1 of this series here.
In our exploration of a newly generated plugin, we have so far mostly looked at the facilities Adhearsion provides to hook into the framework and your application. It is now time to actually build some new business logic, although it is entirely possible to have a plugin that consists of Rake tasks or configuration variables only.
A plugin is at its heart simply a Ruby gem, and bundled code needs to be loaded through requiring the proper files.
The generated plugin has a single business logic file in lib/controller_methods.rb. Neither the file name nor the module name are mandatory, this is just normal Ruby code.
Plugin Code
Content is as follows:
lib/controller_methods.rb
module GreetPlugin
module ControllerMethods
# The methods are defined in a normal method the user will then mix in their CallControllers
# The following also contains an example of configuration usage
def greet(name)
play "#{Adhearsion.config[:greet_plugin].greeting}, #{name}"
end
end
end
The module is intended to be used as a mixin in call controllers.
Testing your code
Module usage can be seen in action in the generated test file, which also showcases how the call controller methods can be easily tested.
spec/greet_plugin/controller_methods_spec.rb
require 'spec_helper'
module GreetPlugin
describe Plugin do
describe "mixed in to a CallController" do
class TestController < Adhearsion::CallController
include GreetPlugin::ControllerMethods
end
let(:mock_call) { mock 'Call' }
subject do
TestController.new mock_call
end
describe "#greet" do
it "greets with the correct parameter" do
subject.expects(:play).once.with("Hello, Luca")
subject.greet "Luca"
end
end
end
end
end
Since plugin code is a normal Ruby library, it can be tested in an easy way using Rspec and some facilities provided by Adhearsion.
Using the plugin
You have generated your new plugin, built tests and are ready to use it. Now what?
The plugin is a gem, so you might eventually publish it, but you can simply use it locally by adding a path line to your application's Gemfile.
Gemfile
gem 'adhearsion', '>= 2.0.0.rc1' gem 'greet_plugin', :path => '/home/user/projects/greet_plugin' # ... whatever other gems you need
Do not forget to run 'bundle install' to load eventual dependencies after adding the gem.
Adding an entire CallController
It is also possible to provide a full CallController implementation that can be used out-of-the-box by your application. Ben Langfeld's excellent blog post explains how a CallController works and what you can do with it.
We will be adding a new controller to our plugin, complete with new configuration keys and test. Our goal is to have a controller that dials a SIP device during office hours, and plays a message when the office is closed.
Setup
First, we add configuration for the times used:
lib/greet_plugin/plugin.rb
config :greet_plugin do greeting "Hello", :desc => "What to use to greet users" office_hours_start 8, :desc => "Start of office hours, integer, 24 hour format" office_hours_end 18, :desc => "End of office hours, integer, 24 hour format" end
To ease testing of time-based features, we add the excellent Timecop gem to our gemspec, under the development group, and add "require 'timecop'" at the top of spec/spec_helper.rb.
Tests first!
We then add a few tests, taking advantage of Adhearsion testing facility and the generated helpers. The tests describe what we will be implementing in the controller.
spec/hours_controller_spec.rb
require 'spec_helper'
module GreetPlugin
describe HoursController do
let(:mock_call) { mock 'Call' }
subject do
HoursController.new mock_call
end
it 'dials out when inside office hours' do
Timecop.freeze(Time.utc(2012, 3, 8, 12, 0, 0))
subject.expects(:dial).once
subject.run
end
it 'plays a message when outside office hours' do
Timecop.freeze(Time.utc(2012, 3, 8, 22, 0, 0))
subject.expects(:play).once
subject.run
end
end
end
Our CallController
Last but not least, we build the actual CallController.
lib/greet_plugin/hours_controller.rb
module GreetPlugin
class HoursController < Adhearsion::CallController
def run
if Time.now.hour.between?(Adhearsion.config[:greet_plugin].office_hours_start, Adhearsion.config[:greet_plugin].office_hours_end)
dial "SIP/101"
else
play "Office is open between #{Adhearsion.config[:greet_plugin].office_hours_start} and #{Adhearsion.config[:greet_plugin].office_hours_end}."
end
end
end
end
Routes
To allow our application to reach the controller, we add routes in its configuration. For the purpose of this post, we will simply be using the default route.
my_application_dir/config/adhearsion.rb
Adhearsion.router do route 'default', GreetPlugin::HoursController end
Conclusion
In this post we have highlighted how easy it is to add reusable and tested functionality to your Adhearsion applications using plugins. The next post will deal with adding custom generators to your plugin.