1.2.0
◀Back | Minified | Changelog2012-01-19
v1.2 is now released! This release adds some cool new features that will take Sugar in a bit of a new direction.
Sugar is now extendable.
New in 1.2 is the extend method, which is available to all built-in Javascript classes. This method hooks into Sugar's internal system of mapping methods onto the prototype, and allows developers to add their own methods! There are a number of benefits to doing this. First, it will make use of the ES5 method defineProperty if available to prevent the method from appearing in for..in loops as an enumerable property. Additionally, when extending native objects you can have better control in the case of collisions. By default, Sugar will always defer to methods that already exist, as it does internally. However, passing true as the second property to extend will override any existing methods:
Where it starts getting really interesting, however, is by passing a function as the override property. This will allow you to override methods but defer to them conditionally:
In addition to the methods themselves, the module also adds a new object String.Inflector to help augment the inflector itself:
These replacements will be run when calling the appropriate method. uncountable and irregular apply to both singular and pluralize. Note also acronym, which is a new part of ActiveSupport that hasn't found its way to Rails yet. Also a point of personal pride is titleize which will properly not capitalize prepositions, articles, and the like.
Finally, String#namespace was added, which will find a global namespace or return undefined if none is found:
If any of the namespaces are not defined along the way, for example Ext or Ext.Base, the method will return undefined instead of throwing an error.
Array fuzzy object finding
Sugar previously supported passing an object to array methods like findAll or any. This would recursively match every property of that object against elements in the array, allowing for identical objects whose references are different to match. Compare this to built-in indexOf, which does not match object properties:
[person].indexOf(person) > true
[person].indexOf({ name: 'joe' }) > false
[person].any(person) > true
[person].any({ name: 'joe' }) > true Although this would properly match, objects previously had to be identical. This behavior has changed and now all array methods are "fuzzy" by default when passing an object:
[person].any({ name: 'joe' }) > true
[person].any({ name: 'joe', age: 20 }) > true
[person].any({ name: 'joe', age: 22 }) > false Where this gets even more interesting is that now any property of the search object passed can also be either a regex, which will match a string against the pattern, or a function which will match against a callback. Both of these were available previously to Sugar when directly passed, however now that they themselves are subject to recursive matching inside objects, some very cool patterns become possible:
[person].any({ name: /j(oe|erry)/ }); // true
[person].any({
age: function(age) {
return a > 10 &&; a;
}); // true This opens up a whole range of possibilties such as building up search filters that can be cached, and much, much more. This behavior is now the default for all Sugar array methods (when passing an object), which affects the following methods:
Array#everyArray#someArray#filterArray#findArray#findAllArray#findIndexArray#removeArray#noneArray#countArray#exclude
One of the more cool things is that this change is across the board, as those methods in the ES5 spec (every, some, and filter) do not natively support passing an object as an argument, so the default behavior is still preserved. Of course if you want to match identical objects, this is still perfectly possible:
[person].any(function(obj) {
return Object.equal(obj, { name: 'joe' });
} > false Or even simpler:
[person].any(Object.equal.fill({ name: 'joe' })); > false If you can assure that your data all has the same number of properties, then you don't even have to bother with this:
[joe, sam].any(joe); > true
[joe, sam].any(sam); > true
[joe, sam].all(joe); > false Number abbreviations
Another new feature in v1.2 is abbreviation methods on the Number class:
(1245).abbr(1) > '1k'
(1245).abbr(2) > '1.2k'
(1245).abbr(3) > '1.25k' Number#abbr will abbreviate the number with an upper limit of t for "trillion", beyond which it will pretty format the numeral using Number#format. It can be passed a single number that will determine it's rounding precision. From here we get a bit crazy:
(1250).metric(2) + 'g' > "1.25kg"
(1250).metric(2, 0) + 'L' > "1,250L"
(0.025).metric() + 'm' > "25mm"
(0.00025).metric() + 'm' > "250μm" Number#metric will render the number into the metric system, using standard unit suffixes. Like Number#abbr, the first argument is the rounding precision. The second parameter is the "limit" which caps the highest unit to be used. The default is 1, which is k ("kilo-"), however, this can be changed by passing a different value, or by passing false, in which case the only imposed limit is the highest unit, currently 6, or E ("exa-"). Number#metric can also convert extremely small numbers as well, down to the "nano" level.
Finally, Number#bytes hooks into the same system to produce "bytes" abbreviations on a base 2 system. Arguments are identical, but the default limit is 4, or T ("tera-"). However, this default may eventually be subject to Moore's law :)
Other changes
The "sugar" method is now split into two:
- Restoring methods is now
restore. - Object.prototype extension functionality is now on
extend. - For more info see objects.
Other:
- Added
Number#isIntegerwhich returns true if the number has no decimal. - Object.keys now passes values as part of its callback, when passed.
- Object.merge now merges undefined properties as well.
Array#cloneis now no longer based offArray#concat, which will fail on sparse arrays in IE7.- Fixed issue with
Number#ordinalizewhere 113 would be "113rd". String#eachwill now pass the match into the callback like array methods.String#toDatewill now check for Date.create before hooking into it.String#underscorewill now check for acronyms if Inflectors module is present.String#camelizewill now check for acronyms if Inflectors module is present.RegExp.escapewill now perform a[toString]operation on non-strings (ie. numbers, etc).Function#fillnow uses internal Array#splice to fill in arguments.- Added support for JSON date format
Date(xxxxxxxxxx). - Fixed issues with
Date#getWeek. - Fixed issues with traversing months before January.