Created
July 10, 2011 18:11
-
-
Save JoshCheek/1074785 to your computer and use it in GitHub Desktop.
script for Pry session
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | |
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 ;)" | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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