I <3 CoffeeScript and Angular.js. Here’s a little technique to make Angular controllers play better with CoffeeScript classes:

Here’s a running example: http://plnkr.co/edit/XqYizAvY5DADziwurgRE?p=preview

1
2
3
4
heroku[web.1]: Error R10 (Boot timeout) -> Web process failed to bind to $PORT within 60 seconds of launch
heroku[web.1]: Stopping process with SIGKILL
heroku[web.1]: Process exited with status 137
heroku[web.1]: State changed from starting to crashed

After tons of boot timeouts of a Heroku Ruby on Rails app (Error R10), it was time to optimize the app.

What I did:

  1. Removed some gems require on load and required on demand in runtime
    1
    2
    3
    
    gem 'aws-sdk', require: false
    gem 'rmagick', require: false
    ...
    
    To know what gems take the most time to load, I added the following code to config/boot.rb (thanks to this answer on StackOverflow)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    
    require 'benchmark'
    
    def require(file)
      result = nil
      puts Benchmark.measure("") {
        result = super
      }.format("%t require #{file}")
      result
    end
    
    watched the app’s log and analyzed the slowest gems.
  2. Made sure no external resource access is made during boot (Redis, Neo4j, Solr) except MySQL which is on RDS and Rails requires this connection on start. To do that, I pointed all resources to non-existing ones and started the app locally. No operation is done with the DB on boot.
  3. Precompiled all assets locally and pushed to S3 with asset_sync gem (optimized precompilation with gem turbo-sprockets-rails3)
  4. Moved all asset-related gems into :assets group in the Gemfile (jquery-railssass-rails, coffee-railscompass-rails etc)
  5. Switched to Ruby 1.9.3 - https://devcenter.heroku.com/articles/ruby-versions
  6. Removed rails_admin from the main app as it adds a few seconds to boot even if initialization is skipped. I’m going to create another, smaller app that’ll contain only rails_admin, its dependencies, models, observers etc.

Result: Heroku boot time less than 30s.

On my local machine I get 15s on production env (including the connection to external DB on RDS), but maybe it’s only because I have a faster CPU than Heroku’s (i7 2.7).

Jastor on Github ]

Jastor is an Objective-C base class that is initialized with a dictionary (probably from your JSON response), and assigns dictionary values to all its (derived class?s) typed @properties.

It supports nested types, arrays, NSString, NSNumber, NSDate and more.

Jastor is NOT a JSON parser. For that, you have JSONKit, yajl and many others.

The name sounds like JSON to Objecter. Or something.

Examples

You have the following JSON:

1
2
3
4
{
    "name": "Foo",
    "amount": 13
}

and the following class:

1
2
3
4
5
6
7
8
@interface Product
@property (nonatomic, copy) NSString *name;
@property (nonatomic, copy) NSNumber *amount;
@end

@implementation Product
@synthesize name, amount;
@end

with Jastor, you can just inherit from Jastor class, and use initWithDictionary:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// Product.h
@interface Product : Jastor
@property (nonatomic, copy) NSString *name;
@property (nonatomic, copy) NSNumber *amount;
@end

// Product.m
@implementation Product
@synthesize name, amount;
@end

// Some other code
NSDictionary *dictionary = /* parse the JSON response to a dictionary */;
Product *product = [[Product alloc] initWithDictionary:dictionary];

// Log
product.name // > Foo
product.amount // > 13

Nested Objects

Jastor also converts nested objects to their destination type:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
// JSON
{
    "name": "Foo",
    "category": {
        "name": "Bar Category"
    }
}

// ProductCategory.h
@interface ProductCategory : Jastor
@property (nonatomic, copy) NSString *name;
@end

// ProductCategory.m
@implementation ProductCategory
@synthesize name;
@end

// Product.h
@interface Product : Jastor
@property (nonatomic, copy) NSString *name;
@property (nonatomic, copy) ProductCategory *category;
@end

// Product.m
@implementation Product
@synthesize name, category;
@end

// Code
NSDictionary *dictionary = /* parse the JSON response to a dictionary */;
Product *product = [[Product alloc] initWithDictionary:dictionary];

// Log
product.name // > Foo
product.category // >
product.category.name // > Bar Category

Arrays

Having fun so far?

Jastor also supports arrays of a certain type:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
// JSON
{
    "name": "Foo",
    "categories": [
        { "name": "Bar Category 1" },
        { "name": "Bar Category 2" },
        { "name": "Bar Category 3" }
    ]
}

// ProductCategory.h
@interface ProductCategory : Jastor
@property (nonatomic, copy) NSString *name;
@end

// ProductCategory.m
@implementation ProductCategory
@synthesize name;
@end

// Product.h
@interface Product : Jastor
@property (nonatomic, copy) NSString *name;
@property (nonatomic, retain) NSArray *categories;
@end

// Product.m
@implementation Product
@synthesize name, categories;

+ (Class)categories_class {
    return [ProductCategory class];
}
@end

// Code
NSDictionary *dictionary = /* parse the JSON response to a dictionary */;
Product *product = [[Product alloc] initWithDictionary:dictionary];

// Log
product.name // > Foo
product.categories // >
[product.categories count] // > 3
[product.categories objectAtIndex:1] // >
[[product.categories objectAtIndex:1] name] // > Bar Category 2

Notice the declaration of

1
2
3
+ (Class)categories_class {
    return [ProductCategory class];
}

it tells Jastor what class of items the array holds.

Nested + Arrays = Trees

Jastor can handle trees of data:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
// JSON
{
    "name": "1",
    "children": [
        { "name": "1.1" },
        { "name": "1.2",
          children: [
            { "name": "1.2.1",
              children: [
                { "name": "1.2.1.1" },
                { "name": "1.2.1.2" },
              ]
            },
            { "name": "1.2.2" },
          ]
        },
        { "name": "1.3" }
    ]
}

// ProductCategory.h
@interface ProductCategory : Jastor
@property (nonatomic, copy) NSString *name;
@property (nonatomic, retain) NSArray *children;
@end

// ProductCategory.m
@implementation ProductCategory
@synthesize name, children;

+ (Class)children_class {
    return [ProductCategory class];
}
@end

// Code
NSDictionary *dictionary = /* parse the JSON response to a dictionary */;
ProductCategory *category = [[ProductCategory alloc] initWithDictionary:dictionary];

// Log
category.name // > 1
category.children // >
[category.children count] // > 3
[category.children objectAtIndex:1] // >
[[category.categories objectAtIndex:1] name] // > 1.2

[[[category.children objectAtIndex:1] children] objectAtIndex:0] // >
[[[[category.children objectAtIndex:1] children] objectAtIndex:0] name] // > 1.2.1.2

How does it work?

Runtime API. The class?s properties are read in runtime and assigns all values from dictionary to these properties with NSObject setValue:forKey:. For Dictionaries, Jastor instantiates a new class, based on the property type, and issues another initWithDictionary. Arrays are only a list of items such as strings (which are not converted) or dictionaries (which are treated the same as other dictionaries).

Installation

Clone Jastor from github: https://github.com/elado/jastor

Copy Jastor.m+.h and JastorRuntimeHelper.m+.h to your project, create a class, inherit, use the initWithDictionary and enjoy!

REALLY Good to know

Where?s the dealloc in the inheritor classes?

dealloc is implemented in the base class and it nilifies all properties.

What about properties that are reserved words?

As for now, id is converted to objectId automatically. Maybe someday Jastor will have ability to map server and obj-c fields.

Jastor classes also conforms to NSCoding protocol

So you get initWithCoder/encodeWithCoder for free.

You can look at the tests for real samples.

After complaining to our developers about using the old, <1.8’s => syntax in hashes, I was challenged by my ninja colleague Avi Tzurel to create a script that will convert all the old Ruby hash syntax to the new 1.9, beautiful colon notation.

I came up with this:

1
2
3
4
5
6
7
8
Dir['**/*.rb'].each { |f|
  s = open(f).read
  awesome_rx = /(?<!return)(?<!:)(?<!\w)(\s+):(\w+)\s*=>/
  count = s.scan(awesome_rx).length
  next if count.zero?
  s.gsub!(awesome_rx, '\1\2:')
  puts "#{count} replacements @ #{f}"
  open(f, 'w') { |b| b << s } }

The crazy negative lookbehinds ensures that nothing like

1
2
3
4
5
begin
   # ...
rescue Namespace::Exception => ex

end
1
2
3
def something
  return :x => 1, :y => 2
end

will get replaced. Turns out that after return you can only use the old syntax, or have curly brackets. Also, unfortunately, negative lookbehinds can’t contain Regexp inside them. So the multiple negative lookbehinds are like a big ‘or’.

Our really big project, with hundreds of .rb files, Gogobot, converted and is working great. Still afraid to do the final git push though ;)

Enjoy!

Isotope on Github ]

Update: Jul 23th, 2011

Updated to Ruby 1.9.2 with ArthurN’s amazing fork.

Update: Apr 13th, 2011

Updated API, external script support and fixes.

The problem:

In Ajax-based sites, there’s a constant dilemma: How to get objects rendered in templates? In server side (and output full HTML)? Client side (and mess with JSON objects and HTML strings/DOM generation)? What should be the role division between server and client?

Common Approaches, Pros & Cons:

A few approaches to output a rendered template evaluated with an object are:

Approach #1: Regular ERB Partial

Evaluate a simple ERB partial with a local object, and server it as a string to the client, simply by

1
<%= render :partial => "article", :object => @article %>

in a view, or from a controller and request it by Ajax.

This partial can look like:

1
2
3
4
5
6
7
8
9
<h2><%= article.title %></h2>
<div class="content">
<%= article.content %>
</div>
<ul class="tags">
    <% article.tags.each { |tag| %>
    <li><%= tag.name %></li>
    <% } %>
</ul>
Pros
  • Simple, readable and well known ERB for Rails/Sinatra
  • SEO and accessibility - HTML code is downloaded into the source
Cons
  • Server side only
  • Requires download of the whole HTML code, can cause performance issues
  • Cannot bind easily to a different object on client side. Must re-rendered in the server-side and be downloaded

Approach #2: Client Side EJS Template with JSON Objects

Having an EJS template in the HTML code, with techniques such as John Resig’s JavaScript Micro-Templating

1
2
3
4
5
6
7
8
9
10
11
12
13
<script type="text/html" id="article-template">
<h2><%= item.title %></h2>

<div class="content">
<%= item.content %>
</div>

<ul class="tags">
    <% item.tags.forEach(function (tag) { %>
    <li><%= tag.name %></li>
    <% }); %>
</ul>
</script>

Query the server for a JSON article and evaluate the template with this object into a string, and place it inside a container, using a technique as mentioned:

1
2
var results = document.getElementById("results"); // some container on the page
results.innerHTML = tmpl("article-template", article); // article is an object, probably a result of an AJAX JSON request
Pros
  • Fast - requires the server to send only the JSON object and the HTML is downloaded only once as a template
Cons
  • SEO and accessibility - HTML code isn’t in the source of the page but being rendered after load

Approach #3: Regular ERB Partial With Marked Spots for Data Place Holders

This approach tries to combine server side and client side but requires a lot of work. It contains a regular ERB template and place holder markers like class names on elements. The template can be first evaluated on the server with a Ruby object and on the client side it can be evaluated with a different JS object (probably from a JSON request).

Template file should look like:

1
2
3
4
5
6
7
8
9
<h2 class="data-title"><%= article.title %></h2>
<div class="content data-content">
<%= article.content %>
</div>
<ul class="tags data-tags">
    <% article.tags.each { |tag| %>
    <li><%= tag.name %></li>
    <% } %>
</ul>

And then, from a JS function, doing something like:

1
2
3
4
5
6
7
8
// article is an object probably from a JSON request
container.querySelector('.data-title').textContent=article.title;
container.querySelector('.data-content').textContent=article.content;
var tags=container.querySelector('.data-tags');
tags.innerHTML="";
article.tags.forEach(function (tag) {
    tags.appendChild(document.createElement("li")).textContent=tag.name;
});
Pros
  • One template for both client and server (not really, see Cons)
  • SEO and accessibility - HTML code is downloaded into the source
Cons
  • On the client side - Must mimic the Ruby functionality with JS when it comes to loops, conditions etc. However, text values are pretty easy to embed. This code should probably written manually for everything that is not a simple textual content.
  • Must maintain data place holder markers

So…

In these three approaches, the developer needs to choose according to the task and the project requirements, or worse, maintain two templates, ERB and EJS.

Each approach is written in a totally different way, and switching between the approaches means a lot of work.

Introducing: Isotope - Ruby Hybrid Template Engine for Client Side and Server Side

So why not combining all the pros of the approaches together?

The biggest constraints to be considered are:

  • Client side doesn’t understand Ruby
  • Ruby can’t be translated fully into JavaScript
  • And the most important one: Template should be maintained in one single file for both client and server uses

Isotope is from greek - “Equal Place”. An equal place of editing a template for both client and server (Thanks @yuvalraz for the name!).

Using jbarnette’s AWESOME Johnson gem, Ruby and JavaScript can interact together!

That means, that ruby code can handle EJS templates and JSON objects. A great and very inspiring article is Write your Rails view in? JavaScript? by Aaron Patterson.

In this approach, only one template is written and maintained in an EJS format, for both client side and server side.

Usage

Isotope gives the ability to have a single template file, and easily switch between the approaches:

1
2
3
4
5
6
7
8
9
10
11
12
13
# article.html.ejs

<h2><%= item.title %></h2>

<div class="content">
<%= item.content %>
</div>

<ul class="tags">
    <% item.tags.forEach(function (tag) { %>
    <li><%= tag.name %></li>
    <% }); %>
</ul>

On the Client Side

Outputting from the server side (controller or view)

1
<%= isotope_render_template("articles/article", :id => "article-template") %>

The above code will output:

1
2
3
4
5
6
7
8
9
10
11
12
13
<script type="text/x-isotope" id="article-template">
<h2><%= item.title %></h2>

<div class="content">
<%= item.content %>
</div>

<ul class="tags">
    <% item.tags.forEach(function (tag) { %>
    <li><%= tag.name %></li>
    <% }); %>
</ul>
</script>

which is easy to evaluate with any JS object using the mentioned technique.

On the Server Side (The Holy Grail)

Using Johnson, the famous micro-templating technique and JSONed Ruby objects, this library provides the following functionality:

1
<%= isotope_render_partial("articles/article", :locals => { :item => @article }) %>

This code reads the source of the EJS file, uses Johnson and John Resig’s technique and serves a string as an output.

Configuration

External JS files can be included in order to have special functionality in the EJS templates, on both client and server. To include files, create a config/isotope.yml file and fill this array, relatively to the app root:

1
2
include_scripts:
    - /public/javascripts/isotope_functions.js

And in order to have it available on client side, put this line before the close:

1
<%= isotope_included_scripts.html_safe %>

Scripts will be automatically included in server side.

Scripts and templates are never cached on development environment.

Installation:

1
2
# Rails 3.x
ruby script/rails plugin install git@github.com:elado/isotope.git
1
2
# Rails 2.3.x
ruby script/plugin install git@github.com:elado/isotope.git
Rails
Rails 3.x

Add to your Gemfile

1
2
3
gem 'json'
gem 'johnson'
gem 'isotope'

and run bundle install

Rails 2.3.x

Add to config/environment.rb

1
2
3
config.gem 'json'
config.gem 'johnson'
config.gem 'isotope'

and run rake gems:install

Add to config/environment.rb

require ‘isotope’

Server Side Example:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# ArticlesController

def show
    @article = {
        :title => "Hello!",
        :content => "World!",
        :tags => [
            {:name => "tag 1"},
            {:name => "tag 2"},
            {:name => "tag 3"},
            {:name => "tag 4"}
        ]
    } # Or an ActiveRecord fetch

    render :text => isotope_render_partial('articles/article', :locals => { :item => @article })
end

Or, with a view:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# ArticlesController

def show
    @article = {
        :title => "Hello!",
        :content => "World!",
        :tags => [
            {:name => "tag 1"},
            {:name => "tag 2"},
            {:name => "tag 3"},
            {:name => "tag 4"}
        ]
    } # Or an ActiveRecord fetch
end

# views/articles/show.html.erb

<%= isotope_render_partial('articles/article', :locals => { :item => @article }) %>
Client Side Example:
1
2
3
# views/articles/show.html.erb

<%= isotope_render_template('articles/article', :id => "article") %>
Sinatra

Actually the same usage, more or less.

Run Tests

Install rspec (gem install rspec)

1
rspec test/isotope_spec.rb

Launch sample Rails app

1
cd examples/rails3-example &amp;&amp; rails s

and go to http://localhost:3000

Backups are important. But usually they are made daily or even less often than this.

Quick tip I wish I had known a month ago when my MacBook froze and didn’t boot after a fruitful, productive day: backup all the code in realtime, all the time, with Dropbox.

Every CMD+S sends the file to Dropbox, and that means, that if something terrible happens to my computer (can’t boot, coffee accident, or it gets stolen), I know that all my code is backed up to the latest save.

That doesn’t even mean you should put your code directory inside the Dropbox’s one, you can Symlink it, excluding big files that don’t need to be backed up, or if you’re short on space.

A template I use for Rails projects w/ Git, excluding the tmp, log and other irrelevant folders:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
mkdir -p ~/Dropbox/Sites/PROJECT_NAME/
ln -s ~/Sites/PROJECT_NAME/.git ~/Dropbox/Sites/PROJECT_NAME/
ln -s ~/Sites/PROJECT_NAME/.gitignore ~/Dropbox/Sites/PROJECT_NAME/
ln -s ~/Sites/PROJECT_NAME/.rvmrc ~/Dropbox/Sites/PROJECT_NAME/
ln -s ~/Sites/PROJECT_NAME/app ~/Dropbox/Sites/PROJECT_NAME/
ln -s ~/Sites/PROJECT_NAME/Capfile ~/Dropbox/Sites/PROJECT_NAME/
ln -s ~/Sites/PROJECT_NAME/config ~/Dropbox/Sites/PROJECT_NAME/
ln -s ~/Sites/PROJECT_NAME/config.ru ~/Dropbox/Sites/PROJECT_NAME/
ln -s ~/Sites/PROJECT_NAME/db ~/Dropbox/Sites/PROJECT_NAME/
ln -s ~/Sites/PROJECT_NAME/doc ~/Dropbox/Sites/PROJECT_NAME/
ln -s ~/Sites/PROJECT_NAME/features ~/Dropbox/Sites/PROJECT_NAME/
ln -s ~/Sites/PROJECT_NAME/Gemfile ~/Dropbox/Sites/PROJECT_NAME/
ln -s ~/Sites/PROJECT_NAME/Gemfile.lock ~/Dropbox/Sites/PROJECT_NAME/
ln -s ~/Sites/PROJECT_NAME/lib ~/Dropbox/Sites/PROJECT_NAME/
ln -s ~/Sites/PROJECT_NAME/public ~/Dropbox/Sites/PROJECT_NAME/
ln -s ~/Sites/PROJECT_NAME/Rakefile ~/Dropbox/Sites/PROJECT_NAME/
ln -s ~/Sites/PROJECT_NAME/README ~/Dropbox/Sites/PROJECT_NAME/
ln -s ~/Sites/PROJECT_NAME/script ~/Dropbox/Sites/PROJECT_NAME/
ln -s ~/Sites/PROJECT_NAME/spec ~/Dropbox/Sites/PROJECT_NAME/
ln -s ~/Sites/PROJECT_NAME/test ~/Dropbox/Sites/PROJECT_NAME/
ln -s ~/Sites/PROJECT_NAME/vendor ~/Dropbox/Sites/PROJECT_NAME/

If you still don’t have a Dropbox account, you can use my referral link: Create Dropbox account or create a new account without my referral here.

I once built a nested message board (using ASP & VBScript, bah). In order to print all messages, nested, I created a recursive function that queries the DB for all messages of a certain parent, prints the messages and calls the same function itself with parent ID of the current message. That was a disaster to the server, as a single page could execute about 100 queries.

I decided to move the rendering logic to the client side, since SEO wasn’t such a big of a deal for this, and the load time was critical. So at first I queried the messages I wanted (I could do this in one query thanks to the DB structure), I pushed the data to JavaScript, as a flat, unordered array of objects, using JSON:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var treeData=[
  { "id":1,    "parentId":null,  "title":"1"            },
  { "id":2,    "parentId":1,     "title":"1.1"          },
  { "id":3,    "parentId":null,  "title":"2"            },
  { "id":4,    "parentId":1,     "title":"1.2"          },
  { "id":5,    "parentId":1,     "title":"1.3"          },
  { "id":6,    "parentId":4,     "title":"1.2.1"        },
  { "id":7,    "parentId":4,     "title":"1.2.2"        },
  { "id":8,    "parentId":4,     "title":"1.2.3"        },
  { "id":9,    "parentId":null,  "title":"3"            },
  { "id":10,   "parentId":9,     "title":"3.1"          },
  { "id":11,   "parentId":10,    "title":"3.1.1"        },
  { "id":12,   "parentId":11,    "title":"3.1.1.1"      },
  { "id":13,   "parentId":11,    "title":"3.1.1.2"      },
  { "id":14,   "parentId":11,    "title":"3.1.1.3"      },
  { "id":15,   "parentId":13,    "title":"3.1.1.2.1"    }
];

The first approach to print this, nested, is using a recursive function in JavaScript, that, on every call needs to find the child messages based on their parentId, and actually mimic the server behavior (loop on root messages, query child messages, print, recursively).

But a way cooler approach, is to utilize the DOM itself for nesting, and to utilize a hash table indexer to store and find messages based on their id.

After creating all elements for all messages, a hash table (associative array, or just a JavaScript “object”) can be used to store a node based on its id, so when we want to find it, we can just use nodesById[someNodeId]:

1
2
3
4
var nodesById={};
for (var i=0;i<nodeCollection.length;i++) {
    nodesById[nodeCollection[i].data.id]=nodeCollection[i];
}

Then, the magic of having all elements nested happens when looping on all nodes. Each node has a parent_id except root nodes. We need to find the parent of current node in the nodesById object, by using nodesById[nodeParentId], and append the current node to its parent we found. Root nodes appended to a root container.

1
2
3
4
5
for (var i=0;i<nodeCollection.length;i++) {
    var node=nodeCollection[i];
    var parentElement=node.data.parentId ? nodesById[node.data.parentId].getChildrenElement() : rootNodeItemsContainer;
    parentElement.appendChild(node.element);
}

That way, we utilize the DOM for native nesting, without a recursion, and a simple single loop. The array doesn’t even have to be ordered, and no worries about requesting a node when its parent isn’t exist, as all of the elements are already created before.

The Entire Code

[iframe: style=“width: 100%; height: 860px” src=“http://jsfiddle.net/elado/yxmKZ/embedded/js,css,result”]

“`js var treeData=[ {“id”:1,”parentId”:null,”title”:”1”}, {“id”:2,”parentId”:1,”title”:”1.1”}, {“id”:3,”parentId”:null,”title”:”2”}, {“id”:4,”parentId”:1,”title”:”1.2”}, {“id”:5,”parentId”:1,”title”:”1.3”}, {“id”:6,”parentId”:4,”title”:”1.2.1”}, {“id”:7,”parentId”:4,”title”:”1.2.2”}, {“id”:8,”parentId”:4,”title”:”1.2.3”}, {“id”:9,”parentId”:null,”title”:”3”}, {“id”:10,”parentId”:9,”title”:”3.1”}, {“id”:11,”parentId”:10,”title”:”3.1.1”}, {“id”:12,”parentId”:11,”title”:”3.1.1.1”}, {“id”:13,”parentId”:11,”title”:”3.1.1.2”}, {“id”:14,”parentId”:11,”title”:”3.1.1.3”}, {“id”:15,”parentId”:13,”title”:”3.1.1.2.1”} ]; function NodeItem(data) { this.data=data; var container=document.createElement(“li”), title=container.appendChild(document.createElement(“div”)); title.innerHTML=this.data.title; this.element=container; } NodeItem.prototype={ // lazy children element creation - not all nodes have children getChildrenElement:function () { return this._childElement = this._childElement || this.element.appendChild(document.createElement(“ul”)); } }; // convert all nodes to NodeItem instance var nodeCollection=treeData.map(function (node) { return new NodeItem(node); }); // for faster lookup, store all nodes by their id var nodesById={}; for (var i=0;i

I’ve been using Mac OS X for a almost two years. I like it, I really do. But there are a lot of things that drive me crazy. At least in the native/default configuration:

  1. You cannot rename/move/copy files in a save dialog. And you cannot open the enclosing folder to do so. You must open Finder yourself and look for that folder. This should be useful if you just want to replace a file but maintain the original in a different name.
  2. On that same file dialog, you can’t paste a web URL (http), which means, that if you want to open a file from web you must first download the it and then open it manually.
  3. You can’t delete a single file from trash. What happens if you just want to destroy evidence of something?
  4. Sometimes (e.g. in Chrome), when I mark text, it forgets where I started to mark from and where I ended. If I change the mark using Shift+Arrow/Shift+Click elsewhere, it either enlarges the selection when I wanted to subtract, or vice-versa. It should always proceed from the place the last mark was stopped at.
  5. When multiple windows of the same application are opened, a click on the dock icon brings them all to front. Same for cmd+tab menu. To me, it seems it happens because of poor window management. When I have a lot of Finder windows it’s very annoying. Partial solutions: HyperDock (for dock) and Witch (for alt+tab between all windows, not apps)
  6. You can’t cut & paste files. As time goes by I see how I really need it. Imagine you wouldn’t be able to cut & paste text, but only copy-paste-delete. Solution: TotalFinder
  7. You can’t merge folders. Drag / copy&paste of a folder named A, onto a folder which contains another folder named A, will totally remove the second A and replace it by the first one. The only way to merge is to use Terminal or an external tool.
  8. If your Finder window with Details view is packed with files, you can’t create a new folder with the right click menu unless you either enlarge the window, to get space below the files where a right click have New Folder command or use shortcut/main menu. On Windows - right click would work after the last column because a files don’t spread over an entire line.
  9. In details view, with a tree of files opened (great feature!), when pasting a file it’ll paste it to the top most directory you’re in, and not the one you marked.
  10. In native apps, if a text field is disabled, you can’t select the text in it at all.
  11. Several applications require you to right click on their dock icon in order to open them. For example, Adium: when the contact list is closed and there’s a conversation opened. True, it’s also Adium’s fault, but it’s more a window management UI issue.
  12. Deleting a file on the Finder (cmd+Backspace) clears the selected file. If you want to go to the next file with the down arrow - it’ll start from the first file on the top of the list. It should remember the location of the last deleted file and focus on the one that was next to it (or previous if it’s the last file).
  13. You must use Terminal for lots of advanced configurations. They don’t appear on System Preferences. Things like “Show hidden files” and more.
  14. No editable address bar in finder. ‘Go to Folder’ doesn’t count. It would, if it was showing the full current address of a window, but it shows only the last accessed path. Again, only terminal can make things easier.
  15. The Preview application won’t let you navigate through files in the same directory, unless they were all opened together initially.
  16. Weird and inconsistent Home & End buttons. I want it to go to the beginning/end of a line and not the top of the document. Several applications use the first approach and others use the second one. Solution: KeyFixer
  17. No Right-Click+Dragging (used for copy/move/extract etc.)
  18. Cmd+N in a Finder window opens the home directory. But most of the times I used it, I meant to duplicate the same window. Solution: TotalFinder
  19. Windows are resizable only from one corner. That means, that if a window is “stuck” on a size that is bigger than the screen, it cannot be resized, and you’re probably doomed, because most apps remember their size/location. It happend to me more than once after plugging off an external screen. Solution: Divvy

I guess that most of the users don’t need all of these, but I’m sure I’m not the only one complaining about them. Apple might want to protect the general users, and their approach seems like “We are way smarter than you”. But why don’t they create “Advanced Mode” for developers and advanced users?

I still use it because of the full native support for Ruby on Rails, Apache, iPhone development and such, but sometimes, I miss Windows 7.

(Title based on)