Quick Fixes With Vim And The Command Line

Vim allows you to perform external commands with the !(bang) operator. The most common use I see is when someone opens a file requiring sudo permissions. They don’t find out until they’ve made their changes and try to save.

Instead of losing the work and re-opening the file under sudo permissions you can save it with :w !sudo tee %. Nathan Long provides an explanation of what’s happening here on Stack Overflow.


I’ve been having issues with a local Ruby on Rails app for the past few days. It doesn’t have the records I expect it to. I’ve run the seed files and they are still missing.

I discovered the reason was that the slugs had been modified. Two months ago I refactored the seed files when I added data to them.

Original

content = Content.find_or_initialize_by(slug: 'easy-reading-title')
content.name = "Easy Reading Title"
content.save!

Refactored

assessment_generator = GenerateContent.new(
slug: 'brand-easy-reading-title',
title: "Easy Reading Title"
)

By refactoring procedural code to objects I could easily use macros to convert a spreadsheet into a seed file.

I’ve reduced this code for demonstrations but left my error in place. The slug changed to something it wasn’t supposed to. At first glance, my problem seems pretty large. I have to compare the current files to what they were months ago. They are completely different in structure and source lines of code.

For 30+ files the process is

  1. Open a file for editing.
  2. Open the file to it’s state two months ago in version control.
  3. Identify the original slug.
  4. Update the current files slug.

Using Vim and the External Command operator I can do this with efficiency. While having the current file open in vim I can type the following: /slug:<enter>:read !git show 0abbdaa37057d:% | grep -o "slug: '.*'" | sed 's/$/,/'<enter>==kdd:w<enter>

  • /slug: Find the first line containing ‘slug’ and put the cursor there.
  • :read !git show 0abbdaa37057d:% | grep -o “slug: ‘.*'” | sed ‘s/$/,/’
    • read: Write the input to current file.
    • !: Perform external command.
    • git show 0abbdaa37057d:%: Show the current file (%) at the state of commit 0abbdaa37057d.
    • |: Pipe operator, take the output from the git statement and input it into the grep.
    • grep -o “slug: ‘.*'”: Find a line containing ‘slug:’ with anything between two quotations. The -o flag tells grep to only return what matches in the pattern. This means instead of getting the entire line, we will just get the slug.
    • |: Pipe operator, take the output from grep and put it into sed.
    • sed ‘s/$/,/’: Append the line with a comma.

At this point we should have the incorrect slug followed by the correct slug.

slug: 'brand-easy-reading-title',
slug: 'easy-reading-title',

  • ==: Correctly indent the new ‘slug’ line.
  • k: Move the cursor up to the incorrect ‘slug’ line.
  • dd: Delete the incorrect ‘slug’ line.
  • :w: Save the changes.

To recap, we add the correct slug by retrieving from git, filtering it with grep, and correct syntax with sed. Then delete the old slug line.

Now that I have my macro I can perform it on all my seed files.

  • vim $(find db/seeds -type f): Open all my seed files in vim.
  • Copy my macro into a register ‘m’.
  • :argdo normal @m: In vim, perform the macro on every file.

Knowing Vim enables you to spend time on greater problems because it’s so easy to solve repetitive problems like this one. Having experience with the command line empowers the use of Vim in greater ways.

99 Bottles of OOP – Shameless Green

I’ve been reading through Katrina Owen’s and Sandi Metz’s latest book 99 Bottles of OOP. I have a history with Object Oriented languages and wasn’t sure what to expect but I have been pleasantly surprised.

99 Bottles starts with the Beer Song exercise over at Exercism.io. You are tasked to write a class that puts out the verses to ’99 bottles of beer’. There are 4 different solutions presented, all based on different needs.

The last example, Shameless Green, is the preferred. It’s redundant and has no scrap of DRY. However, it passes all the tests and is the easiest to read.

My solution extrapolated every duplication. The flog score for my code is 42.3 while the flog score of Shameless green is 29.3. That’s a significant difference.

This was very interesting to me and I think the authors pin me down in their summary:

“As programmers grow, they get better at solving challenging problems, and become comfortable with complexity. This higher level of comfort sometimes leads to the belief that complexity is inevitable, as if it’s the natural, inescapable state of all finished code. However, there’s something beyond complexity—a higher level of simplicity. Infinitely experienced programmers do not write infinitely complex code; they write code that’s blindingly simple.”

Excerpt From: Sandi Metz, Katrina Owen. “99 Bottles of OOP.”

Test Doubles

The other day I broke our tests by including a Module that required configuration. I didn’t realize this until our Continuous Integration setup reported failures. If I wanted to get my pull request through I would need those tests to pass. One dev recommended a test adapter. I began designing and thinking of a solution to get this module working while testing.

However, another dev had a much simpler solution and resolved it with a single line in the spec:

allow(Mail::NewUser).to receive(:send)

RSpec refers to this as a Test Double, after Martin Fowlers article. The idea is that our tests are specific to a single value or behavior. However, these can unexpectedly change when they depend on another object’s value or behavior. If we can replace that dependency with an object providing consistent behavior we can keep our tests simple and clean.

Suppose I want to test a Hello module. It accepts an instance of Person and says hello.

module Hello
  def Hello.person(person)
    "Hello #{person.name}"
  end
end

An issue with testing this module is that the Person class is complex. While person.name is expected to be a short string, it’s a complicated algorithm to generate and create.

This shouldn’t be an interruption to creating the Hello test. It’s also not the time to think about the Person class. How can we test the Hello module’s behavior without having an instance of Person readily available?

Below I have created two tests. The first uses an Open Struct to provide the needed behavior to test Hello.person. The second uses RSpec’s doubles to create an instance of Person. It also has a ‘name’ method to call and return the value ‘Dave’.

RSpec.describe "Hello" do
  it "accepts a dummy object to greet" do
    require 'ostruct'
    dave = OpenStruct.new(name: 'Dave')
    expect(Hello.person(dave)).to eq("Hello Dave")
  end

  it "uses a test double to greet" do
    dave = double("Person", name: "Dave")
    expect(Hello.person(dave)).to eq("Hello Dave")
  end
end

These tests are only concerned with the Hello Module. They do it with minimal knowledge of what the Person class is. Whatever happens to Person, this test double will always remain the same, leaving our tests safe and happy.

Test doubles are beneficial.

  • They enable you to be lazy. In our example we didn’t need to know the Person object to test Hello.
  • They prevent things from creeping into our tests that we are not testing.

I hope this overview of Test Doubles helped you understand testing. I recommend the RSpec Mock documents for a full overview of RSpec and test doubles.

http://www.relishapp.com/rspec/rspec-mocks/v/3-5/docs

Uncle Bob has also written a helpful article on the strengths and weaknesses of mocks, https://8thlight.com/blog/uncle-bob/2014/05/10/WhenToMock.html.