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#every
Array#some
Array#filter
Array#find
Array#findAll
Array#findIndex
Array#remove
Array#none
Array#count
Array#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#isInteger
which 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#clone
is now no longer based offArray#concat
, which will fail on sparse arrays in IE7.- Fixed issue with
Number#ordinalize
where 113 would be "113rd". String#each
will now pass the match into the callback like array methods.String#toDate
will now check for Date.create before hooking into it.String#underscore
will now check for acronyms if Inflectors module is present.String#camelize
will now check for acronyms if Inflectors module is present.RegExp.escape
will now perform a[toString]
operation on non-strings (ie. numbers, etc).Function#fill
now 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.