Don't say "patches welcome" it does more harm to your community than good. Why? It's a polite way of saying "I don't care. Fuck you. Fix it yourself. End of discussion".
1.) Not a Developer
The person you are saying this to is not developer. They don't know how to do it. PERIOD. At this point you are refusing to help them. This person may now have the opinion that your community isn't helpful. Don't ever for any reason assume someone is a developer, assume they are not. I would wager only 1 person in 10,000 is a developer.
I was once told that I should be able to fix a bug in git (msysgit technically) because git is a developer tool. At that time I couldn't code at all but was using git to store homework or something...
2.) Novice Developer
Some how you know the person can code through some method other than assumption. They aren't as smart as you are, there code is so amateurish that it wouldn't be worthy of inclusion, even if they could figure out how to fix the problem. They can't get that far, they've no idea where to begin. You're probably just frustrating them instead of helping the problem. All people that you know are developers fall into this category (unless they fall into the next), either be willing to help this person patch your code or just give them the real reason (e.g. I've no interest in this problem) for not helping. These people know they could be helping, they may even want to be helping, but you telling them that they could be is not helping. They need guidance, not an invitation.
3.) Doesn't Care
So the person doesn't fall into any of the 2 above categories. Guess what? they don't care about it enough. They don't need you to tell them "patches welcome", they know what open source is. They know they could send you a patch, and that you might accept it. They know all that, but there's some reason they don't want to. You aren't telling them anything they don't know. Again just tell them the truth of why you don't want to work on it. Maybe ask them why they don't. Maybe it's a silly little barrier that you can help with. But only bring that up if you know they are competent enough to do it.
Just Stop
Just stop, after years of hearing this when I couldn't do it. All I hear is "fuck you I don't want to take the time to help you". Why would I want to help if that's what I hear? Don't tell me it's not what you mean. Because I've had that said directly.
Stop acting as though everyone can or should write you a patch. Most of you don't agree that you have a responsibility to the free software you create. No one else has a responsibility to contribute to the software. They aren't leeching if they don't give back, you gave it away. Don't ask them to, don't tell them to. They don't want to hear it anymore than you want to fix their problem. Definitely do NOT "volunteer them" to get something done, that's just plain rude.
Pretty much everyone you've ever told this too already knew that patches were welcome, so there's some other reason they weren't writing one.
Exception: If someone asks you if you mind if they work on your code. You can of course answer them "patches welcome" this is because they asked, as opposed to you volunteering that info.
So lastweek you should have covered variables, conditionals, flow control statements, calling functions, stdin/out/err, and using new perl features.
This week we're covering text processing, scalars, external libraries, and reinforcing what we learned last week. Text Processing is one of Perl's specialty's, mostly due to it's powerful regular expression engine.
First install LWP with cpan. cpanp -i Bundle::LWP will do it.
So this is almost completely new... what does it do? and what does it have to do with text?
LWP is short for lib www perl. LWP::Simple is a simple procedural interface to it. getprint is a method which is roughly equivilant to fetch uri and print the content that you got back. So this isn't very useful... (ok it's actually quite useful if you're on arch and you want a PKGBUILD) what we want to do in this case is cut the junk and print the pkgname. As a side note, this code does the exact same thing as the python example in Head First Programming: A Learner's Guide to Programming Using the Python Language but is shorter if you cut the boilerplate (#! ... use strict; use warnings ), and the same length if you don't.
Now let's have a first attempt at getting the package name shall we? We need to read the contents into a variable first. note: we've changed from getprint just to get because it returns the contents to a variable. (note: still shorter than the python.) At this point the book goes into how a string is an array of characters. Perl is contextual so at this point our scalar is essentially a string but just because it's a scalar does not mean it's currently a string. In our previous examples we were handling it in a numeric context.
So here we're looking at the 11 character substring past character 281. The output should be modern-perl. This code is horrible, what should happen if I were to change this PKGBUILD? (if this ever doesn't output modern-perl that's probably exactly what happened). Remember say appends a newline character to it's output print doesn't. We used print previously because the output already had a newline at the end.
There are thousands of PKGBUILD's on AUR let's see if we can get the name from another one by changing the URI.The output at the time of this writing is
dirs')
depe
and will probably change. A newline is just another character in the scalar so nothing prevents one from being printed within the substring. Our URI got a little long here so we moved split that peace of code up to be on 2 lines for readability. Your code lines shouldn't go over 78 characters long if you can help it. A URI would be an acceptable exception though.
So we use the index function to search the string for some text and return the position we can then use that position to get our substring. The position returned is 1 less than where the string we searched for starts. So we added the 9 to get to the string we actually want. Our output is now
perl-moose'
why the '? well "perl-moose" is shorter than "modern-perl" so we've got extra characters in there.
Let's use a regular expression.
regular expressions are really their own mini language, very terse, and several dialects. Have your students go through the Regular Expression Tutorial and the Regular Expression page. In short this regex looks for pkgname='something' in $content and takes something and puts in in $pkgname. the ( ) in the / / tell which part of the regex to assign to $pkgname. [\w-]+ says to match 1 or more alphanumeric or _ or - characters. Regular expressions is a huge topic in and of itself. So don't spend a huge amount of time on it, they are important to know, but you don't have to master them right now.
The example in Head First Programming: A Learner's Guide to Programming Using the Python Language goes on to explain how to check the page periodically for updates, and only output when a value is less than a certain amount. Since I have no idea when I'll be updating these PKGBUILDs I don't want to get into that code. It would make a good homework assignment. You can use sleep to make sure you only fetch the code ever so often. I can guarantee barring a buggy release I won't update any PKGBUILD more than once every 86400 seconds (1 day). You'll have to check pkgver and pkgrel to see if either of them are newer than the previously fetched PKGBUILD.
So I think that Head First Programming: A Learner's Guide to Programming Using the Python Language is a great guideline to teach any programming course, esp a 10 week course as it has 10 chapters. We're one week behind. Arguably you could merge week 2 into week 1 and I may do just that in a rewrite of this series. In fact I'd suggest you do just that. But for now I'm going to continue on and we'll see what people think once I reach the end. No reason I can't rewrite this series, especially since it's not really planned I'm just writing it on the fly.
Although this book is a good guideline (note: I'm also concerned that if I follow it's examples to the letter all the time I might violate fair use), chapter 2 annoys me, it's on textual data and uses html scraping as an example. However, it completely ignores html parsers and any other sane way of doing it. So I had to find a better example and I think I have with parsing PKGBUILD's, which are sort of a microformat bash script.
I solved my problem with Dist::Zilla. If you agree with me that you should be able to install from your git repository, without requiring your users to have Dist::Zilla installed here's one way of doing it.
First install Dist::Zilla::Plugin::CopyTo. Now Edit your dist.ini. Most people probably use one of the Dist::Zilla bundles. Assuming you use Basic here's what you do. Now as you can see we use GatherDir to get where the source should come from and CopyTo to tell additional places where the output of the script should be sent to. It will still send to the default directory, that's ok, you can just ignore those files. add . to your repo (making sure to add the default generated location to your ignore list) and commit. now if dzil changes any of these you can see it.
If you wanted to with git you could use a git-new-workdir and another branch and copy to it and commit this stuff to a different branch. I haven't found another way to do it in a seperate branch yet, although someone said it's possible.
P.S. 1
If dzil ever gives you some vague error about some util file... run dzil clean I don't know why it was doing that to me occasionally through all this but I spent like 8 hours thinking my config was screwed up when the directory just needed to be cleaned.
P.S. 2 Thanks to rjbs for putting up with my asininity while I asked a lot of questions and ranted.
P.S 3
My stuff is 99% working now... I just have a problem where my licensing is wrong :( I've set it to Perl_5 but it really should be GPL3 and Artistic2 (or whatever those are in Software::License).
Dist::Zilla is a great release tool, code generator, and it just plain takes the boring part of doing a release away from you.That having been said, it does, imo, horrible things to your source repository. "But, Caleb, it cleans up your source repository you can remove a lot of excess stuff you don't really need to be storing there". Well... I disagree, to the point that I've used every explicative in the book to express my displeasure. Let me explain why I disagree.
First let me explain my use cases. I have only one package on CPAN, Template::ShowStartStop and it's relatively simple to the point that Dist::Zilla is almost overkill (but I still find it nice). I also maintain a sizeable portion of CPAN on Arch Linux's AUR. In addition to standard CPAN Packaging for my own package I created a -git package which allows me to install directly from my source repository on Github. That worked wonderfully well until I started using Dist::Zilla (note: I haven't gotten a poorly working (read hack that's buggy) version now).
So Dist::Zilla is great for CPAN, no problem for normal downstream packages, but makes things more painful for Version Control Users. "But Caleb, it does nice things for me for version control". Yes it does, but I think it also has some consequences that people don't realize. If you know how Dist::Zilla works pretend that you don't.
Look at my repo What License is my code licensed under? usually this is in the COPYING file. There's no COPYING file there. How do I install it? No README either, oh and the module isn't complete as is things like version are stripped so Dist::Zilla can generate them for me. This list goes on and on all basically leading back to my issue. Why does Dist::Zilla have to take these things out of my source repository?
The answer was... you wouldn't store .o files in your repository would you? why would you store these generated files... oh I dunno... because someone shouldn't have to install Dist::Zilla just to use my latest git? and they aren't like .o files because those are binarily specific to a lot of things and won't be useful on most other machines, unlike these files.
Let's say Dist::Zilla has a bug in what they generate for code. They fix it, I update, all is good for me. Someone else who hasn't updated Dist::Zilla downloads the code and builds and hits the bug... they complain to me. I explain it to them, they update Dist::Zilla, they're happy, I'm happy. But we could have avoided this, if I stored all the output in my repo they'd never have to worry about Dist::Zilla.
So I've been told this will never be fixed because they don't want to clobber the existing files, plus the whole... these are like .o files, thing. Ok, clobber == bad. So how could we fix it so I'm happy? and everyones happy. We should a directory src shall be the source of all non generated code. Much like when working with compiled code you have a src directory for source files and a directory for output. the lib that's still here will be the final generated lib. All the top level files will also be generated. Only the stuff in src is what should be worked on. And the generated README will give all these wonderful instructions that will now be presented to users visiting the github repo. And when I'm writing a -git package I won't have to include any dzil instructions because I don't need to generate this code all the time.
and you know what? if people don't want to store generated files in there vcs they can always use something like .gitignore. So everybody should be happy.
For backcompat just make it a configuration in dist.ini. We can have a [src] dir which could be . for those who want it the way it works now. and an [output] dir.
Will Dist::Zilla be worth this pain? I'm not sure.
So in the tabs vs spaces war I'm squarely on the side of use tabs. tabs have meaning. tabs allow people to set there editor's to whatever space display width their eyes are comfortable with as opposed to what yours are (e.g. you like 2 spaces I like 4). However, I've heard the argument what about when you cat the file, etc. Well it is actually a bit annoying... so let's fix it.
my requirements when I type cat foo if foo has tabs they will be displayed at 4 spaces, and I can still pass all cli options as I normally would to cat. To do this we're going to create a shell function called etcat()
I'd like to note, that in order for this to work you must use either an absolute path or a call to env cat because otherwise the shell will attempt to call cat as a recursive function. I put this in my .alias file and sourced it.
you can now put alias cat="etcat" in your aliases file, or run etcat. This is to protect you from any problems that could otherwise be caused by overriding cat in scripts you don't control (not that I'm actually aware of any for this function).
P.S. Thanks to @greybot on #bash for the incantation as I was having trouble with the "$@"
This part2 was prompted by Chromatic's post on state. I'd never heard of state before, and it's documentation is poor. Let's take a look at how state could affect our game.As you can see this allows us to make our $guess variable lexically scoped, meaning it's contained within the loop. This however generates some warnings: Use of uninitialized value $guess in numeric eq (==) at ./game.pl line 14. and if you enter non-numeric input Argument "l\n" isn't numeric in numeric eq (==) at ./game.pl line 14, line 1.. Both are completely fixable, but lets fix the uninitialized first.
So all we've had to change is adding parenthesis around state and assign it to a value. If we had used a my declaration it would reassign to 0 every time and we'd never match the $winning_num. But since state will only ever initialize once we don't have that problem. We still have our problem if we enter a character though, let's sanitize that input.
So in order to fix the 'not a numerical comparison' issue we check $guess to see if it's a digit with a regular expression. If it isn't a digit we set it to 0 which is an invalid guess anyways, but fixes the warning. This actually fixes two bugs. Before if you entered a letter it would tell you that it was too low (which I don't actually understand, because aren't characters > numbers? if someone on Iron Man could explain it in a comment.)
This game is a lot less challenging, and still not very good. So one one of the problems is it exits instead of letting it try till we get it right. So lets change that.
This one is going to show your students something they likely haven't seen before. An until statement. until is logically equivalent to while not or in this case you could write while ( $guess != 5 ) {...} and have it do exactly the same thing.
We've got some bad practices in this code it lacks useful comments and uses a magic number. Also the instructions aren't clear if you don't know how the program is written. Let's add that stuff next.
So this code is too simple for comments, but I've tried to show what I think some good ones would be. Usually 'novice' books say use meaningful comments but don't show any. Students then end up writing comments like # initialize local variable guess to 0. That's not useful the code obviously says that. Instead comments should say, what a larger chunk of is trying to do, or why it's doing it that way.
In Head First Programming: A Learner's Guide to Programming Using the Python Language the author uses the variable secret where I've used $winning_num because he ends up using a random number generator (we will in a moment), however, this is not a very descriptive name. $winning_num is a better name because it's more descriptive of what the number actually is. He also skips removing the 'magic numbers' step which is probably why the variable name used is poor.
So let's make the winning number random.
There we go... Now are number is random. ... ... ... notice the logic error yet? no? go read the rand documentation. Got it now? ok simply put this generates 10 total possible random numbers starting at 0, e.g 0-9. Our code isn't broken but it's not doing what we want. But the docs don't say how to generate a range... how can I do that? run perldoc -q random this will return perlfaq4 we're looking for How do I get a random number between X and Y?. That tells us how to fix it... our code should now look something like.
we could just put 10 in rand in this case but that's not as flexible. You'll also note I commented on why we did it that way. Kind of a way of making sure no one goes back to the other way, it also tells people why we did it this way.
If you've used another language you might ask, "Why not use a switch case?". Most instructors and books say "perl doesn't have a switch case". Even perl intro still falsely states that
"Perl has most of the usual conditional and looping constructs except for case/switch (but if you really want it, there is a Switch module in Perl 5.8 and newer, and on CPAN."
. That's even worse! Switch.pm has been in core for a while now... but is deprecated an you should NOT use it. since perl 5.10.0 perl has had a Switch statement, so let's rewrite our code using that.
Note the use of use feature 'switch'; make sure you use this instead of use Switch; which will use the now deprecated Switch.pm module.
You can shorten use feature 'say'; use feature 'switch'; to use feature qw(say switch);.
Beside's introducing switch/case this introduces the default argument $_ and smart matching.
You'll also note that I changed the algorithm but my comments didn't change.
What else is wrong with our game? how could we fix it? How could we prevent the problem from being reintroduced? How can we be sure that our random problem is actually fixed? and make sure that it's not reintroduced? Can you think of any other ways we can write this program? or any other improvements? write the program so that it has 3 difficulty levels easy, medium, hard with ranges 1-10,1-100,1-1000 respectively. Blog these to Iron Man.
Now let's install Padre the Perl IDE to give the students a nice development environment. There are instructions on the website, however, cpanp -i Padre should get the trick done since it is on CPAN In the future Strawberry will ship with Padre but that future isn't quite here.
First Program
Ok so we want to make sure that we have Perl installed correctly and since you're taking my advice I'm assuming that you've given your students access to 5.10.1 and may have 5.8 as well... So I'm gonna do this one twice. Have them create a text file hello_world.pl and add the following lines
#!/usr/bin/env perl
print "Hello, World\n";
Since I'm sure this is not your students first programming class this will be familliar to them. Explain the shebang (#!) line and note that it has no effect on windows. Now let's modernize it, using the say feature from perl 5.10.
#!/usr/bin/env perl
use feature 'say';
say "Hello, World";
note the removal of the \n and that use feature is a pragma that allows you to enable features that are newer in perl that weren't available in the original perl 5. Perl is a bit backwards about this, IMO. We should be using the newest version and features unless we specify otherwise, IMO, but that's not how it works, ATM. If 5.10 isn't available to you and your students just use print in future examples. I will be excluding the shebang line from future examples too.
Now let's expand hello world a bit. Have them Make it print
use feature 'say';
say "Hello, programming"
. "Here we go";
This example is inspired by Programming: Principles and Practice Using C++ ( This is an excellent book and should be the textbook for BOTH C++ classes at Baker. I recommend all novice to intermediate programmers have a copy whether you like C++, or not, this book is excellent ). Please note that the . operator is in the front. This draws a programmers attention to it and notes that it's a continuation. See Perl Best Practices for more details on this.
Your output will be.
Hello, programming Here we go
That's not what we want! obviously say appends a newline to the end but doesn't help with long strings.
use feature 'say';
say "Hello, programming\n"
. "Here we go";
Much Better.
Simple Game
Now let's up the ante a bit. Again not there first programming class, the following example is rewritten in Perl from Head First Programming: A Learner's Guide to Programming Using the Python Language which arguably should be the textbook for Intro to Programming. This is the first example that book gives in chapter 1 (but it gives it in python).
note: you can use < STDIN > but blogger screws it up because of the brackets. This code works exactly the same.
So now you can discuss: scalars, if then else statements,and readline. There are also two additional pragma's strict and warnings that you should tell your students to always use unless they have a 'good' reason to disable them (these have been there since the beginning).
So usually on the first night of class you're lucky to get past hello world. I think this is all doable. In 1 small program I just took you all the way to Chapter 6 in Perl by Example (3rd Edition) the chapter on control structures. Remember, this is not your students first class... you don't need to hold their hand through all this. Race through it so they can improve on it as the term goes on. Instead of spending 4 weeks (assuming a chapter a week) on if then statements you can now spend 10
Homework
Start a blog using whatever site you prefer (preexisting blogs acceptable) and add it to Iron Man. Do a first post that talks a little about you (blog can be anonymous). Include a copy of the simple game and what you think would be better about it. Also mention anything you'd like to do with, or know about, Perl.
As I said before Baker provides a Linux server for the perl class. However, none of the students have had a unix class. So I advise touching on it and giving them a link to these tutorials if they want to use it, and a helping hand. The book also talks about ActiveState but this isn't the recommended way to do perl on windows anymore. Avoiding crux will prevent you from wasting a week or more on unix which is not what the class is about (my instructor failed horribly at this, and at knowing unix (or perl for that matter) well enough to cover it).
Strawberry
Strawberry Perl is the recommend open source binaries for windows these days and should work just like the unix ones. You should cover not only normal installation; but installing to their network drives (use portable edition), so they can have strawberry on any baker computer on campus; and to their flash drives (use portable edition), so they can take it with them to any computer running windows.
CPAN
Next you should mention CPAN. CPAN is the #1 resource in perl, if you need to do something, most of the time someone else has done it for you and it's on CPAN. Don't forget to mention search. and kobesearch.cpan.org.
local::lib
After talking about CPAN use it. Help your students install a local::lib esp if you're using the schools linux server which won't allow installs of global CPAN modules.
Task::Kensho
You'll want to recommend that students check out Task::Kensho which a CPAN module that lists all the best modules for common tasks, they may not be the only module for that task but they are the recommended ones. You could have them install them with cpanp -i Task::Kensho at this point or just recommend they look them over to see if they might find them useful. These are all probably ahead of where your students are at, but it never hurts to point useful libraries out early. Just tell them they can get back to them later. Note: local::lib is on Task::Kensho.
P.S. Week 1 will be multipart I have to leave now but I want to hit publish. coming next is how to teach them to do their first program the right way so they don't have to learn it twice.