Mixin.js: View with model loading timeout

I’m still excited about finally releasing Mixin.js yesterday…and hope other people find it as exciting as me!

I’ve started a repository with examples from my various project (https://github.com/kmalakoff/examples-kmalakoff) and added the following first example for Mixin.js.

class ViewWithModelLoadingTimeout
  constructor: ->
    Mixin.in(this, ['RefCount', => Mixin.out(this)], 'AutoMemory', 'Timeouts')
    @id = _.uniqueId('model_view')
    @el = $("<div id='#{@id}' class='model_loading'></div>").appendTo($('body'))[0]
    @autoWrappedProperty('el', 'remove')
    @addTimeout('Waiting for Model', (=>@render(false)), 20)

  render: (successful_load) ->
    $(@el).remove()
    if successful_load
      @el = $("<div id='#{@id}' class='model_loaded'></div>").appendTo($('body'))[0]
    else
      @el = $("<div id='#{@id}' class='model_failed'></div>").appendTo($('body'))[0]

  callbackModelLoaded: ->
    @killTimeout('Waiting for Model'); @render(true)

# create a view and send tell is that it's model was loaded
view_successful_loading = new ViewWithModelLoadingTimeout()
view_successful_loading.callbackModelLoaded()

# create a view and let the timer get called triggering it to move into a failed state
view_failed_loading = new ViewWithModelLoadingTimeout()
# LATER...
# cleanup - elements removed, timers killed
view_successful_loading.release()
view_failed_loading.release()

If you try out Mixin.js, please share your stories and your mixins!

Download now (Right-click, and use “Save As”):

Or check out the project here: https://github.com/kmalakoff/mixin and look at the tests folder for many more examples!

Backbone-articulation with localized string example

As Jeremy recommended, I’ve listed Backbone-Articulation on the Backbone Wiki. To prepare for some questions (maybe!), I’ve prepared an example:

ENV.LOCALIZED_STRINGS =
  1: 'bonjour'
  2: 'mes'
  3: 'amis'

class LocalizedString
  constructor: (@id) ->
    @string = if (@id!=undefined) and ENV.LOCALIZED_STRINGS and ENV.LOCALIZED_STRINGS.hasOwnProperty(@id) then ENV.LOCALIZED_STRINGS[@id] else 'undefined'

  toJSON: -> return if (@id!=undefined) then {_type:'LocalizedString', id: @id} else null

  @parseJSON: (json) ->
    throw new Error("LocalizedString.parseJSON: unrecognized json") if json._type!='LocalizedString'
    return new LocalizedString(json.id)

# create some models with attributes that need to be serailized and deserialized
model1_1 = new Backbone.Model({id:1, string: new LocalizedString(1)})
model1_2 = new Backbone.Model({id:2, array: [new LocalizedString(1), new LocalizedString(2), new LocalizedString(3)]})
model1_3 = new Backbone.Model({id:3, object: {hello: new LocalizedString(1), my: new LocalizedString(2), friend: new LocalizedString(3)}})

# put them into collection1, serialize collection1, deserialize the json into collection2
collection1 = new Backbone.Collection([model1_1, model1_2, model1_3])
json = collection1.toJSON()

# now imagine the next time the collection is fetched...collection2 is deserialized with the localized strings
collection2 = new Backbone.Collection(); collection2.add(collection2.parse(json))

You can find this example and more (eventually) here: https://github.com/kmalakoff/examples-kmalakoff

Enjoy!

Mixin.js: the Javascript nano-framework

A few months ago, I was using Backbone.Views and many views (or categories of views) had slightly different needs. For example, if one view needed a timeout to check if model failed to load, did all of my views need the timeout functionality. 

I was faced with a fundamental architecture decision. Should I keep pushing functionality higher in my Backbone.View hierarchy to expose the functionality and cause bloat super class bloat, or was there a better way?

I think I found a better way…mixins! 

I started with just mixing in simple Javascript objects, but as I kept developing the idea, I realized that sometimes I needed initialization or cleanup code, and I needed to know which instances had been initialized with which mixins, etc. Plus, it was getting really exciting to try to push my code to the DRYest state possible….

After a few months, I’ve developed quite a sophisticated solution and I think it is mature enough to share publicly so i spent a few days packaging it, writing tests, etc.  I just had to release it because it is so fun and flexible to use!

Here’s a taster:

class StatusBar
  constructor: -> Mixin.in('Subscriber')
  updateProgress: (progress) -> # update bar
  workerDone: -> # clear bar

class HardWorker 
  constructor: ->
    Mixin.in(['Observable', 'progress_update'], 'AutoMemory', 'Backbone.Events')
    @list = new Background.List(100); @autoProperty('list', 'destroy')
    @list.append(null, (=>doWork()))
  doWork: ->
    # do something
    @notifySubscribers('progress_update', progress)

status_bar = app.getStatusBar()
worker = new HardWorker()
worker.addSubscriber(status_bar, 'progress_update', status_bar.updateProgress, 
	{destroy:status_bar.workerDone})

# later use a Backbone.Event to kill the worker and and the status bar 
# is notified (workerDone) and the background list (BGList) is cleaned up
worker.trigger('destroy')

I’ll write more examples over the coming days and weeks. Enjoy!

Download now (Right-click, and use “Save As”):

Or check out the project here: https://github.com/kmalakoff/mixin 

Introducing Backbone.Articulation!

Have you ever wished that you can control the lifecycle or serialization/deserialization of your Backbone.Model attributes? Well, now you can!

Backbone.Articulation complies with various attribute lifecycle conventions of your attributes:

  1. clone() and destroy()
  2. retain() and release()
  3. new() only and using Javascript’s garbage collection
  4. plain old JSON (with no custom serialization)

And if you want custom serialization/deserialization, just add toJSON() instance method and parseJSON class or factory method to your classes.

Please note the difference between toJSON and parseJSON: toJSON will be found on your instance whereas parseJSON will be found in the global namespace (just like Javascript’s Date.parse()).

All of this is achieved using underscore enhancements…(http://braincode.tumblr.com/post/10682303919/addawesomefeatures).

Download now (Right-click, and use “Save As”):

Production: Background-Articulation.min.js

Or check out the project here: https://github.com/kmalakoff/backbone-articulation 

Enjoy!

Until the dependent changes have been merged into and released with the 
main projects, please use my modified versions of:
- Underscore.js https://github.com/kmalakoff/underscore
- Backbone.js (https://github.com/kmalakoff/backbone

_.addAwesomeFeatures()

As you can see from the title, I’m quite excited (!) by a few things I’ve taken from my personal project and have repackaged, tested, and sent a pull request to the main DocumentCloud/underscore repository.

Highlights:

1) Keypaths (_.hasKeypath, _.keypath, _.keypathValueOwner) - rather than just using simple keys to reference properties, you can use keypaths (dot-delimited strings or arrays of strings) to traverse you object.

Examples:

  • _.keypath({hello: {world: ‘!’} }, ‘hello.world’); // returns ‘!’
  • _.keypathValueOwner({hello: {world: ‘!’} }, ‘hello.world’); // returns hello

2) Type Conversions (_.resolveConstructor, _.toType) - _.toType introduces a convention of _.to{SomeType} and complies with underscore’s _.is{SomeType} convention if the constructor name or instanceof don’t find a match. Useful it you wrap a class inside another.

Examples:

  • var constructor = _.resolveConstructor(‘SomeNamespace.SomeClass’), instance = new constructor();
  • var actual_date = _.toType(wrapped_date, ‘Date’);

3) Removal (_.remove) - provides many variants on how to remove something from an array or object collection. 

Examples:

  • var removed = _.remove([2,4,2], 2); _.isEqual(removed, 2);
  • var removed = _.remove({bob: 1, fred: 3, george: 5}, [‘bob’, ‘george’]); _.isEqual(removed, [1,5]);

4) JSON serialization (_.toJSON, _.parseJSON) - provides a convention for serializing and deserializing class instances (with a configurable _type property).

Examples:

  • var plain_old_json = _.toJSON(some_instance), some_instance_copy = _.parseJSON(plain_old_json);
  • var namespaced_instance = _.parseJSON({_type: ‘SomeNamepace.SomeClass’, prop1: 1, prop2: 2});

5) Object Lifecycle (_.own, _.disown) - handles individual objects, arrays, and object properties that comply with some lifecycle conventions:

  1. clone() and destroy()
  2. retain() and release()
  3. clone() and Javascript memory management
  4. plain old JSON 

Examples:

  • var an_object = new Object(); var owned_copy_object = _.own(an_object); _.disown(an_object);
  • var an_array = [new Object(), ‘hello’, new Object()]; var owned_copy_array = _.own(an_array); _.disown(an_array);
  • var an_object = {one: new Object(), two: new Object(), three: ‘there’}; var owned_copy_object = _.own(an_object, {properties:true}); _.disown(an_object);

6) Compare for the rest of us (_.compare) - wraps built in compare with self-evident return types (_.COMPARE_EQUAL, _.COMPARE_ASCENDING, _.COMPARE_DESCENDING) and allows objects to provide custom compare methods.

Examples:

  • if (_.compare(‘x’, ‘y’) === _.COMPARE_ASCENDING) return ‘y’ 
  • if (_.compare(‘こんにちは’, ‘さようなら’, ‘localeCompare’) === _.COMPARE_ASCENDING) return ‘さようなら’; 
  • if (_.compare(custom_compare_instance, ‘a string’) === _.COMPARE_ASCENDING) return custom_compare_instance;

7) Super helpers (_.getSuperFunction/_.superCall/_.superApply) - useful if you don’t know what the super class will be ahead of time:

  • local_backbone_collection_mixin { _add: function(model) { if (!model.id) model.id = model.cid;); _.superApply(this, ‘_add’, arguments); } };

And more: _.cloneToDepth, _pluck with remove, _.findIndex, _.functionExists/_.callIfExists, and _.getValue with default if missing.

Hopefully, these will get integrated into the main branch, but if not, you can find an add-on pack at: https://github.com/kmalakoff/underscore-awesomer.

Download now (Right-click, and use “Save As”):

Enjoy!

Background.js now with multi-dimensional arrays!

I had a need for combining arrays on a background thread and after a bit of thought, I came up with a simple way to iterate over any number of arrays in fixed sized batches.

For example, you may want to apply the same list of filters to some models and then based on the results, so some more heavy processing. Take a look at this gist for a code snippet.

Enjoy!

Download now (Right-click, and use “Save As”):

Or check out the project here: https://github.com/kmalakoff/background

Background.js

I’ve been writing a single page CoffeeScript web app and needed to put some processing on a background thread so my GUI would remain responsive.

I found some articles referring to a good JavaScript WorkerQueue library so I gave it a shot.

After playing with it, I realized that I needed some extra functionality:

1) set up and clean up before and after the worker is run

2) the ability to destroy the worker queue (to support a single page app) 

3) Array iterator helpers to keep the code DRY

If you are interested in theses capabilities in an easy to use background queue and list library, download now (Right-click, and use “Save As”):

Or check out the project here: https://github.com/kmalakoff/background

Enjoy!

git flow release finish first_missing_piece_android

I was able to port the Objective-C CouchMover to Java for the android version!

The interface is basically the same so it should be familiar:

PasswordAuthentication credential = new PasswordAuthentication("admin", 
   "admin".toCharArray());
credential = null; // NO USER/PASSWORD ON ANDROID
CouchMover couchMover = new CouchMover(serverURL, credential, "mycouchapp_db");
    
couchMover.loadDocumentFromAssetManager(getAssets(), "_design/mycouchapp", 
   "mycouchapp.json", "mycouchapp.version");
couchMover.loadDocumentFromAssetManager(getAssets(), "mydata", 
   "mydata.json", "mydata.version");

couchMover.gotoAppPage("_design/mycouchapp", appView, "index.html");

I also wrote a small helper CouchStarter that encapsulates the installation process for Couchbase. I’m not planning on maintaining it for production purposes, but it should be useful for getting up and running quickly. 

You can find the code, samples, and a README here: https://github.com/kmalakoff/phonegap-couchbase-xplatform 

Note: it works reasonably well, but I believe due to the refactoring of the Couchbase android version, the underlying couchlib-android library has a few limitations (it should work on Android SDK 2.1, 2.2 and 2.3 although I only tested on Android 2.3.1 and 2.3.3, and view generation seems to cause an exception in Couchbase). Once it works flawlessly, I’ll update this post.  

Enjoy!

git flow release finish first_missing_piece

Today, I published what I solution to the first missing piece:

Allow for offline CouchApp loading since you cannot assume there will be a connection to download a CouchApp

that I hope others will find useful and efficient to use in their day-to-day development workflow.

Workflow

To end up with a nicely packaged couchapp, views, and application seed data, you need to decide what workflow you want to follow during development, testing, release, etc. I chose the following process:

  1. use source files for everything. I originally tried to edit views in futon, but besides not having source files that could be checked into version control, after the first edit, the web formatting made it difficult to maintain.
  2. develop and debug on my laptop to take advantage of a full suite of browser developer tools. If you want to get a feel for how difficult directly testing in phonegap can be, take a look at the following post: http://www.phonegap.com/2011/05/18/debugging-phonegap-javascript.
  3. run on a mobile simulator or hardware periodically after testing on laptop/PC. This should catch device-specific problems and differences after the general problems have been fixed in a more productive laptop/PC development environment.

In order to achieve this result, I am using the following development workflow:

  1. use soca on my local filesystem to have source files for everything including the couchapp, views, and application seed data.
  2. use ‘soca autopush’ to propagate any local changes into a couch development server. Note: I added a new flag to soca’s config.js file so until the main branch picks it up (fingers crossed), you will need to use my copy in GitHub.
  3. use ‘couchpack database_url destination_file —auto’ to watch for and pack all changes into my iOS project’s Resources directory. I wrote the couchpack and couchwatcher gems for this purpose.
  4. build and run in XCode
  5. use an Objective-C class called ‘CouchMover’ to check packed version files for changes at runtime and to upload on app launch. I released this class in the phonegap-couchbase-xplatform GitHub repository.

Note: currently, this workflow has only been tested on the Mac OSX platform and does not yet have sample code for an android version. Volunteers are welcome!

Setup details

Install: soca 

For now, you’ll need to get a local copy from GitHub and to build/install a local copy:

sudo gem uninstall soca
git clone git@github.com:kmalakoff/soca.git
cd soca
sudo rake install

Install: couchpack 

sudo gem install couchpack

Usage - Laptop/PC

I recommend you download the cross-platform demo project at: https://github.com/kmalakoff/phonegap-couchbase-xplatform. It demonstrates the workflow and you won’t be slowed down with setting up a PhoneGap/Couchbase project from scratch.

In the demo project, you will find a file called couch_automate.rb. It demonstrates how you can launch all of the soca and couchpack watching with one command ‘ruby couch_automate.rb’. Here’s the meaningful parts:

exec 'cd soca/mycouchapp; soca autopush'
exec 'cd phonegap-couchbase-ios/phonegap-couchbase-ios/Resources; 
   couchpack document http://localhost:5984/mycouchapp_db/_design/mycouchapp 
      mycouchapp --auto'

The first line starts watching the soca project and pushes changes into the couchdb document; the second line starts watching the couchdb document and packs any changes into the iOS Xcode project Resources directory.

Usage - Objective-C

When you receive the CouchbaseDelegate's method callback couchbaseDidStart you can use the CouchMover class to check for version changes in your packed Resources and if there are changes, upload them to the iOS Couchbase CouchDB using the following:

NSURLCredential *credential = [NSURLCredential credentialWithUser:@"admin" 
  password:@"admin" persistence:NSURLCredentialPersistenceForSession];
CouchMover* couchMover = [[CouchMover alloc] init:serverURL 
  serverCredential:credential databaseName:@"mycouchapp_db"];
[couchMover loadDocumentFromBundle:[NSBundle mainBundle] 
  documentName:@"_design/mycouchapp" 
  documentBundlePath:@"mycouchapp.json" 
  versionBundlePath:@"mycouchapp.version"];
[couchMover gotoAppPage:@"_design/mycouchapp" webView:self.webView 
  page:@"index.html"];
[couchMover release];

The CouchMover class is flexible enough to upload documents which can be packaged couchapps, views, or application seed data to any database (just call ‘[couchMover setDatabaseName:@”yourdatadatabasename”]’ to switch databases) and can be used without the bundles if you prefer (just call ‘[couchMover loadDocument:documentName version:version getAppAsJSONDataBlock:yourblock_returningNSData]’)

Gotchas

There are many and I’ll maintain this list based on your feedback:

  1. To get the sample running on actual hardware, you’ll need to register the app with Apple using these PhoneGap instructions: http://wiki.phonegap.com/w/page/39991939/Getting-Started-with-PhoneGap-iOS-using-Xcode-4-(Template-Version
  2. After you pack your couchdb documents for the first time, you need to drag them into your XCode project’s Resources directory.
  3. In order to not have your PhoneApp switch to the local Safari app when you call [webView stringByEvaluatingJavaScriptFromString:couchappApgeURL], you need to add localhost to the ExternalHosts key in your PhoneGap.plist. Select your PhoneGap.plist in the “Supporting Files” directory, and add the following 2 items as separate entries: 127.0.0.1 and 0.0.0.0.
  4. The CouchMover Objective-C class  current has dependencies on TouchFoundation’s classes on NSData asBase64EncodedString. If you aren’t linking with TouchFoundation, include the files that you find in the sample project’s Vendor/TouchFoundation_MinimalExtraction in your project.

Done! Well, if only reality were that simple… I’m happy to update this post and answer your questions as you are confronted with real-world problems in getting this to work.

Good luck!

Kevin

open.(“source”)

A colleague at work (thank you Stephane!) recommended that I consider Couchbase-iOS (https://github.com/couchbaselabs/iOS-Couchbase) for my mobile project.

Before choosing RhoSync as my syncing solution a few months ago, I spent weeks investigating options for a syncable offline database solution for cross-platform mobile applications - RhoSync seemed to be the only show in town. With Couchbase-iOS, I have to admit that I was a bit hesitant because it is still in beta and there were some obviously missing pieces, but after doing some research into CouchDB, it became clear that it wasn’t a matter of “if” Couchbase takes off, but “when”. So I decided to jump in and help to open source community build some of those missing pieces!

To address some of the missing pieces, I drafted a list of currently missing pieces:

  1. Allow for offline CouchApp loading since you cannot assume there will be a connection to download a CouchApp.
  2. Provide a standard way for users to to authorized locally and to create an account on a remote server.
  3. Provide best practice samples for organizing and syncing local and remote databases. For example: using local databases like “appdata_db” with server databases like “myusername/appdata_db” and making sure authentication and authorization is secure.
  4. Allow for users to trigger synchronizations from their mobile device while handling B. and C.
  5. Cross-platform project creation in as simple and trouble free way as possible.

Also, I created a demonstration project (https://github.com/kmalakoff/phonegap-couchbase-xplatform) on GitHub that I hope will demonstrate solutions to these and more design problems.

Enjoy!

Kevin