the dark artjaoo.dk/dl/jaoo-ruby-oslo-2008/slides/rubyfools... · • ruby class definitions are...
TRANSCRIPT
![Page 1: The Dark Artjaoo.dk/dl/jaoo-ruby-oslo-2008/slides/RubyFools... · • Ruby class definitions are code ... • use extend to add class method • include the new behaviour by including](https://reader034.vdocuments.net/reader034/viewer/2022052009/601de4d072feaa1e2c7b8abc/html5/thumbnails/1.jpg)
The Dark Artof Rails Plugins
James Adamreevoo.com
![Page 2: The Dark Artjaoo.dk/dl/jaoo-ruby-oslo-2008/slides/RubyFools... · • Ruby class definitions are code ... • use extend to add class method • include the new behaviour by including](https://reader034.vdocuments.net/reader034/viewer/2022052009/601de4d072feaa1e2c7b8abc/html5/thumbnails/2.jpg)
Anatomy of a plugin
Photo: http://flickr.com/photos/guccibear2005/206352128/
![Page 3: The Dark Artjaoo.dk/dl/jaoo-ruby-oslo-2008/slides/RubyFools... · • Ruby class definitions are code ... • use extend to add class method • include the new behaviour by including](https://reader034.vdocuments.net/reader034/viewer/2022052009/601de4d072feaa1e2c7b8abc/html5/thumbnails/3.jpg)
![Page 4: The Dark Artjaoo.dk/dl/jaoo-ruby-oslo-2008/slides/RubyFools... · • Ruby class definitions are code ... • use extend to add class method • include the new behaviour by including](https://reader034.vdocuments.net/reader034/viewer/2022052009/601de4d072feaa1e2c7b8abc/html5/thumbnails/4.jpg)
lib
![Page 5: The Dark Artjaoo.dk/dl/jaoo-ruby-oslo-2008/slides/RubyFools... · • Ruby class definitions are code ... • use extend to add class method • include the new behaviour by including](https://reader034.vdocuments.net/reader034/viewer/2022052009/601de4d072feaa1e2c7b8abc/html5/thumbnails/5.jpg)
lib
• added to the $LOAD_PATH
• classes auto-loaded via Dependencies magic
• order determined by config.plugins
![Page 6: The Dark Artjaoo.dk/dl/jaoo-ruby-oslo-2008/slides/RubyFools... · • Ruby class definitions are code ... • use extend to add class method • include the new behaviour by including](https://reader034.vdocuments.net/reader034/viewer/2022052009/601de4d072feaa1e2c7b8abc/html5/thumbnails/6.jpg)
init.rb
![Page 7: The Dark Artjaoo.dk/dl/jaoo-ruby-oslo-2008/slides/RubyFools... · • Ruby class definitions are code ... • use extend to add class method • include the new behaviour by including](https://reader034.vdocuments.net/reader034/viewer/2022052009/601de4d072feaa1e2c7b8abc/html5/thumbnails/7.jpg)
init.rb
• evaluated near the end of rails initialization
• evaluated in order of config.plugins
• special variables available
• config, directory, name - see source of Rails::Plugin
![Page 8: The Dark Artjaoo.dk/dl/jaoo-ruby-oslo-2008/slides/RubyFools... · • Ruby class definitions are code ... • use extend to add class method • include the new behaviour by including](https://reader034.vdocuments.net/reader034/viewer/2022052009/601de4d072feaa1e2c7b8abc/html5/thumbnails/8.jpg)
tasks[un]install.rb
testgenerators
![Page 9: The Dark Artjaoo.dk/dl/jaoo-ruby-oslo-2008/slides/RubyFools... · • Ruby class definitions are code ... • use extend to add class method • include the new behaviour by including](https://reader034.vdocuments.net/reader034/viewer/2022052009/601de4d072feaa1e2c7b8abc/html5/thumbnails/9.jpg)
Writing Plugins
![Page 10: The Dark Artjaoo.dk/dl/jaoo-ruby-oslo-2008/slides/RubyFools... · • Ruby class definitions are code ... • use extend to add class method • include the new behaviour by including](https://reader034.vdocuments.net/reader034/viewer/2022052009/601de4d072feaa1e2c7b8abc/html5/thumbnails/10.jpg)
Sharing Code
lib tasks
![Page 11: The Dark Artjaoo.dk/dl/jaoo-ruby-oslo-2008/slides/RubyFools... · • Ruby class definitions are code ... • use extend to add class method • include the new behaviour by including](https://reader034.vdocuments.net/reader034/viewer/2022052009/601de4d072feaa1e2c7b8abc/html5/thumbnails/11.jpg)
Adding new behaviour
![Page 12: The Dark Artjaoo.dk/dl/jaoo-ruby-oslo-2008/slides/RubyFools... · • Ruby class definitions are code ... • use extend to add class method • include the new behaviour by including](https://reader034.vdocuments.net/reader034/viewer/2022052009/601de4d072feaa1e2c7b8abc/html5/thumbnails/12.jpg)
What we’re aiming forclass Personend
class Programmer < Personend
class ProjectManager < Personend
p = Programmer.newp.hello # => "hi!"
ProjectManager.is_friendly? # => true
![Page 13: The Dark Artjaoo.dk/dl/jaoo-ruby-oslo-2008/slides/RubyFools... · • Ruby class definitions are code ... • use extend to add class method • include the new behaviour by including](https://reader034.vdocuments.net/reader034/viewer/2022052009/601de4d072feaa1e2c7b8abc/html5/thumbnails/13.jpg)
Modules
module Friendly def hello "hi from #{self}" endend
![Page 14: The Dark Artjaoo.dk/dl/jaoo-ruby-oslo-2008/slides/RubyFools... · • Ruby class definitions are code ... • use extend to add class method • include the new behaviour by including](https://reader034.vdocuments.net/reader034/viewer/2022052009/601de4d072feaa1e2c7b8abc/html5/thumbnails/14.jpg)
require 'friendly'
class Person include Friendlyend
alice = Programmer.newalice.hello # => "hi from #<Programmer#123>"
![Page 15: The Dark Artjaoo.dk/dl/jaoo-ruby-oslo-2008/slides/RubyFools... · • Ruby class definitions are code ... • use extend to add class method • include the new behaviour by including](https://reader034.vdocuments.net/reader034/viewer/2022052009/601de4d072feaa1e2c7b8abc/html5/thumbnails/15.jpg)
Methods in classes...
class Person def hello "hi from #{self}" endend
![Page 16: The Dark Artjaoo.dk/dl/jaoo-ruby-oslo-2008/slides/RubyFools... · • Ruby class definitions are code ... • use extend to add class method • include the new behaviour by including](https://reader034.vdocuments.net/reader034/viewer/2022052009/601de4d072feaa1e2c7b8abc/html5/thumbnails/16.jpg)
... and in modules
module Friendly def hello "hi from #{self}" endend
![Page 17: The Dark Artjaoo.dk/dl/jaoo-ruby-oslo-2008/slides/RubyFools... · • Ruby class definitions are code ... • use extend to add class method • include the new behaviour by including](https://reader034.vdocuments.net/reader034/viewer/2022052009/601de4d072feaa1e2c7b8abc/html5/thumbnails/17.jpg)
Defining class methods...
class Person def self.is_friendly? true endend
![Page 18: The Dark Artjaoo.dk/dl/jaoo-ruby-oslo-2008/slides/RubyFools... · • Ruby class definitions are code ... • use extend to add class method • include the new behaviour by including](https://reader034.vdocuments.net/reader034/viewer/2022052009/601de4d072feaa1e2c7b8abc/html5/thumbnails/18.jpg)
... and in modules?
module Friendly def self.is_friendly? true end def hello "hi from #{self}" endend
![Page 19: The Dark Artjaoo.dk/dl/jaoo-ruby-oslo-2008/slides/RubyFools... · • Ruby class definitions are code ... • use extend to add class method • include the new behaviour by including](https://reader034.vdocuments.net/reader034/viewer/2022052009/601de4d072feaa1e2c7b8abc/html5/thumbnails/19.jpg)
Not quite :(
class Person include Friendlyend
Person.is_friendly? # ~> undefined method `is_friendly?' for Person:Class (NoMethodError)
![Page 20: The Dark Artjaoo.dk/dl/jaoo-ruby-oslo-2008/slides/RubyFools... · • Ruby class definitions are code ... • use extend to add class method • include the new behaviour by including](https://reader034.vdocuments.net/reader034/viewer/2022052009/601de4d072feaa1e2c7b8abc/html5/thumbnails/20.jpg)
It’s all about selfmodule Friendly def self.is_friendly? true endend
Friendly.is_friendly? # => true
![Page 21: The Dark Artjaoo.dk/dl/jaoo-ruby-oslo-2008/slides/RubyFools... · • Ruby class definitions are code ... • use extend to add class method • include the new behaviour by including](https://reader034.vdocuments.net/reader034/viewer/2022052009/601de4d072feaa1e2c7b8abc/html5/thumbnails/21.jpg)
Try this insteadmodule Friendly::ClassMethods def is_friendly? true endend
class Person extend Friendly::ClassMethodsend
Person.is_friendly? # => true
![Page 22: The Dark Artjaoo.dk/dl/jaoo-ruby-oslo-2008/slides/RubyFools... · • Ruby class definitions are code ... • use extend to add class method • include the new behaviour by including](https://reader034.vdocuments.net/reader034/viewer/2022052009/601de4d072feaa1e2c7b8abc/html5/thumbnails/22.jpg)
Mixing in Modules
class Person include AnyModule # adds to class definitionend
class Person extend AnyModule # adds to the object (self)end
![Page 23: The Dark Artjaoo.dk/dl/jaoo-ruby-oslo-2008/slides/RubyFools... · • Ruby class definitions are code ... • use extend to add class method • include the new behaviour by including](https://reader034.vdocuments.net/reader034/viewer/2022052009/601de4d072feaa1e2c7b8abc/html5/thumbnails/23.jpg)
Some other ways:
Person.instance_eval do def greetings "hello via \ instance_eval" endend
![Page 24: The Dark Artjaoo.dk/dl/jaoo-ruby-oslo-2008/slides/RubyFools... · • Ruby class definitions are code ... • use extend to add class method • include the new behaviour by including](https://reader034.vdocuments.net/reader034/viewer/2022052009/601de4d072feaa1e2c7b8abc/html5/thumbnails/24.jpg)
Some other ways:
class << Person def salutations "hello via \ class << Person" end end
![Page 25: The Dark Artjaoo.dk/dl/jaoo-ruby-oslo-2008/slides/RubyFools... · • Ruby class definitions are code ... • use extend to add class method • include the new behaviour by including](https://reader034.vdocuments.net/reader034/viewer/2022052009/601de4d072feaa1e2c7b8abc/html5/thumbnails/25.jpg)
module ActsAsFriendly module ClassMethods def is_friendly? true end end
def hello "hi from #{self}!" endend
Person.send(:include, ActsAsFriendly)Person.extend(ActsAsFriendly::ClassMethods)
![Page 26: The Dark Artjaoo.dk/dl/jaoo-ruby-oslo-2008/slides/RubyFools... · • Ruby class definitions are code ... • use extend to add class method • include the new behaviour by including](https://reader034.vdocuments.net/reader034/viewer/2022052009/601de4d072feaa1e2c7b8abc/html5/thumbnails/26.jpg)
includedmodule B def self.included(base) puts "B included into #{base}!" endend
class A include Bend# => "B included into A!"
![Page 27: The Dark Artjaoo.dk/dl/jaoo-ruby-oslo-2008/slides/RubyFools... · • Ruby class definitions are code ... • use extend to add class method • include the new behaviour by including](https://reader034.vdocuments.net/reader034/viewer/2022052009/601de4d072feaa1e2c7b8abc/html5/thumbnails/27.jpg)
extendedmodule B def self.extended(base) puts "#{base} extended by B!" endend
class A extend Bend# => "A extended by B!"
![Page 28: The Dark Artjaoo.dk/dl/jaoo-ruby-oslo-2008/slides/RubyFools... · • Ruby class definitions are code ... • use extend to add class method • include the new behaviour by including](https://reader034.vdocuments.net/reader034/viewer/2022052009/601de4d072feaa1e2c7b8abc/html5/thumbnails/28.jpg)
module ActsAsFriendly def self.included(base) base.extend(ClassMethods) end
module ClassMethods def is_friendly? true end end
def hello "hi from #{self}!" endend
Person.send(:include, ActsAsFriendly)
![Page 29: The Dark Artjaoo.dk/dl/jaoo-ruby-oslo-2008/slides/RubyFools... · • Ruby class definitions are code ... • use extend to add class method • include the new behaviour by including](https://reader034.vdocuments.net/reader034/viewer/2022052009/601de4d072feaa1e2c7b8abc/html5/thumbnails/29.jpg)
module ActsAsFriendly def self.included(base) base.extend(ClassMethods) end
module ClassMethods def is_friendly? true end end
def hello "hi from #{self}!" endend
Person.send(:include, ActsAsFriendly)
![Page 30: The Dark Artjaoo.dk/dl/jaoo-ruby-oslo-2008/slides/RubyFools... · • Ruby class definitions are code ... • use extend to add class method • include the new behaviour by including](https://reader034.vdocuments.net/reader034/viewer/2022052009/601de4d072feaa1e2c7b8abc/html5/thumbnails/30.jpg)
class EvilBoss < Personend
EvilBoss.is_friendly? # => true
![Page 31: The Dark Artjaoo.dk/dl/jaoo-ruby-oslo-2008/slides/RubyFools... · • Ruby class definitions are code ... • use extend to add class method • include the new behaviour by including](https://reader034.vdocuments.net/reader034/viewer/2022052009/601de4d072feaa1e2c7b8abc/html5/thumbnails/31.jpg)
Showing restraint...
• maybe we only want to apply it to particular classes
• particularly if we’re going to change how the class behaves (see later...)
![Page 32: The Dark Artjaoo.dk/dl/jaoo-ruby-oslo-2008/slides/RubyFools... · • Ruby class definitions are code ... • use extend to add class method • include the new behaviour by including](https://reader034.vdocuments.net/reader034/viewer/2022052009/601de4d072feaa1e2c7b8abc/html5/thumbnails/32.jpg)
... using class methods
• Ruby class definitions are code
• So, has_many is a class method
![Page 33: The Dark Artjaoo.dk/dl/jaoo-ruby-oslo-2008/slides/RubyFools... · • Ruby class definitions are code ... • use extend to add class method • include the new behaviour by including](https://reader034.vdocuments.net/reader034/viewer/2022052009/601de4d072feaa1e2c7b8abc/html5/thumbnails/33.jpg)
Class methods!class BlogPost < ActiveRecord::Base
has_many :comments validates_presence_of :title
end
![Page 34: The Dark Artjaoo.dk/dl/jaoo-ruby-oslo-2008/slides/RubyFools... · • Ruby class definitions are code ... • use extend to add class method • include the new behaviour by including](https://reader034.vdocuments.net/reader034/viewer/2022052009/601de4d072feaa1e2c7b8abc/html5/thumbnails/34.jpg)
Class methods!class BlogController < ApplicationController
before_filter :load_blog_posts
end
![Page 35: The Dark Artjaoo.dk/dl/jaoo-ruby-oslo-2008/slides/RubyFools... · • Ruby class definitions are code ... • use extend to add class method • include the new behaviour by including](https://reader034.vdocuments.net/reader034/viewer/2022052009/601de4d072feaa1e2c7b8abc/html5/thumbnails/35.jpg)
Class methods!
class Person attr_reader :nameend
![Page 36: The Dark Artjaoo.dk/dl/jaoo-ruby-oslo-2008/slides/RubyFools... · • Ruby class definitions are code ... • use extend to add class method • include the new behaviour by including](https://reader034.vdocuments.net/reader034/viewer/2022052009/601de4d072feaa1e2c7b8abc/html5/thumbnails/36.jpg)
class Alpha
puts self
end
# => Alpha
Self in class definitions
class SomeClass puts selfend # >> SomeClass
![Page 37: The Dark Artjaoo.dk/dl/jaoo-ruby-oslo-2008/slides/RubyFools... · • Ruby class definitions are code ... • use extend to add class method • include the new behaviour by including](https://reader034.vdocuments.net/reader034/viewer/2022052009/601de4d072feaa1e2c7b8abc/html5/thumbnails/37.jpg)
Calling methods
class SomeClass def self.greetings "hello" end greetingsend# >> hello
![Page 38: The Dark Artjaoo.dk/dl/jaoo-ruby-oslo-2008/slides/RubyFools... · • Ruby class definitions are code ... • use extend to add class method • include the new behaviour by including](https://reader034.vdocuments.net/reader034/viewer/2022052009/601de4d072feaa1e2c7b8abc/html5/thumbnails/38.jpg)
module AbilityToFly def fly! true end # etc...end
class Person def self.has_powers include AbilityToFly endend
![Page 39: The Dark Artjaoo.dk/dl/jaoo-ruby-oslo-2008/slides/RubyFools... · • Ruby class definitions are code ... • use extend to add class method • include the new behaviour by including](https://reader034.vdocuments.net/reader034/viewer/2022052009/601de4d072feaa1e2c7b8abc/html5/thumbnails/39.jpg)
class Villain < Personend
class Hero < Person has_powersend
clark_kent = Hero.newclark_kent.fly! # => true
lex_luthor = Villain.newlex_luthor.fly! # => NoMethodError
![Page 40: The Dark Artjaoo.dk/dl/jaoo-ruby-oslo-2008/slides/RubyFools... · • Ruby class definitions are code ... • use extend to add class method • include the new behaviour by including](https://reader034.vdocuments.net/reader034/viewer/2022052009/601de4d072feaa1e2c7b8abc/html5/thumbnails/40.jpg)
Villain.has_powerslex.fly! # => true
![Page 41: The Dark Artjaoo.dk/dl/jaoo-ruby-oslo-2008/slides/RubyFools... · • Ruby class definitions are code ... • use extend to add class method • include the new behaviour by including](https://reader034.vdocuments.net/reader034/viewer/2022052009/601de4d072feaa1e2c7b8abc/html5/thumbnails/41.jpg)
module MyPlugin def acts_as_friendly include MyPlugin::ActsAsFriendly end
module ActsAsFriendly def self.included(base) base.extend(ClassMethods) end
module ClassMethods def is_friendly? true end end
def hello "hi from #{self}" end
end # of ActsAsFriendlyend # of MyPlugin
Person.extend(MyPlugin)
![Page 42: The Dark Artjaoo.dk/dl/jaoo-ruby-oslo-2008/slides/RubyFools... · • Ruby class definitions are code ... • use extend to add class method • include the new behaviour by including](https://reader034.vdocuments.net/reader034/viewer/2022052009/601de4d072feaa1e2c7b8abc/html5/thumbnails/42.jpg)
module MyPlugin def acts_as_friendly include MyPlugin::ActsAsFriendly end
module ActsAsFriendly def self.included(base) base.extend(ClassMethods) end
module ClassMethods def is_friendly? true end end
def hello "hi from #{self}" end
end # of ActsAsFriendlyend # of MyPlugin
Person.extend(MyPlugin)
![Page 43: The Dark Artjaoo.dk/dl/jaoo-ruby-oslo-2008/slides/RubyFools... · • Ruby class definitions are code ... • use extend to add class method • include the new behaviour by including](https://reader034.vdocuments.net/reader034/viewer/2022052009/601de4d072feaa1e2c7b8abc/html5/thumbnails/43.jpg)
module MyPlugin def acts_as_friendly include MyPlugin::ActsAsFriendly end
module ActsAsFriendly def self.included(base) base.extend(ClassMethods) end
module ClassMethods def is_friendly? true end end
def hello "hi from #{self}" end
end # of ActsAsFriendlyend # of MyPlugin
Person.extend(MyPlugin)
![Page 44: The Dark Artjaoo.dk/dl/jaoo-ruby-oslo-2008/slides/RubyFools... · • Ruby class definitions are code ... • use extend to add class method • include the new behaviour by including](https://reader034.vdocuments.net/reader034/viewer/2022052009/601de4d072feaa1e2c7b8abc/html5/thumbnails/44.jpg)
class Grouch < Personend
oscar = Grouch.newoscar.hello # => NoMethodError
class Hacker < Person acts_as_friendlyend
Hacker.is_friendly? # => truejames = Hacker.newjames.hello # => “hi from #<Hacker:0x123>”
![Page 45: The Dark Artjaoo.dk/dl/jaoo-ruby-oslo-2008/slides/RubyFools... · • Ruby class definitions are code ... • use extend to add class method • include the new behaviour by including](https://reader034.vdocuments.net/reader034/viewer/2022052009/601de4d072feaa1e2c7b8abc/html5/thumbnails/45.jpg)
Person.extend(MyPlugin)
![Page 46: The Dark Artjaoo.dk/dl/jaoo-ruby-oslo-2008/slides/RubyFools... · • Ruby class definitions are code ... • use extend to add class method • include the new behaviour by including](https://reader034.vdocuments.net/reader034/viewer/2022052009/601de4d072feaa1e2c7b8abc/html5/thumbnails/46.jpg)
ActiveRecord::Base.extend(MyPlugin)
![Page 47: The Dark Artjaoo.dk/dl/jaoo-ruby-oslo-2008/slides/RubyFools... · • Ruby class definitions are code ... • use extend to add class method • include the new behaviour by including](https://reader034.vdocuments.net/reader034/viewer/2022052009/601de4d072feaa1e2c7b8abc/html5/thumbnails/47.jpg)
Extending Rails
![Page 48: The Dark Artjaoo.dk/dl/jaoo-ruby-oslo-2008/slides/RubyFools... · • Ruby class definitions are code ... • use extend to add class method • include the new behaviour by including](https://reader034.vdocuments.net/reader034/viewer/2022052009/601de4d072feaa1e2c7b8abc/html5/thumbnails/48.jpg)
![Page 49: The Dark Artjaoo.dk/dl/jaoo-ruby-oslo-2008/slides/RubyFools... · • Ruby class definitions are code ... • use extend to add class method • include the new behaviour by including](https://reader034.vdocuments.net/reader034/viewer/2022052009/601de4d072feaa1e2c7b8abc/html5/thumbnails/49.jpg)
acts_as_archivable
• when a record is deleted, save a YAML version. Just in case.
• It’s an odd example, but bear with me.
![Page 50: The Dark Artjaoo.dk/dl/jaoo-ruby-oslo-2008/slides/RubyFools... · • Ruby class definitions are code ... • use extend to add class method • include the new behaviour by including](https://reader034.vdocuments.net/reader034/viewer/2022052009/601de4d072feaa1e2c7b8abc/html5/thumbnails/50.jpg)
Archivable Module
module Archivable def archive_to_yaml File.open("#{id}.yml", 'w') do |f| f.write self.to_yaml end endend
ActiveRecord::Base.send(:include, Archivable)
![Page 51: The Dark Artjaoo.dk/dl/jaoo-ruby-oslo-2008/slides/RubyFools... · • Ruby class definitions are code ... • use extend to add class method • include the new behaviour by including](https://reader034.vdocuments.net/reader034/viewer/2022052009/601de4d072feaa1e2c7b8abc/html5/thumbnails/51.jpg)
Redefine via a modulemodule Archivable def archive_to_yaml File.open("#{id}.yml") # ...etc... end
def destroy # redefine destroy! connection.delete %{ DELETE FROM #{table_name} WHERE id = #{self.id} } archive_to_yaml endend
![Page 52: The Dark Artjaoo.dk/dl/jaoo-ruby-oslo-2008/slides/RubyFools... · • Ruby class definitions are code ... • use extend to add class method • include the new behaviour by including](https://reader034.vdocuments.net/reader034/viewer/2022052009/601de4d072feaa1e2c7b8abc/html5/thumbnails/52.jpg)
Redefine via a moduleActiveRecord::Base.send(:include, Archivable)
class Thing < ActiveRecord::Baseend
t = Thing.find(:first)
t.destroy # => no archive created :’(
![Page 53: The Dark Artjaoo.dk/dl/jaoo-ruby-oslo-2008/slides/RubyFools... · • Ruby class definitions are code ... • use extend to add class method • include the new behaviour by including](https://reader034.vdocuments.net/reader034/viewer/2022052009/601de4d072feaa1e2c7b8abc/html5/thumbnails/53.jpg)
Redefining in the classclass ActiveRecord::Base def destroy # Actually delete the record connection.delete %{ DELETE FROM #{table_name} WHERE id = #{self.id} } # call our new method archive_to_yaml endend
![Page 54: The Dark Artjaoo.dk/dl/jaoo-ruby-oslo-2008/slides/RubyFools... · • Ruby class definitions are code ... • use extend to add class method • include the new behaviour by including](https://reader034.vdocuments.net/reader034/viewer/2022052009/601de4d072feaa1e2c7b8abc/html5/thumbnails/54.jpg)
...it’s evil naughty
• ties our new functionality to ActiveRecord, in this example
• maybe we want to add this to DataMapper? Or Sequel? Or Ambition?
• What if Rails changes?
![Page 55: The Dark Artjaoo.dk/dl/jaoo-ruby-oslo-2008/slides/RubyFools... · • Ruby class definitions are code ... • use extend to add class method • include the new behaviour by including](https://reader034.vdocuments.net/reader034/viewer/2022052009/601de4d072feaa1e2c7b8abc/html5/thumbnails/55.jpg)
What we want
• Our new behaviour should be triggered when destroy is called
• The record should still be removed from the database
• We shouldn’t need to reimplement the existing behaviour
![Page 56: The Dark Artjaoo.dk/dl/jaoo-ruby-oslo-2008/slides/RubyFools... · • Ruby class definitions are code ... • use extend to add class method • include the new behaviour by including](https://reader034.vdocuments.net/reader034/viewer/2022052009/601de4d072feaa1e2c7b8abc/html5/thumbnails/56.jpg)
alias_method
def hello "hi!"end
alias_method :greetings, :hello
greetings # => "hi!"
![Page 57: The Dark Artjaoo.dk/dl/jaoo-ruby-oslo-2008/slides/RubyFools... · • Ruby class definitions are code ... • use extend to add class method • include the new behaviour by including](https://reader034.vdocuments.net/reader034/viewer/2022052009/601de4d072feaa1e2c7b8abc/html5/thumbnails/57.jpg)
alias_methodalias_method :original_destroy, :destroy
def new_destroy original_destroy archive_to_yamlend
alias_method :destroy, :new_destroy
![Page 58: The Dark Artjaoo.dk/dl/jaoo-ruby-oslo-2008/slides/RubyFools... · • Ruby class definitions are code ... • use extend to add class method • include the new behaviour by including](https://reader034.vdocuments.net/reader034/viewer/2022052009/601de4d072feaa1e2c7b8abc/html5/thumbnails/58.jpg)
module Archivable alias_method :original_destroy, :destroy def new_destroy original_destroy archive_to_yaml end
alias_method :destroy, :new_destroyend
# ~> undefined method `destroy' for module `Archivable'
![Page 59: The Dark Artjaoo.dk/dl/jaoo-ruby-oslo-2008/slides/RubyFools... · • Ruby class definitions are code ... • use extend to add class method • include the new behaviour by including](https://reader034.vdocuments.net/reader034/viewer/2022052009/601de4d072feaa1e2c7b8abc/html5/thumbnails/59.jpg)
module Archivable def self.included(base) base.class_eval do alias_method :original_destroy, :destroy alias_method :destroy, :new_destroy end end def archive_to_yaml File.open("#{id}.yml") # ... end def new_destroy original_destroy archive_to_yaml endend
ActiveRecord::Base.send(:include, Archivable)
![Page 60: The Dark Artjaoo.dk/dl/jaoo-ruby-oslo-2008/slides/RubyFools... · • Ruby class definitions are code ... • use extend to add class method • include the new behaviour by including](https://reader034.vdocuments.net/reader034/viewer/2022052009/601de4d072feaa1e2c7b8abc/html5/thumbnails/60.jpg)
class Thing < ActiveRecord::Baseend
t = Thing.find(:first)
t.destroy # => archive created!
![Page 61: The Dark Artjaoo.dk/dl/jaoo-ruby-oslo-2008/slides/RubyFools... · • Ruby class definitions are code ... • use extend to add class method • include the new behaviour by including](https://reader034.vdocuments.net/reader034/viewer/2022052009/601de4d072feaa1e2c7b8abc/html5/thumbnails/61.jpg)
alias_method again
alias_method :destroy_without_archiving, :destroy
def destroy_with_archiving destroy_without_archiving # then add our new behaviourend
alias_method :destroy, :destroy_with_archiving
alias_method :destroy_without_archiving, :destroy
def destroy_with_archiving destroy_without_archiving archive_to_yamlend
alias_method :destroy, :destroy_with_archiving
![Page 62: The Dark Artjaoo.dk/dl/jaoo-ruby-oslo-2008/slides/RubyFools... · • Ruby class definitions are code ... • use extend to add class method • include the new behaviour by including](https://reader034.vdocuments.net/reader034/viewer/2022052009/601de4d072feaa1e2c7b8abc/html5/thumbnails/62.jpg)
alias_method_chain
def destroy_with_archiving destroy_without_archiving archive_to_yamlend
alias_method_chain :destroy, :archiving
![Page 63: The Dark Artjaoo.dk/dl/jaoo-ruby-oslo-2008/slides/RubyFools... · • Ruby class definitions are code ... • use extend to add class method • include the new behaviour by including](https://reader034.vdocuments.net/reader034/viewer/2022052009/601de4d072feaa1e2c7b8abc/html5/thumbnails/63.jpg)
module Archivable def self.included(base) base.class_eval do alias_method_chain :destroy, :archiving end end def archive_to_yaml File.open("#{id}.yml", "w") do |f| f.write self.to_yaml end end def destroy_with_archiving destroy_without_archiving archive_to_yaml endend
ActiveRecord::Base.send(:include, Archivable)
![Page 64: The Dark Artjaoo.dk/dl/jaoo-ruby-oslo-2008/slides/RubyFools... · • Ruby class definitions are code ... • use extend to add class method • include the new behaviour by including](https://reader034.vdocuments.net/reader034/viewer/2022052009/601de4d072feaa1e2c7b8abc/html5/thumbnails/64.jpg)
So adding up everything
• use extend to add class method
• include the new behaviour by including a module when class method is called
• use alias_method_chain to wrap existing method
![Page 65: The Dark Artjaoo.dk/dl/jaoo-ruby-oslo-2008/slides/RubyFools... · • Ruby class definitions are code ... • use extend to add class method • include the new behaviour by including](https://reader034.vdocuments.net/reader034/viewer/2022052009/601de4d072feaa1e2c7b8abc/html5/thumbnails/65.jpg)
module ActsAsArchivable def acts_as_archivable include ActsAsArchivable::Behaviour end module Behaviour def self.included(base) base.class_eval do alias_method_chain :destroy, :archiving end end
def archive_to_yaml File.open("#{id}.yml") # ... end
def destroy_with_archiving destroy_without_archiving archive_to_yaml end endend
ActiveRecord::Base.extend(ActsAsArchivable)
![Page 66: The Dark Artjaoo.dk/dl/jaoo-ruby-oslo-2008/slides/RubyFools... · • Ruby class definitions are code ... • use extend to add class method • include the new behaviour by including](https://reader034.vdocuments.net/reader034/viewer/2022052009/601de4d072feaa1e2c7b8abc/html5/thumbnails/66.jpg)
module ActsAsArchivable def acts_as_archivable include ActsAsArchivable::Behaviour alias_method_chain :destroy, :archiving end module Behaviour def archive_to_yaml File.open("#{id}.yml") # ... end
def destroy_with_archiving destroy_without_archiving archive_to_yaml end endend
ActiveRecord::Base.extend(ActsAsArchivable)
![Page 67: The Dark Artjaoo.dk/dl/jaoo-ruby-oslo-2008/slides/RubyFools... · • Ruby class definitions are code ... • use extend to add class method • include the new behaviour by including](https://reader034.vdocuments.net/reader034/viewer/2022052009/601de4d072feaa1e2c7b8abc/html5/thumbnails/67.jpg)
module ActsAsArchivable def acts_as_archivable include ActsAsArchivable::Behaviour alias_method_chain :destroy, :archiving end module Behaviour def archive_to_yaml File.open("#{id}.yml") # ... end
def destroy_with_archiving destroy_without_archiving archive_to_yaml end endend
ActiveRecord::Base.extend(ActsAsArchivable)
![Page 68: The Dark Artjaoo.dk/dl/jaoo-ruby-oslo-2008/slides/RubyFools... · • Ruby class definitions are code ... • use extend to add class method • include the new behaviour by including](https://reader034.vdocuments.net/reader034/viewer/2022052009/601de4d072feaa1e2c7b8abc/html5/thumbnails/68.jpg)
class Thing < ActiveRecord::Baseend
t1 = Thing.create!t1.destroy # => normal destroy calledThing.count # => 0Dir["*.yml"] # => []
class PreciousThing < ActiveRecord::Base acts_as_archivableendt2 = PreciousThing.create!t2.destroyPreciousThing.count # => 0Dir["*.yml"] # => ["1.yml"]
![Page 69: The Dark Artjaoo.dk/dl/jaoo-ruby-oslo-2008/slides/RubyFools... · • Ruby class definitions are code ... • use extend to add class method • include the new behaviour by including](https://reader034.vdocuments.net/reader034/viewer/2022052009/601de4d072feaa1e2c7b8abc/html5/thumbnails/69.jpg)
Plugin
Photo: http://flickr.com/photos/jreed/322057793/
Tips
![Page 70: The Dark Artjaoo.dk/dl/jaoo-ruby-oslo-2008/slides/RubyFools... · • Ruby class definitions are code ... • use extend to add class method • include the new behaviour by including](https://reader034.vdocuments.net/reader034/viewer/2022052009/601de4d072feaa1e2c7b8abc/html5/thumbnails/70.jpg)
Package your code
• ...in a module
• domain name, nickname, quirk
module Lazyatom module ActsAsHasselhoff # ... endend
Tip#1
![Page 71: The Dark Artjaoo.dk/dl/jaoo-ruby-oslo-2008/slides/RubyFools... · • Ruby class definitions are code ... • use extend to add class method • include the new behaviour by including](https://reader034.vdocuments.net/reader034/viewer/2022052009/601de4d072feaa1e2c7b8abc/html5/thumbnails/71.jpg)
Developing plugins
• Dependencies.load_once_paths
• config/environment/development.rb
config.after_initialize do Dependencies.load_once_paths. delete_if do |path| path =~ /vendor\/plugins/ endend
Tip#2
![Page 72: The Dark Artjaoo.dk/dl/jaoo-ruby-oslo-2008/slides/RubyFools... · • Ruby class definitions are code ... • use extend to add class method • include the new behaviour by including](https://reader034.vdocuments.net/reader034/viewer/2022052009/601de4d072feaa1e2c7b8abc/html5/thumbnails/72.jpg)
Gems as plugins
• coming in Rails 2.1 (it’s in r9101)
• add rails/init.rb to your gem
• require “rubygems” in environment.rb
Tip#3
![Page 73: The Dark Artjaoo.dk/dl/jaoo-ruby-oslo-2008/slides/RubyFools... · • Ruby class definitions are code ... • use extend to add class method • include the new behaviour by including](https://reader034.vdocuments.net/reader034/viewer/2022052009/601de4d072feaa1e2c7b8abc/html5/thumbnails/73.jpg)
Thanks!
lazyatom.com/plugins