Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Escrevendo Aplicações Melhores @ RubyConf Brasil

Escrevendo Aplicações Melhores @ RubyConf Brasil

Carlos Antonio

September 05, 2012
Tweet

More Decks by Carlos Antonio

Other Decks in Programming

Transcript

  1. obj = MyClass.new obj.attr = 'test' puts obj.valid? # =>

    true obj.attr = 'tst' puts obj.valid? # => false
  2. require 'activerecord' ActiveRecord::Base # autoload all modules class MyClass def

    save; end def save!; end def new_record?; true; end include ActiveRecord::Validations attr_accessor :attr validates_length_of :attr, :minimum => 4 end
  3. “I had to go through some hoops to make this

    code work.” Paolo Perrotta Metaprogramming Ruby
  4. require 'activerecord' ActiveRecord::Base # autoload all modules class MyClass def

    save; end def save!; end def new_record?; true; end include ActiveRecord::Validations attr_accessor :attr validates_length_of :attr, :minimum => 4 end What? ActiveRecord::Base # autoload all modules
  5. require 'activerecord' ActiveRecord::Base # autoload all modules class MyClass def

    save; end def save!; end def new_record?; true; end include ActiveRecord::Validations attr_accessor :attr validates_length_of :attr, :minimum => 4 end def save; end def save!; end LOL
  6. require 'activerecord' ActiveRecord::Base # autoload all modules class MyClass def

    save; end def save!; end def new_record?; true; end include ActiveRecord::Validations attr_accessor :attr validates_length_of :attr, :minimum => 4 end def new_record?; true; end trolling
  7. require 'activerecord' ActiveRecord::Base # autoload all modules class MyClass def

    save; end def save!; end def new_record?; true; end include ActiveRecord::Validations attr_accessor :attr validates_length_of :attr, :minimum => 4 end include ActiveRecord::Validations attr_accessor :attr validates_length_of :attr, :minimum => 4 there we go!
  8. “However, that wasn’t too much work in exchange for a

    flexible set of validation Class Macros.” Paolo Perrotta Metaprogramming Ruby
  9. require 'activerecord' ActiveRecord::Base # autoload all modules class MyClass def

    save; end def save!; end def new_record?; true; end include ActiveRecord::Validations attr_accessor :attr validates_length_of :attr, :minimum => 4 end ActiveRecord::Base # autoload all modules def save; end def save!; end def new_record?; true; end
  10. require 'activerecord' ActiveRecord::Base # autoload all modules class MyClass def

    save; end def save!; end def new_record?; true; end include ActiveRecord::Validations attr_accessor :attr validates_length_of :attr, :minimum => 4 end include ActiveRecord::Validations attr_accessor :attr validates_length_of :attr, :minimum => 4
  11. require 'activerecord' ActiveRecord::Base # autoload all modules class MyClass def

    save; end def save!; end def new_record?; true; end include ActiveRecord::Validations attr_accessor :attr validates_length_of :attr, :minimum => 4 end
  12. module ActiveRecord class Base extend ActiveModel::Naming # Uses ActiveModel::Translation extend

    Translation # Uses ActiveModel::MassAssignmentSecurity include AttributeAssignment include ActiveModel::Conversion # Uses ActiveModel::Validations include Validations # Uses ActiveModel::AttributeMethods include AttributeMethods # Uses ActiveModel::Callbacks include Callbacks include ActiveModel::Observing include ActiveModel::SecurePassword # Uses ActiveModel::Serialization include Serialization # ... end end
  13. module ActiveResource class Base extend ActiveModel::Naming # Uses ActiveModel::Observing include

    Observing # Uses ActiveModel::Validations include Validations include ActiveModel::Conversion include ActiveModel::Serializers::JSON include ActiveModel::Serializers::Xml # ... end end
  14. class ReportValidator < ActiveModel::Validator def validate(report) if report.name.blank? report.errors.add :name,

    :blank end # More validations... end end Active Record ReportValidator < ActiveModel::Validator def validate(report)
  15. class Report include ActiveModel::Validations validates_with ReportValidator attr_accessor :name end Active

    Model include ActiveModel::Validations validates_with ReportValidator
  16. class Report include ActiveModel::Validations attr_accessor :name # validates_presence_of :name validates

    :name, presence: true end Active Model include ActiveModel::Validations validates :name, presence: true
  17. class Report include ActiveModel::Validations attr_accessor :no_name validates :no_name, absence: true

    end include ActiveModel::Validations validates :no_name, absence: true Active Model
  18. class AbsenceValidator < ActiveModel::EachValidator def validate_each(record, attribute, value) if value.present?

    record.errors.add attribute, :absence end end end AbsenceValidator Active Model
  19. class AbsenceValidator < ActiveModel::EachValidator def validate_each(record, attribute, value) if value.present?

    record.errors.add attribute, :absence end end end AbsenceValidator Active Model AbsenceValidator < ActiveModel::EachValidator def validate_each(record, attribute, value)
  20. class Report < ActiveRecord::Base before_save { puts "it works before"

    } after_save { puts "it works after as well" } end Active Record
  21. class Report extend ActiveModel::Callbacks define_model_callbacks :save before_save { puts "it

    works before" } after_save { puts "it works after as well" } def save run_callbacks :save do puts "saving..." end end end Active Model
  22. class Report extend ActiveModel::Callbacks define_model_callbacks :save before_save { puts "it

    works before" } after_save { puts "it works after as well" } def save run_callbacks :save do puts "saving..." end end end extend ActiveModel::Callbacks define_model_callbacks :save before_save { puts "it works before" } after_save { puts "it works after as well" } run_callbacks :save do puts "saving..." end Active Model
  23. class Report extend ActiveModel::Naming include ActiveModel::Serializers::JSON attr_accessor :name def attributes

    { name: name } end end Active Model include ActiveModel::Serializers::JSON def attributes { name: name } end
  24. report = Report.new report.name = "Omglol" puts report.to_xml #=> <?xml

    version="1.0" encoding="UTF-8"?> #=> <report> #=> <name>Omglol</name> #=> </report> Active Record
  25. class Report extend ActiveModel::Naming include ActiveModel::Serializers::Xml attr_accessor :name def attributes

    { name: name } end end include ActiveModel::Serializers::Xml def attributes { name: name } end Active Model
  26. report = Report.new report.name = "Omglol" puts report.to_xml #=> <?xml

    version="1.0" encoding="UTF-8"?> #=> <report> #=> <name>Omglol</name> #=> </report> Active Model
  27. report = Report.new puts report.name? #=> false report.name = "Omglol"

    puts report.name? #=> true report.name? #=> false report.name = "Omglol" report.name? #=> true Active Record
  28. class Report include ActiveModel::AttributeMethods attribute_method_suffix '?' define_attribute_methods [:name] attr_accessor :name

    private def attribute?(attr) send(attr).present? end end include ActiveModel::AttributeMethods attribute_method_suffix '?' define_attribute_methods [:name] def attribute?(attr) send(attr).present? end Active Model
  29. report = Report.new puts report.name? #=> false report.name = "Omglol"

    puts report.name? #=> true report.name? #=> false report.name = "Omglol" report.name? #=> true Active Model
  30. class Report include ActiveModel::AttributeMethods attribute_method_prefix 'clear_' define_attribute_methods [:name] attr_accessor :name

    private def clear_attribute(attr) send "#{attr}=", nil end end Active Model include ActiveModel::AttributeMethods attribute_method_prefix 'clear_' define_attribute_methods [:name] def clear_attribute(attr) send "#{attr}=", nil end
  31. report.name = "Omglol" puts report.name? #=> true report.clear_name puts report.name?

    #=> false report.name? #=> true report.clear_name report.name? #=> false Active Model
  32. class Invitation attr_accessor :contacts, :message def new_record? true end def

    id nil end end def new_record? true end def id nil end
  33. class Invitation attr_accessor :contacts, :message def new_record? true end def

    id nil end end def new_record? true end def id nil end
  34. <form action="/reports" class="new_report" id="new_report" method="post"> <label for="report_name">Nome</label> <input id="report_name" size="30"

    name="report[name]" type="text" /> <input name="commit" type="submit" value="Criar Relatório" /> </form>
  35. <form action="/reports" class="new_report" id="new_report" method="post"> <label for="report_name">Nome</label> <input id="report_name" size="30"

    name="report[name]" type="text" /> <input name="commit" type="submit" value="Criar Relatório" /> </form> <form action="/reports" class="new_report" id="new_report" method="post"> como?
  36. <form action="/reports" class="new_report" id="new_report" method="post"> <label for="report_name">Nome</label> <input id="report_name" size="30"

    name="report[name]" type="text" /> <input name="commit" type="submit" value="Criar Relatório" /> </form> <form action="/reports" class="new_report" id="new_report" method="post"> como?
  37. <form action="/reports" class="new_report" id="new_report" method="post"> <label for="report_name">Nome</label> <input id="report_name" size="30"

    name="report[name]" type="text" /> <input name="commit" type="submit" value="Criar Relatório" /> </form> <form action="/reports" class="new_report" id="new_report" method="post"> como?
  38. <form action="/reports" class="new_report" id="new_report" method="post"> <label for="report_name">Nome</label> <input id="report_name" size="30"

    name="report[name]" type="text" /> <input name="commit" type="submit" value="Criar Relatório" /> </form> <label for="report_name">Nome</label> como?
  39. <form action="/reports" class="new_report" id="new_report" method="post"> <label for="report_name">Nome</label> <input id="report_name" size="30"

    name="report[name]" type="text" /> <input name="commit" type="submit" value="Criar Relatório" /> </form> <label for="report_name">Nome</label> como?
  40. <form action="/reports" class="new_report" id="new_report" method="post"> <label for="report_name">Nome</label> <input id="report_name" size="30"

    name="report[name]" type="text" /> <input name="commit" type="submit" value="Criar Relatório" /> </form> <label for="report_name">Nome</label> como?
  41. <form action="/reports" class="new_report" id="new_report" method="post"> <label for="report_name">Nome</label> <input id="report_name" size="30"

    name="report[name]" type="text" /> <input name="commit" type="submit" value="Criar Relatório" /> </form> <input id="report_name" size="30" name="report[name]" type="text" /> como?
  42. <form action="/reports" class="new_report" id="new_report" method="post"> <label for="report_name">Nome</label> <input id="report_name" size="30"

    name="report[name]" type="text" /> <input name="commit" type="submit" value="Criar Relatório" /> </form> <input id="report_name" size="30" name="report[name]" type="text" /> como?
  43. <form action="/reports" class="new_report" id="new_report" method="post"> <label for="report_name">Nome</label> <input id="report_name" size="30"

    name="report[name]" type="text" /> <input name="commit" type="submit" value="Criar Relatório" /> </form> <input id="report_name" size="30" name="report[name]" type="text" /> como?
  44. <form action="/reports" class="new_report" id="new_report" method="post"> <label for="report_name">Nome</label> <input id="report_name" size="30"

    name="report[name]" type="text" /> <input name="commit" type="submit" value="Criar Relatório" /> </form> <input name="commit" type="submit" value="Criar Relatório" /> como?
  45. <form action="/reports" class="new_report" id="new_report" method="post"> <label for="report_name">Nome</label> <input id="report_name" size="30"

    name="report[name]" type="text" /> <input name="commit" type="submit" value="Criar Relatório" /> </form> <input name="commit" type="submit" value="Criar Relatório" /> como?
  46. module ActiveModel::Lint::Tests def test_to_key; end def test_to_param; end def test_to_partial_path;

    end def test_valid?; end def test_persisted?; end def test_model_naming; end def test_errors_aref; end def test_errors_full_messages; end end
  47. module ActiveModel::Lint::Tests def test_to_key; end def test_to_param; end def test_to_partial_path;

    end def test_valid?; end def test_persisted?; end def test_model_naming; end def test_errors_aref; end def test_errors_full_messages; end end to_key to_param to_partial_path valid? persisted? model_naming errors_aref errors_full_messages
  48. module ActiveModel::Lint::Tests def test_to_key; end def test_to_param; end def test_to_partial_path;

    end def test_valid?; end def test_persisted?; end def test_model_naming; end def test_errors_aref; end def test_errors_full_messages; end end to_key to_param to_partial_path valid? persisted? model_naming errors_aref errors_full_messages Naming
  49. puts Report.model_name #=> "Report" puts Report.model_name.singular #=> report puts Report.model_name.plural

    #=> reports puts Report.model_name.param_key #=> report model_name "Report" model_name.singular report model_name.plural reports model_name.param_key report
  50. module ActiveModel::Lint::Tests def test_to_key; end def test_to_param; end def test_to_partial_path;

    end def test_valid?; end def test_persisted?; end def test_model_naming; end def test_errors_aref; end def test_errors_full_messages; end end to_key to_param to_partial_path valid? persisted? model_naming errors_aref errors_full_messages Conversion
  51. module ActiveModel::Lint::Tests def test_to_key; end def test_to_param; end def test_to_partial_path;

    end def test_valid?; end def test_persisted?; end def test_model_naming; end def test_errors_aref; end def test_errors_full_messages; end end to_key to_param to_partial_path valid? persisted? model_naming errors_aref errors_full_messages Implementar
  52. report = Report.new report.id = 1 puts report.persisted? #=> true

    puts report.to_key #=> [1] puts report.to_param #=> '1'
  53. report = Report.new report.id = 1 puts report.persisted? #=> true

    puts report.to_key #=> [1] puts report.to_param #=> '1' report.persisted? #=> true report.to_key #=> [1] report.to_param #=> '1'
  54. module ActiveModel::Lint::Tests def test_to_key; end def test_to_param; end def test_to_partial_path;

    end def test_valid?; end def test_persisted?; end def test_model_naming; end def test_errors_aref; end def test_errors_full_messages; end end to_key to_param to_partial_path valid? persisted? model_naming errors_aref errors_full_messages Validations
  55. require 'minitest/autorun' class OmglolTest < MiniTest::Unit::TestCase include ActiveModel::Lint::Tests def setup

    @model = Omglol.new end end include ActiveModel::Lint::Tests def setup @model = Omglol.new end
  56. require 'active_model' class Omglol extend ActiveModel::Naming include ActiveModel::Conversion include ActiveModel::Validations

    def persisted?; false; end end extend ActiveModel::Naming include ActiveModel::Conversion include ActiveModel::Validations def persisted?; false; end
  57. $ ruby activemodel_test.rb Run options: --seed 9998 # Running tests:

    ........ Finished tests in 0.029155s, 274.3955 tests/s, 1303.3785 assertions/s. 8 tests, 38 assertions, 0 failures, 0 errors, 0 skips
  58. $ ruby activemodel_test.rb Run options: --seed 9998 # Running tests:

    ........ Finished tests in 0.029155s, 274.3955 tests/s, 1303.3785 assertions/s. 8 tests, 38 assertions, 0 failures, 0 errors, 0 skips
  59. module ActiveModel::Lint::Tests def test_to_key; end def test_to_param; end def test_to_partial_path;

    end def test_valid?; end def test_persisted?; end def test_model_naming; end def test_errors_aref; end def test_errors_full_messages; end end to_key to_param to_partial_path valid? persisted? model_naming errors_aref errors_full_messages
  60. module ActiveModel::Lint::Tests def test_to_key; end def test_to_param; end def test_to_partial_path;

    end def test_valid?; end def test_persisted?; end def test_model_naming; end def test_errors_aref; end def test_errors_full_messages; end end to_key to_param to_partial_path valid? persisted? model_naming errors_aref errors_full_messages Validations?
  61. module ActiveModel::Lint::Tests def test_to_key; end def test_to_param; end def test_to_partial_path;

    end def test_valid?; end def test_persisted?; end def test_model_naming; end def test_errors_aref; end def test_errors_full_messages; end end RAILS 4 to_key to_param to_partial_path valid? persisted? model_naming errors_aref errors_full_messages
  62. require 'minitest/autorun' class OmglolTest < MiniTest::Unit::TestCase include ActiveModel::Lint::Tests def setup

    @model = Omglol.new end end RAILS 4 include ActiveModel::Lint::Tests def setup @model = Omglol.new end
  63. require 'active_model' class Omglol extend ActiveModel::Naming include ActiveModel::Conversion def persisted?;

    false; end def errors; Hash.new([]); end end RAILS 4 def errors; Hash.new([]); end
  64. require 'active_model' class Omglol extend ActiveModel::Naming include ActiveModel::Conversion def persisted?;

    false; end def errors; Hash.new([]); end end RAILS 4 extend ActiveModel::Naming include ActiveModel::Conversion def persisted?; false; end def errors; Hash.new([]); end def errors; Hash.new([]); end
  65. $ ruby activemodel_master_test.rb Run options: --seed 10850 # Running tests:

    ...... Finished tests in 0.002590s, 2316.6023 tests/s, 11583.0116 assertions/s. 6 tests, 30 assertions, 0 failures, 0 errors, 0 skip
  66. $ ruby activemodel_master_test.rb Run options: --seed 10850 # Running tests:

    ...... Finished tests in 0.002590s, 2316.6023 tests/s, 11583.0116 assertions/s. 6 tests, 30 assertions, 0 failures, 0 errors, 0 skip
  67. require 'active_model' class Omglol extend ActiveModel::Naming include ActiveModel::Conversion def persisted?;

    false; end def errors; Hash.new([]); end end RAILS 4 extend ActiveModel::Naming include ActiveModel::Conversion def persisted?; false; end def errors; Hash.new([]); end
  68. module Model def self.included(base) #:nodoc: base.class_eval do extend ActiveModel::Naming extend

    ActiveModel::Translation include ActiveModel::Validations include ActiveModel::Conversion end end def initialize(params={}) params.each do |attr, value| self.public_send("#{attr}=", value) end if params end def persisted? false end end RAILS 4
  69. module Model def self.included(base) #:nodoc: base.class_eval do extend ActiveModel::Naming extend

    ActiveModel::Translation include ActiveModel::Validations include ActiveModel::Conversion end end def initialize(params={}) params.each do |attr, value| self.public_send("#{attr}=", value) end if params end def persisted? false end end RAILS 4 extend ActiveModel::Naming extend ActiveModel::Translation include ActiveModel::Validations include ActiveModel::Conversion def persisted? false end
  70. Active Model Attribute Methods Callbacks Dirty Mass Assignment Secure Password

    Observing Serialization Validations Validator Model Conversion Naming Translation Lint