-
Notifications
You must be signed in to change notification settings - Fork 123
Cowsay coursework #189
Cowsay coursework #189
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
--- | ||
id: readme | ||
title: Cowsay | ||
sidebar_label: Cowsay Project | ||
--- | ||
|
||
## Cowsay | ||
|
||
This coursework assumes you have [Node](https://nodejs.org/en/download/), a text editor, and a terminal or command line. | ||
|
||
Cowsay is a fun script that prints an [ASCII](https://simple.wikipedia.org/wiki/ASCII) cow with your words in a speech bubble. It works like this: there is a library of pictures of cows made out of ASCII characters. You call the script in your terminal and you pass in arguments. There are lots of options, but one argument is required: a text string for the cow to say. | ||
|
||
``` | ||
________ | ||
< Mooooo > | ||
-------- | ||
\ ^__^ | ||
\ (oo)\_______ | ||
(__)\ )\/\ | ||
||----w | | ||
|| || | ||
|
||
``` | ||
|
||
Cowsay was originally written in [Perl](https://simple.wikipedia.org/wiki/Perl). In this coursework, we will run it with Node. How would we go about this? What things would be helpful? I think we could use: | ||
|
||
* A node package that contains the cowsay library. I'll start you off by letting you know there is one, and it is called ```cowsay``` | ||
* A way to execute the script. | ||
|
||
Before we start, what's the fastest way you could get the cow to talk? Well, you can execute some packages directly [in the command line with npx](https://nodejs.dev/learn/the-npx-nodejs-package-runner). | ||
|
||
``` | ||
npx cowsay Moooo | ||
``` | ||
|
||
We did it! But let's explore some more. How would you install cowsay as a dependency? Make a new folder called /cowsaying and initialise a new package. | ||
``` | ||
mkdir /cowsaying | ||
cd /cowsaying | ||
npm init | ||
``` | ||
Press return through all the options and then do. | ||
Comment on lines
+40
to
+42
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hmm, I was about to suggest that we remove this, to avoid the interactive prompt. However I had forgotten that So instead, maybe we could switch this to |
||
``` | ||
npm install cowsay | ||
``` | ||
### npm run | ||
|
||
Let's find out how to execute cowsay from our package.json. Open /cowsaying in your text editor and look at the [package.json](https://nodejs.dev/learn/the-package-json-guide). | ||
|
||
Add cowsay to the scripts object. | ||
``` | ||
"scripts": { | ||
"cowsay": "cowsay Mooooo" | ||
}, | ||
``` | ||
Now cowsay is listed as a script, and it has an argument. In your terminal, run cowsay. | ||
``` | ||
npm run cowsay | ||
``` | ||
What are the downsides of this approach? I would say one is that we want to be able to pass in arguments, not just always say moo. How could we make the cow say Baaaa? | ||
|
||
Remove the hardcoded "Mooooo". Can you pass a different string in the command line? | ||
|
||
### node | ||
|
||
Now let's execute cowsay in a different way. Open /index.js in your text editor. Import the cowsay package with require. | ||
``` | ||
const cowsay = require("cowsay"); | ||
``` | ||
Comment on lines
+67
to
+69
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Minor nitpick, you get nicer syntax highlighting if you mark the code block as Javascript by putting |
||
And log a cow to the console that says "I require a package". Add some more arguments if you can. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Perhaps it might be useful to link to the cowsay documentation here? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Actually... having poked around with it a bit, I think the docs are pretty confusing (and maybe plain wrong?). So I'm having second thoughts about it. |
||
``` | ||
console.log(cowsay.say({ | ||
text : "I require a package", | ||
e : "oO", | ||
T : "U " | ||
Comment on lines
+74
to
+75
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I found these options a bit confusing when I first saw them. The docs seem to imply that it accepts |
||
})); | ||
``` | ||
Now run this with node: | ||
``` | ||
node index.js | ||
``` | ||
## Going deeper, your stretch goal | ||
|
||
How is this cow being made and what else can we make? Open your node modules and look inside cowsay. There's a README file that tells you all about the package and a library of other animals you can make. Read it. You don't have to understand all the code to get an idea of what is going on. | ||
|
||
How would you extend this library to add a new animal? What about [a duck](https://www.asciiart.eu/animals/birds-water)? Look at how the existing ```.cows``` are imported and try adapting this for your own .cow. There are no solutions provided for this challenge. Dig around for yourself. | ||
|
||
## Project | ||
|
||
Let's figure out how to make a cow say things in Node by ourselves. For this project we don't really need a package, a library or lots of options. Let's just get the cow printing out and saying whatever we write in the command line. What would be helpful? I think we need to: | ||
|
||
* [Accept an argument](https://nodejs.dev/learn/nodejs-accept-arguments-from-the-command-line) from the command line. | ||
* Output to the command line. You've already done this with console.log. | ||
* Make an ASCII cow. | ||
* Write a function that puts the string into the cow's speech bubble. | ||
|
||
Write your solution in a file called solution.js and test it by running your program in the command line. How will you handle a null argument? | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think there are two layers being discussed here - the sentence is about the command line (where you can't pass null), and the "null argument" question seems to be more about the function... It could be a little clearer to say something like "no argument being passed" so that both sentences are talking about the same layer of abstraction? |
||
|
||
### Iterating | ||
|
||
We could make our program more accessible by adding a command line interface that prompts us to write in the cow's words. What tools can we use? I think we could use: | ||
|
||
* A command line interface. I'll start you off by letting you know that there is a built in CLI called [readline](https://nodejs.dev/learn/accept-input-from-the-command-line-in-nodejs). | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think writing async callback functions is sadly a bit advanced to just link to for JS1/JS2 and expect the trainees to be able to follow - if we're going to use There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Agreed - I think with some scaffolding around how to accept command line argument it could be a really nice exercise There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, I agree with this. What about splitting cowsay into two: Part one is just investigating installations and running things in terminal and then return to it in JS3 where we write our own cowsay and iterate on that. Returning to cowsay and being able to write your own by JS3 would create a satisfying experience of progress and mastery. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ...That's with some more scaffolding around the MVP cowsay script and then this time using it to layer up on features - could maybe do readline, commander, and then a library of cows/ducks/unicorns? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I like the idea of splitting up the project, however I would point out that we don't actually touch NPM at all until React in the current syllabus. I'm actually not quite sure at what point we introduce the terminal now? My feeling is that we should really focus on the basics of JS before introducing packages. I was actually going to suggest that the first section of the project might be useful as a lesson/coursework in JS3 as an fun introduction to packages. The second half would be useful as a challenge, especially if we gave some more step-by-step instructions or provided some scaffolding. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, pushing the whole thing into JS3 sounds great! |
||
* Our ASCII cow again. | ||
* And our cow function. | ||
|
||
Write your solution in a file called solution2.js and test it by running your program in the command line. Use a prompt to ask for your cow saying. | ||
|
||
If you get stuck, I've included a couple of solutions. Yours might be different and that's ok. If you can print a cow and you can make it say different things, you solved it. Below I include a slightly simpler ASCII cow that might help if you hit formatting issues. | ||
|
||
``` | ||
/ | ||
/ | ||
^__^ / | ||
(oo)'_______ | ||
(__) )-~ | ||
||----w | | ||
|| || | ||
``` |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
// ================= | ||
// Stripped down cowsayer CLI, | ||
// no libraries | ||
// https://nodejs.dev/learn/nodejs-accept-arguments-from-the-command-line | ||
// ================= | ||
|
||
// 1. Accept arguments | ||
|
||
const args = process.argv.slice(2); | ||
|
||
// 2. Make supplies for our speech bubble | ||
|
||
let topLine = '_'; | ||
let bottomLine = '-'; | ||
let saying = ''; | ||
|
||
// 3. Make a cow that takes a string | ||
|
||
function cowsay(saying) { | ||
if(saying) { | ||
let cowsaying = | ||
` | ||
${topLine.repeat(saying.length)} | ||
< ${saying} > | ||
${bottomLine.repeat(saying.length)} | ||
Comment on lines
+21
to
+25
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If we stripped these lines out and turned them into an exercise, I think that would make it a lot more approachable for JS1/2 students |
||
/ | ||
/ | ||
^__^ / | ||
(oo)'_______ | ||
(__) )-~ | ||
||----w | | ||
|| ||`; | ||
|
||
return cowsaying; | ||
} else { | ||
// account for empty strings | ||
return 'You must add an argument. Try again and add "some words in quotes".' | ||
} | ||
} | ||
|
||
//4. Pipe argument into cowsay function and return a cow | ||
console.log(cowsay(args[0])); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
// ================= | ||
// Stripped down cowsayer CLI, | ||
// no libraries or arguments | ||
// https://nodejs.dev/learn/accept-input-from-the-command-line-in-nodejs | ||
// ================= | ||
|
||
// 1. Make a command line interface. | ||
|
||
const readline = require('readline').createInterface({ | ||
input: process.stdin, | ||
output: process.stdout | ||
}) | ||
|
||
// 2. Make supplies for our speech bubble | ||
|
||
let topLine = '_'; | ||
let bottomLine = '-'; | ||
let saying = ''; | ||
|
||
// 3. Make a cow that takes a string | ||
|
||
function cow(saying) { | ||
let cowsay = | ||
` | ||
${topLine.repeat(saying.length)} | ||
< ${saying} > | ||
${bottomLine.repeat(saying.length)} | ||
/ | ||
/ | ||
^__^ / | ||
(oo)'_______ | ||
(__) )-~ | ||
||----w | | ||
|| ||`; | ||
|
||
return cowsay; | ||
} | ||
|
||
// 4. Use readline to get a string from the terminal | ||
// (with a prompt so it's clearer what we want) | ||
|
||
readline.question(`What does the cow say?`, saying => { | ||
console.log(cow(saying)) | ||
readline.close() | ||
}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One thing this highlights is that I don't think we have a consistent way we get our trainees to organise code on their laptops, which occasionally causes problems. Maybe we could introduce something like "All of your projects/git repos should be in ~/code" or similar early in the course, to help with this?
We definitely see problems with people accidentally running
npm init
in their homedir and it breaking stuff - having clear guidance here would help to ensure people don't get tripped up...For now in this exercise, though, maybe ~/cowsaying would be handier than /cowsaying - I suspect the latter may have some permissions issues for some trainees :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we added some instructions to navigate to the trainee's CYF work folder, would
mkdir cowsaying
work? I feel like adding to~
would not be helping with the folder mess.