Code Reading 101
TWO THINGS TO
KNOW ABOUT ME


I wrote the TextMate book

My name is Jim Weirich
JAMES EDWARD
GRAY II
I wrote two books for the Pragmatic Programmers: Best of
Ruby Quiz and TextMate: Power Editing for th...
HI. I’M JAMES AND
   I READ CODE.
HOW MUCH SHOULD
   YOU READ?
                      0%   25%        50%         75%
                                       ...
WHY IS CODE
READING IMPORTANT?
It can show you common idioms

It’s good to practice breaking down possibly challenging
cod...
INTRODUCING
 RESTCLIENT
WHAT IS RESTCLIENT?


Sinatra’s sister library (sometimes called “reverse Sinatra”)

It provides a very clean interface to...
require quot;rubygemsquot;
require quot;rest_clientquot;
require quot;jsonquot;

twitter = RestClient::Resource.new( quot;...
require quot;rubygemsquot;
require quot;rest_clientquot;
require quot;jsonquot;

twitter = RestClient::Resource.new( quot;...
NETWORKING CODE
   DONE RIGHT
def process_result(res)
                                                       if res.code =~ /A2d{2}z/
                  ...
A RESTFUL SHELL
   (IN 90 LOC)
$ restclient 
> get http://twitter.com/statuses/friends_timeline.json?count=1 
> JEG2 secret
[{quot;textquot;:quot;Sent ou...
$ restclient http://twitter.com/statuses JEG2 secret
>> post quot;update.jsonquot;, :status => quot;The RestClient shell i...
LOGGING IN RUBY
$ RESTCLIENT_LOG=twitter_fun.rb restclient …
    >> post quot;update.jsonquot;, :status => quot;The RestClient shell is fu...
FASTERCSV IS
THE NEW CSV
THE LESS BORING
PARTS OF CSV
Tricky data structures are needed

  Rows need ordered access for their columns

  Users also...
THE ARRAY-HASH-
WITH-DUPLICATES
  DATA THING
require quot;csvquot;   # using Ruby 1.9

data = <<END_DATA
Console,Units Sold 2007,Percent,Units Sold 2008,Percent
Wii,qu...
M17N IN ACTION
@io       =   if data.is_a? String then StringIO.new(data) else data end
@encoding =   if @io.respond_to? :internal_encodi...
OTHER POINTS
OF INTEREST
The parser

  Ruby 1.9’s CSV library uses primarily one ugly regular
  expression from Master Reg...
BJ, SLAVE,
AND TERMINATOR
WHY THESE
LIBRARIES?
They teach how to build multiprocessing Unix software

  Covers Thread and fork(), apart and together...
HOW TO ASK YOUR
CHILD TO KILL YOU
def terminate options = {}, &block
  options = { :seconds => Float(options).to_i } unless Hash === options

 seconds = get...
def plot_to_kill pid, options = {}
  seconds = getopt :in, options
  signal = getopt :with, options
  process.puts [pid, s...
fattr :program do
  code = <<-code
    while(( line = STDIN.gets ))
      pid, seconds, signal, *ignored = line.strip.spli...
OTHER POINTS
OF INTEREST
bj – A robust background priority queue for Rails

  Noticing changes from the outside world via ...
THE ART OF
CODE READING
PROCESS TIPS

Take a deep breath and relax

  Not all code sucks

Don’t start with Rails

  There’s a ton of great stuff i...
GETTING THE CODE


gem unpack GEM_NAME

Use anonymous VCS access to pull a local copy of the code

Open it in your standar...
FINDING THINGS
Try the conventions first

  Executables are probably in the bin/ directory

  Look for MyModule::MyClass i...
UNDERSTANDING
THE CODE

Start with the tests/specs if there are any

Check for an “examples/” directory

Try to load and p...
QUESTIONS?
About code or other important topics…
Little Big Ruby
Little Big Ruby
Little Big Ruby
Little Big Ruby
Little Big Ruby
Little Big Ruby
Upcoming SlideShare
Loading in...5
×

Little Big Ruby

2,091

Published on

Published in: Technology
0 Comments
3 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
2,091
On Slideshare
0
From Embeds
0
Number of Embeds
0
Actions
Shares
0
Downloads
36
Comments
0
Likes
3
Embeds 0
No embeds

No notes for slide

Little Big Ruby

  1. 1. Code Reading 101
  2. 2. TWO THINGS TO KNOW ABOUT ME I wrote the TextMate book My name is Jim Weirich
  3. 3. 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
  4. 4. HI. I’M JAMES AND I READ CODE.
  5. 5. HOW MUCH SHOULD YOU READ? 0% 25% 50% 75% 100% Novice Advanced Beginner Competent Proficient Expert My opinion based on the Dreyfus Model of Skill Acquisition.
  6. 6. 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
  7. 7. INTRODUCING RESTCLIENT
  8. 8. 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
  9. 9. require quot;rubygemsquot; require quot;rest_clientquot; require quot;jsonquot; twitter = RestClient::Resource.new( quot;http://twitter.com/statusesquot;, :user => quot;JEG2quot;, :password => quot;secretquot; ) json = twitter[quot;friends_timeline.jsonquot;].get tweets = JSON.parse(json) tweets.each do |tweet| # ... end BASIC GET Reading tweets with Twitter’s API
  10. 10. require quot;rubygemsquot; require quot;rest_clientquot; require quot;jsonquot; twitter = RestClient::Resource.new( quot;http://twitter.com/statusesquot;, :user => quot;JEG2quot;, :password => quot;secretquot; ) json = twitter[quot;update.jsonquot;].post(:status => quot;Hello from #mwrc!quot;) tweet = JSON.parse(json) # ... BASIC POST Posting a tweet with Twitter’s API
  11. 11. NETWORKING CODE DONE RIGHT
  12. 12. def process_result(res) if res.code =~ /A2d{2}z/ decode res['content-encoding'], res.body if res.body elsif %w(301 302 303).include? res.code url = res.header['Location'] def transmit(uri, req, payload) setup_credentials(req) if url !~ /^http/ uri = URI.parse(@url) net = net_http_class.new(uri.host, uri.port) uri.path = quot;/#{url}quot;.squeeze('/') net.use_ssl = uri.is_a?(URI::HTTPS) url = uri.to_s net.verify_mode = OpenSSL::SSL::VERIFY_NONE end net.read_timeout = @timeout if @timeout net.open_timeout = @open_timeout if @open_timeout raise Redirect, url elsif res.code == quot;304quot; display_log request_log raise NotModified, res elsif res.code == quot;401quot; net.start do |http| raise Unauthorized, res res = http.request(req, payload) elsif res.code == quot;404quot; display_log response_log(res) raise ResourceNotFound, res string = process_result(res) else raise RequestFailed, res if string or @method == :head end Response.new(string, res) end else nil end end rescue EOFError def decode(content_encoding, body) raise RestClient::ServerBrokeConnection if content_encoding == 'gzip' and not body.empty? rescue Timeout::Error Zlib::GzipReader.new(StringIO.new(body)).read raise RestClient::RequestTimeout elsif content_encoding == 'deflate' end Zlib::Inflate.new.inflate(body) else body end end
  13. 13. A RESTFUL SHELL (IN 90 LOC)
  14. 14. $ restclient > get http://twitter.com/statuses/friends_timeline.json?count=1 > JEG2 secret [{quot;textquot;:quot;Sent out first round of Twitter client betas…quot;, quot;userquot;:{quot;namequot;:quot;Jeremy McAnallyquot;,quot;screen_namequot;:quot;jeremymcanallyquot;,…}, …}] CURL-ISH REQUESTS Fetching the latest tweet !om Twitter’s API
  15. 15. $ restclient http://twitter.com/statuses JEG2 secret >> post quot;update.jsonquot;, :status => quot;The RestClient shell is fun.quot; => quot;{quot;textquot;:quot;The RestClient shell is fun.quot;,…}quot; >> get quot;friends_timeline.json?count=1quot; => quot;[{quot;textquot;:quot;The RestClient shell is fun.quot;,…}]quot; RESTFUL IRB Interacting with the Twitter API
  16. 16. LOGGING IN RUBY
  17. 17. $ RESTCLIENT_LOG=twitter_fun.rb restclient … >> post quot;update.jsonquot;, :status => quot;The RestClient shell is fun.quot; => … >> get quot;friends_timeline.json?count=1quot; => … # twitter_fun.rb RestClient.post quot;http://twitter.com/statuses/update.jsonquot;, quot;status=The%20RestClient%20shell%20is%20fun.quot;, :content_type=>quot;application/x-www-form-urlencodedquot; # => 200 OK | application/json 379 bytes RestClient.get quot;http://twitter.com/statuses/friends_timeline.json?count=1quot; # => 200 OK | application/json 381 bytes GENERATING RUBY Interactively building a RESTful Ruby script
  18. 18. FASTERCSV IS THE NEW CSV
  19. 19. 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)
  20. 20. THE ARRAY-HASH- WITH-DUPLICATES DATA THING
  21. 21. require quot;csvquot; # using Ruby 1.9 data = <<END_DATA Console,Units Sold 2007,Percent,Units Sold 2008,Percent Wii,quot;719,141quot;,49.4%,quot;1,184,651quot;,49.6% XBox 360,quot;333,084quot;,22.9%,quot;743,976quot;,31.1% PlayStation 3,quot;404,900quot;,27.8%,quot;459,777quot;,19.3% END_DATA ps3 = CSV.parse(data, :headers => true, :header_converters => :symbol)[-1] ps3[0] # => quot;PlayStation 3quot; ps3[:percent] # => quot;27.8%quot; ps3[:percent, 3] # => quot;19.3%quot; ps3[:percent, ps3.index(:units_sold_2008)] # => quot;19.3%quot; CSV::ROW The various ways to refer to data
  22. 22. M17N IN ACTION
  23. 23. @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 sample = read_to_char(1024) sample += read_to_char(1) if sample[-1..-1] == encode_str(quot;rquot;) and not @io.eof? if sample =~ encode_re(quot;rn?|nquot;) @row_sep = $& break end
  24. 24. 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
  25. 25. BJ, SLAVE, AND TERMINATOR
  26. 26. 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
  27. 27. HOW TO ASK YOUR CHILD TO KILL YOU
  28. 28. def terminate options = {}, &block options = { :seconds => Float(options).to_i } unless Hash === options seconds = getopt :seconds, options trap = getopt :trap, options, lambda{ eval(quot;raise(::Terminator::Error, '#{ seconds }s')quot;, block) } handler = Signal.trap(signal, &trap) plot_to_kill pid, :in => seconds, :with => signal begin block.call ensure Signal.trap(signal, handler) end end
  29. 29. 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 quot;#{ ruby } #{ program.inspect }quot;, 'w+' at_exit do begin Process.kill -9, process.pid rescue Object end end process.sync = true process end
  30. 30. 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 quot;#{ ppid }-#{ pid }-#{ rand }quot; tmp.write code tmp.close tmp.path end
  31. 31. 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
  32. 32. THE ART OF CODE READING
  33. 33. 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
  34. 34. 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
  35. 35. 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”
  36. 36. 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()
  37. 37. QUESTIONS? About code or other important topics…
  1. A particular slide catching your eye?

    Clipping is a handy way to collect important slides you want to go back to later.

×