All posts by Andrea Mostosi

Birth and death of an object in Ruby

Last week I played with a SOAP API with savon.rb to develop a newsletter system.

This API require authentication with a two-way handshake. At first you send a login, a password and a key and it gave you back a token. When you ended operation you should send a “close connection” command.

This is a popular way but when you use it in a model seems a bit tricky so I decided to hide this method inside a custom class.

First I create ApiWrapper class that wrap SOAP operation:

class ApiWrapper

  def initialize
    @client = Savon::Client.new APP_CONFIG[:wsdl]
  end

  def open_connection
    response = do_soap_request("openApiConnection", {
      :login => APP_CONFIG[:login],
      :pwd => APP_CONFIG[:pwd],
      :key => APP_CONFIG[:key]
    })
    @token = response[:token]
  end

  def close_connection
    response = do_soap_request("closeApiConnection", {
      :token => @token
    })
  end

  def do_soap_request(method, arguments)
    response = @client.request(:api, method) do
      soap.body = arguments
    end
    response.to_hash
  end

end

Then use the ApiWrapper object inside the model:

class Newsletter

  def initialize
    @api = ApiWrapper.new
  end

  def send
    # do something
  end

end

Now we can use the @api object for communicate with the API. I want to hide the authentication process, first attempt can be to incapsulate operation inside each method:

def send
  @api.open_connection
  @api.do_soap_request("send", arguments)
  @api.close_connection
end

It works but the webservice il very slow, opening and closing connection require about 20 seconds and for hundred operation is too much time.

Another way is to encapsulate authentication process inside object initialization and finalization. For this we need something similar to a C++ constructor and destructor method. Ruby has got the initialize method similar to constructor but it does not have a standard destructor. Luckily we can emulate it.

The ObjectSpace module enable you to define block that is executed when the object is destroyed using the define_finalizer method.

ObjectSpace.define_finalizer(self, Proc.new{@api.close_connection})

In the initialize method we can open the connection and define this finalizer. We can rewite the method as follow:

def initialize
  @api = ApiWrapper.new
  @api.open_connection
  ObjectSpace.define_finalizer(self, Proc.new{@api.close_connection})
end

Now we can use the object with easier and more efficient connection management.

> n = Newsletter.new # implicit connection open
> n.send # connection is still open
> n.send # connection is still open
> n.send # connection is still open
> quit # implicit connection close

These methods are very useful (also) to mask unnecessary complexity and make the data access more readable.

An MVC implementation for Appcelerator – Part 4: Model and DB

In part 3 we setup a simple app based on Fabio Barbieri‘s evolution of Appcelerator on Rails. Now is time to start playing with some models and data.

The application had two controllers: Products and Clients. We added to the Products controller a function that shows a static message when we click on the button. Now we want to fetch the data to display from the database.

First create the “Client” model:

ruby scripts/generate.rb model Client name:string
Resources/models/client.js
Resources/db/migrations/20110721190738.js

Resources/models/client.js

var Client = Model.extend({
    table_name: "clients",
    _fields: {id: Number, name : String},

    find: function(id) {
        var model = new Client(this.db, this._find(id));
        return model;
    },

    item_from: function(row) {
        var model = new Client(this.db, this._item_from(row));
        return model;
    }
});

Resources/db/migrations/20110721190738.js

migrate("20110721190738", "CREATE TABLE IF NOT EXISTS clients (id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, name STRING)");

Each time we start the application, the closure in db.js run the migrations not already executed. We can run the app to create the table then add some fake data with a SQLite manager. Alternatively we can create another migration to add sample data, it’s up to you.

Create Resources/db/migrations/20110721190739.js (one unit after previous migration) and write:

migrate("20110721190739", "INSERT INTO clients (name) VALUES ('John Doe')");
migrate("20110721190740", "INSERT INTO clients (name) VALUES ('Jane Doe')");

When you start the app this migration will insert into “clients” table two items.

Finally add a function to the Clients controller to load the data and display them on an alert box:

loadClients: function() {
	var c = new Client(db);
	var recs = c.find_all();
	var results = "Clients:n";
	if(recs.length > 0)
	{
		for(var i = 0; i < recs.length; i++)
		{
			results += recs[i].name + 'n';
		}
	}
	else
	{
		results += "none";
	}
	alert(results);
}

And the corresponding button into the Clients view:

var button = Titanium.UI.createButton({
	title:'Click me',
	font:{fontSize:12,fontWeight:'bold'},
	width:65,
	height:30,
	top:300
});
button.addEventListener('click', this.controller.loadClients);
this.win.add(button);

Launch the simulator and switch to the “Client” tab. When you click on the button the client list will be showed.

You can download the sample code and look use it for your projects.

With this fourth part we conclude this series of tutorials. It’s not too much, just a start but we are planning to create a new series of tutorials in september that will cover the coding of a complete application with Appcelerator on Rails.

Enjoy and have a good summer vacation!

Links:
Part 1: Introduction
Part 2: Improvements
Part 3: A simple demo

An MVC implementation for Appcelerator – Part 3: A simple demo

In part 2 we learned how to improve a standard distribution of Appcelerator on Rails. Now we will see it in action.

We are going to create a small application with 2 empty tab, with a very simple logic, that at the end will look like this.

First create the controllers and the views. We need the ruby interpreter (version 1.8.7) in ordert to run the generators. If you have no Ruby interpreter installed on your system, you can find one here.

First controller:

ruby scripts/generate.rb controller Products
Resources/controllers/products.js
Resources/views/products.js

Generated code:
Resources/controllers/products.js

Ti.include("/views/products.js");
var ProductController = Controller.extend({
    init: function(win) {
        this._super(win);

        this.view = new ProductView(win, this);
    }
});

Resources/views/products.js

var ProductView = View.extend({
    init: function(win, controller) {
        this._super(win, controller);

        this.layout();
    },
    layout: function() {

    }
});

Second controller:

ruby scripts/generate.rb controller Clients
Resources/controllers/clients.js
Resources/views/clients.js

Now add some (simple) logic to the first controller:

btnClicked: function(event) {
	alert("click");
}

and write code that builds the interface using th controller logic:

layout: function() {
	this.win.title = 'Products';
	this.win.backgroundColor = '#fff';

	var label = Titanium.UI.createLabel({
		color:'#999',
		text:'I am Products Window',
		font:{fontSize:20,fontFamily:'Helvetica Neue'},
		textAlign:'center',
		width:'auto',
	});
	this.win.add(label);

	var button = Titanium.UI.createButton({
		title:'Click me',
		font:{fontSize:12,fontWeight:'bold'},
		width:65,
		height:30,
		top:300
	});
	button.addEventListener('click', this.controller.btnClicked);
	this.win.add(button);
}

You can made the same operation on the other controller and view.

In the app.js file we only setup properties, create tabs and instantiate controllers. Nothing more.

Titanium.UI.setBackgroundColor('#000');
var tabGroup = Titanium.UI.createTabGroup();

// Product tab (root tab)
var productWin = Ti.UI.createWindow({exitOnClose:true});
Ti.include("/controllers/products.js");
var productController = new ProductController(productWin);
var productTab = Titanium.UI.createTab({
    icon:'KS_nav_ui.png',
    title:'Products',
    window:productWin
});

// Client tab
var clientWin = Ti.UI.createWindow({exitOnClose:true});
Ti.include("/controllers/clients.js");
var clientController = new ClientController(clientWin);
var clientTab = Titanium.UI.createTab({
    icon:'KS_nav_views.png',
    title:'Clients',
    window:clientWin
});

tabGroup.addTab(productTab);
tabGroup.addTab(clientTab);
tabGroup.open();

Now we can launch the emulator and enjoy our new MVC-based project.

You can download the sample code wrote and packed by Fabio Barbieri.

Links:
Part 1: Introduction
Part 2: Improvements
Part 4: Model and DB

An MVC implementation for Appcelerator – Part 2: Improvements

Hi again, in this four parts tutorial I will present some ideas and projects to implement a MVC framework for Appcelerator Titanium, a multiplatform (iOS and Android) Javascript framework to build native mobile apps.

In part 1 we discovered the structure of Appcelerator on Rails. It’s a quite well designed framework, the basic ideas are good but there are several limitations. The first problem comes from the implementation of the controller.

var MainController = Controller.extend({
    init: function(win) {
        this._super(win);
        this.view = new MainView(win, this);
    }
});

(function() {
    var win = Titanium.UI.currentWindow;
    new MainController(win);
})();

The closure at the end of this class instantiates the controller only when you include the file. If you want to instantiate one more, you must include the class file again and this isn’t good from a coding perspective. A better implementation would split definition and instantiation.

Controller file can be more compact:

var MainController = Controller.extend({
    init: function(win) {
        this._super(win);
        this.view = new MainView(win, this);
    }
});

In this way, when you use the class include file once and it will instantiate the controller every time you need it.

Ti.include("/controllers/main.js");
var mainController = new MainController(mainWin);

This, as well as having potential advantages in terms of memory usage, it’s more rational too.

Another advantage is the ability to access global variables inside the controllers and views without weird tricks, something not previously allowed.

These were functional improvements: another improvement is to clean the included code. The Appcelerator on Rails’ library files are full of code that is no longer used. As well as increasing the size and memory usage it also generates a long series of warnings that complicates debugging. Cleaning and tidying these files is a necessary work.

Fabio Barbieri, the developer behind these improvements, has made ​​a preliminary sample of the code, cleaned and fixed, that can be downloaded here.

That’s all for part 2. In the next part I will present how to build a simple app starting from these considerations.

Links:
Part 1: Introduction
Part 3: A simple demo
Part 4: Model and DB

An MVC implementation for Appcelerator – Part 1: Introduction

Hi all,
let me introduce this post by welcoming Andrea Mostosi as a new addition to our team here at PrimeGap. Andrea is one of the most brilliant coder and passionate geeks I’ve ever met.

Starting with this introduction, he will present several tools and frameworks to enhance your coding with Appcelerator Titanium.

Welcome Andrea and here’s your post.

LT

Since Titanium was introduced, in December 2008, no MVC implementation has been proposed from Appcelerator Inc.

People who work with common MVC frameworks (like Rails, Django, …) don’t like messy files. Many MVC implementations have been proposed, but no one has yet succeeded in becoming the standard.

On the official Wiki there is a “Javascript Frameworks” section with a link to Foundation, a MVC microframework with basic features. With a Google search you can find out a few other. I personally prefer Appcelerator on Rails.

Appcelerator on Rails tries to implement most of Rails features using similar filesystem design and limited-feature Ruby-based generator.

Model generator creates standard code for accessing data

var #{model} = Model.extend({
table_name: "#{table}",
_fields: {id: Number #{fields_sql}},

find: function(id) {
var model = new #{model}(this.db, this._find(id));
return model;
},

item_from: function(row) {
var model = new #{model}(this.db, this._item_from(row));
return model;
}
});

Controller generator writes both View and Controller code

var #{name}View = View.extend({
init: function(win, controller) {
this._super(win, controller);
this.layout();
},

layout: function() {
// do something
}
});
var #{name}Controller = Controller.extend({
init: function(win) {
this._super(win);
this.view = new #{name}View(win, this);
}
});

(function() {
var win = Titanium.UI.currentWindow;
new #{name}Controller(win);
})();

Controller gets its own View using a conventional (and static) name and View has a method layout() which draws the interface. Then there is a closure which instantiates the controller.

This is an efficient strategy, but with many big downside, we will see advantages and disadvantages in part 2.

There’s also a Migration generator who generate SQL code for table creation.

migrate("#{migration}", "CREATE TABLE IF NOT EXISTS #{model} (id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT #{fields_sql})");

The migrate method executes SQL code and add a new row to the migration table.

Stay tuned for Part 2, where we will see Appcelerator on Rails in action.

UPDATED on July 22nd: added the Part 2 link. Enjoy!