Project

plugins

0.0
No commit activity in last 3 years
No release in over 3 years
A flexible plugins framework.
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
 Dependencies

Development

>= 3.2.0, ~> 3.2
 Project Readme

Gem Version Code Climate Test Coverage Build Status Inch CI

Plugins

Easily add plugins to any library. Plugins takes care of calling before, after and around callbacks for you. All you need to do is wrap your blocks of interest in a Plugins#perform block. Add any number of plugins and any number of callbacks within each plugin.

Installation

Add this to your Gemfile:

gem 'plugins'

Then run

bundle

Or you can install it manually:

gem install plugins

Basic Usage

Define your component

In Plugins, whatever code you're writing that will have plugin support is called a "component". The Plugins::ComponentMixin simplifies integrating with the Plugins gem, although it's not required that you use it.

require 'plugins'
class ComponentWithPlugins
  include Plugins::ComponentMixin

  ##
  # Allow users to use the :logging symbol to reference the LoggingPlugin
  plugin_loader { |plugin|
    case plugin
    when :logging
      LoggingPlugin
    end
  }

  def do_something(*args)
    plugins.perform(:do_something, *args) { |*args|
      puts "Doing something: #{args.inspect}"
    }
  end
end

Define your plugins

class LoggingPlugin < Plugins::Plugin
  def initialize(plugins, file_name=nil)
    super(plugins)
    raise "Logging to a file is't supported yet!" if file_name
  end

  before_do_something do |*args|
    # Any instance methods can be called within callback blocks.
    log("Sending these args: #{args.inspect}")
  end

  around_do_something do |*args|
    begin
      do_something # Magic method to call code being performed
    rescue Exception => e
      log("Exception occurred! #{e.inspect}")
    end
  end

  after_do_something do |*args|
    log("Finished with args: #{args.inspect}")
  end

  private
  def log(message)
    puts "Logging Message: #{message}"
  end
end

Add plugins to your component

component = ComponentWithPlugins.new
component.plugin(:logging) # Utilizes your plugin_loader block.

# This would also work, too.
# But don't both because plugins can be added multiple times!
# component.plugin(LoggingPlugin)

# Alternatively, pass additional args to the Plugin initializer:
# component.plugin(:logging, 'file_name') # LoggingPlugin will raise an exception

component.do_something(1, :two, 'three')
# Should output:
# Logging Message: Sending these args: [1, :two, "three"]
# Doing something: [1, :two, "three"]
# Logging Message: Finished with args: [1, :two, "three"]

User's can also define their own custom plugins:

component.plugin {
  after_do_something {
    puts "Custom plugin!"
  }
}

component.do_something("hello world")
# Should output:
# Logging Message: Sending these args: ["hello world"]
# Doing something: ["hello world"]
# Custom plugin!
# Logging Message: Finished with args: ["hello world"]

Details

Defining a Plugin

There are two ways to define a plugin.

  1. Extending Plugins::Plugin
  2. Plugins::Plugin.create

When defining a plugin, you can define any arbitrary before, around and after callbacks. You can also define multiple callbacks of the same type. They will be executed in reverse order that you defined them.

Extending Plugins::Plugin

require 'plugins'

class CustomPlugin < Plugins::Plugin
  before_i_do_something do |*args|
    puts "I'm about to do something..."
  end
  before_i_do_something { puts "This one will be executed first" }

  around_i_do_something do |*args|
    puts "And you won't like it..."

    perform_i_do_something # Just `i_do_something` will also work.

    puts "But too bad..."
  end

  after_i_do_something do |*args|
    puts "Because I just did it."
    helper_method
  end

  # All *instance* methods will be available.
  def helper_method
    puts "Running helper method"
  end
end

Plugin.create

You can also create on-the-fly plugins:

custom_plugin = Plugins::Plugin.create do
  before_brush_teeth do
    floss
  end

  after_brush_teeth do
    spit
  end
end