Skip to content

Commit

Permalink
Refactored StringBuilder to use a List<String> as a buffer and use
Browse files Browse the repository at this point in the history
String.join() to build the result string more efficiently than string
concatenation.

Introduced new method setDelimiter on CommaDelimitedListBuilder
to support a custom delimiter when building a string. The delimiter
defaults to a comma but can be changed as required.
  • Loading branch information
alan-morey committed Apr 6, 2014
1 parent 27687aa commit ed6df6f
Show file tree
Hide file tree
Showing 2 changed files with 71 additions and 33 deletions.
41 changes: 26 additions & 15 deletions fflib/src/classes/fflib_StringBuilder.cls
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
**/
public virtual with sharing class fflib_StringBuilder
{
protected String m_stringValue;
protected List<String> buffer = new List<String>();

/**
* Construct an empty StringBuilder
Expand All @@ -51,52 +51,64 @@ public virtual with sharing class fflib_StringBuilder
**/
public virtual void add(List<String> values)
{
for(String value : values)
add(value);
buffer.addAll(values);
}

/**
* Add the given value to the StringBuilder
**/
public virtual void add(String value)
{
m_stringValue = ( m_stringValue==null ? value : m_stringValue + value );
buffer.add(value);
}

public virtual override String toString()
{
return String.join(buffer, '');
}

/**
* Return the state of the StringBuilder
**/
public virtual String getStringValue()
{
return m_stringValue;
return toString();
}


/**
* Subclasses the StringBuilder to produce a comma delimited contactination of strings
**/
public virtual with sharing class CommaDelimitedListBuilder extends fflib_StringBuilder
{
String itemPrefix = '';
String delimiter = ',';

public CommaDelimitedListBuilder() {}

public CommaDelimitedListBuilder(List<String> values)
{
super(values);
}

public virtual override void add(String value)
public void setItemPrefix(String itemPrefix)
{
m_stringValue = ( m_stringValue==null ? '{0}' + value : m_stringValue + ',{0}' + value );
this.itemPrefix = itemPrefix;
}

public override String getStringValue()
public void setDelimiter(String delimiter)
{
return getStringValue('');
this.delimiter = delimiter;
}

public String getStringValue(String itemPrefix)
{
return m_stringValue==null ? null : String.format(m_stringValue,new List<String>{itemPrefix});
setItemPrefix(itemPrefix);
return toString();
}

public override String toString()
{
return itemPrefix + String.join(buffer, delimiter + itemPrefix);
}
}

Expand All @@ -113,14 +125,13 @@ public virtual with sharing class fflib_StringBuilder
public FieldListBuilder(List<Schema.SObjectField> values, List<Schema.Fieldset> fieldSets)
{
// Create a distinct set of fields (or field paths) to select
Set<String> selectFields = new Set<String>();
for(Schema.SObjectField value : values)
selectFields.add(value.getDescribe().getName());
add(String.valueOf(value)); // Alternative to value.getDescribe().getName()

if(fieldSets!=null)
for(Schema.Fieldset fieldSet : fieldSets)
for(Schema.FieldSetMember fieldSetMember : fieldSet.getFields())
selectFields.add(fieldSetMember.getFieldPath());
add(new List<String>(selectFields));
add(fieldSetMember.getFieldPath());
}
}

Expand Down
63 changes: 45 additions & 18 deletions fflib/src/classes/fflib_StringBuilderTest.cls
Original file line number Diff line number Diff line change
Expand Up @@ -27,40 +27,67 @@
@IsTest
private with sharing class fflib_StringBuilderTest
{
static testMethod void testfflib_StringBuilder1()
{
static testMethod void testfflib_StringBuilder1()
{
fflib_StringBuilder sb = new fflib_StringBuilder();
sb.add('this is a string');
sb.add(new List<String>{', which is made',' up from\r ','a number of smaller strings', '. 5 in this case!'});
system.assertEquals(sb.getStringValue(),'this is a string, which is made up from\r a number of smaller strings. 5 in this case!');
}
}

static testMethod void testfflib_StringBuilder2()
{
static testMethod void testfflib_StringBuilder2()
{
fflib_StringBuilder sb = new fflib_StringBuilder(new List<String>{'apples',' and ','pears',': stairs. '});
sb.add('this is a string');
sb.add(new List<String>{', which is made',' up from\r ','a number of smaller strings', '. 5 in this case!'});
system.assertEquals(sb.getStringValue(),'apples and pears: stairs. this is a string, which is made up from\r a number of smaller strings. 5 in this case!');
}
}

static testMethod void testCommaDelimitedBuilder1()
{
static testMethod void testCommaDelimitedBuilder1()
{
fflib_StringBuilder.CommaDelimitedListBuilder sb = new fflib_StringBuilder.CommaDelimitedListBuilder();
sb.add('a');
sb.add(new List<String>{'b','c','d'});
system.assertEquals(sb.getStringValue(),'a,b,c,d');
}
}

static testMethod void testCommaDelimitedBuilder2()
{
static testMethod void testCommaDelimitedBuilder2()
{
fflib_StringBuilder.CommaDelimitedListBuilder sb = new fflib_StringBuilder.CommaDelimitedListBuilder(new List<String>{'x','y'});
sb.add('a');
sb.add(new List<String>{'b','c','d'});
system.assertEquals(sb.getStringValue(),'x,y,a,b,c,d');
}
}

static testMethod void testCommanDelimitedBuilderWithItemPrefix()
{
fflib_StringBuilder.CommaDelimitedListBuilder sb = new fflib_StringBuilder.CommaDelimitedListBuilder(new List<String>{'x','y'});
sb.add('a');
sb.add(new List<String>{'b','c','d'});
system.assertEquals(sb.getStringValue('$'),'$x,$y,$a,$b,$c,$d');
}

static testMethod void testCommanDelimitedBuilderWithAlternativeDelimiter()
{
fflib_StringBuilder.CommaDelimitedListBuilder sb = new fflib_StringBuilder.CommaDelimitedListBuilder(new List<String>{'x','y'});
sb.setDelimiter(';');
sb.add('a');
sb.add(new List<String>{'b','c','d'});
system.assertEquals(sb.getStringValue(),'x;y;a;b;c;d');
}

static testMethod void testCommanDelimitedBuilderWithAlternativeDelimiterAndPrefix()
{
fflib_StringBuilder.CommaDelimitedListBuilder sb = new fflib_StringBuilder.CommaDelimitedListBuilder(new List<String>{'x','y'});
sb.setItemPrefix('#');
sb.setDelimiter(':');
sb.add('a');
sb.add(new List<String>{'b','c','d'});
system.assertEquals(sb.getStringValue(),'#x:#y:#a:#b:#c:#d');
}

static testMethod void testFieldListBuilder()
{
static testMethod void testFieldListBuilder()
{
List<Schema.SObjectField> fields = new List<Schema.SObjectField> { Account.Name, Account.Id, Account.AccountNumber, Account.AccountNumber, Account.AnnualRevenue };
fflib_StringBuilder.FieldListBuilder sb = new fflib_StringBuilder.FieldListBuilder(fields);
List<String> fieldList = sb.getStringValue().split(',');
Expand All @@ -70,10 +97,10 @@ private with sharing class fflib_StringBuilderTest
system.assert(fieldSet.contains('Id'));
system.assert(fieldSet.contains('AccountNumber'));
system.assert(fieldSet.contains('AnnualRevenue'));
}
}

static testMethod void testMultiCurrencyFieldListBuilder()
{
static testMethod void testMultiCurrencyFieldListBuilder()
{
List<Schema.SObjectField> fields = new List<Schema.SObjectField> { Account.Name, Account.Id, Account.AccountNumber, Account.AnnualRevenue };
fflib_StringBuilder.MultiCurrencyFieldListBuilder sb = new fflib_StringBuilder.MultiCurrencyFieldListBuilder(fields);
List<String> fieldList = sb.getStringValue().split(',');
Expand All @@ -84,5 +111,5 @@ private with sharing class fflib_StringBuilderTest
system.assert(fieldSet.contains('AnnualRevenue'));
if(UserInfo.isMultiCurrencyOrganization())
system.assert(fieldSet.contains('CurrencyIsoCode'));
}
}
}

0 comments on commit ed6df6f

Please sign in to comment.