2. TWO THINGS TO
KNOW ABOUT ME
I wrote the TextMate book
My name is Jim Weirich
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
7. 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.
8. 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
11. 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
12. 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
13. 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
17. $ 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
18. $ 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
23. 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)
27. @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
28. 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
31. 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
34. 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
35. 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
36. 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
39. 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
40. 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
41. 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”
42. 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()