Those of you who are still following my "morning posts" know I've been actively focused on testing out, commenting on, and reviewing the entire process of "Learn Ruby the Hard Way". For those of you who have decided to just avoid my feed in the mornings and focusing on my afternoon posts, that's fine, but I'm going to talk about about it here, too. Not the Practicum, but the overall concept, and the site behind it.
I first heard about "The Hard Way" because of a book called "Learn Python the Hard Way", written by Zed Shaw. It was introduced to me by a developer I worked with when I was at Tracker (the company I was at prior to SideReel). We were talking about learning how to code, and I voiced my frustration at the fact that most books skimmed the surface ideas, and offered very little to those of us trying to make the jump from having a superficial knowledge and understanding of a programming language and actually getting proficient in using it. He said "Then you should totally check out this book. It does exactly what you want, as it walks you through a lot of exercises and then has you struggle with the extra ideas to work on. Oh, and he says you're not allowed to copy and paste. You have to actually type everything in!"
I downloaded the book PDF, skimmed it, thought it looked promising... and then forgot about it. Why? While the idea was interesting, I really didn't have a need, or time, to work with Python at that given point. Tracker's a .NET shop, so I spent my time focusing on reading about and monkeying around with C#, but again, just on the periphery, nothing in depth.
Fast forward to 2011. I now work in a Rails shop, where Ruby is the Lingua Franca of the business, as well as all of the additional add-ons that are used to add functionality to an enterprise level Rails site. I'm actively involved in working with Cucumber, Rspec and Ruby as a testing framework. A lot of the framework I've been able to figure out by trial and error, but this time, I decided it would make a lot more sense to just get some in-depth Ruby knowledge, so that I can better communicate with the development team, and also make my own tests perhaps more extensible and add some of my own logic to the mix.
That's when I thought "ah, if only there were a Hard Way book for Ruby. Wouldn't that be cool?" For grins one day I typed in "Learn Ruby the Hard Way" in Google, just to see if there was some kind of discussion board about it. Imagine my surprise and delight (OK, that's pushing it, but will you accept amused interest :)?) to discover that, indeed, there was a "Learn Ruby the Hard Way", and that it was structured nearly exactly along the lines of the original Python book. What's more, that this process was being applied to a number of different languages and concepts, and there's a site dedicated to this process called "Learn Code the Hard Way". The Python book is the most famous, and the Ruby book looks like it will follow suit. Zed is also working on developing three additional books. First is a project to do the same for the C programming language (called, appropriately enough, Learn C the Hard Way), a project for SQL, and a project for Regex. Zed also welcomes those that want to help the project along, so go check out the page and see if you would like to contribute (I'm guessing he might appreciate some testers checking out the site, too :) ). Is there a programming language you'd like to see listed. Suggest it, or better yet, if you have experience and are willing to contribute, why not help write one yourself?
As you might guess, I am finding this site and this approach valuable. testers, you might find it valuable as well. Even if you don't need to use Ruby or Python or C, you may well need to interact with SQL and I'd think understanding Regex would be a valuable skill for any tester that has to write scripts of any kind, even if it's just shell scripts (and know I'm saying that rather tongue in cheek; I'm very aware of just how much power and the full linguistic capability of the shell there is). In short, this is a site I think anyone interested in the inner workings of code should consider spending some time with.
Wednesday, November 16, 2011
Exercise 19: Functions And Variables: Learn Ruby The Hard Way: Practicum
So, yeah, how did that last chapter feel? A bit heavy? I've found it best to sort of think of functions like my old guitar pedals. The sound from your guitar goes in, the pedal does some fun stuff, and what comes out and heads to your amp is juiced and interesting (I'm adding that for Zed's benefit, since I know he's a guitar player ;) ).
Each function works its own set of magic on what comes in, and makes for a unique different thing that comes out (i.e. what goes on inside of the functions themselves have no bearing on what other functions do. A good thing to keep in mind).
Speaking of keeping that in mind, here's an example of how what I just said up above works.
The key point here is that we can pass just about anything to our script as parameters. Straight numbers. variables, math values, variables and math values combined. The idea is, if we can assign it to a variable, we can probably pass it as a parameter to a function.
What You Should See
$ ruby ex19.rb
We can just give the function numbers directly:
You have 20 cheeses!
You have 30 boxes of crackers!
Man that's enough for a party!
Get a blanket.
OR, we can use variables from our script:
You have 10 cheeses!
You have 50 boxes of crackers!
Man that's enough for a party!
Get a blanket.
We can even do math inside too:
You have 30 cheeses!
You have 11 boxes of crackers!
Man that's enough for a party!
Get a blanket.
And we can combine the two, variables and math:
You have 110 cheeses!
You have 1050 boxes of crackers!
Man that's enough for a party!
Get a blanket.
$
Extra Credit:
- Go back through the script and type a comment above each line explaining in English what it does.
- Start at the bottom and read each line backwards, saying all the important characters.
[I'll leave that to the reader, but suffice it to say that the comments and this exercise will help you see why what goes where (say that ten times fast ;) ]
- Write at least one more function of your own design, and run it 10 different ways.
TESTHEAD's Takeaways:
Functions can take lots of values as the parameters, the point that anything that can be assigned as a variable can be entered as a parameter looks to hold true. we can do lots of math operations if we want to as well, and we can even do type conversion (I looked up how to convert integers to floating point numbers so that we could get realistic numbers for percentages, and yes, we have a rounding error since I limited it to 2 significant digits, but you get the point :) ).
Tuesday, November 15, 2011
Come Join Us For a "Testing Vacation"
Yeah, I know what you are thinking. Sorry, I can't offer anything that cool (LOL!).
For those who will be participating in our Weekend Testing session this coming Saturday, we will be working with a concept developed bye Elizabeth Hendrickson for her Agilistry classes, and evangelized by Jonathan Bach, called "Testing Vacations". Before you think of a trip to Cozumel to examine and comment on SCUBA gear, this is actually an extension of "test tours" and fits in well with the context-driven approach to software testing.
So what, pray tell, is a testing vacation? It's a short, focused goal that you can approach and that, when performed, can help you ask a product interesting questions. Since Jon works at eBay, he used eBay as the idea for this concept and using their search functionality for this. While it may seem like the ideas are specific to eBay, a little bit of tweaking and they will work with any site. Here are some eBay specific examples:
Does this approach sound interesting to you? If so, then please come out this Saturday and join us. How do you do that? Simple.
Weekend Testing – Americas Chapter Session No. 22
Session type: Testing Vacations.
Date: Saturday, November 19, 2011
Note the session time!
Time: 11:00 a.m. – 1:00 p.m. PST. Check in your time zone.
http://timeanddate.com/worldclock/fixedtime.html?msg=WTA22&iso=20111119T12&p1=250&ah=2
To join this session, please do the following:
1. Add “weekendtestersamericas” to your Skype contacts if you haven’t already.
2. Fifteen minutes prior to the start of the session, please message “weekendtestingamericas” and ask to be added to the chat session. Once we see you, we will add you to the session.
For more details, contact WTAmericas@gmail.com
For those who will be participating in our Weekend Testing session this coming Saturday, we will be working with a concept developed bye Elizabeth Hendrickson for her Agilistry classes, and evangelized by Jonathan Bach, called "Testing Vacations". Before you think of a trip to Cozumel to examine and comment on SCUBA gear, this is actually an extension of "test tours" and fits in well with the context-driven approach to software testing.
So what, pray tell, is a testing vacation? It's a short, focused goal that you can approach and that, when performed, can help you ask a product interesting questions. Since Jon works at eBay, he used eBay as the idea for this concept and using their search functionality for this. While it may seem like the ideas are specific to eBay, a little bit of tweaking and they will work with any site. Here are some eBay specific examples:
- Try a search on ebay.com and then try the same on your mobile. Any major differences that you can see?
- What is the most expensive Buy It Now item for sale nearest to your location?
- What was the highest bid for an item in support of any charity?
- Which category has the most items?
- Which queries yield no results?
- What item appears most with no bids?
- What is the most popular (trending) item for sale?
- What is the most bizarre item?
- What is the most expensive item for sale?
- What item has been on eBay the longest? Is there a way to tell the age of the item ID?
Does this approach sound interesting to you? If so, then please come out this Saturday and join us. How do you do that? Simple.
Weekend Testing – Americas Chapter Session No. 22
Session type: Testing Vacations.
Date: Saturday, November 19, 2011
Note the session time!
Time: 11:00 a.m. – 1:00 p.m. PST. Check in your time zone.
http://timeanddate.com/worldclock/fixedtime.html?msg=WTA22&iso=20111119T12&p1=250&ah=2
To join this session, please do the following:
1. Add “weekendtestersamericas” to your Skype contacts if you haven’t already.
2. Fifteen minutes prior to the start of the session, please message “weekendtestingamericas” and ask to be added to the chat session. Once we see you, we will add you to the session.
For more details, contact WTAmericas@gmail.com
Exercise 18: Names, Variables, Code, Functions: Learn Ruby The Hard Way: Practicum
Big title, big topic. In most actual implementations of software, there's only so much code that you will be able to use from the base library or the built in functionality. Most, if not all, programming languages are designed to be extensible. What that means is that, if you want to represent things in simpler ways, you move functionality from your main script over to other files or libraries so that they can be references and so that they can be called.
These are called lots of different things in different languages (Procedures, methods, calls, etc.) but I personally like and think the word "function" works the best, and heh, it seems Zed and Rob do, too :).
Functions do three things:
1. They name pieces of code the way variables name strings and numbers.
2. They take arguments the way your scripts take ARGV.
3. Using #1 and #2 they let you make your own "mini scripts" or "tiny commands".
Functions are defined in Ruby by using the word "def" (which stands for define, conveniently enough :) ). Our exercise today has to do with four functions we will create and then call in turn.
So those are four ways of handling functions, and each does it just a little bit differently.
The first function, puts_two, is structured a lot like how we handle a script that takes parameters from the command line (remember ARGV?). In Ruby function calls, though, we can't use ARGV (why? because it's already used by our main script). Thus, if we want to define any input that comes in as parameters to our function, we can say "*args" and it means thew same thing; any input into the function will be parsed as a separate parameter. The name of the function doesn't matter, as long as it is meaningful enough to us to remember it or be able to call it easily (me personally, I am all about descriptive function names, as close to their actual use as possible. Self commenting code and all that).Once we define the function, give it a name, and declare how it handles arguments, we then structure the code inside the function to do what we want to have it do. In this case, we unpack the *args, put them into two variables (or how many we want to declare), and then print them out. The word "end", as it implies, ends our function.
Now, unlike the command line where we would potentially be giving variable amounts of data and dealing with it, in our scripts themselves, it's unlikely that we will have a need for wildly varying argument values. In fact, it's much more likely we will have exactly the parameters we want to work with. With Ruby functions (and many other languages) the whole unpacking step can be skipped. By defining the args during the definition and putting them inside the (). print_two_again does exactly this.
puts_one is an example of a function that takes a single argument, while puts_none shows what happens when you call a function directly, i.e. without any arguments to pass to it.
What You Should See
If you run the above script you should see:
$ ruby ex18.rb
arg1: 'Zed', arg2: 'Shaw'
arg1: 'Zed', arg2: 'Shaw'
arg1: 'First!'
I got nothin'.
$
So does some of this look familiar? It should, most of the commands we have been running in our scripts, especially any that have parentheses () are functions. We just didn't realize it. This means you have the ability to make your own commands, and call them what you want to call them. If you'd like to make equations that you can solve, you can feed the parameters into a function, and then have the operations performed and an answer returned to you (in fact, that's exactly how mathematical functions work, too).
Extra Credit
Write out a function checklist for later exercises. Write these on an index card and keep it by you while you complete the rest of these exercises or until you feel you do not need it:
Index Card #1: Defining and Creating "Functions" in Ruby
- Did you start your function definition with def?
- Does your function name have only characters and _ (underscore) characters?
- Did you put an open parenthesis ( right after the function name?
- Did you put your arguments after the parenthesis ( separated by commas?
- Did you make each argument unique (meaning no duplicated names).
- Did you put a close parenthesis ) after the arguments?
- Did you indent all lines of code you want in the function 2 spaces?
- Did you close your function body by typing "end"?
- And when you run (aka "use" or "call") a function, check these things:
Index Card #2: Calling and Running "Functions" in Ruby
- Did you call/use/run this function by typing its name?
- Did you put ( character after the name to run it? (this isn't required, but is idiomatic)
- Did you put the values you want into the parenthesis separated by commas?
- Did you end the function call with a ) character.
- Use these two checklists on the remaining lessons until you do not need them anymore.
Repeat this a few times:
"To 'run', 'call', or 'use' a function all mean the same thing."
And one more thing... it's a good bet that most of the people that program in Ruby will not call these functions. They will call them "methods". What you ultimately call them will depend a lot on who you work with. Just note that when someone you work with refers to a "method" or a "function", most of the time they are talking about the same thing.
Monday, November 14, 2011
A Year of Weekend Testing in the Americas
I was looking for a cute way of putting this but figured I'd just put it out there. Yesterday marked the first anniversary of the first session of Weekend Testing Americas. I didn't realize that until today, since I'd posted the experience report on November 14th, 2010, which was one year ago today. So in either case, this grand experiment of Weekend Testing in the Western Hemisphere has survived and thrived during its first year.
It's been fun to reminisce on the past year. The first session where so many people came and trying to get any traction was like herding cats (and my apologies to all of the folks who couldn't download the app in time to participate in the session. Growing pains and all that. We learned). Testing RapidReporter and getting intimately familiar with all of its features. Digging into corkboard.me. Playing Lightbot and finding out how it might help develop programming skills. Working with Volunteermatch and helping them meet a release deadline. Checking our RescueTime and seeing a holy war erupt (LOL!).
The most valuable lesson and memory of all? You don't have to ask permission to do something that could reshape the way you see yourself and the world. All you need is a few willing souls to step in and make things happen. So on this momentous day, I'd like to say thanks to Joe Harter and Lynn McKee for helping me get the ball rolling, Ajay Balamurugadas and Santhosh Tuppad for helping us with our early baby steps and getting this little enterprise off the ground, and definitely Albert Gareev for his tireless enthusiasm and encouragement for ideas, projects, and different challenges we've been able to construct over the past year. I also want to say thanks to Michael Bolton, James Bach and Jonathan Bach for their willingness to be guest presenters for WTA and to help us improve our game over the past year. Most of all, we want to say thank you to the people who really make Weekend Testing Americas work, and that's the attendees. There is a regular cadre of participants that are frequently there, actively engaged, and enthusiastic about helping us improve the craft of software testing. This year would have looked a lot different if it weren't for all of you.
As we look back at the year that was, we'd like to invite you all to come out and join us for the beginning of the new year that will be. How do you do that? Come and join us this coming Saturday, November 19, 2012 at 11:00 AM Pacific (2:00 PM Eastern) for our next session. Details for the session will follow shortly, so stay tuned :).
It's been fun to reminisce on the past year. The first session where so many people came and trying to get any traction was like herding cats (and my apologies to all of the folks who couldn't download the app in time to participate in the session. Growing pains and all that. We learned). Testing RapidReporter and getting intimately familiar with all of its features. Digging into corkboard.me. Playing Lightbot and finding out how it might help develop programming skills. Working with Volunteermatch and helping them meet a release deadline. Checking our RescueTime and seeing a holy war erupt (LOL!).
The most valuable lesson and memory of all? You don't have to ask permission to do something that could reshape the way you see yourself and the world. All you need is a few willing souls to step in and make things happen. So on this momentous day, I'd like to say thanks to Joe Harter and Lynn McKee for helping me get the ball rolling, Ajay Balamurugadas and Santhosh Tuppad for helping us with our early baby steps and getting this little enterprise off the ground, and definitely Albert Gareev for his tireless enthusiasm and encouragement for ideas, projects, and different challenges we've been able to construct over the past year. I also want to say thanks to Michael Bolton, James Bach and Jonathan Bach for their willingness to be guest presenters for WTA and to help us improve our game over the past year. Most of all, we want to say thank you to the people who really make Weekend Testing Americas work, and that's the attendees. There is a regular cadre of participants that are frequently there, actively engaged, and enthusiastic about helping us improve the craft of software testing. This year would have looked a lot different if it weren't for all of you.
As we look back at the year that was, we'd like to invite you all to come out and join us for the beginning of the new year that will be. How do you do that? Come and join us this coming Saturday, November 19, 2012 at 11:00 AM Pacific (2:00 PM Eastern) for our next session. Details for the session will follow shortly, so stay tuned :).
Exercise 17: More Files: Learn Ruby The Hard Way: Practicum
So far, we've opened files, we read files, and we've written to files. Now we're going to copy files from one place to another. Are you ready?
Some interesting new stuff this time around. Notice that there is a method called File.exists? I've see this in a lot of code fragments, so I'm going to guess it's somewhat important. It, of course, looks to see if the file is actually there. We are also seeing the ability to get data about a variable and use it inside of the string interpolation/variable substitution areas.
What You Should See
$ ruby ex17.rb test.txt copied.txt
Copying from test.txt to copied.txt
The input file is 81 bytes long
Does the output file exist? False
Ready, hit RETURN to continue, CTRL-C to abort.
Alright, all done.
$ cat copied.txt
To all the people out there.
I say I don't like my hair.
I need to shave it off.
$
Extra Credit
Go read up on Ruby's require statement, and start Ruby to try it out. Try importing some things and see if you can get it right. It's alright if you do not.
[Played with some sample here: http://ruby.about.com/od/rubyfeatures/a/require.htm ]
This script is really annoying. There's no need to ask you before doing the copy, and it prints too much out to the screen. Try to make it more friendly to use by removing features.
See how short you can make the script. I could make this 1 line long.
Notice at the end of the WYSS I used something called cat? It's an old command that "con*cat*enates" files together, but mostly it's just an easy way to print a file to the screen. Type man cat to read about it.
[As an old UNIX hand, I used cat lots in the 90's. It's been interesting to get back onto a UNIX like system again after a decade of working in Windows shops. It's also interesting to see how many flags cat has, and how many I have never used: http://unixhelp.ed.ac.uk/CGI/man-cgi?cat]
Windows people, find the alternative to cat that Linux/OSX people have. Do not worry about man since there is nothing like that.
[The type command lets us do this. It meets the same need.]
Find out why you had to do output.close() in the code.
[Leaving the file open in too many iterations can lead to memory leaks and too many open files pointers. At least that's how things worked in the old school C days. Ruby may be able to handle this better, but it's still good practice to close the files ].
TESTHEAD's TAKEAWAYS:
So there's a few neat things we are seeing in this example. The first is that the file manipulation commands are fairly straightforward. the second is the fact that we can use attributes of variables to appear in string interpolation commands. we also see that some good practices from earlier languages are still followed in Ruby, if for no other reason than to help us be consistent (I may go back and focus on C again after many years, and it helps to use the same habits in these languages for opening and closing files, even if the language and system doesn't specifically require it).
Sunday, November 13, 2011
Exercise 16: Reading And Writing Files: Learn Ruby The Hard Way: Practicum
One of the cool things about visiting the LCtHW site is that you can see the changes Zed is implementing and when stuff gets updated. What stuff would that be? Well, would you be interested in a PDF version of the book that you can have offline? If so, it's available for $2.99. Link is here.
So I did do the extra credit from the last assignment, but I am having difficulty with the ri command. It'll be a project for today to figure out why I'm having trouble with it and see if I can fix it on both my Mac and my PC. Fortunately, Zed doesn't leave us in the dark on this but explains the values we need to know about. Also, I'm being a bit remiss here. I keep saying Zed did all of this, when the Ruby translation of this book owes a lot to the guy that did the conversion, Rob Sobers. Still, Zed did the original book for Python, and since this is based on that, I think it's fair to say it's still Zed asking us to focus our attention, but I want to give Rob some props, too.
So the file commands that are the most important for us to remember are as follow:
So let's take a look at how this works:
This is the longest file we've had to type so far, and here's a piece of interesting news... this didn't work on my Mac, which is running with Ruby 1.8 for work reasons. It only works on my PC, which is running Ruby 1.9.2. What's the difference? It appears that the size parameter isn't available in Ruby 1.8.7, which is what's running on my Mac.
What You Should See
There are actually two things you will see, first the output of your new script:
$ ruby ex16.rb test.txt
We're going to erase 'test.txt'.
If you don't want that, hit CTRL-C (^C).
If you do want that, hit RETURN.
?
Opening the file...
Truncating the file. Goodbye!
Now I'm going to ask you for three lines.
line 1: To all the people out there.
line 2: I say I don't like my hair.
line 3: I need to shave it off.
I'm going to write these to the file.
And finally, we close it.
$
Now, open up the file you made (in my case test.txt) in your editor and check it out. Neat right?
Extra Credit
If you feel you do not understand this, go back through and use the comment trick to get it squared away in your mind. One simple English comment above each line will help you understand, or at least let you know what you need to research more.
Write a script similar to the last exercise that uses read and argv to read the file you just created.
There's too much repetition in this file. Use strings, formats, and escapes to print out line1, line2, and line3 with just one target.write() command instead of 6.
Find out why we had to pass a 'w' as an extra parameter to open. Hint: open tries to be safe by making you explicitly say you want to write a file.
[By us asking to write a file, it in addition to making sure we are writing to the file also physically creates the file in the same step]
If you open the file with 'w' mode, then do you really need the target.truncate()? Go read the docs for Ruby's File.open function and see if that's true.
[I commented out the option for target truncate, and the script worked the same. So no, it is not necessary to run the truncate command if we open the file with 'w' access. The danger of course is that we will wipe out whatever is in there, which might not be our goal. Here's where it pays to make sure :). ]
TESTHEAD's TAKEAWAYS
So we are now able to not just read files, but we have methods to write to them, too. we're still limited in that anything we write will clobber anything we wrote previously. we will need top have some methods to append text if keeping files are important (I can only assume that that is coming, but hey, the fact I'm asking about it means I'm already mentally focused on it, so I should be ready to tackle it when it come our way :) ).
So I did do the extra credit from the last assignment, but I am having difficulty with the ri command. It'll be a project for today to figure out why I'm having trouble with it and see if I can fix it on both my Mac and my PC. Fortunately, Zed doesn't leave us in the dark on this but explains the values we need to know about. Also, I'm being a bit remiss here. I keep saying Zed did all of this, when the Ruby translation of this book owes a lot to the guy that did the conversion, Rob Sobers. Still, Zed did the original book for Python, and since this is based on that, I think it's fair to say it's still Zed asking us to focus our attention, but I want to give Rob some props, too.
So the file commands that are the most important for us to remember are as follow:
- close -- Closes the file. Like File->Save.. in your editor.
- read -- Reads the contents of the file, you can assign the result to a variable.
- readline -- Reads just one line of a text file.
- truncate -- Empties the file, watch out if you care about the file.
- write(stuff) -- Writes stuff to the file.
So let's take a look at how this works:
This is the longest file we've had to type so far, and here's a piece of interesting news... this didn't work on my Mac, which is running with Ruby 1.8 for work reasons. It only works on my PC, which is running Ruby 1.9.2. What's the difference? It appears that the size parameter isn't available in Ruby 1.8.7, which is what's running on my Mac.
There are actually two things you will see, first the output of your new script:
$ ruby ex16.rb test.txt
We're going to erase 'test.txt'.
If you don't want that, hit CTRL-C (^C).
If you do want that, hit RETURN.
?
Opening the file...
Truncating the file. Goodbye!
Now I'm going to ask you for three lines.
line 1: To all the people out there.
line 2: I say I don't like my hair.
line 3: I need to shave it off.
I'm going to write these to the file.
And finally, we close it.
$
Now, open up the file you made (in my case test.txt) in your editor and check it out. Neat right?
Extra Credit
If you feel you do not understand this, go back through and use the comment trick to get it squared away in your mind. One simple English comment above each line will help you understand, or at least let you know what you need to research more.
Write a script similar to the last exercise that uses read and argv to read the file you just created.
There's too much repetition in this file. Use strings, formats, and escapes to print out line1, line2, and line3 with just one target.write() command instead of 6.
Find out why we had to pass a 'w' as an extra parameter to open. Hint: open tries to be safe by making you explicitly say you want to write a file.
[By us asking to write a file, it in addition to making sure we are writing to the file also physically creates the file in the same step]
If you open the file with 'w' mode, then do you really need the target.truncate()? Go read the docs for Ruby's File.open function and see if that's true.
[I commented out the option for target truncate, and the script worked the same. So no, it is not necessary to run the truncate command if we open the file with 'w' access. The danger of course is that we will wipe out whatever is in there, which might not be our goal. Here's where it pays to make sure :). ]
TESTHEAD's TAKEAWAYS
So we are now able to not just read files, but we have methods to write to them, too. we're still limited in that anything we write will clobber anything we wrote previously. we will need top have some methods to append text if keeping files are important (I can only assume that that is coming, but hey, the fact I'm asking about it means I'm already mentally focused on it, so I should be ready to tackle it when it come our way :) ).
Saturday, November 12, 2011
Exercise 15: Reading Files: Learn Ruby The Hard Way: Practicum
So this time we are getting into something that has some meat to it. All of that ARGV and STDIN.gets had a specific purpose. Yes, being able to enter things from the command line are helpful. Interactively typing stuff in for a script is also kind of helpful. By far, though, the most beneficial thing that this offers is the ability to interact with external files; to open them, to read them, to change them, and to use them.
Since we are actually opening and editing files, we have the ability to do some, well, direct and deliberate things to the system, some of which could be dangerous if we are not careful (losing work in simplest case, erasing systems in the worst case). Thus, we need to be careful and pay attention to what we are doing.
We'll be working with two different files. One is our ruby script (ex15.rb) and the other is named ex15_sample.txt. This second file is just a plain text file that we will read into our ruby script.
Here are the contents of ex15_sample.txt file:
This is stuff I typed into a file.
It is really cool stuff.
Lots and lots of fun to have in here.
Yep, that's it. A little anti-climactic, maybe, but it'll do :).
So our goal is to open the file in our script and print it out. We don't want to "hard code" the name of the file, though. We want to read it from the command line. That way we can read in other files later. ARGV and STDIN.gets let us dynamically add the file we want to use.
OK, there's a bunch of new things going on in here.
Line 4 is the first use of the File object where we use a new command File.open. File.open allows the user to, well, open a file.
Line 7 does something interesting and something we haven't done before. We are making an object of txt and calling the file.open option but using the txt label instead.
What You Should See
$ ruby ex15.rb ex15_sample.txt
Here's your file 'ex15_sample.txt':
This is stuff I typed into a file.
It is really cool stuff.
Lots and lots of fun to have in here.
Type the filename again:
> ex15_sample.txt
This is stuff I typed into a file.
It is really cool stuff.
Lots and lots of fun to have in here.
$
Extra Credit:
This is a big jump so be sure you do this extra credit as best you can before moving on.
Above each line write out in English what that line does.
If you are not sure ask someone for help or search online. Many times searching for "ruby THING" will find answers for what that THING does in Ruby. Try searching for "ruby file.open".
[here's a cool example: http://snippets.dzone.com/posts/show/5051]
I used the name "commands" here, but they are also called "functions" and "methods". Search around online to see what other people do to define these. Do not worry if they confuse you. It's normal for a programmer to confuse you with their vast extensive knowledge.
[ These come in different flavors depending on who is writing. I've seen functions, procedured, calls, objects, methods, etc. but I get the idea. The point is that we can create certain items and by adding a dot to them we can string commands and possible parameters based on what the parent command allows. The fact that they can also be named as variables or objects is both clarifying and confusing, but stepping back, it makes sense if you are doing something that involves many files or items. Naming them uniquely helps clarify which item is doing what.]
Get rid of the part from line 9-15 where you use STDIN.gets and try the script then.
Use only STDIN.gets and try the script that way. Think of why one way of getting the filename would be better than another.
[While being able to enter the value in the script would be a positive, you would have to be there to enter the name. by adding it on the command line, you can remove the human from the immediate process. this makes it possible to automate the procedure and put it into a script if desired, and it could be run 10,000 times without a person having to enter the file name. those same 10,000 script runs would have to have a human enter the filename each time]
Run ri File and scroll down until you see the read() command (method/function). See all the other ones you can use? Try some of the other commands.
[Well now, this is odd. Maybe it's a limitation to the PC version, but "ri File" only shows me the following:
C:\Users\Michael\LRtHW\Ex15>ri File
←[0m←[1;32mFile < Object←[m
(from gem activesupport-3.0.3)
------------------------------------------------------------------------------
←[1;32mClass methods:←[m
atomic_write
------------------------------------------------------------------------------
Also found in:
gem bundler-1.0.7
gem thor-0.14.6
and that's it. On my Mac, I got "Nothing known about File".
]
Startup IRB again and use File.open from the prompt. Notice how you can open files and run read on them right there?
Have your script also do a close() on the txt and txt_again variables. It's important to close files when you are done with them.
TESTHEAD's TAKEAWAYS:
So we have made a big jump here. It may not seem like much, but we have now opened up our scripts to the ability of interacting with files, both to read from them and, later, to write to them (come on, you saw that coming, I'm sure ;) ). Having this ability means we can do things with our scripts that can be "hands off" from a human perspective. It also means that we can "pipeline" commands to our scripts via UNIX commands if we want to (granted, right now we're limited to filenames, but the whole point of having ARGV in the first place is to feed variables to the script from the command line, or other scripts). This is helping move us along to scripts that can prove to be very useful.
Friday, November 11, 2011
Moving Forward By Letting Go
Yesterday's post about how I spend my time actually came at an interesting juncture. As I'd said yesterday, to agree to do something, you have to be willing to not do something else. When Matt and I were sitting in the AST board meeting and the discussions about the Education SIG were happening, as I threw my hat in the ring to take on that responsibility, we both knew I'd have to free up bandwidth to do it.
Over the past fifteen months, I've edited 65 shows, plus several extra spots and other details that have helped to shape "This Week in Software Testing" into the format that it is today. By far the most time consuming aspect is the ongoing editing of the audio. Well, with next week's episode, I'm officially handing over a good chunk of the audio editing piece to Rick Baucom.
It's funny, this should be something that I should be totally happy to stop doing; it's not like I'm not going to be doing production for the show still (I'm going to be constructing the bumpers still and the final deliverable, at least for the foreseeable future, though it's possible I may pass that off too at some point). Still, part of me is resisting handing this off.
I think the reason is that, when we spend the time doing something, especially for a regular deliverable, we develop a lot of domain specific knowledge, and we just plain get good at doing it. When we feel we are good at doing something, we develop a bit of a pride in doing it. Anything that's truly onerous we should be happy to be rid of. In this case, while it was time consuming and meticulous stuff, I greatly enjoyed, and enjoy, doing it.
Having said that, I also know that I will have to, in due time, make commitments to focus on other areas, areas that will give me less time to do the day to day audio editing. I have help, and I'm grateful for it, but now I have to ask myself "am I willing to turn over the authority for doing something I've done for what seems like so long?" In all honestly, part of me isn't. What if the results are not the same as if I'd done them? Well, that's a risk... but so what? Do I have any belief that the podcast will suffer because of it. Well, it may. Or it may not. Fact is, I won't know until I let someone else try. They won't do things my way. They won't have my system down. They won't know the tricks I use to make things work the way that I do. And that's OK. They'll figure out their own ways of doing things. It may even (gasp!) change the flavor of the show, or they may discover some techniques or have access to gear that I don't, and that may even make the overall sound of the show even better, and frankly, that's cool, too.
The simple fact is, it's not my show. I don't own it. STP owns it, and from there, Matt owns it if any single person can say they do. I enjoy working on it, and I will stay connected to it as producer, but the daily engineering will go to someone else, and they'll make their own magic work. And it will be cool, it will be relevant, and it will be "the best software testing podcast... by some definition of best" :).
Here's to future days.
Exercise 14: Prompting And Passing: Learn Ruby The Hard Way: Practicum
So as I mentioned yesterday, I wasn't sure how to get gets.chomp() and ARGV to play together. When in doubt, check ahead and you might find an answer. Well, that's what I did and I found out something cool.
This example shows ways to isolate and focus on individual variables, as well as how to get gets.chomp() to play nice within a script that uses ARGV.
This script also prints a simple prompt to use in the script. The example is similar to a text based game (Zork or Adventure, anyone :)?). Also, I'm starting to get some strange issues with publishing my blog entries now because of the Ruby code interfering with Blogger's interface, so I'm going to copy the actual code details into image form (lets see if that resolves it).
OK, first thing (notice this from yesterday?), here's a change-up. gets.chomp() is represented as STDIN.gets.chomp(). Why? Because ARGV is being used. the default gets method will look in ARGV and try to read from the first variable. getting input straight from the keyboard (user input) is referred to in computer parlance as STDIN. So to read the users input, when ARGV is used, STDIN.gets is used. Cool, huh :)?
[here's what I wrote]
What You Should See
When you run this, remember that you have to give the script your name for the ARGV arguments.
[and here's what I get]
Extra Credit
Find out what Zork and Adventure were. Try to find a copy and play it.
[
Zork: http://pot.home.xs4all.nl/infocom/zork1.html
Adventure: http://www.wesleyholland.com/misc/adventure/adventure.html
]
Change the prompt variable to something else entirely.
[ prompt = "#{$0} >> " . Note this is performing string interpolation in the prompt. I don't k now why I'm mentioning it, I just think saying "string interpolation" is fun, really :) ]
Add another argument and use it in your script.
[Since I'm not sure how to enumerate the ARGV vartiable beyond the ARGV.first option given as an example, I've played coy and figured that if an array begins, it has to end, so I entered ARGV.last as an option (note, it's coincidence that firstname corresponds to first and lastname corresponds to last, but that's not what they represent. They represent the first argument in the array and the final argument in the array]
[I get that string interpolation can take place with this example and within this format of multi-line printing, and that's pretty cool :) ].
TESTHEAD's TAKEAWAYS:
Wow, I haven't see or heard about a text based adventure game since I was a kid in the late 70s or early 80s. That brings back memories. It also reminds me how cool the programming behind some simple question and answers could totaly suck you in. It was neat to see a reminder to how this was done, as well as to experiment with pulling in variables from the command line and within a script.
This example shows ways to isolate and focus on individual variables, as well as how to get gets.chomp() to play nice within a script that uses ARGV.
This script also prints a simple prompt to use in the script. The example is similar to a text based game (Zork or Adventure, anyone :)?). Also, I'm starting to get some strange issues with publishing my blog entries now because of the Ruby code interfering with Blogger's interface, so I'm going to copy the actual code details into image form (lets see if that resolves it).
OK, first thing (notice this from yesterday?), here's a change-up. gets.chomp() is represented as STDIN.gets.chomp(). Why? Because ARGV is being used. the default gets method will look in ARGV and try to read from the first variable. getting input straight from the keyboard (user input) is referred to in computer parlance as STDIN. So to read the users input, when ARGV is used, STDIN.gets is used. Cool, huh :)?
[here's what I wrote]
What You Should See
When you run this, remember that you have to give the script your name for the ARGV arguments.
[and here's what I get]
Extra Credit
Find out what Zork and Adventure were. Try to find a copy and play it.
[
Zork: http://pot.home.xs4all.nl/infocom/zork1.html
Adventure: http://www.wesleyholland.com/misc/adventure/adventure.html
]
Change the prompt variable to something else entirely.
[ prompt = "#{$0} >> " . Note this is performing string interpolation in the prompt. I don't k now why I'm mentioning it, I just think saying "string interpolation" is fun, really :) ]
Add another argument and use it in your script.
[Since I'm not sure how to enumerate the ARGV vartiable beyond the ARGV.first option given as an example, I've played coy and figured that if an array begins, it has to end, so I entered ARGV.last as an option (note, it's coincidence that firstname corresponds to first and lastname corresponds to last, but that's not what they represent. They represent the first argument in the array and the final argument in the array]
TESTHEAD's TAKEAWAYS:
Wow, I haven't see or heard about a text based adventure game since I was a kid in the late 70s or early 80s. That brings back memories. It also reminds me how cool the programming behind some simple question and answers could totaly suck you in. It was neat to see a reminder to how this was done, as well as to experiment with pulling in variables from the command line and within a script.
Subscribe to:
Posts (Atom)



































