Silence is Foo Mental notes on Ruby/Git/Rails/Flex

30Jun/100

Prowly, a Ruby API wrapper for Prowl (the Growl client for the iPhone)

What is Growl?

Growl lets Mac OS X applications unintrusively tell you when things happen.

What is Prowl?

Prowl is the Growl client for the iPhone OS. Prowl was made to send the Growl notifications to your iPhone when you are not in front of your computer, but since it has an API you can send notifications to your iPhone from where you want.

What is Prowly?

It's a gem and it's an API wrapper (in Ruby), meaning you will be able to send notifications to your iPhone from any Ruby application (Rails, Sinatra, etc.) or even from the terminal.

What do I need to use Prowl in my iPhone?

1. Install the Prowl app

2. Create a Prowl account in this page

Once you created your account, you can register your iPhone and get your  API Key (which is a 40-byte hexadecimal string) from the settings page, this API Key will be used by Prowly to send notifications to your iPhone.

Where can I get Prowly?

Source code: http://github.com/rafmagana/prowly

Installing the gem:

$ gem install prowly

Usage as a Gem (in a ruby application)

require 'rubygems'
require 'prowly'

Prowly.notify do |n|
     n.apikey = "your_apikey_here"
     n.priority = Prowly::Notification::Priority::MODERATE
     n.application = "My Site"
     n.event = "Alert"
     n.description = "Something went wrong!"
end

Another way.

notif = Prowly::Notification.new(:apikey => "your_apikey_here",
                                 :application => "My Site",
                                 :description => "Something went wrong")

api_keys = ["apikey_1", "apikey_2", "apikey_n"]

notif = Prowly::Notification.new(:apikeys => api_keys,
                                 :application => "Prowly",
                                 :description => "Testing...")

response = Prowly.notify(notif)

Usage as a command-line tool

To see the list of options issue the following command:

$ prowly -h

The help is pretty self-explanatory but here is an example:

$ prowly -k "your_apikey_here" -e "My Site" -d "Something went wrong" -p HIGH

Handling the Prowl API response

api_call = Prowly.notify(notif)

Most of the times you'd only have to check if the call failed or succeeded, Prowly has a method to know it:

puts "Cool" if api_call.succeeded?

puts "Oops" unless api_call.succeeded?

But if you want to know the details of the call:

api_call.status # "success" or "error"
api_call.code # 200 for success; 401 or others for error

#api_call.message would be an empty string if the call was successful, so
puts api_call.message if api_call.status == "error" # => Invalid API Key(s)

Since Prowl only allows 1000 calls per hour, it might come in handy you to know your remaining api calls:

puts api_call.remaining if api_call.status == "success" # => 980

puts api_call.remaining if api_call.succeeded? # => 980

Now, what about real-world usages?

* Server monitoring using the God gem (which uses Prowly)=> http://github.com/mojombo/god

get notifications in your iPhone when a process is using a lot of RAM or CPU, or when a process is not running, etc.

* Get notifications when your deployment process is done

*If you have a large set of tests in your application (unit tests, etc), get notifications after all the tests have finished.

* ... etc, etc, etc.

Hope it helps, see you!

Filed under: iPhone, ruby Leave a comment
28Jun/100

Creating a common sorting function for a DataGrid control in Flex

THE PROBLEM

You have several non-related data grids (different columns with different field names) in the same application and you want to sort this columns of different data grids using the same sorting function.

THE SOLUTION

The first try would be using the DataGridColumn#sortCompareFunction method in the following way:

private function mySortingFunction ( obj1:Object, obj2:Object ) : int
{
     //compare <code>obj1.myField</code> against <code>obj2.myField</code> here

     //The function should return a value based on the comparison of the objects:

     //  -1 if obj1 should appear before obj2 in ascending order.
     //   0 if obj1 = obj2.
     //   1 if obj1 should appear after obj2 in ascending order.
}

Now you send the parameter to sortCompareFunction and this parameter must be a defined function

var myColumn:AdvancedDataGridColumn = new AdvancedDataGridColumn();

myColumn.sortCompareFunction = "mySortingFunction";

NOTE: when the user clicks the column header to sort the datagrid Flex internally will call the "mySortingFunction" and will send the proper parameters.

As you can see you have to *specify the field* you want to sort on (the field is hard-coded), what if you want to sort another column field with a different name? you wouldn't be able to do it, you'd have to repeat the same function.

The second try would be the next one:

public class Comparators
{
   public static const NUMERIC:String = "numeric";
   public static const DATE:String = "date";

   public static function sorterProxy(field:String, sortingType:String = NUMERIC):Function
   {
      return function ( obj1:Object, obj2:Object ) : int
      {
         if ( sortingType == NUMERIC )
         {
            return myNumericCompareFunction ( obj1[field], obj2[field] );
         }
         else if ( sortingType == DATE )
         {
          return myDateCompareFunction( obj1[field], obj2[field] );
         }
     }
  }

  private static function myNumericCompareFunction ( obj1:Object, obj2:Object ) : int {}
  private static function myDateCompareFunction ( obj1:Object, obj2:Object ) : int {}
}

As you can see, the sorterProxy method is returning a function (:Function) so we're ok with the sortCompareFunction method requirements.

c1.sortCompareFunction = Comparators.sorterProxy ( "field1", Comparators.NUMERIC );

c2.sortCompareFunction = Comparators.sorterProxy ( "field2", Comparators.DATE );

Ok, all this works, isn't it? I mean, you can add one static constant for every different kind of comparison you need and you'd be able to use the same sorting function in every data grid and every column you want. This would work for a few types of comparison, but if you need to use more than 5 all those IF statements would be very ugly.

Let's try a different approach: An interface and one class for every kind of comparison. This might be called the Strategy design pattern.

This is the contract (IComparator.as file) or the interface

public interface IComparator
{
    function compare ( obj1:Object, obj2:Object ) : int;
}

Comparison classes (in a "comparators" folder)

//DateComparator.as file
public class DateComparator implements IComparator
{
      public function compare ( obj1:Object, obj2:Object ) : int
      {
         //here you'd compare the data in the way you want
      }
}

//SpecialComparator.as file
public class SpecialComparator implements IComparator
{
      public function compare ( obj1:Object, obj2:Object ) : int
      {
         //here you'd compare the special data in the way you want
      }
}

This is the new signature of the sorterProxy method in the Comparators class

public static function sorterProxy(field:String, comparisonStrategy:IComparator):Function
{
      return function ( obj1:Object, obj2:Object ) : int
      {
         return comparisonStrategy.compare ( obj1[field], obj2[field] );
      }
}

Look at the comparisonStrategy type, it's IComparator, which means that all the classes that implements the IComparator interface will be a valid argument because we'd always call the "compare" method, and all the classes that implements such interface must define a method called "compare" that accepts two objects as arguments (integers, strings, etc) and returns an integer (-1, 0 or 1).

Now the final implementation

c1.sortCompareFunction = Comparators.sorterProxy ( "field1", new SpecialComparator() );

c2.sortCompareFunction = Comparators.sorterProxy ( "field2", new DateComparator() );

c3.sortCompareFunction = Comparators.sorterProxy ( "field3", new SpecialComparator() );

Enjoy!

Filed under: as3, flex Leave a comment