Professional Documents
Culture Documents
Plugin Development
Nick Plante ::
Voices That Matter
Professional Ruby Conference
Pagination
Will Paginate, Paginating Find
Asynchronous Processing
Workling, Background Job, etc
View Helpers
Lightbox helper, Flash media player helper, etc
Why Develop Plugins?
Internal re-use, productivity booster
Opportunity to refactor, clean up
project code
is_rateable vs. gobs of in-line ratings code
How would we
implement this
in a Book model
for a plain old
Rails project?
ISBN-13: 978-1-59059-993-8
ISBN-10: 1-59059-993-4
class Book < ActiveRecord::Base
validates_presence_of :title, :author, :isbn
def validate
unless self.isbn_valid?
errors.add(:isbn, "is not a valid ISBN code")
end
end
def isbn_valid?
!self.isbn.nil? && (self.isbn10_valid? || self.isbn13_valid?)
end
# ...
end
Wait! There’s
More!
# more code in your model…
def isbn10_valid?
if (self || '').isbn.match(ISBN10_REGEX)
isbn_values = self.isbn.upcase.gsub(/\ |-/, '').split('')
check_digit = isbn_values.pop # last digit is check
check_digit = (check_digit == 'X') ? 10 : check_digit.to_i
sum = 0
isbn_values.each_with_index do |value, index|
sum += (index + 1) * value.to_i
end
sum = 0
isbn_values.each_with_index do |value, index|
multiplier = (index % 2 == 0) ? 1 : 3
sum += multiplier * value.to_i
end
validates_http_url :link
def index
@books = Book.paginate :page => params[:page],
:per_page => 20
end
end
ActionView Examples (View
Helpers)
require ‘isbn_validation’
in vendor/plugins/isbn_validation:
- lib/
- isbn_validation.rb
- tasks/
- isbn_validation_tasks.rake
- test/
- isbn_validation_test.rb
- README
- MIT-LICENSE
- Rakefile
- init.rb
- install.rb
- uninstall.rb
Plugin Hooks: Install.rb
Auto-run when plugin is installed
via script/plugin install
Potential Uses
DisplayREADME
Copy needed images, styles, scripts
Remove them with uninstall.rb
Plugin Hooks: Init.rb
Runs whenever your application is started
Use it to inject plugin code into the
framework
Add class methods in IsbnValidation module
to AR::Base
ActiveRecord::Base.class_eval do
extend IsbnValidation
end
Adding Instance Methods?
Use include instead of extend
def self.included(base)
base.extend(ClassMethods)
end
Should I Test My Plugin?
require 'rubygems'
require 'test/unit'
require 'active_record'
require "#{File.dirname(__FILE__)}/../init"
config = YAML::load(IO.read(
File.dirname(__FILE__) + '/database.yml'))
ActiveRecord::Base.logger = Logger.new(
File.dirname(__FILE__) + "/debug.log")
ActiveRecord::Base.establish_connection(
config[ENV['DB'] || 'sqlite3'])
def test_isbn10_should_pass_check_digit_verification
@book.isbn = '159059993-4'
assert @book.valid?
end
# ...
end
Rspec fan?
Use
Pat Maddox’s RSpec plugin
generator
Uses RSpec stubs instead of Test::Unit
Also sets up isolated database for you!
--with-database
http://github.com/pat-maddox/rspec-plugin-generator
Distributing Plugins
Use a publicly visible Subversion or Git
repository.
It’s that easy.
Options:
Google Code (Subversion)
RubyForge (Subversion)
GitHub (Git) <= Recommended!
ruby script/plugin install \
git://github.com/zapnap/isbn_validation.git
Distributing Plugins as Gems?
Canalso package plugins as
RubyGems
In environment.rb:
config.gem “zapnap-isbn_validation”,
:source => “http://gems.github.com”,
:version => “>= 0.1.1”,
:lib => “isbn_validation”
rake gems:unpack:dependencies
Gem Advantages
Reasonsto prefer Gems for
packaging
Properversioning
Dependency management
s.platform = Gem::Platform::RUBY
s.add_dependency(%q<activerecord>, [">= 2.1.2"])
end
Generator plugins
Plugin patterns
alias_method_chain
Conclusion ( PDI )
Everyplugin will require different strategies
for development & testing
Don’t be afraid to read the Rails source
Fortunately,
lots of OSS plugins to look to
for examples -- no better way to learn!
http://github.com
http://agilewebdevelopment.com/plugins
http://railslodge.com - http://railsify.com
Good luck & don’t forget to let us know about your
new plugin!
Thanks!
nap@ubikorp.com
http://ubikorp.com
nap@zerosum.org
http://blog.zerosum.org
http://github.com/zapnap/isbn_validation