mustache.lpr 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. program mustache;
  2. {$mode objfpc}{$H+}
  3. uses
  4. {$IFDEF UNIX}
  5. cthreads,
  6. {$ENDIF}
  7. Classes, SysUtils, CustApp, strutils, fpjson, jsonparser, csvdataset, fpMustache, fpexmustache, fpdbmustache, iostream;
  8. type
  9. { TMustacheApplication }
  10. TMustacheApplication = class(TCustomApplication)
  11. private
  12. FTemplate : TMustacheString;
  13. FJSON : TJSONStringType;
  14. FCSV: TCSVDataset;
  15. FPartials,
  16. FDefines : TStrings;
  17. FAllowExpressions : Boolean;
  18. Foutput,
  19. FSection,
  20. FRootPath : String;
  21. procedure DoGetDefine(const aName: TMustacheString; var aHandled: Boolean;
  22. var aValue: TMustacheString);
  23. procedure ProcessOptions;
  24. Procedure Createoutput;
  25. procedure Usage(ErrorMsg: String);
  26. protected
  27. procedure DoRun; override;
  28. public
  29. constructor Create(TheOwner: TComponent); override;
  30. destructor Destroy; override;
  31. end;
  32. { TMustacheApplication }
  33. procedure TMustacheApplication.Usage(ErrorMsg : String);
  34. begin
  35. If ErrorMsg<>'' then
  36. Writeln('Error : ',ErrorMsg);
  37. Writeln('Usage : mustache [options]');
  38. Writeln('Where options is one or more of:');
  39. writeln('-c --csv=FILE Use a CSV file as data source. First line must contain column names.');
  40. writeln('-d --define=name=value Define fixed value.');
  41. writeln('-e --expressions Allow expressions.');
  42. writeln('-h --help This message.');
  43. writeln('-j --json=JSON Use JSON as data source. @FILENAME will read JSON from file (UTF8).');
  44. writeln('-o --output=FILE output file to write output to. If empty, stdout is assumed.');
  45. writeln('-p --partial=name=PARTIAL Register partial. @FILENAME reads partial from file.');
  46. writeln('-r --root=PATH Register variables at root path PATH for expression engine');
  47. writeln('-s --section=SECTIOn Section name for CSV data');
  48. writeln('-t --template=TEMPLATE Use TEMPLATE as data source. @FILENAME will read template from file (UTF8). Required.');
  49. Halt(Ord(ErrorMsg<>''));
  50. end;
  51. procedure TMustacheApplication.ProcessOptions;
  52. Function StringOrFile(S : String) : UTF8String;
  53. begin
  54. if Copy(S,1,1)<>'@' then
  55. Result:=S
  56. else
  57. With TFileStream.Create(Copy(S,2,Length(S)-1),fmOpenRead or fmShareDenyNone) do
  58. try
  59. SetLength(Result,Size);
  60. ReadBuffer(Result[1],Size);
  61. finally
  62. Free;
  63. end;
  64. end;
  65. Var
  66. S : String;
  67. begin
  68. if Not HasOption('t','template') then
  69. Raise Exception.Create('Need a template');
  70. if HasOption('c','csv') and HasOption('j','json') then
  71. Raise Exception.Create('Cannot specify both JSON or CSV');
  72. FTemplate:=StringOrFile(GetOptionValue('t','template'));
  73. if HasOption('j','json') then
  74. FJSON:=StringOrFile(GetOptionValue('j','json'))
  75. else if HasOption('c','csv') then
  76. begin
  77. FCSV:=TCSVDataset.Create(Self);
  78. FCSV.FileName:=GetOptionValue('c','csv');
  79. FCSV.CSVOptions.FirstLineAsFieldNames:=True;
  80. FCSV.Open;
  81. end;
  82. for S in GetOptionValues('d','define') do
  83. FDefines.Add(S);
  84. for S in GetOptionValues('p','partial') do
  85. FPartials.Add(ExtractWord(1,S,['='])+'='+StringOrFile(ExtractWord(2,S,['='])));
  86. FAllowExpressions:=HasOption('e','expressions');
  87. FRootPath:=GetOptionValue('r','root');
  88. FSection:=GetOptionValue('s','section');
  89. if FSection='' then
  90. FSection:='data';
  91. Foutput:=GetOptionValue('o','output');
  92. end;
  93. procedure TMustacheApplication.DoGetDefine(const aName: TMustacheString;
  94. var aHandled: Boolean; var aValue: TMustacheString);
  95. Var
  96. Idx : Integer;
  97. begin
  98. Writeln('Getting define ',aName);
  99. Idx:=FDefines.IndexOfName(aName);
  100. aHandled:=Idx<>-1;
  101. if aHandled then
  102. aValue:=FDefines.ValueFromIndex[Idx]
  103. else
  104. aValue:='';
  105. end;
  106. procedure TMustacheApplication.DoRun;
  107. var
  108. ErrorMsg: String;
  109. begin
  110. Terminate;
  111. // quick check parameters
  112. ErrorMsg:=CheckOptions('het:j:c:d:o:r:', ['help','template','json','csv','define','output','expressions','root']);
  113. if (ErrorMsg<>'') or HasOption('h','help') then
  114. Usage(ErrorMsg);
  115. ProcessOptions;
  116. CreateOutput;
  117. end;
  118. procedure TMustacheApplication.CreateOutput;
  119. Var
  120. M : TMustache;
  121. C : TMustacheContext;
  122. O : TStream;
  123. S : TMustacheString;
  124. begin
  125. O:=Nil;
  126. M:=Nil;
  127. C:=Nil;
  128. try
  129. if FAllowExpressions then
  130. M:=TMustache.Create(Self)
  131. else
  132. begin
  133. M:=TMustacheExpr.Create(Self);
  134. if (FRootPath<>'') and (FJSON<>'') then
  135. TMustacheExpr(M).RegisterVariables(FJSON,FRootPath,True);
  136. end;
  137. M.Partials:=FPartials;
  138. if Assigned(FCSV) then
  139. begin
  140. C:=TMustacheDBContext.Create(@DoGetDefine);
  141. TMustacheDBContext(C).AddDataset(FCSV,FSection);
  142. end
  143. else if (FJSON<>'') then
  144. C:=TMustacheJSONContext.Create(GetJSON(FJSON),@DoGetDefine)
  145. else
  146. C:=TMustacheContext.Create(@DoGetDefine);
  147. if Foutput<>'' then
  148. O:=TFileStream.Create(Foutput,fmCreate)
  149. else
  150. O:=TIOStream.Create(iosOutput);
  151. M.Template:=FTemplate;
  152. S:=M.Render(C);
  153. O.WriteBuffer(S[1],Length(S));
  154. finally
  155. O.Free;
  156. C.Free;
  157. M.Free;
  158. end;
  159. end;
  160. constructor TMustacheApplication.Create(TheOwner: TComponent);
  161. begin
  162. inherited Create(TheOwner);
  163. FPartials:=TStringList.Create;
  164. FDefines:=TStringList.Create;
  165. StopOnException:=True;
  166. end;
  167. destructor TMustacheApplication.Destroy;
  168. begin
  169. FreeAndNil(FPartials);
  170. FreeAndNil(FDefines);
  171. FreeAndNil(FCSV);
  172. inherited Destroy;
  173. end;
  174. var
  175. Application: TMustacheApplication;
  176. begin
  177. Application:=TMustacheApplication.Create(nil);
  178. Application.Title:='Mustache Templater';
  179. Application.Run;
  180. Application.Free;
  181. end.