Posted by: fijiaaron | July 1, 2009

static logging class for Code Igniter

Here’s a little time waster that makes logging a bit more pleasurable in Code Igniter:

/**
 * Log class to enable logging directly to a level
 *
 * static examples:
 *
 * Log::info('message');
 * Log::write('message', 'error');
 * Log::write('message'); // default level is 'ERROR'
 * Log::setDefaultLevel('info');
 *
 * instance examples:
 *
 * $log = new Log();
 * $log->info("message");
 *
 * $log2 = new Log('debug'); // sets default level
 * $log2->write("message");
 *
 * Note: static use of DefaultLevel is not thread safe
 */
class Log {

	public static $Level = array('NONE', 'ERROR', 'DEBUG',  'INFO', 'ALL');
	public static $DefaultLevel = 'ERROR';

	public static function write($message, $level=null)
	{
		if (! isset($level) )
		{
			$level = self::$DefaultLevel;
		}

		log_message($level, $message);
	}

	public static function setDefaultLevel($default_level)
	{
		$default_level = strtoupper($default_level);

		if ( in_array($default_level, self::$Level) )
		{
			self::$DefaultLevel = $default_level;
		}
		else
		{
			// fail silently for invalid log level
		}
	}

	public static function error($message)
	{
		log_message('ERROR', $message);
	}

	public static function info($message)
	{
		log_message('INFO', $message);
	}

	public static function debug($message)
	{
		log_message('DEBUG', $message);
	}

	function __construct($default_level = null)
	{
		$default_level = strtoupper($default_level);

		if ( in_array($default_level, self::$Level) )
		{
			self::$DefaultLevel = $default_level;
		}
		else
		{
			// fail silently for invalid log level
		}
	}

	function __call($method, $args)
	{
		$level = strtoupper($method);

		if ( in_array($level, self::$Level) )
		{
			if ( isset($args) )
			{
				$log_message($level, $args);
			}
		}
		else
		{
			// fail silently for invalid log level
		}
	}
}

And here are some tests:

log_message('info', 'testing log_message()');

Log::Info('testing static Log::Info');
Log::deBUG('testing static Log::deBUG');
Log::error('testing static Log::error');
Log::Write('testing static Log::Write with level', 'info');
Log::WRITE('testing static Log::WRITE with no level specified');

$log = new Log('debug');
$log->info('testing instantiated $l->info()');
$log->DEBUG('testing instantiated $log->DEBUG()');
$log->Error('testing instantiated $log->Error()');
$log->write('testing instantiated $log->write() with level', 'info');
$log->write('testing instantiated $log->write() with no level specified');
Log::setDefaultLevel('INFO');
$log->write('testing instantiated $log->write() with no level specified after changing default level');
Posted by: fijiaaron | June 15, 2009

JRuby 1.3.0 not working

I installed JRuby 1.3.0 but when I tried to run “gem” I got the following error message:

C:\ruby\jruby-1.3.0\bin>jruby gem install rails
C:/ruby/jruby-1.3.0/bin/../lib/ruby/site_ruby/1.8/rubygems.rb:881:in `searcher’: Mutex relocking by same thread (ThreadError)
from C:/ruby/jruby-1.3.0/bin/../lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:33:in `require’
from C:/ruby/jruby-1.3.0/bin/../lib/ruby/site_ruby/1.8/rubygems.rb:499:in `ensure_gem_subdirectories’
from C:/ruby/jruby-1.3.0/bin/../lib/ruby/site_ruby/1.8/rubygems/defaults/jruby.rb:12:in `ensure_gem_subdirectories’
from C:/ruby/jruby-1.3.0/bin/../lib/ruby/site_ruby/1.8/rubygems.rb:892:in `set_home’
from C:/ruby/jruby-1.3.0/bin/../lib/ruby/site_ruby/1.8/rubygems.rb:467:in `dir’
from C:/ruby/jruby-1.3.0/bin/../lib/ruby/site_ruby/1.8/rubygems.rb:910:in `set_paths’
from C:/ruby/jruby-1.3.0/bin/../lib/ruby/site_ruby/1.8/rubygems/defaults/jruby.rb:17:in `set_paths’
from C:/ruby/jruby-1.3.0/bin/../lib/ruby/site_ruby/1.8/rubygems.rb:689:in `path’
… 8 levels…
from C:/ruby/jruby-1.3.0/bin/../lib/ruby/site_ruby/1.8/rubygems.rb:1125
from C:/ruby/jruby-1.3.0/bin/../lib/ruby/site_ruby/1.8/rubygems.rb:8:in `require’
from gem:8

C:\ruby\jruby-1.3.0\bin>jirb.bat
C:\ruby\jruby-1.3.0\bin\jirb:16:in `require’: no such file to load — irb (LoadError)
from C:\ruby\jruby-1.3.0\bin\jirb:16

Windows XP X86_64 SP2

C:\ruby\jruby-1.2.0\bin>java -version
java version “1.6.0_14″
Java(TM) SE Runtime Environment (build 1.6.0_14-b08)
Java HotSpot(TM) 64-Bit Server VM (build 14.0-b16, mixed mode)

To add a custom Ruby platform in Netbeans 6.5 (in my case updating from the included JRuby 1.1.4 to JRuby 1.2) :

Install the desired version of JRuby

  • Download Ruby 1.2.0 from jruby.org
  • Extract the zip file to c:\ruby\jruby-1.2.0
  • Test it out by going to the c:\ruby\jruby\1.2.0\bin directory and running ‘jirb’
    (It seems this will only work on Windows if you’re in the bin directory)
  • You can install gems with ‘jruby gem install foo’

Add the new version of JRuby to Netbeans

  • Click on Tools -> Ruby Platforms
  • Click “Add Platform” and navigate to the ruby.bat file.
  • Navigate to the c:\ruby\jruby-1.2.0\bin\ folder and select ruby.bat
    (only the ruby.bat file will work on windows)

Netbeans_Ruby_Platforms

Load and update packages from Netbeans

  • click on Tools -> Ruby Gems
  • To update, select the “Updated” tab
    To Install, select the “New Gems” tab
  • (not the most intuitive, but easy enough to figure out.)

Netbeans_Ruby_Gems

My real gripe is the forced network calls that interrupt the application.  In Netbeans 6.1, your whole IDE was frozen, at least in 6.5 you can hit the “Close” button and cancel the extremely slow package refresh and get back to work.

Because of this, I prefer to load my gems from the command line, especially if you want a different version than the latest.

Load and update packages from the command line

  • cd C:\ruby\jruby-1.2.0\bin
    (don’t forget, you have to be here, or mess with your path)
  • jruby gem update –system
  • jruby gem install rails -v=2.1.2
  • jruby gem install jruby-openssl
    (to get rid of that annoying, but harmless message)

Install previous version of a gem in Netbeans

  • Click on Tools -> Ruby Gems
  • Click on the “Installed Gems” tab
    (note that if you installed gems from the command line, you have to click “Reload Gems” to see them in Netbeans.)
  • Enter a seach term to narrow down the list
  • Click on the “Settings” tab
  • Check “Fetch All Gem Versions”
    (don’t do this before you have a sufficiently narrowed down list or it will take forever.  Unfortunately, if you search for “rails” you see about a hundred packages and all their versions, and this could take hours to load.)

Netbeans_Ruby_Gems_Settings_Tab

Create a new Rails project using my selected versions

  • Click File->New Project
  • Select Category: Ruby
  • Select Projects type: Ruby on Rails Application

Netbeans_Rails_Project

  • Click Next
  • Select JRuby 1.2.0 from the Ruby Platform
  • Netbeans_Rails_project_configComplete the project creation by selecting the Database connection
    (I installed the jdbc-mysql and activerecord-jdbc-mysql gems, and then created the database manually.)

Netbeans_Rails_DB_connection

  • and selecting the rails version
    (optionally installing Warbler and JRuby_OpenSSL Support)

Netbeans_Rails_Project_4

Posted by: fijiaaron | June 13, 2009

Likeminds

If you’re like me, you probably think the last thing the web needs is another social networking site. Either I don’t have that many friends, or my friends don’t use the interweb for socializing.

The other day, I overheard a conversation about a dating site. Now if there’s one thing the web absolutely doesn’t need, it’s another dating site. But as I listened (eavesdropped) I realized that at least some people aren’t really looking for romantic relationships, so much as friends. (Let’s forget about “friends with benefits” for now. )

I noted that what she was looking for in a “match” was someone with shared hobbies and interests. While that may be a successful tactic for finding a mate (I’m doubtful), it’s a pretty good strategy for finding friends.

Being married, I don’t want to join a dating site. I like my wife just fine, thank you. And as long as I stay away from dating sites, she’ll probably like me as well. But you don’t do everything with your spouse. Mind doesn’t care for programming computers or watching the History Military Channel, and I’m not that into sewing.

While those are mostly solo activities, I wouldn’t mind finding someone interested in building or restoring a wooden boat, or playing a pickup game of frisbee golf. You’d think the internet would be good at helping people with things like that. But either I don’t know how, or maybe I just have obscure interests.

But what if there was a website for people to find other people with obscure hobbies that match their own? Surely there’s someone else in the Seattle Area who’d like to build a sailboat, play a tabletop wargame, or frolf with me? Nothing serious., you know. I’m not looking for a commitment, at least not yet.

That’s the idea of likemi/likeminds. A website where you can find your “match”, in a completely non-romantic way, have a “good time”, and maybe even make friends.

The idea is simple. Use the same tools that dating sites use to try to pair people up, but more explicity. You’re not looking for someone who’s into alternate history civil war renactment geo-cache kiteboarding scavenger hunts to fall in love with them, just someone willing to do it with.

The risk is that some people will be interested in falling in love (or having sex). But in order to keep it out of the gutter (or the clouds), we’ll ban those interests. There’s plenty of sites for that stuff already. This one is about actually doing things. If you want to fall in love, do it on your own time.

An exciting idea is that you might also find out about hobbies that you didn’t know about. People that have similar hobbies might have similar tastes. If you’re a kiteboarder, you might be also be a latent civil war buff or vice versa. If not — no big deal, you might be able to find another friend to get you’re Gettysburg fix.

I’m just looking for people with like minds to hang out with. Someone like me.

likemi.net

Posted by: fijiaaron | May 21, 2009

Defining multiple RemoteObjects in MXML

Is it possible to define multiple RemoteObjects in MXML?

For instance:

//amf_tests.mxml


<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
 layout="absolute"
 creationComplete="init()">

<mx:Script>
<![CDATA[

  import mx.collections.ArrayCollection;
  import mx.rpc.events.ResultEvent;
  import mx.controls.Alert;

  [Bindable] private var serviceTypes:Object; // the remote object service names and instances
  [Bindable] private var ro:RemoteObject; // the selected service

  private function init() {
    serviceTypes = { amfphp: amfphp_ro, zendamf: zendamf_ro, sabreamf: sabreamf_ro };
  }

  private function sendRemoteServiceRequest():void {
    ro = serviceTypes[serviceType.text];

    ro.sayHi();
    ro.sayBye();
  }

  private function resultHandler(event:ResultEvent):void {
    Alert.show(event.result.toString());
  }

  private function faultHandler(event:FaultEvent):void {
    Alert.show(event.fault.faultString);
  }

  private function getKeys(obj:Object):ArrayCollection {
    var keys:ArrayCollection = new ArrayCollection();

    for (var key:String in obj) {
      keys.addItem(key);
    }

    // there's got to be a better way to sort than this
    keys = new ArrayCollection(keys.toArray().sort(Array.CASEINSENSITIVE));
    return keys;
  }

\]]>
</mx:Script>

<mx:RemoteObject id="amfphp_ro" source="amf_tests_amfphp.HelloWorld" destination="amfphp">
  <mx:method name="sayHi" result="resultHandler(event)"/>
  <mx:method name="sayBye" result="resultHandler(event)"/>
</mx:RemoteObject>

  <mx:RemoteObject id="zendamf_ro" source="amf_tests_zendamf.HelloWorld" destination="zenfamf">
    <mx:method name="sayHi" result="resultHandler(event)"/>
    <mx:method name="sayBye" result="resultHandler(event)"/>
  </mx:RemoteObject>

  <mx:RemoteObject id="sabreamf_ro" source="amf_tests_sabreamf.HelloWorld" destination="sabreamf">
    <mx:method name="sayHi" result="resultHandler(event)" fault="faultHandler(event)"/>
    <mx:method name="sayBye" result="resultHandler(event)"  fault="faultHandler(event)"/>
  </mx:RemoteObject>

  <mx:HBox>     <mx:Label text="Service Type:"/>
    <mx:ComboBox id="serviceType" dataProvider="{getKeys(serviceTypes)}"/>
    <mx:Button label="Send Request" click="sendRemoteServiceRequest()"/>
  </mx:HBox>

</mx:Application>

// services-config.xml

<?xml version="1.0" encoding="UTF-8"?>
<services-config>

 <services>

 <service id="amfphp-flashremoting-service"
 class="flex.messaging.services.RemotingService"
 messageTypes="flex.messaging.messages.RemotingMessage">
 <destination id="amfphp">
 <channels>
 <channel ref="my-amfphp"/>
 </channels>
 <properties>
 <source>*</source>
 </properties>
 </destination>
 </service>

 <service id="zendamf-flashremoting-service"
 class="flex.messaging.services.RemotingService"
 messageTypes="flex.messaging.messages.RemotingMessage">
 <destination id="zendamf">
 <channels>
 <channel ref="my-zendamf"/>
 </channels>
 <properties>
 <source>*</source>
 </properties>
 </destination>
 </service>

 <service id="sabreamf-flashremoting-service"
 class="flex.messaging.services.RemotingService"
 messageTypes="flex.messaging.messages.RemotingMessage">>
 <destination id="sabreamf">
 <channels>
 <channel ref="my-sabreamf"/>
 </channels>
 <properties>
 <source>*</source>
 </properties>
 </destination>
 </service>
   </services>

 <channels>

 <channel-definition id="my-amfphp" class="mx.messaging.channels.AMFChannel">
 <endpoint uri="/amfphp/gateway.php" class="flex.messaging.endpoints.AMFEndpoint"/>
 </channel-definition>

 <channel-definition id="my-zendamf" class="mx.messaging.channels.AMFChannel">
 <endpoint uri="/zendamf/index.php" class="flex.messaging.endpoints.AMFEndpoint"/>
 </channel-definition>

 <channel-definition id="my-sabreamf" class="mx.messaging.channels.AMFChannel">
 <endpoint uri="/sabreamf/index.php" class="flex.messaging.endpoints.AMFEndpoint"/>
 </channel-definition>

 </channels>

</services-config>

Maybe there’s a typo, but amfphp works, and all the others claim there’s no channel associated with the destination:

[MessagingError message='Destination 'sabreamf' either does not exist or the destination has no channels defined (and the application does not define any default channels.)']

My workaround is to declare the other RemoteObjects in the init() function and not try to use the <mx:RemoteObjects> and the services-config.xml. Definitely less elegant:

private function init():void
 {
   zendamf_ro.source = "HelloWorld";
   zendamf_ro.destination = "zendamf";
   zendamf_ro.endpoint = "http://localhost/zend_amf/index.php";
   sabreamf_ro.source = "HelloWorld";
   sabreamf_ro.destination = "sabreamf";
   sabreamf_ro.endpoint = "http://localhost/SabreAMF/index.php";

   serviceTypes = {amfphp: amfphp_ro, zendamf: zendamf_ro, sabreamf: sabreamf_ro};
  }

I ran across a problem today trying to define a RemoteObject (mx.rpc.remoting.mxml.RemoteObject) in ActionScript instead of a services-config.xml file.

It seems like it would be fairly straightforward

 var myRo:RemoteObject = new RemoteObject();
 myRo.source = "amf_tests.HelloWorld";
 myRo.destination = "amfphp";
 myRo.endpoint = "/amfphp/gateway.php";

but, alas, I found that endpoint isn’t a property, though it looks like it might be in the future. It isn’t even a readily accessible class. You need to build a channelset, add a channel, and then pass a url (and id) to the channel to specify the endpoint. Something like this:

 myRo.channelSet(new ChannelSet().addChannel(new AMFChannel("my_amfphp", "/amfphp/gateway.php")));

The above is equivalent to the following services-config.xml (I think):

<?xml version="1.0" encoding="UTF-8"?>
<services-config>
 <services>
  <service id="amfphp-flashremoting-service" class="flex.messaging.services.RemotingService" messageTypes="flex.messaging.messages.RemotingMessage">
   <destination id="amfphp">
    <channels>
     <channel ref="my_amfphp"/>
    </channels>
    <properties>
     <source>*</source>
    </properties>
   </destination>
  </service>
 </services>
 <channels>
  <channel-definition id="my-amfphp" class="mx.messaging.channels.AMFChannel">
   <endpoint uri="/amfphp/gateway.php" class="flex.messaging.endpoints.AMFEndpoint"/>
  </channel-definition>
 <channels>
</services-config>

This explains it better than me.

Posted by: fijiaaron | May 21, 2009

Actionscript collections

This guy implemented HashMap among other things.  Looks like you just have to cut and paste the listings to get it.
http://www.ericfeminella.com/blog/actionscript-3-apis/

The real problem is, you should be able to iterate over an associative array and get it’s values using array syntax.  I don’t want to call HashMap.put(key, object) and HashMap.get(key) every time.  I want to create an object declaratively like

var foo:Object = {myKey:myObject, anotherkey:anotherObject};

I then want to pass the keys to a dataProvider with foo.getKeys() or retrieve data with foo['mykey'].

I tried creating tacking a function onto the prototype

Object.prototype.getKeys = function(){
  var keys:ArrayCollection = new ArrayCollection();
  for each (key in this)
  {
    keys.addItem(key);
  }
  return keys;
}

But that didn’t seem to work.  (obviously we don’t want to add getKeys() to Object, so I’d create a class that extends Object, only I can’t find out an easy way to pass the literal instantiation

{myKey:myObject, anotherkey:anotherObject};

to the base Object.

Here’s another rant about actionscript and collections:

http://blog.iconara.net/2007/11/25/architectural-atrocities-part-8-is-there-no-equality/

Posted by: fijiaaron | May 20, 2009

Taskboard conceptual Model

taskboard_conceptual_model

See this wiki post for more details:
http://qa-site.com:8080/xwiki/bin/view/Taskboard/%2FModel#Comments

Posted by: fijiaaron | May 12, 2009

moccasin – flex graphical framework

Moccasin looks very interesting for Taskboard.  Move, resize, and undo are built into the framework:

Excerpted from this description by the author of moccasin, Joe Berkovitz:

Moccasin is not a “thin” framework that encapsulates a set of recommended practices like Cairngorm. It’s more of a “thick” framework. Moccasin is aimed at building a particular type of app: one with interactive graphical views that support a lot of mouse gestures, have some notion of compound or nested views, have some notion of a current selection, a clipboard for cut/copy/paste, need robust undo/redo, and must load and save documents to persist the editor state. The views in question are generally not Flex UIComponents in Canvases or Boxes, but lower-level Flash DisplayObjects that can have very arbitrary shapes and layout geometries. Within this domain, Moccasin very much adheres to an MVCS way of thinking: there is a model representing the edited document’s state, a set of views that adjust to the model’s state via events, a controller which changes the model in response to user actions, and a set of services responsible for talking to the world around and outside the application.

Joe Berkovitz is the same guy that wrote the article introducing the MVCS blueprint and is also behind the really cool music notation program Noteflight.

Posted by: fijiaaron | May 11, 2009

flex mvc frameworks

There’s probably already more than enough commentary out there about Flex MVC frameworks.  Instead of adding my limited knowledge to the noise, I’ll link to other discussions.

http://www.anandvardhan.com/2008/11/13/popular-flex-frameworks/

a good primer discussion of several different frameworks and their basic design decisions.  Includes PureMVC, Cairngorm, Mate, Penne, Swiz, easyMVC, Guasax, Model-Glue Flex, & Ruboss.

http://www.adobe.com/devnet/flex/articles/flex_framework.html

compares Cairngorm, Mate, PureMVC, and Swiz with a well-thought-out opinion of strengths and weaknesses of each.  Somewhat surprising coming from an Adobe site, but they’re not trying to sell Cairngorm.

http://www.asserttrue.com/articles/2007/10/17/silvafug-application-frameworks-presentation

A great presentation by Ali Mills and Luke Bayes of PatternPark which helps narrow down the list, and has a discussion about PureMVC and Cairngorm. Summary: they really like PureMVC and dislike Cairngorm.  I think there’s pretty much a consensus that Cairngorm is the EJB 1.0 of Flex framworks.

Frameworks they eliminated due to lack of documentation or community:

  • Slide – doesn’t exist
  • ARP – by Aral Balkan, abandoned
  • Servebox Foundry – not really an MVC framework (they later say it’s worth a second look)
  • Guasax – too early stage, runtime XML configuration (a la Spring), only in Spanish
  • Flest
  • MVCS – by Joe Berkovitz – a blueprint not really a framework – definitely worth reading the article though
  • Model:Glue – port of CF framework, not MVC

Their summary also says they don’t use any particular framework, but that understanding the patterns is important, and Flex itself is often good enough without another framework if you can follow the proper patterns and make correct architecture choices on your own.

If you only look at one framework, look at Cairngorm (because everyone else is using it), but if they had to pick one framework, they’d choose PureMVC.

Note: my characterization of their comments does not necessarily accurately represent their opinions.

http://robsondesign.com/blog/index.php/2009/04/02/puremvc-vs-cairngorm-revisited/

Like the title says, a comparison of PureMVC and Cairngorm, which seem to be the two dominant frameworks.  Mate and Penne seem popular as well among the fans of simplicity in a framework.

http://www.adobe.com/devnet/flex/articles/blueprint.html

Joe Berkovitz’s discussion of MVCS mentioned by Luke & Ali.  It’s definitely worth reading, and includes a sample app that shows a concrete example of his ideas, if not an actual framework.

http://corlan.org/flex-frameworks/

A good list of frameworks, not just MVC, but everything from testing and continuous integration to  remoting  and 3d engines.

http://myflex.org/presentations/ComparingFlexFrameworks.pdf

A comparison of Cairngorm, Mate, PureMVC, and Clear Toolkit, by (I think) the creator of Clear Toolkit.  The first three are MVC frameworks, but Clear Toolkit is a library.  Has a very good architectural overview of each framework.

Older Posts »

Categories