From 64cd51667dc498412cbaeb53cd92cc6de7a04e23 Mon Sep 17 00:00:00 2001 From: Adel Gadllah Date: Sun, 4 Oct 2009 23:30:18 +0200 Subject: [PATCH] Add String formatting Add String formatting by extending the String object with a format method. Now we can do stuff like "Text: %s, %d".format(somevar, 5) This is required for proper translation of some strings. https://bugzilla.gnome.org/show_bug.cgi?id=595661 --- js/misc/Makefile.am | 3 ++- js/misc/format.js | 44 ++++++++++++++++++++++++++++++++++++++++++++ js/ui/environment.js | 3 +++ tests/Makefile.am | 3 ++- tests/unit/format.js | 29 +++++++++++++++++++++++++++++ 5 files changed, 80 insertions(+), 2 deletions(-) create mode 100644 js/misc/format.js create mode 100644 tests/unit/format.js diff --git a/js/misc/Makefile.am b/js/misc/Makefile.am index a278812ba..084a45cad 100644 --- a/js/misc/Makefile.am +++ b/js/misc/Makefile.am @@ -1,4 +1,5 @@ jsmiscdir = $(pkgdatadir)/js/misc dist_jsmisc_DATA = \ - docInfo.js + docInfo.js \ + format.js diff --git a/js/misc/format.js b/js/misc/format.js new file mode 100644 index 000000000..e6848b565 --- /dev/null +++ b/js/misc/format.js @@ -0,0 +1,44 @@ +/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */ + +/* + * This function is intended to extend the String object and provide + * an String.format API for string formatting. + * It has to be set up using String.prototype.format = Format.format; + * Usage: + * "somestring %s %d".format('hello', 5); + * It supports %s, %d and %f, for %f it also support precisions like + * "%.2f".format(1.526) + */ + +function format() { + let str = this; + let i = 0; + let args = arguments; + + return str.replace(/%(?:\.([0-9]+))?(.)/g, function (str, precisionGroup, genericGroup) { + + if (precisionGroup != '' && genericGroup != 'f') + throw new Error("Precision can only be specified for 'f'"); + + switch (genericGroup) { + case '%': + return '%'; + break; + case 's': + return args[i++].toString(); + break; + case 'd': + return parseInt(args[i++]); + break; + case 'f': + if (precisionGroup == '') + return parseFloat(args[i++]); + else + return parseFloat(args[i++]).toFixed(parseInt(precisionGroup)); + break; + default: + throw new Error('Unsupported conversion character %' + genericGroup); + } + + }); +} diff --git a/js/ui/environment.js b/js/ui/environment.js index 718b1f1a0..6d0bb4884 100644 --- a/js/ui/environment.js +++ b/js/ui/environment.js @@ -4,6 +4,8 @@ const St = imports.gi.St; const Tweener = imports.ui.tweener; +const Format = imports.misc.format; + // "monkey patch" in some varargs ClutterContainer methods; we need // to do this per-container class since there is no representation // of interfaces in Javascript @@ -30,4 +32,5 @@ _patchContainerClass(St.Table); function init() { Tweener.init(); + String.prototype.format = Format.format; } diff --git a/tests/Makefile.am b/tests/Makefile.am index 0803394fe..ebe65fcfe 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -10,7 +10,8 @@ TEST_JS = \ interactive/scrolling.js \ interactive/table.js \ testcommon/border-image.png \ - testcommon/ui.js + testcommon/ui.js \ + unit/format.js EXTRA_DIST += $(TEST_JS) TEST_MISC = \ diff --git a/tests/unit/format.js b/tests/unit/format.js new file mode 100644 index 000000000..9e618c27b --- /dev/null +++ b/tests/unit/format.js @@ -0,0 +1,29 @@ +/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */ + +/* + * Test cases for the Format module + */ + +const JsUnit = imports.jsUnit; +const assertEquals = JsUnit.assertEquals; +const assertRaises = JsUnit.assertRaises; + +// We can't depend on environment.js to set up the String.prototype.format, +// because the tests run in one JS context, and the imports run in the GJS +// "load context" which has its own copy of the String class +const Format = imports.misc.format; +String.prototype.format = Format.format; + +// Test common usage and %% handling +assertEquals("foo", "%s".format('foo')); +assertEquals("%s", "%%s".format('foo')); +assertEquals("%%s", "%%%%s".format('foo')); +assertEquals("foo 5", "%s %d".format('foo', 5)); +assertEquals("8", "%d".format(8)); +assertEquals("2.58 6.96", "%f %.2f".format(2.58, 6.958)); + +// Precision is only allowed for %f +assertRaises(function() { "%.2d".format(5.21) }); + +// Wrong conversion character ' ' +assertRaises( function() { "%s is 50% done".format('foo') });