Monthly Archives: June 2011

thx: parsing dates

One of the latest additions to thx is thx.dates.DateParser. It is obviously a date parser, the nice thing about it is that it tries to be fuzzy and to extract a date whenever possible. You can try it yourself here:

Examples of expressions:

  • today
  • now
  • tomorrow
  • next april
  • last sunday
  • three weeks ago plus 5 minutes
  • tomorrow in the evening
  • 6/27
  • 27/6

To produce this tiny demo you just need a bunch of lines of code:

import thx.date.DateParser;
import thx.js.Dom;
import js.Dom;
class Main
{
  static function main()
  {
    Dom.select("#date").onNode("keyup", function(n : HtmlDom, _) {
      var t : Text = cast n;
      var result = try {
        Dates.format(DateParser.parse(t.value), "DT");
      } catch (e : Dynamic) {
        Std.string(e);
      }
      Dom.select("#processed")
        .html().string(result);
    });
  }
}

Surely the expression grammar can be improved but it works for my needs right now and it is already very flexible.

thx: basics

In this post I continue to describe the basic functionalities of thx. I’ve decided to put those classes directly in the root because that make them extremely accessible and cases for name conflicts are really low. Having them in the root is perfect if you don’t want to “waste” a line of code for importing a class that you will use just once. For example I always do stuff like:

var values = Ints.range(10);

If you work a lot with math algorithms, the Ints and Floats classes can really make your life easier. Let’s see some examples:

trace(Ints.range(3)); // -> [0,1,2]
trace(Ints.range(7, 10)); // -> [7,8,9]
trace(Ints.range(0, 10, 2)); // -> [0,2,4,6,8]
trace(Floats.range(0, 10, 2.5)); // -> [0,2.5,5,7.5]

I build parsers, encoders and decoders quite often and if that happen to you too you will probably appreciate Ints.canParse(mystring) and Ints.parse. They are really simple functions but help a lot rationalizing your code. The same functions exist in Floats, Dates and Bools (remember that the helper class has the same name as the class it extends but pluralized). The other said of the coin is Ints.format() which convert the value into its string representation. The format function accept formatting options and optionally the reference to a Culture instance (the default one is used if omitted).

Interpolate is also present in most of the basic types. It is really handy for transitions and you can also specify the equation you want to use (default is a linear equation); you can find more pre-cooked equations in thx.math.Equations). So you can interpolate on Strings, Floats, Values, Dates, Arrays and Dynamics … pretty wide options. Where you find the “interpolate” method, usually you find interpolatef too. It works the same but returns a function that takes a float as argument so that you can reuse the same settings over and over. You may wonder what does it mean that you can interpolate over a String or
Dynamic, but it is easy said. Strings.interpolate extracts the floats/integers values from a pair of strings and interpolate those values. Dynamics.interpolate detects the runtime type of the range values and use the function from the corresponding type; if the values do not match a type with a known interpolator an exception is thrown (instance of thx.error.Error).

One of the function I use a lot for debugging is Dynamics.string() that takes any object and transform it into a nicely formatted string. It is surely heavier than Std.string() but it also tries to give a more complete representation of the value passed. Let’s compare both:

var o = [{
	name : "John Doe",
	birthdate : Date.fromString("1972-07-05"),
	score : 7777.7,
	contacts : {
			emails : [
			{ type : "personal", email : "john@example.com" },
			{ type : "work", email : "jd@example.com" }
		]
	}
}, {
	name : "Jane Doe",
	birthdate : Date.fromString("1974-06-09"),
	score : 77777.7,
		contacts : {
			emails : [
			{ type : "personal", email : "jane@example.com" }
		]
	}
}];

trace(Std.string(o));
trace(Dynamics.string(o));

The first trace returns (newline added by hand):

[{
  name : John Doe,
  birthdate : 1972-07-05 00:00:00,
  score : 7777.7,
  contacts : {
    emails : [{
      type : <...>, email : <...> },{
      type : <...>, email : <...> }] } },{
  name : Jane Doe,
  birthdate : 1974-06-09 00:00:00,
  score : 77777.7,
  contacts : {
    emails : [{
      type : <...>,
      email : <...> }] } }]

So you may notice that at some level of recursion the contents are simply striped off; this makes sense in most occasions but I like to have the option to display everything if I have to. This is the output of the second trace (again, newlines added by hand):

[{
  name : "John Doe",
  birthdate : Wednesday, July 05, 1972,
  score : 7,777.70,
  contacts : {
    emails : [{
      type : "personal",
      email : "john@example.com"}, {
      type : "work", email : "jd@example.com"}]}}, {
  name : "Jane Doe",
  birthdate : Sunday, June 09, 1974,
  score : 77,777.70,
  contacts : {
    emails : [{
      type : "personal",
      email : "jane@example.com"}]}}]

So, what are the differences?

  • Strings are quoted (this is handy for guessing the type by just looking at the dump).
  • Dates and numbers are formatted.
  • The whole graph is shown.

That’s all for now ;)

thx : Arrays

In thx there are many helper methods. The convention is that if a class is not meant to be instantiated and its only purpose is to add functionalities to other types than it will be named after the type it enhances but in the plural form. So it is now pretty obvious that Arrays is a helper class for the Array type as Strings is a helper class for String.

So far I am really focused to add (and to improve) features and I am not really worry about file size or performances. Some of the helper classes are pretty dense and refers to other dense definitions which can add some weight to your output. This issue will be addressed at some point by improving thx compatibility with haxe DCE (Dead Code Elimination) or maybe splitting the classes.

Back on the post topic, I’d like to introduce a few of the options you can find in Arrays. So I assume for the following examples that using Arrays; is always in place since that makes the programmer life even easier.

Arrays adds some functions to enhance method chaining, for example you can write:

var arr = [].add(1).add(2).addIf(value > 2, 3).remove(2);

Many methods in Arrays derive from the Lambda class found in the std library but tend to be more flexible and the definitions are also repeated in Iterators and Iterables to make your life easier. Whenever is possible inline is used to prevent adding a new level of indirection. Note that if a method returns a list, it always returns an Array, even if you are using the Iterator or Iterable type. Arrays are pretty fast on all the platforms and are a lot more flexible than the iterators.

// Ints.range(10) returns an array of int from 0 to 9
var arr = Ints.range(10)
  .filter(function(d) return 0 == d % 2)
  .map(function(d,i) return d*d);
// arr is [0,4,16,36,64]

Since hxculture has been included inside thx, you can format many types (and Array is not an exception) to string in a localized fashion. So far you can use 2 formats with array J for “join” and C for “count”.

trace(arr);  //  [0,4,16,36,64]
trace(arr.format("J")); // 0, 4, 16, 36, 64
// the first parameter is for the format of each individual value
trace(arr.format("J", ["D"]));  //  0.00, 4.00, 16.00, 36.00, 64.00
// the second parameter is for empty array
trace([].format("J", ["D", "-"]));  //  -
// the third parameter is the separator
trace(arr.format("J", ["D", "-", "; "]));  //  0.00; 4.00; 16.00; 36.00; 64.00
// the fourth parameter is the max number of elements to display
trace(arr.format("J", ["D", "-", "; ", "3"]));  //  0.00; 4.00; 16.00 ...
// the fifth parameter is for the remaining elements after max
trace(arr.format("J", ["D", "-", "; ", "3", " and more"]));  //  0.00; 4.00; 16.00 and more

trace(arr.format("C"));  //  5

You can also create a format function using var f = Arrays.formatf("J", ["D"]); and after that f([1,2,3]);

Functions like .all()/.any() permits to check if all or at least one of the elements of the array matches a certain rule. The rest of the functions in Arrays are pretty obvious to catch but if you have any doubt I will be glad to five more insights.

thx: color

thx is really growing fast and since it is not yet documented I want to start giving users some hints on the classes included.

The thx.color package is the first set of features I will introduce since the API is pretty stable and I use it a lot.

Creating a color from its channels is really easy:

var color = new Rgb(255, 0, 0); // RGB values are integers from 0 to 255

Of course you can use alternatives to create a Rgb color:

color = Rgb.fromInt(0xFF000);

or

color = Rgb.fromFloats(1.0, 0.0, 0.0);

… but if you are as lazy as I am you can use:

color = NamedColors.red;

or even

color = Colors.parse("red");

Note that Colors.parse() will try everything to find a matching color, infact you can pass a:

  • color name, as defined in NamedColors; names with spaces are accepted aswell (ei: “dark sea green“)
  • css color: #ff0000
  • rgb definition: rgb(255,0,1)
  • hsl definition: hsl(0,1,0.5)
  • cmyk definition: cmyk(0,1,1,0)

Other than Rgb you can define colors in the following colorspaces: Hsl, Grey, Cmyk

I find Hsl particularly useful when you want to create smooth interpolations:

using thx.colors.Hsl;
// ...
var midcolor = Hsl.interpolate(NamedColors.red.toHsl(), NamedColors.blue.toHsl(), 0.5);

If you want to recycle the interpolation and generate an array of colors you can use:

using Arrays;using thx.colors.Hsl;
// ...
var f = Hsl.interpolatef(NamedColors.red.toHsl(), NamedColors.blue.toHsl()),	len = 10;
var colors = Ints.range(len).map(function(_, i) return f(i / (len-1)));

The interpolate/interpolatef methods in Colors will do the same but starting from string definitions.

This can be very handy when you want to interpolate a CSS color. The Rgb.contrast/constrastBW methods are also pretty useful. The former will try to find a pastel color that contrasts with the passed one while the latter will always return white or black. The algorithm of contrastBW uses the grey equivalent of the passed color to estabilish the better contrast for the human vision.