Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Callbacks for your classes

branch: master

Fetching latest commit…

Octocat-spinner-32-eaf2f5

Cannot retrieve the latest commit at this time

Octocat-spinner-32 lib
Octocat-spinner-32 spec
Octocat-spinner-32 README.textile
Octocat-spinner-32 Rakefile
Octocat-spinner-32 aspectory.gemspec
README.textile

Aspectory

Callbacks for Ruby.

How it works

Basically, you get three methods: before, after and around. Each of
these takes a method name, then a splat args of symbols and/or a block. The
symbols/block will be called before/after the method you specified.

The around callback gets passed a proc, in the form of an unnamed block
for handlers that are methods and a block argument for handlers that are
blocks. You must yield or call that block in order for the original
method to be called.

Simple Example

require 'rubygems'
require 'aspectory'
require 'spec'

class Something
  include Aspectory::Hook

  attr_reader :results

  around :foo, :round
  before :foo, :setup
  after  :foo, :teardown

  before :bar do
    @results << :before
  end

  around :bar do |fn|
    @results << :start
    fn.call
    @results << :finish
  end

  after :bar do
    @results << :after
  end

  def initialize
    @results = []
  end

  def foo; @results << :foo; :foo end
  def bar; @results << :bar; :bar end

  def round
    @results << :start
    yield
    @results << :finish
  end

  def setup
    @results << :setup
  end

  def teardown
    @results << :teardown
  end
end

something = Something.new
p something.foo # => :foo
p something.results # => [:setup, :start, :foo, :finish, :teardown]

something = Something.new
p something.bar # => :bar
p something.results # => [:before, :start, :bar, :finish, :after]
something = Something.new
something.foo # => :foo
something.results # => [:setup, :foo, :teardown]

something = Something.new
something.bar # => :bar
something.results # => [:before, :bar, :after]

Calling Methods without Callbacks

You can use the #__PRISTINE__ method to call your methods without any
callbacks, or you can just call method_name_without_callbacks. Here’s an
example with the same example class we used above:

something = Something.new
something.__PRISTINE__(:foo)
something.results # => [:foo]
something.bar_without_callbacks
something.results # => [:foo, :bar]

Preventing a method from being called

If a before callback returns false, then the original method will
not be called. If you want to halt the method being called, but still
want to provide a return value, you can throw the name of the method:

class Something
  before :foo do
    throw :foo, "from the callback"
  end

  def foo
    "from the method"
  end
end

Something.new.foo # => "from the callback"

after callbacks get the results of the method call

Your after callbacks will be passed whatever the original method
call returned:

class Something
  attr_reader :name

  after :foo do |result|
    @name = result.to_s.capitalize
  end
  
  def foo
    :foo
  end
end
something = Something.new
something.name # => nil
something.foo  # => :foo
something.name # => "Foo"

Observing method definitions

If you ever want to see when a method is defined in a class, you can register
observers using the observe method. It can take either a symbol or a regular
expression, then a callback block will be called when the method is defined. The
callback block will be passed the name of the method defined.

To observe class method definitions, you must pass the :meta option.

class Framework
  include Aspectory
  
  # Using a symbol
  observe :admin? do
    puts "Warning! Overriding the admin method can be dangerous."
  end

  # Using a regular expression
  observe(/^_/) do |method_id|
    puts "Warning! The #{method_id} is not part of the public API!"
  end
  
  # Observing a class method definition
  observe(:find_by_name, :meta => true) do
    puts "The method :find_by_name already exists in the framework."
  end
  
  # Observing multiple occurrences of a method definition
  observe(/^show_by_/, :times => true) do |method_id|
    puts "dynamic showing defined: #{method_id}"
  end
end

Why?

Why not?

Requirements

  • nakajima gem install nakajima-nakajima --source=http://gems.github.com

TODO

  • Filters (:if and/or :unless)
  • Compilable callbacks (http://gist.github.com/50397)
  • Maybe don’t worry about @instance_eval@’ing or @instance_exec@’ing callback blocks.
  • Figure out a way to get it working with metaclasses
  • Spec suite could definitely be more readable

Alternatives:

View the CI build

(c) Copyright 2008 Pat Nakajima, released under MIT License.

Something went wrong with that request. Please try again.