terça-feira, 22 de janeiro de 2013

Threads

Olá!

Deparei-me com uma discussão bastante interessante sobre o uso de thread. Achei por bem compartilhar o link:

http://extremeprogramming.wordpress.com/2011/12/19/o-que-voce-precisa-saber-sobre-threads-delphi/

É isto.

sábado, 15 de setembro de 2012

Utilizando o Corretor Ortográfico do Google

Olá amigons!

Recentemente tive a necessidade de implementar um corretor ortográfico em uma solução Delphi.

Pedi algumas indicações e me sugeriram:

http://www.devmedia.com.br/corretor-ortografico-no-delphi/2544
http://devexpress.com/Products/VCL/ExSpellChecker/

Não cheguei a testá-los mas foram muito bem recomendados.

Mas durante minhas pesquisas acabei me deparando com uma solução do Google.

Eu não tenho certeza, e se algum leitor for mais bem informado e puder fazer a gentileza de colocar as suas considerações nos comentários, mas o Google tem um recurso chamado Google Tool Bar Proxy e um dos recursos oferecidos é justamente o de correção ortográfica.

A URL do serviço é:

http://www.google.com/tbproxy/spell?lang=pt&hl=pt

Basicamente deve-se fazer um POST (HTTP) com um conteúdo XML e analisar o retorno.

Vamos imaginar então a palavra "coracao". O XML de requisição seria:



 coracao


E uma resposta válida seria algo como:



 coração


Indo ao ponto, desenvolvi o código abaixo devidamente comentado. É um projeto do tipo console.

É um ótimo exemplo pois tem uma pitada de XML e Expressão Regular.
Confesso que levei algumas boas horas para desenvolver este exemplo.

Me atrapalhei com o TXMLDocument e o UTF-8. Graças a este post de Caio Oliveira consegui resolver e me dei conta de um aparente bug. Achei estranho, mas de fato foi a solução.

Neste projeto foi desenvolvido a classe TCorretor onde efetivamente esta a solução.

program CorretorOrtografico;

{$APPTYPE CONSOLE}
{$R *.res}

uses System.SysUtils,
  Xml.XMLDoc,
  Xml.XMLIntf,
  IdHTTP,
  System.Classes,
  WinApi.ActiveX,
  System.RegularExpressions,
  IdGlobal;

type

  /// 
  /// Implementa o recurso de correção ortográfica oferecido pelo Google
  /// 
  /// 
  /// Descende de TComponent para servir de base para o XMLDocument
  /// 
  /// 
  /// José Mário Silva Guedes - jmarioguedes@gmail.com - eugostododelphi.blogspot.com
  /// 
  TCorretor = class(TComponent)
  private
    /// 
    /// Estrutura do documento XML
    /// 
    FXML: TXMLDocument;
    /// 
    /// Comunicação HTTP
    /// 
    FHTTP: TidHTTP;
  public
    procedure AfterConstruction; override;
    /// 
    /// Processa efetivamente o corretor ortográfico
    /// 
    ///     /// Texto de entrada
    ///     ///     /// Possibilidades de correção
    ///     ///     /// Motivo de um eventual insucesso
    ///     /// 
    /// Indica o sucesso da operação
    /// 
    function Processar(AEntrada: string; ASaida: TStrings; AMotivo: string): Boolean;
  end;

var
  bRet     : Boolean;
  oCorretor: TCorretor;
  sEntrada : string;
  slSaida  : TStringList;
  sMotivo  : string;
  sPalavra : string;
  cSaida   : Char;
  { TCorretor }

procedure TCorretor.AfterConstruction;
begin
  inherited;
  Self.FHTTP := TidHTTP.Create(Self);
  Self.FXML := TXMLDocument.Create(TDataModule.Create(Self));
end;

function TCorretor.Processar(AEntrada: string; ASaida: TStrings; AMotivo: string): Boolean;
const
  C_URL = 'http://www.google.com/tbproxy/spell?lang=pt&hl=pt';
var
  oRequest  : TStringStream;
  oResponse : TStringStream;
  sResponse : string;
  sRequest  : string;
  sResultado: string;
  _raiz     : IXMLNode;
  _texto    : IXMLNode;
  _resultado: IXMLNode;
  aPartes   : TArray;
begin
  oRequest := nil;
  oResponse := nil;
  try
{$REGION 'Preparando o pedido'}
    Self.FXML.Active := False;
    Self.FXML.Active := True;
    Self.FXML.Version := '1.0';
    Self.FXML.Encoding := 'UTF-16';

    _raiz := Self.FXML.AddChild('spellrequest');
    _raiz.Attributes['textalreadyclipped'] := '0';
    _raiz.Attributes['ignoredups'] := '0';
    _raiz.Attributes['ignoredigits'] := '1';
    _raiz.Attributes['ignoreallcaps'] := '0';

    _texto := Self.FXML.CreateNode('text');
    _texto.Text := AEntrada;
    _raiz.ChildNodes.Add(_texto);
{$ENDREGION}
{$REGION 'Gambiarra do UTF-8'}
    Self.FXML.SaveToXML(sRequest);
    // http://www.caiooliveira.com.br/?p=422
    // http://qc.embarcadero.com/wc/qcmain.aspx?d=37433
    sRequest := TRegEx.Replace(sRequest, 'UTF-16', 'UTF-8');
    oRequest := TStringStream.Create;
    oRequest.WriteString(sRequest);
    oRequest.Seek(0, 0);
{$ENDREGION}
{$REGION 'Request\Response'}
    Self.FHTTP.Request.Accept := 'text/xml';
    Self.FHTTP.Request.ContentType := 'text/xml';
    Self.FHTTP.Request.ContentEncoding := 'utf-8';
    oResponse := TStringStream.Create;
    Self.FHTTP.Post(C_URL, oRequest, oResponse);
    sResponse := UTF8ToString(RawByteString(oResponse.DataString));
    Self.FXML.Active := False;
    Self.FXML.LoadFromXML(sResponse);
{$ENDREGION}
{$REGION 'Analisando a resposta'}
    _resultado := Self.FXML.DocumentElement.ChildNodes.FindNode('c');
    while (Assigned(_resultado)) do
    begin
      sResultado := _resultado.Text;
      aPartes := TRegEx.Split(sResultado, #9);
      for sResultado in aPartes do
      begin
        ASaida.Add(sResultado);
      end;
      _resultado := _resultado.NextSibling;
    end;
    Result := True;
{$ENDREGION}
  finally
    if (Assigned(oRequest)) then
    begin
      oRequest.Free;
    end;
    if (Assigned(oResponse)) then
    begin
      oResponse.Free;
    end;
  end;
end;

begin
  oCorretor := nil;
  slSaida := nil;
  ReportMemoryLeaksOnShutdown := True;
  CoInitialize(nil);

  try
    Writeln('/--------------------------------------------------------------\');
    Writeln('|  .:: DEMONSTRAÇÃO DE USO DO CORRETOR ORTOGRÁFICO GOOGLE ::.  |');
    Writeln('| jmarioguedes@gmail.com - http://eugostododelphi.blogspot.com |');
    Writeln('\--------------------------------------------------------------/');
    Writeln('');
    Writeln('');

    oCorretor := TCorretor.Create(nil);
    slSaida := TStringList.Create;
    repeat
      write('Digite um texto: ');
      Readln(sEntrada);
      Writeln('');

      slSaida.Clear;
      bRet := oCorretor.Processar(sEntrada, slSaida, sMotivo);
      if (bRet) then
      begin
        if (slSaida.Count > 0) then
        begin
          for sPalavra in slSaida do
          begin
            Writeln('-> ' + sPalavra);
          end;
          Writeln('');
        end
        else
        begin
          Writeln('Não houve resultados');
        end;
      end
      else
      begin
        Writeln(Format('Insucesso na correção: ', [sMotivo]));
      end;

      Write('Tecle X para cancelar ou qualquer outra tecla para continuar: ');
      ReadLn(cSaida);

    until (CharInSet(cSaida, ['X', 'x']));

  finally
    if (Assigned(oCorretor)) then
    begin
      oCorretor.Free;
    end;
    if (Assigned(slSaida)) then
    begin
      slSaida.Free;
    end;

    Writeln('- Fim do Sistema - ');
    Readln;
  end;

end.

quarta-feira, 27 de junho de 2012

Livro de Delphi ... 2!

A muitos, muitos anos atrás, eu imprimi este livro. Foi um dos meus primeiros materiais de estudo.

Navegando pelo pai Google encontrei-a de novo. Ou foi ele que me encontrou?

:)

http://www.greantoniobraga.seed.pr.gov.br/redeescola/escolas/13/870/10/arquivos/File/Adenildo/Biblia-Delphi-7-PtBr.pdf

sexta-feira, 22 de junho de 2012

Artigos sobre Expressão Regular

Olá!

Durante este primeiro semestre de 2012 escrevi seis artigos sobre Expressão Regular na Active Delphi abordando desde os conceitos básicos até algumas questões mais avançadas.

Foi muito gratificante.

São as edições 95 à 100 (esta última ainda está para sair).

Foi desenvolvido um aplicativo que pode ser útil e que está sendo compartilhando através do link:

https://code.google.com/p/regex-in-delphi/

Se quiser, baixe diretamente do SVN: http://regex-in-delphi.googlecode.com/svn/trunk/

É isto.

sábado, 28 de abril de 2012

Delphi Meeting 2012

Tenho certeza que você já esta por dentro, mas de qualquer forma, segue:

Link para a inscrição: http://www.edobrasil.net/delphimeeting/


Até lá!

sexta-feira, 16 de março de 2012

Instalação de um Servidor SVN

Olá!

Eu uso o SVN a vários anos mas nunca configurei um servidor.
Mas sempre há a primeira vez e compartilho aqui, com você, a minha experiência.

Meu ponto de partida obviamente foi o Google e fiquei um pouco surpreso em perceber que o SVN tomou vários caminhos, forks e etc.
Não sei se estou falando alguma besteira mas é de fato um pouco confuso.

Tive que escolher um ponto inicial e o escolhido foi: http://subversion.apache.org/
Até onde entedi aqui é o lugar certo para iniciar.

Para o efetivo download cheguei neste link: http://subversion.apache.org/packages.html#windows

Dai veio o dilema. Qual escolher? Optei pelo projeto Win32SVN (Subversion for Windows).
O download desta distribuição pode ser feito em: http://alagazam.net/ onde optei pelo instalador MSI, disponível na seguinte URL:

http://sourceforge.net/projects/win32svn/files/1.7.2/Setup-Subversion-1.7.2.msi/download

Após a instalação temos que, manualmente, instalar o SVN como serviço do Windows. O comando para isto é:

sc create svn binpath= "\"c:\program files (x86)\Subversion\bin\svnserve.exe\" --service -r c:\Repositorio" displayname= "Servidor Subversion" depend= Tcpip start= auto

Importante: Execute o prompt de comando como Administrador e coloque um espaço entre o sinal de igual e o valor.

Vamos ao client. O Delphi XE2 dá suporte à interação direta com o SVN. Mas vou continuar usando o Tortoise por enquanto.
O download pode ser feito em: http://tortoisesvn.net/downloads.html

Um post que achei bem completo está em: http://moisesfontana.blogspot.com/2007/09/instalar-e-configurar-um-servidor.html

É isto,

terça-feira, 21 de fevereiro de 2012

Trabalhando com Atributos (Custom Attributes)

Hoje gostaria de falar sobre Atributos, mais especificamente Custom Attributes e compartilhar uma experiência recente onde esta facilidade foi crucial.

Antes de mais nada quero esclarecer que não estou me referindo aos atributos de uma classe e sim de um conceito novo (Delphi 2010) mas já existente em outras plataformas de desenvolvimento.

Do que NÃO estamos falando:


TPessoa = class
private
  FNome: string; 
  FIdade: Integer; {<== Isto é um atributo de uma classe e NÃO é disto que estamos falando}
public
  property Nome: string read FNome write FNome;
  property Idade: Integer read FIdade write FIdade;
end;

Do que estamos falando:

TPessoa = class
private
  FNome: string; 
public
  property Nome: string read FNome write FNome;

  [TIdadeMinima(21)]   {<== É disto que estamos falando!}
  property Idade: Byte read FIdade write FIdade;
end;

Mas o que significa atributo?


No dicionário:

S. m. 1. Aquilo que é próprio de um ser. 2. Emblema distintivo; símbolo. 3. Característica, qualitativa ou quantitativa, que identifica um membro de um conjunto observado. ...

Ou seja, atributo é, basicamente, uma qualidade atribuída a um elemento.

Usando no Delphi

O uso mais recorrente é em frameworks ORM. Mas as possibilidades são muitos mais amplas que isso. Poderíamos utilizar esta facilidade para atender regras de formatação de um documento eletrônico, como por exemplo o EFD Pis/Cofins ou um protocolo de comunicação com algum equipamento.

Então, indo ao ponto, os atributos são classes descendentes de TCustomAttribute. O TCustomAttribute por sua vez não implementa nada de especial.

Seguindo o nosso exemplo inicial, o atributo TIdadeMinima seria declarado da seguinte maneira:

  TIdadeMinima= class(TCustomAttribute)
  private
    FIdadeMinima: Byte;
  public
    constructor Create(AIdadeMinima: Byte); 
    function IsIdadeMaior(AIdade: Byte): Boolean;
    property IdadeMinima: Byte read FIdadeMinima;
  end;

//Implementação//

{ TIdadeMinima }

constructor TIdadeMinima.Create(AIdadeMinima: Byte);
begin
  Self.FIdadeMinima := AIdadeMinima;
end;

function TIdadeMinima.IsIdadeMaior(AIdade: Byte): Boolean;
begin
  Result := AIdade >= Self.FIdadeMinima;
end;

No que devemos focar?

O construtor da classe deve solicitar os parâmetros que fazem parte do escopo do atributo. No exemplo, o atributo está especificando uma idade mínima para a instância de TPessoa. Portanto o constructor do atributo pede justamente a idade mínima.

Para efetivamente tiramos proveito do atributo temos que recorrer à RTTI, pois só com ela temos acesso a um atributo. No exemplo abaixo, temos o código completo de um programa console, que pede o nome e a idade do usuário e valida a idade.

program UsandoAtributos;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  System.SysUtils, Rtti;

type

  TIdadeMinima= class(TCustomAttribute)
  private
    FIdadeMinima: Byte;
  public
    constructor Create(AIdadeMinima: Byte);
    function IsIdadeMaior(AIdade: Byte): Boolean;
    property IdadeMinima: Byte read FIdadeMinima;
  end;

  TPessoa = class
  private
    FNome: string;
    FIdade: Byte;
  public
    property Nome: string read FNome write FNome;
    [TIdadeMinima(21)]
    property Idade: Byte read FIdade write FIdade;
  end;

{ TIdadeMinima }

constructor TIdadeMinima.Create(AIdadeMinima: Byte);
begin
  Self.FIdadeMinima := AIdadeMinima;
end;

function TIdadeMinima.IsIdadeMaior(AIdade: Byte): Boolean;
begin
  Result := AIdade >= Self.FIdadeMinima;
end;

var
oPessoa : TPessoa;
sNome   : string;
bIdade  : Byte;

_ctx    : TRttiContext;
_typ    : TRttiType;
_pro    : TRttiProperty;
oAtt    : TCustomAttribute;
begin
  Writeln('****************************');
  Writeln('*** Bem vindo ao sistema ***');
  Writeln('****************************');
  Writeln(EmptyStr);
  oPessoa := nil;
  try
    oPessoa := TPessoa.Create;
    Write('Digite o seu nome: ');
    Readln(sNome);
    oPessoa.Nome := sNome;

    Write('Digite a sua idade: ');
    Readln(bIdade);
    oPessoa.Idade := bIdade;

    Writeln(EmptyStr);
    Writeln('Dados');
    Writeln(oPessoa.Nome,' - ',oPessoa.Idade);

    _ctx := TRttiContext.Create;
    _typ := _ctx.GetType(oPessoa.ClassType);
    for _pro in _typ.GetProperties do
    begin
      for oAtt in _pro.GetAttributes do
      begin
        if oAtt is TIdadeMinima then
        begin
          Writeln('A idade mínima é de: ',TIdadeMinima(oAtt).IdadeMinima);
          if (TIdadeMinima(oAtt).IsIdadeMaior(oPessoa.Idade)) then
          begin
            Writeln('A idade de ',oPessoa.Nome,' passou!');
          end else
          begin
            Writeln('A idade de ',oPessoa.Nome,' nao passou!');
          end;
        end;
      end;
    end;
  finally
    if (Assigned(oPessoa)) then
    begin
      oPessoa.Free;
    end;
    _ctx.Free;
  end;
  Writeln(EmptyStr);
  Writeln('Tecle [ENTER] para encerrar');
  Readln;
end.

Vale ressaltar que os atributos podem ser atribuídos a qualquer elemento da sua classe. É o seu código RTTI que terá que ser moldado para tirar proveito delas. Outro ponto importante é que um elemento pode ter vários atributos.

Uso prático

Como mencionei no decorrer, muitos exemplos sobre este tema esta ligado diretamente com a ORM, onde um atributo para a classe indica uma tabela enquanto que alguns atributos para as propriedades seriam os campos e as constraints.

Mas no meu caso, onde precisei gerar um documento eletrônico (EFD Pis/Cofins) baseado em regras, eu criei uma classe base e para cada tipo de registro criei uma classe descendente com os campos e, principalmente, seus atributos: tamanho, tamanho exato, se somente números etc e etc. Por fim, na tal classe base, foi disponibilizado um método chamado GetLine que tanto valida as informações da classe quanto gera a linha correspondente. Esta solução foi ótima pois o código ficou mais limpo e tenho certeza que mudanças ou implementações futuras será muito tranquilas.

Também poderíamos usar para implementar uma validação em uma tela de entrada, afinal, o TForm é uma classe como qualquer outra. Este seria um ótimo uso.


É isto.

Minha lista de blogs