Your SlideShare is downloading. ×
0
TDC 2012 - Patterns e Anti-Patterns em Ruby
TDC 2012 - Patterns e Anti-Patterns em Ruby
TDC 2012 - Patterns e Anti-Patterns em Ruby
TDC 2012 - Patterns e Anti-Patterns em Ruby
TDC 2012 - Patterns e Anti-Patterns em Ruby
TDC 2012 - Patterns e Anti-Patterns em Ruby
TDC 2012 - Patterns e Anti-Patterns em Ruby
TDC 2012 - Patterns e Anti-Patterns em Ruby
TDC 2012 - Patterns e Anti-Patterns em Ruby
TDC 2012 - Patterns e Anti-Patterns em Ruby
TDC 2012 - Patterns e Anti-Patterns em Ruby
TDC 2012 - Patterns e Anti-Patterns em Ruby
TDC 2012 - Patterns e Anti-Patterns em Ruby
TDC 2012 - Patterns e Anti-Patterns em Ruby
TDC 2012 - Patterns e Anti-Patterns em Ruby
TDC 2012 - Patterns e Anti-Patterns em Ruby
TDC 2012 - Patterns e Anti-Patterns em Ruby
TDC 2012 - Patterns e Anti-Patterns em Ruby
TDC 2012 - Patterns e Anti-Patterns em Ruby
TDC 2012 - Patterns e Anti-Patterns em Ruby
TDC 2012 - Patterns e Anti-Patterns em Ruby
TDC 2012 - Patterns e Anti-Patterns em Ruby
TDC 2012 - Patterns e Anti-Patterns em Ruby
TDC 2012 - Patterns e Anti-Patterns em Ruby
TDC 2012 - Patterns e Anti-Patterns em Ruby
TDC 2012 - Patterns e Anti-Patterns em Ruby
TDC 2012 - Patterns e Anti-Patterns em Ruby
TDC 2012 - Patterns e Anti-Patterns em Ruby
TDC 2012 - Patterns e Anti-Patterns em Ruby
TDC 2012 - Patterns e Anti-Patterns em Ruby
TDC 2012 - Patterns e Anti-Patterns em Ruby
TDC 2012 - Patterns e Anti-Patterns em Ruby
TDC 2012 - Patterns e Anti-Patterns em Ruby
TDC 2012 - Patterns e Anti-Patterns em Ruby
TDC 2012 - Patterns e Anti-Patterns em Ruby
TDC 2012 - Patterns e Anti-Patterns em Ruby
TDC 2012 - Patterns e Anti-Patterns em Ruby
TDC 2012 - Patterns e Anti-Patterns em Ruby
TDC 2012 - Patterns e Anti-Patterns em Ruby
TDC 2012 - Patterns e Anti-Patterns em Ruby
TDC 2012 - Patterns e Anti-Patterns em Ruby
TDC 2012 - Patterns e Anti-Patterns em Ruby
TDC 2012 - Patterns e Anti-Patterns em Ruby
TDC 2012 - Patterns e Anti-Patterns em Ruby
TDC 2012 - Patterns e Anti-Patterns em Ruby
TDC 2012 - Patterns e Anti-Patterns em Ruby
TDC 2012 - Patterns e Anti-Patterns em Ruby
TDC 2012 - Patterns e Anti-Patterns em Ruby
TDC 2012 - Patterns e Anti-Patterns em Ruby
TDC 2012 - Patterns e Anti-Patterns em Ruby
TDC 2012 - Patterns e Anti-Patterns em Ruby
TDC 2012 - Patterns e Anti-Patterns em Ruby
TDC 2012 - Patterns e Anti-Patterns em Ruby
TDC 2012 - Patterns e Anti-Patterns em Ruby
TDC 2012 - Patterns e Anti-Patterns em Ruby
TDC 2012 - Patterns e Anti-Patterns em Ruby
TDC 2012 - Patterns e Anti-Patterns em Ruby
TDC 2012 - Patterns e Anti-Patterns em Ruby
TDC 2012 - Patterns e Anti-Patterns em Ruby
TDC 2012 - Patterns e Anti-Patterns em Ruby
TDC 2012 - Patterns e Anti-Patterns em Ruby
TDC 2012 - Patterns e Anti-Patterns em Ruby
TDC 2012 - Patterns e Anti-Patterns em Ruby
TDC 2012 - Patterns e Anti-Patterns em Ruby
TDC 2012 - Patterns e Anti-Patterns em Ruby
TDC 2012 - Patterns e Anti-Patterns em Ruby
TDC 2012 - Patterns e Anti-Patterns em Ruby
TDC 2012 - Patterns e Anti-Patterns em Ruby
TDC 2012 - Patterns e Anti-Patterns em Ruby
TDC 2012 - Patterns e Anti-Patterns em Ruby
TDC 2012 - Patterns e Anti-Patterns em Ruby
TDC 2012 - Patterns e Anti-Patterns em Ruby
TDC 2012 - Patterns e Anti-Patterns em Ruby
TDC 2012 - Patterns e Anti-Patterns em Ruby
TDC 2012 - Patterns e Anti-Patterns em Ruby
TDC 2012 - Patterns e Anti-Patterns em Ruby
TDC 2012 - Patterns e Anti-Patterns em Ruby
TDC 2012 - Patterns e Anti-Patterns em Ruby
Upcoming SlideShare
Loading in...5
×

Thanks for flagging this SlideShare!

Oops! An error has occurred.

×
Saving this for later? Get the SlideShare app to save on your phone or tablet. Read anywhere, anytime – even offline.
Text the download link to your phone
Standard text messaging rates apply

TDC 2012 - Patterns e Anti-Patterns em Ruby

2,504

Published on

Palestra apresentada no The Developers Conference 2012 em São Paulo. Explicação sobre Patterns e Anti-Patterns em Ruby para quem está iniciando a aprender a linguagem.

Palestra apresentada no The Developers Conference 2012 em São Paulo. Explicação sobre Patterns e Anti-Patterns em Ruby para quem está iniciando a aprender a linguagem.

Published in: Technology, Business
0 Comments
1 Like
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
2,504
On Slideshare
0
From Embeds
0
Number of Embeds
1
Actions
Shares
0
Downloads
16
Comments
0
Likes
1
Embeds 0
No embeds

Report content
Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
No notes for slide

Transcript

  • 1. “ Genius is the gold in the mine; talent is the miner who works and brings it out. ” Lady Marguerite Blessington Donets Basin Mina de carvão-Ucrânia
  • 2. @akitaonrails Ruby e Ruby on Rails - 2006Rails Summit Latin America - 2008 RubyConf Brasil - 2010
  • 3. Patterns e Anti-Patterns em RubyFabio Akita (@akitaonrails)
  • 4. Pattern PADRÃO
  • 5. STANDARD Pattern PADRÃO Default
  • 6. “Pattern”
  • 7. “Standard”
  • 8. Christopher Alexander
  • 9. "...each pattern represents our current bestguess ... to solve the problem presented. ..., thepatterns are still hypotheses, all ... of them -andare therefore all tentative, all free to evolve underthe impact of new experience and observation" —Christopher Alexander, A Pattern Language, p. xv
  • 10. require erubis def render_erb(filepath) content = File.read(filepath) template = Erubis::Eruby.new(content) context = { title: "Hello World", paragraph: "This is an ERB template." } output = template.evaluate(context) end puts render_erb("sample.erb")ERB
  • 11. <html> <head><title><%= @title %></title></head> <body> <p><%= @paragraph %></p> </body> </html> <html> <head><title>Hello World</title></head> <body> <p>This is an ERB template.</p> </body> </html>ERB
  • 12. require rdiscount def render_markdown(filepath) content = File.read(filepath) template = RDiscount.new(content) output = template.to_html end puts render_markdown("sample.md")Markdown
  • 13. # Hello World This is a Markdown example * [Markdown](http://daringfireball.net/projects/markdown/ syntax/) <h1>Hello World</h1> <p>This is a Markdown example</p> <ul> <li><a href="http://daringfireball.net/projects/markdown/ syntax/">Markdown</a></li> </ul>Markdown
  • 14. def render(filepath) case filepath when /erb$/ then render_erb(filepath) when /md$/ then render_markdown(filepath) when /sass$/ then render_sass(filepath) ... endendputs render("sample.erb")
  • 15. Strategy
  • 16. ENGINE FILE EXTENSIONS REQUIRED LIBRARIES -------------------------- ----------------------- ---------------------------- ERB .erb, .rhtml none (included ruby stdlib) Interpolated String .str none (included ruby core) Erubis .erb, .rhtml, .erubis erubis Haml .haml haml Sass .sass haml (< 3.1) or sass (>= 3.1) Scss .scss haml (< 3.1) or sass (>= 3.1) Less CSS .less less Builder .builder builder Liquid .liquid liquid RDiscount .markdown, .mkd, .md rdiscount Redcarpet .markdown, .mkd, .md redcarpet BlueCloth .markdown, .mkd, .md bluecloth Kramdown .markdown, .mkd, .md kramdown Maruku .markdown, .mkd, .md maruku RedCloth .textile redcloth RDoc .rdoc rdoc Radius .radius radius Markaby .mab markaby Nokogiri .nokogiri nokogiri CoffeeScript .coffee coffee-script (+ javascript) Creole (Wiki markup) .wiki, .creole creole WikiCloth (Wiki markup) .wiki, .mediawiki, .mw wikicloth Yajl .yajl yajl-rubyTemplate Engines supported by Tilt
  • 17. require tilt template = Tilt.new("sample.erb") context = { title: "Hello World", paragraph: "This is an ERB template." } output = template.render(context) puts output template = Tilt.new("sample.md") output = template.render puts outputERB and Markdown through Tilt
  • 18. require tilt template = Tilt::ErubisTemplate.new("sample.erb") context = { title: "Hello World", paragraph: "This is an ERB template." } output = template.render(context) puts output template = Tilt::RDiscountTemplate.new("sample.md") output = template.render puts outputSame example as previously
  • 19. module Tilt ... @preferred_mappings = Hash.new @template_mappings = Hash.new { |h, k| h[k] = [] } # Hash of template path pattern => template implementation class mappings. def self.mappings @template_mappings end ... # Register a template implementation by file extension. def self.register(template_class, *extensions) if template_class.respond_to?(:to_str) # Support register(ext, template_class) too extensions, template_class = [template_class], extensions[0] end extensions.each do |ext| ext = normalize(ext) mappings[ext].unshift(template_class).uniq! end end ...tilt.rb
  • 20. require tilt/string register StringTemplate, str require tilt/erb register ERBTemplate, erb, rhtml register ErubisTemplate, erb, rhtml, erubis require tilt/haml register HamlTemplate, haml require tilt/css register SassTemplate, sass register ScssTemplate, scss register LessTemplate, less ...Tilt#register
  • 21. > Tilt["erb"] => Tilt::ErubisTemplate > Tilt["md"] => Tilt::RDiscountTemplate > Tilt["haml"] => Tilt::HamlTemplate > Tilt[coffee] => Tilt::CoffeeScriptTemplateTilt#[]
  • 22. module Tilt ... # Create a new template for the given # file using the files extension # to determine the the template mapping. def self.new(file, line=nil, options={}, &block) if template_class = self[file] template_class.new(file, line, options, &block) else fail "No template engine registered for #{File.basename(file)}" end endTilt overrided #new
  • 23. Factory
  • 24. module Tilt # Base class for template implementations. # Subclasses must implement the #prepare method and one # of the #evaluate or #precompiled_template methods. class Template ... def render(scope=Object.new, locals={}, &block) evaluate scope, locals || {}, &block end protected def prepare; ... end def evaluate(scope, locals, &block); ... end def precompiled(locals); ... end def precompiled_template(locals); ... end def precompiled_preamble(locals); ... end def precompiled_postamble(locals); ; end def compiled_method(locals_keys); ... end end endTilt::Template Lint
  • 25. module Tilt # RedCloth implementation. See: # http://redcloth.org/ class RedClothTemplate < Template def self.engine_initialized? defined? ::RedCloth end def initialize_engine require_template_library redcloth end def prepare @engine = RedCloth.new(data) @output = nil end def evaluate(scope, locals, &block) @output ||= @engine.to_html end end endTilt::RedClothTemplate Implementation
  • 26. Adapter
  • 27. Rails Mongrel Sinatra CGI Thin Ramaze WebrickSimple Web
  • 28. Rails Mongrel Sinatra CGI Thin Ramaze WebrickSimple Web
  • 29. Rails Mongrel Sinatra Rack CGI Thin Ramaze WebrickSimple Web
  • 30. class HelloWorld def call(env) [200, {"Content-Type" => "text/plain"}, ["Hello world!"]] end end hello_world = ->(env) { [200, {"Content-Type" => "text/plain"}, ["Hello world!"]] }Minimal Rack Compliant
  • 31. hello_world = ->(env) { [200, {"Content-Type" => "text/html"}, ["<h1>Hello world!</h1>"]] } use Rack::ContentType, "text/html" use Rack::ShowExceptions use Rack::Auth::Basic, "Rack Demo" do |username, password| secret == password end # Setup Rack run Rack::URLMap.new( { "/hello" => hello_world, "/" => Rack::File.new( "index.html" ) } )rackup app.ru
  • 32. module Rack class ContentType include Rack::Utils def initialize(app, content_type = "text/html") @app, @content_type = app, content_type end def call(env) status, headers, body = @app.call(env) headers = Utils::HeaderHash.new(headers) unless STATUS_WITH_NO_ENTITY_BODY.include?(status) headers[Content-Type] ||= @content_type end [status, headers, body] end end endrackup app.ru
  • 33. use ActionDispatch::Static use Rack::Lock ... use Rack::Runtime use Rack::MethodOverride use ActionDispatch::RequestId use Rails::Rack::Logger use ActionDispatch::ShowExceptions use ActionDispatch::DebugExceptions use ActionDispatch::RemoteIp use ActionDispatch::Reloader use ActionDispatch::Callbacks use ActiveRecord::ConnectionAdapters::ConnectionManagement use ActiveRecord::QueryCache use ActionDispatch::Cookies use ActionDispatch::Session::CookieStore use ActionDispatch::Flash use ActionDispatch::ParamsParser use ActionDispatch::Head use Rack::ConditionalGet use Rack::ETag use ActionDispatch::BestStandardsSupport use Warden::Manager use OmniAuth::Strategies::Twitter use OmniAuth::Strategies::Facebook run Rubyconf2012::Application.routesrake middleware (Rails)
  • 34. Chain of Responsibility
  • 35. class Relationship attr_accessor :state def initialize @state = :dating end def get_married make_vows @state = :married eat_wedding_cake end def get_divorced @state = :divorced end def make_vows; "I do"; end def eat_wedding_cake; "Yummy"; endend
  • 36. class Relationship attr_accessor :state def initialize @state = :dating end def get_married raise "Must date before marry" unless @state == :dating make_vows @state = :married eat_wedding_cake end def get_divorced raise "Must be married before divorce" unless @state == :married @state = :divorced end def make_vows; "I do"; end def eat_wedding_cake; "Yummy"; endend
  • 37. class Relationship include AASM aasm do state :dating, initial: true state :married state :divorced event :get_married, :before => :make_vows, :after => :eat_wedding_cake do transitions from: [:dating], to: :married end event :get_divorced do transitions from: [:married], to: :divorced end end def make_vows; "I do"; end def eat_wedding_cake; "Yummy"; endend
  • 38. class Relationship attr_accessor :dating, :married, :divorced def initialize @dating, @married, @divorced = true, false, false end def get_married raise "Must date before marry" unless dating make_vows @dating, @married = false, true eat_wedding_cake end def get_divorced raise "Must be married before divorce" unless married @married, @divorced = false, true end def make_vows; "I do"; end def eat_wedding_cake; "Yummy"; endend
  • 39. State
  • 40. class SaleOrder attr_accessor :items, :value, :checkout_date def initialize(*args) @items, @value, @checkout_date = args endendsale = SaleOrder.new( [Biscuit, Cheese], 15.0, "2012-07-07")
  • 41. require moneyrequire timeclass SaleOrder attr_reader :value, :checkout_date def initialize(options = {}) @items, @value, @checkout_date = [], Money.new(0.0, "USD"), nil self.items = options[:items] || [] self.value = options[:value] || 0.0 self.checkout_date = options[:checkout_date] end def items=(items); @items += items.dup; end def items(index); @items[index]; end def value=(value); @value = Money.new(value.to_f, "USD"); end def checkout_date=(date) @checkout_date = Date.parse(date) if date endendsale = SaleOrder.new(items: [Biscuit, Cheese], value: 15.0, checkout_date: "2012-07-07")
  • 42. Primitive Obsession
  • 43. def slug(title) # 1 if title.nil? title.strip.downcase.tr_s(^[a-z0-9], -) end # 2 title.strip.downcase.tr_s(^[a-z0-9], -) if title # 3 (title || "").strip.downcase.tr_s(^[a-z0-9], -) # 4 title.strip.downcase.tr_s(^[a-z0-9], -) rescue nil endhttp:/ /u.akita.ws/avdi-null
  • 44. class Object def try(*a, &b) if a.empty? && block_given? yield self else public_send(*a, &b) end end end class NilClass def try(*args) nil end endActiveSupport - Try
  • 45. require active_support/core_ext/object/try def slug(title) title.try(:strip).try(:downcase). try(:tr_s, ^[a-z0-9], -) end <%= title ? title.downcase : "" %> <%= title.try(:downcase) %>http:/ /u.akita.ws/avdi-null
  • 46. class NullObject def method_missing(*args, &block) self end def to_a; []; end def to_s; ""; end def to_f; 0.0; end def to_i; 0; end def Maybe(value) value.nil? ? NullObject.new : value def tap; self; end end def to_value; nil; end end class Object def to_value self end endhttp:/ /u.akita.ws/avdi-null
  • 47. def slug(title) Maybe(title).strip.downcase.tr_s(^[a-z0-9], -) end def slug(title) title = Maybe(title) if title.to_value # do something useful end title.strip.downcase.tr_s(^[a-z0-9], -) endhttp:/ /u.akita.ws/avdi-null
  • 48. git clone git://github.com/akitaonrails/null.git cd null gem build null.gemspec gem install null-0.1.gem > require null > Maybe(someobj).foo.bar.something #=> null > (100.0 / (NULL * 15.5) - 150) #=> null object = Maybe(someobj) if object.truthy? # something useful endhttp:/ /u.akita.ws/avdi-null
  • 49. Null Object
  • 50. class SalesOrder < Struct.new(:products, :total, :buyer_name) def html_receipt html_items = products.inject("") do |html, item| html += "<li>#{item}</li>" end html = %{<h1>Thanks for the Purchase #{buyer_name}!</h1> <p>You purchased:</p> <ul> #{html_items} </ul> <p>Total: $#{total}</p>} endendorder = SalesOrder.new(["Bacon", "Cheese"], 10.0, "John Doe" )
  • 51. > order.html_receipt=> "<h1>Thanks for the Purchase John Doe!</h1> <p>You purchased:</p> <ul> <li>Bacon</li><li>Cheese</li> </ul> <p>Total: $10.0</p>"
  • 52. class SalesOrder < Struct.new(:products, :total, :buyer_name) def html_receipt html_items = products.inject("") do |html, item| html += "<li>#{item}</li>" end html = %{<h1>Thanks for the Purchase #{buyer_name}!</h1> <p>You purchased:</p> <ul> #{html_items} </ul> <p>Total: $#{total}</p>} endendorder = SalesOrder.new(["Bacon", "Cheese"], 10.0, "John Doe" )
  • 53. class SalesOrder < Struct.new(:products, :total, :buyer_name)endclass SalesOrderDecorator < SimpleDelegator def html_receipt html_items = products.inject("") do |html, item| html += "<li>#{item}</li>" end html = %{<h1>Thanks for the Purchase #{buyer_name}!</h1> <p>You purchased:</p> <ul> #{html_items} </ul> <p>Total: $#{total}</p>} endendorder = SalesOrder.new(["Bacon", "Cheese"], 10.0, "John Doe" )decorated_order = SalesOrderDecorator.new(order)
  • 54. > decorated_order.html_receipt=> "<h1>Thanks for the Purchase John Doe!</h1> <p>You purchased:</p> <ul> <li>Bacon</li><li>Cheese</li> </ul> <p>Total: $10.0</p>"> decorated_order.total=> 10.0> decorated_order.products=> ["Bacon", "Cheese"]
  • 55. # originalorder = SalesOrder.new(["Bacon", "Cheese"], 10.0, "John Doe" )decorated_order = SalesOrderDecorator.new(order)# newclass SalesOrderDecorator < SimpleDelegator def initialize(*args) if args.first.is_a?(SalesOrder) super(args.first) else order = SalesOrder.new(*args) super(order) end end ...enddecorated_order = SalesOrderDecorator.new(["Bacon", "Cheese"], 10.0,"John Doe" )decorated_order.html_receipt
  • 56. Decorator/Presenter
  • 57. Strategy FactoryAdapter (Proxy, Bridge)Chain of Responsibility State Primitive Obsession Null ObjectDecorator (Presenter)
  • 58. +55 11 3729 14 22 www.codeminer42.com.br contact@codeminer42.com.brslideshare.net/akitaonrails
  • 59. MUITO OBRIGADO +55 11 3729 14 22 www.codeminer42.com.br contact@codeminer42.com.brslideshare.net/akitaonrails

×