Nuria has submitted this change and it was merged.

Change subject: Split up utils
......................................................................


Split up utils

The utils file was getting large and it sucked to have to include all
the dependencies just to do a simple thing.

Change-Id: Ie7d6f3b1305a291392f5acae387e3d65b4c69d36
---
M src/app/data-converters/simple-separated-values.js
M src/app/require.config.js
A src/app/utils/arrays.js
A src/app/utils/colors.js
A src/app/utils/datetime.js
A src/app/utils/elements.js
A src/app/utils/numbers.js
A src/app/utils/strings.js
M src/components/annotation-list/annotation-list.js
M src/components/compare-layout/compare-layout.js
M src/components/metric-selector/metric-selector.js
M src/components/project-selector/bindings.js
M src/components/project-selector/project-selector.js
M src/components/visualizers/rickshaw-timeseries/bindings.js
M src/components/visualizers/visualizer/visualizer.js
D src/lib/utils.js
A test/app/utils.js
17 files changed, 240 insertions(+), 109 deletions(-)

Approvals:
  Nuria: Verified; Looks good to me, approved



diff --git a/src/app/data-converters/simple-separated-values.js 
b/src/app/data-converters/simple-separated-values.js
index 7cce9bf..fb595f4 100644
--- a/src/app/data-converters/simple-separated-values.js
+++ b/src/app/data-converters/simple-separated-values.js
@@ -2,9 +2,10 @@
  * This module returns a method that knows how to parse a file with values
  *   separated by arbitrary characters on lines separated by arbitrary 
characters
  */
+'use strict';
 define(function (require) {
 
-    var util = require('utils');
+    var stringUtils = require('utils.strings');
 
     /**
      * Parses a CSV, TSV, or similar into an array of rows.
@@ -35,7 +36,7 @@
             if (rows.length <= 1) { return []; }
 
             // try to determine the type of each column
-            var parsers = rows[1].map(util.parserFromSample);
+            var parsers = rows[1].map(stringUtils.parserFromSample);
             var trimmer = function (s) { return s.trim(); };
 
             // NOTE: will return the header but take care not to parse it
diff --git a/src/app/require.config.js b/src/app/require.config.js
index 196ff05..c8471ec 100644
--- a/src/app/require.config.js
+++ b/src/app/require.config.js
@@ -37,7 +37,6 @@
         'dataConverterFactory'  : 'app/data-converters/factory',
         'typeahead'             : 
'bower_modules/typeahead.js/dist/typeahead.bundle',
         'ajaxWrapper'           : 'lib/ajax-wrapper',
-        'utils'                 : 'lib/utils',
         'window'                : 'lib/window',
         'stateManager'          : 'lib/state-manager',
         'sitematrix'            : 'app/sitematrix',
@@ -68,6 +67,14 @@
         'converters.annotations'            : 
'app/data-converters/annotations-data',
         'converters.pageview-api-response': 
'app/data-converters/pageview-api-response',
 
+        // *** utils
+        'utils.arrays'              : 'app/utils/arrays',
+        'utils.strings'             : 'app/utils/strings',
+        'utils.datetime'            : 'app/utils/datetime',
+        'utils.numbers'             : 'app/utils/numbers',
+        'utils.colors'              : 'app/utils/colors',
+        'utils.elements'            : 'app/utils/elements',
+
         // *** lib
         'lib.polyfills'             : 'lib/polyfills',
     },
diff --git a/src/app/utils/arrays.js b/src/app/utils/arrays.js
new file mode 100644
index 0000000..a633291
--- /dev/null
+++ b/src/app/utils/arrays.js
@@ -0,0 +1,23 @@
+'use strict';
+define(function () {
+
+    return {
+        sortByName: function (a, b) {
+            // NOTE: this purposefully sorts uppercase before lowercase
+            return a.name === b.name ?
+                0 : a.name > b.name ? 1 : -1;
+        },
+        sortByNameIgnoreCase: function (a, b) {
+            return a.name.toLowerCase().localeCompare(b.name.toLowerCase());
+        },
+
+        /**
+         * Returns an array with "n" undefined values
+         */
+        filler: function (n) {
+            var empty = [];
+            empty.length = n;
+            return Array.apply(null, empty);
+        },
+    };
+});
diff --git a/src/app/utils/colors.js b/src/app/utils/colors.js
new file mode 100644
index 0000000..ac8160f
--- /dev/null
+++ b/src/app/utils/colors.js
@@ -0,0 +1,26 @@
+'use strict';
+define(function () {
+
+    return {
+        /**
+         * Poor man's category10 scale from d3, for when you don't want to
+         * import the whole library for a simple color scale
+         */
+        category10: function (domain, range) {
+            range = range || [
+                '#1f77b4', '#ff7f0e', '#2ca02c', '#d62728', '#9467bd',
+                '#8c564b', '#e377c2', '#7f7f7f', '#bcbd22', '#17becf'
+            ];
+            domain = domain || [];
+            return function (x) {
+
+                var index = domain.indexOf(x);
+                if (index < 0) {
+                    index = domain.push(x) - 1;
+                }
+
+                return range[index % range.length];
+            };
+        },
+    };
+});
diff --git a/src/app/utils/datetime.js b/src/app/utils/datetime.js
new file mode 100644
index 0000000..a0df1a4
--- /dev/null
+++ b/src/app/utils/datetime.js
@@ -0,0 +1,17 @@
+'use strict';
+define(function (require) {
+
+    var moment = require('moment');
+
+    require('twix');
+
+    return {
+        timespan: function (a, b) {
+            return moment(a).twix(b, {allDay: true}).format();
+        },
+
+        formatDate: function (d) {
+            return d ? moment(d).format('YYYY-MM-DD') : '(invalid)';
+        },
+    };
+});
diff --git a/src/app/utils/elements.js b/src/app/utils/elements.js
new file mode 100644
index 0000000..85cea37
--- /dev/null
+++ b/src/app/utils/elements.js
@@ -0,0 +1,16 @@
+'use strict';
+define(function (require) {
+
+    require('jquery');
+
+    return {
+        getBounds: function (element, parentSelector) {
+            var container = $(element).parents(parentSelector);
+
+            return {
+                width: container.innerWidth() || 0,
+                height: container.innerHeight() || 0,
+            };
+        },
+    };
+});
diff --git a/src/app/utils/numbers.js b/src/app/utils/numbers.js
new file mode 100644
index 0000000..3ca6ba0
--- /dev/null
+++ b/src/app/utils/numbers.js
@@ -0,0 +1,24 @@
+'use strict';
+define(function (require) {
+
+    var numeral = require('numeral');
+
+    return {
+
+        /**
+         * Get a number formatting function from a numeral.js format
+         */
+        numberFormatter: function (numeralFormatter) {
+            var niceNames = {
+                'percent': '0.0%',
+                'kmb': '0.0a',
+            };
+
+            numeralFormatter = niceNames[numeralFormatter] || numeralFormatter;
+
+            return function (n) {
+                return numeral(n).format(numeralFormatter);
+            };
+        },
+    };
+});
diff --git a/src/app/utils/strings.js b/src/app/utils/strings.js
new file mode 100644
index 0000000..277d10e
--- /dev/null
+++ b/src/app/utils/strings.js
@@ -0,0 +1,32 @@
+'use strict';
+define(function (require) {
+
+    var moment = require('moment');
+
+    return {
+        /**
+         * Using a sample string, returns a function that can parse
+         * similar values.  Falls back to the identity function.
+         */
+        parserFromSample: function (sample) {
+            // NOTE: Dates in YYYYMMDD format will parse incorrectly, please 
use
+            //       YYYY-MM-DD (with your choice of separator)
+            if (!isNaN(parseFloat(sample)) && isFinite(sample)) {
+                return function (x) {
+                    return parseFloat(x);
+                };
+            }
+            if (moment(sample).isValid()) {
+                return function (x) {
+                    return moment.utc(x).toDate();
+                };
+            }
+            // If the sample contains null values,
+            // the default parser tries to cast to float.
+            return function (x) {
+                return parseFloat(x) || x;
+            };
+        },
+
+    };
+});
\ No newline at end of file
diff --git a/src/components/annotation-list/annotation-list.js 
b/src/components/annotation-list/annotation-list.js
index 81a5950..e560c4c 100644
--- a/src/components/annotation-list/annotation-list.js
+++ b/src/components/annotation-list/annotation-list.js
@@ -6,7 +6,7 @@
         annotationsApi = require('apis.annotations'),
         marked = require('marked'),
         moment = require('moment'),
-        utils = require('utils');
+        dateUtils = require('utils.datetime');
 
     require('./bindings');
 
@@ -56,7 +56,7 @@
                 return formattedStart + ' - ' + formattedEnd;
             }
 
-            return utils.timespan(start, end);
+            return dateUtils.timespan(start, end);
         };
 
         this.annotations = ko.computed(function () {
diff --git a/src/components/compare-layout/compare-layout.js 
b/src/components/compare-layout/compare-layout.js
index 9fed7b0..a1d6353 100644
--- a/src/components/compare-layout/compare-layout.js
+++ b/src/components/compare-layout/compare-layout.js
@@ -10,7 +10,8 @@
         configApi = require('apis.config'),
         marked = require('marked'),
         moment = require('moment'),
-        utils = require('utils'),
+        dateUtils = require('utils.datetime'),
+        colorUtils = require('utils.colors'),
         asyncObs = require('observables.async'),
         TimeseriesData = require('converters.timeseries');
 
@@ -33,7 +34,7 @@
         this.fromDate = {
             options: this.dates,
             selected: ko.observable(),
-            format: utils.formatDate,
+            format: dateUtils.formatDate,
         };
         this.toDate = {
             options: ko.computed(function() {
@@ -42,7 +43,7 @@
                 }, this);
             }, this),
             selected: ko.observable(),
-            format: utils.formatDate,
+            format: dateUtils.formatDate,
             defaultToLast: true,
         };
         this.fromDate.selected.subscribe(function (newFromDate) {
@@ -51,7 +52,7 @@
             }
         }, this);
         this.timespan = ko.computed(function() {
-            return utils.timespan(this.fromDate.selected(), 
this.toDate.selected());
+            return dateUtils.timespan(this.fromDate.selected(), 
this.toDate.selected());
             // rate limit for when fromDate forces a change on toDate
         }, this).extend({ rateLimit: 0 });
 
@@ -182,14 +183,14 @@
                     }
 
                     // default to a 10-color scale, but use config if present
-                    var colorScale = utils.category10();
+                    var colorScale = colorUtils.category10();
                     if (c.colors) {
                         var domain = [], range = [];
                         _.forEach(c.colors, function (val, key) {
                             range.push(val);
                             domain.push(key);
                         });
-                        colorScale = utils.category10(domain, range);
+                        colorScale = colorUtils.category10(domain, range);
                     }
                     c.colors = colorScale;
 
diff --git a/src/components/metric-selector/metric-selector.js 
b/src/components/metric-selector/metric-selector.js
index f27f0d6..7b6c1ce 100644
--- a/src/components/metric-selector/metric-selector.js
+++ b/src/components/metric-selector/metric-selector.js
@@ -23,7 +23,7 @@
 
     var ko = require('knockout'),
         templateMarkup = require('text!./metric-selector.html'),
-        utils = require('utils');
+        arrayUtils = require('utils.arrays');
 
     require('./bindings');
 
@@ -57,13 +57,13 @@
         this.categories = ko.computed(function () {
             var unwrap = ko.unwrap(this.metricsByCategory) || [],
                 copy = unwrap.slice(),
-                categories = copy.sort(utils.sortByNameIgnoreCase);
+                categories = copy.sort(arrayUtils.sortByNameIgnoreCase);
 
             categories.splice(0, 0, {
                 name: 'All metrics',
                 metrics: [].concat.apply([], categories.map(function (c) {
                     return c.metrics;
-                })).sort(utils.sortByNameIgnoreCase)
+                })).sort(arrayUtils.sortByNameIgnoreCase)
             });
 
             // lots of different categories are sharing the same layout,
diff --git a/src/components/project-selector/bindings.js 
b/src/components/project-selector/bindings.js
index 6adce64..cedbde5 100644
--- a/src/components/project-selector/bindings.js
+++ b/src/components/project-selector/bindings.js
@@ -2,7 +2,7 @@
 define(function (require) {
 
     var ko = require('knockout'),
-        utils = require('utils');
+        arrayUtils = require('utils.arrays');
 
     require('typeahead');
 
@@ -23,7 +23,7 @@
             // an array that will be populated with substring matches
             matches = unwrapped.filter(function (item) {
                 return substrRegex.test(item.name);
-            }).sort(utils.sortByName);
+            }).sort(arrayUtils.sortByName);
 
             callback(matches);
         };
diff --git a/src/components/project-selector/project-selector.js 
b/src/components/project-selector/project-selector.js
index a8f4f1b..625a42e 100644
--- a/src/components/project-selector/project-selector.js
+++ b/src/components/project-selector/project-selector.js
@@ -3,7 +3,7 @@
 
     var ko              = require('knockout'),
         templateMarkup  = require('text!./project-selector.html'),
-        utils           = require('utils');
+        arrayUtils      = require('utils.arrays');
     require('./bindings');
 
     function ProjectSelector(params) {
@@ -117,7 +117,7 @@
                 this.addProject({project: selection.name});
                 return;
         }
-        options.sort(utils.sortByNameIgnoreCase);
+        options.sort(arrayUtils.sortByNameIgnoreCase);
         this.suboptions(options);
     };
 
diff --git a/src/components/visualizers/rickshaw-timeseries/bindings.js 
b/src/components/visualizers/rickshaw-timeseries/bindings.js
index f3b5556..54a0cc1 100644
--- a/src/components/visualizers/rickshaw-timeseries/bindings.js
+++ b/src/components/visualizers/rickshaw-timeseries/bindings.js
@@ -1,9 +1,10 @@
+'use strict';
 define(function(require) {
 
     var Rickshaw = require('rickshaw'),
         ko = require('knockout'),
         d3 = require('d3'),
-        getBounds = require('utils').getBounds;
+        getBounds = require('utils.elements').getBounds;
 
     require('lib/polyfills');
 
@@ -22,8 +23,8 @@
 
             graphEl.graph = new Rickshaw.Graph({
                 element: graphEl,
-                width: opt.width || bounds.width * (opt.widthRatio || 13/16),
-                height: opt.height || bounds.height * (opt.heightRatio || 5/6),
+                width: opt.width || bounds.width * (opt.widthRatio || 13 / 16),
+                height: opt.height || bounds.height * (opt.heightRatio || 5 / 
6),
                 renderer: 'multi',
                 series: [],
             });
diff --git a/src/components/visualizers/visualizer/visualizer.js 
b/src/components/visualizers/visualizer/visualizer.js
index 2da0341..ec0e348 100644
--- a/src/components/visualizers/visualizer/visualizer.js
+++ b/src/components/visualizers/visualizer/visualizer.js
@@ -5,7 +5,7 @@
         ko = require('knockout'),
         _ = require('lodash'),
         apiFinder = require('api-finder'),
-        utils = require('utils'),
+        colorUtils = require('utils.colors'),
         TimeseriesData = require('converters.timeseries');
 
     require('datepicker-binding');
@@ -22,14 +22,14 @@
         // like visualizers[this.type].showColumnToggle
         this.columnToggle = this.type !== 'sunburst' && this.type !== 
'hierarchy';
 
-        var colorScale = utils.category10();
+        var colorScale = colorUtils.category10();
         if (graph.colors) {
             var domain = [], range = [];
             _.forEach(graph.colors, function (val, key) {
                 range.push(val);
                 domain.push(key);
             });
-            colorScale = utils.category10(domain, range);
+            colorScale = colorUtils.category10(domain, range);
         }
 
         this.data = ko.observable(new TimeseriesData());
diff --git a/src/lib/utils.js b/src/lib/utils.js
deleted file mode 100644
index 8122583..0000000
--- a/src/lib/utils.js
+++ /dev/null
@@ -1,85 +0,0 @@
-'use strict';
-/**
- * Look into doing this with Lodash if we can make a slim enough build
- **/
-define(function (require) {
-
-    var moment = require('moment');
-
-    require('twix');
-
-    var utils = {
-        sortByName: function (a, b) {
-            // NOTE: this purposefully sorts uppercase before lowercase
-            return a.name === b.name ?
-                0 : a.name > b.name ? 1 : -1;
-        },
-        sortByNameIgnoreCase: function (a, b) {
-            return a.name.toLowerCase().localeCompare(b.name.toLowerCase());
-        },
-        getBounds: function (element, parentSelector) {
-            var container = $(element).parents(parentSelector);
-
-            return {
-                width: container.innerWidth() || 0,
-                height: container.innerHeight() || 0,
-            };
-        },
-        /**
-         * Using a sample string, returns a function that can parse
-         * similar values.  Falls back to the identity function.
-         */
-        parserFromSample: function (sample) {
-            // NOTE: Dates in YYYYMMDD format will parse incorrectly, please 
use
-            //       YYYY-MM-DD (with your choice of separator)
-            if (!isNaN(parseFloat(sample)) && isFinite(sample)) {
-                return function (x) { return parseFloat(x); };
-            }
-            if (moment(sample).isValid()) {
-                return function (x) { return moment(x).toDate(); };
-            }
-            // If the sample contains null values,
-            // the default parser tries to cast to float.
-            return function (x) { return parseFloat(x) || x; };
-        },
-
-        timespan: function (a, b) {
-            return moment(a).twix(b, {allDay: true}).format();
-        },
-
-        formatDate: function (d) {
-            return d ? moment(d).format('YYYY-MM-DD') : '(invalid)';
-        },
-
-        /**
-         * Returns an array with "n" undefined values
-         */
-        filler: function (n) {
-            var empty = [];
-            empty.length = n;
-            return Array.apply(null, empty);
-        },
-
-        /**
-         * Poor man's category10 scale from d3, for when you don't want to
-         * import the whole library for a simple color scale
-         */
-        category10: function (domain, range) {
-            range = range || [
-                '#1f77b4', '#ff7f0e', '#2ca02c', '#d62728', '#9467bd',
-                '#8c564b', '#e377c2', '#7f7f7f', '#bcbd22', '#17becf'
-            ];
-            domain = domain || [];
-            return function (x) {
-
-                var index = domain.indexOf(x);
-                if (index < 0) {
-                    index = domain.push(x) - 1;
-                }
-
-                return range[index % range.length];
-            };
-        },
-    };
-    return utils;
-});
diff --git a/test/app/utils.js b/test/app/utils.js
new file mode 100644
index 0000000..9882d07
--- /dev/null
+++ b/test/app/utils.js
@@ -0,0 +1,68 @@
+'use strict';
+define(function (require) {
+
+    var arrays = require('utils.arrays'),
+        strings = require('utils.strings'),
+        datetime = require('utils.datetime'),
+        numbers = require('utils.numbers'),
+        colors = require('utils.colors'),
+        elements = require('utils.elements');
+
+    describe('Array Utilities', function () {
+
+        it('should make a zero-filled array', function () {
+            expect(arrays.filler(3)).toEqual([undefined, undefined, 
undefined]);
+        });
+    });
+
+    describe('String Utilities', function () {
+        var dateString = '2015-01-02 00:00:10',
+            dateString2 = '2015-01-02 00:00:20',
+            floatString = '1234.40',
+            d = strings.parserFromSample(dateString),
+            f = strings.parserFromSample(floatString);
+
+        var timediff = d(dateString2).getTime() - d(dateString).getTime();
+
+        it('should parse dates or numbers properly', function () {
+            expect(timediff).toBe(10000);
+            expect(f(floatString)).toBe(1234.40);
+        });
+    });
+
+    describe('Datetime Utilities', function () {
+
+        it('should format a span of dates', function () {
+            expect(datetime.timespan('2015-01-30', '2015-02-01'))
+                .toBe('Jan 30 - Feb 1, 2015');
+        });
+    });
+
+    describe('Number Utilities', function () {
+
+        it('should format kmb', function () {
+            expect(numbers.numberFormatter('kmb')(1234567)).toBe('1.2m');
+            expect(numbers.numberFormatter('0.00a')(1234567)).toBe('1.23m');
+            expect(numbers.numberFormatter('percent')(0.123)).toBe('12.3%');
+        });
+    });
+
+    describe('Color Utilities', function () {
+        var scale = colors.category10();
+
+        scale('one');
+        scale('two');
+        scale('three');
+
+        it('should produce consistent colors', function () {
+            expect(scale('one')).toBe(scale('one'));
+        });
+    });
+
+    describe('Element Utilities', function () {
+        // needs DOM to test
+        it('should define something', function () {
+            expect(elements.getBounds).toBeDefined();
+        });
+    });
+});
\ No newline at end of file

-- 
To view, visit https://gerrit.wikimedia.org/r/282183
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: merged
Gerrit-Change-Id: Ie7d6f3b1305a291392f5acae387e3d65b4c69d36
Gerrit-PatchSet: 2
Gerrit-Project: analytics/dashiki
Gerrit-Branch: master
Gerrit-Owner: Milimetric <[email protected]>
Gerrit-Reviewer: Mforns <[email protected]>
Gerrit-Reviewer: Nuria <[email protected]>

_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to