Closed Sequoia closed 9 years ago
[x] Add note about toString on buffers
I disagree with using the
+
to automatically cast the buffer into a string. I purposely left the buffer in the output because otherwise we're hiding the fact thatinput
is actually a buffer andString.prototype
method calls will not work on it directly.I specifically linked to process.stdin which basically has a copy/paste solution for reading all of the stdin
Luckily, if the user did so something like
total += chunk
where both areBuffer
objects, it would result in a string.Buffer("hello") + Buffer("world");
results in(string) "helloworld"
.comments?
[ ] boilerplate (console.log in on('readable'),
) may actually lead the learner away from the solution-- it seems intuitive that cl
ing should happen on readable but really it should (probably) happen on end
The
end
event does not fire until you've consumed the stream though. E.g., I've verified this solution does not work
process.stdin.on("end", function() {
var input = process.stdin.read().toString();
console.log("total input from stdin:", input);
});
The
end
event will never fire becauseprocess.stdin.read
isn't called. It seems that the boilerplate contained within the docs (linked above) is the minimal code to get everything workingcomments?
clijs run
does I think it should actually set up the env like it will be set up for verify
, i.e. pipe data in & feed it a switch[ ] link to regexp.test
I feel like introducing RegExp here is a little out of scope. I provided a more thorough explanation of
str.indexOf
that should help people not get hung up on the string matching. Feel free to adjust this if necessary.comments?
str.indexOf
usage example and link to docsstream-adventure
if they want to learn more about this exciting topic[ ] "Append to results
string then operate on it on('end')
" pattern is canonical but not necessarily obvious. I suggest adding note/example that highlights this technique
commented on this above (re: only using with
readable
event works). More discussion can be had if necessary.
[x] I may shorten intro if that's alright
You can shorten it to whatever you like ! This entire lesson is yours to use however it suits you best.
@Sequoia
I'd probably say that this lesson is "too hard" as it currently stands. It took me a minute to figure it out and I'm reasonably good at this stuff. I want to carefully avoid (as much as possible) learners getting "stuck", and I think this lesson would get people a lot of people stuck.
Understood. I can't say I completely disagree.
After amending the readme
with another 1,000 words of explanation and several more code examples, it's clear that -- at least for absolute beginners -- this example has too many dependencies.
I'll start thinking of new ways to maybe make the lesson a little easier :tired_face:
@Sequoia new idea !
What if we try something more like this:
(proposed intro for updated lesson)
So far our CLI programs have taken a small number or command line arguments. But what if our program needed to accept a different kind of input? Or, what if we didn't know value of the inputs at the time our program was launched?
It's possible to feed information into a program's standard input (or stdin) using a mechanism called piping. The primary benefit of using this kind of input is that we can accept input from another program's output. The command line supports piping via the
|
symbol and we'd like to take advantage of that.In this exercise, a Bingo Number Generator will send a number to your program once per second. Your program will receive a total of 5 numbers. Your job is to output each number and finally say
"BINGO!"
after all 5 numbers have been printed.
Whipped these up quick
index.js
var letters = ["B", "I", "N", "G", "0"];
var numbers = ["1", "2", "3", "4", "5"];
function sample(arr) {
return arr[Math.floor(Math.random()*arr.length)];
}
function getNumber() {
return sample(letters) + sample(numbers);
}
function asyncForEach(arr, iterator, callback) {
var queue = arr.slice(0);
function next(err) {
if (queue.length === 0) return;
iterator(queue.shift(), next);
}
next();
}
asyncForEach([1,2,3,4,5], function(_, done) {
setTimeout(function() {
process.stdout.write(getNumber());
done();
}, 1000);
});
solution.js
process.stdin.on("data", function(number) {
console.log("received: %s", number);
});
process.stdin.on("end", function() {
console.log("BINGO!");
});
Example run
node index.js | node solution.js
Output
received: G3
received: I5
received: B5
received: G4
received: N5
BINGO!
Looking at that solution.js
file, it seems like a much nicer example.
Let me know your thoughts.
And yes, I know that 5 random numbers don't always result in a bingo... I just ...
/me gives up :sob:
I disagree with using the + to automatically cast the buffer into a string.
You do this in the solution tho :question: If the learner uses toString
they will get an error when .read()
returns null
which is just another layer of complexity. Basically my point was "if they need to cast/convert buffers let's mention that in the Readme"
if the user did so something like total += chunk
This is gr8 I like it, my concern is that they are not going to know to do that from the readme/examples.
The end event does not fire until you've consumed the stream though. E.g., I've verified this solution does not work
I just meant don't put console.log
in there cuz it makes it seem like that's where you should be outputting lines for your solution-- I didn't mean to say "don't listen to readable at all" tho I can see how I wasn't totally clear.
Using Pipes revisions will not result in an elementary exercise that benefits the learner
Notes
Add note about toString on buffers
console.log('x' + ...read())
casts buffer to str butconsole.log('x', ...read())
(i.e. 2 args for console.log does not. The latter is in the boilerplateconsole.log("reading:" + process.stdin.read().toString());
does not work because readable is emitted with anull
on end of input it seems :/^ This basically work
on('readable'),
) may actually lead the learner away from the solution-- it seems intuitive thatcl
ing should happen on readable but really it should (probably) happen onend
clijs run
does I think it should actually set up the env like it will be set up forverify
, i.e. pipe data in & feed it a switchlink to process.stdin or whatever docsstream-adventure
if they want to learn more about this exciting topicresults
string then operate on iton('end')
" pattern is canonical but not necessarily obvious. I suggest adding note/example that highlights this techniqueMy Impression
I'd probably say that this lesson is "too hard" as it currently stands. It took me a minute to figure it out and I'm reasonably good at this stuff. I want to carefully avoid (as much as possible) learners getting "stuck", and I think this lesson would get people a lot of people stuck.
Proposal