I hate RSpec reports!

Who the hell thought that Pokémon error handling is good solution? What I mean? See the difference:

RSpec

FF

Failures:

  1) RSpec test fails
     Failure/Error: expect(2).to == 3
     ArgumentError:
       The expect syntax does not support operator matchers, so you must pass a matcher to `#to`.
     # ./rspec.rb:3:in `block (2 levels) in <top (required)>'

  2) RSpec test is error
     Failure/Error: 'lol' + 3
     TypeError:
       no implicit conversion of Fixnum into String
     # ./rspec.rb:7:in `+'
     # ./rspec.rb:7:in `block (2 levels) in <top (required)>'

Finished in 0.00133 seconds (files took 0.15476 seconds to load)
2 examples, 2 failures

Failed examples:

rspec ./rspec.rb:2 # RSpec test fails
rspec ./rspec.rb:6 # RSpec test is error

MiniTest

Run options: --seed 51098

# Running:

EF

Finished in 0.002406s, 831.1025 runs/s, 415.5513 assertions/s.

  1) Error:
MiniTest test#test_0002_is error:
TypeError: no implicit conversion of Fixnum into String
    minitest.rb:10:in `+'
    minitest.rb:10:in `block (2 levels) in <main>'


  2) Failure:
MiniTest test#test_0001_fails [minitest.rb:6]:
Expected: 2
  Actual: 3

2 runs, 1 assertions, 1 failures, 1 errors, 0 skips

See the difference? MiniTest inform you that test is failure only if any of the assertions fails, if it is the syntax error or uncatched exception then it is marked as an error. RSpec tell you that both are failure.

PS

Test(ing) files was:

RSpec

describe 'RSpec test' do
  it 'fails' do
    expect(2).to == 3
  end

  it 'is error' do
    'lol' + 3
  end
end

and MiniTest

require 'minitest/spec'
require 'minitest/autorun'

describe 'MiniTest test' do
  it 'fails' do
    3.must_equal 2
  end

  it 'is error' do
    'lol' + 3
  end
end

PPS

To not be so hateful about RSpec I must say that I would prefer expect syntax in MiniTest instead of must_*. It is much more clean and doesn't involve Monkey patching Object.

Off-side rule

Some days ago I have started thinking about "why I hate languages with blocks by indentation while I love Haml, Slim or Sass?". Finally I found answer:

HTML is a tree structure, my code is not

What does it mean? That when I write my HTML I can think about it as a drawing a DOM tree. We have a root element <html> and then we create its children, and children of his children, and children of these children, so on... We can display this like tree, i.e.

DOM tree example image

So if we write our code using off-side rule, then we can display our tree in plain text

html
  head
    title Some title
    meta encoding='utf-8'
    link href='style.css'
    script src='script.js'
  body
    header
    div#content
    footer

But we can't do this with code, especially with asynchronous languages like JavaScript (and it off-side rule preprocessor CoffeeScript). There is no tree which can be display. In most cases we cannot predict flow of our JS code as most of it is written as callbacks and depends on user or server reaction. It only force indentation to be used.

But I am programmer and I know that indentation is important. I don't always have time to create it by myself so in curly or keyworded languages I can use some external help. In Vim, i.e., there is nice functionality that after I press =G it will reindent file from line with cursor to end of file.

So conclusion is that I love writing my code indented, but not when I forced to, as my code isn't tree and I cannot predict it flow (in CoffeeScript). In the other hand I love off-side HTML preprocessors as there I have my DOM tree displayed directly in my editor.

Go Fishing

When I began using *nix 7 years ago (I have started with Ubuntu, now switched to Arch Linux) my default shell was bash. I don't even know at the beginning that there are others shells. As I has been getting better and better in working with CLI I've started thinking how to get even better and how to make my work easier. Then I found zsh. It is quite awesome. Has a lot of impressive stuff like:

  • spell checking
  • case-independent suggestions
  • is more customizable
  • is POSIX compatible
  • and has a lot more great stuff

But after that I on some screencast (to be specify this one) I have seen fish I get love in it. It isn't POSIX so I need get used to it, but now I cannot work without it. Why?

Syntax coloring

First impression began when you discover that fish is coloring commands as you input. It look awesome and also is great help when you make a typo. You can perfectly see where it is.

Simpler syntax

When I was writing sh scripts I never remember how to write conditions and loops. It was quite hard for me to remember that I can or cannot write if and then in one line without semicolon. Also if is closed with fi, case with esac and for with... done, WUT?

Built-ins reduced to minimum

In bash and zsh we have enormous amount of built-ins: test, [[, regexps, arithmetic via $((...)), variable modification via ${var_name##.}, etc. In fish it was reduced to needed minimum. If we need to test something, we use [ command, compute some arithmetic expression - bc or dc, use regexp - grep, awk, sed, perl, etc. In bash it usually take a lot of time to run another process due it's design, but fish use threads for different processes (not time-wasting fork) so it is fast and you don't see any delay.

Variable is an array

In bash (and zsh) you have difference between scalar and vector (array) variables. The second one need to be enclosed in () and referencing to it's elements was quite ugly ${arr[0]}.

var=some_value
arr=(a b c)

Also for beginners it can be hard to remember that there cannot be any whitespace before and after assignment sign, so:

var=data # work well
var = data # doesn't work

Fish don't have scalars, everything is an one based array and one-element array can be treated as an scalar, also to set variable you use built-in command, not the assignment sign (which is quite confusing, but is more powerful than POSIX one).

set var some_value
set arr a b c

Booth above commands create local variable named by first argument, and containing the rest. As a good shell command, set has some flags that modify it's behaviour.

Easy configuration and awesome help

Fish is created to be friendly for developers. It work on 256-colour terminals with nice colours and has great documentation available through help command.

Summary

If you are not afraid of changes, and want to check something new and awesome - go fish :)

LeGit

I'm using git quite often so I've started to use a bunch of git aliases, now I will share them with you :)

Basics

First install hub what is a great extension of git and provide a lot of GitHub shorcuts. So just write

$ curl http://defunkt.io/hub/standalone -sLo ~/bin/hub
$ chmod +x ~/bin/hub

or if you are using MacOS you can use brew

$ brew install hub

Then check if it's working

$ hub version
git version 1.7.9
hub version 1.8.4 # ← it works!

After that we do some magic (I assume that you are using ZSH, if other, you need to write your proper RC file):

$ echo 'eval $(hub alias -s)' >> ~/.zshrc
$ echo 'alias g=git' >> ~/.zshrc

Now i.e. when we want to clone repo from GitHub we only need to write:

$ g clone some-our-repo

And if it's someone other repo then we have (in this example I use my sass-960gs repo):

$ g clone hauleth/sass-960gs

More of hub utilities is on it's homepage.

Start aliasing

So when we have our awesome hub and g alias we need to shortcut more git commands, so begin with very basic commands:

g config --global alias.ci commit
g config --global alias.cl clone
g config --global alias.co checkout
g config --global alias.f fetch
g config --global alias.b branch
g config --global alias.cp cherry-pick
g config --global alias.com 'checkout master'

Great, now we save 5-8 key strokes in most popular tasks. So let's go further:

g config --global color.status.added green
g config --global color.status.modified red
g config --global color.status.untracked blue
g config --global alias.st statis -sb

Now we have pretty short and pretty clear status output in your repo. All files in stage are green, unstaged but modified are red and all untracked files are blue what is pretty clear when you need to check what happening in your tree.

More git magic

It was only basis. Now we will setup some useful hacks for git masters.

Prettier logs :)

Now one of my favourite and widely described in Protips on Coderwall:

prettier version of git log

g config --global alias.lg "log --color --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit"

Whoops, I forgot to add some files

A lot of times we accidentally forgot to add some files to our commit. Reverting it only for adding some minor edit in README or Procfile isn't very pretty. So what can we do? Use git commit --amend --reuse-message=HEAD. But it is too long and too ugly to use. So just add aliases to it:

g config --global alias.ca 'commit --amend --reuse-message=HEAD'

Yay. Pretty clear and pretty short. But remember that if you already pushed your commits to remote it will be bad idea to use this.

Clean untracked files

Sometimes we have a bunch of untracked files in our repo and also most of them is unneeded in our work (i.e. .gem files with builded RubyGem). So how to easily get rid of them in a second? Just make this alias:

g config --global alias.cleanse '!git ls-files --others --exclude-standard | xargs rm'

Now calling g cleanse will remove all untracked files from working tree.

Find conflicts

Sometimes when we merge some branches the tree-way merge cannot fix all of conflicts in files. Then we need to fix them using some merge tool or if someone is a purist then fix it by hand. For the second ones this alias will be very helpful:

g config --global alias.conflicts '!git ls-files -u | cut -f 2 | sort -u'

Quickly go to repo root

So why not use g root?

g config --global alias.root '!cd $(git rev-parse --show-toplevel)'

Some tasks to do? Check it out

According to bbatsov's Ruby Style annotations guide we have two most important annotations - TODO: and FIXME:. So lets find them in our tree.

g config --global alias.todo=grep --heading --break --ignore-case -e 'TODO:'
g config --global alias.fix=grep --heading --break --ignore-case -e 'FIX:' -e 'FIXME:'

Pretty clear, isn't it?