big ruby 2014: a 4 pack of lightning talks
TRANSCRIPT
![Page 1: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/1.jpg)
![Page 2: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/2.jpg)
![Page 3: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/3.jpg)
Chris Morris Sr. Engineer
@the_chrismo
![Page 4: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/4.jpg)
4,000-plus-person company Almost $400 million in revenue
About $1 billion in sales last year Hundreds of millions in the bank
— TIM O'SHAUGHNESSY, CEO CNNMONEY - JAN 2014
![Page 5: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/5.jpg)
4 PACK OF LIGHTNING TALKS
![Page 6: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/6.jpg)
COBBLER’S PRODUCTION CONSOLE HAS NO SHOES
![Page 7: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/7.jpg)
LIVINGSOCIAL PAYMENTS
• Credit Card, PayPal, V.me, MasterPass, International (Adyen, iPay88)
• 1.5M API calls a day
• 70k-150k credit card transactions a day
![Page 8: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/8.jpg)
LIVINGSOCIAL PAYMENTS
• Whole Foods - 1,000,000
• Starbucks - 1,500,000
![Page 9: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/9.jpg)
![Page 10: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/10.jpg)
irb(main):004:0> Transaction.find_all_by_person_id 2 => [#<SaleTransaction id: 5, credit_card_id: 47523892, reference_transaction_id: nil, amount: #<BigDecimal:7fb60bc0ad78,'0.2E2',9(18)>, response: nil, transaction_type: "sale", aasm_state: "processed", created_at: "2014-02-04 19:42:57", updated_at: "2014-02-04 19:43:05", type: "SaleTransaction", callback_queue_name: "medium", callback_queue_application: "pry", options: "{\"country\":\"US\",\"profile\":null,\"requires_cvv\":null,...", processor_authorization_code: "illoearumi", gateway_transaction_id: "excepturiq", success: true, failure_reason: nil, avs_response_code: "M", cvv_response_code: "M", scope_identifier: nil, person_id: 2>, #<SaleTransaction id: 6, credit_card_id: 47523892, reference_transaction_id: nil, amount: #<BigDecimal:7fb60bc0a828,'0.2E2',9(18)>, response: nil, transaction_type: "sale", aasm_state: "processed", created_at: "2014-02-04 19:43:11", updated_at: "2014-02-04 19:43:20", type: "SaleTransaction", callback_queue_name: "medium", callback_queue_application: "pry", options: "{\"country\":\"US\",\"profile\":null,\"requires_cvv\":null,...", processor_authorization_code: "errorconse", gateway_transaction_id: "eumauttene", success: true, failure_reason: nil, avs_response_code: "M", cvv_response_code: "M", scope_identifier: nil, person_id: 2>]
![Page 11: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/11.jpg)
[159] pry(main)> b=PB.from_people_ids 2 => +----+-------------------------+------------+ | id | created_at | aasm_state | +----+-------------------------+------------+ | 5 | 2014-02-04 19:42:57 UTC | processed | | 6 | 2014-02-04 19:43:11 UTC | processed | +----+-------------------------+------------+
![Page 12: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/12.jpg)
![Page 13: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/13.jpg)
irb(main):080:0> b.options .=> [{"country"=>"US", "profile"=>nil, "requires_cvv"=>nil, "order"=>nil, "priority"=>nil, "use_deal_bucks"=>nil, "requires_avs"=>nil, "charge_distribution_strategy"=>nil, "device_data"=>nil}, {"country"=>"US", "profile"=>nil, "requires_cvv"=>nil, "order"=>nil, "priority"=>nil, "use_deal_bucks"=>nil, "requires_avs"=>nil, "charge_distribution_strategy"=>nil, "device_data"=>nil}]
![Page 14: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/14.jpg)
[33] pry(main)> b.options => [{"country"=>"US", "profile"=>nil, "requires_cvv"=>nil, "order"=>nil, "priority"=>nil, "use_deal_bucks"=>nil, "requires_avs"=>nil, "charge_distribution_strategy"=>nil, "device_data"=>nil}, {"country"=>"US", "profile"=>nil, "requires_cvv"=>nil, "order"=>nil, "priority"=>nil, "use_deal_bucks"=>nil, "requires_avs"=>nil, "charge_distribution_strategy"=>nil, "device_data"=>nil}]
![Page 15: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/15.jpg)
class Batch < Array def initialize(ary) self << ary flatten! end !! def method_missing(meth_id, *args) self.map do |t| t.send(meth_id, *args) end end end
![Page 16: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/16.jpg)
[14] pry(main)> b.map { |t| t.aasm_state } => ["processed", "processed"] [15] pry(main)> b.map(&:type) => ["SaleTransaction", "RefundTransaction"]
![Page 17: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/17.jpg)
[11] pry(main)> b.aasm_state => ["processed", "processed"] [12] pry(main)> b.type => ["SaleTransaction", "RefundTransaction"]
![Page 18: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/18.jpg)
class PaymentsBatch < Batch def self.from_people_ids(ary) transactions = [ary].flatten.collect do |person_id| Transaction.find_all_by_person_id(person_id) end PaymentsBatch.new(transactions) end end !PB = PaymentsBatch !![50] pry(main)> b=PB.from_people_ids 2 => #<PaymentsBatch:0x3fd8eab40048>
![Page 19: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/19.jpg)
![Page 20: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/20.jpg)
class PaymentsBatch < Batch def report puts self.map do |t| [t.id.to_s.ljust(5), t.created_at.to_s.ljust(25), t.aasm_state.to_s.ljust(15)].join end.join("\n") end end !![75] pry(main)> b.report 5 2014-02-04 19:42:57 UTC processed 6 2014-02-04 19:43:11 UTC processed => nil
![Page 21: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/21.jpg)
class PaymentsBatch < Batch def report self.map do |t| [t.id, t.created_at, t.aasm_state] end.to_text_table end end ![22] pry(main)> b.report => +---+-------------------------+-----------+ | 5 | 2014-02-04 19:42:57 UTC | processed | | 6 | 2014-02-04 19:43:11 UTC | processed | | 7 | 2014-02-04 19:43:42 UTC | processed | +---+-------------------------+-----------+
![Page 22: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/22.jpg)
![Page 23: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/23.jpg)
class PaymentsBatch < Batch def report cols = [:id, :created_at, :aasm_state] h = serializable_hash(only: cols) rows = ([h.first.keys] + h.map(&:values)) rows.to_table(:first_row_is_head => true) end end !![87] pry(main)> b.report => +------------+-------------------------+----+ | aasm_state | created_at | id | +------------+-------------------------+----+ | processed | 2014-02-04 19:42:57 UTC | 5 | | processed | 2014-02-04 19:43:11 UTC | 6 | | processed | 2014-02-04 19:43:42 UTC | 7 | +------------+-------------------------+----+
![Page 24: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/24.jpg)
[155] pry(main)> b=PB.from_people_ids 2 => [#<SaleTransaction id: 5, credit_card_id: 47523892, reference_transaction_id: nil, amount: #<BigDecimal:7ff71ecc9b48,'0.2E2',9(18)>, response: nil, transaction_type: "sale", aasm_state: "processed", created_at: "2014-02-04 19:42:57", updated_at: "2014-02-04 19:43:05", type: "SaleTransaction", callback_queue_name: "medium", callback_queue_application: "pry", options: "{\"country\":\"US\",\"profile\":null,\"requires_cvv\":null,...", processor_authorization_code: "illoearumi", gateway_transaction_id: "excepturiq", success: true, failure_reason: nil, avs_response_code: "M", cvv_response_code: "M", scope_identifier: nil, person_id: 2>, #<SaleTransaction id: 6, credit_card_id: 47523892, reference_transaction_id: nil, amount: #<BigDecimal:7ff71ecc9620,'0.2E2',9(18)>, response: nil, transaction_type: "sale", aasm_state: "processed", created_at: "2014-02-04 19:43:11", updated_at: "2014-02-04 19:43:20", type: "SaleTransaction", callback_queue_name: "medium", callback_queue_application: "pry", options: "{\"country\":\"US\",\"profile\":null,\"requires_cvv\":null,...", processor_authorization_code: "errorconse", gateway_transaction_id: "eumauttene", success: true, failure_reason: nil, avs_response_code: "M", cvv_response_code: "M", scope_identifier: nil, person_id: 2>] [156] pry(main)> b.report .=> +----+-------------------------+------------+ | id | created_at | aasm_state | +----+-------------------------+------------+ | 5 | 2014-02-04 19:42:57 UTC | processed | | 6 | 2014-02-04 19:43:11 UTC | processed | +----+-------------------------+------------+
LOL
![Page 25: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/25.jpg)
class Batch < Array def pretty_inspect report.to_s end end
![Page 26: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/26.jpg)
[155] pry(main)> b=PB.from_people_ids 2 => +----+-------------------------+------------+ | id | created_at | aasm_state | +----+-------------------------+------------+ | 5 | 2014-02-04 19:42:57 UTC | processed | | 6 | 2014-02-04 19:43:11 UTC | processed | +----+-------------------------+------------+
![Page 27: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/27.jpg)
class PaymentsBatch def email addr = '[email protected]' Mail::Message.new(to: addr, from: addr, subject: 'PaymentsBatch', body: report.to_s).deliver end end
![Page 28: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/28.jpg)
LOG SEARCH
![Page 29: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/29.jpg)
chris.morris@support01:$ RAILS_ENV=production bundle exec thor grep:payments -p '(PCI|SPT) environment' -d 1 ********** support01 ********** ssh support01 'grep -P "(PCI|SPT) environment" log/production.log-20140218' 14-02-18T02:48:20 - [INFO] (#21648) SPT environment forwarding #create to PCI environment 14-02-18T02:49:22 - [INFO] (#21651) SPT environment forwarding #create to PCI environment 14-02-18T03:00:04 - [INFO] (#21648) SPT environment forwarding #create to PCI environment ********** support02 ********** ssh support02 'grep -P "(PCI|SPT) environment" log/production.log-20140218' 14-02-17T15:00:50 - [INFO] (#3844) SPT environment forwarding #create to PCI environment 14-02-17T19:18:37 - [INFO] (#3841) SPT environment forwarding #create to PCI environment 14-02-17T22:12:38 - [INFO] (#3844) SPT environment forwarding #create to PCI environment 14-02-18T01:40:56 - [INFO] (#3844) SPT environment forwarding #create to PCI environment ********** boxen01 ********** ssh boxen01 'grep -P "(PCI|SPT) environment" log/production.log-20140218' 14-02-17T19:18:37 - [INFO] (#24618) PCI environment handling #create 14-02-18T01:40:56 - [INFO] (#24618) PCI environment handling #create 14-02-18T02:49:22 - [INFO] (#24615) PCI environment handling #create ********** boxen02 ********** ssh boxen02 'grep -P "(PCI|SPT) environment" log/production.log-20140218' 14-02-17T15:00:50 - [INFO] (#8119) PCI environment handling #create 14-02-17T22:12:38 - [INFO] (#8129) PCI environment handling #create 14-02-18T02:48:20 - [INFO] (#8125) PCI environment handling #create 14-02-18T03:00:04 - [INFO] (#8122) PCI environment handling #create
![Page 30: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/30.jpg)
chris.morris@support01:$ RAILS_ENV=production bundle exec thor grep:payments -p '(PCI|SPT) environment' -d 1 -c --pry ********** support01 ********** ssh support01 'grep -P -C 15 "(PCI|SPT) environment" log/production.log-20140218' ********** support02 ********** ssh support02 'grep -P -C 15 "(PCI|SPT) environment" log/production.log-20140218' ********** boxen01 ********** ssh boxen01 'grep -P -C 15 "(PCI|SPT) environment" log/production.log-20140218' ********** boxen02 ********** ssh boxen02 'grep -P -C 15 "(PCI|SPT) environment" log/production.log-20140218' +-------+---------------------+--------+-------------+---------------+ | pid | timestamp | action | status_code | ip_addr | +-------+---------------------+--------+-------------+---------------+ | 3844 | 2014-02-17T15:00:50 | POST | 201 | x.x.x.x | | 8119 | 2014-02-17T15:00:50 | POST | 201 | x.x.x.x | | 3841 | 2014-02-17T19:18:36 | POST | 500 | x.x.x.x | | 24618 | 2014-02-17T19:18:37 | POST | 500 | x.x.x.x | | 8129 | 2014-02-17T22:12:38 | POST | 201 | x.x.x.x | | 3844 | 2014-02-17T22:12:38 | POST | 201 | x.x.x.x | | 24618 | 2014-02-18T01:40:56 | POST | 201 | x.x.x.x | | 21648 | 2014-02-18T02:48:20 | POST | 201 | x.x.x.x | | 8125 | 2014-02-18T02:48:20 | POST | 201 | x.x.x.x | | 24615 | 2014-02-18T02:49:22 | POST | 400 | x.x.x.x | | 21651 | 2014-02-18T02:49:22 | POST | 500 | x.x.x.x | | 21648 | 2014-02-18T03:00:04 | POST | 201 | x.x.x.x | | 8122 | 2014-02-18T03:00:04 | POST | 201 | x.x.x.x | +-------+---------------------+--------+-------------+---------------+
![Page 31: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/31.jpg)
From: script/grep.payments.thor @ line 81 Thor::Sandbox::Grep#payments: ! 76: wheelhouse = Wheelhouse.new(sio) 77: chunks = wheelhouse.chunk_it(:grep => options[:pattern], 78: :filename => options[:save_chunks], 79: :range_threshold_in_seconds => options[:timestamp_range_in_seconds]) 80: puts wheelhouse.to_text_table(chunks) => 81: binding.pry if options[:pry] 82: end 83: end 84: 85: private 86: ![1] pry(#<Thor::Sandbox::Grep>)>
![Page 32: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/32.jpg)
[1] pry(#<Thor::Sandbox::Grep>)> chunks => [#<RequestChunk:0x00000004f39540 @action="POST", @completed=true, @controller="Api::V1::CreditCardsController#create", @ip_addr="x.x.x.x", @lines= ["14-02-18T02:48:20 - [INFO] (#21648) Started POST ... for x.x.x.x with ...", "14-02-18T02:48:20 - [INFO] (#21648) Processing by Api::V1::CreditCards...", "14-02-18T02:48:20 - [INFO] (#21648) Parameters: {\"...\"", "14-02-18T02:48:20 - [INFO] (#21648) SPT environment forwarding #create...", "14-02-18T02:48:22 - [INFO] (#21648) Completed 201 Created in 1279.5ms ..."] @parameters= {"foo"=> {"token"=>"e4facf2d83cf58bd78b05485e21d0923", "checkout_resource_url"=>"https://foobar.com", "return_url"=>"https://www.livingsocial.com", "country_code"=>"AU"}, "person_id"=>"12345678"}, @pid="21648", @range_threshold_in_seconds=2, @referrer="", @route="http://...", @status_code="201", @timestamp="2014-02-18T02:48:20", @user_agent="Ruby">,
![Page 33: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/33.jpg)
![Page 34: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/34.jpg)
THE END
![Page 35: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/35.jpg)
DIY MOCKS AND FIXTURES
![Page 36: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/36.jpg)
RAVE REVIEWS
"You either get an F for logic or an A+ for balls.”
!
!
— J. B. Rainsberger author of JUnit Recipes
![Page 37: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/37.jpg)
[~]$ curl -s http://www.linkedin.com/in/chrismo | grep Relevance [~]$
![Page 38: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/38.jpg)
![Page 39: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/39.jpg)
NOT GLENN VANDERBURG =>
![Page 40: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/40.jpg)
NOT GLENN VANDERBURG =>
!
CODMONGER !
![Page 41: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/41.jpg)
FactoryGirl.define do factory :customer do external_record_type 'person' sequence(:external_id) email Faker::Internet.email end ! factory :address do name Faker::Name.name customer end ! sequence :purchase_external_id sequence :purchase_deal_id ! factory :purchase do currency 'USD' external_record_type 'purchase' external_id { FactoryGirl.generate(:purchase_external_id) } deal_id { FactoryGirl.generate(:purchase_deal_id) } price { rand(50) + 1 } customer association :address, :method => :build quantity { rand(4) + 1 } title Faker::Company.catch_phrase end ! factory :collection do purchase end end
![Page 42: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/42.jpg)
describe Collection do it "should not return old exported collection with end status" do [:collected, :canceled, :refused].each do |status| collection = Factory.build(:collection, :exported_at => 4.days.ago, :status => status.to_s) assert !Collection.problem_old_exports.include?(collection) end end
![Page 43: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/43.jpg)
describe Collection do it "should not return old exported collection with end status" do [:collected, :canceled, :refused].each do |status| collection = Factory.build(:collection, :exported_at => 4.days.ago, :status => status.to_s) assert !Collection.problem_old_exports.include?(collection) end end end
NoMethodError: undefined method `customer' for nil:NilClass ./app/models/collection.rb:90:in `customer' ./app/models/collection.rb:14:in `block in <class:Collection>' ./spec/models/collection_spec.rb:43:in `block (3 levels) in <top (required)>' ./spec/models/collection_spec.rb:42:in `each' ./spec/models/collection_spec.rb:42:in `block (2 levels) in <top (required)>'
![Page 44: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/44.jpg)
class Collection < ActiveRecord::Base def customer purchase.customer end end
NoMethodError: undefined method `customer' for nil:NilClass ./app/models/collection.rb:90:in `customer' ./app/models/collection.rb:14:in `block in <class:Collection>' ./spec/models/collection_spec.rb:43:in `block (3 levels) in <top (required)>' ./spec/models/collection_spec.rb:42:in `each' ./spec/models/collection_spec.rb:42:in `block (2 levels) in <top (required)>'
![Page 45: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/45.jpg)
FactoryGirl.define do ... # YOU HAD ONE JOB factory :collection do purchase end end
![Page 46: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/46.jpg)
require 'machinist/active_record' require 'faker' !Sham.sham_id { |i| i } !Customer.blueprint do external_record_type { 'person' } external_id { Sham.sham_id } email { Faker::Internet.email } end !Address.blueprint do name Faker::Name.name customer purchase end !Purchase.blueprint do currency {'USD'} external_record_type {'purchase'} external_id { Sham.sham_id } deal_id { Sham.sham_id } price { rand(50) + 1 } customer quantity { rand(4) + 1 } title { Faker::Company.catch_phrase } end !Collection.blueprint do purchase end
![Page 47: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/47.jpg)
describe Collection, 'scope :problem_old_exports (machinist)' do it "should not return old exported collection with end status" do [:collected, :canceled, :refused].each do |status| collection = Collection.make_unsaved(:exported_at => 4.days.ago, :status => status.to_s) assert !Collection.problem_old_exports.include?(collection) end end end
![Page 48: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/48.jpg)
describe Collection, 'scope :problem_old_exports (machinist)' do it "should not return old exported collection with end status" do [:collected, :canceled, :refused].each do |status| collection = Collection.make_unsaved(:exported_at => 4.days.ago, :status => status.to_s) assert !Collection.problem_old_exports.include?(collection) end end end
!NoMethodError: undefined method `customer' for nil:NilClass ./app/models/collection.rb:90:in `customer' ./app/models/collection.rb:14:in `block in <class:Collection>' ./spec/models/collection_spec.rb:61:in `block (3 levels) in <top (required)>' ./spec/models/collection_spec.rb:60:in `each' ./spec/models/collection_spec.rb:60:in `block (2 levels) in <top (required)>'
![Page 49: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/49.jpg)
!# ONE. JOB. Collection.blueprint do purchase end
![Page 50: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/50.jpg)
![Page 51: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/51.jpg)
![Page 52: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/52.jpg)
require 'faker' !class CodmongerFixture def self.create(opts={}) record = self.new(opts); record.save!; record end end !class AddressFixture < CodmongerFixture def self.new(opts={}) Address.new({:name => Faker::Name.name}.merge(opts)) end end !class CustomerFixture < CodmongerFixture @@customer_id = Customer.last.external_id + 1 rescue 1 def self.new(opts={}) Customer.new({:external_record_type => 'person', :external_id => @@customer_id += 1, :email => Faker::Internet.email}.merge(opts)) end end !class PurchaseFixture < CodmongerFixture @@purchase_id = Purchase.last.external_id + 1 rescue 1 def self.new(opts={}) customer = CustomerFixture.new Purchase.new({:currency => 'USD', :deal_id => 1, :external_record_type => 'purchase', :external_id => @@purchase_id += 1, :price => rand(50) + 1, :quantity => rand(4) + 1, :title => Faker::Company.catch_phrase, :address => AddressFixture.new(:customer => customer), :customer => customer}.merge(opts)) end end !class CollectionFixture < CodmongerFixture def self.new(opts={}) Collection.new({:purchase => PurchaseFixture.new}.merge(opts)) end end
![Page 53: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/53.jpg)
describe Collection do it "should not return old exported collection with end status" do [:collected, :canceled, :refused].each do |status| collection = CollectionFixture.new(:exported_at => 4.days.ago, :status => status.to_s) assert !Collection.problem_old_exports.include?(collection) end end end
1 example, 0 failures, 1 passed
![Page 54: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/54.jpg)
![Page 55: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/55.jpg)
FactoryGirl::Proxy::ObjectWrapper
def object @object ||= @klass.new assign_object_attributes @object end
![Page 56: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/56.jpg)
class Collection < ActiveRecord::Base state_machine :status, :initial => lambda{ |collection| collection.customer.new? ? :received : :customer_verified} do ... end end
![Page 57: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/57.jpg)
![Page 58: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/58.jpg)
ACTIVE RECORD IS
HARD ENOUGH !
!
I DON’T NEED YOUR FREEKING
DSL ON TOP OF IT
![Page 59: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/59.jpg)
![Page 60: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/60.jpg)
![Page 61: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/61.jpg)
require 'faker' !class CodmongerFixture def self.create(opts={}) record = self.new(opts); record.save!; record end end !class AddressFixture < CodmongerFixture def self.new(opts={}) Address.new({:name => Faker::Name.name}.merge(opts)) end end !class CustomerFixture < CodmongerFixture @@customer_id = Customer.last.external_id + 1 rescue 1 def self.new(opts={}) Customer.new({:external_record_type => 'person', :external_id => @@customer_id += 1, :email => Faker::Internet.email}.merge(opts)) end end !class PurchaseFixture < CodmongerFixture @@purchase_id = Purchase.last.external_id + 1 rescue 1 def self.new(opts={}) customer = CustomerFixture.new Purchase.new({:currency => 'USD', :deal_id => 1, :external_record_type => 'purchase', :external_id => @@purchase_id += 1, :price => rand(50) + 1, :quantity => rand(4) + 1, :title => Faker::Company.catch_phrase, :address => AddressFixture.new(:customer => customer), :customer => customer}.merge(opts)) end end !class CollectionFixture < CodmongerFixture def self.new(opts={}) Collection.new({:purchase => PurchaseFixture.new}.merge(opts)) end end
![Page 62: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/62.jpg)
FactoryGirl.define do factory :customer do external_record_type 'person' sequence(:external_id) email Faker::Internet.email end ! factory :address do name Faker::Name.name customer end ! sequence :purchase_external_id sequence :purchase_deal_id ! factory :purchase do currency 'USD' external_record_type 'purchase' external_id { FactoryGirl.generate(:purchase_external_id) } deal_id { FactoryGirl.generate(:purchase_deal_id) } price { rand(50) + 1 } customer association :address, :method => :build quantity { rand(4) + 1 } title Faker::Company.catch_phrase end ! factory :collection do purchase end end
![Page 63: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/63.jpg)
require 'faker' !class CodmongerFixture def self.create(opts={}) record = self.new(opts); record.save!; record end end !class AddressFixture < CodmongerFixture def self.new(opts={}) Address.new({:name => Faker::Name.name}.merge(opts)) end end !class CustomerFixture < CodmongerFixture @@customer_id = Customer.last.external_id + 1 rescue 1 def self.new(opts={}) Customer.new({:external_record_type => 'person', :external_id => @@customer_id += 1, :email => Faker::Internet.email}.merge(opts)) end end
![Page 64: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/64.jpg)
class PurchaseFixture < CodmongerFixture @@purchase_id = Purchase.last.external_id + 1 rescue 1 def self.new(opts={}) customer = CustomerFixture.new Purchase.new({:currency => 'USD', :deal_id => 1, :external_record_type => 'purchase', :external_id => @@purchase_id += 1, :price => rand(50) + 1, :quantity => rand(4) + 1, :title => Faker::Company.catch_phrase, :address => AddressFixture.new(:customer => customer), :customer => customer}.merge(opts)) end end !class CollectionFixture < CodmongerFixture def self.new(opts={}) Collection.new({:purchase => PurchaseFixture.new}.merge(opts)) end end
![Page 65: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/65.jpg)
WHEN A DSL POOPS OUT ON YOU
!
YOU CAN'T LOOK AT ITS SOURCE CODE
!
BECAUSE IT'S ALL META AND STUFF.
![Page 66: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/66.jpg)
MOCK FRAMEWORKSNOT ALL EXPECTATIONS WERE SATISFIED
![Page 67: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/67.jpg)
not all expectations were satisfied unsatisfied expectations: - expected exactly once, not yet invoked: Purchase(id: integer, person_id: integer, deal_id: integer, created_at: datetime, updated_at: datetime, credit_card_id: integer, ref_code: string, charged_at: datetime, coupons_count: integer, aasm_state: string, approval_code: string, referring_purchase_id: integer, referring_purchases_count: integer, discount: decimal, referring_user_id: integer, last_transaction_id: string, collapsed: boolean, blasted_to_feed_at: datetime, fb_fan_incentive: decimal, deleted_at: datetime, latitude: float, longitude: float, ip_address: string, visa_discount: decimal, purchaser_id: integer, cheerios_discount: decimal, city_id: integer).find('1234567')
![Page 68: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/68.jpg)
unexpected invocation: #<Mock:0x1022aff50>.reload() satisfied expectations: - allowed any number of times, not yet invoked: #<Mock:0x1022b6df0>.available_credit(any_parameters) - allowed any number of times, not yet invoked: #<Mock:0x1022b6df0>.available_credit(any_parameters) - allowed any number of times, not yet invoked: #<Mock:0x1022b6df0>.Person(any_parameters) - allowed any number of times, not yet invoked: #<Mock:0x1022b57e8>.LocalDeal(any_parameters) - allowed any number of times, not yet invoked: #<Mock:0x1022aff50>.Purchase(any_parameters) - allowed any number of times, not yet invoked: #<Mock:0x1022aff50>.total_price(any_parameters) - allowed any number of times, not yet invoked: #<Mock:0x1022aff50>.alternate_payment(any_parameters) - allowed any number of times, invoked once: #<Mock:0x1022aff50>.person(any_parameters) - allowed any number of times, invoked once: #<Mock:0x1022aff50>.deal(any_parameters) - allowed any number of times, not yet invoked: #<Mock:0x1022aff50>.aasm_state(any_parameters) - allowed any number of times, not yet invoked: #<Mock:0x1022aff50>.id(any_parameters) - allowed any number of times, invoked once: #<Mock:0x1022aff50>.referred_purchases(any_parameters)
![Page 69: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/69.jpg)
purchase = stub() purchase.stubs(:id).returns(123) purchase.stubs(:quantity).returns(2) !deal = stub() deal.stubs(:title).returns("Mr. Bones's Deal'") deal.stubs(:price).returns(12) deal.stubs(:currency_unit).returns('$') !person = stub() person.stubs(:email).returns('[email protected]') person.stubs(:id).returns(8675309) !purchase.stubs(:person).returns(person) purchase.stubs(:deal).returns(deal)
![Page 70: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/70.jpg)
PurchaseStub = Struct.new(:id, :quantity, :deal, :person) DealStub = Struct.new(:title, :price, :currency_unit) PersonStub = Struct.new(:id, :email) !person = PersonStub.new(8675309, '[email protected]') deal = DealStub.new("Mr. Bones's Deal'", 12, '$') purchase = PurchaseStub.new(123, 2, deal, person)
![Page 71: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/71.jpg)
person = OpenStruct.new(id: 8675309, email: '[email protected]') !deal = OpenStruct.new(title: "Mr. Bones's Deal'", price: 12, currency_unit: '$') !purchase = OpenStruct.new(id: 123, quantity: 2, deal: deal, person: person)
![Page 72: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/72.jpg)
require 'ostruct' !person = OpenStruct.new(id: 8675309, email: '[email protected]', available_credit: {'USD'=>5,'MYR'=>0}) !def person.available_credit_by_currency(currency) self.available_credit[currency] end
![Page 73: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/73.jpg)
module PaymentProviders module DoubleFake class Payment @@db = {} ! def self.load_payment(id, params) @@db[id] end ! def initialize(purchase, hash, all_params={}) @hash = hash end ! def address @hash[:address] end ! def save @@db[@hash[:id]] = self end end end end
![Page 74: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/74.jpg)
DIY
—
Gem
![Page 75: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/75.jpg)
BUILD —
BUY
![Page 76: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/76.jpg)
BUYtrades in
FAMILIARITY
TRANSPARENCY
![Page 77: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/77.jpg)
![Page 78: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/78.jpg)
![Page 79: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/79.jpg)
THE END
![Page 80: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/80.jpg)
TRACK YER BIG STUFF
![Page 81: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/81.jpg)
No tengo ni idea de lo que estoy haciendo
![Page 82: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/82.jpg)
• 2500 translation keys
• 1/2 in use
![Page 83: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/83.jpg)
dozens of translate calls / request
![Page 84: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/84.jpg)
![Page 85: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/85.jpg)
![Page 86: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/86.jpg)
module Humperdink class DirtySet attr_reader :dirty, :clean, :config ! def initialize(initial_contents=[], config={}) @clean = Set.new(initial_contents) @dirty = Set.new @config = config end ! def <<(value) @dirty << value if [email protected]?(value) clean! if getting_messy? end ! def getting_messy? ... end ! def clean! @clean.merge(@dirty) cleaned = @dirty.to_a.dup @dirty.clear cleaned end ! def length # wonky -> doesn't include @dirty @clean.length end ! def clear @clean.clear @dirty.clear end end end
![Page 87: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/87.jpg)
describe Humperdink::DirtySet do let(:set) { Humperdink::DirtySet.new } ! it 'should only append to dirty' do set << ‘foo' set.dirty.should == ['foo'].to_set set.clean.should == [].to_set end ! it 'should clean! dirty things to clean' do set << 'foo' wuz_dirty = set.clean! wuz_dirty.should == [‘foo'] set.dirty.should == [].to_set set.clean.should == ['foo'].to_set end end
![Page 88: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/88.jpg)
it 'should only append to dirty if not in clean' do set << ‘foo' set.dirty.should == ['foo'].to_set set.clean.should == [].to_set ! set.clean! set.dirty.should == [].to_set set.clean.should == ['foo'].to_set ! set << ‘foo' set.dirty.should == [].to_set set.clean.should == ['foo'].to_set end
![Page 89: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/89.jpg)
it 'should initialize clean with initialize' do set = Humperdink::DirtySet.new(['a', ‘b']) set.dirty.should == [].to_set set.clean.should == ['a', 'b'].to_set end ! it 'should only append to dirty if not in clean' do set = Humperdink::DirtySet.new(['foo']) set << ‘foo' set.dirty.should == [].to_set set.clean.should == ['foo'].to_set end
![Page 90: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/90.jpg)
module Humperdink class RedisDirtySet < DirtySet def initialize(initial_content=[], config={}) super(initial_content, config) end ! def clean! to_save = super save(to_save) end ! def load @clean.merge(redis.smembers(@config[:key])) end ! def save(to_save) redis.sadd(@config[:key], to_save.to_a) end end end
![Page 91: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/91.jpg)
module Humperdink class Tracker attr_reader :set, :config ! def initialize(set=Set.new, config={}) @set = set @config = config end ! def track(data) @set << data end ! def tracker_enabled @config[:enabled] end ! # Anytime an exception happens, we want to skedaddle out of the way # and let life roll on without any tracking in the loop. def shutdown(exception) begin on_event(:shutdown, "#{exception.message}") rescue => e $stderr.puts([e.message, e.backtrace].join("\n")) rescue nil end @config[:enabled] = false end end end
![Page 92: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/92.jpg)
class KeyTracker def initialize(redis, key) redis_set = Humperdink::RedisDirtySet.new(:redis => redis, :key => key, :max_dirty_items => 9) @tracker = Humperdink::Tracker.new(redis_set, :enabled => true) end ! def on_translate(locale, key, options = {}) begin if @tracker.tracker_enabled requested_key = normalize_requested_key(key, options) @tracker.track(requested_key) end rescue => e @tracker.shutdown(e) end end end
![Page 93: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/93.jpg)
module KeyTrackerBackend def key_tracker @key_tracker end ! def key_tracker=(value) @key_tracker = value end ! def translate(locale, key, options = {}) @key_tracker.on_translate(locale, key, options) if @key_tracker super end end !def setup @redis = Redis.connect(:url => 'redis://127.0.0.1:6379/8') @redis_key = 'humperdink:example:i18n' ! tracker = KeyTracker.new(@redis, @redis_key) I18n.backend.class.class_eval { include KeyTrackerBackend } I18n.backend.key_tracker = tracker end
![Page 94: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/94.jpg)
CONFIGURATION
![Page 95: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/95.jpg)
module Humperdink class DirtySet ! def <<(value) @dirty << value if [email protected]?(value) clean! if getting_messy? end ! end end
![Page 96: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/96.jpg)
module Humperdink class DirtySet ! def getting_messy? if @config[:max_dirty_items] && @dirty.length > @config[:max_dirty_items] return true end ! if @config[:clean_timeout] && Time.now > @time_to_clean return true end end ! end end
![Page 97: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/97.jpg)
module Humperdink class DirtySet def initialize(initial_contents=[], config={}) @clean = Set.new(initial_contents) @dirty = Set.new @config = config ... at_exit { clean! if @config[:clean_at_exit] } end end end
![Page 98: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/98.jpg)
CONFIGURATIONRESQUE
![Page 99: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/99.jpg)
module Resque class Worker def work(interval = 5.0, &block) loop do break if shutdown? ! if not paused? and job = reserve if @child = fork(job) ... else perform(job, &block) exit!(true) if will_fork? end ! done_working @child = nil else sleep interval end end end end end
![Page 100: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/100.jpg)
module Humperdink::ForkPiping
![Page 101: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/101.jpg)
class KeyTracker def initialize(redis, key) redis_set = Humperdink::RedisDirtySet.new(:redis => redis, :key => key, :max_dirty_items => 9) @tracker = Humperdink::Tracker.new(redis_set, :enabled => true) @tracker.include Humperdink::ForkPiping end end
![Page 102: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/102.jpg)
def on_translate(locale, key, options = {}) begin if @tracker.tracker_enabled requested_key = normalize_requested_key(key, options) @tracker.track(requested_key) end rescue => e @tracker.shutdown(e) end end
![Page 103: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/103.jpg)
def on_translate(locale, key, options = {}) begin if @tracker.not_forked_or_parent_process if @tracker.tracker_enabled requested_key = normalize_requested_key(key, options) @tracker.track(requested_key) end else if @tracker.config[:enabled] requested_key = normalize_requested_key(key, options) @tracker.write_to_child_pipe(requested_key) end end rescue => e @tracker.shutdown(e) end end
![Page 104: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/104.jpg)
![Page 106: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/106.jpg)
use Coverband::Middleware
![Page 107: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/107.jpg)
module Coverband class Middleware ! def call(env) configure_sampling record_coverage results = @app.call(env) report_coverage results end ! end end
![Page 108: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/108.jpg)
def configure_sampling if (rand * 100.0) > @sample_percentage @enabled = false else @enabled = true end end
![Page 109: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/109.jpg)
def record_coverage if @enabled unless @function_set set_trace_func proc { |event, file, line, id, binding, classname| add_file(file, line) } @function_set = true end else if @function_set set_trace_func(nil) @function_set = false end end end
![Page 110: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/110.jpg)
module Coverband class Middleware ! def call(env) configure_sampling record_coverage results = @app.call(env) report_coverage results end ! end end
![Page 111: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/111.jpg)
![Page 112: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/112.jpg)
<= NOT DAN MAYER
![Page 113: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/113.jpg)
THE END
![Page 114: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/114.jpg)
ALL THE ANALOGIES
![Page 115: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/115.jpg)
![Page 116: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/116.jpg)
![Page 117: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/117.jpg)
![Page 118: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/118.jpg)
![Page 119: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/119.jpg)
![Page 120: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/120.jpg)
![Page 121: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/121.jpg)
![Page 122: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/122.jpg)
![Page 123: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/123.jpg)
![Page 124: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/124.jpg)
![Page 125: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/125.jpg)
![Page 126: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/126.jpg)
![Page 127: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/127.jpg)
![Page 128: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/128.jpg)
![Page 129: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/129.jpg)
![Page 130: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/130.jpg)
![Page 131: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/131.jpg)
![Page 132: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/132.jpg)
META
![Page 133: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/133.jpg)
![Page 134: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/134.jpg)
![Page 135: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/135.jpg)
THE END
![Page 136: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/136.jpg)
Chris Morris Sr. Engineer
@the_chrismo
![Page 137: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/137.jpg)
CREDITShttp://www.flickr.com/photos/tracy_olson/61056391/ http://imgs.xkcd.com/comics/the_general_problem.png http://upload.wikimedia.org/wikipedia/commons/a/a3/PikePlaceMarket2006.jpg http://pixabay.com/en/why-question-gorilla-monkey-234596/ http://www.flickr.com/photos/liquidator/3450997601/in/photostream/ http://upload.wikimedia.org/wikipedia/commons/c/c2/EWM_shop_2007.jpg http://upload.wikimedia.org/wikipedia/commons/5/52/Vader_2011_in_Rostock.jpg http://upload.wikimedia.org/wikipedia/commons/4/4e/Construction_in_Toronto_May_2012.jpg http://upload.wikimedia.org/wikipedia/commons/9/9a/SF_Japanese_Garden.JPG http://upload.wikimedia.org/wikipedia/commons/3/32/Climbing_in_Joshua_Tree_NP.jpg http://www.flickr.com/photos/pagedooley/7899921242/ http://upload.wikimedia.org/wikipedia/commons/f/f3/Symfonicky_orchestr_hl._m._Prahy_FOK.jpg http://upload.wikimedia.org/wikipedia/commons/5/57/Chess-king.JPG http://upload.wikimedia.org/wikipedia/commons/6/62/ElBulliKitchen.jpg http://farm7.staticflickr.com/6020/5994637447_01d1e6107a_o.jpg http://static3.wikia.nocookie.net/__cb20100721202821/muppet/images/5/52/Bobby_Benson_and_the_Babies.jpg http://upload.wikimedia.org/wikipedia/commons/f/fd/Detail_Lewis_%26_Clark_at_Three_Forks.jpg http://upload.wikimedia.org/wikipedia/commons/e/e3/Lewis_and_Clark_track_map_published_1814_LoC.jpg http://www.fhwa.dot.gov/byways/Uploads/asset_files/000/006/078/Rugged_Point.jpg http://www.geograph.org.uk/photo/2415063 http://www.flickr.com/photos/18203311@N08/4405479417/ http://upload.wikimedia.org/wikipedia/commons/4/45/Thomas_Eakins,_The_Agnew_Clinic_1889.jpg http://www.flickr.com/photos/theslowlane/6111718072/
![Page 138: Big Ruby 2014: A 4 Pack of Lightning Talks](https://reader033.vdocument.in/reader033/viewer/2022052514/542b483f8d7f7247428b5d6e/html5/thumbnails/138.jpg)
Chris Morris Sr. Engineer
@the_chrismo