
O Quicklib é uma biblioteca Delphi/Firemonkey (Windows, Linux, Android, OSX e iOS) e FPC (Windows & Linux), contendo funções interessantes e rápidas para implementar, criadas para simplificar o desenvolvimento de aplicativos e o suporte cruzado e melhorar a produtividade. Delphi XE8 - Delphi 12 Atenas apoiou.
Por favor, "estrela" este projeto no Github! Custa nada além de ajuda a fazer referência ao código. 
Se você achar esse projeto útil, considere fazer uma doação.
Áreas de funcionalidade:
Descrição das unidades principais:
Atualizações:
Permita que um aplicativo de console seja executado como modo de console ou modo de serviço com as mesmas tarefas de depuração simplificando de código.
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 ;Simplifica a iteraction BLOB com o Azure e o 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 ;Funções de intervalo Cidr e IP.
// 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);Funções freqüentemente necessárias no cotidiano de um desenvolvedor.
// 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 ;O cronômetro e a comparação de um pedaço de código é simples.
// 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 Escreva mensagens de log para console com cores e muito mais ...
// 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;Faça logon no disco ou memória com níveis detalhados e rotação diária ou máxima do espaço.
// 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);Carregue/salve uma configuração como arquivos JSON ou YAML ou teclas de registro do Windows. Crie uma classe descendente de TapppConfigjson, TapppConfigyaml ou TapppConfigRegistry e as propriedades publicadas adicionadas serão carregadas/salvas. As configurações de arquivos podem ser recarregadas nas alterações de detecção de arquivos.
// 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_USERSoftwareMyApp
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 ' );
Monitoriza um arquivo para alterações e lança eventos.
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;Utils para trabalhar com objetos JSON.
// 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);Envie email com duas linhas de código.
// 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;Aulas seguras de tópicos.
TTHreadEdQueuecs: versão do TTHreadEdQueue com seção crítica.
TTHReadObjectList: Lista de objetos seguros do thread.
TTHreadEdQueuelist: Lista de filas seguras do tópico. AutoGrow e com seção crítica.
TanonymousThread: Cria um thread anônimo que define os métodos de execução e o terminado. Use métodos Execute_Sync e OnTerminE_Sync se o código precisar atualizar a interface do usuário.
// 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: Inicie um encadeamento de tarefa única automática com políticas de controle de falha e repetição. Os parâmetros podem ser passados e criados para o código.
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: inicie as tarefas em segundo plano, permitindo o número de trabalhadores simultâneos com políticas de controle de falhas e repetições. Use os métodos Addtask_sync e OnTerMinate_Sync se o código precisar atualizar a interface do usuário.
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: alternativa ao timer. Você pode atribuir tarefas com o horário de início, repetir as opções e a data de validade e falhar e repetir as políticas de controle. Use Addtask_sync, OnTerminate_Sync e Onexired_sync se o código precisar atualizar a UI. Você pode atribuir métodos anônimos para executar, excepção, encerrar e eventos de validade.
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;As administrações falham e repetem políticas, definindo tentativas máximas, tempo de espera entre tentativas e mecanismo de quebra de circuito.
Gerencia os processos do Windows.
// 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 ' );Gerencia os serviços do Windows.
// 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 ' );Formato de string.
// Format bytes to MB, GB, TB...
FormatBytes( 50000 ) // shows 50KB
FormatBytes( 90000000 ) // shows 90MB Serializa um objeto de/para o texto JSON. Você pode definir se o público ou publicado será processado (apenas Delphi, FPC RTTI suporta apenas propriedades publicadas)
json := ' {"name":"Peter","age":30} ' ;
serializer := TJsonSerializer.Create(TSerializeLevel.slPublishedProperty);
try
serializer.JsonToObject(user,json);
finally
serializer.Free;
end ;Mapa Campos de uma classe para outra classe. Permite que os mapeamentos personalizados correspondam a diferentes campos e procedimento de mapeamento personalizado para fundir/converter campos manualmente.
// 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);Usado como uma classe DTO, com as funções JSON Serialize e Mapping incluídas.
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 ;Listas aprimoradas com recursos de indexação ou pesquisa.
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 ;O FlexValue armazena qualquer tipo de dados e permita passar para outra classe com operadores e autofrees integrados.
var
value : TFlexValue;
str : string;
num : Integer;
begin
value := ' hello ' ;
str := value ;
value := 123 ;
num := value ;
end ;Matrizes aprimoradas.
TXARRAY: Matriz com métodos como 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: matriz com métodos como o TLIST do que o armazenamento de diferentes tipos de valor na mesma matriz.
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: Matriz com métodos como Tlist do que pode armazenar diferentes tipos de valor na mesma matriz e pesquisar pelo nome do item.
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 ;Estrutura do objeto YAML.
Tyamlobject: Um objeto YAML é e uma matriz de pares YamlValue.
// create Yaml object from yaml text
yamlobj.ParseYamlValue(aYaml)
// add a pair
yamlobj.AddPair( ' Name ' , ' Mike ' );
// display as yaml structure
Writeln(yamlobj.ToYaml);Tyamlarray: Matriz de objetos ou escalares.
yamlarray.AddElement(TYamlPair.Create( ' Age ' , 30 ));
yamlobj.AddPair( ' myarray ' ,yamlarray);Tyamlpair: par de nomes-valor. O valor pode ser objeto, matriz ou escalar.
n := yamlobj.GetPair( ' Name ' ). Value as TYamlInteger;Serialize/desserialize objeto de/para yaml.
// Serialize
text := YamlSerializer.ObjectToYaml(obj);
// Deserialize
YamlSerializer.YamlToObject(obj,yamltext);Avalie as propriedades do objeto ou valores únicos usando expressões.
if TExpressionParser.Validate(user,( ' (Age > 30) AND (Dept.Name = "Financial") ' ) then
begin
// do something
end ;
if TExpressionParser.Validate(user,( ' (20 > 30) OR (5 > 3) ' ) then
begin
// do something
end ;Faz o LINQ consultas para qualquer TobjectList, Tlist, Tarray e TXARRAY, executando o Select By Complex, onde a sintaxe, atualização e pedido do SQL, atualize e encomende pela sua lista. Onde as cláusulas usam espaços para nomes para determinar propriedades aninhadas. O LINQ pode procurar um elemento em uma matriz de propriedades. Agora inclui e Tarray Helper para adicionar, remover e pesquisar com expressões regulares na matriz.
// 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;O TCUSTOMHTTPSERVER é um simples httpServer com interface com implementações HTTPRequest e HTTPRESPSONS de HTTPPRESS para permitir alterações fáceis do motor HttpServer. Você pode ativar as páginas de erro personalizadas para retornar páginas personalizadas e páginas de erro dinâmico. O THTTPSERVER é a implementação do IndyhttpServer, mas você pode definir o seu próprio.
TMyHttpServer = class (THttpServer)
public
procedure ProcessRequest (aRequest: IHttpRequest; aResponse: IHttpResponse); override;
end ;
procedure TMyHttpServer.ProcessRequest (aRequest: IHttpRequest; aResponse: IHttpResponse);
begin
aResponse.ContentText := ' Hello world! ' ;
end ;Objetos ou strings em cache com um tempo de validade, para evitar gerar essas informações toda vez que for necessária (consultas de banco de dados, difícil calcular informações etc.). O TMemoryCache permite cache objetos e strings. Versão genérica O TMemoryCache permite cache apenas um tipo definido.
// create MemoryCache with 10 seconds purge interval
cache := TMemoryCache.Create( 10 );
// create MemoryCache for a type
cache := TMemoryCache<TMyObj>.Create; // set string to cache without expiration
cache.SetValue( ' mystring ' , ' hello world ' );
// set string to cache with expiration to 10 seconds
cache.SetValue( ' mystring ' , ' this cache will expire in 10 seconds ' ;
// set object to cache
cache.SetValue( ' Obj1 ' ,valueobj); // get string query result
cache.GetValue( ' Query12 ' );
// get integer
cache.TryGetValue<Integer>( ' number ' ,valueint);
// get object
cache.TryGetValue( ' Obj1 ' ,valueobj);Remover Value: Remove um objeto do cache.
Provedores de mecanismo de cache:
TcacheSerializerjson: usa JSON para serializar dados de cache.
Tcachecompressorgzip: usa GZIP para compactar dados de cache.
Tcachecompressorlzo: usa LZO para compactar dados de cache.
// create MemoryCache with 20 seconds purge interval and compression with LZO engine
cache := TMemoryCache.Create( 10 , nil ,TCacheCompressorLZO.Create);A inversão do Control Manager permite que o objeto instanciado com interface autocereado ou autoinjejasse nas classes construtores, para evitar a dependência.
Crie um contêiner para gerenciar a injeção de dependência.
iocContainer := TIocContainer.Create;Tipos de registro:
Você precisa registrar tipos antes de injetá -los. Um tipo pode ser registrado como Singleton, transitório. Singleton : O ciclo de vida será uma única instância para todas as injeções, semelhante a uma variável global. Transiente : o ciclo de vida será uma instância por cada injeção. Registre um tipo de interface no contêiner como transitório:
iocContainer.RegisterType<IMultService,TMultService>.AsTransient;Registre um tipo de interface como singleton, delegando construção:
iocContainer.RegisterType<ISumService,TSumService>.AsSingleTon.DelegateTo(
function : TSumService
begin
Result := TSumService.Create;
end
);Instâncias de registro:
Registre um objeto de instância nomeado como transitório, delegando construção:
iocContainer.RegisterInstance<TDivideService>( ' one ' ).AsTransient.DelegateTo(
function : TDivideService
begin
Result := TDivideService.Create(True);
end
);Opções de registro:
Registre ioptions (apenas singleton):
iocContainer.RegisterOptions<TMyOptions>(MyOptions);Resolver tipos:
AbractFactory: cria uma classe tentando resolver todo o parâmetro do método de criação com injeção de dependência.
MyClass := iocContainer.AbstractFactory<TMyBaseClass>(TMyClass);Resolva uma dependência da interface:
multservice := iocContainer.Resolve<IMultService>;
result := multservice.Mult( 2 , 4 );Resolva instâncias:
Resolva uma dependência de instância nomeada:
divideservice := iocContainer.Resolve<TDivideService>( ' other ' );
result := divideservice.Divide( 100 , 2 );As instâncias da interface serão libertadas automaticamente, mas as dependências de instância serão libertadas se definidas como singleton, instâncias transitórias serão destruídas pelo código.
Você define seções como classes e salva como configurações de arquivo único. Funciona semelhante às opções de dotnet. O arquivo de opções pode estar no formato JSON ou YAML.
Definir sua classe de opção herdada das tópicas e todas as propriedades publicadas serão carregadas/salvar. Crie o contêiner de opções, com JSonserializer e recarregar na mudança:
Options := TOptionsContainer.Create( ' .options.conf ' ,TJsonOptionsSerializer.Create,True);Adicione uma seção às opções de seu contêiner:
Options.AddSection<TLoggingOptions>( ' Logging ' )Configurar opções:
Você pode definir o nome da seção para salvar no arquivo e delegar as configurações de configuração e valores de validação:
Options.AddSection<TLoggingOptions>( ' Logging ' ).ConfigureOptions(
procedure(aOptions : TLoggingOptions)
begin
aOptions.Path := ' C: ' ;
end
).ValidateOptions;Validar opções:
As opções de validar permitem verificar se as configurações da opção são definidas entre os intervalos definidos. Essa validação precisa previamente atributos personalizados atribuídos às propriedades da sua classe de tópicas.
TLoggingOptions = class (TOptions)
private
fPath : string;
published
[Required, StringLength( 255 , ' Path too long ' )]
property Path : string read fPath write fPath;
[Range( 0.0 , 5.2 )]
property Level : Double read fLevel write fLevel;
end ;Use Opções: Para recuperar a seção de opções:
LoggingOptions := Options.GetSection<TLoggingOptions>;
LoggginOptions.Path := ' C:Path ' ;Use ioptions: as ioptions é uma interface injetável de dependência para as tópicas. Você pode se registrar no ioccontainer.registerOptions para tornar injetável nos métodos construtores.
UIOptions := Options.GetSectionInterface<TUIOptions>. Value ;
UIOptions.WindowColor := clBlue;Carregar/salvar opções:
Carregar opções nas configurações de arquivo:
options.Load;Salvar opções para configurações de arquivo:
options.Save;Se você definiu a criação de contêineres com o parâmetro RELOADOnchanged para true, sempre que as configurações de arquivo são alteradas, a configuração será recarregada. Se você precisar controlar quando recarregar, pode ouvir o evento:
Options.OnFileModified := procedure
begin
cout('Detected config file modification!',etWarning);
end;
Defina o pool de conexão, tópicos ou qualquer objeto que você queira controlar para evitar consumes de recursos, como conexões de banco de dados, clientes HTTP, etc ...
Crie pool de clientes HTTP:
pool := TObjectPool<THTTPClient>.Create( 5 , 5000 ,procedure( var aInstance : THTTPClient)
begin
aInstance := THTTPClient.Create;
aInstante.UserAgent := ' MyAgent ' ;
end );Obtenha objeto do pool:
httpcli := pool.Get.Item;
statuscode := httpcli.Get( ' https://www.mydomain.com ' ).StatusCode;Define a lista interface e objeto com o suporte do LINQ herdado.
myarray := [ ' Joe ' , ' Mat ' , ' Lee ' ];
// search for regex match
cout( ' Search for regex match ' ,ccYellow);
for name in myarray.Where( ' e$ ' ,True).Select do
begin
cout( ' User %s ends with "e" ' ,[ name ],etInfo);
end ;user := ListObj.Where( ' Profile.Name = ? ' ,[ ' Lee ' ]).SelectFirst;Pesquisa de expressão para a matriz de itens:
users := ListObj.Where( ' Roles CONTAINS ? ' ,[ ' SuperAdmin ' ]).Select;Pesquisa predicada:
user := ListObj.Where(function(aUser : TUser) : Boolean
begin
Result := aUser. Name .StartsWith( ' J ' );
end ).SelectFirst;
if user <> nil then cout( ' %s starts with J letter ' ,[user. Name ],etInfo);Consulte a seção Quick.Linq para visualizar mais funções permitidas.
Modelo de string Substituindo usando uma função de dicionário ou delegado. Você pode especificar chars de token citado.
Substitua a passagem de um dicionário:
dict := TDictionary<string,string>.Create;
dict.Add( ' User ' , ' John ' );
dict.Add( ' Age ' , ' 20 ' );
dict.Add( ' SurName ' , ' Peterson ' );
mytemplate := ' User {{User}} {{SurName}} are {{Age}} years old. ' ;
template := TStringTemplate.Create( ' {{ ' , ' }} ' ,dict);
Result := template.Replace(mytemplate);Substitua pela função delegada:
mytemplate := ' User {{User}} {{SurName}} are {{Age}} years old. ' ;
template := TStringTemplate.Create( ' {{ ' , ' }} ' ,function( const aToken : string) : string
begin
if token = ' User ' then Result := ' John '
else if token = ' Surname ' then Result := ' Peterson '
else if token = ' Age ' then Result := ' 20 ' ;
end );
Result := template.Replace(mytemplate);Debug utiliza -se para verificar o desempenho e obter o método de verificação do método de entrada e saída.Define com um depuração de uma diretiva de compilador apenas para estar ativo quando seu aplicativo é compilado no modo de depuração. On Console Apps usa o console por padrão. Você pode passar um madeireiro para produzir:
TDebugUtils.SetLogger(ilogger);Rastreie uma parte do seu código:
function TCalculator.Subs (a, b: Int64): Int64;
begin
{ $IFDEF DEBUG }
TDebugger.Trace(Self,Format( ' Substract %d - %d ' ,[a,b]));
{ $ENDIF }
Result := a - b;
// simulate working for 200ms
Sleep( 200 );
end ;
// Returns:
// 29-06-2020 23:31:41.391 [TRACE] TCalculator -> Substract 30 - 12Calcule o tempo a processar da função de ponto para saída:
function TCalculator.Sum (a, b: Int64): Int64;
begin
{ $IFDEF DEBUG }
TDebugger.TimeIt(Self, ' Sum ' ,Format( ' Sum %d + %d ' ,[a,b]));
{ $ENDIF }
Result := a + b;
// simulate working for 1 seconds
Sleep( 1000 );
end ;
// Returns:
// 29-06-2020 22:58:45.808 [CHRONO] TCalculator.Sum -> Sum 100 + 50 = 1,00sCalcule o tempo para processar da função Point a Point e Sair:
function TCalculator.Divide (a, b: Int64): Double;
begin
{ $IFDEF DEBUG }
var crono := TDebugger.TimeIt(Self, ' Divide ' ,Format( ' Divide %d / %d ' ,[a,b]));
{ $ENDIF }
Result := a / b;
// simulate working for 500ms
Sleep( 500 );
{ $IFDEF DEBUG }
crono.BreakPoint( ' Only divide ' );
{ $ENDIF }
// simulate working for 1 second
Sleep( 1000 );
{ $IFDEF DEBUG }
crono.BreakPoint( ' Only Sleep ' );
{ $ENDIF }
end ;
// Returns:
// 29-06-2020 23:25:46.223 [CHRONO] TCalculator.Divide -> First point = 500,18ms
// 29-06-2020 23:25:47.224 [CHRONO] TCalculator.Divide -> Second point = 1,00s
// 29-06-2020 23:25:47.225 [CHRONO] TCalculator.Divide -> Divide 10 / 2 = 1,50sObtenha notificação ao entrar e sair da função e vezes a ele:
function TCalculator.Mult (a, b: Int64): Int64;
begin
{ $IFDEF DEBUG }
TDebugger.Enter(Self, ' Mult ' ).TimeIt;
{ $ENDIF }
Result := a * b;
// simulate working for 2 seconds
Sleep( 2000 );
end ;
// Returns:
// 29-06-2020 22:58:45.808 [ENTER] >> TCalculator.Mult
// 29-06-2020 22:58:47.810 [EXIT] >> TCalculator.Mult in 2,00s Trabalhar com os parâmetros de linha de comando será fácil usando a extensão de comando. Defina uma classe herdada de TParameters ou TServiceParameters (se estiver trabalhando com QuickAppservices) com seus argumentos possíveis como propriedades publicadas:
uses
Quick.Parameters;
type
TCommand = (Copy, Move, Remove);
TMyMode = (mdAdd, mdSelect, mdRemove);
[CommandDescription( ' Simple console application example with Quick.Parameters ' )]
TMyParameter = class (TParameters)
private
fCommand : TCommand;
fHost : string;
fPort : Integer;
fRetries : Integer;
fUseTCP : Boolean;
fConfigFile: string;
fSilent: Boolean;
fMyMode: TMyMode;
fLogErrorsConsole: Boolean;
fLogErrors: Boolean;
fShowReport: Boolean;
published
[ParamCommand( 1 )]
[ParamRequired]
[ParamHelp( ' Command action. ' , ' command-action ' )]
property Command : TCommand read fCommand write fCommand;
[ParamName( ' HostName ' ),ParamRequired]
[ParamHelp( ' Define host to connect. ' , ' host ' )]
property Host : string read fHost write fHost;
[ParamName( ' Port ' , ' p ' )]
[ParamValueIsNextParam]
[ParamHelp( ' Define Port to connect (default 80) ' , ' port ' )]
property Port : Integer read fPort write fPort;
[ParamHelp( ' Number of max retries. ' )]
property Retries : Integer read fRetries write fRetries;
[ParamHelp( ' Path to config. ' , ' path ' )]
[ParamName( ' Config-file ' )]
property ConfigFile : String read fConfigFile write fConfigFile;
[ParamHelp( ' Silent mode. ' )]
property Silent : Boolean read fSilent write fSilent;
[ParamHelp( ' Modes (mdAdd, mdSelect, mdRemove) ' )]
property Mode : TMyMode read fMyMode write fMyMode;
end ;
Use Param:
params := TMyParameter.Create;Quando você liga para o seu exe com -Help, você recebe documentação. Se você precisar verificar se uma opção ou valor, pode fazer assim:
if params.Port = 0 then ...
if params.Silent then ...O QuickParameters usa atributos personalizados para definir condições especiais de parâmetros:
CommandDescription: define texto para descrever seu aplicativo na documentação de ajuda.
ParamCommand (número): define a posição estática no comando linha para parâmetros únicos.
ParamName (nome, alias): defina um nome diferente para o parâmetro. Permite usar caracteres especiais não permitidos para propriedades de classe (como nomes de arquivo ou config.file). O argumento de alias opcional define um nome de parâmetro alternativo (normalmente nome curto).
ParamHelp (HelpText, Valuename): Define um texto de ajuda com comando e nome de valor na seção de uso.
ParamSwitchchar (sinal): define string ou char para indicar o comutador ou o parâmetro. Se não for definido, um traço duplo (-) será usado por padrão.
ParamValueSeParator (sinal): define string ou char para separar o nome do parâmetro do value (filename = config.json). Se não for definido, o sinal igual (=) será usado por padrão.
ParamvalueIsNextParam: define um parâmetro com um valor sem valor separador (nome do arquivo c: config.ini)
Paramrequired: define um parâmetro conforme necessário. Se param não for encontrado, uma exceção será levantada.
O QuickParameter verifica automaticamente os tipos de valor. Se você definir um valor de parâmetro como número inteiro e passar por um alfanumérico, será aumentada uma exceção.
Ajude a personalização: você pode definir sua própria personalização de cores com o ColorizeHelp. A propriedade ativada usará cores personalizadas, caso contrário, B/W será usado.
Parameters.ColorizeHelp.Enabled := True;
Parameters.ColorizeHelp.CommandName := ccCyan;
Parameters.ColorizeHelp.CommandUsage := ccBlue;Quando os parâmetros detectarem o parâmetro de ajuda, a documentação de ajuda será mostrada.
Parameters.showHelp: mostra a documentação de ajuda, gerada automaticamente:
Parameters v.1.0
Usage: Parameters <command-action> <--HostName=<host>> [--Port <port>] [--Retries=<value>]
[--Config-file=<path>] [--UseTCP] [--Silent] [--Mode=<value>]
[--ShowReport] [--Help]
Simple console application example with Quick.Parameters
Arguments:
Command Command action.
--HostName Define host to connect.
--Port, -p Define Port to connect (default 80)
--Retries Number of max retries.
--Config-file Path to config.
--UseTCP Use TCP connection if present.
--Silent Silent mode.
--Mode Modes (mdAdd, mdSelect, mdRemove)
--Help, -h Show this documentation
Valitações comumente usadas.
Valitações pré e pós -condicionamento em estilo fluente. Condição. Os requisitos avaliam uma variável para condições antes de fazer algumas operações. Condition.Ensures Avalia um resultado variável para as condições após algumas operações.
Condition.Requires(num, " num " )
.IsInRange( 1 , 10 , ' value for num is out of range ' ); // throws custom error if not in range
.IsNotGreater( 50 ); // throws ArgumentException if not equal to 128
Condition.Requires(myobj, " myobj " )
.WithExceptionOnFailure(EMyException) // throws specific exception on failure
.IsNotNull() // throws ArgumentNullException if null
.Evaluate(myobj.id > 10 ); // myobj.id must be greater than 10
Condition.Requires(text, " text " )
.IsNotEmpty() // throws ArgumentNullException if empty
.StartsWith( " <html> " ) // throws ArgumentException if not starts with <html>
.EndsWith( " </html> " ) // throws ArgumentException if not ends with </html>
.IsNotLowerCase // thows ArgumentException if not lowercase
.Evaluate(text.Contains( " sometxt " ) or test.Contains( ' othertxt ' )); // throws ArgumentException if not evaluatesVocê quer aprender Delphi ou melhorar suas habilidades? LearnDelphi.org