Back | Minified | Changelog | Cautionlog

v1.3.0 is out! This one has been a long time in the waiting and has some really nice changes.

Customizable Builds

Sugar just got a lot more customizable. The "core" package is now split by class, meaning you can now create custom Sugar builds that include only the specific classes you need. Date locales have also been moved out of the default and into their own package, as have other language-specific methods, helping to push down the default download size to just under 16kb. This process represents a major refactoring and makes Sugar now extremely modular.

Additionally, the ECMAScript shim methods (browser built-in methods like Array#indexOf for browsers that don't support like IE) are now moved out into their own package as well. If you don't require legacy browser support (typically IE8 and below), you can remove this package and immediately save 1kb.

Sugar custom packages can be built here.

Enumerable Object Methods

Javascript has no internal concept of "Enumerables", but there are a number of enumerable methods on arrays that apply to objects as well, in the sense that they are "things that can be iterated over". Sugar previously provided an each method. This update now provides 14 new array methods to also now work on objects as well. These methods are: any, all, none, count, find, findAll, sum, average, min, max, least, most, map, and reduce.

Sugar of course never modifies Object.prototype, so these methods all exist as class methods. However, they are also available to extended objects, making them nearly as powerful as true Ruby-style hashes for a little extra work up front. This is especially evident when storing and manipulating JSON data:

var obj = Object.extended(json); obj.average('age'); obj.sum('votes'); obj.findAll(function(name, person) { return person.age > 10; });

Note that when callbacks are passed to enumerable methods, where they would previously be passed element, index for arrays, they are now instead passed key, value as the first 2 arguments. Last argument and this keyword is still the object itself.

Also of note is that these methods (as well as each and isEmpty) now reside in the Array package (which can be thought of as the "Enumerables" package), which means that they won't be available without including that package.

Finally, a single method Object.size was added as a shortcut to get the number of members in an object. "Size" was chosen as it is distinct from length, which is not a method, but a property.

Date Ranges

A new concept for Sugar, "date ranges", as the name implies, are an object that define a specific range of time with a discernable start and end. They are created through the Date class by simply passing a start and end to Date.range, which understands anything that Date.create does:

Date.range('now', 'next Sunday'); Date.range('15 minutes ago'); Date.range(new Date(2001, 1), new Date(2003, 1)); Date.range(980953200000, 986050800000);

All of these will result in valid ranges (note that if an argument is falsy it is assumed to be the current time). Once created, these ranges can be iterated over in various ways:

range.eachDay(fn); range.eachMonth(fn); range.every('2 weeks', fn); range.every((30).seconds(), fn);

In the examples above, callback fn will be passed a date object for each unit within the range, and will return an array containing every date object that was visited. Important to note is that the string format "2 weeks", and the each shortcuts, which are equivalent, reset lower units and increment that unit directly. This means that eachDay or every("day") on a range starting at June 27th 4:25pm will first visit June 27th 12:00:00am and increment the date by 1 on every iteration. In contrast, every((1).day()), which is receiving a number in milliseconds, will begin at June 27th 4:25pm and increment the date by 86400000 milliseconds on every iteration. Passing a number is more useful when precision is required.

Ranges also have a few other useful methods like contains which will determine if the range contains a date or another date range. Ranges can also be manipulated with intersect and union which act much like their Array counterparts. Of note, however, is that Date Ranges only have a single start and end, so any gaps in 2 ranges that have been merged will effectively be "filled in".

Date Ranges reside in their own package, which is included in the default download. For a full method list, see the docs.


A lot of updates have gone into the Date class, including some good performance optimizations. Date parsing formats are now scoped to their respective locale. Previously, when a language was set, its formats were added globally. While this did allow formats to be parsed without the proper locale code passed, it was a large performance penalty. This has now been changed so that the locale must be set correctly (either globally or by passing it to the date creation methods), however once set, the number of formats to lookup is significantly smaller, making for a faster result. Formats that are language-agnostic (such as numeric formats) are common to all locales.

This update also added the concept of a "cached format", which will take the last format that was successfully parsed and front load it, making operations that parse the same format repeatedly much faster.

Date output also has been enhanced, with 3 new output formats added for each locale: short, long, and full. short is the date alone, long is the date and time, and full is the full date and time with weekday and seconds. All 3 are available both through format, and as instance shortcut methods and can be passed locale codes returning formats appropriate to their given locale:

new Date().short() // -> "July 26, 2012" new Date().long() // -> "July 26, 2012 10:52pm" new Date().full() // -> "Thursday July 26, 2012 10:53:12pm" new Date().format('short') // -> "July 26, 2012" new Date().long('ja') // -> "2012年7月26日 22時54分"

The default format for Date.format() is now the long format.

Date manipulation also got some polishing. Date#reset will now accept any unit, for example date.reset('day') will reset the date and all smaller units. This method replaces Date#resetTime, which is now deprecated.

Date#advance will now accept a string format like "4 days", and, along with advancing methods like Date#addDays, now accepts a 2nd boolean argument which will reset all units lower than the one being passed, similar to Date#set:

new Date().advance('4 days') // -> 4 days from now new Date().advance('4 days', true) // -> 4 days from now and reset the time new Date().advance('2 years', true) // -> 2 years from now, all other units reset

Another cool addition is Date.past, and Date.future, which are alternate forms of Date.create. They will similarly parse a date, but will assume past or future when there is ambiguity, allowing the parsing system to infer context that was previously impossible:

Date.past('Monday') // -> last week Monday if Sunday, otherwise this week Monday Date.future('June') // -> next year June if after, this year June otherwise Date.future('11pm') // -> 11pm today or tomorrow

A good use for these methods would be a commenting system where such ambiguities are always in the past, or conversely a to-do list, where they are always in the future.

Date parsing now also handles a lot more formats. Time parsing is now much more robust and is fully supported in all locales, and includes time strings both before and after their corresponding date formats. Some pretty cool features like being able to parse out Chinese character numerals as numbers in dates and localized <date> at <time> formats are now supported as well.

Timezone issues also got a long looking at and a number of issues, especially those dealing with traversing across DST (daylight savings time) have now been addressed.

Other date changes include:


Methods in Math are now mapped to Number, making them easily accessible. This previously included floor, ceil, and round, (all of which take a value for precision), but now includes abs, pow, sin, asin, cos, acos, tan, atan, exp, pow, sqrt, and log. Note that the base parameter for log defaults to Math.E, returning the natural log of the number.

Other Changes