Skip to content
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 <jprichardson@gmail.com>

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 <jprichardson@gmail.com>
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 <jprichardson@gmail.com>
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 <jprichardson@gmail.com>
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 <jprichardson@gmail.com>
//#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 <jprichardson@gmail.com>
//#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 <jprichardson@gmail.com>
}
})

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 <jprichardson@gmail.com>
},

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 <jprichardson@gmail.com>
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 <jprichardson@gmail.com>
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 <jprichardson@gmail.com>

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 <jprichardson@gmail.com>
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 <jprichardson@gmail.com>
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 <jprichardson@gmail.com>
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 <jprichardson@gmail.com>
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 <jprichardson@gmail.com>
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 <jprichardson@gmail.com>
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 <jprichardson@gmail.com>
//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 <jprichardson@gmail.com>
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 <jprichardson@gmail.com>
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 <jprichardson@gmail.com>
__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