it编程 > 编程语言 > Delphi

Quick Library 简介

166人参与 2024-05-16 Delphi

quicklib 是一个快速开发库

quicklib是一个快速开发库,它提供了诸如automapper、linq、ioc依赖注入、memorycache、计划任务、json和yml配置、序列化程序等多种功能。这个库特别支持delphi和firemonkey的多平台开发,包括windows、linux、android、osx和ios。同时,quicklib也支持freepascal,使得开发人员能够更轻松地构建跨平台应用程序并提高生产力。

功能领域:

主要单元描述:

quick.appservice

允许控制台应用程序以控制台模式或服务模式运行相同的代码,从而简化调试任务。

if not appservice.isrunningasservice then
begin
    ...你的代码以控制台模式运行
end
else
begin
    appservice.servicename := 'myservice';
    appservice.displayname := 'myservicesvc';
    //你可以将匿名方法传递给事件
    appservice.onstart := procedure
                          begin
                            ...你的启动代码
                          end;
    appservice.onexecute := yourexecutefunction;
    appservice.onstop := yourstopfunction;
    appservice.checkparams;
end;

quick.azure/amazon:

简化了与azure和amazon云存储的blob交互。

//连接到azure blob存储
quickazure := tquickazure.create(azureaccountname, azureaccountkey);

//将blob文件下载到流中
done := quickazure.getblob('mycontainer', 'myfile.jpg', responseinfo, mystream);
  
//检查是否存在文件夹
found := existfolder('mycontainer', '/public/documents/personal');
  
//列出以特定模式开头的blobs(递归或非递归)
for azblob in listblobs('mycontainer', '/public/documents', recursive, responseinfo) do
begin
    if azblob.size > 1000 then showmessage(azblob.name);
end;

quick.network:

提供cidr和ip范围功能。

//将ip字符串转换为整数
ipv4toint('192.168.1.10');

//获取子网范围的第一个和最后一个ip
getiprange('192.168.100.0', '255.255.255.0', lowip, highip);

quick.commons:

开发人员日常工作中经常需要的函数。

//将utc时间tdatetime转换为本地日期时间
utctolocaltime(myutctime);
  
//生成一个长度为10的随机密码,包含字母数字和符号。
randompassword(10, [pfincludenumbers, pfincludesigns]);

//将短语中的每个单词首字母大写
capitalizeall('the grey fox'); //返回 "the grey fox"

//简单的tcounter和ttimecounter用于循环
counter := tcounter;
counter.init(200);
timecounter : ttimecounter;
timecounter.init(10000);
while true do
begin
    inc(n);
    {你的过程处理代码在这里}
    //每200步写入控制台
    if counter.check then writeln(format('processed %d entries', [n]));
    //每10秒写入控制台
    if timecounter.check then writeln('im working...'); 
end;

quick.chrono:

计时器和代码基准测试很简单。

//获取代码部分执行所消耗的时间
chrono := tchronometer.create(false);
chrono.start;
...你需要基准测试的代码
chrono.stop;

//以长时间格式显示经过的时间(例如2小时10分钟)
showmessage(chrono.timeelapsed(true));

//以短时间格式显示经过的时间(例如02:10:00)
showmessage(chrono.timeelapsed(false));
//获取进程的基准测试信息
chrono := tchronobenchmark.create;
chrono.totalprocess := 100000;
for i := 1 to 10000 do
begin
    {你的进程代码在这里}
    chrono.currentprocess := i;
    //显示你的进程预计需要的时间,格式为x小时x分钟x秒
    writeln(chrono.estimatedtime(true));
    //显示你的进程处理速度:每秒处理的项数
    writeln(format('items processed %d/sec', [chrono.speed]));
end;
writeln(chrono.elapsedtime(false)); //以00:00:00格式显示总经过时间

quick.console:

将日志消息以不同颜色等写入控制台。

//定义需要的输出级别
console.verbose := log_debug;

//以红色在控制台上写行
cout('error x', eterror); 

//以绿色格式化输出行
coutfmt('proccess %s finished', [proccesname], etsuccess);

//写整数
cout(12348);

//连接quicklog并一行代码同时写入磁盘和屏幕(具有独立的详细级别)
myquicklog := tquicklog.create;
myquicklog.verbose := log_all;
console.verbose := log_onlyerrors;
console.log := myquicklog;

quick.log:

记录到磁盘或内存,具有详细的日志等级和每日或最大空间轮换功能。

// 在开始时写入包含运行路径、应用程序名称、调试模式、用户等信息的页眉
log.showheader := true;// 设置20mb时轮换的日志
log.setlog('.\mylog.log',false,20);// 写入一条错误信息
log.add('error x',eterror);// 写入格式化的错误信息
log.add('error is %s',[errorstr],eterror);quick.config:
以json、yaml文件或windows注册表项的形式加载/保存配置。从tappconfigjson、tappconfigyaml或tappconfigregistry创建一个派生类,并添加将加载/保存的已发布的属性。当检测到文件更改时,可以重新加载文件配置。// 创建一个类继承
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;// 将配置创建为json文件
// 在您的uses中添加quick.config.json
myconfig := tmyconfig.create('config.json');
myconfig.provider.createifnotexists := true;
myconfig.provider.reloadiffilemodified := true;
myconfig.name := 'john';
myconfig.surname := 'smith';
// 加载
myconfig.load;
// 保存
myconfig.save;// 将配置创建到windows注册表中
// 在您的uses中添加quick.config.registry
myconfig := tmyconfig.create;
// 将注册表定义为hkey_current_user\software\myapp
myconfig.hroot := hkey_current_user;
myconfig.mainkey := 'myapp';
myconfig.name := 'john';
myconfig.surname := 'smith';
// 加载
myconfig.load;
// 保存
myconfig.save;// 创建一个没有默认提供者的自定义配置
tmyconfig = class(tappconfig)
... 您的属性
end;myconfig := tmyconfig.create(tappconfigjsonprovider.create('.\config.json');

quick.filemonitor:

监视文件的更改并触发事件。

filemonitor.filename := '.\myfile.txt';
// 每2秒检查一次文件更改
filemonitor.interval := 2000;
// 监视文件被删除或修改的事件
filemonitor.notifies := [mnfilemodified, mnfiledeleted)];
filemonitor.onfilechange := myfilechangefunction;
filemonitor.enabled := true;

quick.jsonutils:

用于处理json对象的工具。

// 当在uses中声明单元时,tobject helper允许将所有对象从/加载到json字符串
myobject.fromjson := jsonstring;
mystring := myobject.tojson;// 您可以使用clone函数克隆简单对象
myobject1.clone(myobject2);

quick.smtp:

用两行代码发送电子邮件。

// 发送电子邮件
smtp := tsmtp.create('mail.domain.com',25,false);
smtp.sendmail('my@email.com','to@email.com','email subject','my message body');// 您可以定义更高级的选项
smtp.sendername := 'john';
smtp.from := 'my@email.com';
smtp.recipient := 'one@email.com,two@email.com';
smtp.subject := 'email subject';
smtp.addbodyfromfile := '.\body.html';
smtp.cc := 'other@email.com';
smtp.bcc := 'more@email.com';
smtp.attachments.add('.\notes.txt');
smtp.sendmail;

quick.threads:

线程安全类。

tthreadedqueuecs: 使用临界区的tthreadedqueue版本。

tthreadobjectlist: 线程安全的对象列表。

tthreadedqueuelist: 线程安全的队列列表。支持自动增长和临界区。

tanonymousthread: 创建匿名线程,定义非链式的execute和onterminate方法。如果代码需要更新ui,请使用execute_sync和onterminate_sync方法。

// 简单的匿名线程
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: 启动一个自动释放的单任务线程,具有故障和重试控制策略。可以在代码中传递和创建参数。

  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: 在后台启动任务,允许一定数量的并发工作线程,并具有故障和重试控制策略。如果代码需要更新ui,请使用addtask_sync和onterminate_sync方法。

    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: 定时器的替代方案。您可以分配具有开始时间、重复选项、到期日期和故障及重试控制策略的任务。如果代码需要更新ui,请使用addtask_sync、onterminate_sync和onexpired_sync方法。
您可以为执行、异常、终止和到期事件分配匿名方法。

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: 传递给truntask、tbackgroundtasks和tscheduledtasks的每个任务事件的接口。

quick.faultcontrol:

管理失败和重试策略,定义最大重试次数、重试之间的等待时间和熔断机制。

quick.process:

管理windows进程。

// 终止explorer进程
killprocess('explorer.exe');
// 判断一个应用程序是否正在运行
if isprocessrunning('explorer.exe') then showmessage('explorer正在运行!');
// 获取运行exe的用户名
writeln('explorer.exe由以下用户打开:' + getprocessuser('explorer.exe'));
// 使用20秒的超时获取窗口句柄
if findwindowtimeout('mainwindow',20) then writeln('检测到窗口');

quick.services:

管理windows服务。

// 检测服务是否已安装
if not serviceispresent('localhost','mysvc') then raise exception.create('服务未安装!');
// 启动服务
servicestart('localhost','mysvc');
// 卸载服务
serviceuninstall('mysvc');

quick.format:

字符串格式化。

// 将字节格式化为mb、gb、tb...
formatbytes(50000) // 显示 50kb
formatbytes(90000000) // 显示 90mb

quick.jsonserializer:

将对象序列化为json文本或从json文本反序列化为对象。您可以定义是否处理公开或已发布的属性(仅delphi,fpc rtti仅支持已发布的属性)。

json := '{"name":"peter","age":30}';
serializer := tjsonserializer.create(tserializelevel.slpublishedproperty);
try
   serializer.jsontoobject(user,json);
finally
   serializer.free;
end;

quick.automapper:

将一个类的字段映射到另一个类。允许自定义映射以匹配不同的字段,并允许自定义映射过程以手动转换字段。

// 将user1的值映射到user2
tmapper<tuser2>.map(user);

// 自定义映射
automapper := tautomapper<tuser,tuser2>.create;

// 选项1:您可以定义自动映射不同名称的属性
automapper.custommapping.addmap('cash','money');
automapper.custommapping.addmap('id','iduser');

// 选项2:您可以决定手动修改每个属性或允许自动映射某些属性
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;

// 选项3:您可以在自动映射完成后修改某些属性
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:

用作dto类,包含json序列化和映射功能。

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;
   // 展示为json字符串
   writeln(user.tojson);
   // 映射到其他类
   user.mapto(user2);
   writeln(user2.tojson);
   // 从文件加载
   user.loadfromfile('.\user.json');
   // 保存到文件
   user2.savetofile('.\user2.json');
end;

quick.lists:

带有索引或搜索功能的改进列表。

var
   users : tindexedobjectlist<tuser>;
begin
   users := tindexedobjectlist<tuser>.create(true);
   // 根据属性"name"创建索引
   users.indexes.add('name','name',tclassfield.cfproperty);
   // 根据私有字段"id"创建索引
   users.indexes.add('id','fid',tclassfield.cffield);
   // 通过"name"索引获取用户
   writeln(users.get('name','peter').surname);
end;

quick.value

flexvalue可以存储任何数据类型,并允许使用集成操作符和自动释放功能传递给其他类。

var
  value : tflexvalue;
  str : string;
  num : integer; 
begin
  value := 'hello';
  str := value;
  value := 123;
  num := value;
end;

quick.arrays:

改进的数组。

txarray: 带有类似tlist方法的数组。

(注意:下面的代码段似乎被错误地复制了 tindexedobjectlist的示例,这里应该展示 txarray的使用。)

var
   users : txarray<tuser>;
begin
   users := txarray<tuser>.create;
   users.add(user); // 假设user已经是一个tuser类型的对象
   // ... 其他txarray的操作
end;

tflexarray: 可以存储不同值类型的数组,类似于tlist。

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: 可以存储不同值类型的数组,并可以通过项目名称进行搜索,类似于tlist。

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对象结构。

tyamlobject: yaml对象是一个yaml值对的数组。

// 从yaml文本创建yaml对象
yamlobj.parseyamlvalue(ayaml);
// 添加一个对
yamlobj.addpair('name','mike');
// 显示为yaml结构
writeln(yamlobj.toyaml);

tyamlarray: 对象或标量的数组。

yamlarray.addelement(tyamlpair.create('age',30));
yamlobj.addpair('myarray',yamlarray);

tyamlpair: 名称-值对。值可以是对象、数组或标量。

n := yamlobj.getpair('name').value as tyamlinteger;

quick.yaml.serializer:

将对象序列化/反序列化为yaml。

// 序列化
text := yamlserializer.objecttoyaml(obj);
// 反序列化
yamlserializer.yamltoobject(obj, yamltext);

quick.expression:

使用表达式评估对象属性或单个值。

if texpressionparser.validate(user, '(age > 30) and (dept.name = "financial")') then
begin
  // 执行一些操作
end;

if texpressionparser.validate(user, '(20 > 30) or (5 > 3)') then
begin
  // 执行一些操作
end;

quick.linq:

对任何 tobjectlist<t>tlist<t>tarray<t>txarray<t>执行linq查询,通过类似sql语法的复杂where子句进行select、更新和排序列表。where子句使用命名空间来确定嵌套属性。linq可以在属性数组中搜索元素。
现在包括一个 tarray<string>助手,用于在数组中添加、删除和通过正则表达式搜索。

// 多条件选择
for user in tlinq<tuser>.from(userslist).where('(name = ?) or (surname = ?) or (surname = ?)', ['peter', 'smith', 'huan']).select do
begin
  // 执行一些操作
end;

// 选择并更新字段
tlinq<tuser>.from(userlist).where('surname like ?', ['%son']).selectfirst.name := 'robert';

// 选择顶部并按字段排序
for user in tlinq<tuser>.from(userlist).where('age > ?', [18]).selecttop(10).orderby('name') do
begin
  // 执行一些操作
end;

// 按条件更新字段
tlinq<tuser>.from(userlist).where('name = ?', ['peter']).update(['name'], ['joe']);

// 计数结果
numusers := tlinq<tuser>.from(userlist).where('(age > ?) and (age < ?)', [30, 40]).count;

quick.httpserver:

tcustomhttpserver是一个简单的接口httpserver,具有自己的httprequest和httpresponse实现,允许轻松更改httpserver引擎。
您可以启用自定义错误页面以返回自定义页面和动态错误页面。
thttpserver是indyhttpserver的实现,但您可以定义自己的实现。

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;

quick.memorycache:

使用过期时间缓存对象或字符串,以避免每次需要时都生成这些信息(数据库查询、难以计算的信息等)。tmemorycache允许缓存对象和字符串。泛型版本tmemorycache <t>仅允许缓存定义的类型。

// 创建具有10秒清除间隔的memorycache
cache := tmemorycache.create(10);

// 为特定类型创建memorycache
cache := tmemorycache<tmyobj>.create;
// 将字符串设置到缓存中,没有过期时间
cache.setvalue('mystring', 'hello world');

// 将字符串设置到缓存中,10秒后过期
cache.setvalue('mystring', '这个缓存将在10秒后过期');

// 将对象设置到缓存中
cache.setvalue('obj1', valueobj);
// 获取字符串查询结果
cache.getvalue('query12');

// 获取整数
cache.trygetvalue<integer>('number', valueint);

// 获取对象
cache.trygetvalue('obj1', valueobj);
// 创建具有20秒清除间隔并使用lzo引擎压缩的memorycache
cache := tmemorycache.create(10, nil, tcachecompressorlzo.create);

quick.ioc:

控制反转管理器允许自动创建接口或实例化对象,或在构造函数类中自动注入它们,以避免依赖关系。

创建一个容器来管理依赖注入。

ioccontainer := tioccontainer.create;

注册类型:

在注入之前,您需要注册类型。类型可以作为singleton或transient注册。
singleton:生命周期将是所有注入的一个单一实例,类似于全局变量。
transient:生命周期将是每次注入的一个新实例。

将接口类型作为transient注册到容器中:

ioccontainer.registertype<imultservice, tmultservice>.astransient;

将接口类型作为singleton注册,并委托构造:

ioccontainer.registertype<isumservice, tsumservice>.assingleton.delegateto(
  function : tsumservice
  begin
    result := tsumservice.create;
  end
);

注册实例:

将命名实例对象作为transient注册,并委托构造:

ioccontainer.registerinstance<tdivideservice>('one').astransient.delegateto(
  function : tdivideservice
  begin
    result := tdivideservice.create(true);
  end
);

注册选项:

注册ioptions(仅适用于singleton):

ioccontainer.registeroptions<tmyoptions>(myoptions);

解析类型:

abstractfactory:
尝试使用依赖注入解析所有创建方法参数来创建类。

myclass := ioccontainer.abstractfactory<tmybaseclass>(tmyclass);

解析接口依赖:

multservice := ioccontainer.resolve<imultservice>;
result := multservice.mult(2, 4);

解析实例:

解析命名实例依赖:

divideservice := ioccontainer.resolve<tdivideservice>('other');
result := divideservice.divide(100, 2);

接口实例将自动释放,但实例依赖项仅当定义为singleton时才会被释放,transient实例将由代码销毁。#3

quick.options:

您可以将部分定义为类,并将其保存为单个文件设置。其工作方式类似于dotnet options。选项文件可以是json或yaml格式。

定义从toptions继承的选项类,所有已发布的属性都将被加载/保存。
创建选项容器,使用jsonserializer并在更改时重新加载:

options := toptionscontainer.create('.\options.conf', tjsonoptionsserializer.create, true);

向容器选项添加一个部分:

options.addsection<tloggingoptions>('logging');

配置选项:

您可以定义要保存到文件中的部分名称,并委托配置默认设置和验证值:

options.addsection<tloggingoptions>('logging').configureoptions(
  procedure(aoptions: tloggingoptions)
  begin
    aoptions.path := 'c:\';
  end
).validateoptions;

验证选项:

验证选项允许验证选项设置是否在定义的范围内。此验证需要先在toptions类中的属性上分配自定义属性。

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;

使用选项:
检索选项部分:

loggingoptions := options.getsection<tloggingoptions>;
loggingoptions.path := 'c:\path';

使用ioptions:
ioptions是一个可注入依赖的toptions接口。您可以使用ioccontainer.registeroptions <toptions>注册它以使其可注入到构造函数方法中。

uioptions := options.getsectioninterface<tuioptions>.value;
uioptions.windowcolor := clblue;

加载/保存选项:

从文件设置中加载选项:

options.load;

将选项保存到文件设置:

options.save;

如果您在创建容器时定义了reloadonchanged参数为true,则每次文件设置更改时,配置都将重新加载。如果您需要控制何时重新加载,可以监听事件:

options.onfilemodified := procedure
  begin
    cout('detected config file modification!', etwarning);
  end;

quick.pooling:

定义连接池、线程池或您想要控制的任何对象池,以避免资源消耗,如数据库连接、http客户端等。

创建http客户端池:

pool := tobjectpool<thttpclient>.create(5, 5000, procedure(var ainstance: thttpclient)
        begin
          ainstance := thttpclient.create;
          ainstance.useragent := 'myagent';
        end);

从池中获取对象:

httpcli := pool.get.item;
statuscode := httpcli.get('https://www.mydomain.com').statuscode;

quick.collections:

定义了具有linq支持的接口list和objectlist。

myarray := ['joe', 'mat', 'lee'];
// 搜索正则表达式匹配项
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;

对项数组的表达式搜索:

users := listobj.where('roles contains ?', ['superadmin']).select;

谓词搜索:

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);

查看quick.linq部分以查看更多允许的函数。

quick.template:

使用字典或委托函数进行字符串模板替换。您可以指定引号的标记字符。

通过传递字典进行替换:

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);

使用委托函数进行替换:

mytemplate := 'user {{user}} {{surname}} are {{age}} years old.';
template := tstringtemplate.create('{{', '}}', function(const atoken: string): string
  begin
    if atoken = 'user' then result := 'john'
    else if atoken = 'surname' then result := 'peterson'
    else if atoken = 'age' then result := '20';
  end);
result := template.replace(mytemplate);

quick.debug.utils:

调试工具,用于检查性能并获取进入和退出方法的检查点。通过debug编译器指令定义,仅在应用程序以调试模式编译时激活。
在控制台应用程序中,默认使用控制台输出。您可以传递一个记录器以输出到:

tdebugutils.setlogger(ilogger);

跟踪代码的一部分:

function tcalculator.subs(a, b: int64): int64;
begin
  {$ifdef debug}
  tdebugger.trace(self, format('substract %d - %d', [a, b]));
  {$endif}
  result := a - b;
  // 模拟工作200毫秒
  sleep(200);
end;
// 返回:
// 29-06-2020 23:31:41.391  [trace] tcalculator -> substract 30 - 12

计算从点到退出函数的处理时间:

function tcalculator.sum(a, b: int64): int64;
begin
  {$ifdef debug}
  tdebugger.timeit(self, 'sum', format('sum %d + %d', [a, b]));
  {$endif}
  result := a + b;
  // 模拟工作1秒
  sleep(1000);
end;
// 返回:
// 29-06-2020 22:58:45.808  [chrono] tcalculator.sum -> sum 100 + 50 = 1,00s

计算从点到点以及退出函数的处理时间:

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;
  // 模拟工作500毫秒
  sleep(500);
  {$ifdef debug}
  crono.breakpoint('only divide');
  {$endif}
  // 模拟工作1秒
  sleep(1000);
  {$ifdef debug}
  crono.breakpoint('only sleep');
  {$endif}
end;
// 返回:
// 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,50s

当进入和退出函数时获取通知,并计算时间:

function tcalculator.mult(a, b: int64): int64;
begin
  {$ifdef debug}
  tdebugger.enter(self, 'mult').timeit;
  {$endif}
  result := a * b;
  // 模拟工作2秒
  sleep(2000);
end;
// 返回:
// 29-06-2020 22:58:45.808  [enter] >> tcalculator.mult
// 29-06-2020 22:58:47.810  [exit] >> tcalculator.mult in 2,00s

quick.parameters:

使用命令行扩展,可以轻松处理命令行参数。
定义一个从tparameters或tserviceparameters(如果使用quickappservices)继承的类,将可能的参数作为已发布的属性:

uses
  quick.parameters;
type
  tcommand = (copy, move, remove);
  tmymode = (mdadd, mdselect, mdremove);

  [commanddescription('使用quick.parameters的简单控制台应用程序示例')]
  tmyparameter = class(tparameters)
  private
    // ... [私有成员]
  published
    // ... [已发布的属性]
  end;

使用参数:

params := tmyparameter.create;

当您使用--help调用exe时,将获得文档。如果需要检查开关或值,可以这样做:

if params.port = 0 then ...
if params.silent then ...

quickparameters使用自定义属性来定义特殊的参数条件:

quickparameter会自动检查值类型。如果将参数值定义为integer,并传递了字母数字值,将引发异常。

帮助定制:
您可以使用colorizehelp定义自己的颜色定制。如果enabled属性为true,则使用自定义颜色,否则使用黑白颜色。

parameters.colorizehelp.enabled := true;
parameters.colorizehelp.commandname := cccyan;
parameters.colorizehelp.commandusage := ccblue;

当参数检测到帮助参数时,将显示帮助文档。

parameters.showhelp: 显示自动生成的帮助文档。

quick.url.utils:

quick.regex.utils:

常用验证工具。
(此部分未给出具体示例代码)

quick.conditions:

以流畅风格进行前置条件和后置条件的验证。
condition.requires在执行某些操作之前评估变量的条件。
condition.ensures在执行某些操作之后评估变量结果的条件。

condition.requires(num, "num")
    .isinrange(1, 10, 'value for num is out of range');   // 如果不在范围内,则抛出自定义错误
    .isnotgreater(50);   // 如果不等于50,则抛出argumentexception

condition.requires(myobj, "myobj")
    .withexceptiononfailure(emyexception) // 如果失败,则抛出特定异常
    .isnotnull();          // 如果为null,则抛出argumentnullexception
    .evaluate(myobj.id > 10); // myobj.id必须大于10

condition.requires(text, "text")
    .isnotempty();          // 如果为空,则抛出argumentnullexception
    .startswith("<html>") // 如果不以<html>开头,则抛出argumentexception
    .endswith("</html>") // 如果不以</html>结尾,则抛出argumentexception
    .isnotlowercase; // 如果不是小写,则抛出argumentexception
    .evaluate(text.contains("sometxt") or text.contains('othertxt')); // 如果不满足条件,则抛出argumentexception

你想学习delphi或提高你的技能吗?访问 learndelphi.org

(0)
打赏 微信扫一扫 微信扫一扫

您想发表意见!!点此发布评论

推荐阅读

mORMot2 的 Logger日志

05-16

delphi JSON序列化(四)

05-16

解决升级到 Delphi 12 后遇到 SQLite 不兼容的问题

05-16

mormot2 笔记(二) Http服务的简单搭建

05-12

delphi redisclient测试

05-12

Delphi 实现刘谦春晚魔术

05-12

猜你喜欢

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论