Nordic Ruby 2011
Upcoming SlideShare
Loading in...5
×
 

Nordic Ruby 2011

on

  • 3,611 views

 

Statistics

Views

Total Views
3,611
Views on SlideShare
3,606
Embed Views
5

Actions

Likes
3
Downloads
16
Comments
1

2 Embeds 5

http://twitter.com 3
https://twitter.com 2

Accessibility

Categories

Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

Nordic Ruby 2011 Nordic Ruby 2011 Presentation Transcript

  • Saturday, June 18, 2011
  • Saturday, June 18, 2011
  • bitcoin == con-currency?Saturday, June 18, 2011
  • Saturday, June 18, 2011
  • José! Me!Saturday, June 18, 2011
  • WWFMD?Saturday, June 18, 2011
  • Public Service AnnouncementsSaturday, June 18, 2011
  • SIGSEGV is badSaturday, June 18, 2011
  • neversaydieSaturday, June 18, 2011
  • begin # something dangerous rescue NeverSayDie # fix memory endSaturday, June 18, 2011
  • "Not working in production mode"Saturday, June 18, 2011
  • DO NOT USE THIS SOFTWARESaturday, June 18, 2011
  • ruby -wSaturday, June 18, 2011
  • def hello x = Object.new # warning 10 + 10 endSaturday, June 18, 2011
  • warning: assigned but unused variable - xSaturday, June 18, 2011
  • How deprecation notices SHOULD be writtenSaturday, June 18, 2011
  • class Foo def deprecated if $VERBOSE warn "hey bro, dont call this" end 10 end endSaturday, June 18, 2011
  • RSpec ProblemSaturday, June 18, 2011
  • warning: useless use of == in void contextSaturday, June 18, 2011
  • it "passes" do 10.should == 10 11.should == 11 endSaturday, June 18, 2011
  • def check(thing) end def deprecated check 10.should == 10 check 11.should == 10 endSaturday, June 18, 2011
  • @tenderloveSaturday, June 18, 2011
  • AT&T, AT&T logo and all AT&T related marks are trademarks of AT&T Intellectual Property and/or AT&T affiliated companies.Saturday, June 18, 2011
  • Ruby Core TeamSaturday, June 18, 2011
  • Rails Core TeamSaturday, June 18, 2011
  • Saturday, June 18, 2011
  • White GuySaturday, June 18, 2011
  • Story about Geethika and pinochle, java, etcSaturday, June 18, 2011
  • Story about Geethika and pinochle, java, etc Its TYRA!Saturday, June 18, 2011
  • <3 <3 <3Saturday, June 18, 2011
  • "Congratulations, you just made us not consider Rails for anything anymore despite our coders liking it."Saturday, June 18, 2011
  • SWEDEN!Saturday, June 18, 2011
  • IKEA!Saturday, June 18, 2011
  • MEATBALLS!Saturday, June 18, 2011
  • SWEDISH FISH!Saturday, June 18, 2011
  • Made in Canada!Saturday, June 18, 2011
  • Made in Canada!Saturday, June 18, 2011
  • How do you catch such tiny fish?Saturday, June 18, 2011
  • Will you share your Swedish Fish Fishing spot?Saturday, June 18, 2011
  • Talk about Rails, Talk about work projects Mountain Dew and my Trail of TearsSaturday, June 18, 2011
  • Legacy CodeSaturday, June 18, 2011
  • What is Legacy Code?Saturday, June 18, 2011
  • UntestedSaturday, June 18, 2011
  • OldSaturday, June 18, 2011
  • Maintainers are gone Not UnderstoodSaturday, June 18, 2011
  • Importance of Legacy CodeSaturday, June 18, 2011
  • Old code contains KnowledgeSaturday, June 18, 2011
  • Solves Todays ProblemsSaturday, June 18, 2011
  • All Legacy Code is Not EqualSaturday, June 18, 2011
  • Tenderlove Tear FormulaSaturday, June 18, 2011
  • Code Burden Tears TimeSaturday, June 18, 2011
  • Tears cried at time TSaturday, June 18, 2011
  • Volume at time TSaturday, June 18, 2011
  • Last WeekSaturday, June 18, 2011
  • I LOVE hacking old codeSaturday, June 18, 2011
  • TechniquesSaturday, June 18, 2011
  • Techniques Universal Testing ExtendingSaturday, June 18, 2011
  • UniversalSaturday, June 18, 2011
  • Liskov substitution principleSaturday, June 18, 2011
  • A subclass can be used in place of its superclassSaturday, June 18, 2011
  • Object Animal PersonSaturday, June 18, 2011
  • class Animal end class Person < Animal endSaturday, June 18, 2011
  • def leg_count(animal) animal.legs end def account_number(person) person.account_number endSaturday, June 18, 2011
  • Single Responsibility PrincipalSaturday, June 18, 2011
  • Each class has one and only one responsibilitySaturday, June 18, 2011
  • Each class has one reason to changeSaturday, June 18, 2011
  • Method ExtractionSaturday, June 18, 2011
  • class WebClient def get(url) url = URI.parse url Net::HTTP.get(url.host, url.path) end endSaturday, June 18, 2011
  • class WebClient def get(url) url = URI.parse url http_get end private def http_get Net::HTTP.get(url.host, url.path) end endSaturday, June 18, 2011
  • I dont like it, but it helps us to class WebClient reason def get(url) url = URI.parse url http_get(url.host, url.path) end private def http_get(host, path) Net::HTTP.get(host, path) end endSaturday, June 18, 2011
  • Object#extendSaturday, June 18, 2011
  • class Foo def metaclass class << self; self; end end end x = Foo.new p x.metaclass.ancestors x.extend(Module.new { }) p x.metaclass.ancestorsSaturday, June 18, 2011
  • [Foo, Object, Kernel, BasicObject] [#<Module:0x81c98>, Foo, Object, Kernel, BasicObject]Saturday, June 18, 2011
  • Code SeamsSaturday, June 18, 2011
  • TestingSaturday, June 18, 2011
  • Load Path HackingSaturday, June 18, 2011
  • $LOAD_PATHSaturday, June 18, 2011
  • ruby -Ifoo script.rbSaturday, June 18, 2011
  • require net/http class WebClient def get(url) url = URI.parse url Net::HTTP.get(url.host, url.path) end endSaturday, June 18, 2011
  • [aaron@higgins project (master)]$ find . . ./test ./test/lib ./test/lib/net ./test/lib/net/http.rb ./web.rbSaturday, June 18, 2011
  • test/lib/net/http.rb module Net class HTTP def self.get(host, path) "hello world" end end endSaturday, June 18, 2011
  • ruby -I test/lib web.rbSaturday, June 18, 2011
  • require web require minitest/autorun class WebTest < MiniTest::Unit::TestCase def test_get client = WebClient.new response = client.get http://www.reddit.com/r/ruby assert_equal hello world, response end endSaturday, June 18, 2011
  • RSpec and People dont know about -I test/unit will set your -I for you require File.expand_path( File.join(.., foo))Saturday, June 18, 2011
  • Heavy HandedSaturday, June 18, 2011
  • Good for Small APIsSaturday, June 18, 2011
  • Constant HackingSaturday, June 18, 2011
  • require net/http class WebClient def get(url) url = URI.parse url Net::HTTP.get(url.host, url.path) end endSaturday, June 18, 2011
  • class MyHTTP def self.get(host, path) "hello world" end end WebClient.const_set(:Net, Module.new) WebClient::Net.const_set(:HTTP, MyHTTP)Saturday, June 18, 2011
  • class WebTest < MiniTest::Unit::TestCase def setup WebClient.const_set(:Net, Module.new) WebClient::Net.const_set(:HTTP, MyHTTP) end def teardown WebClient.send(:remove_const, :Net) end def test_get client = WebClient.new response = client.get http://www.reddit.com/r/ruby assert_equal hello world, response end endSaturday, June 18, 2011
  • class WebClient def get(url) url = URI.parse url ::Net::HTTP.get(url.host, url.path) end endSaturday, June 18, 2011
  • Localized Still must changes to mock one class entire API Heavy HandedSaturday, June 18, 2011
  • Subclass TestingSaturday, June 18, 2011
  • class WebClient def get(url) url = URI.parse url Net::HTTP.get(url.host, url.path) end endSaturday, June 18, 2011
  • require net/http class WebClient def get(url) url = URI.parse url http_get(url.host, url.path) end private def http_get(host, path) Net::HTTP.get(host, path) end endSaturday, June 18, 2011
  • Class.newSaturday, June 18, 2011
  • class WebTest < MiniTest::Unit::TestCase def test_get client = Class.new(WebClient) { def http_get(host, path) hello world end }.new response = client.get http://www.reddit.com/r/ruby assert_equal hello world, response end endSaturday, June 18, 2011
  • Annoying ConstructorsSaturday, June 18, 2011
  • Many parameters, class Column def initialize(name, default, sql_type = nil,dont care=about null true) some of them @name = name @sql_type = sql_type @null = null @limit = extract_limit(sql_type) @precision = extract_precision(sql_type) @scale = extract_scale(sql_type) @type = simplified_type(sql_type) @default = extract_default(default) @primary = nil @coder = nil end .... endSaturday, June 18, 2011
  • Just Pass nilSaturday, June 18, 2011
  • def test_type_cast_true c = Column.new(nil, 1, int) assert_equal t, @conn.type_cast(true, nil) assert_equal 1, @conn.type_cast(true, c) endSaturday, June 18, 2011
  • Cant construct, but want to break dependencies Not ConstructibleSaturday, June 18, 2011
  • Too hard to construct pool = ActiveRecord::Base.connection_poolSaturday, June 18, 2011
  • pool = ActiveRecord::Base.connection_pool.dup pool.extend(Module.new { def checkin conn @checkins << conn conn.object_id end })Saturday, June 18, 2011
  • Detecting ChangesSaturday, June 18, 2011
  • Measure http_get class WebClient def get(url) url = URI.parse url http_get(url.host, url.path) end private def http_get(host, path) Net::HTTP.get(host, path) end endSaturday, June 18, 2011
  • via Class.newSaturday, June 18, 2011
  • def test_http_get_count call_count = 0 client = Class.new(WebClient) { define_method(:http_get) { |host, path| call_count += 1 "hello world" } }.new assert_equal 0, call_count client.get http://www.reddit.com/r/ruby assert_equal 1, call_count endSaturday, June 18, 2011
  • def test_http_get_count call_count = 0 client = Class.new(WebClient) { define_method(:http_get) { |host, path| call_count += 1 "hello world" } }.new assert_equal 0, call_count client.get http://www.reddit.com/r/ruby assert_equal 1, call_count endSaturday, June 18, 2011
  • Decide to call def test_http_get_count super or not call_count = 0 client = Class.new(WebClient) { define_method(:http_get) { |host, path| call_count += 1 "hello world" } }.new assert_equal 0, call_count client.get http://www.reddit.com/r/ruby assert_equal 1, call_count endSaturday, June 18, 2011
  • via Module.newSaturday, June 18, 2011
  • def test_http_get_count client = WebClient.new call_count = 0 client.extend(Module.new { define_method(:http_get) { |host, path| call_count += 1 "hello world" } }) assert_equal 0, call_count client.get http://www.reddit.com/r/ruby assert_equal 1, call_count endSaturday, June 18, 2011
  • def test_http_get_count client = WebClient.new call_count = 0 client.extend(Module.new { define_method(:http_get) { |host, path| call_count += 1 "hello world" } }) assert_equal 0, call_count client.get http://www.reddit.com/r/ruby assert_equal 1, call_count endSaturday, June 18, 2011
  • def test_http_get_count client = WebClient.new call_count = 0 client.extend(Module.new { define_method(:http_get) { |host, path| call_count += 1 "hello world" } }) assert_equal 0, call_count client.get http://www.reddit.com/r/ruby assert_equal 1, call_count endSaturday, June 18, 2011
  • ExtendingSaturday, June 18, 2011
  • Huge Methods!Saturday, June 18, 2011
  • def table_rows rows[table_name] = fixtures.map do |label, fixture| if model_class && model_class < ActiveRecord::Base reflection_class.reflect_on_all_associations.each do |association| case association.macro when :belongs_to # Do not replace association name with association foreign key if they are named the same fk_name = (association.options[:foreign_key] || "#{association.name}_id").to_s if association.name.to_s != fk_name && value = row.delete(association.name.to_s) if association.options[:polymorphic] && value.sub!(/s*(([^)]*))s*$/, "") # support polymorphic belongs_to as "label (Type)" row[association.foreign_type] = $1 end row[fk_name] = ActiveRecord::Fixtures.identify(value) end when :has_and_belongs_to_many if (targets = row.delete(association.name.to_s)) targets = targets.is_a?(Array) ? targets : targets.split(/s*,s*/) table_name = association.options[:join_table] rows[table_name].concat targets.map { |target| { association.foreign_key => row[primary_key_name], association.association_foreign_key => ActiveRecord::Fixtures.identify (target) } } end end end end row end rows endSaturday, June 18, 2011
  • Extract MethodsSaturday, June 18, 2011
  • def belongs_to_row(association, row) # Do not replace association name with association foreign key if they are named the same fk_name = (association.options[:foreign_key] || "# {association.name}_id").to_s if association.name.to_s != fk_name && value = row.delete (association.name.to_s) if association.options[:polymorphic] && value.sub!(/s*(([^)] *))s*$/, "") # support polymorphic belongs_to as "label (Type)" row[association.foreign_type] = $1 end row[fk_name] = ActiveRecord::Fixtures.identify(value) endSaturday, June 18, 2011
  • def habtm_row(association, row) if (targets = row.delete(association.name.to_s)) targets = targets.is_a?(Array) ? targets : targets.split(/s*, s*/) table_name = association.options[:join_table] rows[table_name].concat targets.map { |target| { association.foreign_key => row [primary_key_name], association.association_foreign_key => ActiveRecord::Fixtures.identify(target) } } end endSaturday, June 18, 2011
  • def table_rows rows[table_name] = fixtures.map do |label, fixture| row = fixture.to_hash if model_class && model_class < ActiveRecord::Base # If STI is used, find the correct subclass for association reflection reflection_class = if row.include?(inheritance_column_name) row[inheritance_column_name].constantize rescue model_class else model_class end reflection_class.reflect_on_all_associations.each do |association| case association.macro when :belongs_to belongs_to_row(association, row) when :has_and_belongs_to_many habtm_row(association, row) end end end row end rows endSaturday, June 18, 2011
  • Extract ObjectSaturday, June 18, 2011
  • class RowFilter def rows fixtures.map do |label, fixture| row = fixture.to_hash if model_class && model_class < ActiveRecord::Base # If STI is used, find the correct subclass for association reflection reflection_class = if row.include?(inheritance_column_name) row[inheritance_column_name].constantize rescue model_class else model_class end reflection_class.reflect_on_all_associations.each do |association| case association.macro when :belongs_to belongs_to_row(association, row) when :has_and_belongs_to_many habtm_row(association, row) end end end row end end endSaturday, June 18, 2011
  • class RowFilter attr_reader :fixtures, :model_class def initialize(fixtures, model_class) @fixtures = fixtures @model_class = model_class end endSaturday, June 18, 2011
  • def table_rows filter = RowFilter.new(fixtures, model_class) rows[table_name] = filter.rows rows endSaturday, June 18, 2011
  • Huge Classes!Saturday, June 18, 2011
  • Look at Method NamesSaturday, June 18, 2011
  • Look at shared instance variablesSaturday, June 18, 2011
  • Group Similar MethodsSaturday, June 18, 2011
  • Use SRP to create a new classSaturday, June 18, 2011
  • Then Delegate.Saturday, June 18, 2011
  • All API callsSaturday, June 18, 2011
  • Once we had extracted the HTTP class WebClient methods to their own functions, could def get(url) reason about HTTP url = URI.parse url api. http_get(url.host, url.path) end private def http_get(host, path) Net::HTTP.get(host, path) end endSaturday, June 18, 2011
  • class WebClient def initialize(client = Net::HTTP) @client = client end def get(url) url = URI.parse url http_get(url.host, url.path) end private def http_get(host, path) @client.get(host, path) end endSaturday, June 18, 2011
  • class TestHTTP < Struct.new(:data) def get(host, path) data[[host, path]] end endSaturday, June 18, 2011
  • class WebTest < Test::Unit::TestCase def test_get_home mockhttp = TestHTTP.new({ [localhost, /~aaron/] => hello }) wc = WebClient.new mockhttp assert_equal hello, wc.get(http://localhost/~aaron/) end endSaturday, June 18, 2011
  • We define expectationsSaturday, June 18, 2011
  • Not Bound to HTTPSaturday, June 18, 2011
  • Legacy code can make you crySaturday, June 18, 2011
  • But it doesnt have toSaturday, June 18, 2011
  • Dont be afraid!Saturday, June 18, 2011
  • Ruby is your mocking frameworkSaturday, June 18, 2011
  • Credits & More InfoSaturday, June 18, 2011
  • Open Questions?Saturday, June 18, 2011
  • Do you like mocking / stubbing?Saturday, June 18, 2011
  • How do these testing tools impact your API?Saturday, June 18, 2011
  • Do you like hearts?Saturday, June 18, 2011
  • How about kittens?Saturday, June 18, 2011
  • <3 <3 <3Saturday, June 18, 2011