Nordic Ruby 2011

3,634 views

Published on

Published in: Technology
1 Comment
3 Likes
Statistics
Notes
No Downloads
Views
Total views
3,634
On SlideShare
0
From Embeds
0
Number of Embeds
7
Actions
Shares
0
Downloads
18
Comments
1
Likes
3
Embeds 0
No embeds

No notes for slide

Nordic Ruby 2011

  1. 1. Saturday, June 18, 2011
  2. 2. Saturday, June 18, 2011
  3. 3. bitcoin == con-currency?Saturday, June 18, 2011
  4. 4. Saturday, June 18, 2011
  5. 5. José! Me!Saturday, June 18, 2011
  6. 6. WWFMD?Saturday, June 18, 2011
  7. 7. Public Service AnnouncementsSaturday, June 18, 2011
  8. 8. SIGSEGV is badSaturday, June 18, 2011
  9. 9. neversaydieSaturday, June 18, 2011
  10. 10. begin # something dangerous rescue NeverSayDie # fix memory endSaturday, June 18, 2011
  11. 11. "Not working in production mode"Saturday, June 18, 2011
  12. 12. DO NOT USE THIS SOFTWARESaturday, June 18, 2011
  13. 13. ruby -wSaturday, June 18, 2011
  14. 14. def hello x = Object.new # warning 10 + 10 endSaturday, June 18, 2011
  15. 15. warning: assigned but unused variable - xSaturday, June 18, 2011
  16. 16. How deprecation notices SHOULD be writtenSaturday, June 18, 2011
  17. 17. class Foo def deprecated if $VERBOSE warn "hey bro, dont call this" end 10 end endSaturday, June 18, 2011
  18. 18. RSpec ProblemSaturday, June 18, 2011
  19. 19. warning: useless use of == in void contextSaturday, June 18, 2011
  20. 20. it "passes" do 10.should == 10 11.should == 11 endSaturday, June 18, 2011
  21. 21. def check(thing) end def deprecated check 10.should == 10 check 11.should == 10 endSaturday, June 18, 2011
  22. 22. @tenderloveSaturday, June 18, 2011
  23. 23. 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
  24. 24. Ruby Core TeamSaturday, June 18, 2011
  25. 25. Rails Core TeamSaturday, June 18, 2011
  26. 26. Saturday, June 18, 2011
  27. 27. White GuySaturday, June 18, 2011
  28. 28. Story about Geethika and pinochle, java, etcSaturday, June 18, 2011
  29. 29. Story about Geethika and pinochle, java, etc Its TYRA!Saturday, June 18, 2011
  30. 30. <3 <3 <3Saturday, June 18, 2011
  31. 31. "Congratulations, you just made us not consider Rails for anything anymore despite our coders liking it."Saturday, June 18, 2011
  32. 32. SWEDEN!Saturday, June 18, 2011
  33. 33. IKEA!Saturday, June 18, 2011
  34. 34. MEATBALLS!Saturday, June 18, 2011
  35. 35. SWEDISH FISH!Saturday, June 18, 2011
  36. 36. Made in Canada!Saturday, June 18, 2011
  37. 37. Made in Canada!Saturday, June 18, 2011
  38. 38. How do you catch such tiny fish?Saturday, June 18, 2011
  39. 39. Will you share your Swedish Fish Fishing spot?Saturday, June 18, 2011
  40. 40. Talk about Rails, Talk about work projects Mountain Dew and my Trail of TearsSaturday, June 18, 2011
  41. 41. Legacy CodeSaturday, June 18, 2011
  42. 42. What is Legacy Code?Saturday, June 18, 2011
  43. 43. UntestedSaturday, June 18, 2011
  44. 44. OldSaturday, June 18, 2011
  45. 45. Maintainers are gone Not UnderstoodSaturday, June 18, 2011
  46. 46. Importance of Legacy CodeSaturday, June 18, 2011
  47. 47. Old code contains KnowledgeSaturday, June 18, 2011
  48. 48. Solves Todays ProblemsSaturday, June 18, 2011
  49. 49. All Legacy Code is Not EqualSaturday, June 18, 2011
  50. 50. Tenderlove Tear FormulaSaturday, June 18, 2011
  51. 51. Code Burden Tears TimeSaturday, June 18, 2011
  52. 52. Tears cried at time TSaturday, June 18, 2011
  53. 53. Volume at time TSaturday, June 18, 2011
  54. 54. Last WeekSaturday, June 18, 2011
  55. 55. I LOVE hacking old codeSaturday, June 18, 2011
  56. 56. TechniquesSaturday, June 18, 2011
  57. 57. Techniques Universal Testing ExtendingSaturday, June 18, 2011
  58. 58. UniversalSaturday, June 18, 2011
  59. 59. Liskov substitution principleSaturday, June 18, 2011
  60. 60. A subclass can be used in place of its superclassSaturday, June 18, 2011
  61. 61. Object Animal PersonSaturday, June 18, 2011
  62. 62. class Animal end class Person < Animal endSaturday, June 18, 2011
  63. 63. def leg_count(animal) animal.legs end def account_number(person) person.account_number endSaturday, June 18, 2011
  64. 64. Single Responsibility PrincipalSaturday, June 18, 2011
  65. 65. Each class has one and only one responsibilitySaturday, June 18, 2011
  66. 66. Each class has one reason to changeSaturday, June 18, 2011
  67. 67. Method ExtractionSaturday, June 18, 2011
  68. 68. class WebClient def get(url) url = URI.parse url Net::HTTP.get(url.host, url.path) end endSaturday, June 18, 2011
  69. 69. 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
  70. 70. 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
  71. 71. Object#extendSaturday, June 18, 2011
  72. 72. 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
  73. 73. [Foo, Object, Kernel, BasicObject] [#<Module:0x81c98>, Foo, Object, Kernel, BasicObject]Saturday, June 18, 2011
  74. 74. Code SeamsSaturday, June 18, 2011
  75. 75. TestingSaturday, June 18, 2011
  76. 76. Load Path HackingSaturday, June 18, 2011
  77. 77. $LOAD_PATHSaturday, June 18, 2011
  78. 78. ruby -Ifoo script.rbSaturday, June 18, 2011
  79. 79. require net/http class WebClient def get(url) url = URI.parse url Net::HTTP.get(url.host, url.path) end endSaturday, June 18, 2011
  80. 80. [aaron@higgins project (master)]$ find . . ./test ./test/lib ./test/lib/net ./test/lib/net/http.rb ./web.rbSaturday, June 18, 2011
  81. 81. test/lib/net/http.rb module Net class HTTP def self.get(host, path) "hello world" end end endSaturday, June 18, 2011
  82. 82. ruby -I test/lib web.rbSaturday, June 18, 2011
  83. 83. 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
  84. 84. 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
  85. 85. Heavy HandedSaturday, June 18, 2011
  86. 86. Good for Small APIsSaturday, June 18, 2011
  87. 87. Constant HackingSaturday, June 18, 2011
  88. 88. require net/http class WebClient def get(url) url = URI.parse url Net::HTTP.get(url.host, url.path) end endSaturday, June 18, 2011
  89. 89. 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
  90. 90. 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
  91. 91. class WebClient def get(url) url = URI.parse url ::Net::HTTP.get(url.host, url.path) end endSaturday, June 18, 2011
  92. 92. Localized Still must changes to mock one class entire API Heavy HandedSaturday, June 18, 2011
  93. 93. Subclass TestingSaturday, June 18, 2011
  94. 94. class WebClient def get(url) url = URI.parse url Net::HTTP.get(url.host, url.path) end endSaturday, June 18, 2011
  95. 95. 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
  96. 96. Class.newSaturday, June 18, 2011
  97. 97. 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
  98. 98. Annoying ConstructorsSaturday, June 18, 2011
  99. 99. 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
  100. 100. Just Pass nilSaturday, June 18, 2011
  101. 101. 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
  102. 102. Cant construct, but want to break dependencies Not ConstructibleSaturday, June 18, 2011
  103. 103. Too hard to construct pool = ActiveRecord::Base.connection_poolSaturday, June 18, 2011
  104. 104. pool = ActiveRecord::Base.connection_pool.dup pool.extend(Module.new { def checkin conn @checkins << conn conn.object_id end })Saturday, June 18, 2011
  105. 105. Detecting ChangesSaturday, June 18, 2011
  106. 106. 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
  107. 107. via Class.newSaturday, June 18, 2011
  108. 108. 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
  109. 109. 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
  110. 110. 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
  111. 111. via Module.newSaturday, June 18, 2011
  112. 112. 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
  113. 113. 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
  114. 114. 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
  115. 115. ExtendingSaturday, June 18, 2011
  116. 116. Huge Methods!Saturday, June 18, 2011
  117. 117. 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
  118. 118. Extract MethodsSaturday, June 18, 2011
  119. 119. 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
  120. 120. 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
  121. 121. 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
  122. 122. Extract ObjectSaturday, June 18, 2011
  123. 123. 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
  124. 124. class RowFilter attr_reader :fixtures, :model_class def initialize(fixtures, model_class) @fixtures = fixtures @model_class = model_class end endSaturday, June 18, 2011
  125. 125. def table_rows filter = RowFilter.new(fixtures, model_class) rows[table_name] = filter.rows rows endSaturday, June 18, 2011
  126. 126. Huge Classes!Saturday, June 18, 2011
  127. 127. Look at Method NamesSaturday, June 18, 2011
  128. 128. Look at shared instance variablesSaturday, June 18, 2011
  129. 129. Group Similar MethodsSaturday, June 18, 2011
  130. 130. Use SRP to create a new classSaturday, June 18, 2011
  131. 131. Then Delegate.Saturday, June 18, 2011
  132. 132. All API callsSaturday, June 18, 2011
  133. 133. 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
  134. 134. 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
  135. 135. class TestHTTP < Struct.new(:data) def get(host, path) data[[host, path]] end endSaturday, June 18, 2011
  136. 136. 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
  137. 137. We define expectationsSaturday, June 18, 2011
  138. 138. Not Bound to HTTPSaturday, June 18, 2011
  139. 139. Legacy code can make you crySaturday, June 18, 2011
  140. 140. But it doesnt have toSaturday, June 18, 2011
  141. 141. Dont be afraid!Saturday, June 18, 2011
  142. 142. Ruby is your mocking frameworkSaturday, June 18, 2011
  143. 143. Credits & More InfoSaturday, June 18, 2011
  144. 144. Open Questions?Saturday, June 18, 2011
  145. 145. Do you like mocking / stubbing?Saturday, June 18, 2011
  146. 146. How do these testing tools impact your API?Saturday, June 18, 2011
  147. 147. Do you like hearts?Saturday, June 18, 2011
  148. 148. How about kittens?Saturday, June 18, 2011
  149. 149. <3 <3 <3Saturday, June 18, 2011

×