Skip to content

Commit

Permalink
feat(Collection): Add push, unshift, and splice methods
Browse files Browse the repository at this point in the history
* Add push, unshift and splice methods

* update to push and unshift methods

* Update docs for append, prepend, push, and unshift

Make notes about adding multiple items at once

* Add test coverage for adding multiple items

* Normalize append, prepend, push, and unshift

Have push and unshift be aliases to append and prepend.
  • Loading branch information
tonyjunkes authored and elpete committed Nov 30, 2017
1 parent cfbd4b3 commit e7c3efb
Show file tree
Hide file tree
Showing 3 changed files with 238 additions and 12 deletions.
58 changes: 49 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -753,22 +753,22 @@ var collection = new models.Collection();
collection.range( 4 );
// [ 0, 1, 2, 3 ]
collection.range( -4 );
// [ 0, -1, -2, -3 ]
collection.range( 1, 4 );
// [ 1, 2, 3, 4 ]
collection.range(0, 40, 10);
// [ 0, 10, 20, 30 ]
collection.range( 0, -4, -1 );
// [ 0, -1, -2, -3 ]
collection.range( 1, 4, 0 );
// [ 1, 1, 1 ]
collection.range( 0 );
// []
```
Expand Down Expand Up @@ -801,18 +801,21 @@ collect( [ 1, 2, 3, 4 ] )
```

### append
Adds an item to the end of the collection.
Adds one or more items to the end of the collection.
(Adding more than one item must be done as variadic parameters.)

```cfc
var collection = new models.Collection( [ 1, 2, 3 ] );
collection.append( 4 );
collection.append( 5, 6 );
writeDump( collection.toArray() );
// [ 1, 2, 3, 4 ]
// [ 1, 2, 3, 4, 5, 6 ]
```

### prepend
Adds an item to the beginning of the collection.
Adds one or more items to the beginning of the collection.
(Adding more than one item must be done as variadic parameters.)

```cfc
var collection = new models.Collection( [ 2, 3, 4 ] );
Expand All @@ -835,6 +838,18 @@ writeDump( collection.toArray() );
// [ "A", "B", "C" ]
```

### push
Add one or more items to the end of a collection.
(Alias for `append`)

```cfc
var collection = new models.Collection( [ 3, 2, 1 ] );
collection.push( "lift off!" );
writeDump( collection.get() );
// [ 3, 2, 1, "lift off!" ]
```

### shift
Removes an item from the beginning of the collection and return it.

Expand All @@ -848,6 +863,31 @@ writeDump( collection.toArray() );
// [ "B", "C", "D" ]
```

### unshift
Add one or more items to the beginning of a collection.
(Alias for `prepend`)

```cfc
var collection = new models.Collection( [ "kiwi", "orange", "banana" ] );
collection.unshift( "apple" );
writeDump( collection.get() );
// [ "apple", "kiwi", "orange", "banana" ]
```

### splice
Modifies the contents of a collection by removing existing items and/or adding new items. Returns an array containing the removed items.

```cfc
var collection = new models.Collection( [ "Aragorn", "Boromir", "Gimli", "Legolas" ] );
var result = collection.splice( 2, 1, "Gandalf" );
writeDump( result );
// [ "Boromir" ]
writeDump( collection.get() );
// [ "Aragorn", "Gandalf", "Gimli", "Legolas" ]
```

## Static Support

If your CFML engine supports static scopes and functions, you have some additional functionality available to you in the `MacroableCollection` component. This component will be returned by default if you are using WireBox.
Expand Down
61 changes: 58 additions & 3 deletions models/Collection.cfc
Original file line number Diff line number Diff line change
Expand Up @@ -268,16 +268,32 @@ component {
return this;
}

public Collection function append( required any item ) {
arrayAppend( variables.collection, item );
public Collection function append() {
if ( structCount( arguments ) ) {
for ( var value in arguments ) {
arrayAppend( variables.collection, arguments[ value ] );
}
}

return this;
}

public Collection function push() {
return this.append( argumentCollection = arguments );
}

public Collection function prepend( required any item ) {
arrayPrepend( variables.collection, item );
for ( var i = structCount( arguments ); i > 0; i-- ) {
arrayPrepend( variables.collection, arguments[ i ] );
}

return this;
}

public Collection function unshift() {
return this.prepend( argumentCollection = arguments );
}

/* Returns a Pipeline function */

public any function when( required boolean condition, required any callback, any defaultCallback ) {
Expand Down Expand Up @@ -451,6 +467,45 @@ component {
return result;
}

public array function splice( numeric start, numeric deleteCount ) {
var result = [];
var args = [];
var collection = this.get();
var length = this.length();
var index = ( start == 0 ) ? 1 : start;

if ( structCount( arguments ) > 2 ) {
args = keys( arguments ).reject( function( key ) {
return arrayFindNoCase( [ "start", "deleteCount" ], key );
} ).get();
}
if ( start > length ) {
index = length;
} else if ( sgn( start ) == -1 ) {
index = abs( start ) > length ? 1 : length + start + 1;
}
if ( isNull( deleteCount ) || deleteCount > length - start ) {
result = this.slice( index + 1 ).get();
collection = collect( collection ).slice( 1, length - index ).get();
for ( var item in args ) {
arrayAppend( collection, arguments[ item ] );
}
} else {
var position = deleteCount;
while ( position-- ) {
arrayAppend( result, collection[ index ] );
arrayDeleteAt( collection, index );
}
for ( var item in args ) {
arrayInsertAt( collection, index, arguments[ item ] );
index++;
}
}
variables.collection = collection;

return result;
}

/* Private Methods */

private Collection function clone() {
Expand Down
131 changes: 131 additions & 0 deletions tests/specs/non-static/CollectionSpec.cfc
Original file line number Diff line number Diff line change
Expand Up @@ -695,6 +695,8 @@ component extends="testbox.system.BaseSpec" {
expect( collection.range( -4, 0 ).get() ).toBe( [ -4, -3, -2, -1 ] );
expect( collection.range( 0 ).get() ).toBe( [] );
} );


} );

describe( "pipeline functions", function() {
Expand Down Expand Up @@ -1304,6 +1306,37 @@ component extends="testbox.system.BaseSpec" {

expect( collection.toArray() ).toBe( expected );
} );

it( "can add multiple items at once", function() {
var data = [ 1, 2, 3 ];
var expected = [ 1, 2, 3, 4, 5 ];

var collection = new models.Collection( data );
collection.append( 4, 5 );

expect( collection.toArray() ).toBe( expected );
} );
} );

describe( "push", function() {
it( "adds the arguments to the end of the collection", function() {
var data = [ 3, 2, 1 ];
var collection = new models.Collection( data );

collection.push( "lift off!" );

expect( collection.get() ).toBe( [ 3, 2, 1, "lift off!" ] );
} );

it( "can add multiple items at once", function() {
var data = [ 1, 2, 3 ];
var expected = [ 1, 2, 3, 4, 5 ];

var collection = new models.Collection( data );
collection.push( 4, 5 );

expect( collection.toArray() ).toBe( expected );
} );
} );

describe( "prepend", function() {
Expand All @@ -1316,6 +1349,37 @@ component extends="testbox.system.BaseSpec" {

expect( collection.toArray() ).toBe( expected );
} );

it( "can add multiple items at once", function() {
var data = [ 2, 3, 4 ];
var expected = [ 0, 1, 2, 3, 4 ];

var collection = new models.Collection( data );
collection.prepend( 0, 1 );

expect( collection.toArray() ).toBe( expected );
} );
} );

describe( "unshift", function() {
it( "adds the arguments to the beginning of the collection", function() {
var data = [ "kiwi", "orange", "banana" ];
var collection = new models.Collection( data );

collection.unshift( "apple" );

expect( collection.get() ).toBe( [ "apple", "kiwi", "orange", "banana" ] );
} );

it( "can add multiple items at once", function() {
var data = [ 2, 3, 4 ];
var expected = [ 0, 1, 2, 3, 4 ];

var collection = new models.Collection( data );
collection.unshift( 0, 1 );

expect( collection.toArray() ).toBe( expected );
} );
} );

describe( "pop", function() {
Expand Down Expand Up @@ -1345,6 +1409,73 @@ component extends="testbox.system.BaseSpec" {
expect( collection.toArray() ).toBe( expectedCollection );
} );
} );

describe( "splice", function() {
it( "insert items at a given index", function() {
var data = [ "Frodo", "Sam", "Merry", "Pippin" ];
var collection = new models.Collection( data );

var result = collection.splice( 2, 0, "Bilbo" );

expect( result ).toBe( [] );
expect( collection.get() ).toBe( [ "Frodo", "Bilbo", "Sam", "Merry", "Pippin" ] );
} );

it( "remove items at given index", function() {
var data = [ "Thorin", "Dwalin", "Balin", "Gloin" ];
var collection1 = new models.Collection( data );
var collection2 = new models.Collection( data );
var collection3 = new models.Collection( data );

var result1 = collection1.splice( 2, 1 );
var result2 = collection2.splice( -2, 1 );
var result3 = collection3.splice( -1, 1 );

expect( result1 ).toBe( [ "Dwalin" ] );
expect( collection1.get() ).toBe( [ "Thorin", "Balin", "Gloin" ] );

expect( result2 ).toBe( [ "Balin" ] );
expect( collection2.get() ).toBe( [ "Thorin", "Dwalin", "Gloin" ] );

expect( result3 ).toBe( [ "Gloin" ] );
expect( collection3.get() ).toBe( [ "Thorin", "Dwalin", "Balin" ] );
} );

it( "remove items and insert at given index", function() {
var data = [ "Aragorn", "Boromir", "Gimli", "Legolas" ];
var collection1 = new models.Collection( data );
var collection2 = new models.Collection( data );

var result1 = collection1.splice( 2, 1, "Gandalf" );
var result2 = collection2.splice( 0, 2, "Gandalf", "Elrond" );

expect( result1 ).toBe( [ "Boromir" ] );
expect( collection1.get() ).toBe( [ "Aragorn", "Gandalf", "Gimli", "Legolas" ] );

expect( result2 ).toBe( [ "Aragorn", "Boromir" ] );
expect( collection2.get() ).toBe( [ "Gandalf", "Elrond", "Gimli", "Legolas" ] );
} );

it( "remove items to the right of [start] when [count] is ommitted or greater than [length - start]", function() {
var data = [ "Hobbit", "Elf", "Dwarf", "Human" ];
var collection1 = new models.Collection( data );
var collection2 = new models.Collection( data );
var collection3 = new models.Collection( data );

var result1 = collection1.splice( 2 );
var result2 = collection2.splice( 2, 7 );
var result3 = collection3.splice( 2, 7, "Ent" );

expect( result1 ).toBe( [ "Dwarf", "Human" ] );
expect( collection1.get() ).toBe( [ "Hobbit", "Elf" ] );

expect( result2 ).toBe( [ "Dwarf", "Human" ] );
expect( collection2.get() ).toBe( [ "Hobbit", "Elf" ] );

expect( result3 ).toBe( [ "Dwarf", "Human" ] );
expect( collection3.get() ).toBe( [ "Hobbit", "Elf", "Ent" ] );
} );
} );
} );
}

Expand Down

0 comments on commit e7c3efb

Please sign in to comment.