From 6d87cd028b32570973450424db164e5405a0ee13 Mon Sep 17 00:00:00 2001
From: Xavier Noria <fxn@hashref.com>
Date: Sat, 17 Mar 2012 08:32:49 -0700
Subject: moves the guides up to the root directory

---
 guides/source/plugins.textile | 432 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 432 insertions(+)
 create mode 100644 guides/source/plugins.textile

(limited to 'guides/source/plugins.textile')

diff --git a/guides/source/plugins.textile b/guides/source/plugins.textile
new file mode 100644
index 0000000000..97b4eca779
--- /dev/null
+++ b/guides/source/plugins.textile
@@ -0,0 +1,432 @@
+h2. The Basics of Creating Rails Plugins
+
+A Rails plugin is either an extension or a modification of the core framework. Plugins provide:
+
+* a way for developers to share bleeding-edge ideas without hurting the stable code base
+* a segmented architecture so that units of code can be fixed or updated on their own release schedule
+* an outlet for the core developers so that they don’t have to include every cool new feature under the sun
+
+After reading this guide you should be familiar with:
+
+* Creating a plugin from scratch
+* Writing and running tests for the plugin
+
+This guide describes how to build a test-driven plugin that will:
+
+* Extend core ruby classes like Hash and String
+* Add methods to ActiveRecord::Base in the tradition of the 'acts_as' plugins
+* Give you information about where to put generators in your plugin.
+
+For the purpose of this guide pretend for a moment that you are an avid bird watcher.
+Your favorite bird is the Yaffle, and you want to create a plugin that allows other developers to share in the Yaffle
+goodness.
+
+endprologue.
+
+h3. Setup
+
+Before you continue, take a moment to decide if your new plugin will be potentially shared across different Rails applications.
+
+* If your plugin is specific to your application, your new plugin will be a _vendored plugin_.
+* If you think your plugin may be used across applications, build it as a _gemified plugin_.
+
+h4. Generate a gemified plugin.
+
+Writing your Rails plugin as a gem, rather than as a vendored plugin,
+ lets you share your plugin across different rails applications using
+ RubyGems and Bundler.
+
+Rails 3.1 ships with a +rails plugin new+ command which creates a
+ skeleton for developing any kind of Rails extension with the ability
+ to run integration tests using a dummy Rails application. See usage
+ and options by asking for help:
+
+<shell>
+$ rails plugin --help
+</shell>
+
+h3. Testing your newly generated plugin
+
+You can navigate to the directory that contains the plugin, run the +bundle install+ command
+ and run the one generated test using the +rake+ command.
+
+You should see:
+
+<shell>
+	2 tests, 2 assertions, 0 failures, 0 errors, 0 skips
+</shell>
+
+This will tell you that everything got generated properly and you are ready to start adding functionality.
+
+h3. Extending Core Classes
+
+This section will explain how to add a method to String that will be available anywhere in your rails application.
+
+In this example you will add a method to String named +to_squawk+. To begin, create a new test file with a few assertions:
+
+<ruby>
+# yaffle/test/core_ext_test.rb
+
+require 'test_helper'
+
+class CoreExtTest < Test::Unit::TestCase
+  def test_to_squawk_prepends_the_word_squawk
+    assert_equal "squawk! Hello World", "Hello World".to_squawk
+  end
+end
+</ruby>
+
+Run +rake+ to run the test. This test should fail because we haven't implemented the +to_squawk+ method:
+
+<shell>
+	  1) Error:
+	test_to_squawk_prepends_the_word_squawk(CoreExtTest):
+	NoMethodError: undefined method `to_squawk' for "Hello World":String
+	    test/core_ext_test.rb:5:in `test_to_squawk_prepends_the_word_squawk'
+</shell>
+
+Great - now you are ready to start development.
+
+Then in +lib/yaffle.rb+ require +lib/core_ext+:
+
+<ruby>
+# yaffle/lib/yaffle.rb
+
+require "yaffle/core_ext"
+
+module Yaffle
+end
+</ruby>
+
+Finally, create the +core_ext.rb+ file and add the +to_squawk+ method:
+
+<ruby>
+# yaffle/lib/yaffle/core_ext.rb
+
+String.class_eval do
+  def to_squawk
+    "squawk! #{self}".strip
+  end
+end
+</ruby>
+
+To test that your method does what it says it does, run the unit tests with +rake+ from your plugin directory.
+
+<shell>
+	3 tests, 3 assertions, 0 failures, 0 errors, 0 skips
+</shell>
+
+To see this in action, change to the test/dummy directory, fire up a console and start squawking:
+
+<shell>
+$ rails console
+>> "Hello World".to_squawk
+=> "squawk! Hello World"
+</shell>
+
+h3. Add an "acts_as" Method to Active Record
+
+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 Active Record models.
+
+To begin, set up your files so that you have:
+
+<ruby>
+# yaffle/test/acts_as_yaffle_test.rb
+
+require 'test_helper'
+
+class ActsAsYaffleTest < Test::Unit::TestCase
+end
+</ruby>
+
+<ruby>
+# yaffle/lib/yaffle.rb
+
+require "yaffle/core_ext"
+require 'yaffle/acts_as_yaffle'
+
+module Yaffle
+end
+</ruby>
+
+<ruby>
+# yaffle/lib/yaffle/acts_as_yaffle.rb
+
+module Yaffle
+  module ActsAsYaffle
+    # your code will go here
+  end
+end
+</ruby>
+
+h4. Add a Class Method
+
+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'.
+
+To start out, write a failing test that shows the behavior you'd like:
+
+<ruby>
+# yaffle/test/acts_as_yaffle_test.rb
+
+require 'test_helper'
+
+class ActsAsYaffleTest < Test::Unit::TestCase
+
+  def test_a_hickwalls_yaffle_text_field_should_be_last_squawk
+    assert_equal :last_squawk, Hickwall.yaffle_text_field
+  end
+
+  def test_a_wickwalls_yaffle_text_field_should_be_last_tweet
+    assert_equal :last_tweet, Wickwall.yaffle_text_field
+  end
+
+end
+</ruby>
+
+When you run +rake+, you should see the following:
+
+<shell>
+	  1) Error:
+	test_a_hickwalls_yaffle_text_field_should_be_last_squawk(ActsAsYaffleTest):
+	NameError: uninitialized constant ActsAsYaffleTest::Hickwall
+	    test/acts_as_yaffle_test.rb:6:in `test_a_hickwalls_yaffle_text_field_should_be_last_squawk'
+
+	  2) Error:
+	test_a_wickwalls_yaffle_text_field_should_be_last_tweet(ActsAsYaffleTest):
+	NameError: uninitialized constant ActsAsYaffleTest::Wickwall
+	    test/acts_as_yaffle_test.rb:10:in `test_a_wickwalls_yaffle_text_field_should_be_last_tweet'
+
+	5 tests, 3 assertions, 0 failures, 2 errors, 0 skips
+</shell>
+
+This tells us that we don't have the necessary models (Hickwall and Wickwall) that we are trying to test.
+We can easily generate these models in our "dummy" Rails application by running the following commands from the
+test/dummy directory:
+
+<shell>
+$ cd test/dummy
+$ rails generate model Hickwall last_squawk:string
+$ rails generate model Wickwall last_squawk:string last_tweet:string
+</shell>
+
+Now you can create the necessary database tables in your testing database by navigating to your dummy app
+and migrating the database. First
+
+<shell>
+$ cd test/dummy
+$ rake db:migrate
+$ rake db:test:prepare
+</shell>
+
+While you are here, change the Hickwall and Wickwall models so that they know that they are supposed to act
+like yaffles.
+
+<ruby>
+# test/dummy/app/models/hickwall.rb
+
+class Hickwall < ActiveRecord::Base
+  acts_as_yaffle
+end
+
+# test/dummy/app/models/wickwall.rb
+
+class Wickwall < ActiveRecord::Base
+  acts_as_yaffle :yaffle_text_field => :last_tweet
+end
+
+</ruby>
+
+We will also add code to define the acts_as_yaffle method.
+
+<ruby>
+# yaffle/lib/yaffle/acts_as_yaffle.rb
+module Yaffle
+  module ActsAsYaffle
+    extend ActiveSupport::Concern
+
+    included do
+    end
+
+    module ClassMethods
+      def acts_as_yaffle(options = {})
+        # your code will go here
+      end
+    end
+  end
+end
+
+ActiveRecord::Base.send :include, Yaffle::ActsAsYaffle
+</ruby>
+
+You can then return to the root directory (+cd ../..+) of your plugin and rerun the tests using +rake+.
+
+<shell>
+	  1) Error:
+	test_a_hickwalls_yaffle_text_field_should_be_last_squawk(ActsAsYaffleTest):
+	NoMethodError: undefined method `yaffle_text_field' for #<Class:0x000001016661b8>
+	    /Users/xxx/.rvm/gems/ruby-1.9.2-p136@xxx/gems/activerecord-3.0.3/lib/active_record/base.rb:1008:in `method_missing'
+	    test/acts_as_yaffle_test.rb:5:in `test_a_hickwalls_yaffle_text_field_should_be_last_squawk'
+
+	  2) Error:
+	test_a_wickwalls_yaffle_text_field_should_be_last_tweet(ActsAsYaffleTest):
+	NoMethodError: undefined method `yaffle_text_field' for #<Class:0x00000101653748>
+	    Users/xxx/.rvm/gems/ruby-1.9.2-p136@xxx/gems/activerecord-3.0.3/lib/active_record/base.rb:1008:in `method_missing'
+	    test/acts_as_yaffle_test.rb:9:in `test_a_wickwalls_yaffle_text_field_should_be_last_tweet'
+
+	5 tests, 3 assertions, 0 failures, 2 errors, 0 skips
+
+</shell>
+
+Getting closer... Now we will implement the code of the acts_as_yaffle method to make the tests pass.
+
+<ruby>
+# yaffle/lib/yaffle/acts_as_yaffle.rb
+
+module Yaffle
+  module ActsAsYaffle
+   extend ActiveSupport::Concern
+
+    included do
+    end
+
+    module ClassMethods
+      def acts_as_yaffle(options = {})
+        cattr_accessor :yaffle_text_field
+        self.yaffle_text_field = (options[:yaffle_text_field] || :last_squawk).to_s
+      end
+    end
+  end
+end
+
+ActiveRecord::Base.send :include, Yaffle::ActsAsYaffle
+</ruby>
+
+When you run +rake+ you should see the tests all pass:
+
+<shell>
+	5 tests, 5 assertions, 0 failures, 0 errors, 0 skips
+</shell>
+
+h4. Add an Instance Method
+
+This plugin will add a method named 'squawk' to any Active Record object that calls 'acts_as_yaffle'. The 'squawk'
+method will simply set the value of one of the fields in the database.
+
+To start out, write a failing test that shows the behavior you'd like:
+
+<ruby>
+# yaffle/test/acts_as_yaffle_test.rb
+require 'test_helper'
+
+class ActsAsYaffleTest < Test::Unit::TestCase
+
+  def test_a_hickwalls_yaffle_text_field_should_be_last_squawk
+    assert_equal "last_squawk", Hickwall.yaffle_text_field
+  end
+
+  def test_a_wickwalls_yaffle_text_field_should_be_last_tweet
+    assert_equal "last_tweet", Wickwall.yaffle_text_field
+  end
+
+  def test_hickwalls_squawk_should_populate_last_squawk
+    hickwall = Hickwall.new
+    hickwall.squawk("Hello World")
+    assert_equal "squawk! Hello World", hickwall.last_squawk
+  end
+
+  def test_wickwalls_squawk_should_populate_last_tweet
+    wickwall = Wickwall.new
+    wickwall.squawk("Hello World")
+    assert_equal "squawk! Hello World", wickwall.last_tweet
+  end
+end
+</ruby>
+
+Run the test to make sure the last two tests fail with an error that contains "NoMethodError: undefined method `squawk'",
+then update 'acts_as_yaffle.rb' to look like this:
+
+<ruby>
+# yaffle/lib/yaffle/acts_as_yaffle.rb	
+
+module Yaffle
+  module ActsAsYaffle
+    extend ActiveSupport::Concern
+
+    included do
+    end
+
+    module ClassMethods
+      def acts_as_yaffle(options = {})
+        cattr_accessor :yaffle_text_field
+        self.yaffle_text_field = (options[:yaffle_text_field] || :last_squawk).to_s
+
+        include Yaffle::ActsAsYaffle::LocalInstanceMethods
+      end
+    end
+
+    module LocalInstanceMethods
+      def squawk(string)
+        write_attribute(self.class.yaffle_text_field, string.to_squawk)
+      end
+    end
+  end
+end
+
+ActiveRecord::Base.send :include, Yaffle::ActsAsYaffle
+</ruby>
+
+Run +rake+ one final time and you should see:
+
+<shell>
+	7 tests, 7 assertions, 0 failures, 0 errors, 0 skips
+</shell>
+
+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 <tt>send("#{self.class.yaffle_text_field}=", string.to_squawk)</tt>.
+
+h3. Generators
+
+Generators can be included in your gem simply by creating them in a lib/generators directory of your plugin. More information about
+the creation of generators can be found in the "Generators Guide":generators.html
+
+h3. Publishing your Gem
+
+Gem plugins currently in development can easily be shared from any Git repository. To share the Yaffle gem with others, simply
+commit the code to a Git repository (like Github) and add a line to the Gemfile of the application in question:
+
+<ruby>
+gem 'yaffle', :git => 'git://github.com/yaffle_watcher/yaffle.git'
+</ruby>
+
+After running +bundle install+, your gem functionality will be available to the application.
+
+When the gem is ready to be shared as a formal release, it can be published to "RubyGems":http://www.rubygems.org.
+For more information about publishing gems to RubyGems, see: "http://blog.thepete.net/2010/11/creating-and-publishing-your-first-ruby.html":http://blog.thepete.net/2010/11/creating-and-publishing-your-first-ruby.html
+
+h3. RDoc Documentation
+
+Once your plugin is stable and you are ready to deploy do everyone else a favor and document it! Luckily, writing documentation for your plugin is easy.
+
+The first step is to update the README file with detailed information about how to use your plugin. A few key things to include are:
+
+* Your name
+* How to install
+* How to add the functionality to the app (several examples of common use cases)
+* Warnings, gotchas or tips that might help users and save them time
+
+Once your README is solid, go through and add rdoc comments to all of the methods that developers will use. It's also customary to add '#:nodoc:' comments to those parts of the code that are not included in the public api.
+
+Once your comments are good to go, navigate to your plugin directory and run:
+
+<shell>
+$ rake rdoc
+</shell>
+
+h4. References
+
+* "Developing a RubyGem using Bundler":https://github.com/radar/guides/blob/master/gem-development.md
+* "Using Gemspecs As Intended":http://yehudakatz.com/2010/04/02/using-gemspecs-as-intended/
+* "Gemspec Reference":http://docs.rubygems.org/read/chapter/20
+* "GemPlugins":http://www.mbleigh.com/2008/06/11/gemplugins-a-brief-introduction-to-the-future-of-rails-plugins
-- 
cgit v1.2.3

