Building an application to track expenses in one hour using GeoChat
Whenever one of our team member travels to another country we tell her to track expenses like food, transportation and accomodation so that later that money can be refunded. Each of us does it in a different way: we write it in a notes application in a cellphone, or in a text file in our computer, or maybe in a web application. The problem with the two first approaches is that the information might be lost: the machine might crash or be lost. The last approach is ok, but then you need to remember to connect to the internet to track the expense, and that can happen several hours after having paid, and our memory is not very good.
So I wanted to simply send an sms message to some number to track my expenses. I carry my cellphone all the time so I can send an sms immediately after paying something. Such an application seems very hard to do at first, specially because of the messaging component: receiving sms, configuring a number, etc. Doesn’t it?
Well, we have GeoChat! GeoChat is an application that lets you create groups of people to stay in touch with them. When a message is sent to a group it will be broadcasted to every member. And not necessarily to their mobile phone: each user can decide to receive emails, twitter updates, an instant message to their jabber client, etc. The original use case is for people in the field to report emergency and disaster situations to recover from them as quickly as possible. But that doesn’t mean we can use it for other purposes.
For example, one thing that you can do is configure a group in GeoChat to forward some or all of the messages to an external service. You can also configure GeoChat not to broadcast its messages.
So here’s the idea: we’ll create a group and we’ll configure it to send every message to an external service. This service will receive messages like “shopping $20″ or “accomodation $300″.
So I started coding it and in one hour I got it working! This new tool is called Xpenz.
That shows us how easy is to build some applications on top of GeoChat. In fact, here we are not using much of GeoChat’s power, mainly the messaging component. For this you could instead use Nuntium, but I decided to use GeoChat since a lot of messaging is already configured for me and I also had the authentication problem solved.
The code is in Google Code, so it’s open source. Let’s review the main logic:
class TrackController < ApplicationController
def expense
name = params[:sender]
if name.blank?
head 'bad_request'
else
User.track :user => name, :message => request.raw_post
head 'ok'
end
end
end
So basically we are getting the sender query parameter, which is the GeoChat login name, and if it is present we track the expense by using the request raw post body. And here’s User#track:
def self.track(options)
user = User.find_or_create_by_name options[:user]
pieces = options[:message].split(' ')
pieces.map!{|x| x.start_with?('$') ? x[1 .. -1] : x}
numbers = pieces.select{|x| x.float?}
texts = pieces.select{|x| !x.float?}
text = texts.join(' ')
if numbers.length == 0
user.currency = text
user.save!
else
if numbers.length == 1
amount = numbers[0].to_f
else
amount = numbers.last
numbers[0 .. -2].reverse.each{|n| text = "#{n} #{text}"}
end
Expense.create! :user => user, :amount => amount, :reason => text, :currency => user.currency
end
end
So the first line finds or create the user in xpenz for the GeoChat user. Then we split the message in spaces and do some logic do termine whether it’s a currency change or an expense track.
The main point here is that I just had to write about 20 lines of code to make it work. Well, maybe 50 because I tested it.
Quick way to test many values in ruby
Many times we end up having similar tests: same logic but different inputs and expected outputs. For example, suppose we need to test our brand new sqrt function:
test "sqrt 1" do assert_equals 1, sqrt(1) end test "sqrt 4" do assert_equals 2, sqrt(4) end test "sqrt 9" do assert_equals 3, sqrt(9) end
Here we are dupplicating code, since “assert_equals X, sqrt(Y)” is written all over the place. The naive way to refactor this is:
def assert_sqrt(input, output) assert_equals output, sqrt(input) end test "sqrt 1" do assert_sqrt 1, 1 end test "sqrt 4" do assert_sqrt 4, 2 end test "sqrt 9" do assert_sqrt 9, 3 end
Much better.
Some languages provide tools to deal with this problem in a nicer way. In C# you can do this:
[Test]
public void TestSqrt(
Values(
new int[] { 1, 1 },
new int[] { 4, 2 },
new int[] { 9, 3 }
) int[] values) {
Assert.Equals(values[1], Sqrt(values[0]));
}
So here we are supplying a set of values for our test. (maybe not much nicer, but the code duplication is gone)
The thing I like most about ruby is that the language gives you the tools to get the most out of your code so you don’t end up inventing classes, attributes or whatever just to make something as simple as supplying many values to a test.
Here’s a better way to do it in ruby:
[[1, 1], [4, 2], [9, 3]].each do |values|
test "sqrt #{values[0]}"
assert_equal values[1], sqrt(values[0])
end
end
Very good!
What makes this possible?
- Ruby lets you define code that will be executed at the class definition level
- Ruby lets you define methods dynamically (here the test function defines a “test_…” method)
Those two particularities makes the language really nice to work with.
Oh, but wait, there’s one more thing. I just found out I can do |input, output| in that last piece of code. It seems that if you iterate an array of arrays, you can specify many arguments to the given block and the i-th argument will match the i-th element of the array, so you don’t end up doing values[0] and values[1], which obfuscates the meaning of our code. Thanks again, ruby!
So, here’s the final code:
[[1, 1], [4, 2], [9, 3]].each do |input, output|
test "sqrt #{input}"
assert_equal output, sqrt(input)
end
end
String concatenation in ruby
I just found out the difference between += and << when used for a string.
irb(main):001:0> str = 'chan' => "chan" irb(main):002:0> str.object_id => 69952758899780 irb(main):003:0> str += 'ged' => "changed" irb(main):004:0> str.object_id => 69952758848800 irb(main):005:0> str << ', now not' => "changed, now not" irb(main):006:0> str.object_id => 69952758848800
So I think that basically you should never use += for strings, unless you really want to hurt the garbage collector.
Ruby-Jump plugin for gedit
I searched the internet for a gedit plugin that would allow me to press a key and jump (navigate) to the file where a ruby class is defined. I couldn’t find one so I wrote one (I know about Geany but I couldn’t find that functionality there either).
Usage
If the file you are editing is located in a ruby on rails projects, this will work automatically. If not, you will need to have the FileBrowser plugin installed and activated. The file browser should be pointing to your project’s root path.
Pressing F3 will jump to the file of the name under the cursor. This uses ruby convention so if your cursor is over the word SomeClass the file some_class.rb will be opened. It also works for some plural forms, so pressing F3 over :my_messages will try to open my_message.rb.
Pressing F4 goes to the test file of the name under the cursor, or to the test file of the current document if no match was found for the previous search. So pressing F4 over SomeClass will open some_class_test.rb.
Download
ruby-jump_0.2.tar.gz – Extract the contents of the file in /home/youruser/.gnome2/gedit/plugins
Keep an eye open on what LINQ does
Today I was profiling an application. The timings pointed to a piece of code that executed a query using LINQ. I opened an SQL profiler and saw what queries were performed. Here they are:
SELECT [t3].[value] AS [Key] FROM ( SELECT ( SELECT [t2].[Role] FROM ( SELECT TOP (1) [t1].[Role] FROM [dbo].[Membership] AS [t1] WHERE ([t1].[UserID] = @p0) AND ([t1].[SocialID] = [t0].[Id]) ) AS [t2] ) AS [value], [t0].[Id], [t0].[IsPrivate] FROM [dbo].[Social] AS [t0] ) AS [t3] WHERE (EXISTS( SELECT NULL AS [EMPTY] FROM [dbo].[Membership] AS [t4] WHERE ([t4].[UserID] = @p1) AND ([t4].[SocialID] = [t3].[Id]) )) AND ((NOT ([t3].[IsPrivate] = 1)) OR (EXISTS( SELECT NULL AS [EMPTY] FROM [dbo].[Membership] AS [t5] WHERE ([t5].[UserID] = @p2) AND ([t5].[SocialID] = [t3].[Id]) ))) GROUP BY [t3].[value]
SELECT [t0].[Id], [t0].[SocialName], [t0].[Title], [t0].[Description], [t0].[IsPrivate], [t0].[CreationDate], [t0].[LastModified], [t0].[Logo], [t0].[LogoUrl], [t0].[CustomSidebar], [t0].[AuthenticatedUserRole], [t0].[Activity] FROM [dbo].[Social] AS [t0] WHERE (((@x1 IS NULL) AND ((( SELECT [t2].[Role] FROM ( SELECT TOP (1) [t1].[Role] FROM [dbo].[Membership] AS [t1] WHERE ([t1].[UserID] = @p0) AND ([t1].[SocialID] = [t0].[Id]) ) AS [t2] )) IS NULL)) OR ((@x1 IS NOT NULL) AND ((( SELECT [t4].[Role] FROM ( SELECT TOP (1) [t3].[Role] FROM [dbo].[Membership] AS [t3] WHERE ([t3].[UserID] = @p0) AND ([t3].[SocialID] = [t0].[Id]) ) AS [t4] )) IS NOT NULL) AND (@x1 = (( SELECT [t6].[Role] FROM ( SELECT TOP (1) [t5].[Role] FROM [dbo].[Membership] AS [t5] WHERE ([t5].[UserID] = @p0) AND ([t5].[SocialID] = [t0].[Id]) ) AS [t6] ))))) AND (EXISTS( SELECT NULL AS [EMPTY] FROM [dbo].[Membership] AS [t7] WHERE ([t7].[UserID] = @p1) AND ([t7].[SocialID] = [t0].[Id]) )) AND ((NOT ([t0].[IsPrivate] = 1)) OR (EXISTS( SELECT NULL AS [EMPTY] FROM [dbo].[Membership] AS [t8] WHERE ([t8].[UserID] = @p2) AND ([t8].[SocialID] = [t0].[Id]) ))) ORDER BY [t0].[Title]
It doesn’t matter what the LINQ code that generated that query was. It looked “nice”. What matters is that I was able to change that LINQ code to do the same thing but using a different expression (instead of using EntitySets in the query, I used context.GetTable<…> and made the joins myself). Here’s the resulting query:
SELECT [t0].[Id], [t0].[SocialName], [t0].[Title], [t0].[Description], [t0].[IsPrivate], [t0].[CreationDate], [t0].[LastModified], [t0].[Logo], [t0].[LogoUrl], [t0].[CustomSidebar], [t0].[AuthenticatedUserRole], [t0].[Activity], [t1].[Role] FROM [dbo].[Social] AS [t0], [dbo].[Membership] AS [t1] WHERE ([t0].[Id] = [t1].[SocialID]) AND ([t1].[UserID] = @p0)
The timings were lower than with the previous queries.
So my recomendation is that you keep an eye open (preferably an SQL profiler open) to see how LINQ translates are queries.
Eclipse plugin to exclude svn and cvs folders in text search
Once again, Sergio was complaining because matches inside svn folders were showing up in search results. Since I like challenges, I wrote this small Eclipse plugin that excludes .svn and CVS folders from searches.
Here’s the relevant file (contains also the source code).
To activate it, first copy it to your plugins folder, restart Eclipse, go to Windows -> Preferences -> General -> Search and select “Better Search Engine” in “Text Search Engine to be used”.
Update: Here‘s the same plugin for Eclipse 3.5 (the other won’t work).
Enjoy!
Eclipse Plugin to sort proposals by hierarchy
Again, Sergio, a friend of mine, came up with a need: to sort Eclipse Java proposals by hierarchy. What that means is that if you have a type C < B < A (where < means subclass of), first C‘s methods will be shown, then B‘s methods and finally A‘s methods.
This is specially useful when writing GUI code with libraries like Swing or SWT, because when you request a ComboBox‘s members you’d normally want to set or change the items to show, what to do when you select an item, maybe less often what’s the size of the component, etc. You’d almost never use methods in bottom-level classes like Object.
So I made a plugin that does exactly that. And better: the proposals are first sort by hierarchy and then by relevance (JDT‘s default order which takes into account, for example, the type of the expected expression).
You can download a copy for free that comes with the source code. To active it first copy the JAR into your plugins directory. Then open Eclipse and go to Windows -> Preferences -> Java -> Editor -> Content Assist and select “by hierarchy” in the combo “Sort proposals”.
Enjoy!
Black theme for Eclipse
A friend of mine just asked me if I had a black theme for Eclipse similar to this one. I didn’t, so I made one. Here’s the result (click to enlarge):
You can download a copy of it. To start using it you must extract the zip file in
$workspace\.metadata\.plugins\org.eclipse.core.runtime\.settings
where $workspace is your workspace location.
Enjoy!
Neyun: an awesome way to visualize your content
As you might already read here and here, the beta release of Neyun is finally with us!
In a nutshell: it’s a web application that allows you to extract your emails, contacts, photos, videos and more from services like Gmail, Facebook, YouTube and Twitter and see them all at once.
So… why use Neyun when you already have access to all these services in their websites? Well, Neyun allows you do do some things you can’t do otherwise, for example:
- Since all your information is accessible in a single place you can search over all your content at once and find results in your emails, photos, videos, etc.
- Even wanted to search photos in Facebook? Just connect your Facebook account to Neyun and search!
- Want to see your friends’ birthdays in a nice way? Turn on the timeline and drag the “Contact” icon to the left.
- Want to see some photos in a cool way? First search or filter your content as you wish and then turn on Cool Iris. For me, that’s one of the coolest features in Neyun.
- See a tag cloud of all your content.
- Explore all your stuff in a timeline so you can quickly see, for example, which mails and twitters your receieved, and which photos you uploaded when you graduated.
I must say I’m pretty excited about this new application. I think you’ll love it, specially if you are into all this cool applications.
There are sure a lot of other nice things you can do with Neyun. If you find something cool you can do with it please send me a comment!
Indentation also means something else…
Some days ago I read this in the Digital Mars D programming language newsgroup.
bearophile says:
http://jeremymanson.blogspot.com/2009/02/small-language-changes-for-jdk7.html
Automated Resource Blocks, to be able to say things like:
try (BufferedReader br = new BufferedReader(new FileReader(path)) {
return br.readLine();
}
instead of:
BufferedReader br = new BufferedReader(new FileReader(path));
try {
return br.readLine();
} finally {
br.close();
}
and Andrei Alexandrescu (one of the designers behind the language) replies:
And he’s so right!
In D you’d write it like this:
Disposable disp = new Disposable();
scope(exit) disp.dispose(); // you can use braces too: scope(exit) { }
disp.doSomething();
disp.doSomethingElse();
I think this concept is really important. You want the important logic of your method to be always at the same indentation level. The things that, well, you need to do to cleanup things, catch errors, etc., should be on a separate indentation level so that the reader of the code (and that can be you, later!) understands it better.
That’s why I prefer this:
void process(Foo someObject) {
if (isNotValidForThisFunctionBecauseOfBar(someObject))
return;
if (isNotValidForThisFunctionBecauseOfBaz(someObject))
return;
// do something else with someObject
}
instead of this:
void process(Foo someObject) {
if (isValidForThisFunctionBecauseOfBar(someObject)) {
if (isValidForThisFunctionBecauseOfBaz(someObject)) {
// do something with someObject
}
}
}
Those last indentation levels are distracting. They are forcing you to read on cascade. The first example clearly marks which are the invalid values for the function, or the exceptional values to be handled, while the second one mixes those conditions with the main logic.
