10.02.2013

Delphi XE JSON Update

I recently updated my JSON-Library. Both, IJSONObject and IJSONArray now have methods to check for the type of the nested items.
IJSONObject = interface
['{D00A665F-3CBB-4DDB-8300-FB8020DA564B}']
  .
  .
  .
  function isJSONObject(aKey : string) : boolean;
  function isJSONArray(aKey : string) : boolean;
  function isString(aKey : string) : boolean;
  function isInteger(aKey : string) : boolean;
  function isBoolean(aKey : string) : boolean;
  function isDouble(aKey : string) : boolean;
end;

IJSONArray = interface
['{B120D59A-1D00-469E-97CE-AE2A635A51ED}']
  .
  .
  .
  function isJSONObject(aIndex : integer) : boolean;
  function isJSONArray(aIndex : integer) : boolean;
  function isString(aIndex : integer) : boolean;
  function isInteger(aIndex : integer) : boolean;
  function isBoolean(aIndex : integer) : boolean;
  function isDouble(aIndex : integer) : boolean;
end;

Usage:
var
  jo : IJSONObject;
begin
  jo := TJSON.NewObject('{"string":"abc", "integer":123}');

  jo.isString('string'); // true
  jo.isInteger('integer'); // true
  jo.isBoolean('string'); // false
end;
The implementation is very strict, e.g. isDouble will return false if the value is an integer and could be accessed as a double. I also included unit tests to cover these methods.

tracert -h 60 obiwan.scrye.net

Someone had fun with the routing at Beaglenetworks
Routenverfolgung zu obiwan.scrye.net [216.81.59.173] über maximal 60 Abschnitte:

  7   137 ms   127 ms   127 ms  10gigabitethernet1-2.core1.atl1.he.net [184.105.213.110] 
  8   126 ms   126 ms   127 ms  216.66.0.26 
  9     *        *        *     Zeitberschreitung der Anforderung.
 10   163 ms   165 ms   164 ms  Episode.IV [206.214.251.1] 
 11   193 ms   166 ms   164 ms  A.NEW.HOPE [206.214.251.6] 
 12   169 ms   164 ms   167 ms  It.is.a.period.of.civil.war [206.214.251.9] 
 13   168 ms   164 ms   166 ms  Rebel.spaceships [206.214.251.14] 
 14   169 ms   163 ms   164 ms  striking.from.a.hidden.base [206.214.251.17] 
 15   169 ms   165 ms   165 ms  have.won.their.first.victory [206.214.251.22] 
 16   165 ms   167 ms   165 ms  against.the.evil.Galactic.Empire [206.214.251.25] 
 17   165 ms   164 ms   168 ms  During.the.battle [206.214.251.30] 
 18   166 ms   164 ms   165 ms  Rebel.spies.managed [206.214.251.33] 
 19   166 ms   167 ms   162 ms  to.steal.secret.plans [206.214.251.38] 
 20   166 ms   165 ms   163 ms  to.the.Empires.ultimate.weapon [206.214.251.41] 
 21   165 ms   163 ms   164 ms  the.DEATH.STAR [206.214.251.46] 
 22   168 ms   166 ms   167 ms  an.armored.space.station [206.214.251.49] 
 23   164 ms   169 ms   167 ms  with.enough.power.to [206.214.251.54] 
 24   164 ms   189 ms   168 ms  destroy.an.entire.planet [206.214.251.57] 
 25   170 ms   168 ms   174 ms  Pursued.by.the.Empires [206.214.251.62] 
 26   166 ms   169 ms   167 ms  sinister.agents [206.214.251.65] 
 27   166 ms   163 ms   166 ms  Princess.Leia.races.home [206.214.251.70] 
 28   168 ms   163 ms   163 ms  aboard.her.starship [206.214.251.73] 
 29   168 ms   171 ms   165 ms  custodian.of.the.stolen.plans [206.214.251.78] 
 30   169 ms   172 ms   168 ms  that.can.save.her [206.214.251.81] 
 31   166 ms     *      165 ms  people.and.restore [206.214.251.86] 
 32   168 ms   167 ms   164 ms  freedom.to.the.galaxy [206.214.251.89] 
 33   166 ms   166 ms   164 ms  0-------------------0 [206.214.251.94] 
 34   165 ms   170 ms   166 ms  0------------------0 [206.214.251.97] 
 35   168 ms   170 ms   164 ms  0-----------------0 [206.214.251.102] 
 36   166 ms   169 ms   168 ms  0----------------0 [206.214.251.105] 
 37   167 ms   168 ms   164 ms  0---------------0 [206.214.251.110] 
 38   163 ms   165 ms   165 ms  0--------------0 [206.214.251.113] 
 39   167 ms   171 ms   166 ms  0-------------0 [206.214.251.118] 
 40   167 ms   166 ms   172 ms  0------------0 [206.214.251.121] 
 41   166 ms   165 ms   165 ms  0-----------0 [206.214.251.126] 
 42   172 ms   169 ms   172 ms  0----------0 [206.214.251.129] 
 43   165 ms   168 ms   166 ms  0---------0 [206.214.251.134] 
 44   168 ms   163 ms   168 ms  0--------0 [206.214.251.137] 
 45   166 ms   167 ms   260 ms  0-------0 [206.214.251.142] 
 46   166 ms   164 ms   173 ms  0------0 [206.214.251.145] 
 47   164 ms   167 ms   165 ms  0-----0 [206.214.251.150] 
 48   168 ms   166 ms   168 ms  0----0 [206.214.251.153] 
 49   166 ms   164 ms   168 ms  0---0 [206.214.251.158] 
 50   184 ms   171 ms   169 ms  0--0 [206.214.251.161] 
 51   168 ms   170 ms   168 ms  0-0 [206.214.251.166] 
 52   165 ms   168 ms   169 ms  00 [206.214.251.169] 
 53   172 ms   169 ms   165 ms  I [206.214.251.174] 
 54   171 ms   169 ms   169 ms  By.Ryan.Werber [206.214.251.177] 
 55   171 ms   168 ms   171 ms  When.CCIEs.Get.Bored [206.214.251.182] 
 56   167 ms   168 ms   173 ms  read.more.at.beaglenetworks.net [206.214.251.185] 
 57   179 ms   170 ms   166 ms  FIN [216.81.59.173] 

Ablaufverfolgung beendet.

31.01.2013

Instacode

Instacode is for developers what Instagram is for hipsters. Just paste your code into the textfield and choose the level of "hipness" to get a nice image of your code. The range of supported languages is amazing and our beloved Delphi is supported as well.

The service is currently not working, due to the heavy load of users, that are trying to "beautify" their code.
Here's an example from the website:


PS: If you are visiting the site with IE, you are in for a treat ;-)

28.01.2013

Delphi and Sleepsort

A while ago, someone on 4chan posted a fun sorting algorithm. It is called Sleepsort and is not recommended to be usedin production. However, I thought it would be fun to implement it in Delphi. Here it is (for your amusement):
program Sleepsort;

var
  items: TArray<integer>;
  i: integer;

begin
  randomize;
  writeln('Random: ');
  setlength(items, 25);
  for i := 0 to High(items) do
  begin
    items[i] := random(length(items) * 4);
    write(IntToStr(items[i]) + ' ');
  end;
  writeln;
  writeln('Sorted: ');
  for i := 0 to high(items) do
  begin
     TSortThread.Create(items[i]);
  end;
  readln;
end.
unit uSortThread;

interface

uses
  Classes;

type
  TSortThread = class (TThread)
  private
    fValue : integer;
  protected
    procedure Execute; override;
  public
    constructor Create(n : integer);
  end;

implementation

uses SysUtils;

constructor TSortThread.Create(n: integer);
begin
  inherited Create;
  fValue := n;
end;

procedure TSortThread.Execute;
begin
  sleep(fValue * 333); // artificial slowdown, to make the process visible for the human eye
  write(IntToStr(fValue)+' ');
end;

end. 

18.02.2012

Delphi and Redis

Redis is short for Remote Dictionary Server and it is a NoSQL-Database or more specific, a Key-Value-Store. Since there was no Client for Delphi, I decided to write one by myself.


The project is available on Google Code: http://code.google.com/p/delphi-redis/
It uses the Indy TCP Client by default, but you can use either Constructor or Property Injection to switch to another implementation.

01.02.2012

Delphi and JSON

I am currently developing my own JSON Library for Delphi. There are already libraries for that, but none of them suited my needs.
There is the built-in DBXJSON, which is used in the DataSnap part of Delphi. However, it is a bit of a hassle to work with.
There is TlkJSON from Simon Stuart, which has (or had, I don't know the current status) some problems with Umlauts (ä,ö,ü,ß, etc.)
There is the Delphi Web Utils from Jose Fabio N Almeida, which has some memory issues and other bugs, and most importantly, does not work well under XE2. It also hasn't been updated for a while.
And there is the SuperObject which is very powerful, but it has IMO a horrible syntax.

Since I was using the Delphi Web Utils before and I didn't want to rewrite all my other code when switching libraries, I designed my Interfaces and Classes in a similar way, e.g. the objects and array have methods named "Put" and "GetString".

I have released my library on Google Code. You can check it out via subversion or you can download the zipfile. Any feedback or help is appreciated. It uses Generics, Rtti (for TValue) and Regular Expressions, which is why it is targeted only for newer versions of Delphi (XE and XE2).

23.10.2011

Delphi and RTTI / Class Helper

In many of my applications I have some data-objects which look something like this:
type
  TMyObject = class
  private
    fInt: integer;
    fDouble: double;
    fBool: boolean;
  public
    property IntegerProp : integer read fInt write fInt;
    property DoubleProp : double read fDouble write fDouble;
    property BoolProp : boolean read fBool write fBool;
  end;
Writing a SaveToFile and LoadFromFile for each is tedious work and if I change the object I have to change the two procedures as well. With Delphis support for RTTI and class helpers we can get rid of the tedious work. I am using a class helper for TObject, so technically its possible to do this with every object.
  TSerialHelper = class helper for TObject
  private
    function isPublicProperty(aProperty : TRttiProperty): boolean;
  public
    function Serialize(aHumanreadable : boolean = true) : string;
    procedure Deserialize(const text : string);
  end;
And here is the implementation:
function TSerialHelper.Serialize(aHumanreadable : boolean = true): string;
var
  context : TRttiContext;
  typ : TRttiType;
  prop : TRttiProperty;
  soJSON : ISuperObject;
  value : TValue;
begin
  context := TRttiContext.Create;
  try
    typ := context.GetType(self.ClassType);
    soJSON := SO; // Get Superobject Interface
    for prop in typ.GetProperties do
    begin
      if isPublicProperty(prop) and prop.IsWritable then
      begin
        value := prop.GetValue(self);
        case value.Kind of
          tkInteger, tkInt64 :
            soJSON.I[prop.Name] := value.AsInteger;
          tkEnumeration:
            if value.IsType<boolean> then
              soJSON.B[prop.Name] := value.AsBoolean;
          tkFloat:
            soJSON.D[prop.Name] := value.AsExtended;
          tkChar, tkString, tkWChar, tkLString, tkWString, tkUString:
            soJSON.S[prop.Name] := value.AsString;
        end;
      end;
    end;
    result := soJSON.AsJSon(aHumanreadable);
  finally
    context.Free;
  end;
end;

procedure TSerialHelper.Deserialize(const text: string);
var
  context : TRttiContext;
  typ : TRttiType;
  prop : TRttiProperty;
  soJSON : ISuperObject;
begin
  context := TRttiContext.Create;
  try
    soJSON := SO(text); // Init the Superobject Interface
    typ := context.GetType(self.ClassType);
    for prop in typ.GetProperties do
    begin
      if isPublicProperty(prop) and prop.IsWritable then
      begin
        case prop.PropertyType.TypeKind of
          tkInteger, tkInt64 :
            prop.SetValue(self, TValue.From<int64>(soJSON.I[prop.Name]));
          tkEnumeration:
            if prop.GetValue(self).IsType<boolean> then
              prop.SetValue(self, TValue.From<boolean>(soJSON.B[prop.Name]));
          tkFloat:
            prop.SetValue(self, TValue.From<double>(soJSON.D[prop.Name]));
          tkChar, tkString, tkWChar, tkLString, tkWString, tkUString:
            prop.SetValue(self, TValue.From<string>(soJSON.S[prop.Name]));
        end;
      end;
    end;
  finally
    context.Free;
  end;
end;

function TSerialHelper.isPublicProperty(aProperty: TRttiProperty): boolean;
begin
  result := aProperty.Visibility in [mvPublic, mvPublished];
end;
It is not finished, since it can't serialize sets, arrays or childobjects, but so far it works for simple objects.

You can download the unit here.
This unit uses the SuperObject by Henri Gourvest