1 == Add an `acts_as_yaffle` method to Active Record ==
3 A common pattern in plugins is to add a method called 'acts_as_something' to models. In this case, you want to write a method called 'acts_as_yaffle' that adds a 'squawk' method to your models.
5 To begin, set up your files so that you have:
7 *vendor/plugins/yaffle/test/acts_as_yaffle_test.rb*
10 ------------------------------------------------------
11 require File.dirname(__FILE__) + '/test_helper.rb'
13 class ActsAsYaffleTest < Test::Unit::TestCase
15 ------------------------------------------------------
17 *vendor/plugins/yaffle/lib/yaffle.rb*
20 ------------------------------------------------------
21 require 'yaffle/acts_as_yaffle'
22 ------------------------------------------------------
24 *vendor/plugins/yaffle/lib/yaffle/acts_as_yaffle.rb*
27 ------------------------------------------------------
29 # your code will go here
31 ------------------------------------------------------
33 Note that after requiring 'acts_as_yaffle' you also have to include it into ActiveRecord::Base so that your plugin methods will be available to the rails models.
35 One of the most common plugin patterns for 'acts_as_yaffle' plugins is to structure your file like so:
37 *vendor/plugins/yaffle/lib/yaffle/acts_as_yaffle.rb*
40 ------------------------------------------------------
42 def self.included(base)
43 base.send :extend, ClassMethods
47 # any method placed here will apply to classes, like Hickwall
49 send :include, InstanceMethods
53 module InstanceMethods
54 # any method placed here will apply to instaces, like @hickwall
57 ------------------------------------------------------
59 With structure you can easily separate the methods that will be used for the class (like `Hickwall.some_method`) and the instance (like `@hickwell.some_method`).
61 === Add a class method ===
63 This plugin will expect that you've added a method to your model named 'last_squawk'. However, the plugin users might have already defined a method on their model named 'last_squawk' that they use for something else. This plugin will allow the name to be changed by adding a class method called 'yaffle_text_field'.
65 To start out, write a failing test that shows the behavior you'd like:
67 *vendor/plugins/yaffle/test/acts_as_yaffle_test.rb*
70 ------------------------------------------------------
71 require File.dirname(__FILE__) + '/test_helper.rb'
73 class Hickwall < ActiveRecord::Base
77 class Wickwall < ActiveRecord::Base
78 acts_as_yaffle :yaffle_text_field => :last_tweet
81 class ActsAsYaffleTest < Test::Unit::TestCase
84 def test_a_hickwalls_yaffle_text_field_should_be_last_squawk
85 assert_equal "last_squawk", Hickwall.yaffle_text_field
88 def test_a_wickwalls_yaffle_text_field_should_be_last_tweet
89 assert_equal "last_tweet", Wickwall.yaffle_text_field
92 ------------------------------------------------------
94 To make these tests pass, you could modify your `acts_as_yaffle` file like so:
96 *vendor/plugins/yaffle/lib/yaffle/acts_as_yaffle.rb*
99 ------------------------------------------------------
101 def self.included(base)
102 base.send :extend, ClassMethods
106 def acts_as_yaffle(options = {})
107 cattr_accessor :yaffle_text_field
108 self.yaffle_text_field = (options[:yaffle_text_field] || :last_squawk).to_s
113 ActiveRecord::Base.send :include, Yaffle
114 ------------------------------------------------------
116 === Add an instance method ===
118 This plugin will add a method named 'squawk' to any Active Record objects that call 'acts_as_yaffle'. The 'squawk' method will simply set the value of one of the fields in the database.
120 To start out, write a failing test that shows the behavior you'd like:
122 *vendor/plugins/yaffle/test/acts_as_yaffle_test.rb*
125 ------------------------------------------------------
126 require File.dirname(__FILE__) + '/test_helper.rb'
128 class Hickwall < ActiveRecord::Base
132 class Wickwall < ActiveRecord::Base
133 acts_as_yaffle :yaffle_text_field => :last_tweet
136 class ActsAsYaffleTest < Test::Unit::TestCase
139 def test_a_hickwalls_yaffle_text_field_should_be_last_squawk
140 assert_equal "last_squawk", Hickwall.yaffle_text_field
143 def test_a_wickwalls_yaffle_text_field_should_be_last_tweet
144 assert_equal "last_tweet", Wickwall.yaffle_text_field
147 def test_hickwalls_squawk_should_populate_last_squawk
148 hickwall = Hickwall.new
149 hickwall.squawk("Hello World")
150 assert_equal "squawk! Hello World", hickwall.last_squawk
153 def test_wickwalls_squawk_should_populate_last_tweeted_at
154 wickwall = Wickwall.new
155 wickwall.squawk("Hello World")
156 assert_equal "squawk! Hello World", wickwall.last_tweet
159 ------------------------------------------------------
161 Run this test to make sure the last two tests fail, then update 'acts_as_yaffle.rb' to look like this:
163 *vendor/plugins/yaffle/lib/yaffle/acts_as_yaffle.rb*
166 ------------------------------------------------------
168 def self.included(base)
169 base.send :extend, ClassMethods
173 def acts_as_yaffle(options = {})
174 cattr_accessor :yaffle_text_field
175 self.yaffle_text_field = (options[:yaffle_text_field] || :last_squawk).to_s
176 send :include, InstanceMethods
180 module InstanceMethods
182 write_attribute(self.class.yaffle_text_field, string.to_squawk)
187 ActiveRecord::Base.send :include, Yaffle
188 ------------------------------------------------------
191 NOTE: The use of `write_attribute` to write to the field in model is just one example of how a plugin can interact with the model, and will not always be the right method to use. For example, you could also use `send("#{self.class.yaffle_text_field}=", string.to_squawk)`.