P. 1
LittleBIGRuby

LittleBIGRuby

|Views: 103|Likes:
Published by Best Tech Videos
LittleBIGPlanet is kind of an open source game creation engine for the PlayStation 3. There are two very important things we can learn from it:

* Creative problem solving
* Code reading

Those are some of the strongest weapons in the programmer’s arsenal and we all need to make sure we are employing them regularly. I’ll prime the pump by taking you on a tour of some of the most creative LittleBIGPlanet levels–err, Ruby projects–out there. Let’s see how the pros build servers, communicate between processes, process data, optimize code, and more. This turns out to be a double-win as you will become more familiar with other projects you might be able to make use of while you are learning handy techniques to use in your own creations. Jolly great, eh?

A PlayStation 3 is optional for attendees of this talk.

Watch a video at http://www.bestechvideos.com/2009/03/29/mountainwest-rubyconf-2009-littlebigruby
LittleBIGPlanet is kind of an open source game creation engine for the PlayStation 3. There are two very important things we can learn from it:

* Creative problem solving
* Code reading

Those are some of the strongest weapons in the programmer’s arsenal and we all need to make sure we are employing them regularly. I’ll prime the pump by taking you on a tour of some of the most creative LittleBIGPlanet levels–err, Ruby projects–out there. Let’s see how the pros build servers, communicate between processes, process data, optimize code, and more. This turns out to be a double-win as you will become more familiar with other projects you might be able to make use of while you are learning handy techniques to use in your own creations. Jolly great, eh?

A PlayStation 3 is optional for attendees of this talk.

Watch a video at http://www.bestechvideos.com/2009/03/29/mountainwest-rubyconf-2009-littlebigruby

More info:

Published by: Best Tech Videos on Mar 29, 2009
Copyright:Attribution Non-commercial

Availability:

Read on Scribd mobile: iPhone, iPad and Android.
download as PDF, TXT or read online from Scribd
See more
See less

08/18/2011

pdf

text

original

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 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

HI. I’M JAMES AND I READ CODE.

HOW MUCH SHOULD YOU READ?
0% Novice Advanced Beginner Competent Proficient Expert 25% 50% 75% 100%

My opinion based on the Dreyfus Model of Skill Acquisition.

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

INTRODUCING RESTCLIENT

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

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

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 tweet # ... = twitter["update.json"].post(:status => "Hello from #mwrc!") = JSON.parse(json)

BASIC POST
Posting a tweet with Twitter’s API

NETWORKING CODE DONE RIGHT

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'] 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 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 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

A RESTFUL SHELL (IN 90 LOC)

$ 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",…}, …}]

CURL-ISH REQUESTS
Fetching the latest tweet !om Twitter’s 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.\",…}]"

RESTFUL IRB
Interacting with the Twitter API

LOGGING IN RUBY

$ 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

GENERATING RUBY
Interactively building a RESTful Ruby script

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 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)

THE ARRAY-HASHWITH-DUPLICATES DATA THING

require "csv"

# using Ruby 1.9

data = <<END_DATA Console,Units Sold 2007,Percent,Units Sold 2008,Percent Wii,"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_DATA ps3 = CSV.parse(data, :headers => true, :header_converters => :symbol)[-1] ps3[0] ps3[:percent] ps3[:percent, 3] ps3[:percent, ps3.index(:units_sold_2008)] # # # # => => => => "PlayStation 3" "27.8%" "19.3%" "19.3%"

CSV::ROW
The various ways to refer to data

M17N IN ACTION

@io = @encoding =

if data.is_a? String then StringIO.new(data) else data end 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("\r") and not @io.eof? if sample =~ encode_re("\r\n?|\n") @row_sep = $& break end

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

BJ, SLAVE, AND TERMINATOR

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

HOW TO ASK YOUR CHILD TO KILL YOU

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

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

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

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

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 in there But it’s a big and complex beast Have a goal

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

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”

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()

QUESTIONS?
About code or other important topics…

You're Reading a Free Preview

Download
scribd
/*********** DO NOT ALTER ANYTHING BELOW THIS LINE ! ************/ var s_code=s.t();if(s_code)document.write(s_code)//-->