As members of the Ruby on Rails community, we’ve taken advantage of a wonderful framework, fantastic libraries, and enjoyed the company of other great, creative minds. But it’s important to make sure we give back! In this talk, we’ll look at how we can start to release our own libraries. We’ll look at how we can manage our open-source contributions, to make sure that we don’t alienate new developers. Finally, we’ll see just how easy it is to provide support for the next generation of Ruby on Rails enthusiasts and coders!
5. class Foo
include Filters
before_filter :before_method
after_filter :after_method, :only => :bar
def foo(x)
puts "foo #{x}"
end
def bar
puts "bar"
end
def before_method
puts "before_method" and return true
end
def after_method
puts "after_method" and return true
end
end
6. module Filters
class << self
def included(mod)
mod.extend(Filters::ClassMethods)
mod.instance_methods(false).each do |method|
mod.add_global_hook(method)
end
end
end
module ClassMethods
# Real methods
end
end
7. befo
re_filte
r :me
# op thod
tions , :onl
[:onl
y] => y => :foo
[:foo
module ClassMethods ]
def before_filter(hook_method,options={})
options.keys.each{|k|options[k] = [options[k]].flatten}
(@@before_hooks||={})[hook_method.to_sym] = options
end
def after_filter(hook_method,options={})
options.keys.each{|k|options[k] = [options[k]].flatten}
(@@after_hooks||={})[hook_method.to_sym] = options
end
end
> [:foo]
ethod, : except =
afte r_ filter :m > [:foo]
[:only] =
# options
8. Hook Tactics
✤ Alias the original method :foo => :__foo
✤ Rewrite :foo
✤ Run any before_hooks
✤ Run the original method (if the before_hooks returned true)
✤ Run any after_hooks
9. def add_global_hook(method)
alias_method "__#{method}", method
define_method method do |*args,&block|
@@before_hooks ||= {}
@@after_hooks ||= {}
@@before_hooks.keys.each do |hook|
unless (@@before_hooks[hook][:except]||[]).include?(method) ||
(@@before_hooks[hook][:only] &&
!@@before_hooks[hook][:only].include?(method))
return unless send(hook)
end
end unless @@before_hooks[method] || @@after_hooks[method]
returnable = send("__#{method}",*args,&block)
@@after_hooks.keys.each do |hook|
unless (@@after_hooks[hook][:except]||[]).include?(method) ||
(@@after_hooks[hook][:only] &&
!@@after_hooks[hook][:only].include?(method))
return unless send(hook)
end
end unless @@before_hooks[method] || @@after_hooks[method]
return returnable
end
end
10. def add_global_hook(method)
alias_method "__#{method}", method
define_method method do |*args,&block|
@@before_hooks ||= {}
@@after_hooks ||= {}
@@before_hooks.keys.each do |hook|
unless (@@before_hooks[hook][:except]||[]).include?(method) ||
(@@before_hooks[hook][:only] &&
!@@before_hooks[hook][:only].include?(method))
return unless send(hook)
end
end unless @@before_hooks[method] || @@after_hooks[method]
returnable = send("__#{method}",*args,&block)
@@after_hooks.keys.each do |hook|
unless (@@after_hooks[hook][:except]||[]).include?(method) ||
(@@after_hooks[hook][:only] &&
!@@after_hooks[hook][:only].include?(method))
return unless send(hook)
end
end unless @@before_hooks[method] || @@after_hooks[method]
return returnable
end
end
11. module Filters
class << self
def included(mod)
mod.extend(Filters::ClassMethods)
mod.instance_methods(false).each do |method|
mod.add_global_hook(method)
end
end
end
module ClassMethods
# ...
def method_added(method)
add_global_hook(method) unless
method.to_s[0,2] == "__" ||
instance_methods.include?("__#{method}".to_sym)
end
end
end
12. class Foo
include Filters
before_filter :before_method
after_filter :after_method, :only => :bar
def foo(x)
puts "foo #{x}"
end
def bar
puts "bar"
end
def before_method
puts "before_method" and return true
end
def after_method
puts "after_method" and return true
end
end
13. Let’s Make It A Gem!
filt.gemspec
Gem::Specification.new do |s|
s.name = "filt"
s.version = "0.0.1"
s.summary = "before and after filters for Ruby"
s.files = ["lib/filt"]
end
17. John Doe Programmer
✤ Windows 7 machine (moderate hardware)
✤ Visual Studio
✤ Microsoft SQL Server
✤ A little bit of PHP
✤ Minimal web experience
18.
19.
20. This Isn’t Bad!
✤ Choice is important!
✤ There are many “right ways”
✤ Flexibility allows us to create better solutions
21. OpenPGP
module OpenPGP
class Message
include Enumerable
# ...
def self.decrypt(data, options = {}, &block)
raise NotImplementedError # TODO
end
end
end
23. Aesthetics
map.resources :products, :member => {:short
=> :post}, :collection => {:long => :get} do |products|
products.resource :category
end
resources :products do
resource :category
member do
post :short
end
collection do
get :long
end
end
match "/posts/github" => redirect("http://github.com/rails.atom")
29. The Lazy Programmer’s Manifesto
✤ I want to write code once
✤ I want to be able to read code without having to refer to external docs
✤ I want to be able to rely on other libraries
✤ I want to use adaptable solutions for numerous problems
✤ I want to always be working on something new
32. Idea Filtering
✤ To share
✤ Business value
✤ Practical use
✤ To learn
✤ No requirements!
✤ Don’t post it publicly!
33. Testing
✤ We all say we do it!
✤ RSpec and Cucumber are both easy to set up for gems
✤ Design verification tool
34. Extensible
✤ Write clean code (don’t post a spike)
✤ Have a peer review your stuff
✤ Follow the Unix philosophy: do one thing really well
✤ Leverage other gems!
35. Documented
✤ Who’s looking at your code if it’s on GitHub, RubyGems?
✤ RDoc, YARD, etc
✤ Getting Started
✤ Blog posts!
36. Supported
✤ Put your name on it
✤ Answer your emails, damnit
✤ Accept patches (at minimum)
37. Be Honest
✤ Don’t be too proud to hand over the reins
✤ If your project is worth supporting, someone will step up
✤ Be a net-positive for the community
✤ Don’t announce things if they’re not done
38.
39. But, But, But!!!
✤ Don’t post it
✤ Post it in a limited venue
✤ Put a disclaimer on your project
40. How Does The Internet Filter
Stupid?
✤ It doesn’t?
✤ Making tasks difficult
✤ Having enough eyes
41. Matz Wisdom
✤ “Ruby treats you like a grown-up programmer”
43. How To Be A Good Parent
✤ Don’t create sensory overload
✤ Spoon-feed sometimes
✤ Remember you’re used to the
status quo
✤ Be a mentor
✤ Provide solutions to problems,
not blocks of code