Little Big Ruby
-
Upload
littlebigruby -
Category
Technology
-
view
2.100 -
download
1
Transcript of Little Big Ruby
![Page 1: Little Big Ruby](https://reader038.fdocuments.net/reader038/viewer/2022102722/554f3ebcb4c905471e8b4c1c/html5/thumbnails/1.jpg)
Code Reading 101
![Page 2: Little Big Ruby](https://reader038.fdocuments.net/reader038/viewer/2022102722/554f3ebcb4c905471e8b4c1c/html5/thumbnails/2.jpg)
TWO THINGS TO KNOW ABOUT ME
I wrote the TextMate book
My name is Jim Weirich
![Page 3: Little Big Ruby](https://reader038.fdocuments.net/reader038/viewer/2022102722/554f3ebcb4c905471e8b4c1c/html5/thumbnails/3.jpg)
JAMES EDWARDGRAY 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
![Page 4: Little Big Ruby](https://reader038.fdocuments.net/reader038/viewer/2022102722/554f3ebcb4c905471e8b4c1c/html5/thumbnails/4.jpg)
![Page 5: Little Big Ruby](https://reader038.fdocuments.net/reader038/viewer/2022102722/554f3ebcb4c905471e8b4c1c/html5/thumbnails/5.jpg)
![Page 6: Little Big Ruby](https://reader038.fdocuments.net/reader038/viewer/2022102722/554f3ebcb4c905471e8b4c1c/html5/thumbnails/6.jpg)
HI. I’M JAMES ANDI READ CODE.
![Page 7: Little Big Ruby](https://reader038.fdocuments.net/reader038/viewer/2022102722/554f3ebcb4c905471e8b4c1c/html5/thumbnails/7.jpg)
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.
![Page 8: Little Big Ruby](https://reader038.fdocuments.net/reader038/viewer/2022102722/554f3ebcb4c905471e8b4c1c/html5/thumbnails/8.jpg)
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
![Page 9: Little Big Ruby](https://reader038.fdocuments.net/reader038/viewer/2022102722/554f3ebcb4c905471e8b4c1c/html5/thumbnails/9.jpg)
![Page 10: Little Big Ruby](https://reader038.fdocuments.net/reader038/viewer/2022102722/554f3ebcb4c905471e8b4c1c/html5/thumbnails/10.jpg)
INTRODUCING RESTCLIENT
![Page 11: Little Big Ruby](https://reader038.fdocuments.net/reader038/viewer/2022102722/554f3ebcb4c905471e8b4c1c/html5/thumbnails/11.jpg)
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
![Page 12: Little Big Ruby](https://reader038.fdocuments.net/reader038/viewer/2022102722/554f3ebcb4c905471e8b4c1c/html5/thumbnails/12.jpg)
BASIC GETReading 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"].gettweets = JSON.parse(json)tweets.each do |tweet| # ...end
![Page 13: Little Big Ruby](https://reader038.fdocuments.net/reader038/viewer/2022102722/554f3ebcb4c905471e8b4c1c/html5/thumbnails/13.jpg)
BASIC POSTPosting 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)# ...
![Page 14: Little Big Ruby](https://reader038.fdocuments.net/reader038/viewer/2022102722/554f3ebcb4c905471e8b4c1c/html5/thumbnails/14.jpg)
NETWORKING CODE DONE RIGHT
![Page 15: Little Big Ruby](https://reader038.fdocuments.net/reader038/viewer/2022102722/554f3ebcb4c905471e8b4c1c/html5/thumbnails/15.jpg)
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 endend
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 endrescue EOFError raise RestClient::ServerBrokeConnectionrescue Timeout::Error raise RestClient::RequestTimeoutend
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 endend
![Page 16: Little Big Ruby](https://reader038.fdocuments.net/reader038/viewer/2022102722/554f3ebcb4c905471e8b4c1c/html5/thumbnails/16.jpg)
A RESTFUL SHELL (IN 90 LOC)
![Page 17: Little Big Ruby](https://reader038.fdocuments.net/reader038/viewer/2022102722/554f3ebcb4c905471e8b4c1c/html5/thumbnails/17.jpg)
CURL-ISH REQUESTSFetching the latest tweet !om 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",…}, …}]
![Page 18: Little Big Ruby](https://reader038.fdocuments.net/reader038/viewer/2022102722/554f3ebcb4c905471e8b4c1c/html5/thumbnails/18.jpg)
RESTFUL IRBInteracting 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.\",…}]"
![Page 19: Little Big Ruby](https://reader038.fdocuments.net/reader038/viewer/2022102722/554f3ebcb4c905471e8b4c1c/html5/thumbnails/19.jpg)
LOGGING IN RUBY
![Page 20: Little Big Ruby](https://reader038.fdocuments.net/reader038/viewer/2022102722/554f3ebcb4c905471e8b4c1c/html5/thumbnails/20.jpg)
GENERATING RUBYInteractively 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.rbRestClient.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 bytesRestClient.get "http://twitter.com/statuses/friends_timeline.json?count=1"# => 200 OK | application/json 381 bytes
![Page 21: Little Big Ruby](https://reader038.fdocuments.net/reader038/viewer/2022102722/554f3ebcb4c905471e8b4c1c/html5/thumbnails/21.jpg)
![Page 22: Little Big Ruby](https://reader038.fdocuments.net/reader038/viewer/2022102722/554f3ebcb4c905471e8b4c1c/html5/thumbnails/22.jpg)
FASTERCSV ISTHE NEW CSV
![Page 23: Little Big Ruby](https://reader038.fdocuments.net/reader038/viewer/2022102722/554f3ebcb4c905471e8b4c1c/html5/thumbnails/23.jpg)
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)
![Page 24: Little Big Ruby](https://reader038.fdocuments.net/reader038/viewer/2022102722/554f3ebcb4c905471e8b4c1c/html5/thumbnails/24.jpg)
THE ARRAY-HASH-WITH-DUPLICATES
DATA THING
![Page 25: Little Big Ruby](https://reader038.fdocuments.net/reader038/viewer/2022102722/554f3ebcb4c905471e8b4c1c/html5/thumbnails/25.jpg)
CSV::ROWThe various ways to refer to data
require "csv" # using Ruby 1.9
data = <<END_DATAConsole,Units Sold 2007,Percent,Units Sold 2008,PercentWii,"719,141",49.4%,"1,184,651",49.6%XBox 360,"333,084",22.9%,"743,976",31.1%PlayStation 3,"404,900",27.8%,"459,777",19.3%END_DATAps3 = CSV.parse(data, :headers => 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%"
![Page 26: Little Big Ruby](https://reader038.fdocuments.net/reader038/viewer/2022102722/554f3ebcb4c905471e8b4c1c/html5/thumbnails/26.jpg)
M17N IN ACTION
![Page 27: Little Big Ruby](https://reader038.fdocuments.net/reader038/viewer/2022102722/554f3ebcb4c905471e8b4c1c/html5/thumbnails/27.jpg)
@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 = $& breakend
def encode_re(*chunks) Regexp.new(encode_str(*chunks))end
def encode_str(*chunks) chunks.map { |chunk| chunk.encode(@encoding.name) }.joinend
![Page 28: Little Big Ruby](https://reader038.fdocuments.net/reader038/viewer/2022102722/554f3ebcb4c905471e8b4c1c/html5/thumbnails/28.jpg)
OTHER POINTSOF 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
![Page 29: Little Big Ruby](https://reader038.fdocuments.net/reader038/viewer/2022102722/554f3ebcb4c905471e8b4c1c/html5/thumbnails/29.jpg)
![Page 30: Little Big Ruby](https://reader038.fdocuments.net/reader038/viewer/2022102722/554f3ebcb4c905471e8b4c1c/html5/thumbnails/30.jpg)
BJ, SLAVE,AND TERMINATOR
![Page 31: Little Big Ruby](https://reader038.fdocuments.net/reader038/viewer/2022102722/554f3ebcb4c905471e8b4c1c/html5/thumbnails/31.jpg)
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
![Page 32: Little Big Ruby](https://reader038.fdocuments.net/reader038/viewer/2022102722/554f3ebcb4c905471e8b4c1c/html5/thumbnails/32.jpg)
HOW TO ASK YOUR CHILD TO KILL YOU
![Page 33: Little Big Ruby](https://reader038.fdocuments.net/reader038/viewer/2022102722/554f3ebcb4c905471e8b4c1c/html5/thumbnails/33.jpg)
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
![Page 34: Little Big Ruby](https://reader038.fdocuments.net/reader038/viewer/2022102722/554f3ebcb4c905471e8b4c1c/html5/thumbnails/34.jpg)
def plot_to_kill pid, options = {} seconds = getopt :in, options signal = getopt :with, options process.puts [pid, seconds, signal].join(' ') process.flushend
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 processend
![Page 35: Little Big Ruby](https://reader038.fdocuments.net/reader038/viewer/2022102722/554f3ebcb4c905471e8b4c1c/html5/thumbnails/35.jpg)
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
![Page 36: Little Big Ruby](https://reader038.fdocuments.net/reader038/viewer/2022102722/554f3ebcb4c905471e8b4c1c/html5/thumbnails/36.jpg)
OTHER POINTSOF 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
![Page 37: Little Big Ruby](https://reader038.fdocuments.net/reader038/viewer/2022102722/554f3ebcb4c905471e8b4c1c/html5/thumbnails/37.jpg)
![Page 38: Little Big Ruby](https://reader038.fdocuments.net/reader038/viewer/2022102722/554f3ebcb4c905471e8b4c1c/html5/thumbnails/38.jpg)
THE ART OFCODE READING
![Page 39: Little Big Ruby](https://reader038.fdocuments.net/reader038/viewer/2022102722/554f3ebcb4c905471e8b4c1c/html5/thumbnails/39.jpg)
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
![Page 40: Little Big Ruby](https://reader038.fdocuments.net/reader038/viewer/2022102722/554f3ebcb4c905471e8b4c1c/html5/thumbnails/40.jpg)
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
![Page 41: Little Big Ruby](https://reader038.fdocuments.net/reader038/viewer/2022102722/554f3ebcb4c905471e8b4c1c/html5/thumbnails/41.jpg)
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”
![Page 42: Little Big Ruby](https://reader038.fdocuments.net/reader038/viewer/2022102722/554f3ebcb4c905471e8b4c1c/html5/thumbnails/42.jpg)
UNDERSTANDINGTHE 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()
![Page 43: Little Big Ruby](https://reader038.fdocuments.net/reader038/viewer/2022102722/554f3ebcb4c905471e8b4c1c/html5/thumbnails/43.jpg)
QUESTIONS?About code or other important topics…