Thursday 21 October 2010

Shared Examples group on RSpec (Drying up)


When you are drying up your RSpec, shared example group could become very handy, since it can help you gather (hence the name) the common / similar behaviors applied in your methods/ classes. All you need to do is factor out the common behaviors, put it in a shared example group and than use it in pairs with it_should_behave_like (add let(s) if you need to parameterized your specs). For example :

shared_examples_for "a shape" do
  it { should have(expected_n_items).sides}
  
  it "should have a color" do
      # ...
  end

  it "should have a center point" do
      # ...
  end
end
And call it like so :
describe "a cube" do
  let(:expected_n_items) { 6 }

  it_should_behave_like "a shape"

  it "should be 3D" do
      # ...
  end
end


Call them again for orb, prism, and so on ^^.

Saturday 16 October 2010

How to Write Unmaintainable Code

I read this years ago, but still got me laughing like crazy even now =))
some sneak peek :

1. New Uses For Names For Baby
Buy a copy of a baby naming book and you'll never be at a loss for variable names. Fred is a wonderful name, and easy to type. If you're looking for easy to type variable names, try adsf.

2. Single Letter Variable Names
If you call your variables a, b, c, then it will be impossible to search for instances of them using a simple text editor. Further, nobody will be able to guess what they are for. If anyone even hints at breaking the tradition honoured since FRTRAN of using i, j, and k for indexing variables, replacing them with ii, jj and kk, warn them about what the Spanish Inquisition did to heretics.

3. Creative Missspelling
If you must use descriptive variable and function names, misspell them. By misspelling in some function and variable names, and spelling it correctly in others (such as SetPintleOpening SetPintalClosing) we effectively negate the use of grep or CodeWright search techniques. It works amazingly well. Add an international flavor by spelling theater and theatre in different situations.

read all!

Even more robust XPath to go with Nokogiri

I'm not big on XPath and truthfully only using it when I do screen scraping with Nokogiri (Blimey! I know). Anyway, I found XPath to be clever and surprisingly simple. Here below one of its examples :

//*[@id='someid']/tr[contains(.,'somestring') and not(contains(.,'otherstring'))]

We can mix match almost any HTML elements in it, it's very readable we can describe what we want like describing something to another human being. Say, we want filled fields on a row containing the word 'Usage', this row is placed on a table with class = 'billing_table', and the table is put inside a div with id = 'counterbox'. Here's how it will look like on XPath :

//div[@id='counterbox']/table[@class='billing_table']/tr[contains(.,'Usage')]/td[not(.,contains(''))]


Have fun with XPath! ^^

Beginner's guide to : Undo commits on Git

You have second though on your last(or more) commit(s),
for these sort of reasons :

(1) incomplete work / last minute idea (locally)
(2) incomplete work / last minute idea (remotely)(other solution git rebase)

Solution for (1)
Now, you'd like to undo your local commit; initially, here's what you need to be doing :

$ git reset --soft HEAD^

The line above tells git to remove the last commit.
Change HEAD^ to HEAD~2 if you want to remove last 2 commits, or HEAD~3 for three, and so on.
For the 3 cases mentioned above, git-reset(1) Manual Page recommend to use this line below after edit :

$ git commit -a -c ORIG_HEAD

But, personally, I wouldn't do this. Yes, the commit objects wouldn't have to be re-add-ed, but I have files that I don't want to be committed on the same commit group, '-a' would add all of those together with the recently modified files. And with using '-c' only, the recently modified file wouldn't be included while all un-staged files would be committed. This is hell!

I would recommend the good old fashion way of commit, where we would have full control on what/when should be committed. But first, remove the commit objects from previous reset --soft, like so :

$ git reset

Now, when you're done editing, run proper commit (run git add when needed).

$ git commit -m "commit message" filepath1 filepath2 filepath3 ..

You're all well & done! ^^


Solution for (2)
Your changes were committed to the remote repository, and then you realized, that the changes is not appropriate, and you would want to undo this, and let the repository holds only commit history until the one before. Run this :

$ git revert HEAD

Now, the line above means, to revert the changes you made on the last commit(HEAD). You can change HEAD to HEAD^ for next to last commit, or change with specific SHA (get it from git log --oneline), careful with merging tho'. Anyway, back to our subject, an editor would came, and you can change the commit message if you want (I don't find it necessary). Push and then run this :

$ git rebase -i HEAD~3

We need to pack the changes to one line history only, we don't want history that says something like 'I revert my own changes'. So now, on the editor you'll see :

pick 75589b5 seek method added
pick bfb8cf0 working seek method
pick a0f2df9 Revert "working seek method"

# Rebase 75589b5..a0f2df9 onto 75589b5
#

Now, the first line is older than the rest, we need it to be our base. The second line is your last commit, and the third is the reverted commit. What we want is to make second & third line to disappear; So, we need to change the word 'pick' to 'fixup' for those line, and then run save & quit. Another editor will show, it's to modify the commit message, I wouldn't recommend you to change it, just run another save and quit. Push force it, and it's like you never had commit it.

^^ Gittiful ^^

Beginner's guide to : Change commit messages on Git

I think, as human, it is understandable if we misspelled words, therefore it is only fair if we can change our commit messages on Git. Wait, even better, change our commit messages both locally and remotely!

Ok, this is do-able, let's start with changing our un-push-ed commit message :

$ git commit --amend

The line above will lead you to an editor where you can change your message on the last commit to what may satisfy you. Now, let's move on, what should we do if -we already commit the changes into the remote repository when we realized that the message need to be changed- ?

No worries! unlike our lives, we can re-write history in Git, here's what you need to do :

$ git rebase -i HEAD~1

The line above means that we want to run rebase interactively for the last commit, HEAD~2 would mean the one commit before last, and so on. This will lead you to an editor, saying something like this :

pick 9b504bf f.txt file added

# Rebase 78d81b4..9b504bf onto 78d81b4
#

You would need to change the word 'pick' with 'reword', do save & exit. Next, you will face another editor where you can edit your previous commit message. Another save & exit, and then push force it. Oh my Git, it's fun! ^^

Beginner's guide to : Remove uncommitted changes in Git

Our case is, somewhat below :

(1) Remove changes on specific file.
(2) Remove all changes we made.

What we want is to get into the previous state, before we started to tinker with it.
We need to run this below for case (1) :

$ git checkout filename

And here below, to remove EVERY changes made :

$ git reset --hard HEAD || $ git reset --hard

(tips HEAD = last, HEAD^ = next to last, HEAD~2 = last - 2, and so on)

Friday 8 October 2010

Beginner's guide to : Starting to work on project with existing git repository

The other day I have a colleague scanning through this blog to find a way on getting started to work with git repository (he found none because I haven't write it down here), so I think it won't hurt to actually write it. So here goes...

The case is, you need to work on a collaboration project, git repository is made (or maybe the project is half-way already), but you are clueless on what/how/when to start working with the repository.

what you need to do :

  1. Sign up to github.
  2. Register your public key here : Account Settings > SSH Public Keys
    or run this ssh-keygen -t rsa on a console if you don't have public key yet
    can be found later on ~/.ssh copy whatever inside id_rsa.pub
  3. Run these below on your console, to set up your username & email :
    $ git config --global user.name yourusername
    $ git config --global user.email youremail@yourdomain.com
  4. Ask your team leader/whoever has access to the original repository to invite you into their organization.
    In case they are clueless:
    Dashboard > Switch context into the organization's > Teams
  5. Once they've invite you, go to their repository page & copy the SSH url, supposedly with the write & read access.
  6. Go to your terminal run :
    $ git clone git@github.com:organization_name/repo_name.git
    $ cd repo_name
  7. If somehow you need the repo's branches, run this:
    $ git branch -r
    $ git fetch origin repo_branch_name:local_branch_name
  8. Create your working branch like so : (here for more detailed info)
    $ git push origin master:refs/heads/mynewbranchname
  9. Checkout to your new working branch with this line :
    $ git checkout mynewbranchname
  10. There you go, you're all set to rock your project!

Sunday 19 September 2010

Beginner's guide to : Unstaging committed files on Git

For example, we have this below :

$ git status
# On branch tryone
# Changes to be committed:
#   (use "git reset HEAD ..." to unstage)
#
# new file:   config/database.yml
# new file:   log/development.log
# new file:   log/production.log
# new file:   log/server.log
# new file:   log/test.log

and we have a change of mind about committing log/test.log, we want it off the list, we don't want the changes on it to be committed further more to be saved on the remote repository. So what we need to do is to run this line below:

$ git reset log/test.log

Voila! it's done! check it out with git status and you'll have log/test.log no longer on the list.

Btw, those mentioned above works on removing single added file, or, if you're in the mood of listing the files (after HEAD) you can do multiple remove, but if removing all added files (uncommitted ones) do this below instead :

$ git reset

'Enjoy!

Wednesday 15 September 2010

Beginner's guide to : Create a Git branch

Lets say you want to have a working branch, here's what you need to do.
On your local (automatically added to your remote repo):

$ git push origin master:refs/heads/branchName
e.g.: git push origin master:refs/heads/mybranchname

means that you will create a new branch named 'mybranchname' to the remote repository, copying everything from master.



Next step :

$ git checkout branchName
e.g.: git checkout mybranchname

moving, fetch, and start to work on branch 'mybranchname'



Enjoy!

Saturday 28 August 2010

Collapsing git repository history with rebase

Assuming you have a couple of git repository history that you want to wrap up together (after a conflict or some changes needed to be revert but you don't want to expose it), you might find git rebase quite handy. To do this, first thing we need is to run this :

$ git log
commit 83af3c6f8aaaf91dad91cc34c02092f520ce3327
Author: John Doe 
Date:   Fri Aug 25 17:55:21 2010 +0700

condition for js links passed as nokogiri object

commit d717a68c0f8199d27b50e08d74b2acc22b9a35d8
Author: John Doe 
Date:   Wed Aug 25 17:32:46 2010 +0700

latest revision, replaced indexed css for nokogiri search

commit 9c83b904880b33bd1a112b9bf43ec71155859f27
Author: Peter Piper 
Date:   Tue Aug 24 17:47:56 2010 -0400

move common asp javascript helpers into a module

commit 5ec142c344508d0c9f3b89b501646d2bb703ffb4
Author: John Doe 
Date:   Tue Aug 24 18:37:44 2010 +0700

deleting data_point variable declaration
We can see that there are 2 history listed on aug 25, while what we want is to let only 1 history on john doe's action right after peter piper's. So what we need to do is to run git rebase, like so :

$ git rebase -i HEAD~2

This line would mean, we want to collapse the last 2 commits from the log above and write down just one history afterwards. After we hit enter on that line above, we would find git nano such this :

$ git rebase -i HEAD~1
pick yyyyyy   latest revision, replaced indexed css for nokogiri search
pick xxxxxx   condition for js links passed as nokogiri object

# generate a pick list of all commits starting with 2bcdef
# Rebasing zzzzzz onto yyyyyyy 
# 
# Commands: 
#  pick = use commit 
#  edit = use commit, but stop for amending 
#  squash = use commit, but meld into previous commit 
# 
# If you remove a line here THAT COMMIT WILL BE LOST.
We need to let the first one to stick with pick (this list is ASC, unlike the log which would give you the latest changes first), and change the second line (or more if you have more to come) from pick to squash, this would mean the first act is the one with 'pick' and the ones with squash is the latter that we would want to combine. Follow with save and quit and we will get another editor as a reply :
# This is a combination of 2 commits.
# The first commit's message is:

condition for js links passed as nokogiri object

# This is the 2nd commit message:

latest revision, replaced indexed css for nokogiri search

# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
# Explicit paths specified without -i nor -o; assuming --only paths...
# Not currently on any branch.
# Changes to be committed:
#   (use "git reset HEAD ..." to unstage)
#
# modified:   README
# modified:   lib/importer/asp_javascript_helper.rb
You might want to create a new commit message than describe the two, and then another save and quit and you'll get this message :

Created commit xxxxx: latest revision, replaced indexed css & js link condition for nokogiri
2 files changed, 27 insertions(+), 30 deletions(-)
create mode 100644 yyyyyy
Successfully rebased and updated refs/heads/master.

If somewhere between the two committed files happend to be a conflict, you will have a message stating that you need to resolve the conflict, this will happen after squash just before editting commit message. When this supposed to happen, you need the resolve the conflict(s) manually and then run :

$ git add filename_path
$ git rebase --continue

And all will be good again (^.^). Last thing to wrap this whole things up :

$ git push -f origin branchname

A little tip, the rebase will take place on an unknown temporary branch until you push it, if you're like me (completely paranoid type of person, won't believe on anyone or anything until you see the results with your own two eyes) you might want to run these below every now and then to make sure everything works the way & at the place you want it to be :

$ git reflog --oneline
$ git status
$ git branch

If you find it doesn't behave/do what you think it would do, you can abort the whole thing (as long you haven't push them).

$ git rebase --abort

As a closure, this is what you'll end up with :

$ git log
commit 83af3c6f8aaaf91dad91cc34c02092f5xxxxxxxxx
Author: John Doe 
Date:   Fri Aug 25 18:55:21 2010 +0700

latest revision, replaced indexed css & js link condition for nokogiri

commit 9c83b904880b33bd1a112b9bf43ec71155859f27
Author: Peter Piper 
Date:   Tue Aug 24 17:47:56 2010 -0400

move common asp javascript helpers into a module

commit 5ec142c344508d0c9f3b89b501646d2bb703ffb4
Author: John Doe 
Date:   Tue Aug 24 18:37:44 2010 +0700

deleting data_point variable declaration

Have a Git day (^.^)v

Robust XPath to scrap a specific field with dynamic row and column index

A simple XPath like below is easy to digest and quite effective on doing its work, as long the field we want to scrap is always on the same position (on this case first row second column).

//table[@class='mytableclassname']/tr[1]/td[2]

But what should we do if both column and row can change its position, depending on what group a user classified as?

Here's what I did to overcome this challenge, I made a line of XPath to tell nokogiri to look for a row which contains a certain String, and a certain column whose 'th' index equals another certain String. Like this one below :

//table[@class='mytableclassname']/tr[.='my_row_contains_some_string']/td[count(//th[.= 'my_destined_column_th' ]/preceding-sibling::*)+1)]

The path will search for a table with 'mytableclassname' class, and then a row which contains 'my_row_contains_some_string' on at least one of its field, and on that certain row will search for a field whose index equal to 'th' = 'my_destined_column_th'.

The column and row can change however they want, but I will have the exact field whenever I want too (^.^).

Friday 27 August 2010

Beginner's guide to : Delete a Git remote branch

Say you have a working branch that is not of any use anymore, and you want to remove it from both your local machine and from the remote server. Here's what you need to do.

On your local :

$ git branch -D branchName
e.g.: git delete -D mybranchname

To permanently delete the branch from the remote repo :

$ git push remoteName :branchName
e.g.: git push origin :mybranchname

Enjoy!

Sunday 1 August 2010

Beginner's guide to : Initiate a Git project

Assuming: Active github account is made, SSH public keys passed and a new repository already created on the site.

First you need to know the address of your new repository, this can be easily found on the repository page (http://github.com/username/repository_name), the addy supposed to look like this below :



On your local console run :


$ mkdir myNewRepo
$ cd myNewRepo
 
$ git init
$ git add .
$ git commit * -m "write your message here"
$ git remote add git@github.com:ms-egg-gee/pronto.git
$ git push origin master

Basically, what it did was :

1) & 2) self explained
4) initiate the directory to be git-i-fied
5) add all files & folders inside the directory
6) stage the changes to be committed
7) self explained
8) commit changes to remote repository