Braving Bash, Part 2

Diving into ~/.bash_profile.

In Part 1, I talk about facing my fears of potential machine ruin and beginning to figure out what, exactly, is happening in my bash init files. At the end of that post, I had just figured out that three lines of code in my ~/.bash_profile file were checking to see if I had a ~/.bashrc file, and executing it if so. Now that I know that, I can start digging into what this code actually does. Since I’m already hanging out in ~/.bash_profile, might as well start there.

Step Three: Take apart .bash_profile

Line 1

export PATH=/usr/local/bin:$PATH

PATH is something that comes up a LOT when you’re setting up different coding-related tools. I knew it had something to do with finding the right versions of executable code (including programming languages like Ruby or PHP). The Wikipedia article on $PATH explains: “When a command name is specified by the user or an exec call is made from a program, the system searches through $PATH, examining each directory from left to right in the list, looking for a filename that matches the command name.” Adding specific paths to your $PATH variable makes sure you’re using the versions of code that you want to be using.

Old Unix machines originally looked in /bin for executable files. Later versions of Unix added /usr/bin (and then /usr/local/bin) because /bin grew too large to be efficient.

Looking at the line above one piece at a time: as far as I can tell, export makes the variable you’re exporting (in this case, PATH) available to the current environment, including any subprocesses (see this Stack Exchange post) and the “Environment” section of the GNU Bash Reference Manual.1

Moving on: we’re setting PATH (the variable) to /usr/local/bin:$PATH. It looks like paths within PATH are separated by colons. $PATH echoes out the current value of PATH. To sum up: we’re adding /usr/local/bin to the beginning of the PATH variable.

Sweet. Now we know what this is doing!

Next question: why?

Wikipedia says the default PATH includes /usr/bin and /usr/local/bin. So why add /usr/local/bin again?2

I don’t know the answer for this right now, so I’m going to move on.

Line 2

test -f ~/.bashrc && source ~/.bashrc

This looks suspiciously similar to lines 6-8, which I talk about in Part 1.

test is a builtin Bash command that “tests file types and compares strings.” In Part 1, I learned the -f flag returns true if the file exists and is a “regular” file, i.e., not a directory or a file that’s actually a physical device like (I think?) a USB key or an external hard drive. && is a way of chaining commands together where the second command executes if the first command returns true. From the googling I did last time, I know source ~/.bashrc looks for the ~/.bashrc file and executes it.

To sum up: this is doing the exact same thing as lines 6-8. Fun fact: that welcome message that was showing up twice every time I opened a new tab in Terminal? THIS IS WHY. Leaving this line in and removing lines 6-8 solved that problem.3

Success!

Line 4

export PATH=$PATH:/Applications/Sublime\ Text.app/Contents/SharedSupport/bin

Adding more things to my PATH! This one adds the path to my copy of Sublime Text, which is the text editor I for anything where I’m looking at more than a single file at once. Adding it to my path enables me to use the subl command line tool. I don’t know if this is in the right place,4 but I know that temporarily commenting it out makes attempting to run subl in Terminal give me a “command not found” error, so for now, it’s staying.

Line 10

eval "$(rbenv init -)"

Last line! According to this Stack Overflow post, eval takes a string and evaluates it as if you’d typed it into the command line. Wrapping something in $(…) runs it in a subshell (see 1 again).

That leaves us with rbenv init -. rbenv is a Ruby version management tool that we’re using as part of General Assembly. I installed this as part of our “Installfest,” a day where we type a bunch of commands into Terminal and paste a bunch of code into our bash init files, and I haven’t done any research on how it works. According to the docs, it uses a trick in the PATH variable that lets us specify, at a project-by-project level, a specific version of Ruby to use rather than always using the default version on our system.5

The docs also talk about rbenv init. That section starts with “Skip this section unless you must know what every line in your shell profile is doing,” which means I’m definitely going to read it for the purposes of this adventure. My understanding is that rbenv init: 1) makes the PATH magic happen by adding ~/.rbenv/shims to the beginning of my PATH (which I think only needs to happen/only happens once?); 2) “installs autocompletion” (for what? no idea6); 3) rehashes the shims (makes sure that rbenv knows where different Ruby versions are and can direct commands like rake and pry appropriately); and 4) gives rbenv the power to “change variables in your current shell.” Back to my question about shells.1

At the end of the docs, they say “Run rbenv init - for yourself to see exactly what happens under the hood.” This is the output:

~ $ rbenv init –
export PATH=”/usr/local/var/rbenv/shims:${PATH}”
export RBENV_SHELL=bash
source ‘/usr/local/Cellar/rbenv/1.0.0/libexec/../completions/rbenv.bash’
command rbenv rehash 2>/dev/null
rbenv() {
local command
command=”$1″
if [ “$#” -gt 0 ]; then
shift
fi  case “$command” in
rehash|shell)
eval “$(rbenv “sh-$command” “$@”)”;;
*)
command rbenv “$command” “$@”;;
esac
}

Right. As far as I can tell, this is updating my PATH, setting the RBENV_SHELL to bash, then running whatever exists at /usr/local/Cellar/rbenv/1.0.0/libexec/../completions/rbenv.bash. The rest is doing the rehashing bit, I gather—I’ll dig more deeply into this another day, I think. Okay!

Side note: this line used to be in my ~/.bashrc file. I was having trouble getting my Ruby linter to work in Sublime, and then I found out that it needs to be in ~/.bash_profile (long PDF; the relevant part is on page 49 of the file/page 43 according to the printed page numbers). I moved it, and rubocop is working again, so I’m happy with that for now.

Wrapping Up

Whew
Okay! That’s one file down. I deleted three lines and got rid of that pesky repeated welcome message, so that’s good. I also have a ton of questions (do you know about these things? are you willing to help out a well-intentioned and somewhat confused newbie?).

A friend commented on my last post to recommend, among other things, an O’Reilly book on learning the bash shell. (Huge thanks to him and to everyone else who’s given advice/helped answer questions so far!) Since then, I’ve heard from several other people that getting comfortable with the command line is one of the best things I can do to make myself a better, more fluent engineer. That advice plus this process plus the recent Twitter kerfluffle around this HackerNoon article about JavaScript tool/framework proliferation (and in particular, this excellent thread by Safia Abdalla about what things are actually important for engineers to learn)—all of this has reinforced my desire to be able to be willing to open up the hood, ask questions, and understand what’s going on behind the code/scenes.

I’m mixing my metaphors, but the point is: I’m having fun, and I can’t wait to write up what I’ve learned about my ~/.bashrc file in Part 3, coming soon!

Notes and Questions

Do you know the answer to any of these? Are you willing to share? Please do! Comments/emails/tweets all welcome!

1. Still not 100% clear on when to use/not to use export, or what “subprocesses” and “subshells” mean in this context. When I open Terminal on my Mac, I think that I’m entering (running? using?) the bash shell. From there, I’m not sure what a subshell would be. A subprocess could potentially be something within my shell, like irb or pry or node.

2. I’m using a 2010 MacBook Pro, running OS 10.11.6 (El Capitan). Do I need this line, and if so, is it in the right place? Relatedly: is there a way to find out what the “default” PATH is, sans any changes made by the user in any of their bash init files? Predictably, echoing out my entire PATH gives me a giant mess (removed the colons and separated this into lines for better readability):

3. Does anyone know what the exact differences between line 2 and lines 6-8 are, other than syntax, if any? I chose to leave in the shortest/most compact version (test), but I’d be curious to know if there’s a best practice or preferred standard around when to use test vs if statements.

4. While we’re on best practices: is there a best practice for where to put any necessary export PATH statements, and/or in what order?

5. Corrections/clarifications here welcome!

6. What does rbenv autocompletion do? What does it autocomplete?

Resources

Braving Bash, Part 1

In which I face my fears and finally decide to learn what’s happening in ~/.bash_profile and ~/.bashrc.

At some point in early grade school, after I had exhausted my Jetpack attention span and my ideas for Hypercard-based animated art, I decided I would explore all of the settings I could find on my parents’ Macintosh SE. I was feeling very knowledgable, right up until the moment I stumbled onto the Sad Mac:

Sad Mac

Cue panic.

My dad assures me “the sad Mac was way more common in those days—the MacOS was easier to break,” but even so: since then, I’ve been a bit squeamish about messing around under the hood of my computers.

And then I decided to learn how to code, which—once you make it past online tutorials like Code Academy and Free Code Camp—almost always starts, in my experience, with being told to run a bunch of commands in Terminal and/or paste a bunch of code into your ~/.bash_profile and/or ~/.bashrc files. If you’re lucky, these instructions come with explanations, but often, you have to take it on faith.

I’ve done my best to ignore the creeping feelings of unease and the shades of decades-old Sad Mac panic for several years, dutifully following the instructions and watching these files grow more and more bloated.

When I started at GA, we were given around 20 lines of code to paste into the two files. The next time I opened up Terminal, I saw this:

Last login: Tue Sep 27 11:39:11 on ttys003
You have new mail.
[1;90m
—————————-
Loaded ~/.bashrcTo edit run $ bashedit
To refresh run $ bashrefresh

You are: Rebekah
You’re in: /Users/Rebekah

All aliases…$ alias
—————————-
[1;90m
—————————-
Loaded ~/.bashrc

To edit run $ bashedit
To refresh run $ bashrefresh

You are: Rebekah
You’re in: /Users/Rebekah

All aliases…$ alias
—————————-
~ $

That’s not a copy and paste error: I was getting TWO COPIES of a welcome message I didn’t remember setting but had mostly ignored for several years because everything else seemed to function well enough.

Two copies. Of a message I can’t remember asking for. That starts with 1;90m, which, for all I knew, could be CRITICALLY IMPORTANT SUPER SEKRIT BASH CODE or, you know, a typo.

That's enough!

It was time to fix this.

Step One: Actually look at the code

My approach to all things bash-related for as long as I can remember has been to open up the file(s) using nano, paste in whatever I’m told to paste in wherever I’m told to paste it (usually at the very top or very bottom), save, and close out as quickly as possibly to avoid breaking things.

Pro tip: this is not a good way to understand how things work.

This time, I copied the contents of each file to a separate file so I could “safely” open them up, annotate them, and experiment without—I hoped—bricking my laptop.*

Here’s my ~/.bashrc:

And here’s my ~/.bash_profile:

WAT

Step Two: Ask questions

Now that I had code to look at, I could start googling.

First up: what’s the difference between these two files? Stack Exchange says:

.bash_profile is executed for login shells, while .bashrc is executed for interactive non-login shells.

When you login (type username and password) via console, either sitting at the machine, or remotely via ssh: .bash_profile is executed to configure your shell before the initial command prompt.

But, if you’ve already logged into your machine and open a new terminal window (xterm) then .bashrc is executed before the window command prompt. .bashrc is also run when you start a new bash instance by typing /bin/bash in a terminal.

Cool. I log into my machine every time I restart it or wake it up, and I started this whole journey because of what I was seeing when I opened a new Terminal window. Sounds like I should be looking at .bashrc then. Oh, but wait—there’s more:

if you add the following to your .bash_profile, you can then move everything into your .bashrc file so as to consolidate everything into one place instead of two:

if [ -f $HOME/.bashrc ]; then
  source $HOME/.bashrc
fi

Interesting. I have something pretty similar in lines 6-8 of my .bash_profile:

It’s the same code, minus the $HOME part of the file path. Some more googling leads me to The Linux Documentation Project’s Bash Guide for Beginners, which tells me that -f will be “True if FILE exists and is a regular file.” source means run the code in the file.

To sum up: if a .bashrc file exists in the $HOME directory (in my own .bash_profile, this is written as ~/.bashrc, which means the same thing), then run all of the code it contains.

Okay! Now we’re getting somewhere, sort of: I know that I have two files, and I know that, given how they’re currently set up, they’re both executing when I open a window in Terminal.

Next up

In Part 2: what is all that executable code doing?

Notes and questions

* Is this a thing that’s even possible to do from ~/.bash_profile? It’s been a fear of mine for years. If you know the answer (or can share a good resource), please let me know.

Resources

The Linux Documentation Project’s Bash Guide for Beginners, by Machtelt Garrels

General Assembly WDI, Week 5

Rails is actually a pretty good distraction from the first presidential debate-slash-impending fall of America.

(Apologies in advance if this is more scattered than usual—trying to distract myself from the most painful parts of the first Clinton/Trump presidential debate by blogging.)

Prework

We had some fairly significant studying to do over the weekend, so I’m splitting it into its own section.

The SOLID Principles

We read about SOLID design principles, starting with “Design Principles and Design Patterns” by Robert C. Martin. Delving into these five principles helped scratch some of the itch I’ve been feeling since handing in my Tic-Tac-Toe project: sometimes jumping in and hacking bits off of a large project and tackling whatever I can tackle in order to break the problem down and get it done is exhilarating. Piecemeal != coherent, though, and it’s nice to know there are established guidelines for thinking about a more orderly approach.

The basic gist: bad design is caused by bad dependencies. It’s rigid (difficult to change), fragile (one change causes multiple breaks), immobile (code can’t be easily reused), and viscous (optimal changes are too hard and take too long; it’s easier and faster to circumvent the system). Good object-oriented design uses “dependency firewalls” to help avoid these problems.

  • Single Responsibility Principle: Classes should only do one thing.
  • Open Closed Principle: “A module should be open for extension but closed for modification.” Write modules that can be extended without having to modify them. Rely on abstraction: don’t hard code in a bunch of if/else or switch statements that lock down specific behaviors within a module.
  • Liskov Substitution Principle: “Subclasses should be substitutable for their base classes.” Subclasses should honor the “contracts” of their base classes—they shouldn’t have stronger preconditions (i.e., they shouldn’t need additional things to be true before they’re called), and they shouldn’t have weaker postconditions (i.e., they shouldn’t guarantee that fewer things are true after they’re called).
  • Interface Segregation Principle: Don’t overload a class with methods that all its clients don’t need. It’s better to have multiple small, specific client interfaces than a single large, general interface. Separate methods into different interfaces, and inherit only those that are necessary into a class.
  • Dependency Inversion Principle: “Depend upon Abstractions. Do not depend upon concretions.” High-level things shouldn’t rely on mid-level things that rely on detailed things. Instead, everything should rely on abstract things, which are less likely to break or be changed.

Sandi Metz’s rules

Sandi Metz is a developer and author who specializes in object-oriented programming. Her four rules for developers are focused on keeping things clean and modular in order to help adhere to the SOLID principles. The rules are:

  1. Class shouldn’t be >100 lines
  2. Method shouldn’t be > 5 lines
  3. Methods shouldn’t take >4 parameters (each hash option is 1 parameter)
  4. Controllers can instantiate only one object. Views can only know about one instance variable, and views should only send messages to that object.

Day 20: Code Retreat

Monday gave us a chance to put some of these principles into practice: after a quick discussion on modules (the basics: classes in Ruby can only inherit from one other class. Using modules (mixins) lets us pull in different sets of behaviors/methods and make them available to the class), we spent the rest of the day on a single problem: Conway’s Game of Life. The twist: every 15-45 minutes, we had to wipe the slate clean and start over with a different partner and a different set of constraints. These were the rules:

  • “caveman coder”: We were only allowed a dry erase market and a section of whiteboard.
  • “navigator-driver”: one person types, the other person directs
  • “silent”: can only communicate through comments in the code
  • “flat files”: write methods so things aren’t overly nested
  • “sandi’s rules”: no classes > 100 lines, no methods > 5 lines, etc.
  • “many to one”: one driver, everyone else in the class is navigating
  • “git happens”: we were forced to run git reset --hard HEAD at frequent, random intervals
  • “hot potato”: in a team of four, switch who’s working on the code every 5 minutes

This was both incredibly fun and incredibly frustrating. My takeaways: I like to start with constraints: the board size, the edge case cells. After watching a screencast on using TDD to approach Conway’s Game of Life and talking to others in class, I realized that some people prefer to start with smallest unconstrained piece, ignore the constraints as long as possible, and build from there. This is a totally foreign way of thinking for me, and I’m still struggling to wrap my head around it—even a week later, as I try to process it, my brain is shrieking “BUT…. BUT…. BUT!!!!” Being exposed to this way of thinking and having to pair program with people who tackle problems this way was good for me, though, and I’m hoping to bring a bit more of this kind of thinking into my work, if only as a lightweight experiment at first, and see how it affects my code.

Day 21

Ruby on Rails logo

I’m SO EXCITED to start learning Rails. I’ve used (and am TA-ing for a class on) Laravel, and every time I tell anyone that, I feel like the response is always about how much better Rails is. A few points of comparison so far:

  • The list of ‘uncountables’ in Laravel has long been one of my favorite things (see, e.g., bison, coreopsis, emoji, moose, plankton, pokemon, swine). To be honest, I’m finding the Rails list (in total: equipment information rice money species series fish sheep jeans police) to be sadly lacking.
  • The Rails doctrine is pretty fantastic. I 100% support the idea that “constraints liberate even the most able minds.”
  • Rails gives you the ability to set up example data (used for testing) separately from seed data (necessary for your app to function). This division doesn’t exist by default in Laravel.
  • Serializers let you control what data you pass back (to exclude timestamps or secret/private information, for example). I haven’t used this in Laravel before (it sounds like serializers come into play when you’re building APIs), but the functionality exists.
  • It sounds like I won’t get the chance to compare views in Rails/Laravel—GA only teaches Rails as a way to create APIs (all the front-end work is done as single-page applications).

Before we got too far into Rails, though, we had to learn about PostgreSQL. So far: no real opinions on this vs MySQL, though I am amused by PostgreSQL’s claim to be “the world’s most advanced open source database” compared to MySQL’s “most popular open source database.”

It was good to brush up on my SQL and to play around with psql (a client for working with Postgres), mostly because I can’t wait to start working with data models that I get to design. Front-end is fun, but back-end makes me feel powerful.

Day 22-24

Wednesday kicked off a several-day process of building three different basic APIs: a library API with books and authors, a clinic API with patients and doctors, and a cookbooks API with recipes and ingredients. We learned how to get a Rails app up and running; how to create controllers, models, migrations, and serializers (and how to use scaffold to create all four at once), how to use rails console to interact with our apps through pry, and how to use rails db to interact with the database using psql. A few related notes/tidbits:

  • Sometimes Rails servers don’t close all the way, which prevents you from opening up a new one. To fix: open Activity Monitor and look for spring, ruby, and rails. Kill anything related to those three terms, then try again.
  • Running commands using bundle exec uses the versions you have stored in your gem file instead of global versions.
  • In SQL/Postgres, foreign keys don’t get indices by default. Indices make querying fast. If you’re using an id in a query, write an index. (When you set up references in Rails, indices appear to be automatically created.)
  • SQL Joins: inner joins between tables A and B cover the intersection of data between the two tables. Left joins cover all of table A, plus additional data from table B that meet the join condition. Right joins cover all of table B, plus additional data from table A that meet the join condition. Full joins give you everything.

General Assembly WDI, Week 4

Rubber ducks, Das Sound Machine, and spaceship operators.

Day 15

Monday was project presentation day: we each got five minutes to present our Tic-Tac-Toe games, and two minutes to field questions. I found myself strangely nervous—I was proud of what I had accomplished, but the thought of having to stand up and talk about it, justifying my decisions and explaining my approach, was terrifying.

The order of our presentations was randomized, and I drew one of the last slots, which gave me some time over lunch to open up a couple of different tabs and zoom in on a few things I wanted to talk about in my code—specifically, how I automatically logged users in when they signed up (this Stack Overflow question on passing additional data to AJAX callbacks, which I mentioned in my last weekly write-up, was helpful) and how I checked whether a game had been won or tied. I was proud of the first, and not so proud of the second—I still don’t think a Tic-Tac-Toe game should take 60 lines of code to figure out if it’s over, and near the top of my to-do list is streamlining this.

Taking the time to tee up a browser tab for each of my talking points helped the presentation go smoothly, and at the end, the instructors gave us each a rubber duck, then sent us home early to get some rest. All in all: a good day.

Day 16

Our assignment on Monday night was to walk through a couple of intro to Ruby tutorials and, if we had time, to read Why’s (Poignant) Guide to Ruby. It….

I….

It’s hard to describe.

You should probably read it for yourself.

And then, if it sparks your curiosity as much as it did mine, read Annie Lowrey’s 2009 piece for Slate, “Where’s _why?.”

I read the first half on Monday night and most of the second half on my phone while I was on the train on Tuesday morning, which didn’t in any way do this book justice. I think I need to go back and reread two or three more times at least, preferably on a large screen so I can properly appreciate the sidebars and illustrations.

Jumping into Ruby on Tuesday morning after working with JavaScript for the past year and PHP for several years before that felt like the Barden Bellas felt when they first saw Das Sound Machine.

A few initial notes/impressions (please don’t use these to teach yourself anything about Ruby—this is all Day One knowledge that may or may not be accurate/correct):

  • You don’t need parentheses to call a method without parameters in Ruby. You also don’t need them, even if you’re passing arguments, unless you want to use the results of that call immediately and chain on additional methods.
  • Ruby uses symbols, which, depending on where you read about them, are “lightweight strings,” “a string and a number,” or “the name of the variable, not the value of that variable.” My best shot at describing them: symbols represent a unique spot in memory. They have the same value everywhere in your program. They’re often used in class definitions.
  • Ruby doesn’t have an increment (++) operator. Use += 1 instead.
  • Floats and fixed numbers (integers) are distinct types in Ruby. 7 / 2 will return 3 in Ruby, not 3.5. If you want 3.5, you have to attach .to_f to either the 7 or the 3 before dividing.
  • .to_i truncates, it doesn’t round.
  • Ruby hashes do not allow you to access their keys through a dot notation; you must use square braces.
  • Ruby lets you access values from the end of an array: array[-1] will be the last element in the array.
  • a.equal?(b) will return true if and only if a is the same object in memory as a. Use .eql? to test if the values of a and b are the same.
  • Along the same lines, == is used to test whether values are equal. === is not used to test equality at all, but rather to test for inclusion (is a value in a particular range?). See this Stack Overflow question for details.
  • puts vs p vs print:
    • puts calls .to_s on an object, appends a new line, and prints it.
    • print calls .to_s on an object and prints it without appending a new line.
    • p calls .inspect on an object, appends a new line, and prints it. This can be helpful for debugging because it doesn’t automatically convert everything to a string.
  • Remember my excitement about fat arrow functions in JavaScript? Ruby uses the same symbol (=>) in hash definitions, only it’s called a “hash rocket.”

Day 17

  • More on symbols: Always use symbols as keys when writing hashes. Symbols perform better because Ruby compares them using their object IDs, instead of comparing strings letter by letter.
  • You can search for symbols using Symbolhound. No more frustrating Googling for the Paamayim Nekudotayim!
  • Ruby uses blocks instead of callbacks.
  • In JavaScript, all arguments are optional. JS will try to run the function even if you don’t provide the correct number of arguments. In Ruby, all named arguments are required. In other words: Ruby checks arity (the number of arguments or operands that the function takes); JS does not.
  • The exclamation point after an enumerable method in Ruby means that the method alters the original array.
  • All operators in Ruby are methods. 2 + 2 is the same thing as 2.+(2).

Day 18

We started talking more seriously about enumerables today.

  • Ruby has three basic types of ordered lists: hashes, arrays, and ranges.
  • All of these lists are enumerable, meaning they can take advantage of Ruby’s enumerable methods.
  • In Ruby, hashes have order (in most programming languages, they don’t).
  • In order to use these methods, a class must include the Enumerable module (include Enumerable) and define an each method.
  • Other things—files, for example—are also enumerable. Anything you can iterate over is an enumerable.

We also talked about classes.

  • Ruby is a “classical” language; this means that Ruby uses classes to define and instantiate new objects. JavaScript is a “prototypal” (not prototypical) language; it uses prototypes.
  • Ruby classes have an initialize method that acts like a JS Constructor function. The instance variables set within this method are private by default; “getter” and “setter” methods defined in the class provide access to these variables outside the class definition.
  • Ruby convention is for “getter” and “setter” methods to be named, respectively, propertyName and propertyName=. We can also use attr_reader :varname (getter), attr_writer :varname (setter), and attr_accessor :varname (getter & setter) to create simple versions of these methods.

Day 19

A high-level view of Ruby (made by Artem S.):

Ruby Core Object Model by Artem S.

And a handdrawn version by Jerome Dalbert:

Ruby Core Object Model by Jerome Dalbert

We talked a bit more about enumerables today, and introduced comparables: like enumerables in Ruby, comparables are anything that can be compared, that uses the comparable methods defined in the Comparable module, and that defines a <=> method (aka the “spaceship operator,” apparently so named because it reminded PERL expert Randal L. Schwartz of the spaceship in a Star Trek game).

We also talked briefly about how defining <=> on a comparable class allows you to use the .sort method, which made me wonder what Ruby’s built-in sorting method is. Fun fact: .sort_by in Ruby uses a Schwartzian transform, a sorting algorithm named after the aforementioned Randal L. Schwartz.

A few other notes:

  • Ruby has implicit returns: the last line is always what’s returned.
  • Ruby also has an implicit receiver: you don’t have to use self when you’re calling a getter method on an instance from within a class (though you do have to use it when calling a setter method).
  • super will call the same method defined in the parent or superclass and give you the result.
  • .new is a Class method that calls the Instance method .initialize. .new allocates memory for a new object, creates that object, calls .initialize, and returns the object.
  • self will point to one of three runtime contexts: global context, object context, or class context.
  • In Ruby documentation, # indicates an instance method, while . indicates a class method.
  • def methodname inside a class is how you define an instance method. def self.methodname inside a class is how you define a class method

To sum up

Everyone I know who uses Ruby tells me it’s orders of magnitude better than PHP. I’ve people clap their hands in glee when I told them I’d be learning Ruby as part of GA. I’m hoping to feel some of that excitement soon, but for now: