BlazeDS and open source version of livecycle data services... 2

Posted by Daniel Wanja Thu, 13 Dec 2007 03:35:00 GMT

That sounds cool. Read all about it here…

http://www.techcrunch.com/2007/12/12/adobe-releases-blaze-ds-open-source-version-of-livecycle-data-services/

Maybe not. Techcrunch released this message on their blog but no text was attached and comments where closed. Maybe somebody clicked the submit button to quickly. Now I am curious…

UPDATE: 10:17pm Denver time…it’s official: http://www.adobe.com/aboutadobe/pressroom/pressreleases/200712/121307BlazeDS.html

Rails 2.0 5

Posted by Daniel Wanja Fri, 07 Dec 2007 16:07:46 GMT

Rails 2.0 is out! Thanks guys for all the hard work, this release is just impressive.

Analyzing the Subversion logs from the Rails project with mx:OLAPCube 3

Posted by Daniel Wanja Thu, 29 Nov 2007 05:23:34 GMT

I started playing with Anthony Eden’s ActiveWarehouse and followed his excellent tutorial on how to analyze the Ruby On Rails Svn Commit Log with the ActiveWarehouse framework. Of course this made me want to try to do the same with the new mx:OLAPCube and mx:OLAPDataGrid provided by Flex 3 as part of the DataVisualization components. Let me just say this…I am not done playing with either the Flex OLAPCube nor the Rails ActiveWarehouse framework as these are pretty complex beasts. Both of these frameworks are overlapping and complementary. There are overlapping as both can digest raw data and perform aggregation of that data. They are complementary in the sense that a server side warehouse needs a good visualization front-end. Maybe the OLAPCube and OLAPDataGrid can be this front-end. In my initial trials I haven’t come up with a compelling way to integrate both, but by using some simple SQL I could extract the data from the ActiveWarehouse and pass it to the OLAPCube.

Before going on you may want to read Anthony’s blog and check his presentation on Data Warehouses with ActiveWarehouse. I didn’t find much information on the Flex OLAPCube besides these: Feature_Introductions:_OLAPDataGrid on Adobe’s labs, Flex 3: Feature Introduction Video for OLAP Support, and these Flex examples.

So I create the following sample application. You can try it out here. Note it’s pretty slow, it takes up to a minute to aggregate 10000 values. The Flex team mentioned they didn’t optimize this component yet. I can confirm this. But I may also have messed something up as these are only my initial steps with that component. The application displays the Author dimension with the Author Name as rows and the Time dimension with the Year and Quarter as columns. The facts is the File Change count during that period. Flex calls the “facts” a measure.
20071128_OLAPCube.jpg
Run the applicaiton

To extract the data from the ActiveWarehouse I created this SQL to join the facts table with all the dimensions table. I need to find out if the ActiveWarehouse doesn’t just return this data in xml format by using it’s build-in classes.

  def report_as_xml
    sql = <<-EOSQL
    SELECT
     date.calendar_year,
     date.calendar_quarter,
     date.calendar_month_name,
     author.name,
     file_revision_facts.file_changed AS `file_changed`
    FROM
     file_revision_facts
    JOIN date_dimension as date
     ON file_revision_facts.date_id = date.id
    JOIN author_dimension as author
     ON file_revision_facts.author_id = author.id
    WHERE 
      date.calendar_year > '2005'
    EOSQL

    @@xml ||= ActiveRecord::Base.connection.select_all(sql).to_xml(:dasherize => false)
    render :text => @@xml
  end

In Flex the OLAPCube can be loaded with the XML

    var data:ICollectionView = new ArrayCollection(result.records.record); // is Array
    cube.dataProvider = data;
    cube.addEventListener(CubeEvent.CUBE_COMPLETE, creationCompleteHandler);
    cube.refresh();        

Once the cube is loaded you can slice and dice it in many ways by using an OLAPQuery. I still need to figure out all the possibilities which are offered.

    [Bindable]
    private var cubeResult:IOLAPResult;

    private function creationCompleteHandler(event:CubeEvent):void
    {
        //Cube was created, let's query it
        var query:OLAPQuery = new OLAPQuery;

        // TIME DIMENSION            
        var yearSet:IOLAPSet = new OLAPSet;
        yearSet.addElements(cube.findDimension("Time").findAttribute("Year").members);

        var quarterSet:IOLAPSet = new OLAPSet;
        quarterSet.addElements(cube.findDimension("Time").findAttribute("Quarter").members);

        //year-quarter
        var newTimeSet:IOLAPSet = yearSet.crossJoin(quarterSet);

        // AUTHOR    DIMENSION    
        var authorSet:IOLAPSet = new OLAPSet;
        authorSet.addElements(cube.findDimension("Author").findAttribute("Name").members);

        // ROW/COLUMNS        
        var rowAxis:IOLAPQueryAxis = query.getAxis(OLAPQuery.ROW_AXIS);
        rowAxis.addSet(authorSet.hierarchize(true));
        var colAxis:IOLAPQueryAxis = query.getAxis(OLAPQuery.COLUMN_AXIS);
        colAxis.addSet(newTimeSet.hierarchize(true));

        // QUERY CUBE
        var token:AsyncToken = cube.execute(query);
       token.addResponder(new AsyncResponder(displayResult, olapFaultHandler));
    }
    private function displayResult(result:Object, token:Object=null):void
    {
        cubeResult = result as IOLAPResult;
    }

The cube result is the dataProvider of the Cube which in it’s simplests form can be defined as follows:

<mx:OLAPDataGrid id="olapGrid" dataProvider="{cubeResult}" />

I’ve then added a change listener for the grid to create the dataProvider for the ColumnChart.

    [Bindable]
    private var chartData:Array;

    private function gridSelectionChanged():void {
        if (!(olapGrid.selectedItem is OLAPAxisPosition)) return;
        var rowIndex:Number = olapGrid.selectedIndex;
        var axis:IOLAPQueryAxis = cubeResult.query.getAxis(OLAPQuery.COLUMN_AXIS);
        var columnLength:Number = cubeResult.getAxis(OLAPQuery.COLUMN_AXIS).positions.length;
        var newChartData:Array = [];
        for (var i:int=0;i<columnLength;i++) {
            var tuple:OLAPTuple = axis.tuples[i];
            var key:String = tuple.explicitMembers.toArray().join(",");
            if (key.indexOf("(All)") > -1) continue;            newChartData.push({key:key, value:cubeResult.getCell(rowIndex, i).value});
        }
        chartData = newChartData;
    }
This code to extract a time serie for the chart is a little “hairy”. I hope the Flex team has some OLAPCharts on their todo list ;-)
<mx:ColumnChart id="chart" width="100%" height="30%" dataProvider="{chartData}">
        <mx:series>
            <mx:ColumnSeries yField="value" />
        </mx:series>
        <mx:horizontalAxis>
            <mx:CategoryAxis categoryField="key" />
        </mx:horizontalAxis>
</mx:ColumnChart>

This are my first tribulations with both frameworks. Over the next few month I will have to dive more deeply into the possibilities which are offered. Thanks to both teams as this is pretty cool.

Enjoy! Daniel.

Scripting the Leopard Terminal 14

Posted by Solomon White Wed, 28 Nov 2007 19:38:00 GMT

Hypothetical situation: you’re sitting down with your favorite tasty beverage close at hand for some Rails hacking, and what commands do you run every single time? It’s probably something like this:

RSI
cd Projects/KillerApp
mate .
rake log:clear
tail -f log/development.log

[Command - T for new tab]
cd Projects/KillerApp
mongrel_rails start

[Command - T for new tab]
cd Projects/KillerApp
ruby script/console

[Command - T for new tab]
cd Projects/KillerApp
rake

...etc...

Hmmm. We’re coding DRY, but this bootstrap process doesn’t seem very DRY. This had been bugging me, so I set out on a Google quest to learn to script Terminal.app in Leopard so that I could do something about it. I first looked at AppleScript, since that’s the de facto scripting language of all things Apple. Given a specimen, I could decipher what it was trying to do reasonably well, but going the other way was difficult—starting with a goal, I was generally unsuccessful in trying to express it in AppleScript. This was the best I could come up with:

utopia
tell executive SteveJobs
   tell developers at Apple
      set theScriptingLanguage of OSX to Ruby
   end tell
end tell

Which was a good thought, but didn’t actually do much. At RubyConf last year, Laurent Sansonetti talked about RubyOSA, a scripting bridge between Ruby and the Apple Event Manager, which sounds great, because you can code in Ruby and control AppleScript-able applications, like iTunes. So I ran this:

fail
require 'rbosa'
terminal = OSA.app('Terminal')

Which resulted in this rather discouraging output:

rubyosa-error
RuntimeError: Can't get the target bundle signature
    from /Library/Ruby/Gems/1.8/gems/rubyosa-0.4.0/lib/rbosa.rb:329:in `__scripting_info__'
    from /Library/Ruby/Gems/1.8/gems/rubyosa-0.4.0/lib/rbosa.rb:329:in `app'
    from (irb):3

Hmmm. Not exactly useful. Maybe if I did my coding in iTunes, I could use RubyOSA to build some useful automation. Hopefully someone at Apple can fix Terminal—Hint, Hint. Back to Google…

I eventually ran across Matt Mower’s scripting a better ‘cd’ and then some article. Beautiful. Exactly what I wanted. Except I didn’t want to have to switch to iTerm just to use it. I’m fairly happy with the native Terminal.app in Leopard—the tabs are nice. My biggest complaint is that you cannot name individual tabs, which seems like a glaring omission. Hopefully that will be updated soon.

So Matt’s gp command uses another Ruby / Apple event bridge, called Appscript, which “allows you to control scriptable Mac OS X applications using ordinary Ruby scripts”. Sounds cool, and most of the examples feature TextEdit, which isn’t Terminal, but at least is more of a developer application than iTunes, so we seem to be on the right track.

gem install rb-appscript, and let’s play. In IRB:

appscript1
>> require 'appscript'
>> include Appscript
>> term = app('Terminal')
=> app("/Applications/Utilities/Terminal.app")
>> term.windows
=> app("/Applications/Utilities/Terminal.app").windows
>> term.windows.first
=> app("/Applications/Utilities/Terminal.app").windows.first

Okay, this is a bit strange—it seems to just repeat what you say back to you. After a bit of playing, I understand what’s going on. Some of the methods aren’t executed until you explicitly tell them to execute. For instance:

appscript2
>> term.windows.get
=> [app("/Applications/Utilities/Terminal.app").windows.ID(915), app("/Applications/Utilities/Terminal.app").windows.ID(498), app("/Applications/Utilities/Terminal.app").windows.ID(667)]
>> term.windows.first.get
=> app("/Applications/Utilities/Terminal.app").windows.ID(915)

Why? Most likely, this is for efficiency reasons. With many of these “Event Bridge” solutions, there is a significant “toll” that must be paid to cross the bridge. If we can batch together a string of method invocations and send them across the bridge for a single round trip, it performs much better than multiple round trips would.

At any rate, we can now get a handle on the Terminal application and its already-open windows. The next step is to be able to open new windows and tabs. There is a somewhat useful tool on the rb-appscript download page called ASDictionary, which can examine an application and dump out the objects and methods that it exposes to the bridge. Kinda like rdoc for AppleScript. Running the dictionary against Terminal.app, I found the do_script(command) method, which, when called on the terminal application object, launches a new terminal window and runs the specified UNIX command in it.

appscript3
>> term.do_script("ls")
=> app("/Applications/Utilities/Terminal.app").windows.ID(951).tabs[1]

If you’re following along, you should have a new Terminal window containing a listing of the files and folders in your home directory. Also, notice that the command returns a reference to the first (and only) tab in the new window—we’ll come back to that later. So, new windows, check; now for new tabs.

The Appscript examples show creating new TextEdit documents by executing:

appscript4
app('TextEdit').documents.end.make(:new => :document)

And the Appscript dictionary of Terminal showed the make method, and window and tab classes, so I figured something like this might work:

appscript5
>> window = term.windows.first.get
=> app("/Applications/Utilities/Terminal.app").windows.ID(915)
>> window.make(:new => :tab)
Appscript::CommandError: CommandError
        OSERROR: -10000
        MESSAGE: Apple event handler failed.
        COMMAND: app("/Applications/Utilities/Terminal.app").windows.ID(915).make({:new=>:tab})

    from /Library/Ruby/Gems/1.8/gems/rb-appscript-0.4.0/lib/appscript.rb:505:in `_send_command'
    from /Library/Ruby/Gems/1.8/gems/rb-appscript-0.4.0/lib/appscript.rb:585:in `method_missing'
    from (irb):11

Appscript is having none of that. After many frustrating, fruitless attempts to create a new tab, I found a workaround in native AppleScript here. Here’s the Appscript translation:

appscript6
app("System Events").application_processes[
        "Terminal.app"
     ].keystroke("t", :using => :command_down)

Well, okay, sending a Command-T keystroke works, but it’s a little disappointing. Anyone who knows how to programatically create a new tab, feel free to chime in on the comments, and I’ll update the script.

do_script(command) also takes an optional parameter specifying options. One of the available options is :in, which tells terminal in which window and tab to run the command. Putting this together, we can run a command in the new tab we just created:

appscript7
app('Terminal').do_script("ls", :in => window.tabs.last.get)

We don’t have a handle to the new tab, because it was created via hackery, so we need a handle to its parent window object so we can get at its tabs. Well, our first command we ran with do_script returned us a handle to the first tab of the window, surely we can get the window from that. Right? Anyone?

appscript8
>> tab = term.do_script("ls")
=> app("/Applications/Utilities/Terminal.app").windows.ID(1159).tabs[1]
>> tab.window
RuntimeError: Unknown property, element or command: 'window'
    from /Library/Ruby/Gems/1.8/gems/rb-appscript-0.4.0/lib/appscript.rb:591:in `method_missing'
    from (irb):11
    from :0

(Sigh) Not so much. Time for a hack on a hack, and this one is just embarrassing. Observant readers have probably noticed that the tab referenced shows its parent window id in the string of object references. What if we use that to get a handle to the parent window? Something like this:

evil-hack
>> window = eval("app(\"/Applications/Utilities/Terminal.app\").windows.ID(1159)")
=> app("/Applications/Utilities/Terminal.app").windows.ID(1159)

I’m not proud of it, but it works. Again, if someone knows the “right” way to do this, please let me know—although programatically creating a tab should obviate the need for this hack, too.

Another thing I wanted to change from the original script was that with Matt’s solution, you need to specify the type of project you are opening, either as a command-line argument, or by symlinking the script to a new name with the type embedded. I want the computer to figure all that out for me. Computers are real smart. So my script includes some configurable heuristics for determining project type based on the folder contents. You should be able to specify set of files and folders that defines a project type. For Rails, I used the “skeleton” folders that every Rails app starts with. I haven’t been programming in Erlang very long, so honestly I just guessed at the folders based on some projects I have seen. If you’re a more experienced Erlang programmer, and feel that the project detection or task list should be changed, please let me know.

Matt later enhanced his script to label the iTerm tabs so that you can easily find the tab you need, so naturally I stole incorporated this idea too. It sorta works in Leopard’s Terminal—it does change the name of the Terminal window, but the tab name is unaffected, so you still have to flip through the tabs and watch the window name. This is my biggest request for a feature enhancement for the Terminal, Hint, Hint again, Apple.

So enjoy. You can use the script anywhere—it will look first in your current directory for a matching folder (you only have to specify a non-ambiguous substring of the project folder name), then falls back to the “project root” folder you specify (currently ~/development, ‘cause that’s what I use.). You can configure how deep it should recurse your projects so that the disk seeking time doesn’t eat up all the time you’re saving from not typing the same “cd” commands over and over.

You can download the finished script here. I call it hack, because hack KillerApp flows so nicely as a command. Also, that’s the way I roll. Feel free to send in money, or flattery, or hate mail, I suppose. Thanks to Matt Mower for the inspiration and also to all the other references I’ve linked!

flash.utils.ByteArray compressing 4.1MB to 20K

Posted by Daniel Wanja Tue, 27 Nov 2007 00:01:11 GMT

I am currently preparing a demo using an mx:OLAPCube and OLAPDataGrid which analyze the Rails svn commit log. however I don’t want to deploy a specific server side application as the Cube can load data from XML. So I have an report.xml that is 4.1MB. I created the following AIR application (ZlibCompressor.mxml) that use the standard compression provided by the ByteArray class to compress this file down to 20Kb. The application that consumes this file (UnzipTest.mxml) uses the URLLoader to read this file straight into a ByteArray and uncompress the data. It’s fast!

The key code for compression is the ‘compress’ and ‘uncompress’ method provided by the ByteArray. Note the URLLoader dataFormat is set to “binary”.

ZlibCompressor.mxml

<?xml version="1.0" encoding="utf-8"?>
<mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical"
    nativeDragDrop="onDrop(event)"
    nativeDragEnter="onDragIn(event)"     >
<mx:Script>
    <![CDATA[
    import flash.desktop.ClipboardFormats;    
    import flash.utils.CompressionAlgorithm;
    public function onDragIn(event:NativeDragEvent):void {
        var transferable:Clipboard = event.clipboard;
        if (transferable.hasFormat(ClipboardFormats.FILE_LIST_FORMAT)) {
                DragManager.acceptDragDrop(this);
        }      
    }
    public function onDrop(event:NativeDragEvent):void {
        var fileList:Array = event.clipboard.dataForFormat(ClipboardFormats.FILE_LIST_FORMAT) as Array;
        if (fileList.length==0) return;

        var inFile:File = fileList[0];
        var fileStream:FileStream = new FileStream();
        fileStream.open(inFile, FileMode.READ);
        var ba:ByteArray = new ByteArray();
        fileStream.readBytes(ba, 0, fileStream.bytesAvailable);
        fileStream.close();

        var newFileName:String = inFile.nativePath+".zlib";
        ba.compress();

        var outFile:File = new File(newFileName);
        fileStream = new FileStream();
        fileStream.open(outFile, FileMode.WRITE);
        fileStream.writeBytes(ba, 0, ba.length);
        fileStream.close();        
    }                    
    ]]>
</mx:Script>    
</mx:WindowedApplication>

UnzipTest.mxml

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical" creationComplete="loadData()">
<mx:Script>
    <![CDATA[
    import mx.rpc.events.ResultEvent;
    import flash.utils.ByteArray;

    import flash.events.*;
    import flash.net.*;    

    private function loadData():void {
         var loader:URLLoader = new URLLoader();
         loader.dataFormat = "binary";
         loader.addEventListener(Event.COMPLETE, completeHandler); 
         var request:URLRequest = new URLRequest("../data/report.xml.zlib");
         loader.load(request);
    }
    private function completeHandler(event:Event):void {
        var loader:URLLoader = URLLoader(event.target);
        var ba:ByteArray = loader.data;
        ba.uncompress();
        var s:String = ba.toString();
        var xml:XML = new XML(s);
    }
    ]]>
</mx:Script>    
</mx:Application>

Acts_as_nested_set ActiveRecord rendered with mx:Tree in Flex. 7

Posted by Daniel Wanja Sat, 24 Nov 2007 03:30:13 GMT

ActiveRecord: app/models/category.rb
app/models/category.rb
class Category < ActiveRecord::Base
  acts_as_nested_set
end
Controller: app/controllers/categories_controller.rb
app/controllers/categories_controller.rb
class CategoriesController < ApplicationController
  def index
     Category.result_to_attributes_xml(Category.root.full_set)
  end
end
Flex Application: ActsAsNestedSet.mxml
ActsAsNestedSet.mxml
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" 
    layout="vertical"
    applicationComplete="categories.send()">
<mx:HTTPService id="categories" url="http://localhost:3000/categories" resultFormat="e4x" />
<mx:Tree dataProvider="{categories.lastResult}" 
    labelField="@name"
    width="100%" height="100%" />    
</mx:Application>

Result: 20071123_categories.jpg

XML generated by Category.result_to_attributes_xml(Category.root.full_set):
XML generated by Category.result_to_attributes_xml(Category.root.full_set)
<node name="Main Category" id="15" description="">
  <node name="Cameras &amp; Photo" id="16" description="">
    <node name="Bags" id="17" description=""/>
    <node name="Accessories" id="18" description=""/>
    <node name="Analog Cameras" id="19" description=""/>
    <node name="Digital Cameras" id="20" description=""/>
  </node>
  <node name="Cell Phones" id="21" description="">
    <node name="Accessories" id="22" description=""/>
    <node name="Phones" id="23" description=""/>
    <node name="Prepaid Cards" id="24" description=""/>
  </node>
  <node name="Dvds" id="25" description="">
    <node name="Blueray" id="26" description=""/>
    <node name="HD DVD" id="27" description=""/>
    <node name="DVD" id="28" description=""/>
  </node>
</node>

I used the http://wiki.rubyonrails.org/rails/pages/BetterNestedSet plugin.

Too cool!

UPDATE: The BetterNestedSet plugin doesn’t work out of the box with Rails 2.0 RC1. Thanks Joel for that info. Read more in the comment of this blog entry.

UPDATE2: Thanks Fabien, BetterNestedSet now works with Rails 2.0!

RailsLogVisualizer0.7 for AIR beta 2. 6

Posted by Daniel Wanja Thu, 08 Nov 2007 04:12:00 GMT

I recompiled the RailsLogVisualizer for AIR beta. I added drag&drop of log files to bypass an AIR bug on Leopard. File.browseForOpen doesn't trigger the Event.SELECT when the file is selected. I haven't yet tried this version of the application on older versions of OSX or on Windows. Let me know how it works. Also the feedback when loading large log files could be improved, as the application seems to freeze once the progress bar is complete. Just be a little patient as the AVM is working hard for you to compute all these number.

Install RailsLogVisualizer0.7.air

Install Manually

1) Instal Adobe AIR beta 2. (See release notes if previous version was installed)
Download AIR for OSX Download AIR for Windows
Learn more on AIR

2) Download and install http://myspyder.net/tools/railslogvisualizer/RailsLogVisualizer0.7.air

For time.onrails.org the log file is currently 98Mb and is loaded and process in less than a minute. Here are the loading details:

Loaded 98571986bytes in 28093 milliseconds.
Parsing file. Please Wait this may take some time....
Parsing. Split 1639453entries in 1447 milliseconds.
found:220767 in 1925 milliseconds.
Aggregating data.
	aggregated:220767 in 13426 milliseconds.
	Aggregated:89135
	aggregated String :4440464(bytes) in 2790 milliseconds.
Then you can navigation through time and see how many request where processed and drill down in specific action and specific methods. For example, here we can quickly see that for October 99 people signed up, 869 did login, 22 forgot their password.
20071106_railslogvisualizer.jpg
Enjoy, Daniel.

Finding Balance. 6

Posted by Daniel Wanja Mon, 05 Nov 2007 15:30:27 GMT

Are you a Dad ? Are you thinking becoming one or about to become one? Many people I know in the software development field are Dads and still having fun doing software development, spending late night in front of the computer and getting woken up early by their kids…it’s time to play. My brother in law, RC, is not a software developer but a very successful business man, father of three, dedicates lots of time to his family, is coach on the team for his kids, and regularly manages to take week-ends of with his wife. How does it do all? Well, he even found time to write a book about this. So I offered him to talk about it on my blog as I believe it’s a good read. It’s not only a book about finding balance between your family and work life, but also the influence you can have on your children and children around you. He gave out two chapters of the book and I published them (formatting is not perfect) on http://thenextgenerationofdads.com/.

TABLE OF CONTENTS
Why This Book?
Chapter 1 : Finding Balance
Chapter 2 : Be an Example; Be a Man
Chapter 3 : The Importance of Play
Chapter 4 : Where Do We Draw the Line?
Chapter 5 : Dads and Daughters
Chapter 6 : Teaching Kids about the Real World
Chapter 7 : Raising Independent Thinkers

Chapter 8 : Breaking the Cycle

Sweet way to write Flex Unit tests for Rails

Posted by Daniel Wanja Mon, 05 Nov 2007 15:11:56 GMT

Using ActiveResources from Flex? Using FlexUnit? Here is a nice way to write your tests.

Example Test Case
package tests
{
    import flexunit.framework.*;    
    import mx.rpc.AsyncToken;
    import mx.rpc.events.ResultEvent;
    import resources.Raffles;

    public class TestRaffles extends BaseTestCase
    {    
        private var raffles:Raffles;        
        public function TestRaffles(name : String = null)
        {
            super(name);
            fixtures(["raffles"]);
             raffles = new Raffles();
        }            
        public function testRemoteFindRaffle():void
        {
            assertRemote(raffles.show(1));
        }
        public function assertRemote_testRemoteFindRaffle(data:Object):void
        {
            Assert.assertTrue("Raffle show successfully called", data is ResultEvent);  
            assertEquals("MyString", data.result.name);
        }        

    }
}

Note this code is not yet a plugin and is using code you can find here: http://code.google.com/p/flexonrails/source. I was starting to use it on multiple projects so I thought it was to time find a home for it. Also it is using the org.onrails.rails.ActiveResourceClient Flex class. I would recommend that you use Alex MacCaw’s ActvieResrouce for Actionscript. I still need to talk with Alex and integrate this fixture loading code with his code.

The BaseTestCase Flex class is an extended TestCase that provides support for fixtures. Now in your constructor you can define which fixtures you want to reload between each test. Only tests methods starting with “testRemote” will trigger refreshing the fixtures. As you know, when using AMF or HttpService remote invocations are asynchronous and you cannot test the result of a remote call in the same method than where the call is made from. That’s why I added the assertRemote method which takes an AsyncToken as parameters. This will automatically invoke a method whos name starts with assertRemote_ followed by the test method name. This simplifies greatly writing asynchronous tests. FlexUnit provides the addAsync method, we just add the convenience assertRemote function to setup all the callbacks.

To make this work for you Flex with Rails project. You need to fixtures_controller.rb to your controllers and setup the following routes:

  if RAILS_ENV == "test"
    map.resources :fixtures, :new => { :test_results => :post }
    map.crossdomain '/crossdomain.xml', :controller => 'fixtures', :action => 'crossdomain'
  end

You need to extend your Flex TestCase from tests.BaseTestCase.

Enjoy, Daniel.

Installing RMagick on Leopard (without MacPorts or Fink) 44

Posted by Solomon White Sat, 03 Nov 2007 00:07:00 GMT

I’ve recently upgraded to OS X 10.5 (Leopard), and all-in-all, I’m pleased with the experience. My biggest issue has been the default stacks behavior—the icon changes to the last thing added to the stack, making visual identification unnecessarily cumbersome. I worked around this annoyance (as outlined here) by changing the sort to name rather than date added, and adding a dummy folder named “_1” that will sort to the top. For extra bonus points, I customized the icon of the dummy folder. For some yet unknown reason, the most recently downloaded item still peeks through from time to time, but it’s much better than before.

Maybe it’s my Windows history showing through, but I went with the “clean-sweep” erase and install method. For a non-developer, I’d probably recommend the upgrade (and in fact I used that method for my Father-in-law’s MacBook), but I had lots of custom bits scattered about my machine, and didn’t want to be chasing any incompatibility gremlins.

So now, to get my development environment set up on the new machine… Leopard includes a fairly complete Rails stack out of the box, with a non-broken Ruby, readline support, and most of the commonly used gems. Read more here.

MySQL was not included, but the latest installer (mysql-5.0.45-osx10.4-i686.dmg) for 10.4 from dev.mysql.com downloads worked (mostly) fine. The Server and the StartupItem install and operate correctly. The PrefPane installs, but does not appear to actually do … anything. I’ll have to work on that, but I can live without it for now. After a bit of manual hacking on my database dump file from Tiger (where I was running a 5.1.x beta of MySQL), all my databases are back in place.

One last piece that I needed for my Rails apps—RMagick. I know it’s possible to install RMagick and its dependencies, um, “autoRMagickally” via a package management system like MacPorts or Fink, but I prefer not to. For some background on why not, you can read this article at hivelogic. The last time I was rebuilding my laptop and desktop near the same time, I put together a shell script to automate the process of installing RMagick. I got it back out and dusted off the cobwebs, and voila! RMagick on Leopard. (note: replace wget with “curl -O”, if you don’t have wget installed on your machine) Here’s the code:

install_rmagick.sh
#!/bin/sh
wget http://download.savannah.gnu.org/releases/freetype/freetype-2.3.5.tar.gz
tar xzvf freetype-2.3.5.tar.gz
cd freetype-2.3.5
./configure --prefix=/usr/local
make
sudo make install
cd ..

wget http://superb-west.dl.sourceforge.net/sourceforge/libpng/libpng-1.2.22.tar.bz2
tar jxvf libpng-1.2.22.tar.bz2
cd libpng-1.2.22
./configure --prefix=/usr/local
make
sudo make install
cd ..

wget ftp://ftp.uu.net/graphics/jpeg/jpegsrc.v6b.tar.gz
tar xzvf jpegsrc.v6b.tar.gz
cd jpeg-6b
ln -s `which glibtool` ./libtool
export MACOSX_DEPLOYMENT_TARGET=10.5
./configure --enable-shared --prefix=/usr/local
make
sudo make install
cd ..

wget ftp://ftp.remotesensing.org/libtiff/tiff-3.8.2.tar.gz
tar xzvf tiff-3.8.2.tar.gz
cd tiff-3.8.2
./configure --prefix=/usr/local
make
sudo make install
cd ..

wget http://jaist.dl.sourceforge.net/sourceforge/wvware/libwmf-0.2.8.4.tar.gz
tar xzvf libwmf-0.2.8.4.tar.gz
cd libwmf-0.2.8.4
make clean
./configure
make
sudo make install
cd ..

wget http://www.littlecms.com/lcms-1.17.tar.gz
tar xzvf lcms-1.17.tar.gz
cd lcms-1.17
make clean
./configure
make
sudo make install
cd ..

wget ftp://mirror.cs.wisc.edu/pub/mirrors/ghost/GPL/gs860/ghostscript-8.60.tar.gz
tar zxvf ghostscript-8.60.tar.gz
cd ghostscript-8.60/
./configure  --prefix=/usr/local
make
sudo make install
cd ..

wget ftp://mirror.cs.wisc.edu/pub/mirrors/ghost/GPL/current/ghostscript-fonts-std-8.11.tar.gz
tar zxvf ghostscript-fonts-std-8.11.tar.gz
sudo mv fonts /usr/local/share/ghostscript

wget http://imagemagick.site2nd.org/imagemagick/ImageMagick-6.3.5-9.tar.gz
tar xzvf ImageMagick-6.3.5-9.tar.gz
cd ImageMagick-6.3.5
export CPPFLAGS=-I/usr/local/include
export LDFLAGS=-L/usr/local/lib
./configure --prefix=/usr/local --disable-static --with-modules --without-perl --without-magick-plus-plus --with-quantum-depth=8 --with-gs-font-dir=/usr/local/share/ghostscript/fonts
make
sudo make install
cd ..

sudo gem install RMagick

Older posts: 1 ... 5 6 7 8 9 ... 20