Plugins in Adhearsion 2.0 – Part 1

The ability to easily add reusable functionality to a framework is one of the most important features. Plugins in Adhearsion 2.0 have been completely rebuilt to better suit the new structure and allow them to provide a wider variety of features. Controller methods, initializer code, specific configuration, rake tasks and included generators all are possible with the new plugin classes. In this first post we will be generating a plugin using the CLI and looking through the resulting code.

Components in Adhearsion 1.x

The previous release of Adhearsion was deeply tied to the concept of a dialplan and related contexts, like the dialplan itself or event handling code. That brought the component architecture to simply define a series of methods that were available in some or all of the contexts. Components, however easy to create and use, were limited in scope and very difficult to properly test. Adhearsion 2.0 completely removes support for components in favor of plugins.

What is an Adhearsion 2.0 Plugin?

A plugin, in Adhearsion as in many other Ruby frameworks, simply represents a collection of code, usually in the form of modules used as mixins to CallControllers. The library is packaged as a gem to facilitate its use, reuse, and sharing with the community. In addition to providing classes and modules, a plugin can bring a series of extra functionalities that will be demonstrated below.

Anatomy of a Plugin

The easiest way to create a skeleton plugin is to use the Adhearsion command “ahn generate”.
By running the following ahn generate plugin GreetPlugin a directory named greet_plugin will be created in the current working directory. The plugin itself, being a gem, can reside anywhere, unlike components that needed to be inside the application directory. The output from this command should show the files being created, like this:

      create  greet_plugin
      create  greet_plugin/lib
      create  greet_plugin/lib/greet_plugin
      create  greet_plugin/spec
      create  greet_plugin/greet_plugin.gemspec
      create  greet_plugin/Rakefile
      create  greet_plugin/README.md
      create  greet_plugin/Gemfile
      create  greet_plugin/lib/greet_plugin.rb
      create  greet_plugin/lib/greet_plugin/version.rb
      create  greet_plugin/lib/greet_plugin/plugin.rb
      create  greet_plugin/lib/greet_plugin/controller_methods.rb
      create  greet_plugin/spec/spec_helper.rb
      create  greet_plugin/spec/greet_plugin/controller_methods_spec.rb

Gem Plugin Structure

The .gemspec file contains information on your plugin, required dependencies and other necessary data. Enter your contact information, the name and description of your plugin and list any dependencies in greet_plugin.gemspec to have a fully functional gem. The README is customarily formatted in Markdown and its use is strongly encouraged to help people understand how to use your plugin. The Rakefile contains tasks that pertain to the plugin gem itself, such as running unit tests. Note that it is separate from adding tasks to Adhearsion applications; this will be covered later.

Plugin Files

The entry point for the plugin, as usual with gems, resides in lib/greet_plugin.rb. It is mainly composed of requires for the plugin classes and modules. When adding functionality to a plugin, it will need to be require‘d here to be available. Plugins are namespaced by package name to avoid conflicts.

# lib/greet_plugin.rb
module GreetPlugin
  require "greet_plugin/version"
  require "greet_plugin/plugin"
  require "greet_plugin/controller_methods"
end

In this example Adhearsion plugin:

  • version.rb contains the current version number for the plugin, and is used during packaging.
  • plugin.rb contains the hooks into the Adhearsion framework that are called when the plugin is loaded by the Adhearsion application.
  • controller_methods.rb contains a module that gets mixed into the base CallController class, making its methods available to all calls running in Adhearsion.
# lib/greet_plugin/plugin.rb
module GreetPlugin
  class Plugin < Adhearsion::Plugin
    # Actions to perform when the plugin is loaded
    #
    init :greet_plugin do
      logger.info "GreetPlugin has been loaded"
    end

    # Basic configuration for the plugin
    #
    config :greet_plugin do
      greeting "Hello", :desc => "What to use to greet users"
    end

    # Defining a Rake task is easy
    # The following can be invoked with:
    #   rake greet_plugin:info
    #
    tasks do
      namespace :greet_plugin do
        desc "Prints the PluginTemplate information"
        task :info do
          STDOUT.puts "GreetPlugin plugin v. #{VERSION}"
        end
      end
    end

  end
end

In plugin.rb there are three important blocks shown. The first is the #init block which is invoked by Adhearsion when the plugin is first loaded. In our case, all this does is write an informational message to the log showing that the plugin was, in fact, loaded. The second is the #config block that registers configuration options with the Adhearsion framework. This is important because it allows your users to easily discover the possible configuration options for your plugin by simply running rake config:show within their Adhearsion applications. It also allows you to document the configuration options and set default values. The third block is the #tasks block, which registers Rake tasks to be available within the Adhearsion application. In this case it adds a Rake task called greet_plugin:info that prints the version number of the plugin.

Plugin Methods: #init and #run

The #init method defines code that is run when the plugin is loaded. Every plugin goes through two separate phases before it is ready to run. The plugin first gets initialized through #init, which sets up any basic requirements or configuration. Later, when the Adhearsion framework has booted, the #run block is called to start the plugin. An example of using the #init and #run methods might be an IRC plugin. In the #init method, the IRC class is instantiated and configured, but no connection to the server is made. Then in #run the actual connection is opened and the service begins. Both methods are optional, but if they are defined, the mandatory arguments are the name of the plugin as a symbol and a block to provide the code to be run. A plugin can also request to be initialized before or after another plugin by name, using the :before and :after options passed as an hash to #init and/or #run.

Plugin Methods: #config

The #config block allows a plugin to define configuration values in a customizable and self-documenting way. Every configuration line has the key, followed by a default value, optionally followed by a :desc key to allow for a description. rake config:show in an application directory will display all config keys provided by the core and the plugins, with their descriptions.

A config line can also validate supplied values with a transform:

   max_connections 5, :desc => "Maximum number of connections to make", :transform => lambda { |v| v.to_i }

The :transform will be used to modify the configuration value after it is read from the end-user’s setting.

Plugin Methods: #tasks

The #tasks method allows the plugin developer to define Rake tasks to be made available inside an Adhearsion application. Task definitions follow Rake conventions.

What Next?

In this post we have covered the basic tasks necessary to create a new plugin, identify it to Rubygems with metadata, and provide hooks for loading into Adhearsion applications. In the next post, we will cover how your code may be used by Adhearsion applications as well as testing for plugins.

Continue reading Part 2 here

Subscribe to our mailing list

* indicates required
I want to read about...
Email Format

2 thoughts on “Plugins in Adhearsion 2.0 – Part 1

What do you think?