Sunday, December 28, 2014

Hash class, pretty formatting with printf

I went back tonight to finish up some Ruby file IO practice via the following tutorial:

http://tutorials.jumpstartlab.com/projects/eventmanager.html

I'd finished everything except the last few sections, which eschew the handholding and ask you to clean up phone number, date and time data and generate report files after manipulating it.

As I put the finishing touches on my code, I took a gander at another student's work and was dumbfounded by how much smarter it was than mine. Cleaner, quicker, and easier to read. I felt like an herbal remedy peddler from a lost civilization who'd suddenly been exposed to an open-heart surgery-- why even bother with what I've been doing? That's just better.

So I borrowed some ideas. Not the code itself, mind you.

The biggest thing I picked up was how to quickly generate hashes to keep track of how many of something you have. For example, let's generate a hash to count up how many of each character (case-insensitive) the following sentences contain: "I'm gonna get measured! Hope I measure up!"

To this point I'd been doing the following:

str = "I'm gonna get measured! Hope I measure up!"
hash = {}
str.split('').each do |char|
  char.downcase!
  if hash[char] == nil
    hash[char] = 1
  else
    hash[char] += 1
  end
end


Which is silly, evidently, because I saw the open-heart-surgeon doing it like this:

str = "I'm gonna get measured! Hope I measure up!"
hash = Hash.new(0)
str.split('').each {|char| hash[char.downcase] += 1}

Much better. Frankly I'm not sure why you can do the latter this way-- you'd be subjected to an "undefined method '+' for nil:NilClass" NoMethodError if you tried to add to a hash value for which the key didn't exist in the former code.

Must either be because an instance variable of the Hash class is somehow different from a hash defined as {}, or because of the zero that's given as an argument when making the new hash via Hash.new(0)**

Also, in an effort to get the data formatted nicely I came across the following Stackoverflow question/answer:

http://stackoverflow.com/questions/1087658/nicely-formatting-output-to-console-specifying-number-of-tabs

To align two columns of text nicely, you can use the following command:

printf "%-20s %s\n", string1, string2

The -20 means that the first string (signified by %s here) will occupy 20 characters; whitespace will be used to cover ground that isn't occupied by its actual letters. The minus sign means that the letters will be placed in the beginning of this string, followed by its whitespace, covering 20 characters in total.

If we entered "%20" instead (no minus sign), the letters would come last, being preceded by whitespace. After this 20-character string, we'll have another space, and then the second string.

i.e.

$ printf "%-20s %s\n", "howdy", "y'all"

howdy                y'all

$ printf "%20s %s\n", "howdy", "y'all"

               howdy y'all


...You can change the number, naturally. I'd imagine that you can also add more strings by adding more "%s"s and their alignments, but I haven't tried it yet.

Here's my code!

https://github.com/johnwquarles/jumpstartlab-event-manager

** as of 1/24/2015 I do know why; Michael Hartl's Rails tutorial explains this very point toward the bottom of section 4.4.1. "Hash.new takes a default value for the hash, which is the value of the hash for a nonexistent key." So in the code above, the hash returns zero for nonexistent values, instead of nil, which you can't add to.

Saturday, December 27, 2014

.DS_Store

As a result of switching to this Macbook for my programming purposes, I've gotten to know a little bit about a Mac OS X-specific issue in the past day: .DS_Store files.

These are hidden metadata files present in (all?) Mac OS folders and contain data about the positions of your icons, folder background images (didn't know you could do that), etc.

Their filenames begin with a ".", which is how they're hidden -- my understanding is that this is typically how files are hidden from GUIs in UNIX filesystems. You can easily see them, and any other hidden files with the following (very simple) terminal command, though:

ls -a


Given that these .DS_Store files are hidden, you wouldn't normally notice them.

However, they become quite a source of annoyance when sharing code with version control systems like git, which is exactly how I came across the issue myself.

They'll needlessly pollute your repos and potentially others, should your code be merged in, unless you set your local git configuration to explicitly ignore them.

I learned how to do this from the following Stackoverflow page:

User Turadg compiled information from the best responses and listed two terminal commands that can be entered in order to have git ignore your .DS_Store files. They are:

# specify a global exclusion list
git config --global core.excludesfile ~/.gitignore 
# adding .DS_Store to that list 
echo .DS_Store >> ~/.gitignore

Seems to work. I made a dummy repo on github and uploaded a text file -- no signs of any .DS_Store shenanigans. I rather comically named the repo ".ds_store-ignore-test" (note the ill-advised leading period), so when I cloned it to my computer, sure enough, it was hidden from my OS.

No worries; renamed it from the terminal, but I had a brief chuckle about it.

Hangman

Woke up this "morning" (hey, I'm on my winter holidays) and got to work on my next Odin Project task: making a hangman game in Ruby that loads each game's secret word from a giant text file and allows for saving/loading of game data via serialization.

Long story short: it's done! If you have any interest in a rousing round of potentially lethal wordplay, please give it a shot:

https://github.com/johnwquarles/Ruby-FileIO-Hangman

Writing this game was encouraging for me. I think that I'm getting a better handle on how to structure Ruby programs-- I had a tougher time writing the previous two games I've done, Tic-Tac-Toe and Mastermind, in that I don't think I'd fully adjusted to Ruby relative to Python when I wrote them.

In Python, for example, local variables are available to all functions nested more deeply than whatever the scope is in which the variable resides. In other words, in Python, this code:

i = 1
def foo(number):
    return number + i
print foo(2)

will wind up printing 3.

If we try to do the same thing in Ruby, this code:

i = 1
def foo(number)
  return number + i
end
puts foo(2)

will wind up raising a NameError: namely "undefined local variable or method 'i' for main:Object".

Let's say that functions define a permeable membrane in Python: variables from the outside (those more shallow in scope) can come in. In Ruby, methods seemed to be more of a wall.

My adjustment has been to keep Ruby variables that need to be used by multiple methods within a class and/or multiple classes stored as instance variables within their respective classes. Also, data is passed between methods explicitly as opposed to having it float in the ether of a particular class, function/method or loop in the form of local variables.

I'd written a similar game for MITx's 6.00.1x in Python, but it had all the file IO pre-written and provided skeleton functions and guidance as to what each function needed to accomplish. This Ruby version was written from zero. I'm just a proud lil' guy!

In unrelated news I bought a used 11-inch 2011 Macbook Air via Craigslist from a gentleman a few days ago and have been setting up/getting used to it. I think I like it a lot more than the Windows notebook I'd been using (granted, even if I had liked Windows more, it simply would have been in my best interest to switch given what I've read about Rails on Windows).

I use an external monitor to host my text editor (Textmate) and terminal windows in fullscreen mode. Three-finger sideways swipes on the trackpad quickly switches between them. I also keep a browser window open on the laptop's screen for googling or reading through whatever tutorial I'm doing. Seems like a good setup!


Apropos of nothing: trains in Japan appear to be powered by regularly-distanced flux capacitors 







Friday, December 26, 2014

Introduction

Hi there! My name's John Q. and I'm on a journey to learn more about web development.

I decided upon this course in the beginning of September, 2014 and began by going through Zed Shaw's excellent Learn Python the Hard Way and bountiful bundles of codeacademy.com tracks before being clued in to MOOCs-- namely those on edx.org and coursera.org.

For anyone unfamiliar with MOOCs, the acronym stands for Massive Online Open Courseware. Top universities around the world put many of their courses online for free, with lecture videos, quizzes, tests, online graders (that check code, in my case; not sure how it'd work for a history course), message boards for interacting with your fellow online students, etc. The (free!) courses that I took even had TAs!

The schools that have set up MOOCs to this point have largely been elite (MIT, Harvard, Stanford) so I figure that they're doing this because they see it as an important direction into which education will be expanding in the future. They want to be at the forefront of this movement, so they need data, and thus they need students to generate that data.

Which means that you can take (among many other options) MIT computer science classes for free, and even learn about the big data concepts that are surely being used to analyse the data that you're helping to generate.

Naturally, I'm taking advantage of that.

It's online work, granted, but it's plenty challenging and so long as you take it for what it is (a way to gain knowledge, not a path to a degree), I see it as a very valuable resource.

To this point I've completed certificates for MITx's 6.00.1x Intro to Computer Science using Python6.00.2x Intro to Computational Thinking and Data Science, and a Stanford mini-course in SQL. I'm going to start Stanford's Algorithms: Design and Analysis, part 1 and Princeton's Algorithms, Part 1 this January, although I'll probably wind up choosing one over the other. Any advice is appreciated! Princeton's sounds more beginner-friendly I suppose, but I have no experience with Java programming yet (I've focused on Python and Ruby). I also like the sound of Stanford's course in that it apparently goes into more conceptual learning involving mathematical proofs-- I did a math major as an undergraduate.

Anyway, beyond the MOOC work, I've been active in learning, writing code for and contributing solutions to Erik Trautman's The Odin Project, a free online Ruby-on-Rails bootcamp style curriculum. Erik also runs the Viking Code School, which I'm very happy to plug to the two of you who may be reading this.

About me personally: I'm American but live in Chiba, Japan and speak Japanese. I'll be coming back to the US in April of 2015. Wish me luck! I hope that I can be of use to anyone on a similar journey now or in the future.

Check out my github page and my Twitter page should the mood strike you.

Thanks for stopping by!