Well, we've covered all the basics, but there are a few more odds and ends worth being familiar with, if only in name, that we haven't yet looked at. You'll find them here.
We did see
curl used already, but only briefly.
Like, very briefly.
"curl is a command line tool for transferring data with URL syntax, supporting DICT, FILE, FTP, FTPS, Gopher, HTTP, HTTPS, IMAP, IMAPS, LDAP, LDAPS, POP3, POP3S, RTMP, RTSP, SCP, SFTP, SMTP, SMTPS, Telnet and TFTP. curl supports SSL certificates, HTTP POST, HTTP PUT, FTP uploading, HTTP form based upload, proxies, cookies, user+password authentication (Basic, Digest, NTLM, Negotiate, kerberos...), file transfer resume, proxy tunneling and a busload of other useful tricks." - curl.haxx.se/
So, that's a lot of functionality, but the takeaway for us is that it can do a lot of stuff with HTTP.
Earlier, we performed an HTTP
GET and an HTTP
curl to programmatically hit against our Rails application and view the returned JSON.
Though useful in that capacity alone,
curl can also be used as a general system utility to grab things from the Internet:
$ curl http://www.example.com/some/random/lolcats/picture.jpg > image.jpg
The line above would download the image at that fictional URL and save it to disk as
image.jpg in the working directory.
Having only seen
curl usage in examples from the Rails community, you might never expect that this is possible with
curl, but it just goes to show the incredible flexibility of the tools we have access to. ...for free no less.
Another applications with comparable functionality is
wget, but the Rails community seems to greatly favor
SSH stands for "Secure Shell" and is used to securely log into a remote server and run a remote shell for that machine. This is often the method used to manage things server-side, but since we're using Heroku and Heroku makes use of a distributed environment, we can't
ssh into our Heroku server.
In order to obtain a remote shell using SSH, we just need the address of a machine running an SSH [daemon](http://en.wikipedia.org/wiki/Daemon_(computing))/server and valid login credentials for that machine.
Assuming I have an SSH daemon (
sshd) running on my machine and that my username is
brad, I can SSH into my machine like this:
$ ssh brad@localhost
I would then be prompted for my password and, if correct, I would be granted a Bash prompt.
This would be ridiculously unnecessary for running commands locally, but it is incredibly useful for running shell commands on a remote server.
Pry is a Ruby Gem and alternative to IRB and offers a lot of awesome features. It's definitely worth a look.
Pry can even be used for
rails consolein place of IRB.
After you write code for a while, it becomes apparent that there are methods of numbering and units of measurement that come up often in a programming context. Let's start with numbering.
We live in a society that most commonly uses a decimal numeral system, a system that has a base (or radix) of ten. In this base-10 system there are exactly ten ordered digits:
You could use any number as a base for a numeral system, but four bases are particularly common in computing:
|Numeral System Name||Base/Radix||Ordered Digits||Literal Prefix|
Note that the lowercase characters
abcdefmay also be used for hexadecimal values.
When we call
to_s on a
Fixnum in Ruby, we can pass in a number base as an argument. For instance, if we call
64.to_s(2) we are asking for a string that is the binary representation of the decimal value
Let's take a look in IRB:
> 128.to_s(2) => "10000000" > 128.to_s(8) => "200" > 128.to_s(10) => "128" > 128.to_s(16) => "80"
Keep in mind that these returns are just string values, but Ruby also has several notations we can use to create binary, octal, and hexadecimal literals.
To take a look at these, let's use the Ruby
Fixnum literal representation for each of values we just saw above:
# binary representation > 0b10000000 => 128 # octal representation > 0200 => 128 # hexidecimal representation > 0x80 => 128
And yes, alphabetical characters are used to represent certain hexadecimal values:# lowercase > 0xff => 255 # uppercase > 0xFF => 255 # case doesn't matter
You can see that each of these values is quite varied from the others, but there is a special relationship between binary and hexadecimal: each hexadecimal digit represents four binary digits.
For example, decimal
10 can be represented as
0xa, as can decimal
All of this is nothing that we'd normally have to think about during day to day web programming, but it does help us understand a number of different computing concepts.
In fact, it'll help us understand our very next topic.
Internally, computers keep track of everything in binary.
As it turns out, computers run on electricity. And in electronics, logical values are either "high" or "low", "on" or "off". Computers use
1 to represent "on" and
0 to represent "off".
But from our perspective, they keep track of much more than just numbers, so how do they do it?
Well, as you might expect, everything ends up being eventually mapped to some kind of numeral value. Take strings for example, they end up as something like ASCII- or UTF-encoded values.
Now we've mentioned these character encodings before, but have yet to see exactly what they are. As most of what we've seen in this book, they are topics unto themselves, but now that we have a basic understanding of binary we're now equipped to grasp their fundamentals.
Let's start by screwing around in IRB:
As is tradition.
> 'a'.ord => 97 > '1'.ord => 49 > '*'.ord => 42 > 97.chr => "a" > 49.chr => "1" > 42.chr => "*"
String#ord) stands for "ordinal" by the way.
Is the conversion above immediately useful? No.
Is it interesting? Yes.
Will everyone eventually run into a situation where they'll need to understand this? Absolutely.
The integer values above might look random, but there is some method to the madness. Take a look at the printable ASCII characters to see.
One interesting part of this mapping is that
9 are represented by
Notice that the least significant digits line up.
Also, uppercase alphabetic characters begin at
0x40, while lowercase characters begin at
0x60. This means that we can down case a character by adding
0x20 and upcase by subtracting
We can see this in IRB, making
'A' into an
'a' with some simple hex addition:
# the integer ASCII value for 'A' > up_ord = 'A'.ord => 65 # represented in hex as... > up_ord.to_s(16) => "41" # integer ASCII value for 'a' > down_ord = up_ord + 0x20 => 97 # represented in hex as... > down_ord.to_s(16) => "61" # convert it to a string > down_ord.chr => "a"
So ASCII is pretty interesting, but it has a limit: it can only accommodate seven bits.
Okay, well how much data can be encoded with seven bits?
Not much. Each binary digit has only two possibilities (
0), but with each additional bit, the possibilities are doubled.
In other words, 7 bits allow for 2 to 7th power permutations.
How many possibilities?
Let's ask IRB:
> 2 ** 7 => 128
Powers can be calculated in Ruby using
128 might not seem like much, and it isn't. Especially when you consider how many different languages and writing systems there are.
8 bits in a byte, hence the "8" in "UTF-8".
Most of the text on the Web is UTF-8 encoded, so Ruby and Rails play quite nicely with it.
In fact, you'll find a
app/views/layout/application.html.erbthat declares the
For instance, let's play with a Japanese Hiragana
あ ("a") in IRB:
> "あ" => "あ" > "あ".ord => 12354 > "あ".ord.to_s(16) => "3042" > "あ".ord.to_s(2) => "11000001000010"
One interesting characteristic of UTF-8 is that its first 128 characters map directly to ASCII. This means that well-formed ASCII is also well-formed UTF-8.
There are certainly more encodings (e.g. Base64), but a cursory understanding of ASCII and UTF-8 is a good start.
So character encodings are a helpful means of demonstrating bits and bytes, but keep in mind that computers use these concepts everywhere.
As for hardware, physical memory is hexadecimal addressable and written by the byte and processor registers have a specific byte size. When it comes to networking, data is also transfered by the byte.
For larger values, metric prefixes are used to make things more readable. Some common examples are as follows:
|Name||Abbreviation||Number of Bytes||Value|
|Byte||b / B||1||1b (byte)|
|Kilobyte||kb / KB||210||1024b (bytes)|
|Megabyte||mb / MB||220||1024kb (kilobytes)|
|Gigabyte||gb / GB||230||1024mb (megabytes)|
|Terabyte||tb / TB||240||1024gb (gigabytes)|
As seen in the table on the right of this page, decimal values are sometimes used for these values. This is done a lot by hard drive manufacturers, for example, because they can sell slightly smaller capacity hard drives and claim that they are larger without actually lying.
A base knowledge of these values is incredibly helpful in understanding how much data you're working with.
Time can get rather complicated in computing, but fortunately for us, it's at least measured with a unit we're already familiar with: the second.
As you might have noticed, network requests are measured in Dev Tools and the
rails server output using "ms" – milliseconds.
Let's go over some more metric prefixes real quick to help with this topic.
|Millisecond||10-3 (.001) seconds|
|Microsecond||10-6 (.000001) seconds|
|Nanosecond||10-9 (.000000001) seconds|
A millisecond is actually quite a while for a computer. In fact, if you're spending more than 1ms, you're probably performing some inherently time consuming task like a DB/file operation or a network transfer.
On the other side of the spectrum, processor and memory operations can take as little as a few nanoseconds.
Sadly, I can't tell you in absolute terms what is "fast" and what is "slow" though, because it's always relative. So stay aware and try to get an understanding of how long your code is taking and how long it should be taking.