Sunday 20 October 2013

Improving Scala sorting DSL

Today I encountered an annoying lacking in Scala list sorting support. I just wanted to sort my list by using different fields, some causing an ascending order others causing a descending order.

Well, everything went happily (though with ugly syntax) with Scala´s List.sortBy and unary minus operators... until I needed to perform mixed ascending/descending sorts with strings. Not so easy to implement elegantly.

I tried to google answers but didn't find any useful results. That´s why I decided to make my own syntax by using generics, Ordered trait inheritance and Scala´s implicit Ordering support. I ended up making the following implementation:

Now I can sort my collections (at least in Scala 2.10) with neat syntax:
myList.sortBy(v => (asc(v.mem1), desc(v.mem2), ...))

Syntax should work with all classes having Scala Ordering trait implemented (at least all built-in basic types in Scala). Here is a working example how to use the DSL:

I hope this post helps. Happy sorting!

Wednesday 22 May 2013

Automatic Backbone model validation

Today I'm going to dig into Backbone.js validations and how to automate them. Backbone itself doesn't provide any proper validation. Fortunately, there is quite good plugin: Backbone.validation. It provides an easy way to define own constraints and error messages for models.

However, Backbone.validation plugin has one disadvantage. It doesn't provide any good way to transfer validation messages across multiple Backbone views nor provide events for single attribute validations. In simple applications this is not a problem, but huge user interface must be divided into multiple views and validation must work automatically for all of those, without generating too much processing overhead.

The solution?

First step was to implement per-attribute. Actually, Backbone.validation provides per-attribute validation callbacks but those are always bound to a view. In order to make our validations more modular, per-attribute validation events must be view-independent. We can create our own events "valid:<attr>" and "invalid:<attr>" by overriding the Backbone.Validation.mixin.validate function:


Ok. Now we have view independent validation events for attributes. Next step is to bind those events into views so that each input listens valid and invalid events from associated models. The problem is that there is no pre-defined information about available events because they are generated dynamically from model constraints. Thus, I've looped every input element from the view after render and used their name attribute for event binding:

In the above code, I've added also an automatic input-to-model binding so that every time when user changes the input, the changed value will be stored into associated model attribute. Validation binding and input-to-model bindings can be disabled from individual inputs by defining HTML5 data-attributes ignore-model="true" and ignore-validation="true".

Because these kind of validation and input-to-model bindings are kind of boilerplate code, I wanted to automate them by using CoffeeScript inheritance and Backbone.marionette plugin: all that developers must do is to inherit their new view classes from ItemView class and after that all validations and input-to-model synchronizations are working automagically! Cool, I think!

And usage...

Here is a little example code about the usage of our brand new "framework":

Of course our framework requires that our markup follows some specific conventions. I'm using Twitter Bootstrap so the framework expects that every validated input is inside control-group div. However, it shouldn't be non-trivial to tweak setValid and setInvalid methods form part 2 in order to make your own markup implementation. ;)

A working example can be found from jsFiddle: http://jsfiddle.net/RfcMK/4/

Friday 19 April 2013

Don't shit your Grails URL reloading with extreme paths!

Gosh! I hope that the topic will explain itself properly. Do not ever put your Grails project behind a path that contains other characters than [a-zA-Z0-9_.]!

Yesterday I spent several hours trying to figure out why my controller/action/UrlMapping changes are not reflecting into my run-time paths. For example, I changed my FooController's action from "bar" to "foo". The corresponding URL should have changed from <app>/foo/bar to <app>/foo/foo. Well.. it didn't.. However, my Grails console told me that changes have been compiled. If I changed the actual logic inside "bar" action, the changes were applied immediately. Strange indeed!

Power Googling didn't give any results. Neither did Grails version changes (I tried 2.2.1, 2.1.4 and 2.0.4). I suspected that the cause was my Java version (1.7.0_17), because my other IDE with Java 1.6.0_24 was working fine. It wasn't.

Finally I figured that my Eclipse workspace was set to C:/.../Some(thing)/../workspace. So, I moved my workspace to a different path and tried again. Now it worked like a charm! So the lesson of this blog post is: never shit your Grails URL reloading with extreme paths!

Tuesday 26 March 2013

Tuning Grails resources plugin to support multiple modules for same file

A long time since my previous blog post. Deepest apologizes, I have had so little time for my "hobbies"...

But now! I faced so frustrating issue in my work so that I must forward it to you. We have been developing our system quite a time already. Real problems started when it was time for the first test deployment to the actual server. We are using Grails as our controller layer which includes a wonderful resource plugin that enables us to use newest techiques in our assets easily (such as Coffeescript or LESS). The production mode will be caching, zipping and minimizing all resource modules in order to reduce clients' overhead. These are not used in development mode. So, during the deployment I discovered that the resource plugin has a "bug" which prevents the definition of same file to multiple modules.

After a Google moment, I found that the plugin's author wasn't planning to support such a feature (GPRESOURCES-166). We had two options: either divide our code into multiple mini-mini modules (which reduces the usefulness of modules a lot) OR try to go around the bug/feature.

So, after a long moment of discovering plugin's source codes, I managed to find a detour. It is not an elegant way but working well enough. The resouces plugin uses a chain of resource mappers to transform original files into processed files. The bundling and bundle renamining (for cache prevention) are dealt by using file paths as identifiers for files. So so... The best bet is to rename the file with a unique prefix before the resource is "registered" into module. When registering is done, the resources plugin tries to fetch the resource file based on its defined filename. Thus, we need to translate the modified filename back to the original one so that resources plugin can find the actual file. When the file has been fetched, resources plugin starts to process the file with its processing chain. We must add our own custom resource mapper to the beginning of that chain to translate processed resource's URL back to the original so that later processors can deal with right files.

The solution is to override two resource plugin's methods by using meta-programming. First we modify the filename during the resource definition. Then we rename it back to the original for file handle fetching. After that, we use our own resource mapper to change resource's URLs back to the normal at the beginning of the processing chain. And hóle! Now the plugin supports multiple module definitions for same file also with cached-resources plugin.

Here is the actual code:
You must place that into your grails-app/resourceMappers folder. After that you must enable support by calling MultipleStaticResources.enable() from your resources.groovy bean definition closure.
Of course this solution may conflict with our own resource mappers, but for me it works well enough: resource mappers for CoffeeScript, Handlebars, LESS, zipped and bundled/cached resoures (and also few own) are working fine with this hack.

Happy hacking!