Tabbed console windows in Windows at your command... ala Linux's Konsole

Recently I was a bit annoyed with having to open multiple command shells or consoles to run different daemons/servers, which then just lay there and clutter up my task bar.

Enter Console on SourceForge.net ( from: Marko Bozikovic ).

'Don't make my brain get up' installation
  1. I downloaded the latest beta from the project's download page - Console-2.00b138-Beta.zip
  2. Extract to a folder.
  3. Double click on the Console.exe and we're up and running.
Some tweaks:
Console is quite customizable with keyboard shortcuts.. but then that is expected coz this is targeted for the shell users. Just some to get you started
  • Ctrl + T : New Tab (non-default. I set this to match my brain-associated keystroke for a new tab.)
  • Ctrl + W : Close current tab
  • Ctrl + 1, 2, 3 : Go to tab1, 2, 3, etc.
You can reassign any of the keyboard shortcuts via Main Menu > Settings... > Hotkeys.


'Pictures or it didnt happen' dept.

Here I have Console running with three tabs. Tab1 is running the Webrick server for my rails app. Tab2 just finished running my tests with rake. Tab3 is serving up the Fitnesse wiki pages.
And all this just takes one slot on my taskbar. No more manic alt-tabbing to find the right shell window...



Credits: While I was writing up the post on Aptana - the IDE for Rails, I came across another guy who had written up a similar post. And then I found a link on his blog... Credit where credit is due.
http://thenoobonrails.blogspot.com/2007/10/sexy-command-line-for-windows.html

ShowMeTheMoney-17 - I will paginate.. with some help

Iteration#2 Day 4/10

You know when I run rake on the command line to run my tests, i get a lot of deprecation warnings ... which stink! I have been secretly plotting the death of those horrid lil pagination Deprecation warnings. When I run rake from the command prompt, they get in my way of seeing the test results

DEPRECATION WARNING: paginate is deprecated and will be removed from Rails 2.0 (Pagination is moving to a plugin in Rails 2.0: script/plugin install svn://errtheblog.com/svn/plugins/classic_pagination) See http://www.rubyonrails.org/deprecation for details. (called from list at L:/Gishu/Ruby/Rails/ShowMeTheMoney/app/controllers/inflow_controller.rb:12)

After some initial investigation to determine the effort it would take, I find it’s really simple – Its going to be tough going back to the non-rails world out there.
Hey! We're moving.. to will_paginate

The nice folks at errtheblog.com have come up with a better way for pagination (the mechanism to display those next previous page links at the bottom). The current way has some performance issues and needs more code to be written. It has been moved out of the rails 2.0 into a plugin called classic_pagination and hence the warnings.
Now we’ll see how to move to the new way in less than half the amount of typing I did for this post till now.
  • First install the plugin like this..
CmdPrompt> ruby script\plugin install svn://errtheblog.com/svn/plugins/will_paginate
  • Next off to the OutflowController’s list method. There we see..
@expense_pages, @expenses = paginate :expenses, :order=>'created_at', :per_page => 10

Off with the old 2 paginator and array objects and.. in with the new WillPaginate::Collection object
@expenses = Expense.paginate :page=>params[:page], :per_page=>10, :order=>’created_at’


  • Finally we go to the list action’s view. Near the end of the page, we have

<%= link_to 'Previous page', { :page => @expense_pages.current.previous } if @expense_pages.current.previous %>
<%= link_to 'Next page', { :page => @expense_pages.current.next } if @expense_pages.current.next %>

Now check this out.. I love it when you shrink code while keeping the functionality intact. You will agree that this is much neater.

<%= will_paginate @expenses %>


We try it out in our browser and it works as advertised. Awesome. Let’s update the InflowController similarly.. All clear. Hit F5 in firefox… looks good. Rake from the command line is much better now without all those pesky warnings. Of course now we have integrated test running with green bars and the works within Aptana Studio. Groovy! (In case you hit some icebergs.. here’s the Railscasts tutorial video and words straight from the creators at ErrTheBlog )
Update: Will_paginate has moved... http://github.com/mislav/will_paginate/wikis/installation




ShowMeTheMoney-16 - Tallying up the expenses

Iteration#2 Day 3/10

Some TODOs I have jotted down.
  • place all view strings (displayed to the user) under the control of ApplicationHelper::ResourceManager
  • inflow/list with the table style similar to outflow/list
  • credit and expense rows are listed in order of ID. Ordering by entry date is what is required ( Found this out while I was actually using the app.. Real users! nothing comes close to them for feedback)
For the last item – lets take expense first (Credit should be identical), we add another record to the fixtures file, but out of order – make the year 2007 as shown below. We need to update some existing tests to update @fixtureRecordCount to 3. Done!

file: /test/fixtures/expenses.yml
rent_expense_entry:
id: 1
created_at: 2008-01-19 00:00:00
description: rent
amount: 10000
apparel_expense_entry:
id: 2
created_at: 2008-02-20 00:00:00
description: A pair of Jeans
amount: 1000.50
movies_expense_entry:
id: 3
created_at: 2007-12-20 00:00:00
description: Taare Zameen Par
amount: 300

Next, we need to update the controller test to check if the records are displayed in order. For that we inspect the controller’s @expenses variable and assert that they are retrieved order by date i.e. 3 – 1 - 2

def test_list
get :list
assert_response :success
assert_template 'list'
assert_not_nil assigns(:expenses)
assert_equal(@fixtureRecordCount, assigns(:expenses).size )
assert_equal(3, assigns(:expenses)[0].id,not ordered by date”)
assert_equal(1, assigns(:expenses)[1].id)
assert_equal(2, assigns(:expenses)[2].id)
end


Run the tests to see if it fails. It does. That validates our test. Next some research on how to implement this, how do we tell paginate to order the records by “created_at” ? Search search.. online... can't find it. Once again the book comes to the rescue, Pg 352, Section 17.7 Hurray!
def list
@expense_pages, @expenses = paginate :expenses, :order=>'created_at', :per_page => 10
end


The :order key-value pair is all we need. It’s really that simple!!! I even tried out via the browser – It just works!! I LOOVVEEE Rails!!!
Do it again for the credits page. TODOs are done! Quick run of all tests. Green!

Alrighthy! now we got to build ourselves a balance tracker.

file: /test/unit/balance_tracker_test.rb

require File.dirname(__FILE__) + '/../test_helper'

class BalanceTrackerTest < Test::Unit::TestCase
fixtures :credits, :expenses
def test_balance
assert_in_delta(19700, BalanceTracker.balance, 0.01 )

Credit.create(:description=>"D", :amount=>300.50)
assert_in_delta(20000.5, BalanceTracker.balance, 0.01 )

Expense.create(:description=>"E", :amount=>10000)
assert_in_delta(10000.5, BalanceTracker.balance, 0.01 )
end
end



file: /app/models/balance_tracker.rb
class BalanceTracker
def BalanceTracker.balance
models = Credit.find_by_sql("select sum(amount) as totalAmount from Credits");
fTotalCredit = models[0].attributes["totalAmount"].to_f

models = Expense.find_by_sql("select sum(amount) as totalAmount from Expenses");
return fTotalCredit - models[0].attributes["totalAmount"].to_f;
end
end


Done. Now we have everything to go and work on our acceptance test fixtures to make the actionfixture table and second rowfixture table pass.

file: /AcceptanceTests/track_balance.rb

require File.dirname(__FILE__) + '/../test/test_helper'
require 'inflow_controller'
require 'fit/fixture'

class CreditsHelper < Test::Unit::TestCase
def setup
Credit.delete_all
@controller = InflowController.new
@request = ActionController::TestRequest.new
@response = ActionController::TestResponse.new
end
def test_dummy
end
end
class ExpensesHelper < Test::Unit::TestCase
def setup
Expense.delete_all
@controller = OutflowController.new
@request = ActionController::TestRequest.new
@response = ActionController::TestResponse.new
end
def test_dummy
end
end
module AcceptanceTests
class TrackBalance < Fit::Fixture

#enter attributes
attr_accessor :description, :amount, :select_entry

def initialize
@creditHelper = CreditsHelper.new "test_dummy"
@creditHelper.setup

@expenseHelper = ExpensesHelper.new "test_dummy"
@expenseHelper.setup
super
end

#press methods
def add_credit_entry
@creditHelper.get :new
@creditHelper.post :create, :credit => {:description => @description, :amount => @amount}
end
def delete_credit_entry
@creditHelper.post :destroy, :id => getID_ForSelectedEntry(Credit)
end
def add_expense_entry
@expenseHelper.get :new
@expenseHelper.post :create, :expense => {:description => @description, :amount => @amount}
end
def delete_expense_entry
@expenseHelper.post :destroy, :id => getID_ForSelectedEntry(Expense)
end
#check methods
def current_balance
BalanceTracker.balance
end

private
def getID_ForSelectedEntry model
obSelectedEntry = model.find(:all, :order => "id")[@select_entry.to_i - 1]
obSelectedEntry.id
end
end
end


file: /AcceptanceTests/get_inflow_records.rb

puts File.dirname(__FILE__) + '\get_inflow_records'
require File.dirname(__FILE__) + '\get_inflow_records'
require 'fit/row_fixture'
module AcceptanceTests
class GetOutflowRecords < Fit::RowFixture
def query
recordset = []
Expense.find(:all, :order=>'created_at').each{|x|
recordset << InflowRecord.new(x.created_at, x.description, x.amount)
}
end
def get_target_class
InflowRecord
end
end
end


Our Reward !!!

ShowMeTheMoney-15 - Aptana + Radrails.. Hell Yeah!!!

Honey, I got a new IDE!!
Author-Update-Feb2010: Netbeans with the Ruby bundle is my IDE of choice now.. Haven't seen if Aptana has also progressed since then. Netbeans has auto-complete and feels snappier than Radrails.

I was getting kind of opening the same set of files everytime in SciTe and the tacky way of switching between tabs and so on... Of course it had "sessions".. but I didnt remember to save them at the exact points of time.. All in all not happy.
Then I came across Aptana as a free IDE for ROR. With the now inherent apprehension of switching to something new.. I try it on another machine and it turned out pretty well.. Then I went Live on my dev machine. So here's how I went about it
  1. First stop http://www.aptana.com/rails. Read all about it
  2. Download the community edition from here. Around 90 Megs
  3. Next we install it. Now we need the plugin for Rails for all the goodness.
    • Main Menu > Software Updates > Find and Install... > Search for new features to install.
    • Select 'Aptana: RadRails Development Environment' in the list and click Finish
  4. However the auto-get/update service doesn't want to play with me. It showed that it was unable to reach a certain http location. I copy-pasted that url into the browser and it was reachable. I also found the Aptana page offers on manual RadRails installation
  5. So I did that. I think Aptana restarted once. Next we need to open our existing project in this.. After a few minutes of fiddling..
    • Main Menu > File > Import...
    • Select 'Existing Folder as new project' in the 'Others' category and click Next
    • Now browse and select our ShowMeTheMoney project folder and click Finish
  6. Yodel! Can you feeel the loooovvvveee tooonnaaaaiiigghhhttt ?

I can run my tests with a click of the toolbar button shown above.. and Green bars in the GUI!

We got the project hierarchy on the left, integrated refactoring and automated test support and... I'm speechless with joy (for a few minutes.. before I found something that didnt work.. but hey that's ok. As a developer, I can tolerate that does its basic job well... I found another way to do it in the IDE.) And it does ROCK!!

Aptana is apparently a stripped down version of the Eclipse framework. So Eclipse users should feel at home.. as a Visual Studio user I found myself hunting for keystrokes to switch open editor panes and stuff.. needs some more time at the helm.
But good work.. I pat myself on the back. SciTe has been a trusty steed... but now it has earned its rest at my stable of old tools.

ShowMeTheMoney-14 - The Source Code so far..

This is a listing of all the source files produced till now in this iteration (Note: Some of it comes from the next couple of posts i.e. the pagination plugin. It is more of a snapshot after post ShowMeTheMoney-6


file: /test/unit/expense_test.rb

require File.dirname(__FILE__) + '/../test_helper'

class ExpenseTest < Test::Unit::TestCase
fixtures :expenses
def setup
@firstExpense = getFirstEntry
@fixtureRecordCount = 3
end
def test_create
sDescription = 'Rent'
fAmount = 10000

obExpenseEntry = Expense.new
obExpenseEntry.description = sDescription
obExpenseEntry.amount = fAmount
assert obExpenseEntry.save, obExpenseEntry.errors.full_messages.join("; ")

assert_equal @fixtureRecordCount + 1, Expense.count
obExpenseEntry.reload

assert_not_nil obExpenseEntry.id
assert_not_nil obExpenseEntry.created_at
assert_equal sDescription, obExpenseEntry.description
assert_equal fAmount, obExpenseEntry.amount
end

def test_retrieve
assert_kind_of Expense, @firstExpense
assert_equal expenses(:rent_expense_entry).id, @firstExpense.id
assert_equal expenses(:rent_expense_entry).description, @firstExpense.description
assert_equal expenses(:rent_expense_entry).amount, @firstExpense.amount
assert_equal expenses(:rent_expense_entry).created_at, @firstExpense.created_at
end

def test_saveWithNoDescriptionFails
[nil, " "].each{|value|
@firstExpense.description = " "

assert !@firstExpense.save, "Record saved without description!"
assert_equal 1, @firstExpense.errors.count
assert_equal "can't be blank", @firstExpense.errors.on(:description)
}
end

def test_saveWithNoAmountFails
[nil, " "].each{|value|
@firstExpense.amount = value

assert !@firstExpense.save, "Record saved with non-numeric amount!"
assert_equal 1, @firstExpense.errors.count
assert_equal "is not a number", @firstExpense.errors.on(:amount)
}
end

def test_saveWithZeroOrNegativeAmountFails
[0, -24.00].each{|value|
@firstExpense.amount = value

assert !@firstExpense.save, "Credit of amount 0 saved"
assert_equal 1, @firstExpense.errors.count
assert_equal "should be greater than 0", @firstExpense.errors.on(:amount)
}
end

def test_destroy
assert_nothing_raised { getFirstEntry }

getFirstEntry.destroy

assert_raise (ActiveRecord::RecordNotFound) { getFirstEntry }
end


private
def getFirstEntry
Expense.find(1)
end

end


file: /app/models/expense.rb
class Expense < ActiveRecord::Base
validates_presence_of :description
validates_numericality_of :amount

protected
def validate
if (errors.on(:amount).nil?) && (amount <= 0)
errors.add(:amount, "should be greater than 0")
end
end
end



file: /test/functional/outflow_controller_test.rb
require File.dirname(__FILE__) + '/../test_helper'
require 'outflow_controller'

# Re-raise errors caught by the controller.
class OutflowController; def rescue_action(e) raise e end; end

class OutflowControllerTest < Test::Unit::TestCase
fixtures :expenses
def setup
@controller = OutflowController.new
@request = ActionController::TestRequest.new
@response = ActionController::TestResponse.new
@fixtureRecordCount = 3
end

def test_new
get :new

assert_response :success
assert_template 'new'
assert_not_nil assigns(:expense)
end

def test_list
get :list
assert_response :success
assert_template 'list'
assert_not_nil assigns(:expenses)
assert_equal(@fixtureRecordCount, assigns(:expenses).size )

assert_equal(3, assigns(:expenses)[0].id, "not ordered by date")
assert_equal(1, assigns(:expenses)[1].id)
assert_equal(2, assigns(:expenses)[2].id)
end

def test_index
get :index
assert_response :success
assert_template 'list'
end

def test_create
test_new
sDescription = "movies"; fAmount = 140;
post :create, :expense => {:description=>sDescription, :amount=>fAmount}

assert_response :redirect
assert_redirected_to :action => 'list'
assert_equal @fixtureRecordCount+1, Expense.count

obExpenseEntry = Expense.find(:first, :order=>'id DESC')
assert_equal(sDescription, obExpenseEntry.description)
assert_equal(fAmount, obExpenseEntry.amount)
end

def test_destroy
rentExpenseID = expenses(:rent_expense_entry).id
assert_nothing_raised { Expense.find(rentExpenseID) }

post :destroy, :id => rentExpenseID
assert_equal @fixtureRecordCount - 1, Expense.count
assert_raise(ActiveRecord::RecordNotFound) { Expense.find(rentExpenseID) }

assert_redirected_to :action=>'list'
end
end




file: /app/controllers/outflow_controller.rb
class OutflowController < ApplicationController

def list
@expenses = Expense.paginate :per_page=>10, :page=>params[:page], :order=>'created_at'
end

def index
list
render :action => 'list'
end

def new
@expense = Expense.new
end
def create
@expense = Expense.new(params[:expense])
if (@expense.save)
flash[:notice] = 'Expense entry saved'
redirect_to :action=>'list'
else
render :action=>'new'
end
end

def destroy
Expense.find(params[:id]).destroy
redirect_to :action=>'list'
end
end




file: /app/views/outflow/_form.rhtml

<%= error_messages_for(:expense) %>

<!-- Form for expense -->
<table>
<tr>
<td>
<label for='expense_created_at'>
<%= getAppString(:label_created_at) %>
</label>
</td>
<td>
<%= datetime_select 'expense', 'created_at' %>
</td>
</tr>
<tr>
<td>
<label for='expense_description'>
<%= getAppString(:label_description) %>
</label>
</td>
<td>
<%= text_field 'expense', 'description' %>
</td>
</tr>
<tr>
<td>
<label for='expense_amount'>
<%= getAppString(:label_amount) %>
</label>
</td>
<td>
<%= text_field 'expense', 'amount' %>
</td>
</tr>
</table>


file: /app/views/outflow/new.rhtml


<h1> <%= getAppString(:title_new_expense_page) %></h1>

<% form_tag :action=>'create' do %>
<%= render :partial=>'form' %>
<%= submit_tag getAppString(:label_button_add) %>
<% end %>

<%= link_to getAppString(:label_link_back), :action=>'list' %>


file: /app/views/outflow/list.rhtml

<h1><%= getAppString(:title_list_expense_page)%></h1>

<hr/>
<table class='detailsTable'>
<tr>
<th><%= getAppString(:label_created_at) %></th>
<th><%= getAppString(:label_description) %></th>
<th><%= getAppString(:label_amount) %></th>
</tr>
<% for expense in @expenses %>
<tr>
<td class='transactionDate'> <%= h( expense.created_at.strftime("%d %b %Y" ) ) %> </td>
<td class='transactionDescription'> <%= h( expense.description ) %> </td>
<td class='transactionNumeric'> <%= h( sprintf("%0.2f", expense.amount) ) %> </td>
<td class='delete'><%= button_to getAppString(:label_button_delete), \
{ :action => 'destroy', :id => expense.id },
:confirm => getAppString(:confirm_delete),
:method => :post %></td>
</tr>
<% end %>
</table>
<hr/>

<%= will_paginate @expenses %>

<%= button_to getAppString(:label_button_new), :action => 'new' %>


file: /app/helpers/application_helper.rb

# Methods added to this helper will be available to all templates in the application.
module ApplicationHelper
class ResourceManager
@strings = {
:label_created_at => "Date",
:label_description => "Description",
:label_amount => "Amount",
:label_button_new => "New Entry",
:label_button_add => "Create",
:label_button_delete => "Delete",
:label_link_back => "Back",
:title_new_credit_page => "Yay! Enter credit details here..",
:title_new_expense_page => "Sigh! Enter expense details here..",
:title_list_credit_page => "Inflows",
:title_list_expense_page => "Outflows",

:confirm_delete => "Are you sure you wish to delete this ?",

}
def ResourceManager.getString( sKey )
sKey = @strings[sKey] || "Not found!";
end
end

def getAppString( stringID )
ApplicationHelper::ResourceManager.getString(stringID)
end
end

ShowMeTheMoney-13 - More of the same

Iteration2 Day 1/10
Note: Nothing extraordinary in this post.. one of those when you just have to get your head down and get the work done.. Today might be boring.. it was boring for me to type it all in.. All the source code is listed in the next post

I forgot to add a task for exploratory testing as decided in our iteration review. We’ll do that intermittently throughtout this iteration – we’ll plan for it from the next iteration : we don’t have a dedicated-n-free tester.
Let’s begin by writing the acceptance tests for tracking expenses. This should be similar to what we’ve already done. Instead of creating a new wiki page. Lets continue with the flow of the same page. We have already added 3 credit entries and deleted one. Lets create a new page TestsForTrackingBalance. Copy the existing fixtures over there and extend them. First we transfer the fixtures to the new page…. Done.
!|fit.ActionFixture|
|start|AcceptanceTests.TrackBalance|
|enter|description|PayDay|
|enter|amount|5000|
|press|add_credit_entry|
|check|currentBalance|5000|
|enter|description|Interest|
|enter|amount|1000.50|
|press|add_credit_entry|
|check|currentBalance|6000.50|
|enter|description|PayDay|
|enter|amount|5000|
|press|add_credit_entry|
|check|currentBalance|11000.50|
|enter|select_entry|3|
|press|delete_credit_entry|
|check|currentBalance|6000.50|
The changes are in bold. Created a copy of the fixture ruby class. Renamed it to track_balance.rb – Changed a few method names and voila! Green! Now let’s add our extensions to add expense records at the end of the action-fixture-table. We will add 3 expense records and delete the second one. And then in the row-fixture-table, we retrieve the expense records
...
|enter|description|Rent|
|enter|amount|2550.00|
|press|add_expense_entry|
|check|currentBalance|3450.50|
|enter|description|Apparel|
|enter|amount|450.00|
|press|add_expense_entry|
|check|currentBalance|3000.50|
|enter|description|Apparel|
|enter|amount|500.00|
|press|add_expense_entry|
|check|currentBalance|2500.50|
|enter|select_entry|2|
|press|delete_expense_entry|
|check|currentBalance|2950.50|

!|AcceptanceTests.GetOutflowRecords|
|description|amount|
|Rent|2550.00|
|Apparel|500.00|
Ok so now the acceptance tests have been written. Lets make it happen. So like before, we create the expenses table schema, which is identical to the credits table. We update our 3 DBs with the new schema file. We create a test class for the model (\test\unit\expense_test.rb) and add the test_create method.
def test_create
sDescription = 'Rent'
fAmount = 10000

obExpenseEntry = Expense.new
obExpenseEntry.description = sDescription
obExpenseEntry.amount = fAmount
assert obExpenseEntry.save, obExpenseEntry.errors.full_messages.join("; ")

assert_equal 1, Expense.count
obExpenseEntry.reload

assert_not_nil obExpenseEntry.id
assert_not_nil obExpenseEntry.created_at
assert_equal sDescription, obExpenseEntry.description
assert_equal fAmount, obExpenseEntry.amount
end


We create a model class Expense
file:\app\models\expense.rb

class Expense < ActiveRecord::Base; end


We also add a empty fixtures yml file (\test\fixtures\expenses.yml) That makes it pass. Let’s add test_retrieve
def test_retrieve
obExpense = getFirstEntry
assert_kind_of Expense, obExpense
assert_equal expenses(:rent_expense_entry).id, obExpense.id
assert_equal expenses(:rent_expense_entry).description, obExpense.description
assert_equal expenses(:rent_expense_entry).amount, obExpense.amount
assert_equal expenses(:rent_expense_entry).created_at, obExpense.created_at
end
def getFirstEntry
Expense.find(1)
end


Add records to the fixtures file
rent_expense_entry:
id: 1
created_at: 2008-01-19 00:00:00
description: rent
amount: 10000
apparel_expense_entry:
id: 2
created_at: 2008-02-20 00:00:00
description: A pair of Jeans
amount: 1000.50
I have to update the previous test to expect 3 records after adding a new one. That passes both tests.

Now to add the controller tests. This time we’ll not use the auto-generated scaffolding – we’ll build it one action at a time

>Ruby script/generate controller Outflow new
Next on the list test_new. Make it pass. Lets see how it looks in a browser. Whaa... dummy page?! I'll write up the view using the InflowController's view as reference. But we'll use a table so that the label and its associated field are on the same line. We'll add a note to do the same for the inflow view.
Since we'll need our ResourceManager to lookup strings, we move that to application_helper.rb
Also we need a shorter way to say ApplicationHelper::ResourceManager.getString( :stringID )... something like rails h().. I'll settle for getAppString(:stringID)

Iteration2 Day 2/10
Next we write tests for the list, index(redirects to list) actions so that we can see the records once we add them. Make em pass.
Next we attempt test_create. Make that pass too.
Now we can try out the webpage. We don’t have the styles applied yet… other than that looks just fine. I guess we can that fix that easy. If I rename the controller specific layout ‘inflow.rhtml’ to ‘application.rhtml’, Rails is smart enough to apply it to all controllers. And it works just like that!!
I also make a small change to make the second image-link direct the user to outflow/list action… now that we have it implemented.

Next lets move on to validating the add actions. So we need tests for
  • No description
  • No amount
  • No description and amount (should be covered by above two)
  • Amount not numeric
  • Amount negative or 0
To the model !!
Before that.. a tiny lil refactoring. Hmm I see a recurring ‘obExpense = getFirstEntry’ at the top of more than one test. Time for a setup method and a new instance var in the test class @firstExpense = getFirstEntry. Now I can do away with those duplicate lines …

Ok Model tests done. On to the controller.
Done.. with some refactoring.
Added @fixtureRecordCount to controller and unit test classes to remove magic numbers in the tests

Finally Delete to wrap up this story. Model… test_destroy just passes - coz ATCO by Rails.

Write up a controller test for delete. There.. All Green. That’s just sometime over End of Day2 – Nice work. Lets try out our outflow controller…
First thing we have no entry point for delete. We need to update the outflow/list view to add links for delete. And it works.

Lets take a break!
















ShowMeTheMoney-12 - Iteration#2 Planning

Demo
Based on what we’ve accomplished this iteration, the customer doesn’t feel keen for a demo. He’ll like to look at it after the expenses part is also functional.

Release Plan

  • We reduced the estimate for S#7 by 1 : Authentication story from 3 to 2.
  • We bumped the estimate for S#2 by 1: That story has 2 parts. Tagging expenses with a category and generating reports to know which categories drain the most money.

We have a velocity of 1, meaning we would require 13 more iterations at the current pace. However we will wait for one iteration or two to come with a more accurate velocity.


Iteration Planning
The customer tells us that the priorities haven’t change. Which means we need to do
Story#1 : As a user, I would like to track my daily expenses to know monthly outflows
Story#2 : As a user, I would like to know which expense categories drain the most money for a specified time range, so that I can stop :)

We have to clear up the pending tasks from last iteration – we can chuck out the Push-button-releases and CIS tasks.
S#1 is similar if not identical to S#6. We spent more time on the implementation task last time. So we’re upping that one to 3 ideal hours.

We have a total of 20 hrs to plan for in this iteration. With some slack, we should plan for 15 hours.
S#1 comes out to 7 hours.
S#2 is too big to fit - 12 hrs. However it is logically 2 parts. Add support to tag expense entries for category and Create a report for top N expense categories. The first part comes out to 8 hours.

If we can push the second part to the next iteration, we can do S#1 and the first part of S#2 this iteration. We get confirmation from the customer on the plan of action and he's okayed it.

We also update the release plan to split S#2 into two 1 pt parts.
However this comes out to 2 story points for this iteration. We recorded a velocity of 1 last iteration. So how do we explain it ?
Yes, the last time we spent nearly half the iteration before we got the dev. infrastructure working. That won't be the case this time. Definitely achievable.
The customer is satisfied.. (its real easy when they're both the same person :)

So let's begin iteration#2....

ShowMeTheMoney-11 - Iteration#1 Review


I remember Alistair Cockburn’s advice on conducting an iteration review (Agile Software Development 2nd Ed).. I fish out that section. Iteration review.. its called Reflection Workshops.. here it is …


Iteration Reviews/Reflection workshops
are great coz they give you a breather at the end of an iteration and double up as introspection / discussion time. To improve and get better. Although you should ‘stop-the-line’ as soon as any problem surfaces, end-of-iteration reviews are more relaxed and can serve as grounds for open-discussion Identify problems or ‘broken-windows’ areas that may become troublesome soon, find options/alternatives and plan on tackling them. Large-Refactoring may often lose out to new customer requested features on the priority chain .. But if you can convince yourself on why they need to be done now.. you can more or less persuade the customer to add that to the next iteration’s bucket.
  • Reflect on Product: The customer that is Me, would like the ability to track expenses preferable with categorized reports in the product soon as that would make it useful. Currently it’s just tracking inflows. So we need to build in tracking expenses and a running balance at the minimum in the next iteration or two.
  • Reflect on Progress: We spent the first half trying to get Fitnesse and Rails to run. The second half was when the wheels started to turn. We managed to complete one story with its acceptance tests all passing. We also refined the UI quite a bit from its scaffolding origins. I think we should go faster in this iteration but still we will keep a conservative

  • Reflect on Process: Let’s look at our burndown chart.

I think we’re good with the process. Its working out well.
Only thing from the iteration planning p.o.v., we see that we were flat for an extended period of time in the center – the implementation part. I think we should consider splitting CR into smaller tasks on the CRUD lines. It was annoying to see ‘no progress’ for over 2 days ; even though I was chipping away at it. Also there were some tasks that were not needed like CIS, Push Button releases. We need to cut down on tasks that we can do without. As the lean books say – Be LEAN and MEAN with unwanted complexity!! WRITE LESS CODE!

This format from the book is quick-n-easy in a BigVisibleChart kind of way

ShowMeTheMoney-10 - Take it for a spin

Today we’ll make the UI usable and pretty. This might just be tweaking all the rHTML views. So you might just want to skip this post unless you are looking for Rails view code. There's some screenshots at the end !

I have a concern: We are using the created_at special column name for the date and do not support editing. What if I am entering the records for January in February (I am lazy most of the time) ? Can I do that ?

Only way to find out is to try it out..
So start our app locally via
\ShowMeTheMoney>ruby script\server
So start our app locally - Type in http://localhost:3000/inflow to take us to the list page.

Add a new record, Rails is showing Created At to the user. I edit the Month to last month. Add a description and amount and click ‘Create’
Sure enough ATCO.. way of least surprise. Rails saved it as Jan… saving me some work.

Now to edit the view for the 'list' action,
file: /ShowMeTheMoney/app/views/inflow/list.rhtml
<h1>Inflows</h1>

<!-- Translatable strings -->
<%
@created_at_label = InflowHelper::ResourceManager.getString(:credit_created_at)
@description_label = InflowHelper::ResourceManager.getString(:credit_description)
@amount_label = InflowHelper::ResourceManager.getString(:credit_amount)
%>
<!-- Translatable strings -->

<table>
<tr>
<!-- <% for column in Credit.content_columns %>
<th><%= column.human_name %></th>
<% end %>
-->
<th><%= @created_at_label %></th>
<th><%= @description_label %></th>
<th><%= @amount_label %></th>


<% for credit in @credits %>
<tr>
<!--
<% for column in Credit.content_columns %>
<td><%=h credit.send(column.name) %></td>
<% end %>
-->
<td> <%= h( credit.created_at.strftime("%d %b %Y" ) ) %> </td>
<td style='width:350px;text-align:center'> <%= h( credit.description ) %> </td>
<td style='text-align:right'> <%= h( sprintf("%0.2f", credit.amount) ) %> </td>

<!-- <%= link_to 'Show', :action => 'show', :id => credit %> </td> -->
<!-- <td><%= link_to 'Edit', :action => 'edit', :id => credit %></td> -->
<!-- <td><%= link_to 'Destroy', { :action => 'destroy', :id => credit }, :confirm => 'Are you sure?', :method => :post %></td> -->
<td><%= link_to 'Delete', { :action => 'destroy', :id => credit }, :confirm => 'Are you sure?', :method => :post %></td>
</tr>
<% end %>
</table>

<%= link_to 'Previous page', { :page => @credit_pages.current.previous } if @credit_pages.current.previous %>
<%= link_to 'Next page', { :page => @credit_pages.current.next } if @credit_pages.current.next %>

<br />

<%= link_to 'Add new entry', :action => 'new' %>


file: \ShowMeTheMoney\app\views\inflow\_form.rhtml
<%= error_messages_for 'credit' %>

<!--[form:credit]-->
<p>
<label for="credit_created_at">
<%= InflowHelper::ResourceManager.getString(:credit_created_at) %>
</label><br/>
<%= datetime_select 'credit', 'created_at' %>
</p>

<p>
<label for="credit_description">
<%= InflowHelper::ResourceManager.getString(:credit_description) %>
</label><br/>
<%= text_field 'credit', 'description' %>
</p>

<p>
<label for="credit_amount">
<%= InflowHelper::ResourceManager.getString(:credit_amount) %>
</label><br/>
<%= text_field 'credit', 'amount' %>
</p>
<!--[eoform:credit]-->


file: \ShowMeTheMoney\app\helpers\inflow_helper.rb
module InflowHelper
class ResourceManager
@strings = {
:credit_created_at => "Date",
:credit_description => "Description",
:credit_amount => "Amount",
}
def ResourceManager.getString( sKey )
sKey = @strings[sKey] || "";
end
end
end


Phew! I added a class to avoid duplicating the labels/captions. We just need to chip away at list and new views.
We need a layout – a common look-n-feel for the app. For that we modify the rhtml file with the same name as the controller

file: /ShowMeTheMoney/app/views/layouts/inflow.rhtml
<head>
<%= stylesheet_link_tag 'smtm' %>
<title>ShowMeTheMoney - Inflows</title>
<div class='GrandTitle'> Showing you the money.. </div>
</head>
<body>
<div id='banner'>
<%= link_to( image_tag("inflow.jpg"), {:controller => 'inflow', :action => 'list'} ) %>
<%= link_to( image_tag("outflow.jpg"),
{:controller => 'inflow', :action => 'list'} )
%>
</div>
<p style="color: green"><%= flash[:notice] %></p>
<%= yield %>
</body>
</html>


I found 2 images used in the layout to denote inflow and outflow. Copied it to the ShowMeTheMoney\public\images folder.
Next we add the css styles (shown in bold above) to smtm.css (I copied scaffold.css)

.GrandTitle {
background-color:teal;
color:yellow;
height:30px;
width:100%;
font-family: candara, sans-serif;
font-size:xx-large;
text-align:center;
padding-top:1%;
}

#banner{
background-color:teal;
}
Well that’s it for now. It’s as pretty as I’d like for now. I need to learn all that CSS Stuff one of these days…
Adding an inflow record

List all expenses

Moral of the story: UI in Rails is pretty sweet. The way you can change a small thing in the view, Hit F5 in the browser and ZAP! Improved (hopefully) UI just like you wanted it.