Skip to content

Add Ability to Easily Extend string.js #57

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Sep 16, 2013
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -631,6 +631,16 @@ S("Hello").toString() === S("Hello").s; //true
```


### - setValue(value) ###

Sets the string to a `value`.

```javascript
var myString = S('War');
myString.setValue('Peace').s; // 'Peace'
```


### - slugify() ###

Converts the text into a valid url slug.
Expand Down Expand Up @@ -973,6 +983,7 @@ If you contribute to this library, just modify `string.js`, `string.test.js`, an
- [Sean O'Dell](https://github.com/seanodell)
- [Tim de Koning](https://github.com/Reggino)
- [David Volm](https://github.com/daxxog)
- [Jeff Grann](https://github.com/jeffgrann)
- `<your name here>`


Expand Down
127 changes: 81 additions & 46 deletions lib/string.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,31 +9,53 @@ string.js - Copyright (C) 2012-2013, JP Richardson <[email protected]>

var ENTITIES = {};

function S(s) {
//******************************************************************************
// Added an initialize function which is essentially the code from the S
// constructor. Now, the S constructor calls this and a new method named
// setValue calls it as well. The setValue function allows constructors for
// modules that extend string.js to set the initial value of an object without
// knowing the internal workings of string.js.
//
// Also, all methods which return a new S object now call:
//
// return new this.constructor(s);
//
// instead of:
//
// return new S(s);
//
// This allows extended objects to keep their proper instanceOf and constructor.
//******************************************************************************

function initialize (object, s) {
if (s !== null && s !== undefined) {
if (typeof s === 'string')
this.s = s;
object.s = s;
else
this.s = s.toString();
object.s = s.toString();
} else {
this.s = s; //null or undefined
object.s = s; //null or undefined
}

this.orig = s; //original object, currently only used by toCSV() and toBoolean()
object.orig = s; //original object, currently only used by toCSV() and toBoolean()

if (s !== null && s !== undefined) {
if (this.__defineGetter__) {
this.__defineGetter__('length', function() {
return this.s.length;
if (object.__defineGetter__) {
object.__defineGetter__('length', function() {
return object.s.length;
})
} else {
this.length = s.length;
object.length = s.length;
}
} else {
this.length = -1;
object.length = -1;
}
}

function S(s) {
initialize(this, s);
}

var __nsp = String.prototype;
var __sp = S.prototype = {

Expand All @@ -42,19 +64,19 @@ string.js - Copyright (C) 2012-2013, JP Richardson <[email protected]>
var startPos = s.indexOf(left);
var endPos = s.indexOf(right);
var start = startPos + left.length;
return new S(endPos > startPos ? s.slice(start, endPos) : "");
return new this.constructor(endPos > startPos ? s.slice(start, endPos) : "");
},

//# modified slightly from https://github.com/epeli/underscore.string
camelize: function() {
var s = this.trim().s.replace(/(\-|_|\s)+(.)?/g, function(mathc, sep, c) {
return (c ? c.toUpperCase() : '');
});
return new S(s);
return new this.constructor(s);
},

capitalize: function() {
return new S(this.s.substr(0, 1).toUpperCase() + this.s.substring(1).toLowerCase());
return new this.constructor(this.s.substr(0, 1).toUpperCase() + this.s.substring(1).toLowerCase());
},

charAt: function(index) {
Expand All @@ -65,7 +87,7 @@ string.js - Copyright (C) 2012-2013, JP Richardson <[email protected]>
var s = this.s;
if (s.indexOf(prefix) === 0) {
s = s.slice(prefix.length);
return new S(s);
return new this.constructor(s);
} else {
return this;
}
Expand All @@ -75,7 +97,7 @@ string.js - Copyright (C) 2012-2013, JP Richardson <[email protected]>
if (this.endsWith(suffix)) {
var s = this.s;
s = s.slice(0, s.length - suffix.length);
return new S(s);
return new this.constructor(s);
} else {
return this;
}
Expand All @@ -84,7 +106,7 @@ string.js - Copyright (C) 2012-2013, JP Richardson <[email protected]>
//#thanks Google
collapseWhitespace: function() {
var s = this.s.replace(/[\s\xa0]+/g, ' ').replace(/^\s+|\s+$/g, '');
return new S(s);
return new this.constructor(s);
},

contains: function(ss) {
Expand All @@ -106,7 +128,7 @@ string.js - Copyright (C) 2012-2013, JP Richardson <[email protected]>
//#modified from https://github.com/epeli/underscore.string
dasherize: function() {
var s = this.trim().s.replace(/[_\s]+/g, '-').replace(/([A-Z])/g, '-$1').replace(/-+/g, '-').toLowerCase();
return new S(s);
return new this.constructor(s);
},

decodeHtmlEntities: function() { //https://github.com/substack/node-ent/blob/master/index.js
Expand All @@ -132,7 +154,7 @@ string.js - Copyright (C) 2012-2013, JP Richardson <[email protected]>
}
})

return new S(s);
return new this.constructor(s);
},

endsWith: function(suffix) {
Expand All @@ -141,15 +163,15 @@ string.js - Copyright (C) 2012-2013, JP Richardson <[email protected]>
},

escapeHTML: function() { //from underscore.string
return new S(this.s.replace(/[&<>"']/g, function(m){ return '&' + reversedEscapeChars[m] + ';'; }));
return new this.constructor(this.s.replace(/[&<>"']/g, function(m){ return '&' + reversedEscapeChars[m] + ';'; }));
},

ensureLeft: function(prefix) {
var s = this.s;
if (s.indexOf(prefix) === 0) {
return this;
} else {
return new S(prefix + s);
return new this.constructor(prefix + s);
}
},

Expand All @@ -158,15 +180,15 @@ string.js - Copyright (C) 2012-2013, JP Richardson <[email protected]>
if (this.endsWith(suffix)) {
return this;
} else {
return new S(s + suffix);
return new this.constructor(s + suffix);
}
},

humanize: function() { //modified from underscore.string
if (this.s === null || this.s === undefined)
return new S('')
return new this.constructor('')
var s = this.underscore().replace(/_id$/,'').replace(/_/g, ' ').trim().capitalize()
return new S(s)
return new this.constructor(s)
},

isAlpha: function() {
Expand Down Expand Up @@ -196,7 +218,7 @@ string.js - Copyright (C) 2012-2013, JP Richardson <[email protected]>
left: function(N) {
if (N >= 0) {
var s = this.s.substr(0, N);
return new S(s);
return new this.constructor(s);
} else {
return this.right(-N);
}
Expand All @@ -208,23 +230,23 @@ string.js - Copyright (C) 2012-2013, JP Richardson <[email protected]>

pad: function(len, ch) { //https://github.com/component/pad
ch = ch || ' ';
if (this.s.length >= len) return new S(this.s);
if (this.s.length >= len) return new this.constructor(this.s);
len = len - this.s.length;
var left = Array(Math.ceil(len / 2) + 1).join(ch);
var right = Array(Math.floor(len / 2) + 1).join(ch);
return new S(left + this.s + right);
return new this.constructor(left + this.s + right);
},

padLeft: function(len, ch) { //https://github.com/component/pad
ch = ch || ' ';
if (this.s.length >= len) return new S(this.s);
return new S(Array(len - this.s.length + 1).join(ch) + this.s);
if (this.s.length >= len) return new this.constructor(this.s);
return new this.constructor(Array(len - this.s.length + 1).join(ch) + this.s);
},

padRight: function(len, ch) { //https://github.com/component/pad
ch = ch || ' ';
if (this.s.length >= len) return new S(this.s);
return new S(this.s + Array(len - this.s.length + 1).join(ch));
if (this.s.length >= len) return new this.constructor(this.s);
return new this.constructor(this.s + Array(len - this.s.length + 1).join(ch));
},

parseCSV: function(delimiter, qualifier, escape, lineDelimiter) { //try to parse no matter what
Expand Down Expand Up @@ -293,40 +315,45 @@ string.js - Copyright (C) 2012-2013, JP Richardson <[email protected]>
replaceAll: function(ss, r) {
//var s = this.s.replace(new RegExp(ss, 'g'), r);
var s = this.s.split(ss).join(r)
return new S(s);
return new this.constructor(s);
},

right: function(N) {
if (N >= 0) {
var s = this.s.substr(this.s.length - N, N);
return new S(s);
return new this.constructor(s);
} else {
return this.left(-N);
}
},

setValue: function (s) {
initialize(this, s);
return this;
},

slugify: function() {
var sl = (new S(this.s.replace(/[^\w\s-]/g, '').toLowerCase())).dasherize().s;
if (sl.charAt(0) === '-')
sl = sl.substr(1);
return new S(sl);
return new this.constructor(sl);
},

startsWith: function(prefix) {
return this.s.lastIndexOf(prefix, 0) === 0;
},

stripPunctuation: function() {
//return new S(this.s.replace(/[\.,-\/#!$%\^&\*;:{}=\-_`~()]/g,""));
return new S(this.s.replace(/[^\w\s]|_/g, "").replace(/\s+/g, " "));
//return new this.constructor(this.s.replace(/[\.,-\/#!$%\^&\*;:{}=\-_`~()]/g,""));
return new this.constructor(this.s.replace(/[^\w\s]|_/g, "").replace(/\s+/g, " "));
},

stripTags: function() { //from sugar.js
var s = this.s, args = arguments.length > 0 ? arguments : [''];
multiArgs(args, function(tag) {
s = s.replace(RegExp('<\/?' + tag + '[^<>]*>', 'gi'), '');
});
return new S(s);
return new this.constructor(s);
},

template: function(values, opening, closing) {
Expand All @@ -342,11 +369,11 @@ string.js - Copyright (C) 2012-2013, JP Richardson <[email protected]>
if (typeof values[key] != 'undefined')
s = s.replace(match, values[key]);
});
return new S(s);
return new this.constructor(s);
},

times: function(n) {
return new S(new Array(n + 1).join(this.s));
return new this.constructor(new Array(n + 1).join(this.s));
},

toBoolean: function() {
Expand Down Expand Up @@ -376,7 +403,7 @@ string.js - Copyright (C) 2012-2013, JP Richardson <[email protected]>
s = this.s.replace(/(^\s*|\s*$)/g, '')
else
s = this.s.trim()
return new S(s);
return new this.constructor(s);
},

trimLeft: function() {
Expand All @@ -385,7 +412,7 @@ string.js - Copyright (C) 2012-2013, JP Richardson <[email protected]>
s = this.s.trimLeft();
else
s = this.s.replace(/(^\s*)/g, '');
return new S(s);
return new this.constructor(s);
},

trimRight: function() {
Expand All @@ -394,7 +421,7 @@ string.js - Copyright (C) 2012-2013, JP Richardson <[email protected]>
s = this.s.trimRight();
else
s = this.s.replace(/\s+$/, '');
return new S(s);
return new this.constructor(s);
},

truncate: function(length, pruneStr) { //from underscore.string, author: github.com/rwz
Expand All @@ -403,7 +430,7 @@ string.js - Copyright (C) 2012-2013, JP Richardson <[email protected]>
length = ~~length;
pruneStr = pruneStr || '...';

if (str.length <= length) return new S(str);
if (str.length <= length) return new this.constructor(str);

var tmpl = function(c){ return c.toUpperCase() !== c.toLowerCase() ? 'A' : ' '; },
template = str.slice(0, length+1).replace(/.(?=\W*\w*$)/g, tmpl); // 'Hello, world' -> 'HellAA AAAAA'
Expand Down Expand Up @@ -478,7 +505,7 @@ string.js - Copyright (C) 2012-2013, JP Richardson <[email protected]>
//chop last delim
//console.log(buildString.length)
buildString.length = buildString.length - 1;
return new S(buildString.join(''));
return new this.constructor(buildString.join(''));
},

toString: function() {
Expand All @@ -491,11 +518,11 @@ string.js - Copyright (C) 2012-2013, JP Richardson <[email protected]>
if ((new S(this.s.charAt(0))).isUpper()) {
s = '_' + s;
}
return new S(s);
return new this.constructor(s);
},

unescapeHTML: function() { //from underscore.string
return new S(this.s.replace(/\&([^;]+);/g, function(entity, entityCode){
return new this.constructor(this.s.replace(/\&([^;]+);/g, function(entity, entityCode){
var match;

if (entityCode in escapeChars) {
Expand Down Expand Up @@ -553,7 +580,7 @@ string.js - Copyright (C) 2012-2013, JP Richardson <[email protected]>
if (nativeProperties[name] === 'string') {
__sp[name] = function() {
//console.log(name)
return new S(stringProp.apply(this, arguments));
return new this.constructor(stringProp.apply(this, arguments));
}
} else {
__sp[name] = stringProp;
Expand All @@ -575,6 +602,14 @@ string.js - Copyright (C) 2012-2013, JP Richardson <[email protected]>
__sp.decodeHTMLEntities = __sp.decodeHtmlEntities //ensure consistent casing scheme of 'HTML'


//******************************************************************************
// Set the constructor. Without this, string.js objects are instances of
// Object instead of S.
//******************************************************************************

__sp.constructor = S;


/*************************************
/* Private Functions
/*************************************/
Expand Down