Slide 1

Slide 1 text

No content

Slide 2

Slide 2 text

Code Reading 101

Slide 3

Slide 3 text

TWO THINGS TO KNOW ABOUT ME

Slide 4

Slide 4 text

TWO THINGS TO KNOW ABOUT ME I wrote the TextMate book

Slide 5

Slide 5 text

TWO THINGS TO KNOW ABOUT ME I wrote the TextMate book My name is Jim Weirich

Slide 6

Slide 6 text

JAMES EDWARD GRAY II

Slide 7

Slide 7 text

JAMES EDWARD GRAY II I wrote two books for the Pragmatic Programmers: Best of Ruby Quiz and TextMate: Power Editing for the Mac

Slide 8

Slide 8 text

JAMES EDWARD GRAY II I wrote two books for the Pragmatic Programmers: Best of Ruby Quiz and TextMate: Power Editing for the Mac I’ve contributed documentation and patches for some standard libraries, which I now help to maintain

Slide 9

Slide 9 text

JAMES EDWARD GRAY II I wrote two books for the Pragmatic Programmers: Best of Ruby Quiz and TextMate: Power Editing for the Mac I’ve contributed documentation and patches for some standard libraries, which I now help to maintain I built FasterCSV (now CSV), HighLine (with Greg), Elif, and a few other libraries people don’t use

Slide 10

Slide 10 text

JAMES EDWARD GRAY II I wrote two books for the Pragmatic Programmers: Best of Ruby Quiz and TextMate: Power Editing for the Mac I’ve contributed documentation and patches for some standard libraries, which I now help to maintain I built FasterCSV (now CSV), HighLine (with Greg), Elif, and a few other libraries people don’t use I created the Ruby Quiz and ran it for the first three years

Slide 11

Slide 11 text

No content

Slide 12

Slide 12 text

No content

Slide 13

Slide 13 text

No content

Slide 14

Slide 14 text

No content

Slide 15

Slide 15 text

HI. I’M JAMES AND I READ CODE.

Slide 16

Slide 16 text

HOW MUCH SHOULD YOU READ?

Slide 17

Slide 17 text

HOW MUCH SHOULD YOU READ? My opinion based on the Dreyfus Model of Skill Acquisition.

Slide 18

Slide 18 text

WHY IS CODE READING IMPORTANT?

Slide 19

Slide 19 text

WHY IS CODE READING IMPORTANT? It can show you common idioms

Slide 20

Slide 20 text

WHY IS CODE READING IMPORTANT? It can show you common idioms It’s good to practice breaking down possibly challenging code, because you will always have to work with other’s code

Slide 21

Slide 21 text

WHY IS CODE READING IMPORTANT? It can show you common idioms It’s good to practice breaking down possibly challenging code, because you will always have to work with other’s code Understanding how something works gives you insight into any limitations it has

Slide 22

Slide 22 text

WHY IS CODE READING IMPORTANT? It can show you common idioms It’s good to practice breaking down possibly challenging code, because you will always have to work with other’s code Understanding how something works gives you insight into any limitations it has Seeing bad code helps you write better code

Slide 23

Slide 23 text

WHY IS CODE READING IMPORTANT? It can show you common idioms It’s good to practice breaking down possibly challenging code, because you will always have to work with other’s code Understanding how something works gives you insight into any limitations it has Seeing bad code helps you write better code Knowledge workers always need more ideas

Slide 24

Slide 24 text

No content

Slide 25

Slide 25 text

No content

Slide 26

Slide 26 text

INTRODUCING RESTCLIENT

Slide 27

Slide 27 text

WHAT IS RESTCLIENT?

Slide 28

Slide 28 text

WHAT IS RESTCLIENT? Sinatra’s sister library (sometimes called “reverse Sinatra”)

Slide 29

Slide 29 text

WHAT IS RESTCLIENT? Sinatra’s sister library (sometimes called “reverse Sinatra”) It provides a very clean interface to RESTful web services

Slide 30

Slide 30 text

WHAT IS RESTCLIENT? Sinatra’s sister library (sometimes called “reverse Sinatra”) It provides a very clean interface to RESTful web services Simple well-written code (around 500 lines of clear code for the core functionality)

Slide 31

Slide 31 text

WHAT IS RESTCLIENT? Sinatra’s sister library (sometimes called “reverse Sinatra”) It provides a very clean interface to RESTful web services Simple well-written code (around 500 lines of clear code for the core functionality) Plus a couple of exciting features

Slide 32

Slide 32 text

BASIC GET Reading tweets with Twitter’s API

Slide 33

Slide 33 text

BASIC GET Reading tweets with Twitter’s API require "rubygems" require "rest_client" require "json" ! twitter = RestClient::Resource.new( "http://twitter.com/statuses", :user => "JEG2", :password => "secret" ) ! json = twitter["friends_timeline.json"].get tweets = JSON.parse(json) tweets.each do |tweet| # ... end

Slide 34

Slide 34 text

BASIC GET Reading tweets with Twitter’s API require "rubygems" require "rest_client" require "json" ! twitter = RestClient::Resource.new( "http://twitter.com/statuses", :user => "JEG2", :password => "secret" ) ! json = twitter["friends_timeline.json"].get tweets = JSON.parse(json) tweets.each do |tweet| # ... end

Slide 35

Slide 35 text

BASIC POST Posting a tweet with Twitter’s API

Slide 36

Slide 36 text

BASIC POST Posting a tweet with Twitter’s API require "rubygems" require "rest_client" require "json" ! twitter = RestClient::Resource.new( "http://twitter.com/statuses", :user => "JEG2", :password => "secret" ) ! json = twitter["update.json"].post(:status => "Hello from #mwrc!") tweet = JSON.parse(json) # ...

Slide 37

Slide 37 text

BASIC POST Posting a tweet with Twitter’s API require "rubygems" require "rest_client" require "json" ! twitter = RestClient::Resource.new( "http://twitter.com/statuses", :user => "JEG2", :password => "secret" ) ! json = twitter["update.json"].post(:status => "Hello from #mwrc!") tweet = JSON.parse(json) # ...

Slide 38

Slide 38 text

NETWORKING CODE DONE RIGHT

Slide 39

Slide 39 text

No content

Slide 40

Slide 40 text

def process_result(res) if res.code =~ /\A2\d{2}\z/ decode res['content-encoding'], res.body if res.body elsif %w(301 302 303).include? res.code url = res.header['Location'] ! if url !~ /^http/ uri = URI.parse(@url) uri.path = "/#{url}".squeeze('/') url = uri.to_s end ! raise Redirect, url elsif res.code == "304" raise NotModified, res elsif res.code == "401" raise Unauthorized, res elsif res.code == "404" raise ResourceNotFound, res else raise RequestFailed, res end end def transmit(uri, req, payload) setup_credentials(req) ! net = net_http_class.new(uri.host, uri.port) net.use_ssl = uri.is_a?(URI::HTTPS) net.verify_mode = OpenSSL::SSL::VERIFY_NONE net.read_timeout = @timeout if @timeout net.open_timeout = @open_timeout if @open_timeout ! display_log request_log ! net.start do |http| res = http.request(req, payload) display_log response_log(res) string = process_result(res) ! if string or @method == :head Response.new(string, res) else nil end end rescue EOFError raise RestClient::ServerBrokeConnection rescue Timeout::Error raise RestClient::RequestTimeout end def decode(content_encoding, body) if content_encoding == 'gzip' and not body.empty? Zlib::GzipReader.new(StringIO.new(body)).read elsif content_encoding == 'deflate' Zlib::Inflate.new.inflate(body) else body end end

Slide 41

Slide 41 text

A RESTFUL SHELL (IN 90 LOC)

Slide 42

Slide 42 text

CURL-ISH REQUESTS Fetching the latest tweet from Twitter’s API

Slide 43

Slide 43 text

CURL-ISH REQUESTS Fetching the latest tweet from Twitter’s API $ restclient \ > get http://twitter.com/statuses/friends_timeline.json?count=1 \ > JEG2 secret [{"text":"Sent out first round of Twitter client betas…", "user":{"name":"Jeremy McAnally","screen_name":"jeremymcanally",…}, …}]

Slide 44

Slide 44 text

RESTFUL IRB Interacting with the Twitter API

Slide 45

Slide 45 text

RESTFUL IRB Interacting with the Twitter API $ restclient http://twitter.com/statuses JEG2 secret >> post "update.json", :status => "The RestClient shell is fun." => "{\"text\":\"The RestClient shell is fun.\",…}" >> get "friends_timeline.json?count=1" => "[{\"text\":\"The RestClient shell is fun.\",…}]"

Slide 46

Slide 46 text

RESTFUL IRB Interacting with the Twitter API $ restclient http://twitter.com/statuses JEG2 secret >> post "update.json", :status => "The RestClient shell is fun." => "{\"text\":\"The RestClient shell is fun.\",…}" >> get "friends_timeline.json?count=1" => "[{\"text\":\"The RestClient shell is fun.\",…}]"

Slide 47

Slide 47 text

RESTFUL IRB Interacting with the Twitter API $ restclient http://twitter.com/statuses JEG2 secret >> post "update.json", :status => "The RestClient shell is fun." => "{\"text\":\"The RestClient shell is fun.\",…}" >> get "friends_timeline.json?count=1" => "[{\"text\":\"The RestClient shell is fun.\",…}]"

Slide 48

Slide 48 text

LOGGING IN RUBY

Slide 49

Slide 49 text

GENERATING RUBY Interactively building a RESTful Ruby script

Slide 50

Slide 50 text

GENERATING RUBY Interactively building a RESTful Ruby script $ RESTCLIENT_LOG=twitter_fun.rb restclient … >> post "update.json", :status => "The RestClient shell is fun." => … >> get "friends_timeline.json?count=1" => …

Slide 51

Slide 51 text

GENERATING RUBY Interactively building a RESTful Ruby script $ RESTCLIENT_LOG=twitter_fun.rb restclient … >> post "update.json", :status => "The RestClient shell is fun." => … >> get "friends_timeline.json?count=1" => …

Slide 52

Slide 52 text

GENERATING RUBY Interactively building a RESTful Ruby script $ RESTCLIENT_LOG=twitter_fun.rb restclient … >> post "update.json", :status => "The RestClient shell is fun." => … >> get "friends_timeline.json?count=1" => … # twitter_fun.rb RestClient.post "http://twitter.com/statuses/update.json", "status=The%20RestClient%20shell%20is%20fun.", :content_type=>"application/x-www-form-urlencoded" # => 200 OK | application/json 379 bytes RestClient.get "http://twitter.com/statuses/friends_timeline.json?count=1" # => 200 OK | application/json 381 bytes

Slide 53

Slide 53 text

No content

Slide 54

Slide 54 text

No content

Slide 55

Slide 55 text

FASTERCSV IS THE NEW CSV

Slide 56

Slide 56 text

THE LESS BORING PARTS OF CSV

Slide 57

Slide 57 text

THE LESS BORING PARTS OF CSV Tricky data structures are needed

Slide 58

Slide 58 text

THE LESS BORING PARTS OF CSV Tricky data structures are needed Rows need ordered access for their columns

Slide 59

Slide 59 text

THE LESS BORING PARTS OF CSV Tricky data structures are needed Rows need ordered access for their columns Users also like to work with them by header name

Slide 60

Slide 60 text

THE LESS BORING PARTS OF CSV Tricky data structures are needed Rows need ordered access for their columns Users also like to work with them by header name Column names often repeat

Slide 61

Slide 61 text

THE LESS BORING PARTS OF CSV Tricky data structures are needed Rows need ordered access for their columns Users also like to work with them by header name Column names often repeat Now that we have m17n, CSV parses in the encoding of your data (no transcoding is done on your data)

Slide 62

Slide 62 text

THE ARRAY-HASH- WITH-DUPLICATES DATA THING

Slide 63

Slide 63 text

CSV::ROW The various ways to refer to data

Slide 64

Slide 64 text

CSV::ROW The various ways to refer to data require "csv" # using Ruby 1.9 ! data = < true, :header_converters => :symbol)[-1] ! ps3[0] # => "PlayStation 3" ps3[:percent] # => "27.8%" ps3[:percent, 3] # => "19.3%" ps3[:percent, ps3.index(:units_sold_2008)] # => "19.3%"

Slide 65

Slide 65 text

CSV::ROW The various ways to refer to data require "csv" # using Ruby 1.9 ! data = < true, :header_converters => :symbol)[-1] ! ps3[0] # => "PlayStation 3" ps3[:percent] # => "27.8%" ps3[:percent, 3] # => "19.3%" ps3[:percent, ps3.index(:units_sold_2008)] # => "19.3%"

Slide 66

Slide 66 text

M17N IN ACTION

Slide 67

Slide 67 text

No content

Slide 68

Slide 68 text

@io = if data.is_a? String then StringIO.new(data) else data end @encoding = if @io.respond_to? :internal_encoding @io.internal_encoding || @io.external_encoding elsif @io.is_a? StringIO @io.string.encoding end @encoding ||= Encoding.default_internal || Encoding.default_external

Slide 69

Slide 69 text

@io = if data.is_a? String then StringIO.new(data) else data end @encoding = if @io.respond_to? :internal_encoding @io.internal_encoding || @io.external_encoding elsif @io.is_a? StringIO @io.string.encoding end @encoding ||= Encoding.default_internal || Encoding.default_external

Slide 70

Slide 70 text

@io = if data.is_a? String then StringIO.new(data) else data end @encoding = if @io.respond_to? :internal_encoding @io.internal_encoding || @io.external_encoding elsif @io.is_a? StringIO @io.string.encoding end @encoding ||= Encoding.default_internal || Encoding.default_external def encode_re(*chunks) Regexp.new(encode_str(*chunks)) end ! def encode_str(*chunks) chunks.map { |chunk| chunk.encode(@encoding.name) }.join end

Slide 71

Slide 71 text

@io = if data.is_a? String then StringIO.new(data) else data end @encoding = if @io.respond_to? :internal_encoding @io.internal_encoding || @io.external_encoding elsif @io.is_a? StringIO @io.string.encoding end @encoding ||= Encoding.default_internal || Encoding.default_external def encode_re(*chunks) Regexp.new(encode_str(*chunks)) end ! def encode_str(*chunks) chunks.map { |chunk| chunk.encode(@encoding.name) }.join end

Slide 72

Slide 72 text

@io = if data.is_a? String then StringIO.new(data) else data end @encoding = if @io.respond_to? :internal_encoding @io.internal_encoding || @io.external_encoding elsif @io.is_a? StringIO @io.string.encoding end @encoding ||= Encoding.default_internal || Encoding.default_external sample = read_to_char(1024) sample += read_to_char(1) if sample[-1..-1] == encode_str("\r") and not @io.eof? ! if sample =~ encode_re("\r\n?|\n") @row_sep = $& break end def encode_re(*chunks) Regexp.new(encode_str(*chunks)) end ! def encode_str(*chunks) chunks.map { |chunk| chunk.encode(@encoding.name) }.join end

Slide 73

Slide 73 text

@io = if data.is_a? String then StringIO.new(data) else data end @encoding = if @io.respond_to? :internal_encoding @io.internal_encoding || @io.external_encoding elsif @io.is_a? StringIO @io.string.encoding end @encoding ||= Encoding.default_internal || Encoding.default_external sample = read_to_char(1024) sample += read_to_char(1) if sample[-1..-1] == encode_str("\r") and not @io.eof? ! if sample =~ encode_re("\r\n?|\n") @row_sep = $& break end def encode_re(*chunks) Regexp.new(encode_str(*chunks)) end ! def encode_str(*chunks) chunks.map { |chunk| chunk.encode(@encoding.name) }.join end

Slide 74

Slide 74 text

OTHER POINTS OF INTEREST

Slide 75

Slide 75 text

OTHER POINTS OF INTEREST The parser

Slide 76

Slide 76 text

OTHER POINTS OF INTEREST The parser Ruby 1.9’s CSV library uses primarily one ugly regular expression from Master Regular Expressions

Slide 77

Slide 77 text

OTHER POINTS OF INTEREST The parser Ruby 1.9’s CSV library uses primarily one ugly regular expression from Master Regular Expressions The old FasterCSV has switched to a non-regex parser to dodge some regex engine weaknesses

Slide 78

Slide 78 text

OTHER POINTS OF INTEREST The parser Ruby 1.9’s CSV library uses primarily one ugly regular expression from Master Regular Expressions The old FasterCSV has switched to a non-regex parser to dodge some regex engine weaknesses FasterCSV::Table is another interesting data structure that can work in columns or rows

Slide 79

Slide 79 text

No content

Slide 80

Slide 80 text

No content

Slide 81

Slide 81 text

BJ, SLAVE, AND TERMINATOR

Slide 82

Slide 82 text

WHY THESE LIBRARIES?

Slide 83

Slide 83 text

WHY THESE LIBRARIES? They teach how to build multiprocessing Unix software

Slide 84

Slide 84 text

WHY THESE LIBRARIES? They teach how to build multiprocessing Unix software Covers Thread and fork(), apart and together

Slide 85

Slide 85 text

WHY THESE LIBRARIES? They teach how to build multiprocessing Unix software Covers Thread and fork(), apart and together Using pipes

Slide 86

Slide 86 text

WHY THESE LIBRARIES? They teach how to build multiprocessing Unix software Covers Thread and fork(), apart and together Using pipes Signal handling

Slide 87

Slide 87 text

WHY THESE LIBRARIES? They teach how to build multiprocessing Unix software Covers Thread and fork(), apart and together Using pipes Signal handling And much more

Slide 88

Slide 88 text

WHY THESE LIBRARIES? They teach how to build multiprocessing Unix software Covers Thread and fork(), apart and together Using pipes Signal handling And much more Robust code written by an expert

Slide 89

Slide 89 text

HOW TO ASK YOUR CHILD TO KILL YOU

Slide 90

Slide 90 text

No content

Slide 91

Slide 91 text

def terminate options = {}, &block options = { :seconds => Float(options).to_i } unless Hash === options ! seconds = getopt :seconds, options trap = getopt :trap, options, lambda{ eval("raise(::Terminator::Error, '#{ seconds }s')", block) } ! handler = Signal.trap(signal, &trap) ! plot_to_kill pid, :in => seconds, :with => signal ! begin block.call ensure Signal.trap(signal, handler) end end

Slide 92

Slide 92 text

def terminate options = {}, &block options = { :seconds => Float(options).to_i } unless Hash === options ! seconds = getopt :seconds, options trap = getopt :trap, options, lambda{ eval("raise(::Terminator::Error, '#{ seconds }s')", block) } ! handler = Signal.trap(signal, &trap) ! plot_to_kill pid, :in => seconds, :with => signal ! begin block.call ensure Signal.trap(signal, handler) end end

Slide 93

Slide 93 text

No content

Slide 94

Slide 94 text

def plot_to_kill pid, options = {} seconds = getopt :in, options signal = getopt :with, options process.puts [pid, seconds, signal].join(' ') process.flush end

Slide 95

Slide 95 text

def plot_to_kill pid, options = {} seconds = getopt :in, options signal = getopt :with, options process.puts [pid, seconds, signal].join(' ') process.flush end

Slide 96

Slide 96 text

def plot_to_kill pid, options = {} seconds = getopt :in, options signal = getopt :with, options process.puts [pid, seconds, signal].join(' ') process.flush end fattr :process do process = IO.popen "#{ ruby } #{ program.inspect }", 'w+' at_exit do begin Process.kill -9, process.pid rescue Object end end process.sync = true process end

Slide 97

Slide 97 text

def plot_to_kill pid, options = {} seconds = getopt :in, options signal = getopt :with, options process.puts [pid, seconds, signal].join(' ') process.flush end fattr :process do process = IO.popen "#{ ruby } #{ program.inspect }", 'w+' at_exit do begin Process.kill -9, process.pid rescue Object end end process.sync = true process end

Slide 98

Slide 98 text

No content

Slide 99

Slide 99 text

fattr :program do code = <<-code while(( line = STDIN.gets )) pid, seconds, signal, *ignored = line.strip.split ! pid = Float(pid).to_i seconds = Float(seconds) signal = Float(signal).to_i rescue String(signal) ! sleep seconds ! begin Process.kill signal, pid rescue Object end end code tmp = Tempfile.new "#{ ppid }-#{ pid }-#{ rand }" tmp.write code tmp.close tmp.path end

Slide 100

Slide 100 text

fattr :program do code = <<-code while(( line = STDIN.gets )) pid, seconds, signal, *ignored = line.strip.split ! pid = Float(pid).to_i seconds = Float(seconds) signal = Float(signal).to_i rescue String(signal) ! sleep seconds ! begin Process.kill signal, pid rescue Object end end code tmp = Tempfile.new "#{ ppid }-#{ pid }-#{ rand }" tmp.write code tmp.close tmp.path end

Slide 101

Slide 101 text

fattr :program do code = <<-code while(( line = STDIN.gets )) pid, seconds, signal, *ignored = line.strip.split ! pid = Float(pid).to_i seconds = Float(seconds) signal = Float(signal).to_i rescue String(signal) ! sleep seconds ! begin Process.kill signal, pid rescue Object end end code tmp = Tempfile.new "#{ ppid }-#{ pid }-#{ rand }" tmp.write code tmp.close tmp.path end

Slide 102

Slide 102 text

fattr :program do code = <<-code while(( line = STDIN.gets )) pid, seconds, signal, *ignored = line.strip.split ! pid = Float(pid).to_i seconds = Float(seconds) signal = Float(signal).to_i rescue String(signal) ! sleep seconds ! begin Process.kill signal, pid rescue Object end end code tmp = Tempfile.new "#{ ppid }-#{ pid }-#{ rand }" tmp.write code tmp.close tmp.path end

Slide 103

Slide 103 text

fattr :program do code = <<-code while(( line = STDIN.gets )) pid, seconds, signal, *ignored = line.strip.split ! pid = Float(pid).to_i seconds = Float(seconds) signal = Float(signal).to_i rescue String(signal) ! sleep seconds ! begin Process.kill signal, pid rescue Object end end code tmp = Tempfile.new "#{ ppid }-#{ pid }-#{ rand }" tmp.write code tmp.close tmp.path end

Slide 104

Slide 104 text

fattr :program do code = <<-code while(( line = STDIN.gets )) pid, seconds, signal, *ignored = line.strip.split ! pid = Float(pid).to_i seconds = Float(seconds) signal = Float(signal).to_i rescue String(signal) ! sleep seconds ! begin Process.kill signal, pid rescue Object end end code tmp = Tempfile.new "#{ ppid }-#{ pid }-#{ rand }" tmp.write code tmp.close tmp.path end

Slide 105

Slide 105 text

fattr :program do code = <<-code while(( line = STDIN.gets )) pid, seconds, signal, *ignored = line.strip.split ! pid = Float(pid).to_i seconds = Float(seconds) signal = Float(signal).to_i rescue String(signal) ! sleep seconds ! begin Process.kill signal, pid rescue Object end end code tmp = Tempfile.new "#{ ppid }-#{ pid }-#{ rand }" tmp.write code tmp.close tmp.path end

Slide 106

Slide 106 text

OTHER POINTS OF INTEREST

Slide 107

Slide 107 text

OTHER POINTS OF INTEREST bj – A robust background priority queue for Rails

Slide 108

Slide 108 text

OTHER POINTS OF INTEREST bj – A robust background priority queue for Rails Noticing changes from the outside world via signals

Slide 109

Slide 109 text

OTHER POINTS OF INTEREST bj – A robust background priority queue for Rails Noticing changes from the outside world via signals Managing and monitoring an external job

Slide 110

Slide 110 text

OTHER POINTS OF INTEREST bj – A robust background priority queue for Rails Noticing changes from the outside world via signals Managing and monitoring an external job slave – Trivial multiprocessing with built-in IPC

Slide 111

Slide 111 text

OTHER POINTS OF INTEREST bj – A robust background priority queue for Rails Noticing changes from the outside world via signals Managing and monitoring an external job slave – Trivial multiprocessing with built-in IPC How to set up a “heartbeat” between processes

Slide 112

Slide 112 text

OTHER POINTS OF INTEREST bj – A robust background priority queue for Rails Noticing changes from the outside world via signals Managing and monitoring an external job slave – Trivial multiprocessing with built-in IPC How to set up a “heartbeat” between processes How to run DRb over Unix domain sockets

Slide 113

Slide 113 text

No content

Slide 114

Slide 114 text

No content

Slide 115

Slide 115 text

THE ART OF CODE READING

Slide 116

Slide 116 text

PROCESS TIPS

Slide 117

Slide 117 text

PROCESS TIPS Take a deep breath and relax

Slide 118

Slide 118 text

PROCESS TIPS Take a deep breath and relax Not all code sucks

Slide 119

Slide 119 text

PROCESS TIPS Take a deep breath and relax Not all code sucks Don’t start with Rails

Slide 120

Slide 120 text

PROCESS TIPS Take a deep breath and relax Not all code sucks Don’t start with Rails There’s a ton of great stuff in there

Slide 121

Slide 121 text

PROCESS TIPS Take a deep breath and relax Not all code sucks Don’t start with Rails There’s a ton of great stuff in there But it’s a big and complex beast

Slide 122

Slide 122 text

PROCESS TIPS Take a deep breath and relax Not all code sucks Don’t start with Rails There’s a ton of great stuff in there But it’s a big and complex beast Have a goal

Slide 123

Slide 123 text

GETTING THE CODE

Slide 124

Slide 124 text

GETTING THE CODE gem unpack GEM_NAME

Slide 125

Slide 125 text

GETTING THE CODE gem unpack GEM_NAME Use anonymous VCS access to pull a local copy of the code

Slide 126

Slide 126 text

GETTING THE CODE gem unpack GEM_NAME Use anonymous VCS access to pull a local copy of the code Open it in your standard environment as you would if you were going to edit it

Slide 127

Slide 127 text

FINDING THINGS

Slide 128

Slide 128 text

FINDING THINGS Try the conventions first

Slide 129

Slide 129 text

FINDING THINGS Try the conventions first Executables are probably in the bin/ directory

Slide 130

Slide 130 text

FINDING THINGS Try the conventions first Executables are probably in the bin/ directory Look for MyModule::MyClass in lib/my_module/ my_class.rb

Slide 131

Slide 131 text

FINDING THINGS Try the conventions first Executables are probably in the bin/ directory Look for MyModule::MyClass in lib/my_module/ my_class.rb Look for methods in super classes and mixed in modules

Slide 132

Slide 132 text

FINDING THINGS Try the conventions first Executables are probably in the bin/ directory Look for MyModule::MyClass in lib/my_module/ my_class.rb Look for methods in super classes and mixed in modules But remember Ruby is quite dynamic

Slide 133

Slide 133 text

FINDING THINGS Try the conventions first Executables are probably in the bin/ directory Look for MyModule::MyClass in lib/my_module/ my_class.rb Look for methods in super classes and mixed in modules But remember Ruby is quite dynamic Hunt for some “core extensions”

Slide 134

Slide 134 text

UNDERSTANDING THE CODE

Slide 135

Slide 135 text

UNDERSTANDING THE CODE Start with the tests/specs if there are any

Slide 136

Slide 136 text

UNDERSTANDING THE CODE Start with the tests/specs if there are any Check for an “examples/” directory

Slide 137

Slide 137 text

UNDERSTANDING THE CODE Start with the tests/specs if there are any Check for an “examples/” directory Try to load and play with certain classes in isolation

Slide 138

Slide 138 text

UNDERSTANDING THE CODE Start with the tests/specs if there are any Check for an “examples/” directory Try to load and play with certain classes in isolation irb -r a_class_to_play_with

Slide 139

Slide 139 text

UNDERSTANDING THE CODE Start with the tests/specs if there are any Check for an “examples/” directory Try to load and play with certain classes in isolation irb -r a_class_to_play_with Remember Ruby’s reflection methods, like methods()

Slide 140

Slide 140 text

QUESTIONS? About code or other important topics…