I like to think that the following features are what they would have implemented in version 10 of Visual FoxPro
Suggestions are welcome!
This library is part of the VFPX project.
Do you like or benefit from my work? please consider make a donation, a cup of coffee would be nice!
FoxExtends allows you to customize all methods or creating an object by using the constructor method called NEWFOXEXTENDS()
tcPrefix:
type any valid identifier to prefix all functions.tcType:
allowed values areprg | obj
PRG
indicates that all functions will be instantiated in Visual Foxpro global environment (PRG scope).OBJ
indicates that all functions will be wrapped in an object which means you'll need to consume it likeobject.method()
// ================================================================================
// 1. Default behaviour (prg scope)
// ================================================================================
do FoxExtends.prg
=NEWFOXEXTENDS() // call constructor without arguments (PRG scope).
laColors = ALIST('red', 'yellow', 'green')
? ANYTOSTR(@laColors) // ['red', 'yellow', 'green']
// ================================================================================
// 2. Prefix and PRG scope.
// ================================================================================
do FoxExtends.prg
=NEWFOXEXTENDS('FE_') // just provide the prefix for all functions (prg scope)
laColors = FE_ALIST('red', 'yellow', 'green')
? FE_ANYTOSTR(@laColors) // ['red', 'yellow', 'green']
// ================================================================================
// 3. No Prefix and OBJECT scope.
// ================================================================================
do FoxExtends.prg
loFE = NEWFOXEXTENDS(.F., 'obj') // note the loFE variable receiving the object.
laColors = loFE.ALIST('red', 'yellow', 'green')
? loFE.ANYTOSTR(@laColors) // ['red', 'yellow', 'green']
// ================================================================================
// 4. Prefix and OBJECT scope.
// ================================================================================
do FoxExtends.prg
loFE = NEWFOXEXTENDS('FE_', 'obj')
laColors = loFE.FE_ALIST('red', 'yellow', 'green')
? loFE.FE_ANYTOSTR(@laColors) // ['red', 'yellow', 'green']
// ================================================================================
// 1. PAIR(tvKey, tvValue): create a Key-Value object with the data provided:
// ================================================================================
// Example
loPair = PAIR("name", "John")
? loPair.key, loPair.value
// ================================================================================
// 2. ANYTOSTR(tvValue): convert any object into string (including Collections):
// ================================================================================
// Example
? ANYTOSTR(_SCREEN) // the whole screen object :)
// ================================================================================
// 3. APUSH(tArray, tvItem): adds an element into the array
// NOTE: YOU MUST PASS THE ARRAY AS REFERENCE
// ================================================================================
// Example
DIMENSION laCountries[1]
laCountries[1] = "USA"
APUSH(@laCountries, "COLOMBIA")
APUSH(@laCountries, "ARGENTINA")
APUSH(@laCountries, "ESPAÑA")
// ================================================================================
// 4. APOP(tArray): removes an element from the top of the array.
// NOTE: YOU MUST PASS THE ARRAY AS REFERENCE
// ================================================================================
// Example
DIMENSION laCountries[4]
laCountries[1] = "USA"
laCountries[2] = "COLOMBIA"
laCountries[3] = "ARGENTINA"
laCountries[4] = "ESPAÑA"
// Remove and retrieve the removed element
? APOP(@laCountries) // print ESPAÑA
// ================================================================================
// 5. AJOIN(tArray, tcStep): return a string with all array elements delitemited by tcStep
// ================================================================================
// Example
DIMENSION laCountries[4]
laCountries[1] = "USA"
laCountries[2] = "COLOMBIA"
laCountries[3] = "ARGENTINA"
laCountries[4] = "ESPAÑA"
? AJOIN(@laCountries, ', ') // prints USA, COLOMBIA, ARGENTINA, ESPAÑA
// ================================================================================
// 6. ASPLIT(tcString, tcDelimiter): Creates an array with all matches in the string provided.
// ================================================================================
// Example
laColors = ASPLIT("Red, Yellow, Blue, Green, Purple", ',')
FOR EACH lcColor IN laColors
? lcColor
ENDFOR
// ================================================================================
// 7. MATCH(tcString, tcPattern): check if the tcPattern matches in the string provided.
// NOTE: this function relies on VBScript.RegExp
// ================================================================================
// Example
// Validate an email format
? MATCH("[email protected]", "^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$") // print .T.
// ================================================================================
// 8. REVERSE(tcString): reverses a string
// ================================================================================
// Example
? REVERSE("Irwin") // niwrI
// ================================================================================
// 9. STRTOJSON(tcJSONStr): receive a json string and creates a Foxpro equivalent object.
// NOTE: this function relies on JSONFOX: https://github.com/Irwin1985/JSONFox
// ================================================================================
// Example
loMyJson = STRTOJSON('{"name": "John", "age": 36}')
? loMyJson.name
? loMyJson.age
// ================================================================================
// 10. JSONTOSTR(tvJsonObj): pretty print the Foxpro equivalent json object.
// ================================================================================
// Example
? JSONTOSTR(loMyJson) // {"name": "John", "age": 36}
// ================================================================================
// 11. PRINTF(tcFormat, tvVal0...tvVal10): pretty prints up to ten values.
// you can even escape some special characters like: \t, \r, \n, \", \'
// NOTE: sorry for this limitation of ten arguments.
// ================================================================================
// Example
? PRINTF("Hello ${0}! My name is ${1} and I'm glad to ${2} you!", "world", "John", "meet")
// ================================================================================
// 12. ALIST(tvVal1, tvVal2, tvVal3,...tvVal10): creates an array up to ten
// heterogeneous elements.
//
// NOTE: sorry for this limitation of ten arguments.
// ================================================================================
// Example
laData = ALIST("John", 36, .T., .F., .Null., PAIR("Bank of America", "NL40RABO8933084452"), "[email protected]")
FOR EACH lItem IN laData
? lItem
ENDFOR
// print the pair (at index 6!!!)
? laData[6].key // prints Bank of America
? laData[6].value // prints NL40RABO8933084452
// ================================================================================
// 13. CLAMP(tcString, tnFrom, tnTo): captures a range of characters.
// ================================================================================
// Example
lcString = "This is a string"
? CLAMP(lcString, 6, 10) // prints "is a"
// ================================================================================
// 14. AMAP(tArray, tcPredicate): returns an array with tcPredicate expression
// applied.
//
// LIMITATIONS: the array must be one-dimensional and homogeneous.
// ================================================================================
// Example
laNumbers = ALIST(5, 10, 15, 20, 25, 30, 35, 40)
laResult = AMAP(@laNumbers, "$0 + 5")
? ANYTOSTR(@laResult) // prints [10,15,20,25,30,35,40,45]
// ================================================================================
// 15. AFILTER(tArray, tcPredicate): returns all items from tArray that returns .T.
// by applying the tcPredicate expression.
//
// LIMITATIONS: the array must be one-dimensional and homogeneous.
// ================================================================================
// Example
laNumbers = ALIST(5, 10, 15, 20, 25, 30, 35, 40)
laResult = AFILTER(@laNumbers, "BETWEEN($0, 20, 30)") // filter just those items with this range (20 and 30)
? ANYTOSTR(@laResult) // prints [20,25,30]
// ================================================================================
// 15. AFILTER(tArray, tcPredicate): returns all items from tArray that returns .T.
// by applying the tcPredicate expression.
//
// LIMITATIONS: the array must be one-dimensional and homogeneous.
// ================================================================================
// Example
laNumbers = ALIST(5, 10, 15, 20, 25, 30, 35, 40)
laResult = AFILTER(@laNumbers, "BETWEEN($0, 20, 30)") // filter just those items with this range (20 and 30)
? ANYTOSTR(@laResult) // prints [20,25,30]
// ================================================================================
// 16. AFIELDSOBJ(tcAliasOrDataSession)
// returns an array mapped with all the table structure info.
// check AFIELDS() documentation for property names.
// ================================================================================
// Example
Use Home(2) + "\northwind\employees.dbf"
laFields = AFIELDSOBJ('employees')
? ANYTOSTR(laFields) // prints a nice json format :)
// print all properties
FOR EACH loItem IN laFields
? loItem.name
? loItem.field_type
? loItem.field_width
? loItem.decimal_places
? loItem.null_allowed
? loItem.code_page_translation_not_allowed
? loItem.field_validation_expression
? loItem.field_validation_text
? loItem.field_default_value
? loItem.table_validation_expression
? loItem.table_validation_text
? loItem.long_table_name
? loItem.insert_trigger_expression
? loItem.update_trigger_expression
? loItem.delete_trigger_expression
? loItem.table_comment
? loItem.next_value_for_autoincrementing
? loItem.step_for_autoincrementing
ENDFOR
// ================================================================================
// 17. ADIROBJ(tcFileSkeleton, [tcAttribute, [tnFlags]])
// returns an array mapped with all the files structure info.
// check ADIR() documentation for property names.
// ================================================================================
// Example
laDir = ADIROBJ("c:\my\path\*.txt")
? ANYTOSTR(laDir) // prints a nice json format :)
// print all properties
FOR EACH loItem IN laDir
? loItem.file_name
? loItem.file_size
? loItem.date_last_modified
? loItem.time_last_modified
? loItem.file_attributes
ENDFOR
// ================================================================================
// 18. SECRETBOX(tcPrompt, [tcCaption])
// Displays a modal dialog used for typing secret passwords.
// NOTE: the result string is not encrypted, it's just a raw string.
// ================================================================================
// Example
lcPassword = SECRETBOX("Login", "Please type your password")
IF lcPassword != "Admin" THEN
? "Access Denied!"
RETURN
ENDIF
? "Welcome!"
// ================================================================================
// 19. Variadic functions with ARGS() and APARAMS()
// This implementation allows us to simulate variadic functions and avoid passing
// a lot of arguments.
// ARGS(arg1, arg2, argn): wraps all arguments inside a special object. (caller)
// APARAMS(toArgs): unwraps all arguments into an array. (function body)
// ================================================================================
// Example
? arithmeticOperation("+", ARGS(5, 10, 15, 20, 25, 30))
FUNCTION arithmeticOperation(tcOperator, toOperands)
LOCAL lnResult, laParams
lnResult = 0
laParams = APARAMS(toOperands) // unwrap arguments
FOR EACH lnOperand IN laParams
lnResult = lnResult &tcOperator lnOperand
ENDFOR
RETURN lnResult
ENDFUNC
// ================================================================================
// 20. STRINGLIST(): creates an string object that enhance the string manipulation
// NOTE: it's constructor accepts ARGS() parameters. See ARGS() and APARAMS()
// ================================================================================
// Example
laLanguages = STRINGLIST() // empty stringlist
laLanguages.Add("Visual FoxPro")
laLanguages.Add("Swift")
laLanguages.Add("Nim")
laLanguages.Add("V")
? laLanguages.Join(', ') // print "Visual FoxPro, Swift, Nim, V"
// Example 2: using the constructor.
laStuffs = STRINGLIST(ARGS("House", "Horse", "Pencil"))
laStuffs.Add("Red")
laStuffs.Add("Person")
laStuffs.Add("Table")
? laStuffs.Join(', ')
// ================================================================================
// 21. AZIP(tArray1, tArray2): returns a new array with the combination of two
// arrays provided. Each element must be accessed by using the 'left' and 'right'
// properties.
// ================================================================================
// Example
laFruits = ALIST("Apples", "Bananas", "Strawberry")
laVegetables = ALIST("Tomato", "Carrot", "Pumpkins")
laFusion = AZIP(@laFruits, @laVegetables)
FOR EACH loItem IN laFusion
? loItem.left
? loItem.right
ENDFOR
// ================================================================================
// 22. HASHTABLE(tcKey2, tcValue1 [,...]): creates a dictionary with the given
// keys and values.
// LIMITATION:
// 1. keys must be strings
// 2. the function takes up to 50 key-values params.
// ================================================================================
// Example
loDictionary = HASHTABLE("name", "John", "age", 36, "gender", "M", "salary", 3000)
? loDictionary.name
? loDictionary.age
? loDictionary.gender
? loDictionary.salary
// ================================================================================
// 23. HASKEY(toDictionary, tcKey): determines if tcKey exists in toDictionary
// ================================================================================
// Example
loDictionary = HASHTABLE("name", "John", "age", 36, "gender", "M", "salary", 3000)
? HASKEY(loDictionary, "name") // .T.
? HASKEY(loDictionary, "address") // .F.
// ================================================================================
// 24. AKEYS(toDictionary): returns an array with all keys found in toDictionary
// ================================================================================
// Example
loDictionary = HASHTABLE("name", "John", "age", 36, "gender", "M", "salary", 3000)
laKeys = AKEYS(loDictionary)
?ANYTOSTR(@laKeys) // ["NAME", "AGE", "GENDER", "SALARY"]
// ================================================================================
// 25. ASLICE(tArray, tcRange): creates an array with the range provided.
// ================================================================================
// Example
laFruits = ALIST("apple", "banana", "blackberry", "grape", "lemon", "mango", "raspberry")
laSlice = ASLICE(@laFruits, "2..3") // from index 2 until index 3
? ANYTOSTR(@laSlice) // ["banana", "blackberry"]
laSlice = ASLICE(@laFruits, "..3") // from index 1 up to 3
? ANYTOSTR(@laSlice) // ["apple", "banana", "blackberry"]
laSlice = ASLICE(@laFruits, "5..") // from index 5 up to the end of the array.
? ANYTOSTR(@laSlice) // ["lemon", "mango", "raspberry"]
laSlice = ASLICE(@laFruits, "3") // first 3 elements
? ANYTOSTR(@laSlice) // ["apple", "banana", "blackberry"]
laSlice = ASLICE(@laFruits, "-2") // last 2 elements
? ANYTOSTR(@laSlice) // ["mango", "raspberry"]
// ================================================================================
// 26. AMATCH(tcString, tcPattern, tcOccurrences): creates an array with the
// ocurrences found in tcString by applying the tcPattern regular expression.
// ================================================================================
// Example
lcString = "Hi, foxextends has more than 20 functions...! can you help me to make it 100?"
laResult = AMATCH(lcString, "\w+", 1) // first number
? laResult[1] // 20
laResult = AMATCH(lcString, "\w+", 2) // second number
? laResult[1] // 100
// ================================================================================
// 27. AINSERSECT(tArray1, tArray2): creates an array with all elements in tArray1
// that are present in tArray2.
// ================================================================================
// Example
laFruits = ALIST("apple", "banana", "blackberry", "grape", "lemon", "mango", "raspberry")
laSalad = ALIST("tomato", "grape", "onion", "pumpkin", "lemon")
laCommons = AINTERSECT(@laFruits, @laSalad)
? ANYTOSTR(@laCommons) // ["grape", "lemon"]
// Example # 2: compare heterogeneous arrays
laJustNumbers = ALIST(5, 10, 15, 20, 25, 30)
laNumbersAndLetters = ALIST("five", "ten", 15, 30, 100)
laCommons = AINTERSECT(@laJustNumbers, @laNumbersAndLetters)
? ANYTOSTR(@laCommons) // [15, 30]
// ================================================================================
// 28. ADDKEY(toDict, tcKey, tvValue): adds or set a key to toDict.
// NOTE: toDict should be created with HASHTABLE(...)
// ================================================================================
// Example
loPrices = HASHTABLE('apples', 1.45)
=ADDKEY(loPrices, 'oranges', 0.75)
// ================================================================================
// 29. REMOVEKEY(toDict, tcKey): removes a key from toDict.
// NOTE: toDict should be created with HASHTABLE(...)
// ================================================================================
// Example
loPrices = HASHTABLE('apples', 1.45, 'oranges', 0.75, 'tomatoes', 1.40, 'onions', 0.54, 'book', 1.40)
=REMOVEKEY(loPrices, 'book') // book should not be in this list of prices.
// ================================================================================
// 30. ALEFT(tArray, tnExpression): creates an array with the index found on
// tnExpression starting from left to right.
// ================================================================================
// Example
laFruits = ALIST("apple", "banana", "blackberry", "grape", "lemon", "mango", "raspberry")
laTwo = ALEFT(@laFruits, 2)
? ANYTOSTR(@laTwo) // ["apple", "banana"]
// ================================================================================
// 31. ARIGHT(tArray, tnExpression): creates an array with the index found on
// tnExpression starting from right to left.
// ================================================================================
// Example
laFruits = ALIST("apple", "banana", "blackberry", "grape", "lemon", "mango", "raspberry")
laTwo = ARIGHT(@laFruits, 2)
? ANYTOSTR(@laTwo) // ["mango", "raspberry"]
// ================================================================================
// 32. ASUBSTR(tArray, tnFromExp, tnToExp): creates an array starting from index
// found in tnFromExp until tnToExp.
// ================================================================================
// Example
laFruits = ALIST("apple", "banana", "blackberry", "grape", "lemon", "mango", "raspberry")
laLemonAndMango = ASUBSTR(@laFruits, 5, 2)
? ANYTOSTR(@laLemonAndMango) // ["lemon", "mango"]