Rails on Maui

Programming in Paradise

Pry, Ruby, and Fun With the Hash Constructor

| Comments

I recently had a chance to pair with Justin Searls of TestDouble, and we got to chatting about pry and the odd Hash[] constructor. Here’s a few tips that you might find useful.

The main reason I use pry are:

  1. Testing Ruby syntax.
  2. Documentation and source code browsing.
  3. History support.
  4. cd into the an object to change the context, and ls to list methods of that object.

Pry Configuration

To install pry with rails, place this in your Gemfile

1
gem 'pry-rails', :group => :development

Then run bundle install. Then run rails console. That gets you the default pry configuration. At the bottom of this article is my ~/.pryrc (gist). Create that file and then run rails c (short for rails console).

You’ll see this useful reminder of the customizations:

Helpful shortcuts:
h  : hist -T 20       Last 20 commands
hg : hist -T 20 -G    Up to 20 commands matching expression
hG : hist -G          Commands matching expression ever used
hr : hist -r          hist -r <command number> to run a command
Samples variables
a_array: [1, 2, 3, 4, 5, 6]
a_hash: { hello: "world", free: "of charge" }

Testing syntax: Hash[]

The Hash[] method is one of the odder methods in Ruby, and oh-so-useful if you’re doing map, reduce types of operations.

For example, how do you transform all the keys in a hash to be uppercase?

How about if we try this in pry (note, a_hash defined in my .pryrc).

[1] (pry) main: 0> a_hash
{
    :hello => "world",
     :free => "of charge"
}
[2] (pry) main> a_hash.map { |k,v| [k.to_s.upcase, v] }
[
    [0] [
        [0] "HELLO",
        [1] "world"
    ],
    [1] [
        [0] "FREE",
        [1] "of charge"
    ]
]

OK, that gives us an Array of tuples.

Then run these two commands. _ is the value of the last expression.

> tmp = _
> Hash[tmp]
{
    "HELLO" => "world",
     "FREE" => "of charge"
}

Bingo! Now let’s dig into this a bit more.

Memoization with Hash

Hash has another unusual constructor useful for memoizing a method’s return value when parameters are involved. Justin Weiss wrote a good article explaining it: 4 Simple Memoization Patterns in Ruby (and One Gem).

Here’s a quick sample in Pry:

[5] (pry) main: 0> hh = Hash.new { |h, k| h[k] = k * 2 }
{}
[6] (pry) main: 0> hh[2]
4
[7] (pry) main: 0> hh[4]
8

You can even use an array for the key values:

[8] (pry) main: 0> hh = Hash.new { |h, k| h[k] = k[0] * k[1] }
{}
[9] (pry) main: 0> hh[[2,3]]
6
[10] (pry) main: 0> hh[[4,5]]
20

Browsing Documentation and Source

It’s super useful to be able to see the documentation for any method easily, which you can do by the ? command. Similarly, you can also see the source, by using $.

[3] (pry) main> ? Hash[]

From: hash.c (C Method):
Owner: #<Class:Hash>
Visibility: public
Signature: [](*arg1)
Number of lines: 12

Creates a new hash populated with the given objects.

Similar to the literal { _key_ => _value_, ... }. In the first
form, keys and values occur in pairs, so there must be an even number of
arguments.

The second and third form take a single argument which is either an array
of key-value pairs or an object convertible to a hash.

   Hash["a", 100, "b", 200]             #=> {"a"=>100, "b"=>200}
   Hash[ [ ["a", 100], ["b", 200] ] ]   #=> {"a"=>100, "b"=>200}
   Hash["a" => 100, "b" => 200]         #=> {"a"=>100, "b"=>200}

Hmmmm…. Hash[] also takes a plain array. Let’s try that:

[16] (pry) main: 0> a_array
[
    [0] 1,
    [1] 2,
    [2] 3,
    [3] 4,
    [4] 5,
    [5] 6
]
[17] (pry) main: 0> Hash[*a_array]
{
    1 => 2,
    3 => 4,
    5 => 6
}

Neat!

Also note that you can see instance methods by prefixing the method name with # or using an actual instance, like this:

[19] (pry) main: 0> ? Hash#keys

From: hash.c (C Method):
Owner: Hash
Visibility: public
Signature: keys()
Number of lines: 5

Returns a new array populated with the keys from this hash. See also
Hash#values.

   h = { "a" => 100, "b" => 200, "c" => 300, "d" => 400 }
   h.keys   #=> ["a", "b", "c", "d"]
[20] (pry) main: 0> ? a_hash.keys

Browsing History

History expansion in pry is also nice. As mentioned above, my .pryrc has 4 history aliases.

h  : hist -T 20       Last 20 commands
hg : hist -T 20 -G    Up to 20 commands matching expression
hG : hist -G          Commands matching expression ever used
hr : hist -r          hist -r <command number> to run a command

Let’s try those out. It’s import to note that the -T tails results after doing the grep of the whole history. I.e., the -T 20 strips the results down to the last 20 that matched.

Show last 20 commands.

[10] (pry) main: 0> h
1: a_hash
2: a_hash.map { |k,v| [key.upcase, v] }
3: a_hash.map { |k,v| [key.to_s.upcase, v] }
4: a_hash.map { |k,v| [k.upcase, v] }
5: a_hash.map { |k,v| [k.to_s.upcase, v] }
6: tmp = _
7: Hash[tmp]
8: ? Hash[]
9: $ Hash[]

Grep all commands for upcase and show last 20 matches.

[11] (pry) main: 0> hg upcase
2: a_hash.map { |k,v| [key.upcase, v] }
3: a_hash.map { |k,v| [key.to_s.upcase, v] }
4: a_hash.map { |k,v| [k.upcase, v] }
5: a_hash.map { |k,v| [k.to_s.upcase, v] }

Grep all commands for upcase and show all. The history of my example is short so below is the same as above. If the history were longer, as it typically will be, then you might get pages of results!

[12] (pry) main: 0> hG upcase
 2: a_hash.map { |k,v| [key.upcase, v] }
 3: a_hash.map { |k,v| [key.to_s.upcase, v] }
 4: a_hash.map { |k,v| [k.upcase, v] }
 5: a_hash.map { |k,v| [k.to_s.upcase, v] }
11: hg upcase

cd and ls within Pry

I love to use cd and ls in pry.

  1. cd changes the context of pry, a bit like the current directory in the shell, except for Ruby objects. And classes are objects too!
  2. ls lists methods available on an object, a bit like listing files in the shell.
[22] (pry) main: 0> cd a_hash.keys
[26] (pry) main / #<Array>: 1> length
2
[27] (pry) main / #<Array>: 1> first
:hello
[28] (pry) main / #<Array>: 1> last
:free
[29] (pry) main / #<Array>: 1> ls
Enumerable#methods:
  all?  chunk           detect     each_entry  each_with_index   entries   find      flat_map  index_by  lazy   max     member?  min_by  minmax_by  one?           partition  slice_before  sum     to_table
  any?  collect_concat  each_cons  each_slice  each_with_object  exclude?  find_all  group_by  inject    many?  max_by  min      minmax  none?      original_grep  reduce     sort_by       to_set  to_text_table
JSON::Ext::Generator::GeneratorMethods::Array#methods: to_json_without_active_support_encoder
Statsample::VectorShorthands#methods: to_scale  to_vector
SimpleCov::ArrayMergeHelper#methods: merge_resultset
Array#methods:
  &    []=      clear        cycle       drop_while        fill        frozen?       inspect  permutation         push                  reverse       select     slice!      third                          to_gsl_integration_qaws_table        to_qaws_table  unshift
  *    abbrev   collect      dclone      each              find_index  grep          join     place               rassoc                reverse!      select!    sort        to                             to_gsl_vector                        to_query       values_at
  +    append   collect!     deep_dup    each_index        first       hash          keep_if  pop                 recode_repeated       reverse_each  shelljoin  sort!       to_a                           to_gslv                              to_s           zip
  -    as_json  combination  delete      empty?            flatten     in_groups     last     prefix              reject                rindex        shift      sort_by!    to_ary                         to_gv                                to_sentence    |
  <<   assoc    compact      delete_at   eql?              flatten!    in_groups_of  length   prepend             reject!               rotate        shuffle    split       to_csv                         to_h                                 to_xml
  <=>  at       compact!     delete_eql  extract_options!  forty_two   include?      map      pretty_print        repeated_combination  rotate!       shuffle!   suffix      to_default_s                   to_json                              transpose
  ==   blank?   concat       delete_if   fetch             fourth      index         map!     pretty_print_cycle  repeated_permutation  sample        size       take        to_formatted_s                 to_json_with_active_support_encoder  uniq
  []   bsearch  count        drop        fifth             from        insert        pack     product             replace               second        slice      take_while  to_gsl_integration_qawo_table  to_param                             uniq!
self.methods: __pry__
locals: _  __  _dir_  _ex_  _file_  _in_  _out_  _pry_

It’s worth noting that you can see the modules declaring the methods of the object.

To see more of what pry can do for you, simply type help at the command line.

My ~/.pryrc file

Create a file in your home directory called ~/.pryrc.

2014 Golden Gate Ruby Conference: Top 10 Reasons to Attend

| Comments

Woo hoo! I’m going to the 2014 Golden Gate Ruby Conference. It’s at UCSF Mission Bay, San Francisco, September 19-20, 2014. I wrote an article about my experience last year, GoGaRuCo 2013: Community > Code. If you’re on the fence about attending, here’s my top reasons on why you should consider attending. I recommend not delaying signing up, as last year I saw folks begging for tickets once the conference sold out. According to Leah Silber, one of the conference organizers, GoGaRuCo has sold out every year, except for maybe year one.

Top 10 Reasons To Attend GoGaRuCo

  1. San Francisco is a great town to visit, and there’s no better month to visit than September as dense fog is least likely!
  2. It’s relatively small conference, compared to Rails Conf, and I find that much more engaging and relaxing. The attendees seem to be a mix of highly passionate Rubyists, mostly locals, with a mix from around the world.
  3. A one track conference is nice in that you don’t have to worry about picking which talks to attend.
  4. There’s a 15 minute break between each talk to socialize with fellow attendees or speakers. Socializing is why you come to these talks!
  5. Yehuda will likely come up with some interesting talk!
  6. Ruby programming is really more of an art and passion than work, and the people that attend GoGaRuCo reflect this!
  7. You’ll probably make a few new friends and leave inspired.
  8. The food is super, both at the conference and throughout the city. And the evening events last year were great as well.
  9. There’s probably going to be a job board, just in case that interests you.
  10. You won’t need any more T-shirts for another year!

Photography

I’m volunteering as the official photographer of GoGaRuCo. My mission is to “get 2-3 good shots of each speaker, a couple of audience shots during each days lunch and breaks, a shot or two of each exhibitor table, 2-3 team photos, and a smattering of everything else.” So please don’t be shy and ask to have your photograph taken.

Here’s a sample of shots I took at GoGaRuCo 2013. Tons more photos are linked here: GoGaRuCo 2013: Community > Code.

Available for Consulting

If you’d like to meet me around the time of GoGaRuCo, don’t hesitate to email me to try to meet up in person. Possibly you might have a project that could use my help?

On a personal note, I spent the better part of my adulthood in San Francisco, so I’ve got tons of friends there. All my consulting clients tend to be from the Bay Area as well.

Remote Pair Programming Tips Using RubyMine and Screenhero

| Comments

I had the opportunity to spend the entire workday remote pair programming from my office in Maui with a San Francisco client from Cloud City Development. We used our normal tools of RubyMine, Chrome, and iTerm2 on a 27” Cinema Display shared via Screenhero. While remote will probably never be 100% as good as true in-person pairing, it’s getting very close! Here’s some tips for effective remote pair programming. Scroll down to the bottom for the TLDR if you’re short on time. Overall, I would highly recommend remote pairing with RubyMine on a full 27” Cinema Display, using an iPad with a Google Hangout for eye contact!

Here’s a very detailed video of how to do remote collaboration:

Telepresence Using Video Chat on iPad

Per the recommendation of Tim Connor of Cloud City Development, I started using an iPad for telepresence for only the video, using Google Hangouts, muting the microphone on the Hangout, and using the audio on Screenhero. While one can run Google Hangouts on the laptop, it can really suck up the CPU. Note, an iPhone or probably an Android phone or table would work equally as well. In terms of the audio, the microphone and speakers are better on the computer. If one is using the laptop for the telepresence video, and using multiple screens, it’s key to use the camera on the screen where one will be looking at the Hangout, and not at the Screenhero screen. As shown from the below pictures, it’s key that it’s obvious when the pairing partners are looking at each other versus at Screenhero. Incidentally, Screenhero did not suffer from any degradation when combined with the Google Hangout, regardless of using the Hangout on the laptop or mobile device.

In the below images, note where our eyes are focused.

Talking to each other, making eye contact

Both looking at screen

Talking to each other, making eye contact

Shaka from Steve and Justin

Screenhero

We both used Screenhero on Macs. I’ve done plenty of remote pair programming using Google Hangouts, but typically only one person sharing the screen drives the code. Screenhero allows true screen sharing such that both programmers can do the typing and mousing. With the shared screen being a 27” Cinema display, I set my Screenhero window to full screen and the resolution was nearly perfect. Yes, when scrolling and switching apps, there is a slight delay, but it was extremely manageable to the point that I almost would forget that I’m working on a computer 3000 miles away. Although there’s a slight slowness in seeing keys that you type, it’s minor enough that it’s not a nuisance. The dual cursor support works great. Here’s a video demo of the dual cursor support.

RubyMine IDE

Both I and my pairing partners were already using RubyMine, so using RubyMine was a natural choice over trying to pair with the conventional remote pairing setup of tmux and Vim. RubyMine combined with Screenhero, the same size big screens, fast computers, and very good broadband resulted in a productive pairing setup. One thing I hear about Vim setups is that pair programmers tend to not customize their Vim keymaps. With RubyMine, that’s not an issue thanks to a feature called “Quick Switch Scheme” which allows very fast switching of keyboard bindings. I’m a Vim user (IdeaVim), and I would have been crippled without my favorite RubyMine Vim bindings. I like the “Quick Switch” feature so much that I made a short screencast on this feature, displayed below.

RailsConf 2014

| Comments

My Talk: Concerns, Decorators, Presenters, Service Objects, Helpers, Help me Decide

(Lack of) Live Coding in my Talk

Due to time constraints, I chose to skip the live coding I had prepared to do in my talk. Please let me know if you’d be interested in a screencast walking through the sample code. I will create one if there is sufficient demand.

Rocking With Tmux, Tmuxinator, Guard, Zeus, and iTerm2 for Rails Development

| Comments

What’s the most effective way to:

  1. Start several different processes for Rails, such as Zeus, Rails server, rspec, resque, and the scheduler.
  2. Have the output for each process in a separate tab.
  3. Not have the process pause when you scroll the output, as happens in tmux.

Here’s a short demo of using tmuxinator to get a project running in several iterm2 tabs:

Why Guard?

I use Guard for:

  1. Automatically running rspec tests based on changes in either tests or source files. Together with Zeus, I haven’t found a faster way to get immediate feedback from tests. Pro tip: Learn how to use :focus with your specs to configure exactly what tests to have guard run.
  2. Automatically restarting the server when needed. For example, if you change gems or routes, you need to restart the server.

While I love running Guard with Zeus, Spring is the default in Rails 4.1, so I’ll probably give that a try in the near future.

Why Tmuxinator and Tmux?

Tmuxinator is awesome for configuring the layout of several processes.

Here’s a sample tmuxinator file.

When I run the command

1
mux my_project

And then I see the following. This is way easier than opening up tabs in iTerm2 and running commands every time.

The main problem with this setup is that if you scroll a window backwards (using the tmux keyboard bindings), and you don’t un-scroll, then the process pauses, such as the Rails server. That’s super annoying. Often I’m running specs, and I want to scroll back to see a stack trace, but that prevents the continuation of the test run! Here’s a short discussion of the issue.

Capybara PhantomJs Poltergeist Rspec Tips

| Comments

I’ve added a page of tips on integration (aka feature spec) testing using Capybara, PhantomJs, Poltergeist, and Rspec.

Some of the tips include:

  1. Favorite test configuration (gems, spec_helper, etc.) for feature specs.
  2. How to troubleshoot and debug feature specs
  3. My setup for using Zeus with parallel-tests, including a rake task for setting up the databases.
  4. Tricky testing:
    1. Auto-complete dropdowns (some handy utility methods).
    2. Hover effects (easy now!)
    3. AJAX

I’ll try to keep this page of tips updated as my test configuration evolves.

Org-Mode Octopress Setup V2

| Comments

Note: This is a refresh of my original post from April, 2013 to adjust for Emacs 24.3 and org-mode 8.2.x

WordPress seemed like a good blogging platform, but it just didn’t feel right. I spend all my day editing text files using vim key-bindings, and I love Org Mode for all non-coding writing. If you don’t know Org Mode, it’s like having Markdown mode on steroids. You can have a numbered list in Markdown, but org-mode lets you re-order the list, and that’s just the beginning. Editing blog documents in the WordPress editor felt almost as bad as being told to use MS Word. I found that ergonomics of Org Mode, including all the goodness of recent versions of Emacs, including Evil (Vim emulation), just made organization of creative thoughts so much more enjoyable.

So I bit the bullet one weekend, and dove into Octopress, publishing my first article, Octopress Setup with Github, Org Mode, and LiveReload. The solution presented in that article Introducing Octopress Blogging for Org-Mode stopped working when I upgraded Emacs to 24.3 and org-mode to 8.2.x. Here’s a rehash of my original article updated to the latest software versions as of March, 2014.

If you used to writing real web applications, rather than know the intricacies of a giant monolithic blogging platform, then the customization of Octopress seems so much more straightforward. This is so much more like the Unix philosophy that so many of us love, which is small and modular, rather than monolithic.

Simple Form and Disabling Buttons on Submit by Default

| Comments

TLDR

Here’s an easy way to have all your SimpleForm submit buttons default to setting data-disable-with so that you don’t get errors when users double click on submit buttons. If you’ve gotten a few ActiveRecord::RecordNotUnique errors that were hard to reproduce, then here’s your solution, with our without SimpleForm. Additionally, using data-disable-with provides the user with nice feedback once a button is clicked.

ActiveRecord::RecordNotUnique Error!

If you’re using Devise, and you get a ActiveRecord::RecordNotUnique error when a new user is signing up, where do you look?

An ActiveRecord::RecordNotUnique occurred in registrations#create:

PG::UniqueViolation: ERROR: duplicate key value violates unique constraint
"index_users_on_email" DETAIL: Key (email)=(somebody@yahoo.com) already
exists. : INSERT INTO "users" ("address", "city", "confirmation_sent_at",
"confirmation_token", "created_at", "default_location_id", "email",
"encrypted_password", "first_name", "last_name", "mobile", "role", "state",
"updated_at", "zip_code") VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11,
$12, $13, $14, $15) RETURNING "id"

At first, I was concerned that my unique index on my users table is not case insensitive. I started going down the road of converting my normal unique index on users.email to this index:

1
CREATE UNIQUE INDEX users_email_ci_idx ON users ((lower(email)));

However, I soon figured out that Devise was already always saving email in the database in lower case via a before_validation hook.

So then I tried to double click the SAVE button, and, BOOM, I got the same error.

data-disable-with=’Processing…’

A little bit of googling quickly revealed some handy rails techniques disabling a submit button after being clicked, namely the setting of attribute data-disable-with: “Some Message…” on both links and buttons. This works nicely to fix the double submit RecordNotUnique error, and it provides some sweet user feedback upon clicking a button. Here’s an example of a SAVE button.

Immediately after clicking the SAVE button, the button disables and the text changes.

Buttons

Example and API: button_tag

1
<%= button_tag "Checkout", data: { disable_with => "Please wait..." } %>

Links

Example and API: link_to

1
<%= link_to "Profile", profile_path(@profile), data: { disable_with: "Processsing..." } %>

SimpleForm Submit Buttons

Even better, this can be done in one place for all SimpleForm submit buttons!

In a file like config/simple_form.rb, place this initialization code:

1
2
3
4
5
6
7
8
SimpleForm::FormBuilder.class_eval do
  def submit_with_override(field, options = {})
    data_disable_with = { disable_with: 'Processing...' }
    options[:data] = data_disable_with.merge(options[:data] || {})
    submit_without_override(field, options)
  end
  alias_method_chain :submit, :override
end

What the bit of code above does is that it:

  1. Opens up the FormBuilder class to add a method submit_with_override.
  2. Modifies options hash’s :data element, setting a default value for key disable_with that will not apply if there’s already a value there, thus allowing the default to be overridden by any individual button.
  3. Calls alias_method_chain which makes is so that a call to submit actually calls submit_with_override and that method can call submit_without_override, which is the original submit method. The pattern of naming the methods with_override and without_override is part of the alias_method_chain call. Pretty darn cool!

Here’s a sample sign-up form that overrides the default “Processing…” label when the SAVE button is clicked.

1
2
3
4
5
6
7
.box.clearfix.box-last
  = simple_form_for resource, as: resource_name, url: registration_path(resource_name), html: { class: ""}  do |f|
    = f.error_notification
    = f.input :first_name, required: false, autofocus: true, label_html: { class: "label-required"}, input_html: {class: ".col-md-4" }
    = f.input :last_name, required: false, label_html: { class: "label-required"}, input_html: {class: ".col-md-4" }
    = f.input :email, required: false, label_html: { class: "label-required"}, input_html: {class: ".col-md-4" }
    = f.button :submit, "SAVE", class: "submit", data: { disable_with: "Creating New Account..." }

Now go and click on some of your submit buttons, and they will all disable and display “Processing…”. On a remote form that returned js.erb, I had to send back this line to reset the submit button:

1
$("#js-some-button").removeAttr("disabled").attr('value', 'ORIGINAL BUTTON TEXT');

Using RubyMine/IntelliJ Regexp Search/Replace

| Comments

RubyMine’s interactive search/replace is awesome. The Regexp feature is especially useful. Not only will it help you edit faster, but it will improve your ability to write RegExp’s in your code. When do you need to use a regexp? Whenever a standard find/replace won’t cut it. For example, if you changing the rspec syntax from one form to another, such as from:

1
2
let(:my_subject) { something }
it { expect(my_subject.value).to eq(some_value) }

to

1
2
subject { something }
its(:value) { should eq(some_value) }

The following screencast shows how you can interactively use the Regexp feature to figure out the right regexp to search for as well as the right replacement.

In this example, I’m replacing one rspec syntax with a replacement one.

it \{ expect\(my_subject\.(\w+)\)\.to eq\((.*)\) }

Replace with:

its(:$1) { should eq($2) }

Here’s a few key tips:

  1. Be sure to first check the regexp check-box if you’ll need that.
  2. As you type each character into the search box, observe if you’re increasing your match area to get what you want.
  3. If a character doesn’t match, then try escaping the character. For example, I had to escape the { and ( as those characters have special meaning in the regexp.
  4. Once you get a match with the right groupings for replacement, then put in the $1, $2, etc. into the replacement box to refine your replacement string.
  5. Then hit Opt-P (or Alt-P) to replace.

This is best shown with this 2 minute screencast.

Migrating From Bash to Zsh

| Comments

I migrated from Bash to Zsh in October and I’m quite thrilled with zsh.

Motivation

What motivated me to finally move?

  1. I no longer used the shell within Emacs. If you have a bash setup that works well in Emacs, don’t try to switch. Since moving from emacs bindings to evil-mode, I am quite comfortable in Vim, so I find myself using iTerm way more than the Emacs shell.
  2. While doing some pair programming with @jakeonrails, I saw the coolness of zsh, which he pointed out to me “was no big deal”, just what’s on the Railscasts Episode on Oh My ZSH.

Tips on Migrating

Here’s a few tips to somebody migrating might find useful:

  1. Try out oh-my-zsh and take a look at the themes examples. The themes seem to be all customizations of the prompt. I’ll share what I came up with at the bottom, which is a modification of the default robbyrussell theme.
  2. While most of your bash code will migrate as-is, this is a good time to clean up some cruft in your files. I like to organize my shell code into small files, each with a particular theme, and then have the .zshrc source those, rather than having a giant .zshrc file.
  3. The oh-my-zsh plugins are way for you to share shell configuration with other members of the community. It’s simple to read what those plugins are doing. Many are just setting aliases. I started to migrate my own configuration code by converting to plugins, but then I realized that that’s overkill. If I ever want to share the configuration, at that point, I can convert to a plugin, which is quite simple.
  4. If you have any shell functions that use [, you might have escape that character for zsh.
  5. If you install zsh plugins, be very careful with any newly installed aliases from the plugins. I previously had gl aliased as ‘git log’ and the git plugin uses gl for git pull, which caused me a huge headache when I ran that within my octopress branch.
  6. You need to escape the ^ character for commands such as git reset HEAD\^

Migration Notes

Escape []

In the third line of this function, I had to escape the [ and the ].

1
2
3
4
5
6
7
8
9
10
opost() {
  cd $OCTO_HOME
  output=$(rake new_post\["${1}"\])
  new_file=$(echo $output | awk '{print $4}')
  base=$(basename $new_file)
  new_location=$OCTO_HOME/source/org_posts/
  mv $OCTO_HOME/$new_file $new_location
  echo created $new_location$base
  cd -
}

My new zsh prompt

To set this up, I created a custom theme called justin808 by doing the following:

  1. Create a theme file oh_my_zsh/custom/justin808.zsh-theme. See below.
  2. Export the theme name.

This is what it looks like in my .zshrc file. The first line is because I moved my ZSH configuration files.

1
2
export ZSH=$HOME/.oh-my-zsh
export ZSH_THEME="justin808"

Here is my theme file oh_my_zsh/custom/justin808.zsh-theme

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
hostname=`hostname`
if [ $hostname != "$HOME_HOST" ] || [ $USER != "justin" ]; then
  host_stuff='%n@%m:'
else
  host_stuff=''
fi  
PROMPT='%{$fg_bold[red]%}➜ %{$fg_bold[green]%}%p ${host_stuff}%{$fg[cyan]%}${PWD/#$HOME/~} %{$fg_bold[blue]%}$(git_prompt_info)%{$fg_bold[blue]%} % %{$reset_color%}'

# display exitcode on the right when >0
return_code="%(?..%{$fg[red]%}%? ↵%{$reset_color%})"

RPROMPT='${return_code}$(git_prompt_status)%{$reset_color%} [%*]'

# RPROMPT='[%*]'
ZSH_THEME_GIT_PROMPT_PREFIX="(%{$fg[red]%}"
ZSH_THEME_GIT_PROMPT_SUFFIX="%{$reset_color%}"
ZSH_THEME_GIT_PROMPT_DIRTY="%{$fg[blue]%}) %{$fg[yellow]%}✗%{$reset_color%}"
ZSH_THEME_GIT_PROMPT_CLEAN="%{$fg[blue]%})"
GIT_PS1_SHOWUPSTREAM=verbose

ZSH_THEME_GIT_PROMPT_ADDED="%{$fg[green]%} ✚"
ZSH_THEME_GIT_PROMPT_MODIFIED="%{$fg[blue]%} ✹"
ZSH_THEME_GIT_PROMPT_DELETED="%{$fg[red]%} ✖"
ZSH_THEME_GIT_PROMPT_RENAMED="%{$fg[magenta]%} ➜"
ZSH_THEME_GIT_PROMPT_UNMERGED="%{$fg[yellow]%} ═"
ZSH_THEME_GIT_PROMPT_UNTRACKED="%{$fg[cyan]%} ✭"

GoGaRuCo 2013: Community > Code

| Comments

This past weekend was my first GoGaRuCo. Here’s a perspective from a newbie, along with lots of photos.

The number one thing I discovered is that GoGaRuCo, like Ruby, is not just about code. It’s about the awesome people and the community.

If you just want to see the talks at GoGaRuCo, don’t attend. All of the talks will be available on web shortly. So why did the conference sell out, with about 200 wait-listed people begging to attend?

GoGaRuCo attendees are madly passionate about programming, especially in Ruby. Most attendees work at start-ups, at web consulting firms, or as freelancers. The common thread is that we all love to program. It’s not work. It’s a passion. And it’s artistic, cutting-edge, relevant, and fun!

Amongst the community, there’s a genuine feeling that we’re all in this together, and the more we can help each other, the better off we and the world will be. This is truly the open source spirit of contributing whatever code you can give back to the community. Consequently, for me, attending the conference was about meeting others who contribute to open-source and learning more about how I can contribute. As a bonus, I got a chance to personally meet the people whom I follow on Twitter, read their blogs, and use their open source.

My Top 14 for 2013 GoGaRuCo

  1. Won’t need to buy any new T-shirts for a long time.
  2. Got a poster tube that doubles as a form for caissons.
  3. No stress over picking which talks to attend, with one track.
  4. Can, but won’t, write my own replacement for ActiveRecord and IRB.
  5. Will finally be able to solve the Rubik’s cube (soon).
  6. Now understand why privacy from the NSA really does matter to me.
  7. Can write Ruby to fly a surveillance drone.
  8. Got tips on the performance tuning one of the biggest open source rails applications, Discourse.
  9. Everything I wanted to know about Ruby, and my co-worker’s compensation, but was afraid to ask.
  10. Who is @JEG2?
  11. Plenty of break time between talks made for lots of conversation.
  12. Personally met many of the folks I follow on Twitter!
  13. Most folks I met want to visit me in Maui at my B&B Sugar Ranch Maui!
  14. Met the most talented and interesting group of programmers anywhere, who all love Ruby and programming just as much as I do.

Tips

  1. Don’t miss the pre-parties, breakfasts, or after-parties.
  2. Don’t plan to work during the conference, and leave your laptop at home. An good mobile phone or tablet is very useful.
  3. Sign up early if hanging out with other passionate programmers is your idea of fun!

Ruby on Maui, 2014?

If you interested in attending a small Ruby conference in Maui next year, maybe in May, please get in touch with me.

Photographs

If you’d like full resolution, non-watermarked copies of any of the images, please get in touch with me. I personally cropped and adjusted the exposure on all images. These were taken with a Nikon D5100, SB-400 AF Flash, and a very basic Nikon 18-55mm lens.

I hope that folks tag themselves in the Facebook albums! And please share them.

Flickr

I uploaded the full set of 2560 pixel images here. This has the half not shown on Facebook.

  • First 200: Pre-party, conference day 1, some of first after-party.
  • Next 200: Conference day 2.
  • Last 134: Conference day 2 and second post-party.

Upgrading Octopress

| Comments

One of the criticisms of Octopress is how there’s no clear separation of the static generation engine and the content of one’s website, and thus upgrading Octopress is difficult. I delayed upgrading due to this. However, my concerns were unfounded, as it was very painless to upgrade Octopress.

The instructions boil down to this short help page on Updating Octopress:

1
2
3
4
git pull octopress master     # Get the latest Octopress
bundle install                # Keep gems updated
rake update_source            # update the template's source
rake update_style             # update the template's style

The first step resulted in a few merge conflicts. I find RubyMine’s git conflict resolution tools helpful, so I used those. Here’s a short screencast (embedded below) showing you how these tools helped with this process. Besides some minor issues dealing with a few merge conflicts, there was nothing very interesting or eventful about the upgrade, which means that the current process is really quite OK.

I hope a few people find this demo of the RubyMine git conflict resolution tool helpful. The key takeaways from this video are:

  1. Merge conflicts show up as red in the list of changes.
  2. Try the diff’ing buttons in the upper left to get 2 way views of the 3 way merge.

3, “Yours” means your local changes, and “Theirs” means the server’s changes, or, in this case, the changes in the main Octopress development branch.

Did the upgrade work? You’re looking at the results of it.

It’s worth noting that I had one slight snag. When I merged sass/screen.scss, I accidentally removed this line, which is used for the youtube plugin.

1
@import "custom/rve";

I could have figured this out by examining the history of the file and noting that I had added this line, rather than it being part of Octopress. So yes, it would be bit better if there was a cleaner separation between the Octopress code and any enhancements. However, the current mechanism works, and it’s still thousands of times better than WordPress.

Migrating From Capybara-Webkit to Poltergeist-PhantomJs

| Comments

Motivation

Today I migrated a medium size test suite from capybara-webkit to Poltergeist with PhantomJS. I had two main motivations for switching:

  1. PhantomJS is more sensitive to avoiding false positives. For example, in the past, one could click on non-visible DOM elements with capybara-webkit. While this may not currently be true with the latest Capybara, I’ve had good luck with PhantomJS in the past.
  2. Speed. When I last checked, PhantomJS was faster. Speed is critical for slow feature tests.

Here’s one reason that Poltergeist is more accurate and sensitive to failure:

When Poltergeist clicks on an element, rather than generating a DOM click event, it actually generates a “proper” click. This is much closer to what happens when a real user clicks on the page - but it means that Poltergeist must scroll the page to where the element is, and work out the correct co-ordinates to click. If the element is covered up by another element, the click will fail (this is a good thing - because your user won’t be able to click a covered up element either).

Tips for Migrating

Upgrade Gems First

At first, I lost time due to timing issues where I was clicking on elements of a hidden dialog that was not finished showing. Capybara-webkit was not bothered by the fact that the dialog was actually hidden and being loaded. PhantomJS bombed out. However, after I worked around the issue, I realized that my gems were outdated. Since you’re going to be fixing a bunch of tests anyway, it makes sense to get on the latest versions of the testing gems. The gems you want to upgrade are: rspec, rspec-rails, Capybara, and poltergeist.

Visible Option

After upgrading the gems, my workarounds were no longer necessary. However, the change from Capybara 2.0 to 2.1 had a big change in the way that it handles finding dom elements that are not visible. Previously, Capybara would not care if the dom element was hidden. For my tests, this resulted in breaking any tests that queried any non-visible DOM elements, such as scripts, meta tags, and links.

The key thing to be aware of is that you might get this obscure error message, and the fix is to add the visible: false optional parameter so that Capybara is not filtering by visible: true. The visible parameter is available to most finder methods in Capybara.

The obscure error you might see is something like this:

#=> Capybara::ExpectationNotMet Exception: expected to find xpath "//title" with text "Title Text." but there were no matches. Also found "", which matched the selector but not all filters.

The reason is the title element is not visible, and “visible” is the “not all filters” part of the error message.

Debugging Capybara Tests

The main reasons that previously passing feature tests will fail when migrating to Poltergeist is due to timing and visibility. The two main techniques for debugging Capybara tests are:

  1. Using screen shots (render_page below)
  2. Using HTML dumps (=page! below)

Keep in mind that these methods will not wait for elements to load. Thus, you should either have a Capybara statement that will wait for some DOM element to load or you might want to put in a sleep 10 to sleep for 10 seconds before capturing the screen shot or dumping the HTML.

If you use the helper methods specified below, and you should be able to work through why Poltergeist is not doing what you think it should be doing. So far, I haven’t yet run into a case where I have not found out that it’s been my fault rather than a bug in Poltergeist that’s caused a failure due to the migration. In many cases, you’ll be somewhat pleasantly surprised that you’ll be fixing a false positive.

Capybara’s Wait Strategy

Be sure to carefully read the Capybara documentation, especially the part titled “Asynchronous JavaScript”. That section explains how Capybara cleverly will wait until the page or ajax call finished so that the element expected appears. There’s a configurable timeout (Capybara.default_wait_time) for changing the default wait time before a test bombs out.

Xpath Tip

Be sure to understand the difference between //something and .//something. The later can be used inside a within block. The former will find the tag anywhere on the page, even when used inside of a within block!

Setup and Utility Debugging Methods

Here’s the setup and a couple utility methods that I use. Put these in a file in your helpers directory, such spec/helpers/capybara.rb.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
Capybara.default_wait_time = 8 # Seconds to wait before timeout error. Default is 2

# Register slightly larger than default window size...
Capybara.register_driver :poltergeist do |app|
  Capybara::Poltergeist::Driver.new(app, { debug: false, # change this to true to troubleshoot
                                           window_size: [1300, 1000] # this can affect dynamic layout
  })
end
Capybara.javascript_driver = :poltergeist

# Saves page to place specfied at name inside of
# test.rb definition of:
#   config.integration_test_render_dir = Rails.root.join("spec", "render")
# NOTE: you must pass "js:" for the scenario definition (or else you'll see that render doesn't exist!)
def render_page(name)
  png_name = name.strip.gsub(/\W+/, '-')
  path = File.join(Rails.application.config.integration_test_render_dir, "#{png_name}.png")
  page.driver.render(path)
end

# shortcut for typing save_and_open_page
def page!
  save_and_open_page
end

Ember.js Tutorial With Rails 4

| Comments

The first post in this series, Ember.js Hello World, shows Ember working without a persistence backend. This post covers setting up Rails4 as the persistence engine behind that example, plus adding and deleting records. The amount of Ember and Rails code to make this example is almost completely included in this article. It’s that tiny!

The source code for the completed example can be found on GitHub: justin808/ember-js-guides-railsonmaui-rails4. I carefully crafted the commits to explain the steps.

You can try out the application on Heroku at: http://railsonmaui-emberjs-rails4.herokuapp.com/

I put many more details in this comprehensive screencast of how to go from a brand new Rails 4 app to an Ember.js app deployed on Heroku.

Key Tips

  1. Be sure to update the ember and ember-data javascript files with the command from the ember-rails gem (see below). Keeping these files at appropriate versions is key while the API is changing, especially for ember-data.
  2. If you specify the Router property for both model and setupController, you can have some very confusing results (details below).
  3. Get comfortable with Ember’s naming conventions. Ember does a ton with default naming. It’s basically got the same philosophy of “Convention over Configuration” of Rails. So it’s especially important to try to grok when the Ember examples are doing something implicitly versus explicitly. This is a bit like Rails. At first it seems like magic, like “How the heck is that happening”, and then one gets accustomed to the naming conventions and appreciates how much code it saves.
  4. Be mindful that some Ember.js commands run asynchronously, such as commit.