Slide 1

Slide 1 text

Code to Joy Avdi Grimm ShipRise GoGaRuCo 2012 Avdi Grimm (ShipRise) Code to Joy GoGaRuCo 2012 1 / 50

Slide 2

Slide 2 text

Code to Joy Introduction Introduction These are a few of my favorite things. Avdi Grimm (ShipRise) GoGaRuCo 2012 2 / 50

Slide 3

Slide 3 text

Code to Joy Introduction My Job is Awesome • My job is awesome Avdi Grimm (ShipRise) GoGaRuCo 2012 3 / 50

Slide 4

Slide 4 text

Code to Joy Introduction My Job is Awesome • My job is awesome • Remotely pairing with many different people Avdi Grimm (ShipRise) GoGaRuCo 2012 3 / 50

Slide 5

Slide 5 text

Code to Joy Introduction My Job is Awesome • My job is awesome • Remotely pairing with many different people • Different levels of knowledge, different problems to solve Avdi Grimm (ShipRise) GoGaRuCo 2012 3 / 50

Slide 6

Slide 6 text

Code to Joy Introduction My Job is Awesome • My job is awesome • Remotely pairing with many different people • Different levels of knowledge, different problems to solve • ”That’s so cool, I didn’t know you could do that” Avdi Grimm (ShipRise) GoGaRuCo 2012 3 / 50

Slide 7

Slide 7 text

Code to Joy Introduction Ruby is Awesome Ruby is designed to make programmers happy. — Matz It still finds ways to make me smile after all these years. Avdi Grimm (ShipRise) GoGaRuCo 2012 4 / 50

Slide 8

Slide 8 text

Code to Joy Introduction Postcards are Awesome • Work in progress: Confident Ruby Avdi Grimm (ShipRise) GoGaRuCo 2012 5 / 50

Slide 9

Slide 9 text

Code to Joy Introduction Postcards are Awesome • Work in progress: Confident Ruby • ”Pay with a postcard” Avdi Grimm (ShipRise) GoGaRuCo 2012 5 / 50

Slide 10

Slide 10 text

Code to Joy Introduction Postcards are Awesome • Work in progress: Confident Ruby • ”Pay with a postcard” • Postcards make me happy! Avdi Grimm (ShipRise) GoGaRuCo 2012 5 / 50

Slide 11

Slide 11 text

Code to Joy Introduction The Plan • A random walk through the Ruby language and standard library. . . Avdi Grimm (ShipRise) GoGaRuCo 2012 6 / 50

Slide 12

Slide 12 text

Code to Joy Introduction The Plan • A random walk through the Ruby language and standard library. . . • . . . stopping in at some of my favorite idioms and tools. . . Avdi Grimm (ShipRise) GoGaRuCo 2012 6 / 50

Slide 13

Slide 13 text

Code to Joy Introduction The Plan • A random walk through the Ruby language and standard library. . . • . . . stopping in at some of my favorite idioms and tools. . . • . . . and around the world, in postcards! Avdi Grimm (ShipRise) GoGaRuCo 2012 6 / 50

Slide 14

Slide 14 text

Code to Joy Splats Splats Avdi Grimm (ShipRise) GoGaRuCo 2012 7 / 50

Slide 15

Slide 15 text

Code to Joy Splats Simple Destructuring spawn( ’true’ ) pid, status = *Process.wait2 pid # => 9159 status # => # Avdi Grimm (ShipRise) GoGaRuCo 2012 8 / 50

Slide 16

Slide 16 text

Code to Joy Splats Implicit splat spawn( ’true’ ) pid, status = Process.wait2 pid # => 16804 status # => # Avdi Grimm (ShipRise) GoGaRuCo 2012 9 / 50

Slide 17

Slide 17 text

Code to Joy Splats Multiple return values def send_request # ... code = 404 message = "Not found" # ??? end Avdi Grimm (ShipRise) GoGaRuCo 2012 10 / 50

Slide 18

Slide 18 text

Code to Joy Splats One client wants individual values code, message = send_request logger.info " #{ code } : #{ message } " Avdi Grimm (ShipRise) GoGaRuCo 2012 11 / 50

Slide 19

Slide 19 text

Code to Joy Splats Another client wants an object response = send_request case response.code when 400..599 then handle_error(response) else # ... end Avdi Grimm (ShipRise) GoGaRuCo 2012 12 / 50

Slide 20

Slide 20 text

Code to Joy Splats cake.have && cake.eat Response = Struct.new( :code , :message ) r = Response.new(404, "Not found" ) # Attributes: r.code # => 404 r.message # => "Not found" # Splat: code, msg = *r code # => 404 msg # => "Not found" Avdi Grimm (ShipRise) GoGaRuCo 2012 13 / 50

Slide 21

Slide 21 text

Code to Joy Splats One little problem Response = Struct.new( :code , :message ) r = Response.new(404, "Not found" ) code, msg = r # no splat code # => # msg # => nil Avdi Grimm (ShipRise) GoGaRuCo 2012 14 / 50

Slide 22

Slide 22 text

Code to Joy Splats An implicitly splattable Struct Response = Struct.new( :code , :message ) do alias_method :to_ary , :to_a end Avdi Grimm (ShipRise) GoGaRuCo 2012 15 / 50

Slide 23

Slide 23 text

Code to Joy Splats An implicitly splattable Struct Response = Struct.new( :code , :message ) do alias_method :to_ary , :to_a end r = Response.new(404, "Not found" ) code, msg = r # look ma, no splat! code # => 404 msg # => "Not found" Avdi Grimm (ShipRise) GoGaRuCo 2012 15 / 50

Slide 24

Slide 24 text

Code to Joy Splats Returning a splattable Struct def send_request # ... Response.new(code, message) end Avdi Grimm (ShipRise) GoGaRuCo 2012 16 / 50

Slide 25

Slide 25 text

Code to Joy Splats Splatting the Struct into component parts code, message = send_request logger.info " #{ code } : #{ message } " Avdi Grimm (ShipRise) GoGaRuCo 2012 17 / 50

Slide 26

Slide 26 text

Code to Joy Splats Using the response Struct as-is response = send_request case response.code when 400..599 then handle_error(response) else # ... end Avdi Grimm (ShipRise) GoGaRuCo 2012 18 / 50

Slide 27

Slide 27 text

Code to Joy Splats Splats & Structs • Return multiple values from a method. . . • . . . *Or* a single result object. . . • . . . from the same line of code. Magic! Avdi Grimm (ShipRise) GoGaRuCo 2012 19 / 50

Slide 28

Slide 28 text

Code to Joy YAML::Store YAML::Store Avdi Grimm (ShipRise) GoGaRuCo 2012 20 / 50

Slide 29

Slide 29 text

Code to Joy YAML::Store Persisting Posts require ’yaml/store’ repo = YAML::Store.new( ’blog.yml’ ) Post = Struct.new( :title , :body ) repo.transaction do posts = repo[ :posts ] = [] posts << Post.new( "F1rst Post!!!" , "FIRST" ) posts << Post.new( "Hiatus" , "This blog is on vacation" ) end Avdi Grimm (ShipRise) GoGaRuCo 2012 21 / 50

Slide 30

Slide 30 text

Code to Joy YAML::Store The Persisted Data cat blog.yml --- :posts: - !ruby/struct:Post title: F1rst Post!!! body: FIRST - !ruby/struct:Post title: Hiatus body: This blog is on vacation Avdi Grimm (ShipRise) GoGaRuCo 2012 22 / 50

Slide 31

Slide 31 text

Code to Joy YAML::Store Associations Post = Struct.new( :title , :body , :category ) Category = Struct.new( :name ) food = Category.new( :food ) repo.transaction do posts = repo[ :posts ] = [] posts << Post.new( "Cookie!!!" , "C is for cookie!" , food) posts << Post.new( "Durian" , "Stinky!" , food) end Avdi Grimm (ShipRise) GoGaRuCo 2012 23 / 50

Slide 32

Slide 32 text

Code to Joy YAML::Store Associations YAML --- :posts: - !ruby/struct:Post title: Cookie!!! body: C is for cookie! category: &8509480 !ruby/struct:Category name: :food - !ruby/struct:Post title: Durian body: Stinky! category: *8509480 Avdi Grimm (ShipRise) GoGaRuCo 2012 24 / 50

Slide 33

Slide 33 text

Code to Joy YAML::Store PStore • Drop-in replacement require ’pstore’ 2 repo = PStore.new( ’blog.pstore’ ) repo.transaction do 4 # ... end Avdi Grimm (ShipRise) GoGaRuCo 2012 25 / 50

Slide 34

Slide 34 text

Code to Joy YAML::Store PStore • Drop-in replacement require ’pstore’ 2 repo = PStore.new( ’blog.pstore’ ) repo.transaction do 4 # ... end • Faster Adding 1000 posts, with a transaction for each write: user system total real yaml 50.210000 0.210000 50.420000 ( 54.024277) pstore 3.290000 0.130000 3.420000 ( 10.887887) Avdi Grimm (ShipRise) GoGaRuCo 2012 25 / 50

Slide 35

Slide 35 text

Code to Joy YAML::Store YAML#Store • Incredibly simple Hash-like persistence mechanism • Great for local command-line apps • Supports complex object trees • Oh yeah, one more thing. . . Avdi Grimm (ShipRise) GoGaRuCo 2012 26 / 50

Slide 36

Slide 36 text

Code to Joy YAML::Store YAML#Store • Incredibly simple Hash-like persistence mechanism • Great for local command-line apps • Supports complex object trees • Oh yeah, one more thing. . . • ZOMG NOSQL!!! Avdi Grimm (ShipRise) GoGaRuCo 2012 26 / 50

Slide 37

Slide 37 text

Code to Joy Enumerators Enumerators Avdi Grimm (ShipRise) GoGaRuCo 2012 27 / 50

Slide 38

Slide 38 text

Code to Joy Enumerators Kernel#to_enum Convert any old method into an Enumerator def names yield ’Ylva’ yield ’Brighid’ yield ’Shifra’ yield ’Yasmin’ end e = to_enum( :names ) # => # e.to_a # => ["Ylva", "Brighid", "Shifra", "Yasmin"] Avdi Grimm (ShipRise) GoGaRuCo 2012 28 / 50

Slide 39

Slide 39 text

Code to Joy Enumerators Searching for config files + project |-- .rutrc |-- file1 |-- file2 |-+ subproject <-- you are here |-- .rutrc |-- file3 \-- ... Avdi Grimm (ShipRise) GoGaRuCo 2012 29 / 50

Slide 40

Slide 40 text

Code to Joy Enumerators Pathname#ascend require ’pathname’ Dir.chdir( ’/home/avdi/dev’ ) Pathname.pwd.ascend do |dir| puts dir end /home/avdi/dev /home/avdi /home / Avdi Grimm (ShipRise) GoGaRuCo 2012 30 / 50

Slide 41

Slide 41 text

Code to Joy Enumerators Searching upwards for config files require ’pathname’ curdir = Pathname.pwd configs = curdir.to_enum( :ascend ). each_with_object([]){ |dir, files| config = (dir + ’.rutrc’ ) files << config if config.file? } Avdi Grimm (ShipRise) GoGaRuCo 2012 31 / 50

Slide 42

Slide 42 text

Code to Joy Enumerators Searching upwards for config files curdir = Pathname.pwd configs = curdir.to_enum(:ascend). each_with_object([]) { |dir, files| config = (dir + ’.rutrc’) files « config if config.file? } Avdi Grimm (ShipRise) GoGaRuCo 2012 31 / 50

Slide 43

Slide 43 text

Code to Joy Enumerators Searching upwards for config files curdir = Pathname.pwd configs = curdir.to_enum(:ascend). each_with_object([]) { |dir, files| config = (dir + ’.rutrc’) files « config if config.file? } Avdi Grimm (ShipRise) GoGaRuCo 2012 31 / 50

Slide 44

Slide 44 text

Code to Joy Enumerators Searching upwards for config files curdir = Pathname.pwd configs = curdir.to_enum(:ascend). each_with_object([]) { |dir, files| config = (dir + ’.rutrc’) files « config if config.file? } Avdi Grimm (ShipRise) GoGaRuCo 2012 31 / 50

Slide 45

Slide 45 text

Code to Joy Enumerators Enumerator and #to_enum • Turn any method into an iterable series • Make all the power of Enumerator available to the series Avdi Grimm (ShipRise) GoGaRuCo 2012 32 / 50

Slide 46

Slide 46 text

Code to Joy Break Give me a break Avdi Grimm (ShipRise) GoGaRuCo 2012 33 / 50

Slide 47

Slide 47 text

Code to Joy Break break It breaks out of loops. Whoop-de-doo. jobs.each do |job| break if job == :terminate job.call end Avdi Grimm (ShipRise) GoGaRuCo 2012 34 / 50

Slide 48

Slide 48 text

Code to Joy Break break beyond iteration def names yield ’Ylva’ yield ’Brighid’ yield ’Shifra’ yield ’Yasmin’ end Avdi Grimm (ShipRise) GoGaRuCo 2012 35 / 50

Slide 49

Slide 49 text

Code to Joy Break break beyond iteration i = 0 names do |name| puts name break if i >= 1 # that’s plenty! i += 1 end Ylva Brighid Avdi Grimm (ShipRise) GoGaRuCo 2012 35 / 50

Slide 50

Slide 50 text

Code to Joy Break break beyond iteration def names yield ’Ylva’ yield ’Brighid’ # ---- We stopped here! ---- yield ’Shifra’ yield ’Yasmin’ end Without a return, throw, or raise. Avdi Grimm (ShipRise) GoGaRuCo 2012 35 / 50

Slide 51

Slide 51 text

Code to Joy Break break respects ensure blocks def names_with_last yield ’Ylva’ yield ’Brighid’ yield ’Shifra’ yield ’Yasmin’ ensure puts "Grimm" end Avdi Grimm (ShipRise) GoGaRuCo 2012 36 / 50

Slide 52

Slide 52 text

Code to Joy Break break respects ensure blocks i = 0 names_with_last do |name| puts name break if i >= 1 # that’s plenty! i += 1 end Ylva Brighid Grimm Avdi Grimm (ShipRise) GoGaRuCo 2012 36 / 50

Slide 53

Slide 53 text

Code to Joy Break break respects ensure blocks def names_with_last yield ’Ylva’ yield ’Brighid’ # ---- We stopped here... ---- yield ’Shifra’ yield ’Yasmin’ ensure # ...and jumped to here. puts "Grimm" end Avdi Grimm (ShipRise) GoGaRuCo 2012 36 / 50

Slide 54

Slide 54 text

Code to Joy Break break with a value What if we want to capture a name? result = nil result = names do |name| if name =~ /^S/ result = name break end end result # => "Shifra" Avdi Grimm (ShipRise) GoGaRuCo 2012 37 / 50

Slide 55

Slide 55 text

Code to Joy Break break with a value result = names do |name| break name if name =~ /^S/ end result # => "Shifra" This effectively overrides the method’s return value. Avdi Grimm (ShipRise) GoGaRuCo 2012 37 / 50

Slide 56

Slide 56 text

Code to Joy Break Breaking from a #detect f = open( ’code-to-joy.org’ ) result = f.lines.detect do |line| break "" if f.lineno >= 100 line =~ /banana/ end result # => "" Avdi Grimm (ShipRise) GoGaRuCo 2012 38 / 50

Slide 57

Slide 57 text

Code to Joy Subclassing Module Subclassing Module Avdi Grimm (ShipRise) GoGaRuCo 2012 39 / 50

Slide 58

Slide 58 text

Code to Joy Subclassing Module A simple RPG Race = Struct.new( :name , :strength ) CharacterClass = Struct.new( :name , :charisma ) Character = Struct.new( :name , :race , :char_class ) human = Race.new( "Human" , 9) wizard = CharacterClass.new( "Tourist" , 3) player = Character.new( "Rhincewind" , human, wizard) Avdi Grimm (ShipRise) GoGaRuCo 2012 40 / 50

Slide 59

Slide 59 text

Code to Joy Subclassing Module What we’d like Ideally, attributes would be delegated to either race or char_class. player.name # => "Rhincewind" player.strength # => 9 player.charisma # => 3 Avdi Grimm (ShipRise) GoGaRuCo 2012 41 / 50

Slide 60

Slide 60 text

Code to Joy Subclassing Module Using Forwardable require ’forwardable’ Character = Struct.new( :name , :race , :char_class ) do extend Forwardable def_delegators :race , :strength def_delegators :char_class , :charisma end Avdi Grimm (ShipRise) GoGaRuCo 2012 42 / 50

Slide 61

Slide 61 text

Code to Joy Subclassing Module Evolving with Forwardable Race = Struct.new( :name , :strength , :constitution ) human = Race.new( "Human" , 9, 5) # ... Character = Struct.new( :name , :race , :char_class ) do extend Forwardable def_delegators :race , :strength , :constitution # ... end Every change has to be made twice. Avdi Grimm (ShipRise) GoGaRuCo 2012 43 / 50

Slide 62

Slide 62 text

Code to Joy Subclassing Module Using SimpleDelegator require ’delegate’ class Character < SimpleDelegator def initialize(name, race, char_class) @name = name super(race) end # ... end Only one object supported. Avdi Grimm (ShipRise) GoGaRuCo 2012 44 / 50

Slide 63

Slide 63 text

Code to Joy Subclassing Module Subclassing Module class Delegate < Module def initialize(attribute) @attribute = attribute super() do # see next slide... end end end Avdi Grimm (ShipRise) GoGaRuCo 2012 45 / 50

Slide 64

Slide 64 text

Code to Joy Subclassing Module Subclassing Module # ... define_method( :method_missing ) do |message, *args, &block| target = send(attribute) if target.respond_to?(message) target.public_send(message, *args, &block) else super(message, *args, &block) end end # ... Avdi Grimm (ShipRise) GoGaRuCo 2012 45 / 50

Slide 65

Slide 65 text

Code to Joy Subclassing Module Subclassing Module # ... define_method(:method_missing) do |message, *args, &block| target = send(attribute) if target.respond_to?(message) target.public_send(message, *args, &block) else super(message, *args, &block) end end # ... Avdi Grimm (ShipRise) GoGaRuCo 2012 45 / 50

Slide 66

Slide 66 text

Code to Joy Subclassing Module Subclassing Module # ... define_method(:method_missing) do |message, *args, &block| target = send(attribute) if target.respond_to?(message) target.public_send(message, *args, &block) else super(message, *args, &block) end end # ... Avdi Grimm (ShipRise) GoGaRuCo 2012 45 / 50

Slide 67

Slide 67 text

Code to Joy Subclassing Module Subclassing Module # ... define_method(:method_missing) do |message, *args, &block| target = send(attribute) if target.respond_to?(message) target.public_send(message, *args, &block) else super(message, *args, &block) end end # ... Avdi Grimm (ShipRise) GoGaRuCo 2012 45 / 50

Slide 68

Slide 68 text

Code to Joy Subclassing Module Subclassing Module # ... define_method(:method_missing) do |message, *args, &block| target = send(attribute) if target.respond_to?(message) target.public_send(message, *args, &block) else super(message, *args, &block) end end # ... Avdi Grimm (ShipRise) GoGaRuCo 2012 45 / 50

Slide 69

Slide 69 text

Code to Joy Subclassing Module Subclassing Module class Delegate < Module # ... def to_s "Delegate( #{ @attribute.inspect } )" end end Avdi Grimm (ShipRise) GoGaRuCo 2012 45 / 50

Slide 70

Slide 70 text

Code to Joy Subclassing Module Subclassing Module Character = Struct.new( :name , :race , :char_class ) do include Delegate.new( :race ) include Delegate.new( :char_class ) end Avdi Grimm (ShipRise) GoGaRuCo 2012 45 / 50

Slide 71

Slide 71 text

Code to Joy Subclassing Module Subclassing Module player.class.ancestors # => [Character, Delegate( :char_class ), Delegate( :race ), Struct, ...] Avdi Grimm (ShipRise) GoGaRuCo 2012 45 / 50

Slide 72

Slide 72 text

Code to Joy Subclassing Module Subclassing Module Race = Struct.new( :name , :strength ) CharacterClass = Struct.new( :name , :charisma ) # ... player = Character.new( "Rhincewind" , human, wizard) player.name # => "Rhincewind" player.strength # => 9 player.charisma # => 3 A chain of responsibility: 1 self 2 self.char_class 3 self.race 4 Other ancestors. . . Avdi Grimm (ShipRise) GoGaRuCo 2012 45 / 50

Slide 73

Slide 73 text

Code to Joy Subclassing Module Subclassing Module • Creates a new “kind” of module • Enables us to add state to the modules a class includes • Enabled us to implement a new type of message delegation in Ruby Avdi Grimm (ShipRise) GoGaRuCo 2012 46 / 50

Slide 74

Slide 74 text

Code to Joy MINASWAN My Favorite Thing of All MINASWAN Avdi Grimm (ShipRise) GoGaRuCo 2012 47 / 50

Slide 75

Slide 75 text

Code to Joy Conclusion Sometimes we get discouraged • Technical debt got you down? Avdi Grimm (ShipRise) GoGaRuCo 2012 48 / 50

Slide 76

Slide 76 text

Code to Joy Conclusion Sometimes we get discouraged • Technical debt got you down? • Community drama bumming you out? Avdi Grimm (ShipRise) GoGaRuCo 2012 48 / 50

Slide 77

Slide 77 text

Code to Joy Conclusion Sometimes we get discouraged • Technical debt got you down? • Community drama bumming you out? • If you’re blue, don’t know where to go to. . . Avdi Grimm (ShipRise) GoGaRuCo 2012 48 / 50

Slide 78

Slide 78 text

Code to Joy Conclusion Sometimes we get discouraged • Technical debt got you down? • Community drama bumming you out? • If you’re blue, don’t know where to go to. . . • . . . practice joyful coding Avdi Grimm (ShipRise) GoGaRuCo 2012 48 / 50

Slide 79

Slide 79 text

Code to Joy Conclusion Sometimes we get discouraged • Technical debt got you down? • Community drama bumming you out? • If you’re blue, don’t know where to go to. . . • . . . practice joyful coding • How? Avdi Grimm (ShipRise) GoGaRuCo 2012 48 / 50

Slide 80

Slide 80 text

Code to Joy Conclusion Defend your joy • There’s no metric for joyful code Avdi Grimm (ShipRise) GoGaRuCo 2012 49 / 50

Slide 81

Slide 81 text

Code to Joy Conclusion Defend your joy • There’s no metric for joyful code • Shared code is joyful code Avdi Grimm (ShipRise) GoGaRuCo 2012 49 / 50

Slide 82

Slide 82 text

Code to Joy Conclusion Defend your joy • There’s no metric for joyful code • Shared code is joyful code • If you want to feel good about your craft. . . Avdi Grimm (ShipRise) GoGaRuCo 2012 49 / 50

Slide 83

Slide 83 text

Code to Joy Conclusion Defend your joy • There’s no metric for joyful code • Shared code is joyful code • If you want to feel good about your craft. . . • . . . give someone a “wow” moment. Avdi Grimm (ShipRise) GoGaRuCo 2012 49 / 50

Slide 84

Slide 84 text

Code to Joy Conclusion Defend your joy • There’s no metric for joyful code • Shared code is joyful code • If you want to feel good about your craft. . . • . . . give someone a “wow” moment. • Show one person something awesome. Avdi Grimm (ShipRise) GoGaRuCo 2012 49 / 50

Slide 85

Slide 85 text

Code to Joy Conclusion Defend your joy • There’s no metric for joyful code • Shared code is joyful code • If you want to feel good about your craft. . . • . . . give someone a “wow” moment. • Show one person something awesome. • I promise you’ll feel better! Avdi Grimm (ShipRise) GoGaRuCo 2012 49 / 50

Slide 86

Slide 86 text

Code to Joy Conclusion Thank You • Rate! http://spkr8.com/t/16041 • Contact! [email protected] • Tweet! @avdi • Read! http://confidentruby.com • 20% off: GOGARUCO2012 • . . . or send me a postcard! Avdi Grimm (ShipRise) GoGaRuCo 2012 50 / 50