= Standard Library Class Extension methods = The Cobra standard library adds the following extension methods to existing classes. This enables convenient expressions such as: {{{ #!cobra for item in someList.sorted.reversed print item for i, item in someList.sorted.numbered print i, item # i will be 0, 1, 2, ... }}} Here they are: {{{ #!cobra namespace Cobra.Core extend System.Object def typeOf as System.Type """ Return the Type of the object this is called on. Using .typeOf is portable between platforms in contrast to CLR .getType and JVM .getClass. """ def toTechString as String """ Generate a 'technical' string representation of the object suitable for inspection and debugging. Used for AssertExceptions (and subclasses such as RequireException) and the `trace` statement. It provides more information about collections and enumerations and recovers from exceptions when making strings so that debugging can proceed. """ def toPrintString as String """ Generate a string representation of the object suitable for printing. Strings are only quoted if they are inside collections such as a list or dictionary. """ extend String def before(sep as String) as String test s = 'abc|de' assert s.before('|') == 'abc' assert s.before('=') == 'abc|de' assert '|abcde'.before('|') == '' assert 'abcde|'.before('|') == 'abcde' def after(sep as String) as String test s = 'abc|de' assert s.after('|') == 'de' assert s.after('=') == '' assert '|abcde'.after('|') == 'abcde' assert 'abcde|'.after('|') == '' def capitalized as String """ Returns the string with the first character capitalized. Returns a blank string for a blank string. """ ensure result.length == .length result.length implies result[0] == result[0].toUpper test assert 'chuck'.capitalized == 'Chuck' assert 'Chuck'.capitalized == 'Chuck' assert ''.capitalized == '' assert ' foo'.capitalized == ' foo' assert 'f'.capitalized == 'F' assert '1aoeu'.capitalized == '1aoeu' def count(c as char) as int test assert ''.count(c'x')==0 assert 'x'.count(c'x')==1 assert 'X'.count(c'x')==0 # case sensitive assert ' ! ! '.count(c'!')==2 def count(substring as String) as int """ Return a count of the number of occurrences of the substring in this string. """ test assert ''.count('aoeu') == 0 assert 'x'.count('x') == 1 assert 'xyxy'.count('xy') == 2 assert 'xyxy'.count('a') == 0 def isCapitalized as bool test assert 'Aoeu'.isCapitalized assert 'Zaoeu'.isCapitalized assert not 'aoeu'.isCapitalized assert not ''.isCapitalized assert not '1234'.isCapitalized def limitLength(maxLength as int) as String return .limitLength(maxLength, nil) def limitLength(maxLength as int, suffix as String?) as String require suffix implies suffix.length < maxLength ensure result.length <= maxLength test assert ''.limitLength(2) == '' assert 'aoeu'.limitLength(2) == 'ao' assert 'aoeu aoeu aoeu aoeu aoeu'.limitLength(10, '...') == 'aoeu ao...' def md5HashInHex as String ensure result.length == 32 test assert 'Black holes and revelations.'.md5HashInHex == '95b141d670c19f2f20a820751897b9c6' def repeat(times as int) as String """ Return the string repeated a number of times. """ test assert 'xy'.repeat(3) == 'xyxyxy' assert ''.repeat(1_000_000) == '' def split(separator as String) as String[] return .split(separator, int.max, StringSplitOptions.None) def split(separator as String, count as int) as String[] require count >= 0 return .split(separator, count, StringSplitOptions.None) def split(separator as String, options as StringSplitOptions) as String[] return .split(separator, int.max, options) def split(separator as String, count as int, options as StringSplitOptions) as String[] """ Return an array of strings created by splitting this string by the given separator up to a maximum of count items, conforming to the given StringSplitOptions. """ require count >= 0 test big = 100 assert ''.split('aoeu', big) == @[''] assert 'aoeu'.split(' ', 0) == @[] assert 'aoeu'.split(' ', big) == @['aoeu'] assert 'aoeuXasdf'.split('X', big) == @['aoeu', 'asdf'] assert 'aoeuXXasdf'.split('XX', big) == @['aoeu', 'asdf'] assert 'aoeuXXasdf'.split('XX', big) == @['aoeu', 'asdf'] assert 'aoeuXXasdf'.split('XX', 0) == @[] body return .split(@[separator], count, options) to ! def split(chars as List) as List """ Split this string on any of the list of chars given returning a List of Strings. """ test s = 'a,b:c:d,e,f' assert s.split([c',', c':']) == ['a', 'b', 'c', 'd', 'e', 'f'] body return List(.split(chars.toArray) to !) def split(chars as IList) as List def splitLines as List return .splitLines(false) def splitLines(keepEnds as bool) as List """ Returns the string split into lines, recognizing the various line endings (posix, dos/http, old mac) even if mixed within the same string. """ test cases = [ ['', false, []], [' ', false, [' ']], ['x', false, ['x']], ['x y', false, ['x y']], ['a\n', false, ['a']], ['a\n', true, ['a\n']], ['a\nb', false, ['a', 'b']], ['a\nb', true, ['a\n', 'b']], ['a\nb\n', false, ['a', 'b']], ['a\nb\n', true, ['a\n', 'b\n']], ['a\r', false, ['a']], ['a\r', true, ['a\r']], ['a\rb', false, ['a', 'b']], ['a\rb', true, ['a\r', 'b']], ['a\rb\r', false, ['a', 'b']], ['a\rb\r', true, ['a\r', 'b\r']], ['a\r\n', false, ['a']], ['a\r\n', true, ['a\r\n']], ['a\r\nb', false, ['a', 'b']], ['a\r\nb', true, ['a\r\n', 'b']], ['a\r\nb\r\n', false, ['a', 'b']], ['a\r\nb\r\n', true, ['a\r\n', 'b\r\n']], ['a\r\n\r\n', false, ['a', '']], ['a\r\n\r\n', true, ['a\r\n', '\r\n']], ['a\r\n\r\n\r\n', false, ['a', '', '']], ['a\r\n\r\n\r\n', true, ['a\r\n', '\r\n', '\r\n']], ['a\rb\nc\r\nd', false, ['a', 'b', 'c', 'd']], ['a\rb\nc\r\nd', true, ['a\r', 'b\n', 'c\r\n', 'd']], ] for a, b, c in cases input = a to String keepEnds = b to bool expected = c # trace input, keepEnds, expected actual = input.splitLines(keepEnds) assert actual == expected def splitWords as List test # preliminary: assert 'foo bar'.split == ['foo', 'bar'] assert 'foo bar'.split == ['foo', '', 'bar'] # undesireable assert 'foo bar'.split == ['foo', '', '', 'bar'] # undesireable assert Regex(r'\s+').split('foo bar\r\nbaz') == ['foo', 'bar', 'baz'] # this method: assert 'foo bar\r\nbaz'.splitWords == ['foo', 'bar', 'baz'] extend System.Collections.IList def addRange(items as System.Collections.IEnumerable) def swap(i as int, j as int) require i >= -.count and i < .count j >= -.count and j < .count ensure old this[i] == this[j] old this[j] == this[i] .count == old.count extend IEnumerable def join(sep as String) as String """ Join the items in an IEnumerable collection separated by a string. """ test assert ['a', 'b'].join('.') == 'a.b' assert ['a'].join('.') == 'a' assert [1, 2].join(', ') == '1, 2' assert [1, 2].join('') == '12' assert [].join('.') == '' def join(sep as String, lastSep as String) as String """ Join the items in an IEnumerable collection with a separator string except for the last two items; join them with the lastSep string """ test assert ['a', 'b'].join(', ', ' and ') == 'a and b' assert ['a', 'b', 'c'].join(', ', ' and ') == 'a, b and c' assert ['a', 'b', 'c', 'd'].join(', ', ' and ') == 'a, b, c and d' assert [1, 2, 3, 4].join(', ', ' and ') == '1, 2, 3 and 4' assert [1].join('.', ':') == '1' assert [1, 2].join('', '') == '12' assert [].join('.', ':') == '' extend IEnumerable def toList as List return List(this) extend IList def addRange(items as IEnumerable) def clone as IList """ Returns a new list with the contents of this list. Does not clone the contents themselves. This is sometimes known as a "shallow copy". """ ensure result is not this result.count == .count result.typeOf is .typeOf def concated(other as IList?) as IList """ Returns a new list with the contents of this list and the other. Does not modify this list or the other. The returned list is the same class as the receiver. Assumes the receiving type has an initializer that takes a `capacity as int`. """ def get(flexibleIndex as int) as T """ Return the item at flexibleIndex. If flexibleIndex < 0 return item at flexibleIndex+.count, i.e. offset from end of list. Therefore: .get(0) returns first item in list .get(-1) returns last item .get(-2) returns second to last item .get(-.count) returns first item """ require .count > 0 (flexibleIndex >= 0 and flexibleIndex < .count) _ or (flexibleIndex < 0 and flexibleIndex >= -.count) def get(flexibleIndex as int, default as T) as T """ Return item at flexibleIndex. If flexibleIndex < 0 return item at flexibleIndex+.count. Index values outside list index range return default. """ ensure .count == 0 implies result == default (flexibleIndex > .count or flexibleIndex < -.count) _ implies result == default def last as T """ Returns the last element in the list. """ require .count > 0 def numbered as KeyValuePair* """ Returns a stream of pairs of (index, value). Can be used like so: for i, value in someList.numbered ... """ def numberedDown as KeyValuePair* """ Returns a stream of pairs of (index, value) in reverse order from the end of the list down. Can be used like so: for i, value in someList.numberedDown ... """ def pop as T """ Pop value off end/top of List. """ require .count > 0 def random as T require .count > 0 return .random(CobraCore.random) def random(r as Random) as T require .count > 0 return this[r.next % .count] def removeLast """ Remove the last item in the list. """ require .count > 0 ensure .count == old .count - 1 .removeAt(.count-1) def reversed as List ensure result is not this result.count == .count def sorted as List ensure result is not this result.count == .count def sorted(comparison as Comparison) as List ensure result is not this result.count == .count def sorted(comparer as Comparer) as List ensure result is not this result.count == .count def swap(i as int, j as int) """ Swaps the elements at the given indexes which can be negative to index from the end of the list towards the front (-1 is last element, -2 is second to last, etc.). """ require i >= -.count and i < .count j >= -.count and j < .count ensure old this[i] == this[j] old this[j] == this[i] .count == old.count extend Stack def clone as Stack ensure result is not this result.count == .count result.typeOf is .typeOf extend IDictionary def clone as IDictionary # CC: as same """ Returns a new dictionary with the contents of this dictionary. Does not clone the contents themselves. This is sometimes known as a "shallow copy". """ ensure result is not this result.count == .count result.typeOf is .typeOf def get(key as TKey, default as TValue) as TValue """ Returns the value for the given key, or returns the default if the key is not found. """ ensure not .containsKey(key) implies result == default extend Process def runAndCaptureAllOutput as String """ Example: p = System.Diagnostics.Process() p.startInfo.fileName = 'some-program' p.startInfo.arguments = 'foo bar baz' output = p.runAndCaptureAllOutput trace p, p.exitCode, output """ return .runAndCaptureAllOutput(false) def runAndCaptureAllOutput(verbose as bool) as String }}} You can see the full source for these in the [source:cobra/trunk/Source/Cobra.Lang source Cobra.Lang directory]. Specifically[[BR]] - [source:cobra/trunk/Source/Cobra.Core/Extensions.cobra Extensions.cobra] - [source:cobra/trunk/Source/Cobra.Core/ExtendList.cobra ExtendList.cobra] - [source:cobra/trunk/Source/Cobra.Core/ExtendIEnumerable.cobra ExtendIEnumerable.cobra] - [source:cobra/trunk/Source/Cobra.Core/ExtendDictionary.cobra ExtendDictionary.cobra] - [source:cobra/trunk/Source/Cobra.Core/CobraCore.cobra CobraCore.cobra] See also: PrimitiveTypeMembers, TypeExtensions, LibraryTopics