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:
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
123456789
function git_clone_config(){local options=""if[[ -f $PWD/.gitconfig.clone ]]; then while read line ; dooptions=$options" "$linedone < $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).
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.
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 frameworksJavascript (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:
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:
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
12345678910111213141516171819
classModalizedViewextendsBackbone.ViewhandleDone : -># The user is done, close the modal view!@get('modal_view').close()classModalViewextendsBackbone.Viewmodalize : (view) -># Show the view inside the modal# ...# Set a reference to the modal viewview.set('modal_view')=modal_viewclose : -># Close modal windowmodal = newModalView(...)modalized = newModalizedView(...)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
123456789101112131415
classModalizedViewextendsBackbone.ViewhandleDone : -># The user is done, signal it using an event@trigger"modal:close"classModalViewextendsBackbone.Viewmodalize : (view) -># Show the view inside the modalview.on"modal:close",-># Close modal windowmodal = newModalView(...)modalized = newModalizedView(...)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
12345678910111213141516171819
classModalizedViewextendsBackbone.Viewinitialize : ->@_deferred = $.Deferred()@promise = @_deferred().promise()handleDone : ->@_deferred.resolve()classModalViewextendsBackbone.Viewmodalize : (view) -># Show the view inside the modal# Attach a done callback which will close the modal windowview.promise.done-># close modal windowmodal = newModalView(...)modalized = newModalizedView(...)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.
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.
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:
We’ll now apply some PrettyKit customization, take a look:
Go to the Interface Builder file, and change the classes of the navigation bar and tab bar to PrettyNavigationBar and PrettyTabBar.
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?
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;.
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.
And they use blocks, so it’s easy to add a callback when any button is pressed:
1234
gridCell.actionBlock=^(NSIndexPath*indexPath,intselectedIndex){// 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.