├── .gitignore ├── .travis.yml ├── README.md ├── composer.json ├── phpunit.xml.dist ├── src └── RobClancy │ └── String │ ├── String.php │ └── helpers.php └── tests └── StringTest.php /.gitignore: -------------------------------------------------------------------------------- 1 | composer.lock 2 | vendor -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: php 2 | 3 | php: 4 | - 5.3 5 | - 5.4 6 | 7 | before_script: 8 | - curl -s http://getcomposer.org/installer | php 9 | - php composer.phar install 10 | 11 | script: phpunit -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # String 2 | 3 | A PHP library to manipulate strings via a string object similar to other languages. 4 | 5 | This library is designed as an alternative way to using PHP's inconsistant string functions without resorting to a simple wrapper. Basically a string object like you find in other languages. Also with a `str` function to make things a little shorter/easier and hide the longer `new String` when working with strings a lot. 6 | 7 | This library has 2 dependencies: [oodle/inflect](https://github.com/oodle/inflect) and [patchwork/utf8](https://github.com/nicolas-grekas/Patchwork-UTF8) 8 | 9 | ## Installation and Setup 10 | To install add the following to your `composer.json` file: 11 | 12 | ```json 13 | "robclancy/string": "dev-master" 14 | ``` 15 | 16 | Then you can use it out of the box directly with `RobClancy\String\String` or `str`. Alternatively create an alias like follows... 17 | 18 | Native: 19 | ```php 20 | class_alias('RobClancy\String\String', 'String'); 21 | ``` 22 | 23 | Laravel, add to your aliases array in `app/config/app.php`: 24 | ```php 25 | 'String' => 'RobClancy\String\String', 26 | ``` 27 | 28 | ## Examples Note: some of these aren't implemented yet, this package won't be ready for use until I write all the tests 29 | 30 | ### Class name to table name 31 | 32 | ```php 33 | class UserGroup { 34 | 35 | public function getTable() 36 | { 37 | // We might want to point to the plural, snake case version of this class 38 | $class = new String(__CLASS__); 39 | 40 | // Snake case and split 41 | $words = $class->snake()->split('_'); 42 | 43 | // Pluralize last word 44 | // Note: at a later stage I might have an array object which will be used here to do $words->last()->plural(); 45 | $words[count($word)-1]->plural(); 46 | 47 | // Now return it joined back up 48 | return String::join($words, '_'); 49 | } 50 | } 51 | ``` 52 | 53 | ### Ruby styled string replace and python styled slicing 54 | 55 | ```php 56 | 57 | $string = new String('Jason made Basset, it is pretty cool I hear, vote 1 Jason!!'); 58 | 59 | // String replace, the same as doing the key as $search and the value as $replace in $string->replace($search, $value) 60 | $string['Jason'] = 'Jason Lewis'; 61 | $string['Basset'] = 'Basset (Better Asset Management)'; 62 | 63 | // We now want to change the 1 into 9001 but because the array notation here is overloaded to do python style slicing 64 | // and ruby style replacing we need to force it to the replace, we do this simply by starting the replace with 'r|' 65 | $string['r|1'] = 9001; 66 | 67 | // Lastly let's clean it up and make it end with a single ! 68 | $string->finish('!'); 69 | // or 70 | $string['!!'] = '!'; 71 | // or 72 | $string->slice(0, -1); 73 | // or the same as above with python syntax. 74 | $string = $string[':-1']; 75 | 76 | echo $string; 77 | // Outputs: "Jason Lewis made Basset (Better Asset Management), it is pretty cool I hear, vote 9001 Jason Lewis!" 78 | 79 | // Just another example of slicing with python 80 | $string = new String('I like pizza :D'); 81 | $pizza = $string['7:-3']; 82 | echo $pizza; // pizza 83 | 84 | ``` 85 | 86 | ### Basic and quick validation with exceptions 87 | 88 | ```php 89 | 90 | $string = 'Love for laravel <3'; 91 | $string->startsWith('Love'); // true 92 | $string->contains('something'); // false 93 | $string->endsWith('<3'); // true 94 | $string->is('No love for laravel'); // obviously returns false! 95 | 96 | // Now to show with and without exceptions 97 | $string = new String('not_an_email'); 98 | $string->isEmail(); // This will return false 99 | 100 | $string->useExceptions(true); 101 | $string->isEmail(); // This will now throw an exception 102 | 103 | // But calling that method is too verbose, so you can use a shortcut on string creation by passing true as the second argument 104 | $string = new String('still not an email', true); 105 | 106 | // Now any check will throw an exception so you can do quick checking and chain it like the following 107 | try 108 | { 109 | // String must be an email to do with gmail and contain the word awesome 110 | $string->isEmail()->endsWith('@gmail.com')->contains('awesome'); 111 | } 112 | catch (StringException $e) // TODO: change this to whatever I call the exceptions 113 | { 114 | // failed 115 | } 116 | 117 | // Also you can globally set the exceptions flag to be used if one is not specified, defaults to false 118 | String::throwExceptions(true); 119 | ``` 120 | 121 | ### Iteration 122 | 123 | ```php 124 | 125 | $string = new String('It\'s Saturday, I shouldn\'t be working on this and drinking or something'); 126 | 127 | // You can loop over the string chracter by character 128 | // Let's make the first letter of each word a capital just 'cause 129 | $previousSpace = false; 130 | foreach ($string AS $offset => $char) 131 | { 132 | if ($char->is(' ')) 133 | { 134 | $previousSpace = true; 135 | continue; 136 | } 137 | 138 | if ($previousSpace) 139 | { 140 | $string[$offset] = $char->upper(); 141 | } 142 | 143 | $previousSpace = false; 144 | } 145 | 146 | echo $string; // It\'s Saturday, I Shouldn\'t Be Working On This And Drinking Or Something 147 | 148 | // We can do your usual splits, however in this case it splits into String objects like you would expect 149 | $words = $string->split(' '); // normal array 150 | 151 | // Now let's do the same change as above but instead on each word, easier this time 152 | foreach ($words AS $key => $word) 153 | { 154 | $words[$key] = $word->upperFirst(); 155 | } 156 | 157 | // Basically an alias for implode here 158 | $string = String::join($words, ' '); 159 | echo $string; // It\'s Saturday, I Shouldn\'t Be Working On This And Drinking Or Something 160 | ``` 161 | 162 | 163 | [![Build Status](https://secure.travis-ci.org/robclancy/string.png)](http://travis-ci.org/robclancy/string) 164 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "robclancy/string", 3 | "description": "A PHP library to manipulate strings via a string object similar to other languages", 4 | "authors": [ 5 | { 6 | "name": "Robbo", 7 | "email": "robert@mercenarydesign.net" 8 | } 9 | ], 10 | "require": { 11 | "php": ">=5.3.0", 12 | "oodle/inflect": "*", 13 | "patchwork/utf8": "1.0.*" 14 | }, 15 | "require-dev": { 16 | "phpunit/php-code-coverage": "1.2.*@dev" 17 | }, 18 | "autoload": { 19 | "psr-0": { 20 | "RobClancy\\String": "src/" 21 | }, 22 | "files": [ 23 | "src/RobClancy/String/helpers.php" 24 | ] 25 | }, 26 | "minimum-stability": "dev" 27 | } -------------------------------------------------------------------------------- /phpunit.xml.dist: -------------------------------------------------------------------------------- 1 | 2 | 13 | 14 | 15 | ./tests/ 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/RobClancy/String/String.php: -------------------------------------------------------------------------------- 1 | useExceptions($exceptions); 24 | 25 | $this->string = $string; 26 | } 27 | 28 | public static function defaultUseExceptions($exceptions) 29 | { 30 | self::$defaultUseExceptions = $exceptions; 31 | } 32 | 33 | public function useExceptions($exceptions) 34 | { 35 | $this->useExceptions = is_null($exceptions) ? self::$defaultUseExceptions : $exceptions; 36 | } 37 | 38 | public function append($string) 39 | { 40 | $this->string .= $string; 41 | 42 | return $this; 43 | } 44 | 45 | public function prepend($string) 46 | { 47 | $this->string = $string.$this->string; 48 | 49 | return $this; 50 | } 51 | 52 | /** 53 | * Transliterate to ASCII. 54 | * 55 | * @param string $value 56 | * @return RobClancy\String\String 57 | */ 58 | public function ascii() 59 | { 60 | $this->string = u::toAscii($this->string); 61 | 62 | return $this; 63 | } 64 | 65 | public function length() 66 | { 67 | return u::strlen($this->string); 68 | } 69 | 70 | public function count() 71 | { 72 | return $this->length(); 73 | } 74 | 75 | public function lower() 76 | { 77 | $this->string = u::strtolower($this->string); 78 | 79 | return $this; 80 | } 81 | 82 | public function upper() 83 | { 84 | $this->string = u::strtoupper($this->string); 85 | 86 | return $this; 87 | } 88 | 89 | public function lowerFirst() 90 | { 91 | $this->string = u::lcfirst($this->string); 92 | 93 | return $this; 94 | } 95 | 96 | public function upperFirst() 97 | { 98 | $this->string = u::ucfirst($this->string); 99 | 100 | return $this; 101 | } 102 | 103 | public function plural() 104 | { 105 | $this->string = Inflect::pluralize($this->string); 106 | 107 | return $this; 108 | } 109 | 110 | public function singular() 111 | { 112 | $this->string = Inflect::singularize($this->string); 113 | 114 | return $this; 115 | } 116 | 117 | public function slug($delimiter = '-') 118 | { 119 | $this->string = trim(Inflect::urlify($this->string, $delimiter), $delimiter); 120 | 121 | return $this; 122 | } 123 | 124 | public function upperWords() 125 | { 126 | $this->string = u::ucwords($this->string); 127 | 128 | return $this; 129 | } 130 | 131 | public function isLower() 132 | { 133 | return ctype_lower($this->string); 134 | } 135 | 136 | public function isUpper() 137 | { 138 | return ctype_upper($this->string); 139 | } 140 | 141 | public function studly() 142 | { 143 | return $this->replace(array('_', '-'), ' ')->upperWords()->replace(' ', ''); 144 | } 145 | 146 | public function camel() 147 | { 148 | return $this->studly()->lowerFirst(); 149 | } 150 | 151 | public function snake($delimiter = '_') 152 | { 153 | if ($this->isLower()) return $this; 154 | 155 | $this->string = preg_replace('/(.)([A-Z])/', '$1'.$delimiter.'$2', $this->string); 156 | 157 | return $this->lower(); 158 | } 159 | 160 | public function limit($limit, $end = '...') 161 | { 162 | if ($this->length() <= $limit) return $this; 163 | 164 | return $this->part(0, $limit)->append($end); 165 | } 166 | 167 | public function part($start, $length = null) 168 | { 169 | $this->string = u::substr($this->string, $start, $length); 170 | 171 | return $this; 172 | } 173 | 174 | public function position($needle, $offset = 0, $reverse = false) 175 | { 176 | $func = $reverse ? 'strrpos' : 'strpos'; 177 | 178 | return u::$func($this->string, $needle, $offset); 179 | } 180 | 181 | public function contains($needle) 182 | { 183 | foreach ((array) $needle AS $n) 184 | { 185 | if ($this->position($n) !== false) return $this->returnOrThrow(); 186 | } 187 | 188 | return $this->returnOrThrow('The string doesn\'t contain one of the provided needles'); 189 | } 190 | 191 | public function startsWith($needle) 192 | { 193 | foreach ((array) $needle AS $n) 194 | { 195 | if ($this->position($n) === 0) return $this->returnOrThrow(); 196 | } 197 | 198 | return $this->returnOrThrow('The string doesn\'t start with one of the provided needles'); 199 | } 200 | 201 | public function endsWith($needle) 202 | { 203 | foreach ((array) $needle AS $n) 204 | { 205 | $string = new static($n); 206 | if ($n == $string->part($this->length() - $string->length())) 207 | { 208 | return $this->returnOrThrow(); 209 | } 210 | } 211 | 212 | return $this->returnOrThrow('The string doesn\'t end with one of the provided needles'); 213 | } 214 | 215 | public function is($string) 216 | { 217 | if (u::strcmp($this->string, $string)) 218 | { 219 | return $this->returnOrThrow(); 220 | } 221 | 222 | return $this->returnOrThrow('The string doesn\'t match'); 223 | } 224 | 225 | // TODO: below here needs to be redone like the above 226 | 227 | public function matches($pattern) 228 | { 229 | return (bool) preg_match('#^'.$pattern.'#', $this->string); 230 | } 231 | 232 | public function replace($search, $replace, $count = null) 233 | { 234 | $this->string = str_replace($search, $replace, $this->string, $count); 235 | 236 | return $this; 237 | } 238 | 239 | public function extension() 240 | { 241 | $string = clone $this; 242 | if ($pos = $string->position('.', 0, true) === false) 243 | { 244 | return false; 245 | } 246 | 247 | return $string->lower()->part($pos); 248 | } 249 | 250 | public function finish($cap) 251 | { 252 | $this->string = rtrim($this->string, $cap).$cap; 253 | 254 | return $this; 255 | } 256 | 257 | public function split($delimiter, $limit = null) 258 | { 259 | return static::createStrings(explode($delimiter, $this->string, $limit)); 260 | } 261 | 262 | public function getIterator() 263 | { 264 | return new ArrayIterator(static::createStrings(preg_split('#(?string)); 265 | } 266 | 267 | public function offsetGet($offset) 268 | { 269 | $string = clone $this; 270 | 271 | return $string->part($offset, 1); 272 | } 273 | 274 | public function offsetSet($offset, $value) 275 | { 276 | if ($this->length() < $offset) return; 277 | 278 | $string = clone $this; 279 | $start = $string->part(0, $offset); 280 | 281 | $string = clone $this; 282 | $end = $string->part($offset+1); 283 | 284 | $this->string = $start.$value.$end; 285 | 286 | return $this; 287 | } 288 | 289 | public function offsetUnset($offset) 290 | { 291 | $this->offsetSet($offset, ''); 292 | 293 | return $this; 294 | } 295 | 296 | public function offsetExists($offset) 297 | { 298 | return $this->length() >= $offset; 299 | } 300 | 301 | public function isNumeric() 302 | { 303 | return is_numeric($this->string); 304 | } 305 | 306 | public function isIp() 307 | { 308 | return filter_var($this->string, FILTER_VALIDATE_IP) !== false; 309 | } 310 | 311 | public function isEmail() 312 | { 313 | return filter_var($this->string, FILTER_VALIDATE_EMAIL) !== false; 314 | } 315 | 316 | public function isUrl() 317 | { 318 | return filter_var($this->string, FILTER_VALIDATE_URL) !== false; 319 | } 320 | 321 | protected function returnOrThrow($message = false) 322 | { 323 | // TODO: use a custom exception 324 | 325 | if ($message) 326 | { 327 | if ($this->useExceptions) throw new \ErrorException($message); 328 | 329 | return false; 330 | } 331 | 332 | return $this->useExceptions ? $this : true; 333 | } 334 | 335 | public static function join(array $strings, $delimiter) 336 | { 337 | return new static(implode($delimiter, $strings)); 338 | } 339 | 340 | public static function createStrings(array $strings) 341 | { 342 | foreach ($strings AS &$string) 343 | { 344 | $string = new static($string); 345 | } 346 | 347 | return $strings; 348 | } 349 | 350 | /** 351 | * Generate a more truly "random" alpha-numeric string. 352 | * 353 | * @param int $length 354 | * @return string 355 | */ 356 | public static function random($length = 16) 357 | { 358 | if (function_exists('openssl_random_pseudo_bytes')) 359 | { 360 | $bytes = openssl_random_pseudo_bytes($length * 2); 361 | 362 | if ($bytes === false) 363 | { 364 | throw new \RuntimeException('Unable to generate random string.'); 365 | } 366 | 367 | return substr(str_replace(array('/', '+', '='), '', base64_encode($bytes)), 0, $length); 368 | } 369 | 370 | return static::quickRandom($length); 371 | } 372 | 373 | /** 374 | * Generate a "random" alpha-numeric string. 375 | * 376 | * Should not be considered sufficient for cryptography, etc. 377 | * 378 | * @param int $length 379 | * @return string 380 | */ 381 | public static function quickRandom($length = 16) 382 | { 383 | $pool = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; 384 | 385 | return substr(str_shuffle(str_repeat($pool, 5)), 0, $length); 386 | } 387 | 388 | public function __toString() 389 | { 390 | return $this->string; 391 | } 392 | } -------------------------------------------------------------------------------- /src/RobClancy/String/helpers.php: -------------------------------------------------------------------------------- 1 | true, 11 | "\xC3\xB1" => true, 12 | "\xC3\x28" => false, 13 | "\xA0\xA1" => false, 14 | "\xE2\x82\xA1" => true, 15 | "\xE2\x28\xA1" => false, 16 | "\xE2\x82\x28" => false, 17 | "\xF0\x90\x8C\xBC" => true, 18 | "\xF0\x28\x8C\xBC" => false, 19 | "\xF0\x90\x28\xBC" => false, 20 | "\xF0\x28\x8C\x28" => false, 21 | "\xF8\xA1\xA1\xA1\xA1" => false, 22 | "\xFC\xA1\xA1\xA1\xA1\xA1" => false, 23 | ); 24 | 25 | public function testAppendString() 26 | { 27 | $this->assertEquals('string appended', $this->s('string')->append(' appended')); 28 | } 29 | 30 | public function testPrependString() 31 | { 32 | $this->assertEquals('prepended string', $this->s('string')->prepend('prepended ')); 33 | } 34 | 35 | public function testToASCII() 36 | { 37 | $this->assertEquals('', $this->s('')->ascii()); 38 | $this->assertEquals('deja vu', $this->s('déjà vu')->ascii()); 39 | } 40 | 41 | public function testStringLength() 42 | { 43 | foreach (self::$utf8ValidityMap as $u => $t) 44 | { 45 | if ($t) $this->assertEquals(1, $this->s($u)->length()); 46 | } 47 | 48 | $c = 'déjà'; 49 | $d = n::normalize($c, n::NFD); 50 | $this->assertTrue($c > $d); 51 | 52 | $this->assertEquals(4, $this->s($c)->length()); 53 | $this->assertEquals(4, $this->s($d)->length()); 54 | 55 | $this->assertEquals(3, $this->s(n::normalize('한국어', n::NFD))->length()); 56 | } 57 | 58 | public function testCountString() 59 | { 60 | $this->assertSame(4, count($this->s('déjà'))); 61 | } 62 | 63 | public function testStringUpperAndLower() 64 | { 65 | $this->assertEquals('déjà σσς', $this->s('DÉJÀ Σσς')->lower()); 66 | $this->assertEquals('DÉJÀ ΣΣΣ', $this->s('Déjà Σσς')->upper()); 67 | } 68 | 69 | public function testFirstUpperAndLower() 70 | { 71 | $this->assertEquals('éJÀ Σσς', $this->s('ÉJÀ Σσς')->lowerFirst()); 72 | $this->assertEquals('Éjà Σσς', $this->s('éjà Σσς')->upperFirst()); 73 | } 74 | 75 | public function testSingles() 76 | { 77 | $inflections = array( 78 | 'ox' => 'ox', 79 | 'cats' => 'cat', 80 | 'oxen' => 'ox', 81 | 'cats' => 'cat', 82 | 'purses' => 'purse', 83 | 'analyses' => 'analysis', 84 | 'houses' => 'house', 85 | 'sheep' => 'sheep', 86 | 'buses' => 'bus', 87 | 'uses' => 'use', 88 | 'databases' => 'database', 89 | 'quizzes' => 'quiz', 90 | 'matrices' => 'matrix', 91 | 'vertices' => 'vertex', 92 | 'alias' => 'alias', 93 | 'aliases' => 'alias', 94 | 'octopi' => 'octopus', 95 | 'axes' => 'axis', 96 | 'axis' => 'axis', 97 | 'crises' => 'crisis', 98 | 'crisis' => 'crisis', 99 | 'shoes' => 'shoe', 100 | 'foes' => 'foe', 101 | 'pianos' => 'piano', 102 | 'wierdos' => 'wierdo', 103 | 'toes' => 'toe', 104 | 'banjoes' => 'banjo', 105 | 'vetoes' => 'veto', 106 | ); 107 | 108 | foreach ($inflections as $key => $value) 109 | { 110 | $this->assertEquals($value, $this->s($key)->singular()); 111 | } 112 | } 113 | 114 | public function testPlurals() 115 | { 116 | $inflections = array( 117 | 'oxen' => 'ox', 118 | 'cats' => 'cat', 119 | 'cats' => 'cat', 120 | 'purses' => 'purse', 121 | 'analyses' => 'analysis', 122 | 'houses' => 'house', 123 | 'sheep' => 'sheep', 124 | 'buses' => 'bus', 125 | 'axes' => 'axis', 126 | 'uses' => 'use', 127 | 'databases' => 'database', 128 | 'quizzes' => 'quiz', 129 | 'matrices' => 'matrix', 130 | 'vertices' => 'vertex', 131 | 'aliases' => 'aliases', 132 | 'aliases' => 'alias', 133 | 'octopi' => 'octopus', 134 | 'axes' => 'axis', 135 | 'crises' => 'crisis', 136 | 'crises' => 'crises', 137 | 'shoes' => 'shoe', 138 | 'foes' => 'foe', 139 | 'pianos' => 'piano', 140 | 'wierdos' => 'wierdo', 141 | 'toes' => 'toe', 142 | 'banjos' => 'banjo', 143 | 'vetoes' => 'veto', 144 | ); 145 | 146 | foreach ($inflections as $key => $value) 147 | { 148 | $this->assertEquals($key, $this->s($value)->plural()); 149 | } 150 | } 151 | 152 | public function testSlug() 153 | { 154 | $urltests = array( 155 | "This Test's Apostrophe" => 'this-tests-apostrophe', 156 | "@#$%@##^@ @#%@#$%@#$%@#$%@#$%" => '-', 157 | "" => '-', 158 | "_+0990-0&*(&*(*)(&&*)(&*)(32@#%" => '-0990-0-and-32-', 159 | // FIXME: I can't get these working for some reason, to do with file encoding i think 160 | /*"ò" => 'o', 161 | "ó" => 'o', 162 | "ô" => 'o', 163 | "õ" => 'o', 164 | "ö" => 'o', 165 | "ø" => 'o', 166 | "ù" => 'u', 167 | "ú" => 'u', 168 | "û" => 'u', 169 | "ü" => 'u', 170 | "ý" => 'y', 171 | "ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõöøùúûüýþÿ" => strtolower("AAAAAAAECEEEEIIIIETHNOOOOOOUUUUYTHORNszaaaaaaaeceeeeiiiiethnoooooouuuuythorny")*/ 172 | ); 173 | 174 | foreach ($urltests as $key => $value) 175 | { 176 | $this->assertEquals($value, $this->s($key)->slug()); 177 | $this->assertEquals(str_replace('-', '+', $value), $this->s($key)->slug('+')); 178 | } 179 | } 180 | 181 | public function testStringStudly() 182 | { 183 | $this->assertEquals('FooBar', $this->s('foo_bar')->studly()); 184 | $this->assertEquals('FooBarBaz', $this->s('foo-bar_baz')->studly()); 185 | } 186 | 187 | public function testStringCamel() 188 | { 189 | $this->assertEquals('fooBar', $this->s('foo_bar')->camel()); 190 | $this->assertEquals('fooBarBaz', $this->s('foo-bar_baz')->camel()); 191 | } 192 | 193 | public function testStringSnake() 194 | { 195 | $this->assertEquals('foo_bar', $this->s('fooBar')->snake()); 196 | $this->assertEquals('foo-bar', $this->s('FooBar')->snake('-')); 197 | } 198 | 199 | public function testStringLimited() 200 | { 201 | $this->assertEquals('Ro...', $this->s('Robbo')->limit(2)); 202 | $this->assertEquals('Robbo', $this->s('Robbo')->limit(5)); 203 | $this->assertEquals('Rob___', $this->s('Robbo')->limit(3, '___')); 204 | } 205 | 206 | public function testStringPart() 207 | { 208 | $this->assertEquals('Test substring', $this->s('Test substring subness')->part(0, 14)); 209 | } 210 | 211 | public function testStringPosition() 212 | { 213 | $this->assertEquals(0, $this->s('Robbo')->position('R')); 214 | $this->assertEquals(1, $this->s('Robbo')->position('o')); 215 | $this->assertEquals(4, $this->s('Robbo')->position('o', 2)); 216 | $this->assertEquals(4, $this->s('Robbo')->position('o', 0, true)); 217 | $this->assertEquals(5, $this->s('DÉJÀ Σσς')->position('Σ')); 218 | } 219 | 220 | protected function s($string) 221 | { 222 | return new String($string); 223 | } 224 | } 225 | 226 | /*public function testStringLengthCorrect() 227 | { 228 | $this->assertEquals(5, $this->str('Robbo')->length()); 229 | $this->assertEquals(5, $this->str('ラドクリフ')->length()); 230 | } 231 | 232 | public function testStringToLower() 233 | { 234 | $this->assertEquals('robbo', (string)$this->str('RoBbo')->lower()); 235 | $this->assertEquals('άχιστη', (string)$this->str('ΆΧΙΣΤΗ')->lower()); 236 | } 237 | 238 | public function testStringToUpper() 239 | { 240 | $this->assertEquals('ROBBO', (string)$this->str('RoBbo')->upper()); 241 | $this->assertEquals('ΆΧΙΣΤΗ', (string)$this->str('άχιστη')->upper()); 242 | } 243 | 244 | public function testStringToLowerFirst() 245 | { 246 | $this->assertEquals('roBbo', (string)$this->str('RoBbo')->lowerFirst()); 247 | $this->assertEquals('άΧΙΣΤΗ', (string)$this->str('ΆΧΙΣΤΗ')->lowerFirst()); 248 | } 249 | 250 | public function testStringToUpperFirst() 251 | { 252 | $this->assertEquals('RoBbo', (string)$this->str('roBbo')->upperFirst()); 253 | $this->assertEquals('ΆΧισΤη', (string)$this->str('άΧισΤη')->upperFirst()); 254 | } 255 | 256 | protected function str($string) 257 | { 258 | return new String($string); 259 | } 260 | } 261 | 262 | /* old tests, need to keep bringing them in 263 | 264 | 265 | 266 | public function testStringCanBeLimitedByCharacters() 267 | { 268 | $this->assertEquals('Tay...', $this->string->limit('Taylor', 3)); 269 | $this->assertEquals('Taylor', $this->string->limit('Taylor', 6)); 270 | $this->assertEquals('Tay___', $this->string->limit('Taylor', 3, '___')); 271 | } 272 | 273 | public function testStringCanBeLimitedByCharactersIncludingElipses() 274 | { 275 | $this->assertEquals('T...', $this->string->limitExact('Taylor', 4)); 276 | $this->assertEquals('Taylor', $this->string->limitExact('Taylor', 6)); 277 | $this->assertEquals('Ta___', $this->string->limitExact('Taylor', 5, '___')); 278 | } 279 | 280 | public function testStringCanBeLimitedByWords() 281 | { 282 | $this->assertEquals('Taylor...', $this->string->limitWords('Taylor Otwell', 1)); 283 | $this->assertEquals('Taylor___', $this->string->limitWords('Taylor Otwell', 1, '___')); 284 | $this->assertEquals('Taylor Otwell', $this->string->limitWords('Taylor Otwell', 3)); 285 | } 286 | 287 | public function testStringCanBeWordWrapped() 288 | { 289 | $this->assertEquals('Robbo likes beer', $this->string->wordWrap('Robbo likes beer', 10)); 290 | $this->assertEquals('Robbolikes beer', $this->string->wordWrap('Robbolikesbeer', 10)); 291 | $this->assertEquals('Robbo likes beere speci allyw henit is hot!', $this->string->wordWrap('Robbolikesbeerespeciallywhenitis hot!', 5)); 292 | } 293 | 294 | public function testStringsExtension() 295 | { 296 | $this->assertEquals('', $this->string->extension('My nEw post!!!')); 297 | $this->assertEquals('jpg', $this->string->extension('An img name To convert.jpg')); 298 | $this->assertEquals('blah', $this->string->extension('.An imgname.To-convert.blah')); 299 | } 300 | 301 | public function testStringsCanBeSlugged() 302 | { 303 | $this->assertEquals('my-new-post', $this->string->slug('My nEw post!!!')); 304 | $this->assertEquals('my_new_post', $this->string->slug('My nEw post!!!', '_')); 305 | $this->assertEquals('my-new-post', $this->string->slug('my-new-post')); 306 | $this->assertEquals('an-img-name-to-convertjpg', $this->string->slug('An img name To convert.jpg')); 307 | $this->assertEquals('an-img-name-to-convert.jpg', $this->string->slug('An img name To convert.jpg', '-', true)); 308 | } 309 | 310 | public function testStringsCanBeConvertedToAscii() 311 | { 312 | $this->assertEquals('UzEJaPLae', $this->string->ascii('ŪžĒЯПĻæ')); 313 | } 314 | 315 | public function testStringsCanBeCamelCased() 316 | { 317 | $this->assertEquals('FooBar', $this->string->camelCase('foo_bar')); 318 | $this->assertEquals('FooBarBaz', $this->string->camelCase('foo-bar_baz')); 319 | $this->assertEquals('fooBar', $this->string->camelCase('foo_bar', false)); 320 | $this->assertEquals('fooBarBaz', $this->string->camelCase('foo-bar_baz', false)); 321 | } 322 | 323 | public function testStringCanBeSnakeCase() 324 | { 325 | $this->assertEquals('foo_bar', $this->string->snakeCase('fooBar')); 326 | $this->assertEquals('foo-bar', $this->string->snakeCase('fooBar', '-')); 327 | } 328 | 329 | public function testStringSegments() 330 | { 331 | $this->assertEquals($this->string->segments('a/path/of/words'), array( 332 | 'a', 'path', 'of', 'words' 333 | )); 334 | 335 | $this->assertEquals($this->string->segments('/a/path/of/words/'), array( 336 | 'a', 'path', 'of', 'words' 337 | )); 338 | } 339 | 340 | public function testRandomStringsCanBeGenerated() 341 | { 342 | $this->assertEquals(40, strlen($this->string->random(40))); 343 | } 344 | 345 | public function testStringStartsWith() 346 | { 347 | $this->assertTrue($this->string->startsWith('jason', 'jas')); 348 | $this->assertFalse($this->string->startsWith('jason', 'day')); 349 | } 350 | 351 | public function testStringEndsWith() 352 | { 353 | $this->assertTrue($this->string->endsWith('jason', 'on')); 354 | $this->assertFalse($this->string->endsWith('jason', 'no')); 355 | } 356 | 357 | public function testStringContains() 358 | { 359 | $this->assertTrue($this->string->contains('taylor', 'ylo')); 360 | $this->assertFalse($this->string->contains('taylor', 'xxx')); 361 | } 362 | 363 | public function testStringFinish() 364 | { 365 | $this->assertEquals('test string/', $this->string->finish('test string', '/')); 366 | $this->assertEquals('test stringBAM', $this->string->finish('test stringBAMBAM', 'BAM')); 367 | $this->assertEquals('test string/', $this->string->finish('test string/////', '/')); 368 | } 369 | }*/ --------------------------------------------------------------------------------