Pascal Library of Utilities - Quick development library (AutoMapper, LinQ, IOC Dependency Injection, MemoryCache, Scheduled tasks, Json and Yml Config and Options pattern, Serializers, etc) with crossplatform support for Delphi/Firemonkey (Windows,Linux,OSX/IOS/Android) and freepascal (Windows/Linux).
Small delphi/Firemonkey(Windows, Linux, Android, OSX & IOS) and fpc(Windows & Linux) library containing interesting and quick to implement functions, created to simplify application development and crossplatform support and improve productivity.
Areas of functionality:
Main units description:
Updates:
Quick.AppService: Allow a console app to run as console mode or service mode with same code simplifying debug tasks.
if not AppService.IsRunningAsService then
begin
...your code running as console
end
else
begin
AppService.ServiceName := 'MyService';
AppService.DisplayName := 'MyServicesvc';
//you can pass an anonymous method to events
AppService.OnStart := procedure
begin
...your start code
end;
AppService.OnExecute := YourExecuteFunction;
AppService.OnStop := YourStopFunction;
AppService.CheckParams;
end;
Quick.Azure/Amazon: Simplifies blob iteraction with Azure and Amazon Cloud Storage.
//connect to a Azure blobstorage
QuickAzure := TQuickAzure.Create(AzureAccountName,AzureAccountKey);
//download a blob file to a stream
done := QuickAzure.GetBlob('MyContainer','MyFile.jpg',ResponseInfo,MyStream);
//check if exists a folder
found := ExistFolder('MyContainer','/Public/Documents/Personal');
//list blobs starting with a pattern (recursively or not)
for azBlob in ListBlobs('MyContainer','/Public/Documents',Recursive,ResponseInfo) do
begin
if azBlob.Size > 1000 then Showmessage(azBlob.Name);
end;
Quick.Network: CIDR and IP Range functions.
//convert ip string to integer
IPv4ToInt('192.168.1.10');
//get first and last ip of a subnet scope
GetIpRange('192.168.100.0','255.255.255.0',LowIp,HighIP);
Quick.Commons: Functions frequently needed in the everyday of a developer.
//coverts UTC time TDateTime to Local date time
UTCToLocalTime(MyUTCTime);
//generate a 10 char length random password with alfanumeric and signs.
RandomPassword(10,[pfIncludeNumbers,pfIncludeSigns]);
//Capitalize every word of a phrase
CapitalizeAll('the grey fox'); //returns "The Grey Fox"
//Simple TCounter and TTimeCounter for loops
counter := TCounter;
counter.Init(200);
timecounter : TTimeCounter;
timecounter.Init(10000);
while true do
begin
Inc(n);
{your procedural process here}
//every 200 steps writes to console
if counter.Check then writeln(Format('Processed %d entries',[n]));
//every 10 seconds writes to console
if timecounter.Check then writeln('Im working...');
end;
Quick.Chrono: Chronometer and Benchmark a piece of code is simple.
//get elapsed time execution of a code part
Chrono := TChronometer.Create(False);
Chrono.Start;
...code you need benchmark
Chrono.Stop;
//shows elapsed time in LongTime format (2 hour(s) and 10 minute(s))
Showmessage(Chrono.TimeElapsed(True));
//shows elapsed time in ShortTime format (02:10:00)
Showmessage(Chrono.TimeElapsed(False));
//get benchmak info of a process
Chrono := TChronoBenchMark.Create;
Chrono.TotalProcess := 100000;
for i := 1 to 10000 do
begin
{your process here}
Chrono.CurrentProcess := i;
//shows estimated time your process will take in x hour(s), x minute(s) x second(s) format
writeln(Chrono.EstimatedTime(True));
//shows speed: num items per second processed of your process
writeln(Format('Items processed %d/sec',[Chrono.Speed]));
end;
writeln(Chrono.ElapsedTime(False)); //shows total time elapsed in 00:00:00 format
Quick.Console: Write log messages to console with colors and more...
//define which level of output needed
Console.Verbose := LOG_DEBUG;
//writes line to console in red color
cout('Error x',etError);
//writes formatted line in green color
coutFmt('Proccess %s finished',[ProccesName],etSuccess);
//writes integer
cout(12348);
//Connect a QuickLog and write to disk and screen with one line of code (with independent verbose levels)
MyQuickLog := TQuickLog.Create;
MyQuickLog.Verbose := LOG_ALL;
Console.Verbose := LOG_ONLYERRORS;
Console.Log := MyQuickLog;
Quick.Log: Log to disk or memory with verbose levels and daily or max space rotation.
//write a header on start with info as running path, appname, debugmode, user, etc...
Log.ShowHeader := True;
//sets log with rotation at 20MB
Log.SetLog('.\mylog.log',False,20);
//write an error message
Log.Add('Error x',etError);
//write formatted error message
Log.Add('Error is %s',[ErrorStr],etError);
Quick.Config: Load/Save a config as Json or Yaml file or Windows Registry keys. Create a descend class from TAppConfigJson, TAppConfigYaml or TAppConfigRegistry and added published properties will be loaded/saved. Files configs can be reloaded on detect files changes.
//create a class heritage
TMyConfig = class(TAppConfigJson)
private
fName : string;
fSurname : string;
fStatus : Integer;
published
property Name : string read fName write fName;
property SurName : string read fSurname write fSurname;
property Status : Integer read fStatus write fStatus;
end;
//create your config to json file
//Add Quick.Config.Json to your uses
MyConfig := TMyConfig.Create('Config.json');
MyConfig.Provider.CreateIfNotExists := True;
MyConfig.Provider.ReloadIfFileModified := True;
MyConfig.Name := 'John';
MyConfig.Surname := 'Smith';
//load
MyConfig.Load;
//save
MyConfig.Save;
//create your config to Windows Registry
//Add Quick.Config.Registry to your uses
MyConfig := TMyConfig.Create;
//Define Registry as HKEY_CURRENT_USER\Software\MyApp
MyConfig.HRoot := HKEY_CURRENT_USER;
MyConfig.MainKey := 'MyApp';
MyConfig.Name := 'John';
MyConfig.Surname := 'Smith';
//load
MyConfig.Load;
//save
MyConfig.Save;
//Create a custom Config with no default provider
TMyConfig = class(TAppConfig)
...your properties
end;
MyConfig := TMyConfig.Create(TAppConfigJsonProvider.Create('.\config.json');
Quick.FileMonitor: Monitorizes a file for changes and throws events.
FileMonitor.Filename := '.\myfile.txt';
//check file changes every 2 seconds
FileMonitor.Interval := 2000;
//watch for deleted or modified file events
FileMonitor.Notifies := [mnFileModified, mnFileDeleted)];
FileMonitor.OnFileChange := MyFileChangeFunction;
FileMonitor.Enabled := True;
Quick.JsonUtils: Utils for working with json objects.
//When unit declared in uses, a TObject Helper allows all your objects to be loaded or saved to/from json string
MyObject.FromJson := jsonstring;
MyString := MyObject.ToJson;
//You can clone simple objects with clone function
MyObject1.Clone(MyObject2);
Quick.SMTP: Send email with two code lines.
//Send email
SMTP := TSMTP.Create('mail.domain.com',25,False);
SMTP.SendMail('[email protected]','[email protected]','Email subject','My message body');
//You can define more advanced options
SMTP.SenderName := 'John';
SMTP.From := '[email protected]';
SMTP.Recipient := '[email protected],[email protected]';
SMTP.Subject := 'Email subject';
SMTP.AddBodyFromFile := '.\body.html';
SMTP.CC := '[email protected]';
SMTP.BCC := '[email protected]';
SMTP.Attachments.Add('.\notes.txt');
SMTP.SendMail;
Quick.Threads: Thread safe classes.
TAnonymousThread: Creates anonymous thread defining unchained Execute and OnTerminate methods. Use Execute_Sync and OnTerminate_Sync methods if code needs to update UI.
Start: Starts thread execution.
//simple anonymousthread
TAnonymousThread.Execute(
procedure
var
i : Integer;
begin
for i := 0 to 10 do cout('Working %d',[i],etTrace);
cout('executed thread',etSuccess);
end)
.OnTerminate(
procedure
begin
cout('terminated thread',etSuccess);
cout('PRESS <ENTER> TO EXIT',etInfo);
end)
.Start;
TRunTask: Launch an autofree single task thread with fault & retry control policies. Params can be passed and created into code.
Define code to execute:
Define events to control:
Define fail/retry policies:
Run: Starts task execution.
TRunTask.Execute(
procedure(task : ITask)
var
stream : TStringStream;
response : IHttpRequestResponse;
begin
stream := TStringStream.Create;
try
response := TJsonHttpClient(task['httpclient'].AsObject).Get(task['url']);
task.Result := response.StatusCode;
if response.StatusCode <> 200 then raise Exception.Create(response.StatusText);
finally
stream.Free;
end;
end)
.SetParameter('httpclient',(TJsonHttpClient.Create),True)
.SetParameter('url','https://mydomain.com/testfile')
.WaitAndRetry(5,250,2)
.OnRetry(
procedure(task : ITask; aException : Exception; var vStopRetries : Boolean)
begin
//if error 404 don't try to retry request
if task.Result = 404 then vStopRetries := True;
end)
.OnException(
procedure(task : ITask; aException : Exception)
begin
coutFmt('Exception downloading (Error: %s / StatusCode: %d)...',[aException.Message,task.Result.AsInteger],etError);
end)
.OnTerminated(
procedure(task : ITask)
begin
if task.Done then coutFmt('Download "%s" finished ok',[task['url'].AsString],etSuccess)
else coutFmt('Download "%s" failed after %d retries',[task['url'].AsString,task.NumRetries],etError);
end)
.Run;
TBackgroundsTasks: Launch tasks in background allowing number of concurrent workers with fault and retry control policies. Use AddTask_Sync and OnTerminate_Sync methods if code needs to update UI.
Add a task to execute:
Define events to control:
Define fail/retry policies:
Begin execution:
Start: Starts tasks execution.
backgroundtasks := TBackgroundTasks.Create(10);
for i := 1 to 100 do
begin
mytask := TMyTask.Create;
mytask.Id := i;
mytask.Name := 'Task' + i.ToString;
backgroundtasks.AddTask([mytask],False,
procedure(task : ITask)
begin
cout('task %d started',[TMyTask(task.Param[0].AsObject).Id],etDebug);
TMyTask(task.Param[0].AsObject).DoJob;
end
).WaitAndRetry([250,2000,10000])
).OnException(
procedure(task : ITask; aException : Exception)
begin
cout('task %d failed (%s)',[TMyTask(task.Param[0].AsObject).Id,aException.Message],etError);
end
).OnTerminated(
procedure(task : ITask)
begin
cout('task %d finished',[TMyTask(task.Param[0].AsObject).Id],etDebug);
TMyTask(task.Param[0].AsObject).Free;
end
).Run;
end;
backgroundtasks.Start;
TScheduledTasks: Alternative to Timer. You can assign tasks with start time, repeat options and expiration date and fail and retry control policies. Use AddTask_Sync, OnTerminate_Sync and OnExpired_Sync if code needs to update UI. You can assign anonymous methods to execute, exception, terminate and expiration events.
Add a task to execute:
Define events to control:
Define when to start task:
Define if needs to repeat or not (if not defined a previous StartAt, StartOn, etc, task will be executed immediately):
Define fail/retry policies:
Start/Stop scheduler:
Stop: Stops scheduler.
myjob := TMyJob.Create;
myjob.Name := Format('Run at %s and repeat every 1 second until %s',[DateTimeToStr(ScheduledDate),DateTimeToStr(ExpirationDate)]);
scheduledtasks.AddTask('Task1',[myjob],True,
procedure(task : ITask)
begin
cout('task "%s" started',[TMyTask(task.Param[0]).Name],etDebug);
TMyJob(task.Param[0]).DoJob;
end
).OnException(
procedure(task : ITask; aException : Exception)
begin
cout('task "%s" failed (%s)',[TMyJob(task.Param[0]).Name,aException.Message],etError);
end
).OnTerminated(
procedure(task : ITask)
begin
cout('task "%s" finished',[TMyJob(task.Param[0]).Name],etDebug);
end
).OnExpired(
procedure(task : ITask)
begin
cout('task "%s" expired',[TMyJob(task.Param[0]).Name],etWarning);
end
).StartAt(ScheduledDate
).RepeatEvery(1,TTimeMeasure.tmSeconds,ExpirationDate);
scheduledtasks.Start;
ITask: Interface passed to every task event of TRunTask, TBackgroundTasks and TScheduledTasks.
Quick.FaultControl: Manages fail and retry policies, defining max retries, wait time beetween retries and circuit break mecanism.
Quick.Process: Manages windows processes.
//kill explorer process
KillProcess('explorer.exe');
//determine if an application is running
if IsProcessRunning('explorer.exe') then Showmessage('Explorer is running!');
//get username who is running an exe
writeln('Explorer.exe open by: ' + GetProcessUser('explorer.exe');
//gets handle of a window with a 20 seconds timeout
if FindWindowTimeout('MainWindow',20) then writeln('Window detected');
Quick.Services: Manages windows services.
//detect if a service is installed
if not ServiceIsPresent('localhost','MySvc') then raise Exception.Create('Service not installed!');
//Start a service
ServiceStart('localhost','MySvc');
//Uninstall a service
ServiceUninstall('MySvc');
Quick.Format: String format.
//Format bytes to MB, GB, TB...
FormatBytes(50000) //shows 50KB
FormatBytes(90000000) //shows 90MB
Quick.JsonSerializer: Serializes an object from/to json text. You can define if public or published will be processed (only Delphi, fpc rtti only supports published properties)
json := '{"name":"Peter","age":30}';
serializer := TJsonSerializer.Create(TSerializeLevel.slPublishedProperty);
try
serializer.JsonToObject(user,json);
finally
serializer.Free;
end;
Quick.AutoMapper: Map fields from one class to another class. Allows custom mappings to match different fields and custom mapping procedure to cast/convert fields manually.
//Map values from User1 to User2
TMapper<TUser2>.Map(User);
//Map custom mappings
AutoMapper := TAutoMapper<TUser,TUser2>.Create;
//option1: you can define auto map different named properties
AutoMapper.CustomMapping.AddMap('Cash','Money');
AutoMapper.CustomMapping.AddMap('Id','IdUser');
//option2: you can decide to modify each property manually or allow to auto someones
AutoMapper.OnDoMapping := procedure(const aSrcObj : TUser; const aTargetName : string; out Value : TFlexValue)
begin
if aTargetName = 'Money' then Value := aSrcObj.Cash * 2
else if aTargetName = 'IdUser' then Value := aSrcObj.Id;
end;
//option3: you can modify some properties after automapping done
AutoMapper.OnAfterMapping := procedure(const aSrcObj : TUser; aTgtObj : TUser2)
begin
aTgtObj.Money := aSrcObj.Cash * 2;
aTgtObj.IdUser := aSrcObj.Id;
end;
User2 := AutoMapper.Map(User);
Quick.JsonRecord: Used as a DTO class, with json serialize and mapping functions included.
type
TUser = class(TJsonRecord)
private
fName : string;
fAge : Integer;
published
property Name : string read fName write fName;
property Age : Integer read fAge write fAge;
end;
var
user, user2 : TUser;
begin
user := TUser.Create;
//show as json string
Writeln(user.ToJson);
//mapping to other class
user.Mapto(User2);
Writeln(user2.ToJson);
//load from file
user.LoadFromFile('.\user.json');
//save to file
user2.SaveToFile('.\user2.json');
end;
Quick.Lists: Improved lists with indexing or search features.
TSearchObjectList: Allows iteration search by object properties or fields.
var
users : TIndexedObjectList<TUser>;
begin
users := TIndexedObjectList<TUser>.Create(True);
//create index by property "Name"
users.Indexes.Add('Name','Name',TClassField.cfProperty);
//create index by private field "Id"
users.Indexes.Add('Id','fId',TClassField.cfField);
//get user by "Name" index
writeln(users.Get('Name','Peter').SurName);
end;
Quick.Value FlexValue stores any data type and allow pass to other class with integrated operators and autofrees.
var
value : TFlexValue;
str : string;
num : Integer;
begin
value := 'hello';
str := value;
value := 123;
num := value;
end;
Quick.Arrays: Improved arrays.
TXArray: Array with methods like TList.
var
users : TXArray<TUser>;
begin
users.Add(User);
if users.Count:= TIndexedObjectList<TUser>.Create(True);
//create index by property "Name"
users.Indexes.Add('Name','Name',TClassField.cfProperty);
//create index by private field "Id"
users.Indexes.Add('Id','fId',TClassField.cfField);
//get user by "Name" index
writeln(users.Get('Name','Peter').SurName);
end;
TFlexArray: Array with methods like TList than can storage different value types into same array.
var
flexarray : TFlexArray;
begin
flexarray.Add(10);
flexarray.Add('Hello');
user := TUser.Create;
try
user.Name := 'Joe';
flexarray.Add(user);
cout('Integer Item = %d',[flexarray[0].AsInteger],etInfo);
cout('String Item = %s',[flexarray[1].AsString],etInfo);
cout('Record Item = %s',[TUser(flexarray[2]).Name],etInfo);
finally
user.Free;
end;
end;
TFlexPairArray: Array with methods like TList than can store different value types into same array, and search by item name.
var
flexarray : TFlexPairArray;
begin
flexarray.Add('onenumber',10);
flexarray.Add('other','Hello boy!');
user := TUser.Create;
try
user.Name := 'Joe';
flexarray.Add('myuser',user);
cout('Integer Item = %d',[flexarray.GetValue('onenumber').AsInteger],etInfo);
cout('String Item = %s',[flexarray.GetValue('other').AsString],etInfo);
cout('Record Item = %s',[TUser(flexarray.GetValue('myuser')).Name],etInfo);
finally
user.Free;
end;
end;
Quick.YAML: Yaml object structure.
TYamlObject: A Yaml object is and array of YamlValue pairs.
//create Yaml object from yaml text
yamlobj.ParseYamlValue(aYaml)
//add a pair
yamlobj.AddPair('Name','Mike');
//display as yaml structure
Writeln(yamlobj.ToYaml);
TYamlArray: Array of objects or scalars.
yamlarray.AddElement(TYamlPair.Create('Age',30));
yamlobj.AddPair('myarray',yamlarray);
TYamlPair: Name-Value pair. Value can be object, array or scalar.
n := yamlobj.GetPair('Name').Value as TYamlInteger;
Quick.YAML.Serializer: Serialize/Deserialize object from/to Yaml.
//Serialize
text := YamlSerializer.ObjectToYaml(obj);
//Deserialize
YamlSerializer.YamlToObject(obj,yamltext);
Quick.Expression: Evaluate object properties using expressions.
if TExpressionParser.Validate(user,('(Age > 30) AND (Dept.Name = "Financial")') then
begin
//do something
end;
Quick.Linq: Makes Linq queries to any TObjectList, TList, TArray and TXArray, performing Select by complex Where like SQL syntax, update and order over your list.
Count: Return number of elements matching where clause.
//Select multi conditional
for user in TLinq<TUser>.From(userslist).Where('(Name = ?) OR (SurName = ?) OR (SurName = ?)',['Peter','Smith','Huan']).Select do
begin
//do something
end;
//Select like and update field
TLinq<TUser>.From(userlist).Where('SurName Like ?',['%son']).SelectFirst.Name := 'Robert';
//Select top and Order by field
for user in TLinq<TUser>.From(userlist).Where('Age > ?',[18]).SelectTop(10).OrderBy('Name') do
begin
//do something
end;
//update fields by conditional
TLinq<TUser>.From(userlist).Where('Name = ?',['Peter']).Update(['Name'],['Joe']);
//count results
numusers := TLinq<TUser>.From(userlist).Where('(Age > ?) AND (Age < ?)',[30,40]).Count;