Trabe ya no escribe aquí. Puedes encontrarnos en nuestra publicación en Medium: medium.com/trabe.

4Trabes Historias de una empresa en 100 metros cuadrados

El blog de Trabe Soluciones

How to: automatically config a cloned repo

| | Comentarios

Important: If the version of Git you are running is under 1.7.7 this tip won’t run for you.

The problem

The other day I ran into a problem because of using the same computer for work and personal projects: I was commiting with the same user for both kind of projects, which I don’t want.

I want different user.email config setting for each type of project but I didn’t want to do it manually.

The solution

So I came up with a simple solution. It’s composed of four parts:

  • A particular, but not fancy, dir layout.
  • A config file per each type of repo (personal or work).
  • A bash function.
  • A git alias.

Using all this, as you’ll see, each time I clone a work or personal repo I end up with a different value of user.email depending on the type of project.

Dirs layout

Repos for personal and work projects must be contained into separated dirs so they have different config files. This is my layout:

1
2
3
4
5
6
7
8
[madtrick@madbook { repos } ruby-1.9.2-p180 ]
>>tree -L 1 -a personal/
personal/
├── .gitconfig.clone
├── cartos
├── coello
├── dotfiles
...
1
2
3
4
5
6
7
[madtrick@madbook { repos } ruby-1.9.2-p180 ]
>>tree -L 1 -a trabe/
trabe/
├── .gitconfig.clone
├── 4trabes
└── trabenet
...

Config file

The file .gitconfig.clone is where you place your specific bits of configuration. The syntax used is the same that you’ll use with git config

For example, the .gitconfig.clone for my work projects is this:

1
user.email=farruco.sanjurjo@trabesoluciones.com

Bash function

1
2
3
4
5
6
7
8
9
  function git_clone_config(){
    local options=""
    if [[ -f $PWD/.gitconfig.clone ]]; then
      while read line ; do
        options=$options" "$line
      done < $PWD/.gitconfig.clone
      echo "$options"
    fi
  }

When called, this function will look for a file called .gitconfig.clone in the current directory. If it exists, its lines will be returned (echoed).

Git alias

And to finish the git alias:

1
2
3
[alias]
  ...
  cl = !bash -ic 'git_clone_config' | xargs -I configvalues git clone --config configvalues --

Summary

When this alias is used, git cl REPO_URL, the bash function will be run to look for the .gitconfig.clone file. If that file exists its lines will be read and used in git clone --config CONFIG_LINES REPO_URL. This way, when git initializes the cloned repo it’ll use the config options given with --config flag.

Currently I’m using this just for the user.email config setting but it could be used to apply any of the supported config settings.

You can find my gitconfig file and other dot-stuff on my dotfiles repo on Github

Cerrando modales: ¿Quién cierra a quién?

| | Comentarios

Nota introductoria

Los conceptos que vamos a tratar en este post los ejemplificamos con Backbone. Por si no lo conoces o no tienes muy claro que es, aquí te dejamos una brevisima introducción:

Backbone es uno de los múltiples frameworks Javascript (1 y 2) que implementan el paradigma MVC en el navegador. En Backbone el rol de controlador lo juegan los componentes que sus desarrolladores denominan Views (Backbone.View) y el papel de vistas se implementa con cualquiera de las librerías de templating existentes (Eco, Moustache, etc.). Por lo tanto, una vez dicho esto, ten en cuenta que cuando hablemos de vista probablemente nos refiramos a controladores. Sea como sea, intentaremos ser lo más claros posible :___ )

Actualización: Realmente no está tan claro que Backbone siga el paradigma MVC (1, 2 y 3) pero durante el post seguiremos la convención de Vista =~ Plantilla HTML y Controlador =~ Backbone.View.

Al tomate

En Trabe estamos utilizando/probando Backbone en una aplicación en la que hay vistas que se van a mostrar tanto de manera modal como no modal. Como la lógica de estas vistas es independiente de si se están mostrando de manera modal o no, queremos separar la gestión de la ventana modal de su propio contenido y así facilitar la reutilización/refactorización/mantenimiento del código. Para explicarnos mejor vamos a utilizar el siguiente gráfico:

"Vista modal y vista modalizada"

Habrá una vista de Backbone (ModalView en el gráfico) encargada de gestionar la ventana modal (abrir, cerrar, pelearse con el plugin que “pinta” el modal) y una vista modalizada (ModalizedView) que en el caso del gráfico gestiona un formulario.

Hasta aquí todo va muy bien, pero existe un punto en el que, digamos, chocan las responsibilidades de la ModalView y de la ModalizedView. ¿Quién cierra la vista modal? Si es ModalizedView la que cierra el modal, estamos asignándole lógica que no le corresponde con lo que luego será más difícil de mantener o reutilizar. Así que será ModalView la que se cierre a sí misma; pero ¿cómo le indicamos a la ventana modal que puede cerrarse? Podemos hacerlo utilizando:

  • Una referencia a la vista modal
  • Eventos o promesas

El código que utilizaríamos para mostrar la ventana modal sería algo así como:

1
2
3
4
modal = new ModalView(...)
modalized = new ModalizedView(...)

modal.modalize(modalized)

Ahora veremos cómo implementar ModalizedView y ModalView utilizando cada opción.

Referencia a la vista modal

La vista a modalizar tiene una referencia a la vista modal. Cuando quiere cerrarla simplemente invoca un método en dicha vista.

Usando una referencia a la vista modal
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class ModalizedView extends Backbone.View
  handleDone : ->
    # The user is done, close the modal view!
    @get('modal_view').close()

class ModalView extends Backbone.View
  modalize : (view) ->
    # Show the view inside the modal
    # ...
    # Set a reference to the modal view
    view.set('modal_view') = modal_view

  close : ->
    # Close modal window

modal = new ModalView(...)
modalized = new ModalizedView(...)

modal.modalize(modalized)

En este caso los problemos que nos encontramos son los siguientes:

  • Si cambiamos el API de la vista modal podemos afectar a las vistas que la utilicen.
  • Estamos añadiendo lógica que no le corresponde a la vista modalizada.
  • En el caso del ejemplo, el método handleDone no podría ser reutilizado, directamente, si la vista no es modal (no tendríamos una referencia al modal_view correspondiente).

Eventos o promesas

La utilización de eventos y promesas comparte ventajas e inconvenientes. Entre las ventajas están:

  • Desacoplan las dos vistas manteniéndolas independientes. O casi ;)
  • Tanto las promesas como los eventos pueden ser utilizadas no solo por la vista modal sino por otros componentes para tener constancia del estado de la vista modalizada.

Y entre las desventajas:

  • Ambas vistas tienen que adaptar un “protocolo” común (ya sea a través de los eventos o la promesa).
  • En ambos casos dependeremos de una librería que facilite la utilización de promesas o eventos (por ejemplo, jQuery).
  • La lógica correspondiente a lanzar un evento o resolver una promesa no está directamente relacionada con el contexto en el que se encuentra. Claro que este es el precio a pagar por las ventajas que ofrecen.

Eventos

La vista a “modalizar” lanza un evento que la vista modal captura y como consecuencia se cierra.

Usando eventos
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class ModalizedView extends Backbone.View
  handleDone : ->
    # The user is done, signal it using an event
    @trigger "modal:close"

class ModalView extends Backbone.View
  modalize : (view) ->
    # Show the view inside the modal
    view.on "modal:close", ->
      # Close modal window

modal = new ModalView(...)
modalized = new ModalizedView(...)

modal.modalize(modalized)

Promesas

Por promesas nos referimos a los Deferred/Promise de jQuery. Una promesa es un objeto que “represents the eventual value returned from the single completion of an operation” (CommonJS/Promises).

Las vistas a modalizar tienen disponible una promesa que utilizan para indicar que ya han cumplido con su cometido. Esta promesa será utilizada por la vista modal para determinar cuándo tiene que cerrarse.

Usando promesas
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class ModalizedView extends Backbone.View
  initialize : ->
    @_deferred  = $.Deferred()
    @promise    = @_deferred().promise()

  handleDone : ->
    @_deferred.resolve()

class ModalView extends Backbone.View
  modalize : (view) ->
    # Show the view inside the modal
    # Attach a done callback which will close the modal window
    view.promise.done ->
      # close modal window

modal = new ModalView(...)
modalized = new ModalizedView(...)

modal.modalize(modalized)

¿Conclusiones?

Las mejores soluciones son la del evento y la de la promesa. ¿Y entre estas dos? Nos gusta más la promesa porque lleva “de serie” la distinción entre una finalización “exitosa” (resolve/done) y una “fallida” (reject/fail), que en el caso de los modales es bastante común. Además, es un estándar de facto – al menos en jQuery – lo que nos permite aprovechar todas las herramientas asociadas.

PrettyKit, make your iOS app look pretty

| | Comentarios

Since I started to work on my Computer Science Thesis here at Trabe Soluciones, I’ve written some iOS open source libraries. Probably the biggest one is PrettyKit. You can find it at Github.

What is PrettyKit?

We’ve lately been seeing an interesting change on the interfaces of many iOS apps. The glossy effects and gray striped backgrounds nowadays look boring and démodé, and the tendency points to the use of gradients and patterns.

"Tweetie vs Twitter"

The latest apps introduced by Apple, such as Reminders, Game Center or Find My Friends use patterned backgrounds or leather-like navigation bars, for example. What’s more, a new API to allow more appearance customization has been introduced in the iOS SDK. Although it is an interesting step, it is not big enough, as this API is only compatible with iOS 5 or higher and, in some cases, the new appearance’s properties might be not enough.

And here’s where PrettyKit comes.

PrettyKit is a library composed by a set of new widgets and UIKit subclasses that gives you more control to customize your interfaces. You will be able to easily change backgrounds, draw gradients, drop shadows and more. This library will help you to beautify your iOS apps and give them a modern look. Besides, it is fully compatible with iOS 4.0.

Besides, if you need even more control, you can subclass any Pretty class, which will give you even more possibilities. Or, if you’re feeling brave, fork the code, it’s open source ;)

Check this video to see what you can do with PrettyKit:

PrettyKit possibilities

You might say:

Until now you’ve only said that PrettyKit is cool and blah blah, but I want to see if it’s actually that cool.

Challenge accepted!

Let’s say the interface of your application has been built with Interface Builder and it looks like this:

"Your application before PrettyKit"

We’ll now apply some PrettyKit customization, take a look:

  1. Go to the Interface Builder file, and change the classes of the navigation bar and tab bar to PrettyNavigationBar and PrettyTabBar.

  2. Let’s change now the cells’ appearance. First, #import "PrettyKit.h". In your tableView:cellForRowAtIndexPath:, change all references to UITableViewCell to PrettyTableViewCell. And for each cell you work with, add this line [cell prepareForTableView:tableView indexPath:indexPath];. And in your tableView:heightForRowAtIndexPath: add [PrettyTableViewCell tableView:tableView neededHeightForIndexPath:indexPath] to your desired height. Nice, huh?

  3. The final touches. First of all, the background is still stripped, so we’ll create a new one and we’ll set it. Then, let’s make the cells even nicer, less rounded. To change the cell’s corner radius, just do this when initializing them: cell.cornerRadius = 5;.

"Your app being beautified"

This is the final code to generate the cells. Lines 5 and 7 have changed the UITableViewCell reference to PrettyTableViewCell. Lines 8 and 11 are new. And heightForRow now has a sum. That’s all. That simple.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"Cell";

    PrettyTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
        cell = [[[PrettyTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
        cell.cornerRadius = 5;
    }

    [cell prepareForTableView:tableView indexPath:indexPath];
    cell.textLabel.text = [NSString stringWithFormat:@"Text %d",indexPath.row];

    return cell;
}
1
2
3
-(CGFloat) tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    return tableView.rowHeight + [PrettyTableViewCell tableView:tableView neededHeightForIndexPath:indexPath];
}

Not convinced yet?

OK. Have you seen those several-button cells in the video?

"Grid cell" "Grid cell"

They are part of PrettyKit. And using them is really easy, look at this code:

1
2
3
4
5
6
7
gridCell.numberOfElements = 3;
[gridCell setText:@"One" atIndex:0];
[gridCell setDetailText:@"Detail Text" atIndex:0];
[gridCell setText:@"Two" atIndex:1];
[gridCell setDetailText:@"Detail Text" atIndex:1];
[gridCell setText:@"Three" atIndex:2];
[gridCell setDetailText:@"Detail Text" atIndex:2];

Or this line, if you’re using the segmented control row:

1
segmentedCell.titles = [NSArray arrayWithObjects:@"1", @"2", @"3", @"4", nil];

And they use blocks, so it’s easy to add a callback when any button is pressed:

1
2
3
4

gridCell.actionBlock = ^(NSIndexPath *indexPath, int selectedIndex) {
  // whatever you want to do
};

Performance

Take a look at this Twitter article about smooth animation. As they state, jerky scrolling ruins the user experience. PrettyKit is entirely drawn with CoreGraphics. That means it’s really fast, and the scrolling, which usually causes headaches when customizing cells, is very smooth.

Documentation

PrettyKit has a very nice documentation, that might help you more than once. It is written with appledoc syntax, so it will integrate very well with the rest of your project when generating the docs.

That’s all folks. If you’ve got any doubt or opinion to share, comment here, tweet me at @vicpenap or visit the project’s page at github.