Skip to content

nakajima/aspectory

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

55 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

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:

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

About

Callbacks for your classes

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages