Skip to content

Instantly share code, notes, and snippets.

@JoshCheek
Created July 10, 2011 18:11
Show Gist options
  • Save JoshCheek/1074785 to your computer and use it in GitHub Desktop.
Save JoshCheek/1074785 to your computer and use it in GitHub Desktop.
script for Pry session
Notation:
"This will be spoken"
`this will be entered at the terminal`
"`This will be spoken as it is entered`"
# this is a comment
* This indicates screen control, such as slide introduciton/transition switches to terminal, etc
------------------------------
# Don't forget simple prompt
# Figure out how to pronounce `sudo` (is it like "a doe, a deer, a female deer", or "Dammit, computer, just DO it?")
# Figure out how to pronounce "banisterfiend" ("banister" as in "hold onto the banister so you don't slip on the stairs"? "fiend" as in "Love coffee? I am a coffee FIEND!"?)
Introduction
"Hi, I'm Josh Cheek, this is a Code School screencast where we're going to cover the Pry REPL, by banisterfiend."
# Is this supposed to be a Code School screencast, or just a screencast?
# (What does it imply to associate it with Code School?)
* Terminal view
"First, some quick context, I'm using Ruby version 1.9.2"
`ruby -v`
"Pry version 0.9.2"
`pry -v`
"Gem version 1.8.5"
`gem -v`
"And to day is ..."
`date`
* Slide view
* Slide, words should highlight temporarily as they are read (acronym should be highlighted)
Read
Eval
Print
Loop
"Before we begin, lets make sure you know what a REPL is. It stands for
Read, Eval, Print, and then Loop."
* Terminal view
"We can create our own simple REPL with `ruby -e 'loop { p eval gets }'`"
"You can see that as I enter `1 + 1\n`, our REPL has read it in, evaluated it to 2,
and printed that result. Now the loop will cause it to repeat that until we `exit`"
"Ruby comes with a built in REPL called `irb`. Many Rubyists use irb to quickly
try out ideas or play with an object's API. But Pry offers significantly
more control and some powerful features that we'll cover in this screencast."
`exit`
Title of Contents
* Slide should highlight these as they are listed
1. Install
2. Features
3. As a debugger
4. Adding to Rails
5. Your turn
"So here's the gameplan, we're going to get Pry installed, check out why we should care,
use it as a debugger, and use it as our Rails console. Then I'll show you where you can
get more information and suggest some ways you can pry open your code."
Install
# don't forget to comment out --no-ri and --no-rdoc in .gemrc
# don't forget simple prompt
* Terminal view
"Pry is distributed as a gem, so we can just go to our terminal and `$ gem install pry pry-doc`"
Depending on your system, you may need to preface this with sudo"
# arrow showing where to put sudo
"The pry-doc will allow us to view documentation within Pry rather than having to look it up
at a website."
* Slide view (Table of Contents with Killer features highlighted)
Features
"All right, now we have it installed, lets take a look at some of my favourite features."
* Terminal view
`pry`
# some basic theory on commands and their syntax
"Pry has a special set of commands that give you access to the Pry functionality. You can see this
list by typing `help`. The commands are given in the same syntax you use at the shell, where whitespace
separates arguments and flags can be specified with leading dashes. If you want more information on
any of the commands, you can pass the -h flag. So if we wanted to see more information about the
gist-method command, we could type `gi<tab> -h` the tab autocompletes the command name, and the -h
is the flag that displays the help menu."
"Often times, the repl is where you try out an idea or familiarize yourself with an object or class.
In these cases, the documentation can be pretty handy."
`s = Pry`
# show-doc
`show-doc s.each_line`
"But Pry is pretty smart, it will let us use the ri syntax where we specify instance methods of
a class with the hash symbol. So we can get these same docs by checking out `show-doc String#each_line`
This is really handy when you don't have an instance you want to work with."
"So you can see s.each_line is the same as String#each_line" # highlight with mouse
# show-method
"But documentation isn't the only thing Pry lets us get at. We can see how those methods were
implemented with `show-method s.each_line`. Whoah! What's this? Pry can show us the code, even if
it's written in C! Another thing to notice is that Pry presents it to us in a pager, I can
use the arrows to scroll, the slash to search" #show search for pend
"and `q` to quit."
"That was pretty cool, I'd like to show it to my friend, but getting it out of the terminal will
probably be a hassle. Fortunately, we can make a gist out of it" `gist-method String#each_line`"
* Copy URL
* Browser view, show the method we just gisted
# If we're going to show rubinius support, this is probably where to do it, but IDK if it fits well.
# ls
"Now I like to use a gem called 'hello_world' when I want to test things"
`require "hello_world"`
"And it has a method that will say hello world. But I can never remember what it is."
"Pry gives us an ls command, which lists things like methods and variables. Lets see what kinds
of things we can list. The -m flag will let us see the methods that HelloWorld can invoke,
and since HelloWorld is a module, the methods defined within it become methods for instances of
classes that have it mixed in. We can see these instance methods with the -M flag, so lets try
`ls HelloWorld -M`" # => []
"Well I guess it wasn't an instance method, lets try methods on HelloWorld itself" `ls HelloWorld -m`
"Hmm, there's a lot of inherited spam in there, lets limit it to just singleton methods" `ls HelloWorld -jm`
"Aah, there it is" `HelloWorld.say_hello`
# cd
"Now having to keep specifying HelloWorld was kind of obnoxious. On the command line, we can cd into and
out of directories. And in Pry, we can cd into and out of objects. So we'll just `cd HelloWorld` and now
take a look, `self` is HelloWorld. Now when we `ls -jm`, we don't have to pass that extra argument around,
we can even `show-method say_hello`, and invoke it" `say_hello`
# ;
"Hmm, in that last example, we were interested in the text that the method sent to standard output, but
we also got nil, because that's what the method returned since that's what the puts returns. When you find
yourself in situations like that, you can suppress the output by adding a semicolon to the end of the line.
`say_hello;` That's better."
# gem-cd
"Another thing we could have done was just change directories to the gem's code and look at it directly.
Pry gives us that ability with `gem-cd helloworld`."
"And we can execute arbitrary commands at the shell by prepending a dot to our command."
`.tree`
"Well that's a pretty simple gem, lets `.cd lib` and `.cat *` and you can see the code that we
were just invoking"
# I know Pry provides a cat method, but don't think it's remarkable enough to introduce, esp since
# its main benefit seems to be allowing replaying of methods, but I'm not going to introduce the
# play command either.
# nesting
"Sometimes, while exploring, we may end up cding into several different objects."
`cd 12`
`cd String`
`cd Regexp`
"Notice my default prompt, updates to reflect the current object.
But we can also get a list by typing `nesting`."
"In the same way I can cd into an object, I can `cd ..` back out of it. Or `jump-to 0` the the I want to return to"
# !
"Every now and then, I fat finger something" `def helo(name)\n` "Whoops, should have had two 'l's
Well that's okay, this hasn't been evaluated yet, it's sitting in a buffer waiting for me to complete
the method. We can take a look at it with `show-input`, and clear it out with the `!`."
"Lets try again, `def hello(name)\n"Hello, #{name}"\n` *sigh* that finger is _really_ fat, lets just
fix it `show-input` by amending that line" `amend-line 1 def hello(name)` there we go. There's some
interesting features on this one, so if you find yourself doing this, be sure to use the -h flag to
see what all it can do.
I complete the method. But I can clear it out with the
`!` and try again "
* Slide view (Table of Contents)
As a debugger
"Now we've seen most of Pry's features, it can do some pretty powerful stuff. But Pry also has
the ability to be invoked at runtime, which allows it to act as a debugger."
"For example, sometimes you're working with code that is buried away somewhere, and you aren't
really sure how this code got invoked, or what was passed to it, or why it isn't working."
"This can be frustrating, because you want to fix it, but you just don't have easy enough
access to it to really tell what's even wrong with it."
"In this case, I am writing a simple Stack. Lets play with it in Pry."
`pry -r ./stack`
`stack = Stack.new`
"Now I have an each method, but can't remember how it works, lets check the docs" `show-doc stack.each`
"Okay, so we push some objects onto the stack, then we can iterate over them with each"
`
stack.push 5
stack.push "abc"
a = []
stack.each { |e| a << e }
`
"Uh oh, something isn't working right. Lets take a look" `cd stack` `show-method each`
"Looks fine to me, we need to get in there while its executing to see what the problem is."
"Pry knows where our methods come from, and it will allow us to edit them, and then it will
reload them when we're done." `edit-method each` "The best way to get at this is to
pry open the binding."
`binding.pry` # add on the first line of the loop
"In Ruby, you can always ask for a binding to a given scope, this will
give us access to all the variables and everything. If we weren't running this from the Pry
REPL itself, but maybe we were in a Sinatra application or something, we would have to
require Pry before we could do this."
# show what that would look like, then delete it
"Now we save and close it, and if we `show-method each` we see it has been updated. Lets try again"
`each { |elt| puts elt }`
"Now the execution of that method will halt until we're done looking around. Lets see what `crnt.data`
is, looks right to me. I think we're ready for the next iteration so we'll `cd ..` out of this object."
"Now it's invoked pry again on the second iteration, `crnt.data` looks fine to me still. If you ever
want to see where you are in the code, you can use `whereami`."
"Well, everything looks right, so lets go on to the next iteration `cd ..` And now it's been invoked
a third time. What do things look like this time?" `crnt.data` "Hmm, that shouldn't have happened,
what's `crnt`? Aah, it's nil. We never stopped iterating. Lets leave and go fix it."
`cd ..`
`edit-method each`
`
def each
crnt = @head
loop do
break unless crnt
yield crnt.data
crnt = crnt.next
end
end
`
"And now, `each { |e| puts e }` You can see we've fixed the method."
Adding to Rails
# `export USE_BUNDLER=false` before doing this so as to not confuse people with nuances of my env
"Now a lot of you work primarily with Rails, and your main use case for REPLs is the Rails console.
Fortunately it is really easy to add Pry to rails."
"As with all gems, we'll first need to add it as a dependency in our Gemfile"
* Editor view (Gemfile)
`gem "pry", :group => :development`
* Terminal view
`bundle install`
And install it.
"Then, in our development environment, we'll simply replace the constant IRB with the constant Pry!"
* Editor view (config/environments/development.rb)
`
silence_warnings do
begin
require 'pry'
IRB = Pry
rescue LoadError
end
end
`
* Terminal view
"And then we can `rails console` like normal!
and take a quick look around.
For example"
* Editor view (app/models/category.rb)
"Lets find out what that :dependent => :destroy does" # highlight it is spoken
* Terminal view
"Well change contexts into the Category with `cd Category`,
and we can list the methods"
`ls -m`
"and Instance methods"
`ls -M`
"But what we're really interested in is the instance variables"
`ls -i`
"See it there? It's in the `@_destroy_callbacks` instance variable which we can
see is just an array of callbacks that will be invoked when we destroy our Category"
Your turn
* Slide view:
*) Add pry to your app
*) Discover with Pry
*) Swat that bug!
"Now this information will never be as fresh in your mind as it is right now. So, don't
let that knowledge get away! Try adding pry to an application you work on. On a couple of
projects, I've set it up in a rake task to load my app like the Rails console."
"Another thing you could try is to discovering something interesting about Ruby or Rails or
whatever framework or library you're using to accomplish your tasks."
"Or maybe go and try to find that hard to solve bug that's been buzzing around your head lately!"
Conclusion
* Browser view with face at bottom right
"If you want more information, the Pry homepage is at 'pry.github.com', and as of right now,
I think that the wiki on their github page has some really spectacular documentation"
# navigate via the "fork me" link and then the "wiki" link
"There's also an irc channel in Freenode"
irc: irc://irc.freenode.net/pry
* Slide view (portrait slide)
"Okay, so we're finally done! Thanks for sticking with me! Now go do something productive like,
I don't know, maybe installing Pry or something ;)"
class Stack
Node = Struct.new :data, :next
def push(data)
@head = Node.new data, @head
end
def pop
return unless @head
data = @head.data
@head = @head.next
data
end
##
# Iterates across the stack
#
# stack = Stack.new
# stack.push 5
# stack.push "abc"
# array = []
# stack.each { |element| array << element }
# array # => ["abc", 5]
def each
crnt = @head
loop do
yield crnt.data
crnt = crnt.next
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment