Installing Elixir on WebFaction
This is a short guide on installing Elixir on a WebFaction shared server. Overall it is fairly easy: first we will install Erlang, then Elixir proper.
Installing Erlang
We will first install erlang in our home directory. The installation itself will be in $HOME/lib/erlang
, and all binaries will be aliased in $HOME/bin
.
- Download the latest erlang release in a temporary folder
wget http://www.erlang.org/download/otp_src_17.3.tar.gz
- Extract the archive
tar xvzf otp_src_17.3.tar.gz
cd otp_src_17.3
- Compile and install erlang
./configure --prefix=$HOME
make
make install
Installing Elixir
We will now install elixir in a similar fashion by installing it inside $HOME/lib/elixir
, and then aliasing all binaries inside $HOME/bin
.
- Download the latest elixir release in a temporary folder
wget http://s3.hex.pm/builds/elixir/v1.0.2.zip
- Extract the archive directly in the destination folder
unzip -d $HOME/lib/elixir v1.0.2.zip
- Alias all binaries
ln -s $HOME/lib/elixir/bin/elixir $HOME/bin/elixir
ln -s $HOME/lib/elixir/bin/elixirc $HOME/bin/elixirc
ln -s $HOME/lib/elixir/bin/iex $HOME/bin/iex
ln -s $HOME/lib/elixir/bin/mix $HOME/bin/mix
Map to Keyword List
I like to write Elixir functions that take a Keyword List
as optional arguments. Much like for instance HTTPoison does:
def request(method, url, body \\ "", headers \\ [], options \\ []) do
timeout = Keyword.get options, :timeout, 5000
stream_to = Keyword.get options, :stream_to
...
end
But sometimes all I have at hand is a Map
, usually coming straight from a third party json API. Here is a very simple snippet of code to convert such a Map
into a Keyword List
:
def to_keyword_list(dict) do
Enum.map(dict, fn({key, value}) -> {String.to_atom(key), value} end)
end
Of course for this code to work, all keys must be strings!
A Haiku From Bashō
From time to time
The clouds give rest
To the moon-beholders.
MySQL table lock with Django
When operating with a relational database like MySQL or PostgreSQL it is sometimes required to use table locks, usually when performing a transaction susceptible to concurrency problems.
As a rule of thumb:
- a WRITE LOCK on a table is needed when writing to that table while performing a transaction susceptible to concurrency issues,
- a READ LOCK on a table is needed when reading from that table while performing a transaction susceptible to concurrency issues,
- when a lock is acquired, all the tables used in the transaction must be locked,
- all locks must be released when a database transaction is completed.
Django’s ORM doesn’t have support for table locks, which is quite understandable as table locking is database specific.
I wrote a small context manager that can be used to lock tables with MySQL:
import contextlib
from django.db import connection
@contextlib.contextmanager
def acquire_table_lock(read, write):
'''Acquire read & write locks on tables.
Usage example:
from polls.models import Poll, Choice
with acquire_table_lock(read=[Poll], write=[Choice]):
pass
'''
cursor = lock_table(read, write)
try:
yield cursor
finally:
unlock_table(cursor)
def lock_table(read, write):
'''Acquire read & write locks on tables.'''
# MySQL
if connection.settings_dict['ENGINE'] == 'django.db.backends.mysql':
# Get the actual table names
write_tables = [model._meta.db_table for model in write]
read_tables = [model._meta.db_table for model in read]
# Statements
write_statement = ', '.join(['%s WRITE' % table for table in write_tables])
read_statement = ', '.join(['%s READ' % table for table in read_tables])
statement = 'LOCK TABLES %s' % ', '.join([write_statement, read_statement])
# Acquire the lock
cursor = connection.cursor()
cursor.execute(statement)
return cursor
# Other databases: not supported
else:
raise Exception('This backend is not supported: %s' %
connection.settings_dict['ENGINE'])
def unlock_table(cursor):
'''Release all acquired locks.'''
# MySQL
if connection.settings_dict['ENGINE'] == 'django.db.backends.mysql':
cursor.execute("UNLOCK TABLES")
# Other databases: not supported
else:
raise Exception('This backend is not supported: %s' %
connection.settings_dict['ENGINE'])
It works with the models declared in your django application, by simply providing two lists:
- the list of models to lock for read purposes, and
- the list of models to lock for write purposes.
For instance, using django tutorial’s models, you would just call the context manager like this:
with acquire_table_lock(read=[models.Poll], write=[models.Choice]):
pass # Do something here
MVC with GWT: creating and firing custom events with GWT
GWT is obviously able to handle events, for instance ClickEvent
fired by Button
, or ResizeEvent
fired by Window
. Wouldn’t it be nice to be able to create custom events? What I have in mind is to create Models that can be binded to Views. I won’t go that far in this post, but instead will just try to figure out:
- how GWT2 is handling events,
- how we can create custom events and use them.
We will start with a very simple Model, and fire an event whenever its property, called field, is modified.
Here is our simple model:
public class SimpleModel
{
private String field;
public SimpleModel(String field)
{
this.field = field;
}
public String getField()
{
return field;
}
public void setField(String field)
{
this.field = field;
}
}
How is GWT handling events?
If we look all the way up to the Widget
class, we notice that GWT is able to handle two kinds of events.
- DOM events, that are native events fired by the underlying html elements:
/**
* Adds a native event handler to the widget and sinks the corresponding
* native event. If you do not want to sink the native event, use the
* generic addHandler method instead.
*
* @param <H> the type of handler to add
* @param type the event key
* @param handler the handler
* @return {@link HandlerRegistration} used to remove the handler
*/
protected final <H extends EventHandler> HandlerRegistration
addDomHandler(final H handler, DomEvent.Type<H> type) {
assert handler != null : "handler must not be null";
assert type != null : "type must not be null";
sinkEvents(Event.getTypeInt(type.getName()));
return ensureHandlers().addHandler(type, handler);
}
- “other” events:
/**
* Adds this handler to the widget.
*
* @param <H> the type of handler to add
* @param type the event type
* @param handler the handler
* @return {@link HandlerRegistration} used to remove the handler
*/
protected final <H extends EventHandler> HandlerRegistration addHandler(
final H handler, GwtEvent.Type<H> type) {
return ensureHandlers().addHandler(type, handler);
}
Custom events are what we are looking for! The problem is that, well, our simple model does not by any stretch of the imagination qualify as a Widget
. So we cannot have our model inherit from the Widget
class.
If we look a bit more at the two methods above, we notice they are both calling a method called ensureHandlers()
.
/**
* Ensures the existence of the handler manager.
*
* @return the handler manager
* */
HandlerManager ensureHandlers() {
return handlerManager == null ?
handlerManager = new HandlerManager(this) : handlerManager;
}
This method is returning a HandlerManager
. If you go look in the code or the documentation, a HandlerManager
is “responsible for adding handlers to event sources and firing those handlers on passed in events.”. That’s precisely what we were looking for. So all we have to do is to add a HandlerManager
to our SimpleModel
.
Creating a BaseModel
class that is able to fire events
In order to handle events in BaseModel
, we basically need two methods :
- a method to add handlers to the handler manager,
- a method to fire events.
public class BaseModel
{
private HandlerManager handlerManager = new HandlerManager(this);
public <H extends EventHandler> HandlerRegistration
addHandler(GwtEvent.Type<H> type, final H handler)
{
return handlerManager.addHandler(type, handler);
}
public void fireEvent(GwtEvent<?> event)
{
handlerManager.fireEvent(event);
}
}
Perfect. Now all we need to do is to extend the SimpleModel
so that it fires events.
Adding an event handler and firing events from SimpleModel
At first we need to define what the EventHandler
will be. We want to know when the value of field is changed, so it should be something like :
public interface FieldChangedHandler extends EventHandler
{
public void onFieldChanged(String newValue, String oldValue);
}
Here is the final SimpleModel
class, firing a GwtEvent
whenever any of its field is changed:
public class SimpleModel extends BaseModel
{
private String field;
public String getField()
{
return field;
}
public void setField(String field)
{
String oldValue = this.field;
String newValue = field;
this.field = field;
this.fireEvent(new FieldChangedEvent(oldValue, newValue));
}
public HandlerRegistration addFieldChangedHandler(FieldChangedHandler handler)
{
return addHandler(handler, FieldChangedEvent.getType());
}
public interface FieldChangedHandler extends EventHandler
{
public void onFieldChanged(String newValue, String oldValue);
}
public static class FieldChangedEvent extends GwtEvent<FieldChangedHandler>
{
private final String oldValue, newValue;
public FieldChangedEvent(String newValue, String oldValue)
{
this.newValue = newValue;
this.oldValue = oldValue;
}
/**
* The event type.
*/
private static Type<FieldChangedHandler> TYPE = new Type<FieldChangedHandler>();
/**
* Handler hook.
*
* @return the handler hook
*/
public static Type<FieldChangedHandler> getType()
{
if (TYPE == null)
TYPE = new Type<FieldChangedHandler>();
return TYPE;
}
@Override
protected void dispatch(FieldChangedHandler handler)
{
handler.onFieldChanged(newValue, oldValue);
}
@Override
public com.google.gwt.event.shared.GwtEvent.Type<FieldChangedHandler> getAssociatedType()
{
return TYPE;
}
}
}
In order to observe this simple model, just add something like this where needed in your code:
mySimpleModel.addFieldChangedHandler(new FieldChangedHandler()
{
@Override
public void onFieldChanged(String newValue, String oldValue)
{
// TODO Something
}
});
That’s great, now we have a SimpleModel firing events whenever its unique property is changed. But as you can imagine, defining an EventHandler
and a GwtEvent
for each and every field of a model can quickly become tedious work…