Skip to content

Commit

Permalink
Implement round filter
Browse files Browse the repository at this point in the history
  • Loading branch information
jmealo committed Jun 9, 2014
1 parent bcc3632 commit 667ad0c
Show file tree
Hide file tree
Showing 5 changed files with 186 additions and 3 deletions.
22 changes: 22 additions & 0 deletions src/twig.filters.js
Original file line number Diff line number Diff line change
Expand Up @@ -507,6 +507,28 @@ var Twig = (function (Twig) {
raw: function(value) {
//Raw filter shim
return value;
},
round: function(value, params) {
params = params || [];

var precision = params.length > 0 ? params[0] : 0,
method = params.length > 1 ? params[1] : "common";

value = parseFloat(value);

if(precision && !Twig.lib.is("Number", precision)) {
throw new Twig.Error("round filter expects precision to be a number");
}

if (method === "common") {
return Twig.lib.round(value, precision);
}

if(!Twig.lib.is("Function", Math[method])) {
throw new Twig.Error("round filter expects method to be 'floor', 'ceil', or 'common'");
}

return Math[method](value * Math.pow(10, precision)) / Math.pow(10, precision);
}
};

Expand Down
54 changes: 54 additions & 0 deletions src/twig.lib.js
Original file line number Diff line number Diff line change
Expand Up @@ -612,6 +612,60 @@ var Twig = (function(Twig) {
return string.split(search).join(replace);
};

Twig.lib.round = function round(value, precision, mode) {
// discuss at: http://phpjs.org/functions/round/
// original by: Philip Peterson
// revised by: Onno Marsman
// revised by: T.Wild
// revised by: Rafał Kukawski (http://blog.kukawski.pl/)
// input by: Greenseed
// input by: meo
// input by: William
// input by: Josep Sanz (http://www.ws3.es/)
// bugfixed by: Brett Zamir (http://brett-zamir.me)
// note: Great work. Ideas for improvement:
// note: - code more compliant with developer guidelines
// note: - for implementing PHP constant arguments look at
// note: the pathinfo() function, it offers the greatest
// note: flexibility & compatibility possible
// example 1: round(1241757, -3);
// returns 1: 1242000
// example 2: round(3.6);
// returns 2: 4
// example 3: round(2.835, 2);
// returns 3: 2.84
// example 4: round(1.1749999999999, 2);
// returns 4: 1.17
// example 5: round(58551.799999999996, 2);
// returns 5: 58551.8

var m, f, isHalf, sgn; // helper variables
precision |= 0; // making sure precision is integer
m = Math.pow(10, precision);
value *= m;
sgn = (value > 0) | -(value < 0); // sign of the number
isHalf = value % 1 === 0.5 * sgn;
f = Math.floor(value);

if (isHalf) {
switch (mode) {
case 'PHP_ROUND_HALF_DOWN':
value = f + (sgn < 0); // rounds .5 toward zero
break;
case 'PHP_ROUND_HALF_EVEN':
value = f + (f % 2 * sgn); // rouds .5 towards the next even integer
break;
case 'PHP_ROUND_HALF_ODD':
value = f + !(f % 2); // rounds .5 towards the next odd integer
break;
default:
value = f + (sgn > 0); // rounds .5 away from zero
}
}

return (isHalf ? value : Math.round(value)) / m;
}

return Twig;

})(Twig || { });
31 changes: 31 additions & 0 deletions test/test.filters.js
Original file line number Diff line number Diff line change
Expand Up @@ -480,6 +480,37 @@ describe("Twig.js Filters ->", function() {
});
});

describe('round ->', function () {
it('should round up (common)', function () {
var test_template = twig({data: "{{ 2.7|round }}"});
test_template.render().should.equal("3");
});
it('should round down (common)', function () {
var test_template = twig({data: "{{ 2.1|round }}"});
test_template.render().should.equal("2");
});
it('should truncate input when input decimal places exceeds precision (floor)', function () {
var test_template = twig({data: "{{ 2.1234|round(3, 'floor') }}" });
test_template.render().should.equal("2.123");
});
it('should round up (ceil)', function () {
var test_template = twig({data: "{{ 2.1|round(0, 'ceil') }}" });
test_template.render().should.equal("3");
});
it('should truncate precision when a negative precision is passed (common)', function () {
var test_template = twig({data: "{{ 21.3|round(-1)}}" });
test_template.render().should.equal("20");
});
it('should round up and truncate precision when a negative precision is passed (ceil)', function () {
var test_template = twig({data: "{{ 21.3|round(-1, 'ceil')}}" });
test_template.render().should.equal("30");
});
it('should round down and truncate precision when a negative precision is passed (floor)', function () {
var test_template = twig({data: "{{ 21.3|round(-1, 'ceil')}}" });
test_template.render().should.equal("30");
});
});

it("should chain", function() {
var test_template = twig({data: '{{ ["a", "b", "c"]|keys|reverse }}' });
test_template.render().should.equal("2,1,0");
Expand Down
76 changes: 76 additions & 0 deletions twig.js
Original file line number Diff line number Diff line change
Expand Up @@ -1706,6 +1706,60 @@ var Twig = (function(Twig) {
return string.split(search).join(replace);
};

Twig.lib.round = function round(value, precision, mode) {
// discuss at: http://phpjs.org/functions/round/
// original by: Philip Peterson
// revised by: Onno Marsman
// revised by: T.Wild
// revised by: Rafał Kukawski (http://blog.kukawski.pl/)
// input by: Greenseed
// input by: meo
// input by: William
// input by: Josep Sanz (http://www.ws3.es/)
// bugfixed by: Brett Zamir (http://brett-zamir.me)
// note: Great work. Ideas for improvement:
// note: - code more compliant with developer guidelines
// note: - for implementing PHP constant arguments look at
// note: the pathinfo() function, it offers the greatest
// note: flexibility & compatibility possible
// example 1: round(1241757, -3);
// returns 1: 1242000
// example 2: round(3.6);
// returns 2: 4
// example 3: round(2.835, 2);
// returns 3: 2.84
// example 4: round(1.1749999999999, 2);
// returns 4: 1.17
// example 5: round(58551.799999999996, 2);
// returns 5: 58551.8

var m, f, isHalf, sgn; // helper variables
precision |= 0; // making sure precision is integer
m = Math.pow(10, precision);
value *= m;
sgn = (value > 0) | -(value < 0); // sign of the number
isHalf = value % 1 === 0.5 * sgn;
f = Math.floor(value);

if (isHalf) {
switch (mode) {
case 'PHP_ROUND_HALF_DOWN':
value = f + (sgn < 0); // rounds .5 toward zero
break;
case 'PHP_ROUND_HALF_EVEN':
value = f + (f % 2 * sgn); // rouds .5 towards the next even integer
break;
case 'PHP_ROUND_HALF_ODD':
value = f + !(f % 2); // rounds .5 towards the next odd integer
break;
default:
value = f + (sgn > 0); // rounds .5 away from zero
}
}

return (isHalf ? value : Math.round(value)) / m;
};

return Twig;

})(Twig || { });
Expand Down Expand Up @@ -4521,6 +4575,28 @@ var Twig = (function (Twig) {
raw: function(value) {
//Raw filter shim
return value;
},
round: function(value, params) {
params = params || [];

var precision = params.length > 0 ? params[0] : 0,
method = params.length > 1 ? params[1] : "common";

value = parseFloat(value);

if(precision && !Twig.lib.is("Number", precision)) {
throw new Twig.Error("round filter expects precision to be a number");
}

if (method === "common") {
return Twig.lib.round(value, precision);
}

if(!Twig.lib.is("Function", Math[method])) {
throw new Twig.Error("round filter expects method to be 'floor', 'ceil', or 'common'");
}

return Math[method](value * Math.pow(10, precision)) / Math.pow(10, precision);
}
};

Expand Down
6 changes: 3 additions & 3 deletions twig.min.js

Large diffs are not rendered by default.

0 comments on commit 667ad0c

Please sign in to comment.