taskjuggler 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (571) hide show
  1. data/COPYING +280 -0
  2. data/README +31 -0
  3. data/Rakefile +20 -0
  4. data/benchmarks/UTF-8-Strings.rb +58 -0
  5. data/benchmarks/allocate.tjp +30 -0
  6. data/benchmarks/booking.tjp +62 -0
  7. data/benchmarks/depends.tjp +112 -0
  8. data/benchmarks/htmltaskreport.tjp +45 -0
  9. data/benchmarks/runbench.rb +24 -0
  10. data/bin/tj3 +3 -0
  11. data/bin/tj3man +3 -0
  12. data/doc/classes/AppConfig.html +808 -0
  13. data/doc/classes/Arguments.html +226 -0
  14. data/doc/classes/String.html +395 -0
  15. data/doc/classes/TaskJuggler.html +1358 -0
  16. data/doc/classes/TaskJuggler/Account.html +257 -0
  17. data/doc/classes/TaskJuggler/AccountScenario.html +218 -0
  18. data/doc/classes/TaskJuggler/Allocation.html +419 -0
  19. data/doc/classes/TaskJuggler/AllocationAttribute.html +291 -0
  20. data/doc/classes/TaskJuggler/AttributeBase.html +608 -0
  21. data/doc/classes/TaskJuggler/AttributeDefinition.html +259 -0
  22. data/doc/classes/TaskJuggler/Booking.html +307 -0
  23. data/doc/classes/TaskJuggler/BookingListAttribute.html +263 -0
  24. data/doc/classes/TaskJuggler/BooleanAttribute.html +261 -0
  25. data/doc/classes/TaskJuggler/CSVFile.html +325 -0
  26. data/doc/classes/TaskJuggler/Charge.html +279 -0
  27. data/doc/classes/TaskJuggler/ChargeListAttribute.html +229 -0
  28. data/doc/classes/TaskJuggler/ChargeSet.html +440 -0
  29. data/doc/classes/TaskJuggler/ChargeSetListAttribute.html +276 -0
  30. data/doc/classes/TaskJuggler/ColumnTable.html +260 -0
  31. data/doc/classes/TaskJuggler/DateAttribute.html +194 -0
  32. data/doc/classes/TaskJuggler/DependencyListAttribute.html +267 -0
  33. data/doc/classes/TaskJuggler/DurationAttribute.html +229 -0
  34. data/doc/classes/TaskJuggler/FixnumAttribute.html +194 -0
  35. data/doc/classes/TaskJuggler/FlagListAttribute.html +263 -0
  36. data/doc/classes/TaskJuggler/FloatAttribute.html +229 -0
  37. data/doc/classes/TaskJuggler/GanttChart.html +667 -0
  38. data/doc/classes/TaskJuggler/GanttContainer.html +441 -0
  39. data/doc/classes/TaskJuggler/GanttHeader.html +280 -0
  40. data/doc/classes/TaskJuggler/GanttHeaderScaleItem.html +245 -0
  41. data/doc/classes/TaskJuggler/GanttLine.html +398 -0
  42. data/doc/classes/TaskJuggler/GanttLoadStack.html +327 -0
  43. data/doc/classes/TaskJuggler/GanttMilestone.html +415 -0
  44. data/doc/classes/TaskJuggler/GanttRouter.html +425 -0
  45. data/doc/classes/TaskJuggler/GanttTaskBar.html +429 -0
  46. data/doc/classes/TaskJuggler/HTMLDocument.html +240 -0
  47. data/doc/classes/TaskJuggler/HTMLGraphics.html +231 -0
  48. data/doc/classes/TaskJuggler/Interval.html +552 -0
  49. data/doc/classes/TaskJuggler/IntervalListAttribute.html +267 -0
  50. data/doc/classes/TaskJuggler/KeywordDocumentation.html +796 -0
  51. data/doc/classes/TaskJuggler/Limits.html +416 -0
  52. data/doc/classes/TaskJuggler/Limits/Limit.html +381 -0
  53. data/doc/classes/TaskJuggler/LimitsAttribute.html +261 -0
  54. data/doc/classes/TaskJuggler/Log.html +613 -0
  55. data/doc/classes/TaskJuggler/LogicalAttribute.html +226 -0
  56. data/doc/classes/TaskJuggler/LogicalExpression.html +251 -0
  57. data/doc/classes/TaskJuggler/LogicalFlag.html +229 -0
  58. data/doc/classes/TaskJuggler/LogicalFunction.html +324 -0
  59. data/doc/classes/TaskJuggler/LogicalOperation.html +299 -0
  60. data/doc/classes/TaskJuggler/Macro.html +194 -0
  61. data/doc/classes/TaskJuggler/MacroParser.html +360 -0
  62. data/doc/classes/TaskJuggler/MacroTable.html +366 -0
  63. data/doc/classes/TaskJuggler/Message.html +281 -0
  64. data/doc/classes/TaskJuggler/MessageHandler.html +215 -0
  65. data/doc/classes/TaskJuggler/Project.html +1606 -0
  66. data/doc/classes/TaskJuggler/ProjectFileParser.html +412 -0
  67. data/doc/classes/TaskJuggler/PropertyList.html +597 -0
  68. data/doc/classes/TaskJuggler/PropertySet.html +1200 -0
  69. data/doc/classes/TaskJuggler/PropertyTreeNode.html +1449 -0
  70. data/doc/classes/TaskJuggler/Query.html +600 -0
  71. data/doc/classes/TaskJuggler/RealFormat.html +252 -0
  72. data/doc/classes/TaskJuggler/ReferenceAttribute.html +194 -0
  73. data/doc/classes/TaskJuggler/Report.html +528 -0
  74. data/doc/classes/TaskJuggler/ReportElement.html +1070 -0
  75. data/doc/classes/TaskJuggler/ReportTable.html +497 -0
  76. data/doc/classes/TaskJuggler/ReportTableCell.html +518 -0
  77. data/doc/classes/TaskJuggler/ReportTableColumn.html +364 -0
  78. data/doc/classes/TaskJuggler/ReportTableElement.html +644 -0
  79. data/doc/classes/TaskJuggler/ReportTableLegend.html +343 -0
  80. data/doc/classes/TaskJuggler/ReportTableLine.html +431 -0
  81. data/doc/classes/TaskJuggler/Resource.html +211 -0
  82. data/doc/classes/TaskJuggler/ResourceListAttribute.html +267 -0
  83. data/doc/classes/TaskJuggler/ResourceListRE.html +249 -0
  84. data/doc/classes/TaskJuggler/ResourceScenario.html +1137 -0
  85. data/doc/classes/TaskJuggler/RichText.html +537 -0
  86. data/doc/classes/TaskJuggler/RichTextAttribute.html +229 -0
  87. data/doc/classes/TaskJuggler/RichTextDocument.html +418 -0
  88. data/doc/classes/TaskJuggler/RichTextElement.html +829 -0
  89. data/doc/classes/TaskJuggler/RichTextException.html +212 -0
  90. data/doc/classes/TaskJuggler/RichTextParser.html +317 -0
  91. data/doc/classes/TaskJuggler/RichTextProtocolExample.html +303 -0
  92. data/doc/classes/TaskJuggler/RichTextProtocolHandler.html +194 -0
  93. data/doc/classes/TaskJuggler/RichTextScanner.html +561 -0
  94. data/doc/classes/TaskJuggler/RichTextSnip.html +364 -0
  95. data/doc/classes/TaskJuggler/RichTextSyntaxRules.html +883 -0
  96. data/doc/classes/TaskJuggler/Scenario.html +163 -0
  97. data/doc/classes/TaskJuggler/ScenarioData.html +354 -0
  98. data/doc/classes/TaskJuggler/Scoreboard.html +638 -0
  99. data/doc/classes/TaskJuggler/Shift.html +255 -0
  100. data/doc/classes/TaskJuggler/ShiftAssignment.html +488 -0
  101. data/doc/classes/TaskJuggler/ShiftAssignments.html +715 -0
  102. data/doc/classes/TaskJuggler/ShiftAssignmentsAttribute.html +261 -0
  103. data/doc/classes/TaskJuggler/ShiftScenario.html +282 -0
  104. data/doc/classes/TaskJuggler/SourceFileInfo.html +247 -0
  105. data/doc/classes/TaskJuggler/StringAttribute.html +229 -0
  106. data/doc/classes/TaskJuggler/SymbolAttribute.html +194 -0
  107. data/doc/classes/TaskJuggler/SyntaxReference.html +516 -0
  108. data/doc/classes/TaskJuggler/TOCEntry.html +242 -0
  109. data/doc/classes/TaskJuggler/TableColumnDefinition.html +273 -0
  110. data/doc/classes/TaskJuggler/TableOfContents.html +256 -0
  111. data/doc/classes/TaskJuggler/Task.html +203 -0
  112. data/doc/classes/TaskJuggler/TaskDependency.html +251 -0
  113. data/doc/classes/TaskJuggler/TaskListAttribute.html +267 -0
  114. data/doc/classes/TaskJuggler/TaskListRE.html +250 -0
  115. data/doc/classes/TaskJuggler/TaskScenario.html +2206 -0
  116. data/doc/classes/TaskJuggler/TextParser.html +670 -0
  117. data/doc/classes/TaskJuggler/TextParser/Pattern.html +923 -0
  118. data/doc/classes/TaskJuggler/TextParser/Rule.html +779 -0
  119. data/doc/classes/TaskJuggler/TextParser/StackElement.html +267 -0
  120. data/doc/classes/TaskJuggler/TextParser/TextParserResultArray.html +212 -0
  121. data/doc/classes/TaskJuggler/TextParser/TokenDoc.html +221 -0
  122. data/doc/classes/TaskJuggler/TextScanner.html +708 -0
  123. data/doc/classes/TaskJuggler/TextScanner/BufferStreamHandle.html +355 -0
  124. data/doc/classes/TaskJuggler/TextScanner/FileStreamHandle.html +341 -0
  125. data/doc/classes/TaskJuggler/TextScanner/StreamHandle.html +260 -0
  126. data/doc/classes/TaskJuggler/TjException.html +185 -0
  127. data/doc/classes/TaskJuggler/TjTime.html +1845 -0
  128. data/doc/classes/TaskJuggler/TjpExample.html +310 -0
  129. data/doc/classes/TaskJuggler/TjpExportRE.html +329 -0
  130. data/doc/classes/TaskJuggler/TjpSyntaxRules.html +8928 -0
  131. data/doc/classes/TaskJuggler/UserManual.html +606 -0
  132. data/doc/classes/TaskJuggler/WorkingHours.html +582 -0
  133. data/doc/classes/TaskJuggler/WorkingHoursAttribute.html +284 -0
  134. data/doc/classes/TaskJuggler/XMLBlob.html +207 -0
  135. data/doc/classes/TaskJuggler/XMLComment.html +206 -0
  136. data/doc/classes/TaskJuggler/XMLDocument.html +293 -0
  137. data/doc/classes/TaskJuggler/XMLElement.html +341 -0
  138. data/doc/classes/TaskJuggler/XMLNamedText.html +174 -0
  139. data/doc/classes/TaskJuggler/XMLText.html +221 -0
  140. data/doc/files/COPYING.html +448 -0
  141. data/doc/files/README.html +134 -0
  142. data/doc/files/lib/AccountScenario_rb.html +116 -0
  143. data/doc/files/lib/Account_rb.html +118 -0
  144. data/doc/files/lib/Allocation_rb.html +118 -0
  145. data/doc/files/lib/AppConfig_rb.html +116 -0
  146. data/doc/files/lib/AttributeBase_rb.html +106 -0
  147. data/doc/files/lib/AttributeDefinition_rb.html +106 -0
  148. data/doc/files/lib/Attributes_rb.html +130 -0
  149. data/doc/files/lib/Booking_rb.html +106 -0
  150. data/doc/files/lib/ChargeSet_rb.html +116 -0
  151. data/doc/files/lib/Charge_rb.html +116 -0
  152. data/doc/files/lib/HTMLDocument_rb.html +116 -0
  153. data/doc/files/lib/Interval_rb.html +116 -0
  154. data/doc/files/lib/KeywordDocumentation_rb.html +122 -0
  155. data/doc/files/lib/Limits_rb.html +116 -0
  156. data/doc/files/lib/Log_rb.html +116 -0
  157. data/doc/files/lib/LogicalExpression_rb.html +122 -0
  158. data/doc/files/lib/LogicalFlag_rb.html +116 -0
  159. data/doc/files/lib/LogicalFunction_rb.html +116 -0
  160. data/doc/files/lib/LogicalOperation_rb.html +116 -0
  161. data/doc/files/lib/MacroParser_rb.html +118 -0
  162. data/doc/files/lib/MacroTable_rb.html +122 -0
  163. data/doc/files/lib/MessageHandler_rb.html +106 -0
  164. data/doc/files/lib/Message_rb.html +116 -0
  165. data/doc/files/lib/ProjectFileParser_rb.html +122 -0
  166. data/doc/files/lib/Project_rb.html +148 -0
  167. data/doc/files/lib/PropertyList_rb.html +106 -0
  168. data/doc/files/lib/PropertySet_rb.html +118 -0
  169. data/doc/files/lib/PropertyTreeNode_rb.html +106 -0
  170. data/doc/files/lib/Query_rb.html +116 -0
  171. data/doc/files/lib/RealFormat_rb.html +106 -0
  172. data/doc/files/lib/ResourceScenario_rb.html +116 -0
  173. data/doc/files/lib/Resource_rb.html +118 -0
  174. data/doc/files/lib/RichTextDocument_rb.html +120 -0
  175. data/doc/files/lib/RichTextElement_rb.html +120 -0
  176. data/doc/files/lib/RichTextParser_rb.html +120 -0
  177. data/doc/files/lib/RichTextProtocolExample_rb.html +120 -0
  178. data/doc/files/lib/RichTextProtocolHandler_rb.html +106 -0
  179. data/doc/files/lib/RichTextScanner_rb.html +116 -0
  180. data/doc/files/lib/RichTextSnip_rb.html +118 -0
  181. data/doc/files/lib/RichTextSyntaxRules_rb.html +106 -0
  182. data/doc/files/lib/RichText_rb.html +118 -0
  183. data/doc/files/lib/ScenarioData_rb.html +118 -0
  184. data/doc/files/lib/Scenario_rb.html +116 -0
  185. data/doc/files/lib/Scoreboard_rb.html +106 -0
  186. data/doc/files/lib/ShiftAssignments_rb.html +116 -0
  187. data/doc/files/lib/ShiftScenario_rb.html +116 -0
  188. data/doc/files/lib/Shift_rb.html +118 -0
  189. data/doc/files/lib/SourceFileInfo_rb.html +106 -0
  190. data/doc/files/lib/SyntaxReference_rb.html +122 -0
  191. data/doc/files/lib/TOCEntry_rb.html +118 -0
  192. data/doc/files/lib/TableColumnDefinition_rb.html +106 -0
  193. data/doc/files/lib/TableOfContents_rb.html +118 -0
  194. data/doc/files/lib/TaskDependency_rb.html +106 -0
  195. data/doc/files/lib/TaskJuggler_rb.html +120 -0
  196. data/doc/files/lib/TaskScenario_rb.html +116 -0
  197. data/doc/files/lib/Task_rb.html +118 -0
  198. data/doc/files/lib/TextParser/Pattern_rb.html +116 -0
  199. data/doc/files/lib/TextParser/Rule_rb.html +106 -0
  200. data/doc/files/lib/TextParser/StackElement_rb.html +106 -0
  201. data/doc/files/lib/TextParser/TokenDoc_rb.html +106 -0
  202. data/doc/files/lib/TextParser_rb.html +124 -0
  203. data/doc/files/lib/TextScanner_rb.html +128 -0
  204. data/doc/files/lib/Tj3Config_rb.html +118 -0
  205. data/doc/files/lib/TjException_rb.html +106 -0
  206. data/doc/files/lib/TjTime_rb.html +118 -0
  207. data/doc/files/lib/TjpExample_rb.html +116 -0
  208. data/doc/files/lib/TjpSyntaxRules_rb.html +106 -0
  209. data/doc/files/lib/UTF8String_rb.html +132 -0
  210. data/doc/files/lib/UserManual_rb.html +124 -0
  211. data/doc/files/lib/WorkingHours_rb.html +116 -0
  212. data/doc/files/lib/XMLDocument_rb.html +116 -0
  213. data/doc/files/lib/XMLElement_rb.html +116 -0
  214. data/doc/files/lib/reports/CSVFile_rb.html +116 -0
  215. data/doc/files/lib/reports/ColumnTable_rb.html +116 -0
  216. data/doc/files/lib/reports/GanttChart_rb.html +122 -0
  217. data/doc/files/lib/reports/GanttContainer_rb.html +116 -0
  218. data/doc/files/lib/reports/GanttHeaderScaleItem_rb.html +106 -0
  219. data/doc/files/lib/reports/GanttHeader_rb.html +116 -0
  220. data/doc/files/lib/reports/GanttLine_rb.html +126 -0
  221. data/doc/files/lib/reports/GanttLoadStack_rb.html +116 -0
  222. data/doc/files/lib/reports/GanttMilestone_rb.html +116 -0
  223. data/doc/files/lib/reports/GanttRouter_rb.html +106 -0
  224. data/doc/files/lib/reports/GanttTaskBar_rb.html +116 -0
  225. data/doc/files/lib/reports/HTMLGraphics_rb.html +106 -0
  226. data/doc/files/lib/reports/ReportElement_rb.html +118 -0
  227. data/doc/files/lib/reports/ReportTableCell_rb.html +106 -0
  228. data/doc/files/lib/reports/ReportTableColumn_rb.html +106 -0
  229. data/doc/files/lib/reports/ReportTableElement_rb.html +122 -0
  230. data/doc/files/lib/reports/ReportTableLegend_rb.html +106 -0
  231. data/doc/files/lib/reports/ReportTableLine_rb.html +116 -0
  232. data/doc/files/lib/reports/ReportTable_rb.html +118 -0
  233. data/doc/files/lib/reports/Report_rb.html +126 -0
  234. data/doc/files/lib/reports/ResourceListRE_rb.html +122 -0
  235. data/doc/files/lib/reports/TaskListRE_rb.html +122 -0
  236. data/doc/files/lib/reports/TjpExportRE_rb.html +116 -0
  237. data/doc/files/lib/taskjuggler3_rb.html +276 -0
  238. data/doc/files/lib/tj3man_rb.html +189 -0
  239. data/doc/fr_class_index.html +285 -0
  240. data/doc/fr_file_index.html +223 -0
  241. data/doc/fr_method_index.html +1953 -0
  242. data/doc/index.html +21 -0
  243. data/doc/rdoc-style.css +299 -0
  244. data/examples/tutorial.tjp +361 -0
  245. data/gem_spec.rb +30 -0
  246. data/lib/Account.rb +50 -0
  247. data/lib/AccountScenario.rb +39 -0
  248. data/lib/Allocation.rb +102 -0
  249. data/lib/AppConfig.rb +134 -0
  250. data/lib/AttributeBase.rb +131 -0
  251. data/lib/AttributeDefinition.rb +47 -0
  252. data/lib/Attributes.rb +478 -0
  253. data/lib/BatchProcessor.rb +209 -0
  254. data/lib/Booking.rb +59 -0
  255. data/lib/Charge.rb +71 -0
  256. data/lib/ChargeSet.rb +126 -0
  257. data/lib/HTMLDocument.rb +59 -0
  258. data/lib/Interval.rb +127 -0
  259. data/lib/KeywordDocumentation.rb +560 -0
  260. data/lib/Limits.rb +219 -0
  261. data/lib/Log.rb +160 -0
  262. data/lib/LogicalExpression.rb +71 -0
  263. data/lib/LogicalFlag.rb +34 -0
  264. data/lib/LogicalFunction.rb +102 -0
  265. data/lib/LogicalOperation.rb +118 -0
  266. data/lib/MacroParser.rb +77 -0
  267. data/lib/MacroTable.rb +84 -0
  268. data/lib/Message.rb +56 -0
  269. data/lib/MessageHandler.rb +34 -0
  270. data/lib/Project.rb +662 -0
  271. data/lib/ProjectFileParser.rb +333 -0
  272. data/lib/PropertyList.rb +181 -0
  273. data/lib/PropertySet.rb +304 -0
  274. data/lib/PropertyTreeNode.rb +461 -0
  275. data/lib/Query.rb +227 -0
  276. data/lib/RealFormat.rb +73 -0
  277. data/lib/Resource.rb +42 -0
  278. data/lib/ResourceScenario.rb +511 -0
  279. data/lib/RichText.rb +147 -0
  280. data/lib/RichTextDocument.rb +139 -0
  281. data/lib/RichTextElement.rb +391 -0
  282. data/lib/RichTextParser.rb +66 -0
  283. data/lib/RichTextProtocolExample.rb +65 -0
  284. data/lib/RichTextProtocolHandler.rb +35 -0
  285. data/lib/RichTextScanner.rb +390 -0
  286. data/lib/RichTextSnip.rb +104 -0
  287. data/lib/RichTextSyntaxRules.rb +265 -0
  288. data/lib/Scenario.rb +27 -0
  289. data/lib/ScenarioData.rb +65 -0
  290. data/lib/Scoreboard.rb +141 -0
  291. data/lib/Shift.rb +48 -0
  292. data/lib/ShiftAssignments.rb +291 -0
  293. data/lib/ShiftScenario.rb +46 -0
  294. data/lib/SourceFileInfo.rb +37 -0
  295. data/lib/SyntaxReference.rb +284 -0
  296. data/lib/TOCEntry.rb +76 -0
  297. data/lib/TableColumnDefinition.rb +54 -0
  298. data/lib/TableOfContents.rb +46 -0
  299. data/lib/Task.rb +37 -0
  300. data/lib/TaskDependency.rb +39 -0
  301. data/lib/TaskJuggler.rb +84 -0
  302. data/lib/TaskScenario.rb +1622 -0
  303. data/lib/TextParser.rb +416 -0
  304. data/lib/TextParser/Pattern.rb +263 -0
  305. data/lib/TextParser/Rule.rb +171 -0
  306. data/lib/TextParser/StackElement.rb +45 -0
  307. data/lib/TextParser/TokenDoc.rb +38 -0
  308. data/lib/TextScanner.rb +682 -0
  309. data/lib/Tj3Config.rb +27 -0
  310. data/lib/TjException.rb +27 -0
  311. data/lib/TjTime.rb +395 -0
  312. data/lib/TjpExample.rb +119 -0
  313. data/lib/TjpSyntaxRules.rb +4022 -0
  314. data/lib/UTF8String.rb +100 -0
  315. data/lib/UserManual.rb +282 -0
  316. data/lib/WorkingHours.rb +323 -0
  317. data/lib/XMLDocument.rb +54 -0
  318. data/lib/XMLElement.rb +175 -0
  319. data/lib/reports/CSVFile.rb +146 -0
  320. data/lib/reports/ColumnTable.rb +66 -0
  321. data/lib/reports/GanttChart.rb +308 -0
  322. data/lib/reports/GanttContainer.rb +107 -0
  323. data/lib/reports/GanttHeader.rb +141 -0
  324. data/lib/reports/GanttHeaderScaleItem.rb +42 -0
  325. data/lib/reports/GanttLine.rb +329 -0
  326. data/lib/reports/GanttLoadStack.rb +113 -0
  327. data/lib/reports/GanttMilestone.rb +80 -0
  328. data/lib/reports/GanttRouter.rb +375 -0
  329. data/lib/reports/GanttTaskBar.rb +95 -0
  330. data/lib/reports/HTMLGraphics.rb +65 -0
  331. data/lib/reports/Report.rb +344 -0
  332. data/lib/reports/ReportElement.rb +427 -0
  333. data/lib/reports/ReportTable.rb +144 -0
  334. data/lib/reports/ReportTableCell.rb +142 -0
  335. data/lib/reports/ReportTableColumn.rb +82 -0
  336. data/lib/reports/ReportTableElement.rb +852 -0
  337. data/lib/reports/ReportTableLegend.rb +167 -0
  338. data/lib/reports/ReportTableLine.rb +87 -0
  339. data/lib/reports/ResourceListRE.rb +72 -0
  340. data/lib/reports/TaskListRE.rb +73 -0
  341. data/lib/reports/TjpExportRE.rb +394 -0
  342. data/lib/taskjuggler3.rb +106 -0
  343. data/lib/tj3man.rb +88 -0
  344. data/manual/Day_To_Day_Juggling +168 -0
  345. data/manual/Getting_Started +61 -0
  346. data/manual/How_To_Contribute +185 -0
  347. data/manual/Installation +68 -0
  348. data/manual/Intro +102 -0
  349. data/manual/Reporting_Bugs +26 -0
  350. data/manual/Rich_Text_Attributes +90 -0
  351. data/manual/TaskJuggler_2x_Migration +40 -0
  352. data/manual/Tutorial +579 -0
  353. data/manual/fdl +450 -0
  354. data/prj_cfg.rb +43 -0
  355. data/setup.rb +1585 -0
  356. data/tasks/csts.rake +72 -0
  357. data/tasks/gem.rake +14 -0
  358. data/tasks/manual.rake +10 -0
  359. data/tasks/missing.rake +21 -0
  360. data/tasks/rcov.rake +14 -0
  361. data/tasks/rdoc.rake +17 -0
  362. data/tasks/rexml_fix.rb +16 -0
  363. data/tasks/rexml_fix_19.rb +49 -0
  364. data/tasks/show.rake +21 -0
  365. data/tasks/stats.rake +25 -0
  366. data/tasks/test.rake +11 -0
  367. data/test/MessageChecker.rb +53 -0
  368. data/test/TestSuite/CSV-Reports/celltext-Reference.csv +14 -0
  369. data/test/TestSuite/CSV-Reports/celltext.tjp +7 -0
  370. data/test/TestSuite/CSV-Reports/genrefs +6 -0
  371. data/test/TestSuite/CSV-Reports/project-1.tji +57 -0
  372. data/test/TestSuite/CSV-Reports/resourcereport-Reference.csv +4 -0
  373. data/test/TestSuite/CSV-Reports/resourcereport.tjp +10 -0
  374. data/test/TestSuite/CSV-Reports/resourcereport_with_tasks-Reference.csv +22 -0
  375. data/test/TestSuite/CSV-Reports/resourcereport_with_tasks.tjp +11 -0
  376. data/test/TestSuite/CSV-Reports/sortByTree-Reference.csv +14 -0
  377. data/test/TestSuite/CSV-Reports/sortByTree.tjp +8 -0
  378. data/test/TestSuite/CSV-Reports/sortBy_duration.down-Reference.csv +14 -0
  379. data/test/TestSuite/CSV-Reports/sortBy_duration.down.tjp +10 -0
  380. data/test/TestSuite/CSV-Reports/sortBy_effort.up-Reference.csv +14 -0
  381. data/test/TestSuite/CSV-Reports/sortBy_effort.up.tjp +10 -0
  382. data/test/TestSuite/CSV-Reports/sortBy_plan.start.down-Reference.csv +14 -0
  383. data/test/TestSuite/CSV-Reports/sortBy_plan.start.down.tjp +10 -0
  384. data/test/TestSuite/CSV-Reports/taskreport-Reference.csv +14 -0
  385. data/test/TestSuite/CSV-Reports/taskreport.tjp +10 -0
  386. data/test/TestSuite/CSV-Reports/taskreport_with_resources-Reference.csv +24 -0
  387. data/test/TestSuite/CSV-Reports/taskreport_with_resources.tjp +11 -0
  388. data/test/TestSuite/Scheduler/Correct/Allocate.tjp +86 -0
  389. data/test/TestSuite/Scheduler/Correct/AutomaticMilestones.tjp +63 -0
  390. data/test/TestSuite/Scheduler/Correct/Booking.tjp +161 -0
  391. data/test/TestSuite/Scheduler/Correct/Depends.tjp +50 -0
  392. data/test/TestSuite/Scheduler/Correct/Duration.tjp +34 -0
  393. data/test/TestSuite/Scheduler/Correct/InheritStartEnd.tjp +129 -0
  394. data/test/TestSuite/Scheduler/Correct/Limits.tjp +81 -0
  395. data/test/TestSuite/Scheduler/Correct/MultipleMandatories.tjp +43 -0
  396. data/test/TestSuite/Scheduler/Correct/Optimize-1.tjp +28 -0
  397. data/test/TestSuite/Scheduler/Correct/Optimize-2.tjp +33 -0
  398. data/test/TestSuite/Scheduler/Correct/Optimize-3.tjp +33 -0
  399. data/test/TestSuite/Scheduler/Correct/Optimize-4.tjp +34 -0
  400. data/test/TestSuite/Scheduler/Correct/Optimize-5.tjp +62 -0
  401. data/test/TestSuite/Scheduler/Correct/Precedes.tjp +50 -0
  402. data/test/TestSuite/Scheduler/Correct/Shift.tjp +102 -0
  403. data/test/TestSuite/Scheduler/Errors/account_no_leaf.tjp +13 -0
  404. data/test/TestSuite/Scheduler/Errors/booking_conflict.tjp +10 -0
  405. data/test/TestSuite/Scheduler/Errors/booking_no_duty.tjp +9 -0
  406. data/test/TestSuite/Scheduler/Errors/booking_on_vacation.tjp +9 -0
  407. data/test/TestSuite/Scheduler/Errors/container_booking.tjp +14 -0
  408. data/test/TestSuite/Scheduler/Errors/container_duration.tjp +11 -0
  409. data/test/TestSuite/Scheduler/Errors/effort_no_allocations.tjp +7 -0
  410. data/test/TestSuite/Scheduler/Errors/loop_detected_1.tjp +19 -0
  411. data/test/TestSuite/Scheduler/Errors/loop_detected_10.tjp +36 -0
  412. data/test/TestSuite/Scheduler/Errors/loop_detected_11.tjp +27 -0
  413. data/test/TestSuite/Scheduler/Errors/loop_detected_12.tjp +20 -0
  414. data/test/TestSuite/Scheduler/Errors/loop_detected_13.tjp +27 -0
  415. data/test/TestSuite/Scheduler/Errors/loop_detected_14.tjp +26 -0
  416. data/test/TestSuite/Scheduler/Errors/loop_detected_2.tjp +24 -0
  417. data/test/TestSuite/Scheduler/Errors/loop_detected_3.tjp +18 -0
  418. data/test/TestSuite/Scheduler/Errors/loop_detected_4.tjp +36 -0
  419. data/test/TestSuite/Scheduler/Errors/loop_detected_5.tjp +37 -0
  420. data/test/TestSuite/Scheduler/Errors/loop_detected_6.tjp +35 -0
  421. data/test/TestSuite/Scheduler/Errors/loop_detected_7.tjp +46 -0
  422. data/test/TestSuite/Scheduler/Errors/loop_detected_8.tjp +51 -0
  423. data/test/TestSuite/Scheduler/Errors/loop_detected_9.tjp +20 -0
  424. data/test/TestSuite/Scheduler/Errors/maxend.tjp +8 -0
  425. data/test/TestSuite/Scheduler/Errors/maxstart.tjp +8 -0
  426. data/test/TestSuite/Scheduler/Errors/milestone_booking.tjp +10 -0
  427. data/test/TestSuite/Scheduler/Errors/milestone_duration.tjp +8 -0
  428. data/test/TestSuite/Scheduler/Errors/milestone_start_end.tjp +8 -0
  429. data/test/TestSuite/Scheduler/Errors/minend.tjp +8 -0
  430. data/test/TestSuite/Scheduler/Errors/minstart.tjp +8 -0
  431. data/test/TestSuite/Scheduler/Errors/multiple_durations.tjp +11 -0
  432. data/test/TestSuite/Scheduler/Errors/no_tasks.tjp +6 -0
  433. data/test/TestSuite/Scheduler/Errors/not_scheduled.tjp +8 -0
  434. data/test/TestSuite/Scheduler/Errors/task_depend_child.tjp +10 -0
  435. data/test/TestSuite/Scheduler/Errors/task_depend_multi.tjp +13 -0
  436. data/test/TestSuite/Scheduler/Errors/task_depend_parent.tjp +11 -0
  437. data/test/TestSuite/Scheduler/Errors/task_depend_self.tjp +10 -0
  438. data/test/TestSuite/Scheduler/Errors/task_depend_unknown.tjp +10 -0
  439. data/test/TestSuite/Scheduler/Errors/task_overspecified_1.tjp +9 -0
  440. data/test/TestSuite/Scheduler/Errors/task_overspecified_2.tjp +14 -0
  441. data/test/TestSuite/Scheduler/Errors/task_overspecified_3.tjp +14 -0
  442. data/test/TestSuite/Scheduler/Errors/task_underspecified_1.tjp +8 -0
  443. data/test/TestSuite/Scheduler/Errors/task_underspecified_2.tjp +8 -0
  444. data/test/TestSuite/Scheduler/Errors/task_underspecified_3.tjp +9 -0
  445. data/test/TestSuite/Syntax/Correct/Account.tjp +53 -0
  446. data/test/TestSuite/Syntax/Correct/Allocate-1.tjp +24 -0
  447. data/test/TestSuite/Syntax/Correct/Alternative.tjp +13 -0
  448. data/test/TestSuite/Syntax/Correct/AutoMacros.tjp +14 -0
  449. data/test/TestSuite/Syntax/Correct/Booking.tjp +26 -0
  450. data/test/TestSuite/Syntax/Correct/Caption.tjp +33 -0
  451. data/test/TestSuite/Syntax/Correct/Celltext.tjp +28 -0
  452. data/test/TestSuite/Syntax/Correct/Comments.tjp +29 -0
  453. data/test/TestSuite/Syntax/Correct/Complete.tjp +16 -0
  454. data/test/TestSuite/Syntax/Correct/CompletedWork.tji +20 -0
  455. data/test/TestSuite/Syntax/Correct/CriticalPath.tjp +31 -0
  456. data/test/TestSuite/Syntax/Correct/Currencyformat.tjp +12 -0
  457. data/test/TestSuite/Syntax/Correct/CustomAttributes.tjp +14 -0
  458. data/test/TestSuite/Syntax/Correct/Depends1.tjp +22 -0
  459. data/test/TestSuite/Syntax/Correct/Durations.tjp +29 -0
  460. data/test/TestSuite/Syntax/Correct/Efficiency.tjp +19 -0
  461. data/test/TestSuite/Syntax/Correct/Export.tjp +40 -0
  462. data/test/TestSuite/Syntax/Correct/Flags.tjp +32 -0
  463. data/test/TestSuite/Syntax/Correct/Freeze.tjp +28 -0
  464. data/test/TestSuite/Syntax/Correct/Gap.tjp +15 -0
  465. data/test/TestSuite/Syntax/Correct/HtmlTaskReport.tjp +33 -0
  466. data/test/TestSuite/Syntax/Correct/Limits-1.tjp +71 -0
  467. data/test/TestSuite/Syntax/Correct/LoadUnits.tjp +31 -0
  468. data/test/TestSuite/Syntax/Correct/Macro-1.tjp +19 -0
  469. data/test/TestSuite/Syntax/Correct/Mandatory.tjp +17 -0
  470. data/test/TestSuite/Syntax/Correct/Milestone.tjp +12 -0
  471. data/test/TestSuite/Syntax/Correct/MinMax.tjp +17 -0
  472. data/test/TestSuite/Syntax/Correct/Numberformat.tjp +12 -0
  473. data/test/TestSuite/Syntax/Correct/Period.tjp +16 -0
  474. data/test/TestSuite/Syntax/Correct/Persistent.tjp +11 -0
  475. data/test/TestSuite/Syntax/Correct/Precedes1.tjp +17 -0
  476. data/test/TestSuite/Syntax/Correct/Priority.tjp +30 -0
  477. data/test/TestSuite/Syntax/Correct/Project.tjp +21 -0
  478. data/test/TestSuite/Syntax/Correct/ProjectIDs.tjp +23 -0
  479. data/test/TestSuite/Syntax/Correct/RawHTML.tjp +29 -0
  480. data/test/TestSuite/Syntax/Correct/Reports.tjp +54 -0
  481. data/test/TestSuite/Syntax/Correct/Resource.tjp +20 -0
  482. data/test/TestSuite/Syntax/Correct/Responsible.tjp +16 -0
  483. data/test/TestSuite/Syntax/Correct/Scenario.tjp +15 -0
  484. data/test/TestSuite/Syntax/Correct/Scheduling.tjp +26 -0
  485. data/test/TestSuite/Syntax/Correct/Select.tjp +27 -0
  486. data/test/TestSuite/Syntax/Correct/Shift.tjp +55 -0
  487. data/test/TestSuite/Syntax/Correct/Simple.tjp +25 -0
  488. data/test/TestSuite/Syntax/Correct/String.tjp +12 -0
  489. data/test/TestSuite/Syntax/Correct/Supplement.tjp +24 -0
  490. data/test/TestSuite/Syntax/Correct/TaskRoot.tjp +34 -0
  491. data/test/TestSuite/Syntax/Correct/TimeFrame.tjp +19 -0
  492. data/test/TestSuite/Syntax/Correct/Timezone.tjp +8 -0
  493. data/test/TestSuite/Syntax/Correct/Vacation.tjp +33 -0
  494. data/test/TestSuite/Syntax/Correct/csvtest +16 -0
  495. data/test/TestSuite/Syntax/Correct/manual2example.rb +24 -0
  496. data/test/TestSuite/Syntax/Correct/tutorial.tjp +485 -0
  497. data/test/TestSuite/Syntax/Errors/bad_include.tjp +11 -0
  498. data/test/TestSuite/Syntax/Errors/booking_group.tjp +14 -0
  499. data/test/TestSuite/Syntax/Errors/booking_milestone.tjp +13 -0
  500. data/test/TestSuite/Syntax/Errors/booking_no_leaf.tjp +13 -0
  501. data/test/TestSuite/Syntax/Errors/chargeset.tjp +14 -0
  502. data/test/TestSuite/Syntax/Errors/chargeset_master.tjp +15 -0
  503. data/test/TestSuite/Syntax/Errors/container_attribute.tjp +13 -0
  504. data/test/TestSuite/Syntax/Errors/cost_acct_no_top.tjp +24 -0
  505. data/test/TestSuite/Syntax/Errors/cost_rev_same.tjp +24 -0
  506. data/test/TestSuite/Syntax/Errors/date_in_range.tjp +7 -0
  507. data/test/TestSuite/Syntax/Errors/effort_zero.tjp +8 -0
  508. data/test/TestSuite/Syntax/Errors/empty.tjp +1 -0
  509. data/test/TestSuite/Syntax/Errors/export_bad_extn.tjp +9 -0
  510. data/test/TestSuite/Syntax/Errors/extend_id_cap.tjp +7 -0
  511. data/test/TestSuite/Syntax/Errors/interval_end_in_range.tjp +7 -0
  512. data/test/TestSuite/Syntax/Errors/interval_start_in_range.tjp +7 -0
  513. data/test/TestSuite/Syntax/Errors/leaf_resource_id_expected.tjp +12 -0
  514. data/test/TestSuite/Syntax/Errors/misaligned_date.tjp +7 -0
  515. data/test/TestSuite/Syntax/Errors/no_csv_suffix.tjp +10 -0
  516. data/test/TestSuite/Syntax/Errors/no_html_suffix.tjp +10 -0
  517. data/test/TestSuite/Syntax/Errors/operand_attribute.tjp +11 -0
  518. data/test/TestSuite/Syntax/Errors/operand_unkn_flag.tjp +11 -0
  519. data/test/TestSuite/Syntax/Errors/operand_unkn_scen.tjp +11 -0
  520. data/test/TestSuite/Syntax/Errors/overtime_range.tjp +13 -0
  521. data/test/TestSuite/Syntax/Errors/purge_no_list.tjp +8 -0
  522. data/test/TestSuite/Syntax/Errors/purge_unknown_id.tjp +8 -0
  523. data/test/TestSuite/Syntax/Errors/report_end.tjp +10 -0
  524. data/test/TestSuite/Syntax/Errors/report_redifinition.tjp +10 -0
  525. data/test/TestSuite/Syntax/Errors/report_start.tjp +10 -0
  526. data/test/TestSuite/Syntax/Errors/resource_exists.tjp +7 -0
  527. data/test/TestSuite/Syntax/Errors/resource_id_expected.tjp +8 -0
  528. data/test/TestSuite/Syntax/Errors/rev_acct_no_top.tjp +24 -0
  529. data/test/TestSuite/Syntax/Errors/scenario_exists.tjp +7 -0
  530. data/test/TestSuite/Syntax/Errors/shift_assignment_overlap.tjp +15 -0
  531. data/test/TestSuite/Syntax/Errors/shift_exists.tjp +7 -0
  532. data/test/TestSuite/Syntax/Errors/shift_id_expected.tjp +7 -0
  533. data/test/TestSuite/Syntax/Errors/sloppy_range.tjp +13 -0
  534. data/test/TestSuite/Syntax/Errors/sort_direction.tjp +11 -0
  535. data/test/TestSuite/Syntax/Errors/sort_unknown_scen.tjp +11 -0
  536. data/test/TestSuite/Syntax/Errors/sorting_crit_exptd1.tjp +11 -0
  537. data/test/TestSuite/Syntax/Errors/sorting_crit_exptd2.tjp +11 -0
  538. data/test/TestSuite/Syntax/Errors/sorting_wbs.tjp +11 -0
  539. data/test/TestSuite/Syntax/Errors/start_before_end1.tjp +7 -0
  540. data/test/TestSuite/Syntax/Errors/start_before_end2.tjp +6 -0
  541. data/test/TestSuite/Syntax/Errors/task_complete.tjp +8 -0
  542. data/test/TestSuite/Syntax/Errors/task_exists.tjp +7 -0
  543. data/test/TestSuite/Syntax/Errors/task_priority.tjp +8 -0
  544. data/test/TestSuite/Syntax/Errors/task_without_chargeset.tjp +9 -0
  545. data/test/TestSuite/Syntax/Errors/time_interval.tjp +12 -0
  546. data/test/TestSuite/Syntax/Errors/too_many_bangs.tjp +10 -0
  547. data/test/TestSuite/Syntax/Errors/undecl_flag.tjp +6 -0
  548. data/test/TestSuite/Syntax/Errors/unknown_projectid.tjp +7 -0
  549. data/test/TestSuite/Syntax/Errors/unknown_scenario_id.tjp +6 -0
  550. data/test/TestSuite/Syntax/Errors/unknown_scenario_idx.tjp +11 -0
  551. data/test/TestSuite/Syntax/Errors/unknown_task.tjp +10 -0
  552. data/test/all.rb +31 -0
  553. data/test/test_BatchProcessor.rb +54 -0
  554. data/test/test_CSV-Reports.rb +101 -0
  555. data/test/test_Limits.rb +104 -0
  556. data/test/test_LogicalExpression.rb +110 -0
  557. data/test/test_MacroTable.rb +51 -0
  558. data/test/test_Project.rb +57 -0
  559. data/test/test_PropertySet.rb +71 -0
  560. data/test/test_Query.rb +83 -0
  561. data/test/test_RealFormat.rb +83 -0
  562. data/test/test_RichText.rb +869 -0
  563. data/test/test_Scheduler.rb +42 -0
  564. data/test/test_ShiftAssignments.rb +77 -0
  565. data/test/test_Syntax.rb +41 -0
  566. data/test/test_TextScanner.rb +95 -0
  567. data/test/test_TjTime.rb +114 -0
  568. data/test/test_TjpExample.rb +169 -0
  569. data/test/test_UTF8String.rb +84 -0
  570. data/test/test_WorkingHours.rb +56 -0
  571. metadata +649 -0
@@ -0,0 +1,119 @@
1
+ #!/usr/bin/env ruby -w
2
+ # encoding: UTF-8
3
+ #
4
+ # = TjpExample.rb -- The TaskJuggler III Project Management Software
5
+ #
6
+ # Copyright (c) 2006, 2007, 2008, 2009 by Chris Schlaeger <cs@kde.org>
7
+ #
8
+ # This program is free software; you can redistribute it and/or modify
9
+ # it under the terms of version 2 of the GNU General Public License as
10
+ # published by the Free Software Foundation.
11
+ #
12
+
13
+ require 'stringio'
14
+
15
+ class TaskJuggler
16
+
17
+ # This class can extract snippets from an annotated TJP syntax file. The file
18
+ # does not care about the TJP syntax but the annotation lines must start with
19
+ # a '#' character at the begining of the line. The snippets must be enclosed
20
+ # by a starting line and an ending line. Each snippet must have a unique tag
21
+ # that can be used to retrieve the specific snip.
22
+ #
23
+ # The following line starts a snip called 'foo':
24
+ # # *** EXAMPLE: foo +
25
+ #
26
+ # The following line ends a snip called 'foo':
27
+ # # *** EXAMPLE: foo -
28
+ #
29
+ # The function TjpExample#to_s() can be used to get the content of the snip.
30
+ # It takes the tag name as optional parameter. If no tag is specified, the
31
+ # full example without the annotation lines is returned.
32
+ class TjpExample
33
+
34
+ # Create a new TjpExample object.
35
+ def initialize
36
+ @snippets = { }
37
+ # Here we will store the complete example.
38
+ @snippets['full text'] = []
39
+ @file = nil
40
+ end
41
+
42
+ # Use this function to process the file called _fileName_.
43
+ def open(fileName)
44
+ @file = File.open(fileName, 'r')
45
+ process
46
+ @file.close
47
+ end
48
+
49
+ # Use this function to process the String _text_.
50
+ def parse(text)
51
+ @file = StringIO.new(text)
52
+ process
53
+ end
54
+
55
+ # This method returns the snip identified by _tag_.
56
+ def to_s(tag = nil)
57
+ tag = 'full text' unless tag
58
+ return nil unless @snippets[tag]
59
+
60
+ s = ''
61
+ @snippets[tag].each { |l| s << l }
62
+ s
63
+ end
64
+
65
+ private
66
+
67
+ def process
68
+ # This mark identifies the annotation lines.
69
+ mark = '# *** EXAMPLE: '
70
+
71
+ # We need this to remember what snippets are currently active.
72
+ snippetState = { }
73
+ # Now process the file or String line by line.
74
+ @file.each_line do |line|
75
+ if line[0, mark.length] == mark
76
+ # We've found an annotation line. Get the tag and indicator.
77
+ dum, dum, dum, tag, indicator = line.split
78
+
79
+ if indicator == '+'
80
+ # Start a new snip
81
+ if snippetState[tag]
82
+ raise "Snippet #{tag} has already been started"
83
+ end
84
+ snippetState[tag] = true
85
+ elsif indicator == '-'
86
+ # Stop an existing snip
87
+ unless snippetState[tag]
88
+ raise "Snippet #{tag} has not yet been started"
89
+ end
90
+ snippetState[tag] = false
91
+ else
92
+ raise "Bad indicator: #{line}"
93
+ end
94
+ else
95
+ # Process the regular lines and add them to all currently active
96
+ # snippets.
97
+ snippetState.each do |t, state|
98
+ if state
99
+ # Create a new snip buffer if it does not yet exist.
100
+ @snippets[t] = [] unless @snippets[t]
101
+ # Add the line.
102
+ @snippets[t] << line
103
+ end
104
+ end
105
+ # Add all lines to this buffer.
106
+ @snippets['full text'] << line
107
+ end
108
+ end
109
+
110
+ # Remove empty lines at end of all snips
111
+ @snippets.each_value do |snip|
112
+ snip.delete_at(-1) if snip[-1] == "\n"
113
+ end
114
+ end
115
+
116
+ end
117
+
118
+ end
119
+
@@ -0,0 +1,4022 @@
1
+ #!/usr/bin/env ruby -w
2
+ # encoding: UTF-8
3
+ #
4
+ # = TjpSyntaxRules.rb -- The TaskJuggler III Project Management Software
5
+ #
6
+ # Copyright (c) 2006, 2007, 2008, 2009 by Chris Schlaeger <cs@kde.org>
7
+ #
8
+ # This program is free software; you can redistribute it and/or modify
9
+ # it under the terms of version 2 of the GNU General Public License as
10
+ # published by the Free Software Foundation.
11
+ #
12
+
13
+ class TaskJuggler
14
+
15
+ # This module contains the rule definition for the TJP syntax. Every rule is
16
+ # put in a function who's name must start with rule_. The functions are not
17
+ # necessary but make the file more readable and receptable to syntax folding.
18
+ module TjpSyntaxRules
19
+
20
+ def rule_account
21
+ pattern(%w( !accountHeader !accountBody ), lambda {
22
+ @property = @property.parent
23
+ })
24
+ doc('account', <<'EOT'
25
+ Declares an account. Accounts can be used to calculate costs of tasks or the
26
+ whole project. Account declaration may be nested, but only leaf accounts may
27
+ be used to track turnover. When the cost of a task is split over multiple
28
+ accounts they all must have the same top-level group account. Top-level
29
+ accounts can be used for profit/loss calculations. The sub-account structure
30
+ of a top-level account should be organized accordingly.
31
+ EOT
32
+ )
33
+ example('Account', '1')
34
+ end
35
+
36
+ def rule_accountAttributes
37
+ repeatable
38
+ optional
39
+ pattern(%w( !account))
40
+ pattern(%w( !accountScenarioAttributes ))
41
+ pattern(%w( !scenarioId !accountScenarioAttributes ), lambda {
42
+ @scenarioIdx = 0
43
+ })
44
+ # Other attributes will be added automatically.
45
+ end
46
+
47
+ def rule_accountBody
48
+ optionsRule('accountAttributes')
49
+ end
50
+
51
+ def rule_accountHeader
52
+ pattern(%w( _account $ID $STRING ), lambda {
53
+ if @property.nil? && !@accountprefix.empty?
54
+ @property = @project.task(@accountprefix)
55
+ end
56
+ if @project.account(@val[1])
57
+ error('account_exists', "Account #{@val[1]} has already been defined.")
58
+ end
59
+ @property = Account.new(@project, @val[1], @val[2], @property)
60
+ @property.sourceFileInfo = @scanner.sourceFileInfo
61
+ @property.inheritAttributes
62
+ @scenarioIdx = 0
63
+ })
64
+ arg(1, 'id', <<'EOT'
65
+ The ID of the account. Accounts have a global name space. The ID must be
66
+ unique within the whole project.
67
+ EOT
68
+ )
69
+ arg(2, 'name', 'A name or short description of the account')
70
+ end
71
+
72
+ def rule_accountId
73
+ pattern(%w( $ID ), lambda {
74
+ id = @val[0]
75
+ id = @accountprefix + '.' + id unless @accountprefix.empty?
76
+ # In case we have a nested supplement, we need to prepend the parent ID.
77
+ id = @property.fullId + '.' + id if @property && @property.is_a?(Account)
78
+ if (account = @project.account(id)).nil?
79
+ error('unknown_account', "Unknown account #{id}")
80
+ end
81
+ account
82
+ })
83
+ end
84
+
85
+ def rule_accountScenarioAttributes
86
+ pattern(%w( _credit !valDate $STRING !number ), lambda {
87
+ #@property['credit', @scenarioIdx] +=
88
+ # AccountCredit.new(@val[1], @val[2], @val[3])
89
+ })
90
+ doc('credit', <<'EOT'
91
+ Book the specified amount to the account at the specified date.
92
+ EOT
93
+ )
94
+ example('Account', '1')
95
+ arg(2, 'description', 'Short description of the transaction')
96
+ arg(3, 'amount', 'Amount to be booked.')
97
+ # Other attributes will be added automatically.
98
+ end
99
+
100
+ def rule_allocate
101
+ pattern(%w( _allocate !allocations ), lambda {
102
+ checkContainer('allocate')
103
+ # Don't use << operator here so the 'provided' flag gets set properly.
104
+ @property['allocate', @scenarioIdx] =
105
+ @property['allocate', @scenarioIdx] + @val[1]
106
+ })
107
+ doc('allocate', <<'EOT'
108
+ Specify which resources should be allocated to the task. The
109
+ attributes provide numerous ways to control which resource is used and when
110
+ exactly it will be assigned to the task. Shifts and limits can be used to
111
+ restrict the allocation to certain time intervals or to limit them to a
112
+ certain maximum per time period. The purge statement can be used to remove
113
+ inherited allocations or flags.
114
+ EOT
115
+ )
116
+ example('Allocate-1', '1')
117
+ end
118
+
119
+ def rule_allocation
120
+ pattern(%w( !allocationHeader !allocationBody ), lambda {
121
+ @val[0]
122
+ })
123
+ end
124
+
125
+ def rule_allocationAttributes
126
+ optional
127
+ repeatable
128
+
129
+ pattern(%w( _alternative !resourceId !moreAlternatives ), lambda {
130
+ ([ @val[1] ] + @val[2]).each do |candidate|
131
+ @allocate.addCandidate(candidate)
132
+ end
133
+ })
134
+ doc('alternative', <<'EOT'
135
+ Specify which resources should be allocated to the task. The optional
136
+ attributes provide numerous ways to control which resource is used and when
137
+ exactly it will be assigned to the task. Shifts and limits can be used to
138
+ restrict the allocation to certain time intervals or to limit them to a
139
+ certain maximum per time period.
140
+ EOT
141
+ )
142
+ example('Alternative', '1')
143
+
144
+ pattern(%w( !limits ), lambda {
145
+ limits = @property['limits', @scenarioIdx] = @val[0]
146
+ @allocate.candidates.each do |resource|
147
+ limits.limits.each_value do |l|
148
+ l.resource = resource if resource.leaf?
149
+ end
150
+ end
151
+ })
152
+ doc('allocate.limits', 'This keyword is deprecated. Don\'t use it anymore!')
153
+
154
+ pattern(%w( _select !allocationSelectionMode ), lambda {
155
+ @allocate.setSelectionMode(@val[1])
156
+ })
157
+ doc('select', <<'EOT'
158
+ The select functions controls which resource is picked from an allocation and
159
+ it's alternatives. The selection is re-evaluated each time the resource used
160
+ in the previous time slot becomes unavailable.
161
+
162
+ Even for non-persistent allocations a change in the resource selection only
163
+ happens if the resource used in the previous (or next for ASAP tasks) time
164
+ slot has become unavailable.
165
+ EOT
166
+ )
167
+
168
+ pattern(%w( _persistent ), lambda {
169
+ @allocate.persistent = true
170
+ })
171
+ doc('persistent', <<'EOT'
172
+ Specifies that once a resource is picked from the list of alternatives this
173
+ resource is used for the whole task. This is useful when several alternative
174
+ resources have been specified. Normally the selected resource can change after
175
+ each break. A break is an interval of at least one timeslot where no resources
176
+ were available.
177
+ EOT
178
+ )
179
+
180
+ pattern(%w( _mandatory ), lambda {
181
+ @allocate.mandatory = true
182
+ })
183
+ doc('mandatory', <<'EOT'
184
+ Makes a resource allocation mandatory. This means, that for each time slot
185
+ only then resources are allocated when all mandatory resources are available.
186
+ So either all mandatory resources can be allocated for the time slot, or no
187
+ resource will be allocated.
188
+ EOT
189
+ )
190
+ end
191
+
192
+ def rule_allocationBody
193
+ optionsRule('allocationAttributes')
194
+ end
195
+
196
+ def rule_allocationHeader
197
+ pattern(%w( !resourceId ), lambda {
198
+ @allocate = Allocation.new([ @val[0] ])
199
+ })
200
+ end
201
+
202
+ def rule_allocations
203
+ listRule('moreAllocations', '!allocation')
204
+ end
205
+
206
+ def rule_allocationSelectionMode
207
+ singlePattern('_maxloaded')
208
+ descr('Pick the available resource that has been used the most so far.')
209
+
210
+ singlePattern('_minloaded')
211
+ descr('Pick the available resource that has been used the least so far.')
212
+
213
+ singlePattern('_minallocated')
214
+ descr(<<'EOT'
215
+ Pick the resource that has the smallest allocation factor. The
216
+ allocation factor is calculated from the various allocations of the resource
217
+ across the tasks. This is the default setting.)
218
+ EOT
219
+ )
220
+
221
+ singlePattern('_order')
222
+ descr('Pick the first available resource from the list.')
223
+
224
+ singlePattern('_random')
225
+ descr('Pick a random resource from the list.')
226
+ end
227
+
228
+ def rule_allocationShiftAssignment
229
+ pattern(%w( !shiftId !intervalsOptional ), lambda {
230
+ # Make sure we have a ShiftAssignment for the allocation.
231
+ if @allocate.shift.nil?
232
+ @allocate.shift = ShiftAssignments.new
233
+ @allocate.shift.setProject(@project)
234
+ end
235
+
236
+ if @val[1].nil?
237
+ intervals = [ Interval.new(@project['start'], @project['end']) ]
238
+ else
239
+ intervals = @val[1]
240
+ end
241
+ intervals.each do |interval|
242
+ if !@allocate.shift.
243
+ addAssignment(ShiftAssignment.new(@val[0].scenario(@scenarioIdx),
244
+ interval))
245
+ error('shift_assignment_overlap',
246
+ 'Shifts may not overlap each other.')
247
+ end
248
+ end
249
+ })
250
+ end
251
+
252
+ def rule_argument
253
+ pattern(%w( $ID ), lambda {
254
+ @val[0]
255
+ })
256
+ pattern(%w( $DATE ), lambda {
257
+ @val[0]
258
+ })
259
+ end
260
+
261
+ def rule_argumentList
262
+ optional
263
+ pattern(%w( _( !argumentListBody _) ), lambda {
264
+ @val[1].nil? ? [] : @val[1]
265
+ })
266
+ end
267
+
268
+ def rule_argumentListBody
269
+ optional
270
+ pattern(%w( !argument !moreArguments ), lambda {
271
+ [ @val[0] ] + (@val[1].nil? ? [] : @val[1])
272
+ })
273
+ end
274
+
275
+ def rule_balance
276
+ pattern(%w( _balance !accountId !accountId ), lambda {
277
+ if @val[1].parent
278
+ error('cost_acct_no_top',
279
+ "The cost account #{@val[1].fullId} is not a top-level account.")
280
+ end
281
+ if @val[2].parent
282
+ error('rev_acct_no_top',
283
+ "The revenue account #{@val[2].fullId} is not a top-level " +
284
+ "account.")
285
+ end
286
+ if @val[1] == @val[2]
287
+ error('cost_rev_same',
288
+ 'The cost and revenue accounts may not be the same.')
289
+ end
290
+ [ @val[1], @val[2] ]
291
+ })
292
+ doc('balance', <<'EOT'
293
+ During report generation, TaskJuggler can consider some accounts to be revenue accounts, while other can be considered cost accounts. By using the balance attribute, two top-level accounts can be designated for a profit-loss-analysis. This analysis includes all sub accounts of these two top-level accounts.
294
+ EOT
295
+ )
296
+ arg(1, 'cost account', <<'EOT'
297
+ The top-level account that is used for all cost related charges.
298
+ EOT
299
+ )
300
+ arg(2, 'revenue account', <<'EOT'
301
+ The top-level account that is used for all revenue related charges.
302
+ EOT
303
+ )
304
+ end
305
+
306
+ def rule_bookingAttributes
307
+ optional
308
+ repeatable
309
+
310
+ pattern(%w( _overtime $INTEGER ), lambda {
311
+ if @val[1] < 0 || @val[1] > 2
312
+ error('overtime_range',
313
+ "Overtime value #{@val[1]} out of range (0 - 2).", @property)
314
+ end
315
+ @booking.overtime = @val[1]
316
+ })
317
+ doc('overtime.booking', <<'EOT'
318
+ This attribute enables bookings to override working hours and vacations.
319
+ EOT
320
+ )
321
+
322
+ pattern(%w( _sloppy $INTEGER ), lambda {
323
+ if @val[1] < 0 || @val[1] > 2
324
+ error('sloppy_range',
325
+ "Sloppyness value #{@val[1]} out of range (0 - 2).", @property)
326
+ end
327
+ @booking.sloppy = @val[1]
328
+ })
329
+ doc('sloppy.booking', <<'EOT'
330
+ Controls how strict TaskJuggler checks booking intervals for conflicts with
331
+ vacation and other bookings. In case the error is suppressed the booking will
332
+ not overwrite the existing bookings. It will avoid the already assigned
333
+ intervals during booking.
334
+ EOT
335
+ )
336
+ end
337
+
338
+ def rule_bookingBody
339
+ optionsRule('bookingAttributes')
340
+ end
341
+
342
+ def rule_calendarDuration
343
+ pattern(%w( !number !durationUnit ), lambda {
344
+ convFactors = [ 60.0, # minutes
345
+ 60.0 * 60, # hours
346
+ 60.0 * 60 * 24, # days
347
+ 60.0 * 60 * 24 * 7, # weeks
348
+ 60.0 * 60 * 24 * 30.4167, # months
349
+ 60.0 * 60 * 24 * 365 # years
350
+ ]
351
+ ((@val[0] * convFactors[@val[1]]) / @project['scheduleGranularity']).to_i
352
+ })
353
+ arg(0, 'value', 'A floating point or integer number')
354
+ end
355
+
356
+ def rule_chargeset
357
+ pattern(%w( _chargeset !chargeSetItem !moreChargeSetItems ), lambda {
358
+ checkContainer('chargeset')
359
+ items = [ @val[1] ]
360
+ items += @val[2] if @val[2]
361
+ chargeSet = ChargeSet.new
362
+ begin
363
+ items.each do |item|
364
+ chargeSet.addAccount(item[0], item[1])
365
+ end
366
+ chargeSet.complete
367
+ rescue TjException
368
+ error('chargeset', $!.message)
369
+ end
370
+ masterAccounts = []
371
+ @property['chargeset', @scenarioIdx].each do |set|
372
+ masterAccounts << set.master
373
+ end
374
+ if masterAccounts.include?(chargeSet.master)
375
+ error('chargeset_master',
376
+ "All charge sets for this task must have different top-level " +
377
+ "accounts.")
378
+ end
379
+ @property['chargeset', @scenarioIdx] =
380
+ @property['chargeset', @scenarioIdx] + [ chargeSet ]
381
+ })
382
+ doc('chargeset', <<'EOT'
383
+ A chargeset defines how the turnover associated with the task will be charged
384
+ to one or more accounts. A task may have any number of charge sets, but each
385
+ chargeset must deal with a different top-level account. A charge set consists
386
+ of one or more accounts. Each account must be a leaf account. The account ID
387
+ may be followed by a percentage value that determines the share for this
388
+ account. The total percentage of all accounts must be exactly 100%. If some
389
+ accounts don't have a percentage specification, the remainder to 100% is
390
+ distributed evenly to them.
391
+ EOT
392
+ )
393
+ end
394
+
395
+ def rule_chargeMode
396
+ singlePattern('_onstart')
397
+ descr('Charge the amount on starting the task.')
398
+
399
+ singlePattern('_onend')
400
+ descr('Charge the amount on finishing the task.')
401
+
402
+ singlePattern('_perhour')
403
+ descr('Charge the amount for every hour the task lasts.')
404
+
405
+ singlePattern('_perday')
406
+ descr('Charge the amount for every day the task lasts.')
407
+
408
+ singlePattern('_perweek')
409
+ descr('Charge the amount for every week the task lasts.')
410
+ end
411
+
412
+ def rule_chargeSetItem
413
+ pattern(%w( !accountId !optionalPercent ), lambda {
414
+ [ @val[0], @val[1] ]
415
+ })
416
+ arg(0, 'account', 'The ID of a previously defined leaf account.')
417
+ arg(1, 'share', 'A percentage between 0 and 100%')
418
+ end
419
+
420
+ def rule_chartScale
421
+ singlePattern('_hour')
422
+ descr('Set chart resolution to 1 hour.')
423
+
424
+ singlePattern('_day')
425
+ descr('Set chart resolution to 1 day.')
426
+
427
+ singlePattern('_week')
428
+ descr('Set chart resolution to 1 week.')
429
+
430
+ singlePattern('_month')
431
+ descr('Set chart resolution to 1 month.')
432
+
433
+ singlePattern('_quarter')
434
+ descr('Set chart resolution to 1 quarter.')
435
+
436
+ singlePattern('_year')
437
+ descr('Set chart resolution to 1 year.')
438
+ end
439
+
440
+
441
+ def rule_columnBody
442
+ optionsRule('columnOptions')
443
+ end
444
+
445
+ def rule_columnDef
446
+ pattern(%w( !columnId !columnBody ), lambda {
447
+ @val[0]
448
+ })
449
+ end
450
+
451
+ def rule_columnId
452
+ pattern(%w( !reportableAttributes ), lambda {
453
+ title = @reportElement.defaultColumnTitle(@val[0])
454
+ @column = TableColumnDefinition.new(@val[0], title)
455
+ })
456
+ doc('columnid', <<'EOT'
457
+ In addition to the listed IDs all user defined attributes can be used as
458
+ column IDs.
459
+ EOT
460
+ )
461
+ end
462
+
463
+ def rule_columnOptions
464
+ optional
465
+ repeatable
466
+
467
+ pattern(%w( _celltext $STRING ), lambda {
468
+ @column.cellText = @val[1]
469
+ })
470
+ doc('celltext.column', <<'EOT'
471
+ Specifies an alternative content that is used for the cells of the column.
472
+ Usually such a text contains a runtime macro, otherwise all cells of the
473
+ column will have the same fixed value.
474
+ EOT
475
+ )
476
+ arg(1, 'text', 'Alterntive cell text')
477
+
478
+ pattern(%w( _cellurl $STRING ), lambda {
479
+ @column.cellURL = @val[1]
480
+ })
481
+ doc('cellurl.column', <<'EOT'
482
+ Specifies a URL that is associated with the content of the cell.
483
+ Usually such a URL contains a runtime macro, otherwise all cells of the
484
+ column will have the same fixed URL.
485
+ EOT
486
+ )
487
+ arg(1, 'text', 'Hyperlink address (e.g. http://www.taskjuggler.org)')
488
+
489
+ pattern(%w( _hidecelltext !logicalExpression ), lambda {
490
+ @column.hideCellText = @val[1]
491
+ })
492
+ doc('hidecelltext', <<'EOT'
493
+ This logical expression is evaluated during report generation for each report
494
+ cell. If it evaluates to true, the cell will have no content.
495
+ EOT
496
+ )
497
+
498
+ pattern(%w( _scale !chartScale ), lambda {
499
+ @column.scale = @val[1]
500
+ })
501
+ doc('scale.column', <<'EOT'
502
+ Specifies the scale that should be used for a chart column. This value is ignored for all other columns.
503
+ EOT
504
+ )
505
+
506
+ pattern(%w( _title $STRING ), lambda {
507
+ @column.title = @val[1]
508
+ })
509
+ doc('title.column', <<'EOT'
510
+ Specifies an alternative title for a report column.
511
+ EOT
512
+ )
513
+ arg(1, 'text', 'The new column title.')
514
+
515
+ pattern(%w( _width !number ), lambda {
516
+ @column.width = @val[1]
517
+ })
518
+ doc('width.column', <<'EOT'
519
+ Specifies the width of the column in screen pixels. If the content of the
520
+ column does not fit into this width, it will be cut off. In some cases a
521
+ scrollbar is added or a popup window is shown when the mouse is moved over the
522
+ column. The latter is only supported in interactive output formats.
523
+ EOT
524
+ )
525
+ end
526
+
527
+ def rule_csvFileName
528
+ pattern(%w( $STRING ), lambda {
529
+ # '.' means 'use $stdout'
530
+ if @val[0] == '.'
531
+ name = '.'
532
+ else
533
+ unless @val[0][-4,4] == '.csv'
534
+ error('no_csv_suffix',
535
+ "Report name must have .csv suffix: #{@val[0]}")
536
+ end
537
+ # Strip '.csv' suffix from file name
538
+ name = @val[0][0..-5]
539
+ end
540
+ if @project.reports[name]
541
+ error('report_redefinition',
542
+ "A report with the name #{name} has already been defined.")
543
+ end
544
+ name
545
+ })
546
+ arg(1, 'file name', <<'EOT'
547
+ The name of the report file to generate. It should end with a .html extension.
548
+ EOT
549
+ )
550
+ end
551
+
552
+ def rule_csvResourceReport
553
+ pattern(%w( !csvResourceReportHeader !reportBody ))
554
+ doc('csvresourcereport', <<'EOT'
555
+ The report lists all resources and their respective values as colon-separated-value (CSV) file. Due to
556
+ the very simple nature of the CSV format, only a small subset of features will
557
+ be supported for CSV output. Including tasks or listing multiple scenarios
558
+ will result in very difficult to read reports.
559
+ EOT
560
+ )
561
+ end
562
+
563
+ def rule_csvResourceReportHeader
564
+ pattern(%w( _csvresourcereport !csvFileName ), lambda {
565
+ @report = Report.new(@project, @val[1], :csv, sourceFileInfo)
566
+ @reportElement = ResourceListRE.new(@report)
567
+ })
568
+ end
569
+
570
+ def rule_csvTaskReport
571
+ pattern(%w( !csvTaskReportHeader !reportBody ))
572
+ doc('csvtaskreport', <<'EOT'
573
+ The report lists all tasks and their respective values as
574
+ colon-separated-value (CSV) file. Due to the very simple nature of the CSV
575
+ format, only a small subset of features will be supported for CSV output.
576
+ Including resources or listing multiple scenarios will result in very
577
+ difficult to read reports.
578
+ EOT
579
+ )
580
+ end
581
+
582
+ def rule_csvTaskReportHeader
583
+ pattern(%w( _csvtaskreport !csvFileName ), lambda {
584
+ @report = Report.new(@project, @val[1], :csv, sourceFileInfo)
585
+ @reportElement = TaskListRE.new(@report)
586
+ })
587
+ end
588
+
589
+ def rule_date
590
+ pattern(%w( $DATE ), lambda {
591
+ resolution = @project.nil? ? 60 * 60 : @project['scheduleGranularity']
592
+ if @val[0] % resolution != 0
593
+ error('misaligned_date',
594
+ "The date must be aligned to the timing resolution (" +
595
+ "#{resolution / 60} min) of the project.")
596
+ end
597
+ @val[0]
598
+ })
599
+ doc('date', <<'EOT'
600
+ A DATE is an ISO-compliant date in the format
601
+ ''''<nowiki>YYYY-MM-DD[-hh:mm[:ss]][-TIMEZONE]</nowiki>''''. Hour, minutes,
602
+ seconds, and the ''''TIMEZONE'''' are optional. If not specified, the values
603
+ are set to 0. ''''TIMEZONE'''' must be an offset to GMT or UTC, specified as
604
+ ''''+HHMM'''' or ''''-HHMM''''. Dates must always be aligned with the [[timingresolution]].
605
+ EOT
606
+ )
607
+ end
608
+
609
+ def rule_declareFlagList
610
+ listRule('moreDeclareFlagList', '$ID')
611
+ end
612
+
613
+ def rule_durationUnit
614
+ pattern(%w( _min ), lambda { 0 })
615
+ descr('minutes')
616
+
617
+ pattern(%w( _h ), lambda { 1 })
618
+ descr('hours')
619
+
620
+ pattern(%w( _d ), lambda { 2 })
621
+ descr('days')
622
+
623
+ pattern(%w( _w ), lambda { 3 })
624
+ descr('weeks')
625
+
626
+ pattern(%w( _m ), lambda { 4 })
627
+ descr('months')
628
+
629
+ pattern(%w( _y ), lambda { 5 })
630
+ descr('years')
631
+ end
632
+
633
+ def rule_export
634
+ pattern(%w( !exportHeader !exportBody ))
635
+ doc('export', <<'EOT'
636
+ The export report looks like a regular TaskJuggler file but contains fixed
637
+ start and end dates for all tasks. The tasks only have start and end times,
638
+ their description and their project id listed. No other attributes are
639
+ exported unless they are requested using the taskattributes attribute. The
640
+ contents also depends on the extension of the file name. If the file name ends
641
+ with .tjp a complete project with header, resource and shift definitions is
642
+ generated. In case it ends with .tji only the tasks and resource allocations
643
+ are exported.
644
+
645
+ If specified the resource usage for the tasks is reported as well. But only
646
+ those allocations are listed that belong to tasks listed in the same export
647
+ report.
648
+
649
+ The export report can be used to share certain tasks or milestones with other
650
+ projects or to save past resource allocations as immutable part for future
651
+ scheduling runs. When an export report is included the project IDs of the
652
+ included tasks must be declared first with the project id property.`
653
+ EOT
654
+ )
655
+ example('Export')
656
+ end
657
+
658
+ def rule_exportableResourceAttribute
659
+ singlePattern('_all')
660
+ singlePattern('_none')
661
+ singlePattern('_vacation')
662
+ singlePattern('_workinghours')
663
+ end
664
+
665
+ def rule_exportableResourceAttributes
666
+ listRule('moreExportableResourceAttributes', '!exportableResourceAttribute')
667
+ end
668
+
669
+ def rule_exportableTaskAttribute
670
+ singlePattern('_all')
671
+ singlePattern('_booking')
672
+ singlePattern('_complete')
673
+ singlePattern('_depends')
674
+ singlePattern('_flags')
675
+ singlePattern('_maxend')
676
+ singlePattern('_maxstart')
677
+ singlePattern('_minend')
678
+ singlePattern('_minstart')
679
+ singlePattern('_none')
680
+ singlePattern('_note')
681
+ singlePattern('_priority')
682
+ singlePattern('_responsible')
683
+ end
684
+
685
+ def rule_exportableTaskAttributes
686
+ listRule('moreExportableTaskAttributes', '!exportableTaskAttribute')
687
+ end
688
+
689
+ def rule_exportHeader
690
+ pattern(%w( _export $STRING ), lambda {
691
+ if @val[1] == '.'
692
+ mainFile = true
693
+ name = '.'
694
+ else
695
+ extension = @val[1][-4, 4]
696
+ if extension == '.tjp'
697
+ mainFile = true
698
+ elsif extension == '.tji'
699
+ mainFile = false
700
+ else
701
+ error('export_bad_extn',
702
+ 'Export report files must have a .tjp or .tji extension.')
703
+ end
704
+ # File name without extension.
705
+ name = @val[1][0..-5]
706
+ end
707
+
708
+ if @project.reports[name]
709
+ error('report_redefinition',
710
+ "A report with the name #{name} has already been defined.")
711
+ end
712
+ @report = Report.new(@project, name, :export, sourceFileInfo)
713
+ @reportElement = TjpExportRE.new(@report, mainFile)
714
+ })
715
+ arg(1, 'file name', <<'EOT'
716
+ The name of the report file to generate. It must end with a .tjp or .tji
717
+ extension, or use . to use the standard output channel.
718
+ EOT
719
+ )
720
+ end
721
+
722
+ def rule_exportAttributes
723
+ optional
724
+ repeatable
725
+
726
+ pattern(%w( !hideresource ))
727
+ pattern(%w( !hidetask ))
728
+ pattern(%w( !reportEnd ))
729
+ pattern(%w( !reportPeriod ))
730
+ pattern(%w( !reportStart ))
731
+ pattern(%w( _resourceattributes !exportableResourceAttributes ), lambda {
732
+ @reportElement.resourceAttrs = @val[1].include?('none') ? [] : @val[1]
733
+ })
734
+ doc('resourceattributes', <<"EOT"
735
+ Define a list of resource attributes that should be included in the report. To
736
+ include all supported attributes just use ''''all''''. When ''''none'''' is
737
+ used, no optional resource attributes will be exported.
738
+ EOT
739
+ )
740
+ pattern(%w( _taskattributes !exportableTaskAttributes ), lambda {
741
+ @reportElement.taskAttrs = @val[1].include?('none') ? [] : @val[1]
742
+ })
743
+ doc('taskattributes', <<"EOT"
744
+ Define a list of task attributes that should be included in the report. To
745
+ include all supported attributes just use ''''all''''. When ''''none'''' is
746
+ used, no optional task attributes will be exported.
747
+ EOT
748
+ )
749
+ end
750
+
751
+ def rule_exportBody
752
+ optionsRule('exportAttributes')
753
+ end
754
+
755
+ def rule_extendAttributes
756
+ optional
757
+ repeatable
758
+
759
+ pattern(%w( _date !extendId $STRING !extendOptionsBody ), lambda {
760
+ # Extend the propertySet definition and parser rules
761
+ if extendPropertySetDefinition(DateAttribute, nil)
762
+ @ruleToExtendWithScenario.addPattern(TextParser::Pattern.new(
763
+ [ '_' + @val[1], '!date' ], lambda {
764
+ @property[@val[0], @scenarioIdx] = @val[1]
765
+ }))
766
+ else
767
+ @ruleToExtend.addPattern(TextParser::Pattern.new(
768
+ [ '_' + @val[1], '!date' ], lambda {
769
+ @property.set(@val[0], @val[1])
770
+ }))
771
+ end
772
+ })
773
+ doc('date.extend', <<'EOT'
774
+ Extend the property with a new attribute of type date.
775
+ EOT
776
+ )
777
+ arg(2, 'name', 'The name of the new attribute. It is used as header ' +
778
+ 'in report columns and the like.')
779
+
780
+ pattern(%w( _reference !extendId $STRING !extendOptionsBody ), lambda {
781
+ # Extend the propertySet definition and parser rules
782
+ if extendPropertySetDefinition(ReferenceAttribute, nil)
783
+ @ruleToExtendWithScenario.addPattern(TextParser::Pattern.new(
784
+ [ '_' + @val[1], '$STRING', '!referenceBody' ], lambda {
785
+ @property[@val[0], @scenarioIdx] = [ @val[1], @val[2] ]
786
+ }))
787
+ else
788
+ @ruleToExtend.addPattern(TextParser::Pattern.new(
789
+ [ '_' + @val[1], '$STRING', '!referenceBody' ], lambda {
790
+ @property.set(@val[0], [ @val[1], @val[2] ])
791
+ }))
792
+ end
793
+ })
794
+ doc('reference.extend', <<'EOT'
795
+ Extend the property with a new attribute of type reference. A reference is a
796
+ URL and an optional text that will be shown instead of the URL if needed.
797
+ EOT
798
+ )
799
+ arg(2, 'name', 'The name of the new attribute. It is used as header ' +
800
+ 'in report columns and the like.')
801
+
802
+ pattern(%w( _text !extendId $STRING !extendOptionsBody ), lambda {
803
+ # Extend the propertySet definition and parser rules
804
+ if extendPropertySetDefinition(StringAttribute, nil)
805
+ @ruleToExtendWithScenario.addPattern(TextParser::Pattern.new(
806
+ [ '_' + @val[1], '$STRING' ], lambda {
807
+ @property[@val[0], @scenarioIdx] = @val[1]
808
+ }))
809
+ else
810
+ @ruleToExtend.addPattern(TextParser::Pattern.new(
811
+ [ '_' + @val[1], '$STRING' ], lambda {
812
+ @property.set(@val[0], @val[1])
813
+ }))
814
+ end
815
+ })
816
+ doc('text.extend', <<'EOT'
817
+ Extend the property with a new attribute of type text. A text is a character
818
+ sequence enclosed in single or double quotes.
819
+ EOT
820
+ )
821
+ arg(2, 'name', 'The name of the new attribute. It is used as header ' +
822
+ 'in report columns and the like.')
823
+
824
+ end
825
+
826
+ def rule_extendBody
827
+ optionsRule('extendAttributes')
828
+ end
829
+
830
+ def rule_extendId
831
+ pattern(%w( $ID ), lambda {
832
+ unless (?A..?Z) === @val[0][0]
833
+ error('extend_id_cap',
834
+ "User defined attributes IDs must start with a capital letter")
835
+ end
836
+ @val[0]
837
+ })
838
+ arg(0, 'id', 'The ID of the new attribute. It can be used like the ' +
839
+ 'built-in IDs.')
840
+ end
841
+
842
+ def rule_extendOptions
843
+ optional
844
+ repeatable
845
+
846
+ singlePattern('_inherit')
847
+ doc('inherit.extend', <<'EOT'
848
+ If the this attribute is used, the property extension will be inherited by
849
+ child properties from their parent property.
850
+ EOT
851
+ )
852
+
853
+ singlePattern('_scenariospecific')
854
+ doc('scenariospecific.extend', <<'EOT'
855
+ If this attribute is used, the property extension is scenario specific. A
856
+ different value can be set for each scenario.
857
+ EOT
858
+ )
859
+ end
860
+
861
+ def rule_extendOptionsBody
862
+ optionsRule('extendOptions')
863
+ end
864
+
865
+ def rule_extendProperty
866
+ pattern(%w( !extendPropertyId ), lambda {
867
+ case @val[0]
868
+ when 'task'
869
+ @ruleToExtend = @rules['taskAttributes']
870
+ @ruleToExtendWithScenario = @rules['taskScenarioAttributes']
871
+ @propertySet = @project.tasks
872
+ when 'resource'
873
+ @ruleToExtend = @rules['resourceAttributes']
874
+ @ruleToExtendWithScenario = @rules['resourceScenarioAttributes']
875
+ @propertySet = @project.resources
876
+ end
877
+ })
878
+ end
879
+
880
+ def rule_extendPropertyId
881
+ singlePattern('_task')
882
+ singlePattern('_resource')
883
+ end
884
+
885
+ def rule_flag
886
+ pattern(%w( $ID ), lambda {
887
+ unless @project['flags'].include?(@val[0])
888
+ error('undecl_flag', "Undeclared flag #{@val[0]}")
889
+ end
890
+ @val[0]
891
+ })
892
+ end
893
+
894
+ def rule_flags
895
+ pattern(%w( _flags !flagList ), lambda {
896
+ @val[1].each do |flag|
897
+ unless @property['flags', @scenarioIdx].include?(flag)
898
+ @property['flags', @scenarioIdx] =
899
+ @property['flags', @scenarioIdx] + @val[1]
900
+ end
901
+ end
902
+ })
903
+ end
904
+
905
+ def rule_flagList
906
+ listRule('moreFlagList', '!flag')
907
+ end
908
+
909
+ def rule_functions
910
+ # This rule is not used by the parser. It's only for the documentation.
911
+ pattern(%w( !functionsBody ))
912
+ doc('functions', <<'EOT'
913
+ The following functions are supported in logical expressions. These functions
914
+ are evaluated in logical conditions such as hidetask or rollupresource. For
915
+ the evaluation, implicit and explicit parameters are used. All functions may
916
+ operate on the current property and the scope property. The scope property is
917
+ the enclosing property in reports with nested properties. E. g. in a task
918
+ report with nested resources, the task is the scope property and the the
919
+ resource is the property the the function is called for the resource line. The
920
+ explicit parameters are passed in the function call. These arguments may vary
921
+ from function to function.
922
+ EOT
923
+ )
924
+ end
925
+
926
+ def rule_functionsBody
927
+ # This rule is not used by the parser. It's only for the documentation.
928
+ optionsRule('functionPatterns')
929
+ end
930
+
931
+ def rule_functionPatterns
932
+ # This rule is not used by the parser. It's only for the documentation.
933
+ pattern(['_isleaf', '_(', '_)' ])
934
+ doc('isleaf', 'The result is true if the property is not a container.')
935
+
936
+ pattern(['_isresource', '_(', '$ID', '_)' ])
937
+ doc('isresource', <<'EOT'
938
+ The result is true if the property is a resource with the specified ID.
939
+ EOT
940
+ )
941
+ arg(2, 'ID', 'A resource ID')
942
+ end
943
+
944
+ def rule_hideresource
945
+ pattern(%w( _hideresource !logicalExpression ), lambda {
946
+ @reportElement.hideResource = @val[1]
947
+ })
948
+ doc('hideresource', <<'EOT'
949
+ Do not include resources that match the specified logical expression. If the
950
+ report is sorted in tree mode (default) then enclosing resources are listed
951
+ even if the expression matches the resource.
952
+ EOT
953
+ )
954
+ end
955
+
956
+ def rule_hidetask
957
+ pattern(%w( _hidetask !logicalExpression ), lambda {
958
+ @reportElement.hideTask = @val[1]
959
+ })
960
+ doc('hidetask', <<'EOT'
961
+ Do not include tasks that match the specified logical expression. If the
962
+ report is sorted in tree mode (default) then enclosing tasks are listed even
963
+ if the expression matches the task.
964
+ EOT
965
+ )
966
+ end
967
+
968
+ def rule_htmlFileName
969
+ pattern(%w( $STRING ), lambda {
970
+ unless @val[0][-5,5] == '.html'
971
+ error('no_html_suffix',
972
+ "Report name must have .html suffix: #{@val[0]}")
973
+ end
974
+ # Strip '.html' suffix from file name
975
+ name = @val[0][0..-6]
976
+ if @project.reports[name]
977
+ error('report_redefinition',
978
+ "A report with the name #{name} has already been defined.")
979
+ end
980
+ name
981
+ })
982
+ arg(1, 'file name', <<'EOT'
983
+ The name of the report file to generate. It should end with a .html extension.
984
+ EOT
985
+ )
986
+ end
987
+
988
+ def rule_htmlResourceReport
989
+ pattern(%w( !htmlResourceReportHeader !reportBody ))
990
+ doc('htmlresourcereport', <<'EOT'
991
+ The report lists all resources and their respective values as a HTML page. The
992
+ task that are the resources are allocated to can be listed as well.
993
+ EOT
994
+ )
995
+ end
996
+
997
+ def rule_htmlResourceReportHeader
998
+ pattern(%w( _htmlresourcereport !htmlFileName ), lambda {
999
+ @report = Report.new(@project, @val[1], :html, sourceFileInfo)
1000
+ @reportElement = ResourceListRE.new(@report)
1001
+ })
1002
+ end
1003
+
1004
+ def rule_htmlTaskReport
1005
+ pattern(%w( !htmlTaskReportHeader !reportBody ))
1006
+ doc('htmltaskreport', <<'EOT'
1007
+ The report lists all tasks and their respective values as a HTML page. The
1008
+ resources that are allocated to each task can be listed as well.
1009
+ EOT
1010
+ )
1011
+ end
1012
+
1013
+ def rule_htmlTaskReportHeader
1014
+ pattern(%w( _htmltaskreport !htmlFileName ), lambda {
1015
+ @report = Report.new(@project, @val[1], :html, sourceFileInfo)
1016
+ @reportElement = TaskListRE.new(@report)
1017
+ })
1018
+ end
1019
+
1020
+ def rule_includeAttributes
1021
+ optionsRule('includeAttributesBody')
1022
+ end
1023
+
1024
+ def rule_includeAttributesBody
1025
+ optional
1026
+ repeatable
1027
+
1028
+ pattern(%w( _accountprefix !taskId ), lambda {
1029
+ @accountprefix = @val[1].fullId
1030
+ })
1031
+ doc('accountprefix', <<'EOT'
1032
+ This attribute can be used to insert the accounts of the included file as
1033
+ sub-account of the account specified by ID. The parent account must already be
1034
+ defined.
1035
+ EOT
1036
+ )
1037
+
1038
+ pattern(%w( _resourceprefix !taskId ), lambda {
1039
+ @resourceprefix = @val[1].fullId
1040
+ })
1041
+ doc('resourceprefix', <<'EOT'
1042
+ This attribute can be used to insert the resources of the included file as
1043
+ sub-resource of the resource specified by ID. The parent resource must already
1044
+ be defined.
1045
+ EOT
1046
+ )
1047
+
1048
+ pattern(%w( _taskprefix !taskId ), lambda {
1049
+ @taskprefix = @val[1].fullId
1050
+ })
1051
+ doc('taskprefix', <<'EOT'
1052
+ This attribute can be used to insert the tasks of the included file as
1053
+ sub-task of the task specified by ID. The parent task must already be defined.
1054
+ EOT
1055
+ )
1056
+ end
1057
+
1058
+ def rule_includeFile
1059
+ pattern(%w( $STRING ), lambda {
1060
+ @scanner.include(@val[0])
1061
+ })
1062
+ arg(0, 'filename', <<'EOT'
1063
+ Name of the file to include. This must have a ''''.tji'''' extension. The name may have an absolute or relative path. You need to use ''''/'''' characters to separate directories.
1064
+ EOT
1065
+ )
1066
+ end
1067
+
1068
+ def rule_includeProperties
1069
+ pattern(%w( $STRING !includeAttributes ), lambda {
1070
+ pushFileStack
1071
+ @scanner.include(@val[0])
1072
+ })
1073
+ arg(0, 'filename', <<'EOT'
1074
+ Name of the file to include. This must have a ''''.tji'''' extension. The name may have an absolute or relative path. You need to use ''''/'''' characters to separate directories.
1075
+ EOT
1076
+ )
1077
+ end
1078
+
1079
+ def rule_intervalOrDate
1080
+ pattern(%w( !date !intervalOptionalEnd ), lambda {
1081
+ if @val[1]
1082
+ mode = @val[1][0]
1083
+ endSpec = @val[1][1]
1084
+ if mode == 0
1085
+ unless @val[0] < endSpec
1086
+ error('start_before_end', "The end date (#{endSpec}) must be " +
1087
+ "after the start date (#{@val[0]}).")
1088
+ end
1089
+ Interval.new(@val[0], endSpec)
1090
+ else
1091
+ Interval.new(@val[0], @val[0] + endSpec)
1092
+ end
1093
+ else
1094
+ Interval.new(@val[0], @val[0].sameTimeNextDay)
1095
+ end
1096
+ })
1097
+ doc('interval3', <<'EOT'
1098
+ There are three ways to specify a date interval. The first is the most
1099
+ obvious. A date interval consists of a start and end DATE. Watch out for end
1100
+ dates without a time specification! Date specifications are 0 extended. An
1101
+ end date without a time is expanded to midnight that day. So the day of the
1102
+ end date is not included in the interval! The start and end dates must be separated by a hyphen character.
1103
+
1104
+ In the second form, the end date is omitted. A 24 hour interval is assumed.
1105
+
1106
+ The third form specifies the start date and an interval duration. The duration must be prefixed by a plus character.
1107
+ EOT
1108
+ )
1109
+ end
1110
+
1111
+ def rule_interval
1112
+ pattern(%w( !date !intervalEnd ), lambda {
1113
+ mode = @val[1][0]
1114
+ endSpec = @val[1][1]
1115
+ if mode == 0
1116
+ Interval.new(@val[0], endSpec)
1117
+ else
1118
+ Interval.new(@val[0], @val[0] + endSpec)
1119
+ end
1120
+ })
1121
+ doc('interval2', <<'EOT'
1122
+ There are two ways to specify a date interval. The first is the most
1123
+ obvious. A date interval consists of a start and end DATE. Watch out for end
1124
+ dates without a time specification! Date specifications are 0 extended. An
1125
+ end date without a time is expanded to midnight that day. So the day of the
1126
+ end date is not included in the interval! The start and end dates must be separated by a hyphen character.
1127
+
1128
+ In the second form specifies the start date and an interval duration. The
1129
+ duration must be prefixed by a plus character.
1130
+ EOT
1131
+ )
1132
+ end
1133
+
1134
+ def rule_intervalDuration
1135
+ pattern(%w( !number !durationUnit ), lambda {
1136
+ convFactors = [ 60, # minutes
1137
+ 60 * 60, # hours
1138
+ 60 * 60 * 24, # days
1139
+ 60 * 60 * 24 * 7, # weeks
1140
+ 60 * 60 * 24 * 30.4167, # months
1141
+ 60 * 60 * 24 * 365 # years
1142
+ ]
1143
+ duration = @val[0] * convFactors[@val[1]]
1144
+ resolution = @project.nil? ? 60 * 60 : @project['scheduleGranularity']
1145
+ # Make sure the interval aligns with the timing resolution.
1146
+ (duration / resolution).to_i * resolution
1147
+ })
1148
+ arg(0, 'duration', 'The duration of the interval')
1149
+ end
1150
+
1151
+ def rule_intervalEnd
1152
+ pattern([ '_ - ', '!date' ], lambda {
1153
+ [ 0, @val[1] ]
1154
+ })
1155
+
1156
+ pattern(%w( _+ !intervalDuration ), lambda {
1157
+ [ 1, @val[1] ]
1158
+ })
1159
+ end
1160
+
1161
+ def rule_intervalOptionalEnd
1162
+ optional
1163
+ pattern([ '_ - ', '!date' ], lambda {
1164
+ [ 0, @val[1] ]
1165
+ })
1166
+
1167
+ pattern(%w( _+ !intervalDuration ), lambda {
1168
+ [ 1, @val[1] ]
1169
+ })
1170
+ end
1171
+
1172
+ def rule_intervals
1173
+ listRule('moreIntervals', '!intervalOrDate')
1174
+ end
1175
+
1176
+ def rule_intervalsOptional
1177
+ optional
1178
+ singlePattern('!intervals')
1179
+ end
1180
+
1181
+ def rule_leafResourceId
1182
+ pattern(%w( !resourceId ), lambda {
1183
+ resource = @val[0]
1184
+ unless resource.leaf?
1185
+ error('leaf_resource_id_expected', "#{resource.id} is not a leaf resource.")
1186
+ end
1187
+ resource
1188
+ })
1189
+ arg(0, 'resource', 'The ID of a leaf resource')
1190
+ end
1191
+
1192
+ def rule_limitAttributes
1193
+ optionsRule('limitAttributesBody')
1194
+ end
1195
+
1196
+ def rule_limitAttributesBody
1197
+ optional
1198
+ repeatable
1199
+
1200
+ pattern(%w( _end !valDate ), lambda {
1201
+ @limitInterval.end = @val[1]
1202
+ })
1203
+ doc('limit.end', <<'EOT'
1204
+ The end date of the limit interval. It must be within the project time frame.
1205
+ EOT
1206
+ )
1207
+
1208
+ pattern(%w( _period !valInterval ), lambda {
1209
+ @limitInterval = @val[1]
1210
+ })
1211
+ doc('limit.period', <<'EOT'
1212
+ This property is a shortcut for setting the start and end dates of the limit
1213
+ interval. Both dates must be within the project time frame.
1214
+ EOT
1215
+ )
1216
+
1217
+ pattern(%w( _resources !resourceLeafList ), lambda {
1218
+ @limitResources = @val[1]
1219
+ })
1220
+ doc('limit.resources', <<'EOT'
1221
+ When [[limits]] are used in a [[task]] context, the limits can be restricted
1222
+ to a list of resources that are allocated to the task. In that case each
1223
+ resource will not be allocated more than the specified upper limit. Lower
1224
+ limits have no impact on the scheduler but do generate a warning when not met.
1225
+ All specified resources must be leaf resources.
1226
+ EOT
1227
+ )
1228
+
1229
+ pattern(%w( _start !valDate ), lambda {
1230
+ @limitInterval.start = @val[1]
1231
+ })
1232
+ doc('limit.start', <<'EOT'
1233
+ The start date of the limit interval. It must be within the project time frame.
1234
+ EOT
1235
+ )
1236
+ end
1237
+
1238
+ def rule_limitValue
1239
+ pattern([ '!workingDuration' ], lambda {
1240
+ @limitInterval = Interval.new(@project['start'], @project['end'])
1241
+ @limitResources = []
1242
+ @val[0]
1243
+ })
1244
+ end
1245
+
1246
+ def rule_limits
1247
+ pattern(%w( !limitsHeader !limitsBody ), lambda {
1248
+ @val[0]
1249
+ })
1250
+ end
1251
+
1252
+ def rule_limitsAttributes
1253
+ optional
1254
+ repeatable
1255
+
1256
+ pattern(%w( _dailymax !limitValue !limitAttributes), lambda {
1257
+ setLimit(@val[0], @val[1], @limitInterval)
1258
+ })
1259
+ doc('dailymax', <<'EOT'
1260
+ Set a maximum limit for each calendar day.
1261
+ EOT
1262
+ )
1263
+ example('Limits-1', '1')
1264
+
1265
+ pattern(%w( _dailymin !limitValue !limitAttributes), lambda {
1266
+ setLimit(@val[0], @val[1], @limitInterval)
1267
+ })
1268
+ doc('dailymin', <<'EOT'
1269
+ Minimum required effort for any calendar day. This value cannot be guaranteed by
1270
+ the scheduler. It is only checked after the schedule is complete. In case the
1271
+ minium required amount has not been reached, a warning will be generated.
1272
+ EOT
1273
+ )
1274
+ example('Limits-1', '4')
1275
+
1276
+ pattern(%w( _maximum !limitValue !limitAttributes), lambda {
1277
+ setLimit(@val[0], @val[1], @limitInterval)
1278
+ })
1279
+ doc('maximum', <<'EOT'
1280
+ Set a maximum limit for the specified period. You must ensure that the overall
1281
+ effort can be achieved!
1282
+ EOT
1283
+ )
1284
+
1285
+ pattern(%w( _minimum !limitValue !limitAttributes), lambda {
1286
+ setLimit(@val[0], @val[1], @limitInterval)
1287
+ })
1288
+ doc('minimum', <<'EOT'
1289
+ Set a minim limit for each calendar month. This will only result in a warning
1290
+ if not met.
1291
+ EOT
1292
+ )
1293
+
1294
+ pattern(%w( _monthlymax !limitValue !limitAttributes), lambda {
1295
+ setLimit(@val[0], @val[1], @limitInterval)
1296
+ })
1297
+ doc('monthlymax', <<'EOT'
1298
+ Set a maximum limit for each calendar month.
1299
+ EOT
1300
+ )
1301
+
1302
+ pattern(%w( _monthlymin !limitValue !limitAttributes), lambda {
1303
+ setLimit(@val[0], @val[1], @limitInterval)
1304
+ })
1305
+ doc('monthlymin', <<'EOT'
1306
+ Minimum required effort for any calendar month. This value cannot be
1307
+ guaranteed by the scheduler. It is only checked after the schedule is
1308
+ complete. In case the minium required amount has not been reached, a warning
1309
+ will be generated.
1310
+ EOT
1311
+ )
1312
+
1313
+ pattern(%w( _weeklymax !limitValue !limitAttributes), lambda {
1314
+ setLimit(@val[0], @val[1], @limitInterval)
1315
+ })
1316
+ doc('weeklymax', <<'EOT'
1317
+ Set a maximum limit for each calendar week.
1318
+ EOT
1319
+ )
1320
+
1321
+ pattern(%w( _weeklymin !limitValue !limitAttributes), lambda {
1322
+ setLimit(@val[0], @val[1], @limitInterval)
1323
+ })
1324
+ doc('weeklymin', <<'EOT'
1325
+ Minimum required effort for any calendar week. This value cannot be guaranteed by
1326
+ the scheduler. It is only checked after the schedule is complete. In case the
1327
+ minium required amount has not been reached, a warning will be generated.
1328
+ EOT
1329
+ )
1330
+ end
1331
+
1332
+ def rule_limitsBody
1333
+ optionsRule('limitsAttributes')
1334
+ end
1335
+
1336
+ def rule_limitsHeader
1337
+ pattern(%w( _limits ), lambda {
1338
+ @limits = Limits.new
1339
+ @limits.setProject(@project)
1340
+ @limits
1341
+ })
1342
+ end
1343
+
1344
+ def rule_listOfDays
1345
+ pattern(%w( !weekDayInterval !moreListOfDays), lambda {
1346
+ weekDays = Array.new(7, false)
1347
+ ([ @val[0] ] + @val[1]).each do |dayList|
1348
+ 7.times { |i| weekDays[i] = true if dayList[i] }
1349
+ end
1350
+ weekDays
1351
+ })
1352
+ end
1353
+
1354
+ def rule_listOfTimes
1355
+ pattern(%w( _off ), lambda {
1356
+ [ ]
1357
+ })
1358
+ pattern(%w( !timeInterval !moreTimeIntervals ), lambda {
1359
+ [ @val[0] ] + @val[1]
1360
+ })
1361
+ end
1362
+
1363
+ def rule_loadunit
1364
+ singlePattern('_days')
1365
+ descr('Display all load and duration values as days.')
1366
+
1367
+ singlePattern('_hours')
1368
+ descr('Display all load and duration values as hours.')
1369
+
1370
+ singlePattern('_longauto')
1371
+ descr(<<'EOT'
1372
+ Automatically select the unit that produces the shortest and most readable
1373
+ value. The unit name will not be abbreviated.
1374
+ EOT
1375
+ )
1376
+
1377
+ singlePattern('_minutes')
1378
+ descr('Display all load and duration values as minutes.')
1379
+
1380
+ singlePattern('_months')
1381
+ descr('Display all load and duration values as monts.')
1382
+
1383
+ singlePattern('_shortauto')
1384
+ descr(<<'EOT'
1385
+ Automatically select the unit that produces the shortest and most readable
1386
+ value. The unit name will be abbreviated.
1387
+ EOT
1388
+ )
1389
+
1390
+ singlePattern('_weeks')
1391
+ descr('Display all load and duration values as weeks.')
1392
+
1393
+ singlePattern('_years')
1394
+ descr('Display all load and duration values as years.')
1395
+ end
1396
+
1397
+ def rule_logicalExpression
1398
+ pattern(%w( !operation ), lambda {
1399
+ LogicalExpression.new(@val[0], sourceFileInfo)
1400
+ })
1401
+ doc('logicalexpression', <<'EOT'
1402
+ A logical expression is a combination of operands and mathematical operations.
1403
+ The final result of a logical expression is always true or false. Logical
1404
+ expressions are used the reduce the properties in a report to a certain
1405
+ subset. If the logical expression evaluates to true for a certain property,
1406
+ this property is hidden or rolled-up in the report.
1407
+
1408
+ Operands can be declared flags, built-in functions, property attributes
1409
+ (specified as scenario.attribute) or another logical expression. The latter
1410
+ should be enclosed in brackets to avoid ambiguities.
1411
+ EOT
1412
+ )
1413
+ also(%w( functions ))
1414
+ end
1415
+
1416
+ def rule_macro
1417
+ pattern(%w( _macro $ID $MACRO ), lambda {
1418
+ @scanner.addMacro(Macro.new(@val[1], @val[2], @scanner.sourceFileInfo))
1419
+ })
1420
+ doc('macro', <<'EOT'
1421
+ Defines a text fragment that can later be inserted by using the specified ID.
1422
+ To insert the text fragment anywhere in the text you need to write ${ID}.The
1423
+ body is not optional. It must be enclosed in square brackets. Macros can be
1424
+ declared like this:
1425
+
1426
+ macro FOO [ This text ]
1427
+
1428
+ If later ''''${FOO}'''' is found in the project file, it is expanded to
1429
+ ''''This text''''.
1430
+
1431
+ Macros may have arguments. Arguments are accessed with special macros with
1432
+ numbers as names. The number specifies the index of the argument.
1433
+
1434
+ macro FOO [ This ${1} text ]
1435
+
1436
+ will expand to ''''This stupid text'''' if called as ''''${FOO "stupid"}''''.
1437
+ Macros may call other macros.
1438
+
1439
+ User defined macro IDs must have at least one uppercase letter as all
1440
+ lowercase letter IDs are reserved for built-in macros.
1441
+
1442
+ In macro calls the macro names can be prefixed by a question mark. In this
1443
+ case the macro will expand to nothing if the macro is not defined. Otherwise
1444
+ the undefined macro would be flagged with an error message.
1445
+
1446
+ The macro call
1447
+
1448
+ ${?foo}
1449
+
1450
+ will expand to nothing if foo is undefined.
1451
+ EOT
1452
+ )
1453
+ example('Macro-1')
1454
+ end
1455
+
1456
+ def rule_moreAlternatives
1457
+ commaListRule('!resourceId')
1458
+ end
1459
+
1460
+ def rule_moreArguments
1461
+ commaListRule('!argument')
1462
+ end
1463
+
1464
+ def rule_moreChargeSetItems
1465
+ commaListRule('!chargeSetItem')
1466
+ end
1467
+
1468
+ def rule_moreColumnDef
1469
+ commaListRule('!columnDef')
1470
+ end
1471
+
1472
+ def rule_moreDepTasks
1473
+ commaListRule('!taskDep')
1474
+ end
1475
+
1476
+ def rule_moreLeafResources
1477
+ commaListRule('!resourceLeafList')
1478
+ end
1479
+
1480
+ def rule_moreListOfDays
1481
+ commaListRule('!weekDayInterval')
1482
+ end
1483
+
1484
+ def rule_moreProjectIDs
1485
+ commaListRule('$ID')
1486
+ end
1487
+
1488
+ def rule_moreResources
1489
+ commaListRule('!resourceList')
1490
+ end
1491
+
1492
+ def rule_morePredTasks
1493
+ commaListRule('!taskPredList')
1494
+ end
1495
+
1496
+ def rule_moreSortCriteria
1497
+ commaListRule('!sortNonTree')
1498
+ end
1499
+
1500
+ def rule_moreTimeIntervals
1501
+ commaListRule('!timeInterval')
1502
+ end
1503
+
1504
+ def rule_number
1505
+ singlePattern('$INTEGER')
1506
+ singlePattern('$FLOAT')
1507
+ end
1508
+
1509
+ def rule_operand
1510
+ pattern(%w( _( !operation _) ), lambda {
1511
+ @val[1]
1512
+ })
1513
+ pattern(%w( _~ !operand ), lambda {
1514
+ operation = LogicalOperation.new(@val[1])
1515
+ operation.operator = '~'
1516
+ operation
1517
+ })
1518
+
1519
+ pattern(%w( $ABSOLUTE_ID ), lambda {
1520
+ if @val[0].count('.') > 1
1521
+ error('operand_attribute',
1522
+ 'Attributes must be specified as <scenarioID>.<attribute>')
1523
+ end
1524
+ scenario, attribute = @val[0].split('.')
1525
+ if (scenarioIdx = @project.scenarioIdx(scenario)).nil?
1526
+ error('operand_unkn_scen',
1527
+ "Unknown scenario ID #{scenario}")
1528
+ end
1529
+ LogicalAttribute.new(attribute, scenarioIdx)
1530
+ })
1531
+ pattern(%w( !date ), lambda {
1532
+ LogicalOperation.new(@val[0])
1533
+ })
1534
+ pattern(%w( $ID !argumentList ), lambda {
1535
+ if @val[1].nil?
1536
+ unless @project['flags'].include?(@val[0])
1537
+ error('operand_unkn_flag', "Undeclared flag #{@val[0]}")
1538
+ end
1539
+ LogicalFlag.new(@val[0])
1540
+ else
1541
+ func = LogicalFunction.new(@val[0])
1542
+ res = func.setArgumentsAndCheck(@val[1])
1543
+ unless res.nil?
1544
+ error(*res)
1545
+ end
1546
+ func
1547
+ end
1548
+ })
1549
+ pattern(%w( $INTEGER ), lambda {
1550
+ LogicalOperation.new(@val[0])
1551
+ })
1552
+ pattern(%w( $STRING ), lambda {
1553
+ LogicalOperation.new(@val[0])
1554
+ })
1555
+ end
1556
+
1557
+ def rule_operation
1558
+ pattern(%w( !operand !operatorAndOperand ), lambda {
1559
+ operation = LogicalOperation.new(@val[0])
1560
+ unless @val[1].nil?
1561
+ operation.operator = @val[1][0]
1562
+ operation.operand2 = @val[1][1]
1563
+ end
1564
+ operation
1565
+ })
1566
+ arg(0, 'operand', <<'EOT'
1567
+ An operand can consist of a date, a text string or a numerical value. It can
1568
+ also be the name of a declared flag. Finally, an operand can be a negated
1569
+ operand by prefixing a ~ charater or it can be another logical expression
1570
+ enclosed in braces.
1571
+ EOT
1572
+ )
1573
+ end
1574
+
1575
+ def rule_operatorAndOperand
1576
+ optional
1577
+ pattern(%w( !operator !operand), lambda{
1578
+ [ @val[0], @val[1] ]
1579
+ })
1580
+ arg(1, 'operand', <<'EOT'
1581
+ An operand can consist of a date, a text string or a numerical value. It can also be the name of a declared flag. Finally, an operand can be a negated operand by prefixing a ~ charater or it can be another operation enclosed in braces.
1582
+ EOT
1583
+ )
1584
+ end
1585
+
1586
+ def rule_operator
1587
+ singlePattern('_|')
1588
+ descr('The \'or\' operator')
1589
+
1590
+ singlePattern('_&')
1591
+ descr('The \'and\' operator')
1592
+
1593
+ singlePattern('_>')
1594
+ descr('The \'greater than\' operator')
1595
+
1596
+ singlePattern('_<')
1597
+ descr('The \'smaller than\' operator')
1598
+
1599
+ singlePattern('_=')
1600
+ descr('The \'equal\' operator')
1601
+
1602
+ singlePattern('_>=')
1603
+ descr('The \'greater-or-equal\' operator')
1604
+
1605
+ singlePattern('_<=')
1606
+ descr('The \'smaller-or-equal\' operator')
1607
+ end
1608
+
1609
+ def rule_optionalPercent
1610
+ optional
1611
+ pattern(%w( !number _% ), lambda {
1612
+ @val[0] / 100.0
1613
+ })
1614
+ end
1615
+
1616
+ def rule_project
1617
+ pattern(%w( !projectProlog !projectDeclaration !properties ), lambda {
1618
+ @val[1]
1619
+ })
1620
+ end
1621
+
1622
+ def rule_projectBody
1623
+ optionsRule('projectBodyAttributes')
1624
+ end
1625
+
1626
+ def rule_projectBodyAttributes
1627
+ repeatable
1628
+ optional
1629
+
1630
+ pattern(%w( _currencyformat $STRING $STRING $STRING $STRING $INTEGER ),
1631
+ lambda {
1632
+ @project['currencyformat'] = RealFormat.new(@val.slice(1, 5))
1633
+ })
1634
+ doc('currencyformat',
1635
+ 'These values specify the default format used for all currency ' +
1636
+ 'values.')
1637
+ example('Currencyformat')
1638
+ arg(1, 'negativeprefix', 'Prefix for negative numbers')
1639
+ arg(2, 'negativesuffix', 'Suffix for negative numbers')
1640
+ arg(3, 'thousandsep', 'Separator used for every 3rd digit')
1641
+ arg(4, 'fractionsep', 'Separator used to separate the fraction digits')
1642
+ arg(5, 'fractiondigits', 'Number of fraction digits to show')
1643
+
1644
+ pattern(%w( _currency $STRING ), lambda {
1645
+ @project['currency'] = @val[1]
1646
+ })
1647
+ doc('currency', 'The default currency unit.')
1648
+ example('Account')
1649
+ arg(1, 'symbol', 'Currency symbol')
1650
+
1651
+ pattern(%w( _dailyworkinghours !number ), lambda {
1652
+ @project['dailyworkinghours'] = @val[1]
1653
+ })
1654
+ doc('dailyworkinghours', <<'EOT'
1655
+ Set the average number of working hours per day. This is used as
1656
+ the base to convert working hours into working days. This affects
1657
+ for example the length task attribute. The default value is 8 hours
1658
+ and should work for most Western countries. The value you specify
1659
+ should match the settings you specified for workinghours.
1660
+ EOT
1661
+ )
1662
+ example('Project')
1663
+ arg(1, 'hours', 'Average number of working hours per working day')
1664
+
1665
+ pattern(%w( _extend !extendProperty !extendBody ), lambda {
1666
+ updateParserTables
1667
+ })
1668
+ doc('extend', <<'EOT'
1669
+ Often it is desirable to collect more information in the project file than is
1670
+ necessary for task scheduling and resource allocation. To add such information
1671
+ to tasks, resources or accounts the user can extend these properties with
1672
+ user-defined attributes. The new attributes can be of various types such as
1673
+ text, date or reference to capture various types of data. Optionally the user
1674
+ can specify if the attribute value should be inherited from the enclosing
1675
+ property.
1676
+ EOT
1677
+ )
1678
+ example('CustomAttributes')
1679
+
1680
+ pattern(%w( !projectBodyInclude ))
1681
+
1682
+ pattern(%w( _now !date ), lambda {
1683
+ @project['now'] = @val[1]
1684
+ @scanner.addMacro(Macro.new('now', @val[1].to_s,
1685
+ @scanner.sourceFileInfo))
1686
+ })
1687
+ doc('now', <<'EOT'
1688
+ Specify the date that TaskJuggler uses for calculation as current
1689
+ date. If no value is specified, the current value of the system
1690
+ clock is used.
1691
+ EOT
1692
+ )
1693
+ arg(1, 'date', 'Alternative date to be used as current date for all ' +
1694
+ 'computations')
1695
+
1696
+ pattern(%w( _numberformat $STRING $STRING $STRING $STRING $INTEGER ),
1697
+ lambda {
1698
+ @project['numberformat'] = RealFormat.new(@val.slice(1, 5))
1699
+ })
1700
+ doc('numberformat',
1701
+ 'These values specify the default format used for all numerical ' +
1702
+ 'real values.')
1703
+ arg(1, 'negativeprefix', 'Prefix for negative numbers')
1704
+ arg(2, 'negativesuffix', 'Suffix for negative numbers')
1705
+ arg(3, 'thousandsep', 'Separator used for every 3rd digit')
1706
+ arg(4, 'fractionsep', 'Separator used to separate the fraction digits')
1707
+ arg(5, 'fractiondigits', 'Number of fraction digits to show')
1708
+
1709
+ pattern(%w( !scenario ))
1710
+ pattern(%w( _shorttimeformat $STRING ), lambda {
1711
+ @project['shorttimeformat'] = @val[1]
1712
+ })
1713
+ doc('shorttimeformat',
1714
+ 'Specifies time format for time short specifications. This is normal' +
1715
+ 'just the hour and minutes.')
1716
+ arg(1, 'format', 'strftime like format string')
1717
+
1718
+ pattern(%w( !timeformat ), lambda {
1719
+ @project['timeformat'] = @val[0]
1720
+ })
1721
+
1722
+ pattern(%w( !timezone ), lambda {
1723
+ @project['timezone'] = @val[1]
1724
+ })
1725
+
1726
+ pattern(%w( _timingresolution $INTEGER _min ), lambda {
1727
+ goodValues = [ 5, 10, 15, 20, 30, 60 ]
1728
+ unless goodValues.include?(@val[1])
1729
+ error('bad_timing_res',
1730
+ "Timing resolution must be one of #{goodValues.join(', ')} min.")
1731
+ end
1732
+ @project['scheduleGranularity'] = @val[1] * 60
1733
+ })
1734
+ doc('timingresolution', <<'EOT'
1735
+ Sets the minimum timing resolution. The smaller the value, the longer the
1736
+ scheduling process lasts and the more memory the application needs. The
1737
+ default and maximum value is 1 hour. The smallest value is 5 min.
1738
+ This value is a pretty fundamental setting of TaskJuggler. It has a severe
1739
+ impact on memory usage and scheduling performance. You should set this value
1740
+ to the minimum required resolution. Make sure that all values that you specify
1741
+ are aligned with the resolution.
1742
+
1743
+ The timing resolution should be set prior to any value that represents a time
1744
+ value like now or workinghours.
1745
+ EOT
1746
+ )
1747
+
1748
+ pattern(%w( _weekstartsmonday ), lambda {
1749
+ @project['weekstartsmonday'] = true
1750
+ })
1751
+ doc('weekstartsmonday',
1752
+ 'Specify that you want to base all week calculation on weeks ' +
1753
+ 'starting on Monday. This is common in many European countries.')
1754
+
1755
+ pattern(%w( _weekstartssunday ), lambda {
1756
+ @project['weekstartsmonday'] = false
1757
+ })
1758
+ doc('weekstartssunday',
1759
+ 'Specify that you want to base all week calculation on weeks ' +
1760
+ 'starting on Sunday. This is common in the United States of America.')
1761
+
1762
+ pattern(%w( !workinghoursProject ))
1763
+ pattern(%w( _yearlyworkingdays !number ), lambda {
1764
+ @project['yearlyworkingdays'] = @val[1]
1765
+ })
1766
+ doc('yearlyworkingdays', <<'EOT'
1767
+ Specifies the number of average working days per year. This should correlate
1768
+ to the specified workinghours and vacation. It affects the conversion of
1769
+ working hours, working days, working weeks, working months and working years
1770
+ into each other.
1771
+
1772
+ When public holidays and vacations are disregarded, this value should be equal
1773
+ to the number of working days per week times 52.1428 (the average number of
1774
+ weeks per year). E. g. for a culture with 5 working days it is 260.714 (the
1775
+ default), for 6 working days it is 312.8568 and for 7 working days it is
1776
+ 365.
1777
+ EOT
1778
+ )
1779
+ arg(1, 'days', 'Number of average working days for a year')
1780
+ end
1781
+
1782
+ def rule_projectDeclaration
1783
+ pattern(%w( !projectHeader !projectBody ), lambda {
1784
+ @val[0]
1785
+ })
1786
+ doc('project', <<'EOT'
1787
+ The project property is mandatory and should be the first property
1788
+ in a project file. It is used to capture basic attributes such as
1789
+ the project id, name and the expected time frame.
1790
+ EOT
1791
+ )
1792
+ end
1793
+
1794
+ def rule_projectHeader
1795
+ pattern(%w( _project $ID $STRING $STRING !interval ), lambda {
1796
+ @project = Project.new(@val[1], @val[2], @val[3],
1797
+ @messageHandler)
1798
+ @project['start'] = @val[4].start
1799
+ @project['end'] = @val[4].end
1800
+ setGlobalMacros
1801
+ @property = nil
1802
+ @project
1803
+ })
1804
+ arg(1, 'id', 'The ID of the project')
1805
+ arg(2, 'name', 'The name of the project')
1806
+ arg(3, 'version', 'The version of the project plan')
1807
+ end
1808
+
1809
+ def rule_projectIDs
1810
+ pattern(%w( $ID !moreProjectIDs ), lambda {
1811
+ [ @val[0] ] + @val[1]
1812
+ })
1813
+ end
1814
+
1815
+ def rule_projection
1816
+ optionsRule('projectionAttributes')
1817
+ end
1818
+
1819
+ def rule_projectionAttributes
1820
+ optional
1821
+ repeatable
1822
+ pattern(%w( _sloppy ), lambda {
1823
+ @property.set('strict', false)
1824
+ })
1825
+ doc('sloppy.projection', <<'EOT'
1826
+ In sloppy mode tasks with no bookings will be filled from the original start.
1827
+ EOT
1828
+ )
1829
+
1830
+ pattern(%w( _strict ), lambda {
1831
+ @property.set('strict', true)
1832
+ })
1833
+ doc('strict.projection', <<'EOT'
1834
+ In strict mode all tasks will be filled starting with the current date. No
1835
+ bookings will be added prior to the current date.
1836
+ EOT
1837
+ )
1838
+ end
1839
+
1840
+ def rule_projectProlog
1841
+ optional
1842
+ repeatable
1843
+ pattern(%w( !prologInclude ))
1844
+ pattern(%w( !macro ))
1845
+ end
1846
+
1847
+ def rule_projectProperties
1848
+ # This rule is not defining actual syntax. It's only used for the
1849
+ # documentation.
1850
+ pattern(%w( !projectPropertiesBody ))
1851
+ doc('properties', <<'EOT'
1852
+ The project properties. Every project must consists of at least one task.
1853
+ EOT
1854
+ )
1855
+ end
1856
+
1857
+ def rule_projectPropertiesBody
1858
+ # This rule is not defining actual syntax. It's only used for the
1859
+ # documentation.
1860
+ optionsRule('properties')
1861
+ end
1862
+
1863
+ def rule_projectBodyInclude
1864
+ pattern(%w( _include !includeFile !projectBodyAttributes . ))
1865
+ lastSyntaxToken(1)
1866
+ doc('include.project', <<'EOT'
1867
+ Includes the specified file name as if its contents would be written
1868
+ instead of the include property. The only exception is the include
1869
+ statement itself. When the included files contains other include
1870
+ statements or report definitions, the filenames are relative to file
1871
+ where they are defined in.
1872
+
1873
+ The included files may only contain content that may be present in a project
1874
+ header section.
1875
+ EOT
1876
+ )
1877
+ end
1878
+
1879
+ def rule_prologInclude
1880
+ pattern(%w( _include !includeFile !projectProlog . ), lambda {
1881
+ })
1882
+ lastSyntaxToken(1)
1883
+ doc('include.macro', <<'EOT'
1884
+ Includes the specified file name as if its contents would be written
1885
+ instead of the include property. The only exception is the include
1886
+ statement itself. When the included files contains other include
1887
+ statements or report definitions, the filenames are relative to file
1888
+ where they are defined in.
1889
+
1890
+ The included file may only contain macro definitions.
1891
+ EOT
1892
+ )
1893
+ end
1894
+
1895
+ def rule_properties
1896
+ pattern(%w( !propertiesBody . ))
1897
+ end
1898
+
1899
+ def rule_propertiesBody
1900
+ repeatable
1901
+
1902
+ pattern(%w( !account ))
1903
+
1904
+ pattern(%w( _copyright $STRING ), lambda {
1905
+ @project['copyright'] = @val[1]
1906
+ })
1907
+ doc('copyright', <<'EOT'
1908
+ Set a copyright notice for the project file and its content. This copyright notice will be added to all reports that can support it.
1909
+ EOT
1910
+ )
1911
+ example('Caption', '2')
1912
+
1913
+ pattern(%w( !balance ), lambda {
1914
+ @project['costAccount'] = @val[0][0]
1915
+ @project['revenueAccount'] = @val[0][1]
1916
+ })
1917
+
1918
+ pattern(%w( _flags !declareFlagList ), lambda {
1919
+ unless @project['flags'].include?(@val[1])
1920
+ @project['flags'] += @val[1]
1921
+ end
1922
+ })
1923
+ doc('flags', <<'EOT'
1924
+ Declare one or more flag for later use. Flags can be used to mark tasks, resources or other properties to filter them in reports.
1925
+ EOT
1926
+ )
1927
+
1928
+ pattern(%w( !propertiesInclude ))
1929
+
1930
+ pattern(%w( !limits ), lambda {
1931
+ @project['limits'] = @val[0]
1932
+ })
1933
+ doc('limits', <<'EOT'
1934
+ Set per-interval allocation limits for the following resource definitions.
1935
+ The limits can be overwritten in each resource definition and the global
1936
+ limits can be changed later.
1937
+ EOT
1938
+ )
1939
+
1940
+ pattern(%w( !macro ))
1941
+
1942
+ pattern(%w( _projectid $ID ), lambda {
1943
+ @project['projectids'] << @val[1]
1944
+ @project['projectids'].uniq!
1945
+ @project['projectid'] = @val[1]
1946
+ })
1947
+ doc('projectid', <<'EOT'
1948
+ This declares a new project id and activates it. All subsequent
1949
+ task definitions will inherit this ID. The tasks of a project can have
1950
+ different IDs. This is particularly helpful if the project is merged from
1951
+ several sub projects that each have their own ID.
1952
+ EOT
1953
+ )
1954
+
1955
+ pattern(%w( _projectids !projectIDs ), lambda {
1956
+ @project['projectids'] += @val[1]
1957
+ @project['projectids'].uniq!
1958
+ })
1959
+ doc('projectids', <<'EOT'
1960
+ Declares a list of project IDs. When an include file that was generated from another project brings different project IDs, these need to be declared first.
1961
+ EOT
1962
+ )
1963
+
1964
+ pattern(%w( _rate !number ), lambda {
1965
+ @project['rate'] = @val[1].to_f
1966
+ })
1967
+ doc('rate', <<'EOT'
1968
+ Set the default rate for all subsequently defined resources. The rate describes the daily cost of a resource.
1969
+ EOT
1970
+ )
1971
+
1972
+ pattern(%w( !reportDefinitions ))
1973
+ pattern(%w( !resource ))
1974
+ pattern(%w( !shift ))
1975
+
1976
+ pattern(%w( _supplement !supplement ))
1977
+ doc('supplement', <<'EOT'
1978
+ The supplement keyword provides a mechanism to add more attributes to already
1979
+ defined accounts, tasks or resources. The additional attributes must obey the
1980
+ same rules as in regular task or resource definitions and must be enclosed by
1981
+ curly braces.
1982
+
1983
+ This construct is primarily meant for situations where the information about a
1984
+ task or resource is split over several files. E. g. the vacation dates for the
1985
+ resources may be in a separate file that was generated by some other tool.
1986
+ EOT
1987
+ )
1988
+
1989
+ pattern(%w( !task ))
1990
+ pattern(%w( _vacation !vacationName !intervals ), lambda {
1991
+ @project['vacations'] = @project['vacations'] + @val[2]
1992
+ })
1993
+ doc('vacation', <<'EOT'
1994
+ Specify a global vacation period for all subsequently defined resources. A
1995
+ vacation can also be used to block out the time before a resource joint or
1996
+ after it left. For employees changing their work schedule from full-time to
1997
+ part-time, or vice versa, please refer to the 'Shift' property.
1998
+ EOT
1999
+ )
2000
+ arg(1, 'name', 'Name or purpose of the vacation')
2001
+ end
2002
+
2003
+ def rule_propertiesInclude
2004
+ pattern(%w( _include !includeProperties !properties ), lambda {
2005
+ popFileStack
2006
+ })
2007
+ lastSyntaxToken(1)
2008
+ doc('include.properties', <<'EOT'
2009
+ Includes the specified file name as if its contents would be written
2010
+ instead of the include property. The only exception is the include
2011
+ statement itself. When the included files contains other include
2012
+ statements or report definitions, the filenames are relative to file
2013
+ where they are defined in. include commands can be used in the project
2014
+ header, at global scope or between property declarations of tasks,
2015
+ resources, and accounts.
2016
+
2017
+ For technical reasons you have to supply the optional pair of curly
2018
+ brackets if the include is followed immediately by a macro call that
2019
+ is defined within the included file.
2020
+ EOT
2021
+ )
2022
+ end
2023
+
2024
+ def rule_purge
2025
+ pattern(%w( _purge $ID ), lambda {
2026
+ if (attributeDefinition = @property.attributeDefinition(@val[1])).nil?
2027
+ error('purge_unknown_id',
2028
+ "#{@val[1]} is not a known attribute for this property")
2029
+ end
2030
+ if attributeDefinition.scenarioSpecific
2031
+ attr = @property[@val[1], 0]
2032
+ else
2033
+ attr = @propert.get(@val[1])
2034
+ end
2035
+ unless attr.is_a?(Array)
2036
+ error('purge_no_list',
2037
+ "#{@val[1]} is not a list attribute. Only those can be purged.")
2038
+ end
2039
+ if attributeDefinition.scenarioSpecific
2040
+ @property[@val[1], @scenarioIdx] = attributeDefinition.default.dup
2041
+ else
2042
+ @property.set(@val[1], attributeDefinition.default.dup)
2043
+ end
2044
+ })
2045
+ doc('purge', <<'EOT'
2046
+ List attributes, like regular attributes, can inherit their values from the
2047
+ enclosing property. By defining more values for such a list attribute, the new
2048
+ values will be appended to the existing ones. The purge statement clears such
2049
+ a list atribute. A subsequent definition for the attribute within the property
2050
+ will then add their values to an empty list.
2051
+ EOT
2052
+ )
2053
+ arg(1, 'attribute', 'Any name of a list attribute')
2054
+ end
2055
+
2056
+ def rule_referenceAttributes
2057
+ optional
2058
+ repeatable
2059
+ pattern(%w( _label $STRING ), lambda {
2060
+ @val[1]
2061
+ })
2062
+ end
2063
+
2064
+ def rule_referenceBody
2065
+ optionsRule('referenceAttributes')
2066
+ end
2067
+
2068
+ def rule_reportAttributes
2069
+ optional
2070
+ repeatable
2071
+
2072
+ pattern(%w( !balance ), lambda {
2073
+ @reportElement.costAccount = @val[0][0]
2074
+ @reportElement.revenueAccount = @val[0][1]
2075
+ })
2076
+
2077
+ pattern(%w( _caption $STRING ), lambda {
2078
+ @reportElement.caption = newRichText(@val[1])
2079
+ })
2080
+ doc('caption', <<'EOT'
2081
+ The caption will be embedded in the footer of the table or data segment. The
2082
+ text will be interpreted as [[Rich_Text_Attributes Rich Text]].
2083
+ EOT
2084
+ )
2085
+ example('Caption', '1')
2086
+
2087
+ pattern(%w( _columns !columnDef !moreColumnDef ), lambda {
2088
+ columns = [ @val[1] ]
2089
+ columns += @val[2] if @val[2]
2090
+ @reportElement.columns = columns
2091
+ })
2092
+ doc('columns', <<'EOT'
2093
+ Specifies which columns shall be included in a report.
2094
+
2095
+ All columns support macro expansion. Contrary to the normal macro expansion,
2096
+ these macros are expanded during the report generation. So the value of the
2097
+ macro is being changed after each table cell or table line. Consequently only
2098
+ build in macros can be used. To protect the macro calls against expansion
2099
+ during the initial file processing, the report macros must be prefixed with an
2100
+ additional ''''$''''.
2101
+ EOT
2102
+ )
2103
+
2104
+ pattern(%w( _epilog $STRING ), lambda {
2105
+ @reportElement.epilog = newRichText(@val[1])
2106
+ })
2107
+ doc('epilog', <<'EOT'
2108
+ Define a text section that is printed right after the actual report data. The
2109
+ text will be interpreted as [[Rich_Text_Attributes Rich Text]].
2110
+ EOT
2111
+ )
2112
+
2113
+ pattern(%w( !reportEnd ))
2114
+
2115
+ pattern(%w( _headline $STRING ), lambda {
2116
+ @reportElement.headline = @val[1]
2117
+ })
2118
+ doc('headline', <<'EOT'
2119
+ Specifies the headline for a report.
2120
+ EOT
2121
+ )
2122
+
2123
+ pattern(%w( !hideresource ))
2124
+
2125
+ pattern(%w( !hidetask ))
2126
+
2127
+ pattern(%w( _loadunit !loadunit ), lambda {
2128
+ @reportElement.loadUnit = :"#{@val[1]}"
2129
+ })
2130
+ doc('loadunit', <<'EOT'
2131
+ Determines what unit should be used to display all load values in this report.
2132
+ EOT
2133
+ )
2134
+
2135
+ pattern(%w( _prolog $STRING ), lambda {
2136
+ @reportElement.prolog = newRichText(@val[1])
2137
+ })
2138
+ doc('prolog', <<'EOT'
2139
+ Define a text section that is printed right before the actual report data. The
2140
+ text will be interpreted as [[Rich_Text_Attributes Rich Text]].
2141
+ EOT
2142
+ )
2143
+
2144
+ pattern(%w( _rawhead $STRING ), lambda {
2145
+ @reportElement.rawHead = @val[1]
2146
+ })
2147
+ doc('rawhead', <<'EOT'
2148
+ Specifies a section of raw HTML code that will be inserted at the top of the
2149
+ report.
2150
+ EOT
2151
+ )
2152
+
2153
+ pattern(%w( _rawtail $STRING ), lambda {
2154
+ @reportElement.rawTail = @val[1]
2155
+ })
2156
+ doc('rawtail', <<'EOT'
2157
+ Specifies a section of raw HTML code that will be inserted at the bottom of
2158
+ the report.
2159
+ EOT
2160
+ )
2161
+
2162
+ pattern(%w( !reportPeriod ))
2163
+
2164
+ pattern(%w( _rolluptask !logicalExpression ), lambda {
2165
+ @reportElement.rollupTask = @val[1]
2166
+ })
2167
+ doc('rolluptask', <<'EOT'
2168
+ Do not show sub-tasks of tasks that match the specified logical expression.
2169
+ EOT
2170
+ )
2171
+
2172
+ pattern(%w( _scenarios !scenarioIdList ), lambda {
2173
+ # Don't include disabled scenarios in the report
2174
+ @val[1].delete_if { |sc| !@project.scenario(sc).get('enabled') }
2175
+ @reportElement.scenarios = @val[1]
2176
+ })
2177
+ doc('scenrios', <<'EOT'
2178
+ List of scenarios that should be included in the report.
2179
+ EOT
2180
+ )
2181
+
2182
+ pattern(%w( _sortresources !sortCriteria ), lambda {
2183
+ @reportElement.sortResources = @val[1]
2184
+ })
2185
+ doc('sortresources', <<'EOT'
2186
+ Determines how the resources are sorted in the report. Multiple criteria can be
2187
+ specified as a comma separated list. If one criteria is not sufficient to sort
2188
+ a group of resources, the next criteria will be used to sort the resources in
2189
+ this group.
2190
+ EOT
2191
+ )
2192
+
2193
+ pattern(%w( _sorttasks !sortCriteria ), lambda {
2194
+ @reportElement.sortTasks = @val[1]
2195
+ })
2196
+ doc('sorttasks', <<'EOT'
2197
+ Determines how the tasks are sorted in the report. Multiple criteria can be
2198
+ specified as comma separated list. If one criteria is not sufficient to sort a
2199
+ group of tasks, the next criteria will be used to sort the tasks within
2200
+ this group.
2201
+ EOT
2202
+ )
2203
+
2204
+ pattern(%w( !reportStart ))
2205
+
2206
+ pattern(%w( _taskroot !taskId), lambda {
2207
+ @reportElement.taskRoot = @val[1]
2208
+ })
2209
+ doc('taskroot', <<'EOT'
2210
+ Only tasks below the specified root-level tasks are exported. The exported
2211
+ tasks will have the id of the root-level task stripped from their ID, so that
2212
+ the sub-tasks of the root-level task become top-level tasks in the exported
2213
+ file.
2214
+ EOT
2215
+ )
2216
+
2217
+ pattern(%w( !timeformat ), lambda {
2218
+ @reportElement.timeFormat = @val[0]
2219
+ })
2220
+ end
2221
+
2222
+ def rule_reportableAttributes
2223
+ singlePattern('_chart')
2224
+ descr(<<'EOT'
2225
+ A Gantt chart. This column type requires all lines to have the same fixed
2226
+ height. This does not work well with rich text columns in some browsers. Some
2227
+ show a scrollbar for the compressed table cells, others don't. It is
2228
+ recommended, that you don't use rich text columns in conjuction with the chart
2229
+ column.
2230
+ EOT
2231
+ )
2232
+
2233
+ singlePattern('_complete')
2234
+ descr('The completion degree of a task')
2235
+
2236
+ pattern([ '_completed' ], lambda {
2237
+ 'complete'
2238
+ })
2239
+ descr('Deprecated alias for complete')
2240
+
2241
+ singlePattern('_criticalness')
2242
+ descr('A measure for how much effort the resource is allocated for, or' +
2243
+ 'how strained the allocated resources of a task are')
2244
+
2245
+ singlePattern('_cost')
2246
+ descr(<<'EOT'
2247
+ The cost of the task or resource. The use of this column requires that a cost
2248
+ account has been set for the report using the [[balance]] attribute.
2249
+ EOT
2250
+ )
2251
+
2252
+ singlePattern('_daily')
2253
+ descr('A group of columns with one column for each day')
2254
+
2255
+ singlePattern('_duration')
2256
+ descr('The duration of a task')
2257
+
2258
+ singlePattern('_duties')
2259
+ descr('List of tasks that the resource is allocated to')
2260
+
2261
+ singlePattern('_efficiency')
2262
+ descr('Measure for how efficient a resource can perform tasks')
2263
+
2264
+ singlePattern('_effort')
2265
+ descr('The total allocated effort')
2266
+
2267
+ singlePattern('_email')
2268
+ descr('The email address of a resource')
2269
+
2270
+ singlePattern('_end')
2271
+ descr('The end date of a task')
2272
+
2273
+ singlePattern('_flags')
2274
+ descr('List of attached flags')
2275
+
2276
+ singlePattern('_fte')
2277
+ descr('The Full-Time-Equivalent of a resource or group')
2278
+
2279
+ singlePattern('_headcount')
2280
+ descr('The headcount number of the resource or group')
2281
+
2282
+ pattern([ '_hierarchindex' ], lambda {
2283
+ 'wbs'
2284
+ })
2285
+ descr('Deprecated alias for wbs')
2286
+
2287
+ singlePattern('_hourly')
2288
+ descr('A group of columns with one column for each hour')
2289
+
2290
+ singlePattern('_id')
2291
+ descr('The id of the item')
2292
+
2293
+ singlePattern('_index')
2294
+ descr('The index of the item based on the nesting hierachy')
2295
+
2296
+ singlePattern('_line')
2297
+ descr('The line number in the report')
2298
+
2299
+ singlePattern('_maxend')
2300
+ descr('The latest allowed end of a task')
2301
+
2302
+ singlePattern('_maxstart')
2303
+ descr('The lastest allowed start of a task')
2304
+
2305
+ singlePattern('_minend')
2306
+ descr('The earliest allowed end of a task')
2307
+
2308
+ singlePattern('_minstart')
2309
+ descr('The earliest allowed start of a task')
2310
+
2311
+ singlePattern('_monthly')
2312
+ descr('A group of columns with one column for each month')
2313
+
2314
+ singlePattern('_no')
2315
+ descr('The object line number in the report')
2316
+
2317
+ singlePattern('_name')
2318
+ descr('The name or description of the item')
2319
+
2320
+ singlePattern('_note')
2321
+ descr('The note attached to a task')
2322
+
2323
+ singlePattern('_pathcriticalness')
2324
+ descr('The criticalness of the task with respect to all the paths that ' +
2325
+ 'it is a part of.')
2326
+
2327
+ singlePattern('_priority')
2328
+ descr('The priority of a task')
2329
+
2330
+ singlePattern('_quarterly')
2331
+ descr('A group of columns with one column for each quarter')
2332
+
2333
+ singlePattern('_rate')
2334
+ descr('The daily cost of a resource.')
2335
+
2336
+ singlePattern('_responsible')
2337
+ descr('The responsible people for this task')
2338
+
2339
+ singlePattern('_revenue')
2340
+ descr(<<'EOT'
2341
+ The revenue of the task or resource. The use of this column requires that a
2342
+ revenue account has been set for the report using the [[balance]] attribute.
2343
+ EOT
2344
+ )
2345
+
2346
+ singlePattern('_seqno')
2347
+ descr('The index of the item based on the declaration order')
2348
+
2349
+ singlePattern('_start')
2350
+ descr('The start date of the task')
2351
+
2352
+ singlePattern('_wbs')
2353
+ descr('The hierarchical or work breakdown structure index')
2354
+
2355
+ singlePattern('_weekly')
2356
+ descr('A group of columns with one column for each week')
2357
+
2358
+ singlePattern('_yearly')
2359
+ descr('A group of columns with one column for each year')
2360
+
2361
+ end
2362
+
2363
+ def rule_reportDefinitions
2364
+ pattern(%w( !csvResourceReport ))
2365
+ pattern(%w( !csvTaskReport ))
2366
+ pattern(%w( !export ))
2367
+ pattern(%w( !htmlResourceReport ))
2368
+ pattern(%w( !htmlTaskReport ))
2369
+ pattern(%w( !resourceReport ))
2370
+ pattern(%w( !taskReport ))
2371
+ end
2372
+
2373
+ def rule_reportDefinitionsBody
2374
+ # This rule is not defining actual syntax. It's only used for the
2375
+ # documentation.
2376
+ optionsRule('reportDefinitions')
2377
+ end
2378
+
2379
+ def rule_reportBody
2380
+ optionsRule('reportAttributes')
2381
+ end
2382
+
2383
+ def rule_reportEnd
2384
+ pattern(%w( _end !date ), lambda {
2385
+ if @val[1] < @reportElement.start
2386
+ error('report_end',
2387
+ "End date must be before start date #{@reportElement.start}")
2388
+ end
2389
+ @reportElement.end = @val[1]
2390
+ })
2391
+ doc('end.report', <<'EOT'
2392
+ Specifies the end date of the report. In task reports only tasks that start
2393
+ before this end date are listed.
2394
+ EOT
2395
+ )
2396
+ example('Export', '2')
2397
+ end
2398
+
2399
+ def rule_reportPeriod
2400
+ pattern(%w( _period !interval ), lambda {
2401
+ @reportElement.start = @val[1].start
2402
+ @reportElement.end = @val[1].end
2403
+ })
2404
+ doc('period.report', <<'EOT'
2405
+ This property is a shortcut for setting the start and end property at the
2406
+ same time.
2407
+ EOT
2408
+ )
2409
+ end
2410
+
2411
+ def rule_reportStart
2412
+ pattern(%w( _start !date ), lambda {
2413
+ if @val[1] > @reportElement.end
2414
+ error('report_start',
2415
+ "Start date must be before end date #{@reportElement.end}")
2416
+ end
2417
+ @reportElement.start = @val[1]
2418
+ })
2419
+ doc('start.report', <<'EOT'
2420
+ Specifies the start date of the report. In task reports only tasks that end
2421
+ after this end date are listed.
2422
+ EOT
2423
+ )
2424
+ end
2425
+ def rule_reports
2426
+ # This rule is not defining actual syntax. It's only used for the
2427
+ # documentation.
2428
+ pattern(%w( !reportDefinitionsBody ))
2429
+ doc('reports', <<'EOT'
2430
+ The report definitions. In order to see the results of your scheduled project
2431
+ you need to define at least one report.
2432
+ EOT
2433
+ )
2434
+ end
2435
+
2436
+
2437
+ def rule_resource
2438
+ pattern(%w( !resourceHeader !resourceBody ), lambda {
2439
+ @property = @property.parent
2440
+ })
2441
+ doc('resource', <<'EOT'
2442
+ Tasks that have an effort specification need to have resources assigned to do
2443
+ the work. Use this property to define resources and groups of resources.
2444
+ EOT
2445
+ )
2446
+ end
2447
+
2448
+ def rule_resourceAttributes
2449
+ repeatable
2450
+ optional
2451
+ pattern(%w( !purge ))
2452
+ pattern(%w( !resource ))
2453
+ pattern(%w( !resourceScenarioAttributes ))
2454
+ pattern(%w( !scenarioId !resourceScenarioAttributes ), lambda {
2455
+ @scenarioIdx = 0
2456
+ })
2457
+
2458
+ pattern(%w( _supplement !resourceId !resourceBody ), lambda {
2459
+ @property = @property.parent
2460
+ })
2461
+ doc('supplement.resource', <<'EOT'
2462
+ The supplement keyword provides a mechanism to add more attributes to already
2463
+ defined resources. The additional attributes must obey the same rules as in
2464
+ regular resource definitions and must be enclosed by curly braces.
2465
+
2466
+ This construct is primarily meant for situations where the information about a
2467
+ resource is split over several files. E. g. the vacation dates for the
2468
+ resources may be in a separate file that was generated by some other tool.
2469
+ EOT
2470
+ )
2471
+
2472
+ # Other attributes will be added automatically.
2473
+ end
2474
+
2475
+ def rule_resourceBody
2476
+ optionsRule('resourceAttributes')
2477
+ end
2478
+
2479
+ def rule_resourceBooking
2480
+ pattern(%w( !resourceBookingHeader !bookingBody ), lambda {
2481
+ @val[0].task.addBooking(@scenarioIdx, @val[0])
2482
+ })
2483
+ end
2484
+
2485
+ def rule_resourceBookingHeader
2486
+ pattern(%w( !taskId !valIntervals ), lambda {
2487
+ checkBooking(@val[0], @property)
2488
+ @booking = Booking.new(@property, @val[0], @val[1])
2489
+ @booking.sourceFileInfo = @scanner.sourceFileInfo
2490
+ @booking
2491
+ })
2492
+ arg(0, 'id', 'Absolute ID of a defined task')
2493
+ end
2494
+
2495
+ def rule_resourceId
2496
+ pattern(%w( $ID ), lambda {
2497
+ id = @val[0]
2498
+ id = @resourceprefix + '.' + id unless @resourceprefix.empty?
2499
+ # In case we have a nested supplement, we need to prepend the parent ID.
2500
+ id = @property.fullId + '.' + id if @property && @property.is_a?(Resource)
2501
+ if (resource = @project.resource(id)).nil?
2502
+ error('resource_id_expected', "#{id} is not a defined resource.")
2503
+ end
2504
+ resource
2505
+ })
2506
+ arg(0, 'resource', 'The ID of a defined resource')
2507
+ end
2508
+
2509
+ def rule_resourceHeader
2510
+ pattern(%w( _resource $ID $STRING ), lambda {
2511
+ if @property.nil? && !@resourceprefix.empty?
2512
+ @property = @project.task(@resourceprefix)
2513
+ end
2514
+ if @project.resource(@val[1])
2515
+ error('resource_exists', "Resource #{@val[1]} has already been defined.")
2516
+ end
2517
+ @property = Resource.new(@project, @val[1], @val[2], @property)
2518
+ @property.sourceFileInfo = @scanner.sourceFileInfo
2519
+ @property.inheritAttributes
2520
+ @scenarioIdx = 0
2521
+ })
2522
+ arg(1, 'id', <<'EOT'
2523
+ The ID of the resource. Resources have a global name space. The ID must be
2524
+ unique within the whole project.
2525
+ EOT
2526
+ )
2527
+ arg(2, 'name', 'The name of the resource')
2528
+ end
2529
+
2530
+ def rule_resourceLeafList
2531
+ pattern(%w( !leafResourceId !moreLeafResources ), lambda {
2532
+ [ @val[0] ] + @val[1]
2533
+ })
2534
+ end
2535
+
2536
+ def rule_resourceList
2537
+ pattern(%w( !resourceId !moreResources ), lambda {
2538
+ [ @val[0] ] + @val[1]
2539
+ })
2540
+ end
2541
+
2542
+ def rule_resourceReport
2543
+ pattern(%w( !resourceReportHeader !reportBody ))
2544
+ doc('resourcereport', <<'EOT'
2545
+ The report lists all resources and their respective values in the GUI. The
2546
+ task that are the resources are allocated to can be listed as well. In the commandline version this report is ignored.
2547
+ EOT
2548
+ )
2549
+ end
2550
+
2551
+ def rule_resourceReportHeader
2552
+ pattern(%w( _resourcereport $STRING ), lambda {
2553
+ @report = Report.new(@project, @val[1], :gui, sourceFileInfo)
2554
+ @reportElement = ResourceListRE.new(@report)
2555
+ })
2556
+ arg(1, 'file name', <<'EOT'
2557
+ The name of the report.
2558
+ EOT
2559
+ )
2560
+ end
2561
+
2562
+ def rule_resourceScenarioAttributes
2563
+ pattern(%w( _efficiency !number ), lambda {
2564
+ @property['efficiency', @scenarioIdx] = @val[1]
2565
+ })
2566
+ doc('efficiency', <<'EOT'
2567
+ The efficiency of a resource can be used for two purposes. First you can use
2568
+ it as a crude way to model a team. A team of 5 people should have an
2569
+ efficiency of 5.0. Keep in mind that you cannot track the members of the team
2570
+ individually if you use this feature. They always act as a group.
2571
+
2572
+ The other use is to model performance variations between your resources. Again, this is a fairly crude mechanism and should be used with care. A resource that isn't every good at some task might be pretty good at another. This can't be taken into account as the resource efficiency can only set globally for all tasks.
2573
+
2574
+ All resources that do not contribute effort to the task, should have an
2575
+ efficiency of 0.0. A typical example would be a conference room. It's necessary for a meeting, but it does not contribute any work.
2576
+ EOT
2577
+ )
2578
+ example('Efficiency')
2579
+ pattern(%w( !flags ))
2580
+ doc('flags.resource', <<'EOT'
2581
+ Attach a set of flags. The flags can be used in logical expressions to filter
2582
+ properties from the reports.
2583
+ EOT
2584
+ )
2585
+
2586
+ pattern(%w( _booking !resourceBooking ))
2587
+ doc('booking', <<'EOT'
2588
+ The booking attribute can be used to report completed work. This can be part
2589
+ of the necessary effort or the whole effort. When the scenario is scheduled in
2590
+ projection mode, TaskJuggler assumes that only the work reported with bookings
2591
+ has been done up to now. It then schedules a plan for the still missing
2592
+ effort. Task with bookings must be scheduled in ''''asap'''' mode.
2593
+
2594
+ This attribute is also used within export reports to describe the details of a
2595
+ scheduled project.
2596
+
2597
+ The sloppy attribute can be used when you want to skip non-working time or
2598
+ other allocations automatically. If it's not given, all bookings must only
2599
+ cover working time for the resource.
2600
+ EOT
2601
+ )
2602
+ also(%w( scheduling ))
2603
+ example('Booking')
2604
+
2605
+ pattern(%w( !limits ), lambda {
2606
+ @property['limits', @scenarioIdx] = @val[0]
2607
+ })
2608
+ doc('limits.resource', <<'EOT'
2609
+ Set per-interval usage limits for the resource.
2610
+ EOT
2611
+ )
2612
+
2613
+ pattern(%w( _rate !number ), lambda {
2614
+ @property['rate', @scenarioIdx] = @val[1]
2615
+ })
2616
+ doc('rate.resource', <<'EOT'
2617
+ The rate specifies the daily cost of the resource.
2618
+ EOT
2619
+ )
2620
+
2621
+ pattern(%w( _shift !shiftAssignments ))
2622
+ doc('shift.resource', <<'EOT'
2623
+ This keyword has been deprecated. Please use [shifts.resource shifts
2624
+ (resource)] instead.
2625
+ EOT
2626
+ )
2627
+
2628
+ pattern(%w( _shifts !shiftAssignments ))
2629
+ doc('shifts.resource', <<'EOT'
2630
+ Limits the working time of a resource to a defined shift during the specified
2631
+ interval. Multiple shifts can be defined, but shift intervals may not overlap.
2632
+ Outside of the defined shift intervals the resource uses its normal working
2633
+ hours and vacations.
2634
+ EOT
2635
+ )
2636
+
2637
+ pattern(%w( _vacation !vacationName !intervals ), lambda {
2638
+ @property['vacations', @scenarioIdx] =
2639
+ @property['vacations', @scenarioIdx ] + @val[2]
2640
+ })
2641
+ doc('vacation.resource', <<'EOT'
2642
+ Specify a vacation period for the resource. It can also be used to block out
2643
+ the time before a resource joint or after it left. For employees changing
2644
+ their work schedule from full-time to part-time, or vice versa, please refer
2645
+ to the 'Shift' property.
2646
+ EOT
2647
+ )
2648
+
2649
+ pattern(%w( !workinghoursResource ))
2650
+ # Other attributes will be added automatically.
2651
+ end
2652
+
2653
+ def rule_scenario
2654
+ pattern(%w( !scenarioHeader !scenarioBody ), lambda {
2655
+ @property = @property.parent
2656
+ })
2657
+ doc('scenario', <<'EOT'
2658
+ Specifies the different project scenarios. A scenario that is nested into
2659
+ another one inherits all inheritable values from the enclosing scenario. There
2660
+ can only be one top-level scenario. It is usually called plan scenario. By
2661
+ default this scenario is pre-defined but can be overwritten with any other
2662
+ scenario. In this documenation each attribute is listed as scenario specific
2663
+ or not. A scenario specific attribute can be overwritten in a child scenario
2664
+ thereby creating a new, slightly different variant of the parent scenario.
2665
+ This can be helpful to do plan/actual comparisons if what-if-anlysises.
2666
+
2667
+ By using bookings and enabling the projection mode you can capture the
2668
+ progress of your project and constantly get updated project plans for the
2669
+ future work.
2670
+ EOT
2671
+ )
2672
+ end
2673
+
2674
+ def rule_scenarioAttributes
2675
+ optional
2676
+ repeatable
2677
+
2678
+ pattern(%w( _disabled ), lambda {
2679
+ @property.set('enabled', false)
2680
+ })
2681
+ doc('disabled', <<'EOT'
2682
+ Disable the scenario for scheduling. The default for the top-level
2683
+ scenario is to be enabled.
2684
+ EOT
2685
+ )
2686
+ example('Scenario')
2687
+ pattern(%w( _enabled ), lambda {
2688
+ @property.set('enabled', true)
2689
+ })
2690
+ doc('enabled', <<'EOT'
2691
+ Enable the scenario for scheduling. This is the default for the top-level
2692
+ scenario.
2693
+ EOT
2694
+ )
2695
+
2696
+ pattern(%w( _minslackrate !number ), lambda {
2697
+ @property.set('minslackrate', @val[1] / 100.0)
2698
+ })
2699
+ doc('minslackrate', <<'EOT'
2700
+ Specifies the minimum percentage of slack a task path must have before it is
2701
+ marked as critical. A path is any list of explicitely or implicitely connected
2702
+ tasks measured from first task to last task. The slack is the time between
2703
+ start of the first task and end of the last task that is not covered by any
2704
+ task of the path.
2705
+
2706
+ Larger values in combination with a project that uses lots of inherited
2707
+ dependencies and long dependency pathes can result in very long scheduling
2708
+ times. The more slack you require, the more pathes have to be searched till
2709
+ the end. For larger projects an increase of 5% can turn a 10 second scheduling
2710
+ run into a 1 hour or more scheduling run. If you need larger slack rate
2711
+ values, avoid the use of inherited dependencies.
2712
+
2713
+ The default value is 0% which turns off the critical path detector.
2714
+ EOT
2715
+ )
2716
+
2717
+ pattern(%w( _projection !projection ), lambda {
2718
+ @property.set('projection', true)
2719
+ })
2720
+ doc('projection', <<'EOT'
2721
+ Enables the projection mode for the scenario. All tasks will be scheduled
2722
+ taking the manual bookings into account. The tasks will be extended by
2723
+ scheduling new bookings starting with the current date until the specified
2724
+ effort, length or duration has been reached.
2725
+ EOT
2726
+ )
2727
+
2728
+ pattern(%w( !scenario ))
2729
+ end
2730
+
2731
+ def rule_scenarioBody
2732
+ optionsRule('scenarioAttributes')
2733
+ end
2734
+
2735
+ def rule_scenarioHeader
2736
+
2737
+ pattern(%w( _scenario $ID $STRING ), lambda {
2738
+ # If this is the top-level scenario, we must delete the default scenario
2739
+ # first.
2740
+ @project.scenarios.clearProperties if @property.nil?
2741
+ if @project.scenario(@val[1])
2742
+ error('scenario_exists', "Scenario #{@val[1]} has already been defined.")
2743
+ end
2744
+ @property = Scenario.new(@project, @val[1], @val[2], @property)
2745
+ @property.inheritAttributes
2746
+ })
2747
+ arg(1, 'id', 'The ID of the scenario')
2748
+ arg(2, 'name', 'The name of the scenario')
2749
+ end
2750
+
2751
+ def rule_scenarioId
2752
+ pattern(%w( $ID_WITH_COLON ), lambda {
2753
+ if (@scenarioIdx = @project.scenarioIdx(@val[0])).nil?
2754
+ error('unknown_scenario_id', "Unknown scenario: @val[0]")
2755
+ end
2756
+ })
2757
+ end
2758
+
2759
+ def rule_scenarioIdList
2760
+ listRule('moreScnarioIdList', '!scenarioIdx')
2761
+ end
2762
+
2763
+ def rule_scenarioIdx
2764
+ pattern(%w( $ID ), lambda {
2765
+ if (scenarioIdx = @project.scenarioIdx(@val[0])).nil?
2766
+ error('unknown_scenario_idx', "Unknown scenario #{@val[0]}")
2767
+ end
2768
+ scenarioIdx
2769
+ })
2770
+ end
2771
+
2772
+ def rule_schedulingDirection
2773
+ singlePattern('_alap')
2774
+ singlePattern('_asap')
2775
+ end
2776
+
2777
+ def rule_shift
2778
+ pattern(%w( !shiftHeader !shiftBody ), lambda {
2779
+ @property = @property.parent
2780
+ })
2781
+ doc('shift', <<'EOT'
2782
+ A shift combines several workhours related settings in a reusable entity. Besides the weekly working hours it can also hold information such as vacations and a timezone.
2783
+ EOT
2784
+ )
2785
+ end
2786
+
2787
+ def rule_shiftAssignment
2788
+ pattern(%w( !shiftId !intervalsOptional ), lambda {
2789
+ # Make sure we have a ShiftAssignment for the property.
2790
+ if @property['shifts', @scenarioIdx].nil?
2791
+ @property['shifts', @scenarioIdx] = ShiftAssignments.new
2792
+ @property['shifts', @scenarioIdx].setProject(@project)
2793
+ end
2794
+
2795
+ if @val[1].nil?
2796
+ intervals = [ Interval.new(@project['start'], @project['end']) ]
2797
+ else
2798
+ intervals = @val[1]
2799
+ end
2800
+ intervals.each do |interval|
2801
+ if !@property['shifts', @scenarioIdx].
2802
+ addAssignment(ShiftAssignment.new(@val[0].scenario(@scenarioIdx),
2803
+ interval))
2804
+ error('shift_assignment_overlap',
2805
+ 'Shifts may not overlap each other.')
2806
+ end
2807
+ end
2808
+ # Set same value again to set the 'provided' state for the attribute.
2809
+ @property['shifts', @scenarioIdx] = @property['shifts', @scenarioIdx]
2810
+ })
2811
+ end
2812
+
2813
+ def rule_shiftAssignments
2814
+ listRule('moreShiftAssignments', '!shiftAssignment')
2815
+ end
2816
+
2817
+ def rule_shiftAttributes
2818
+ optional
2819
+ repeatable
2820
+
2821
+ pattern(%w( !shift ))
2822
+ pattern(%w( !shiftScenarioAttributes ))
2823
+ pattern(%w( !scenarioId !shiftScenarioAttributes ), lambda {
2824
+ @scenarioIdx = 0
2825
+ })
2826
+ end
2827
+
2828
+ def rule_shiftBody
2829
+ optionsRule('shiftAttributes')
2830
+ end
2831
+
2832
+ def rule_shiftHeader
2833
+ pattern(%w( _shift $ID $STRING ), lambda {
2834
+ if @project.shift(@val[1])
2835
+ error('shift_exists', "Shift #{@val[1]} has already been defined.")
2836
+ end
2837
+ @property = Shift.new(@project, @val[1], @val[2], @property)
2838
+ @property.sourceFileInfo = @scanner.sourceFileInfo
2839
+ @property.inheritAttributes
2840
+ @scenarioIdx = 0
2841
+ })
2842
+ arg(1, 'id', 'The ID of the shift')
2843
+ arg(2, 'name', 'The name of the shift')
2844
+ end
2845
+
2846
+ def rule_shiftId
2847
+ pattern(%w( $ID ), lambda {
2848
+ if (shift = @project.shift(@val[0])).nil?
2849
+ error('shift_id_expected', "#{@val[0]} is not a defined shift.")
2850
+ end
2851
+ shift
2852
+ })
2853
+ arg(0, 'shift', 'The ID of a defined shift')
2854
+ end
2855
+
2856
+ def rule_shiftScenarioAttributes
2857
+ pattern(%w( _replace ), lambda {
2858
+ @property['replace', @scenarioIdx] = true
2859
+ })
2860
+ doc('replace', <<'EOT'
2861
+ Use this attribute if the vacation definition for the shift should replace the vacation settings of a resource. This is only effective for shifts that are assigned to resources directly. It is not effective for shifts that are assigned to tasks or allocations.
2862
+ EOT
2863
+ )
2864
+
2865
+ pattern(%w( _timezone $STRING ), lambda {
2866
+ @property['timezone', @scenarioIdx] = @val[1]
2867
+ })
2868
+ doc('timezone.shift', <<'EOT'
2869
+ Sets the timezone of the shift. The working hours of the shift are assumed to be within the specified time zone. The timezone does not effect the vaction interval. The latter is assumed to be within the project time zone.
2870
+ EOT
2871
+ )
2872
+ arg(1, 'zone', <<'EOT'
2873
+ Time zone to use. E. g. 'Europe/Berlin' or 'America/Denver'. Don't use the 3
2874
+ letter acronyms. Linux systems have a command line utility called tzselect to
2875
+ lookup possible values.
2876
+ EOT
2877
+ )
2878
+
2879
+ pattern(%w( _vacation !vacationName !intervalsOptional ), lambda {
2880
+ @property['vacations', @scenarioIdx] =
2881
+ @property['vacations', @scenarioIdx ] + @val[2]
2882
+ })
2883
+ doc('vacation.shift', <<'EOT'
2884
+ Specify a vacation period associated with this shift.
2885
+ EOT
2886
+ )
2887
+
2888
+ pattern(%w( !workinghoursShift ))
2889
+ end
2890
+
2891
+ def rule_sortCriteria
2892
+ pattern([ "!sortCriterium", "!moreSortCriteria" ], lambda {
2893
+ [ @val[0] ] + (@val[1].nil? ? [] : @val[1])
2894
+ })
2895
+ end
2896
+
2897
+ def rule_sortCriterium
2898
+ pattern(%w( !sortTree ), lambda {
2899
+ @val[0]
2900
+ })
2901
+ pattern(%w( !sortNonTree ), lambda {
2902
+ @val[0]
2903
+ })
2904
+ end
2905
+
2906
+ def rule_sortNonTree
2907
+ pattern(%w( $ABSOLUTE_ID ), lambda {
2908
+ args = @val[0].split('.')
2909
+ case args.length
2910
+ when 2
2911
+ scenario = -1
2912
+ direction = args[1] == 'up'
2913
+ attribute = args[0]
2914
+ when 3
2915
+ if (scenario = @project.scenarioIdx(args[0])).nil?
2916
+ error('sort_unknown_scen',
2917
+ "Unknown scenario #{args[0]} in sorting criterium")
2918
+ end
2919
+ attribute = args[1]
2920
+ if args[2] != 'up' && args[2] != 'down'
2921
+ error('sort_direction', "Sorting direction must be 'up' or 'down'")
2922
+ end
2923
+ direction = args[2] == 'up'
2924
+ else
2925
+ error('sorting_crit_exptd1',
2926
+ "Sorting criterium expected (e.g. tree, start.up or " +
2927
+ "plan.end.down).")
2928
+ end
2929
+ if attribute == 'wbs'
2930
+ error('sorting_wbs',
2931
+ "Sorting by wbs is not supported. Please use 'tree' " +
2932
+ '(without appended .up or .down) instead.')
2933
+ end
2934
+ [ attribute, direction, scenario ]
2935
+ })
2936
+ arg(0, 'criteria', <<'EOT'
2937
+ The soring criteria must consist of a property attribute ID. See [[columnid]]
2938
+ for a complete list of available attributes. The ID must be suffixed by '.up'
2939
+ or '.down' to determine the sorting direction. Optionally the ID may be
2940
+ prefixed with a scenario ID and a dot to determine the scenario that should be
2941
+ used for sorting. So, possible values are 'plan.start.up' or 'priority.down'.
2942
+ EOT
2943
+ )
2944
+ end
2945
+
2946
+ def rule_sortTree
2947
+ pattern(%w( $ID ), lambda {
2948
+ if @val[0] != 'tree'
2949
+ error('sorting_crit_exptd2',
2950
+ "Sorting criterium expected (e.g. tree, start.up or " +
2951
+ "plan.end.down).")
2952
+ end
2953
+ [ 'tree', true, -1 ]
2954
+ })
2955
+ arg(0, 'tree',
2956
+ 'Use \'tree\' as first criteria to keep the breakdown structure.')
2957
+ end
2958
+
2959
+ def rule_supplement
2960
+ pattern(%w( !supplementAccount !accountBody ), lambda {
2961
+ @property = nil
2962
+ })
2963
+ pattern(%w( !supplementResource !resourceBody ), lambda {
2964
+ @property = nil
2965
+ })
2966
+ pattern(%w( !supplementTask !taskBody ), lambda {
2967
+ @property = nil
2968
+ })
2969
+ end
2970
+
2971
+ def rule_supplementAccount
2972
+ pattern(%w( _account !accountId ), lambda {
2973
+ @property = @val[1]
2974
+ })
2975
+ arg(1, 'account ID', 'The ID of an already defined account.')
2976
+ end
2977
+
2978
+ def rule_supplementResource
2979
+ pattern(%w( _resource !resourceId ), lambda {
2980
+ @property = @val[1]
2981
+ })
2982
+ arg(1, 'resource ID', 'The ID of an already defined resource.')
2983
+ end
2984
+
2985
+ def rule_supplementTask
2986
+ pattern(%w( _task !taskId ), lambda {
2987
+ @property = @val[1]
2988
+ })
2989
+ arg(1, 'task ID', 'The ID of an already defined task.')
2990
+ end
2991
+
2992
+ def rule_task
2993
+ pattern(%w( !taskHeader !taskBody ), lambda {
2994
+ @property = @property.parent
2995
+ })
2996
+ doc('task', <<'EOT'
2997
+ Tasks are the central elements of a project plan. Use a task to specify the
2998
+ various steps and phases of the project. Depending on the attributes of that
2999
+ task, a task can be a container task, a milestone or a regular leaf task. The
3000
+ latter may have resources assigned. By specifying dependencies the user can
3001
+ force a certain sequence of tasks.
3002
+ EOT
3003
+ )
3004
+ end
3005
+
3006
+ def rule_taskAttributes
3007
+ repeatable
3008
+ optional
3009
+ pattern(%w( _note $STRING ), lambda {
3010
+ @property.set('note', newRichText(@val[1]))
3011
+ })
3012
+ doc('note.task', <<'EOT'
3013
+ Attach a note to the task. This is usually a more detailed specification of
3014
+ what the task is about.
3015
+ EOT
3016
+ )
3017
+
3018
+ pattern(%w( !purge ))
3019
+
3020
+ pattern(%w( _supplement !supplementTask !taskBody ), lambda {
3021
+ @property = @property.parent
3022
+ })
3023
+ doc('supplement.task', <<'EOT'
3024
+ The supplement keyword provides a mechanism to add more attributes to already
3025
+ defined tasks. The additional attributes must obey the same rules as in
3026
+ regular task definitions and must be enclosed by curly braces.
3027
+
3028
+ This construct is primarily meant for situations where the information about a
3029
+ task is split over several files. E. g. the vacation dates for the
3030
+ resources may be in a separate file that was generated by some other tool.
3031
+ EOT
3032
+ )
3033
+
3034
+ pattern(%w( !task ))
3035
+ pattern(%w( !taskScenarioAttributes ))
3036
+ pattern(%w( !scenarioId !taskScenarioAttributes ), lambda {
3037
+ @scenarioIdx = 0
3038
+ })
3039
+ # Other attributes will be added automatically.
3040
+ end
3041
+
3042
+ def rule_taskBody
3043
+ optionsRule('taskAttributes')
3044
+ end
3045
+
3046
+ def rule_taskBooking
3047
+ pattern(%w( !taskBookingHeader !bookingBody ), lambda {
3048
+ @val[0].task.addBooking(@scenarioIdx, @val[0])
3049
+ })
3050
+ end
3051
+
3052
+ def rule_taskBookingHeader
3053
+ pattern(%w( !resourceId !valIntervals ), lambda {
3054
+ checkBooking(@property, @val[0])
3055
+ @booking = Booking.new(@val[0], @property, @val[1])
3056
+ @booking.sourceFileInfo = @scanner.sourceFileInfo
3057
+ @booking
3058
+ })
3059
+ end
3060
+
3061
+ def rule_taskDep
3062
+ pattern(%w( !taskDepHeader !taskDepBody ), lambda {
3063
+ @val[0]
3064
+ })
3065
+ end
3066
+
3067
+ def rule_taskDepAttributes
3068
+ optional
3069
+ repeatable
3070
+
3071
+ pattern(%w( _gapduration !intervalDuration ), lambda {
3072
+ @taskDependency.gapDuration = @val[1]
3073
+ })
3074
+ doc('gapduration', <<'EOT'
3075
+ Specifies the minimum required gap between the end of a preceding task and the
3076
+ start of this task, or the start of a following task and the end of this task.
3077
+ This is calendar time, not working time. 7d means one week.
3078
+ EOT
3079
+ )
3080
+
3081
+ pattern(%w( _gaplength !workingDuration ), lambda {
3082
+ @taskDependency.gapLength = @val[1]
3083
+ })
3084
+ doc('gaplength', <<'EOT'
3085
+ Specifies the minimum required gap between the end of a preceding task and the
3086
+ start of this task, or the start of a following task and the end of this task.
3087
+ This is working time, not calendar time. 7d means 7 working days, not one
3088
+ week. Whether a day is considered a working day or not depends on the defined
3089
+ working hours and global vacations.
3090
+ EOT
3091
+ )
3092
+
3093
+ pattern(%w( _onend ), lambda {
3094
+ @taskDependency.onEnd = true
3095
+ })
3096
+ doc('onend', <<'EOT'
3097
+ The target of the dependency is the end of the task.
3098
+ EOT
3099
+ )
3100
+
3101
+ pattern(%w( _onstart ), lambda {
3102
+ @taskDependency.onEnd = false
3103
+ })
3104
+ doc('onstart', <<'EOT'
3105
+ The target of the dependency is the start of the task.
3106
+ EOT
3107
+ )
3108
+ end
3109
+
3110
+ def rule_taskDepBody
3111
+ optionsRule('taskDepAttributes')
3112
+ end
3113
+
3114
+ def rule_taskDepHeader
3115
+ pattern(%w( !taskDepId ), lambda {
3116
+ @taskDependency = TaskDependency.new(@val[0], true)
3117
+ })
3118
+ end
3119
+
3120
+ def rule_taskDepId
3121
+ singlePattern('$ABSOLUTE_ID')
3122
+ descr(<<'EOT'
3123
+ A reference using the full qualified ID of a task. The IDs of all enclosing
3124
+ parent tasks must be prepended to the task ID and separated with a dot, e.g.
3125
+ ''''proj.plan.doc''''.
3126
+ EOT
3127
+ )
3128
+
3129
+ singlePattern('$ID')
3130
+ descr('Just the ID of the task without and parent IDs.')
3131
+
3132
+ pattern(%w( $RELATIVE_ID ), lambda {
3133
+ task = @property
3134
+ id = @val[0]
3135
+ while task && id[0] == ?!
3136
+ id = id.slice(1, id.length)
3137
+ task = task.parent
3138
+ end
3139
+ error('too_many_bangs',
3140
+ "Too many '!' for relative task in this context.",
3141
+ @property) if id[0] == ?!
3142
+ if task
3143
+ task.fullId + '.' + id
3144
+ else
3145
+ id
3146
+ end
3147
+ })
3148
+ descr(<<'EOT'
3149
+ A relative task ID always starts with one or more exclamation marks and is
3150
+ followed by a task ID. Each exclamation mark lifts the scope where the ID is
3151
+ looked for to the enclosing task. The ID may contain some of the parent IDs
3152
+ separated by dots, e. g. ''''!!plan.doc''''.
3153
+ EOT
3154
+ )
3155
+ end
3156
+
3157
+ def rule_taskDepList
3158
+ pattern(%w( !taskDep !moreDepTasks ), lambda {
3159
+ [ @val[0] ] + @val[1]
3160
+ })
3161
+ end
3162
+
3163
+ def rule_taskHeader
3164
+ pattern(%w( _task $ID $STRING ), lambda {
3165
+ if @property.nil? && !@taskprefix.empty?
3166
+ @property = @project.task(@taskprefix)
3167
+ end
3168
+ id = (@property ? @property.fullId + '.' : '') + @val[1]
3169
+ if @project.task(id)
3170
+ error('task_exists', "Task #{id} has already been defined.")
3171
+ end
3172
+ @property = Task.new(@project, @val[1], @val[2], @property)
3173
+ @property.sourceFileInfo = @scanner.sourceFileInfo
3174
+ @property.inheritAttributes
3175
+ @scenarioIdx = 0
3176
+ })
3177
+ arg(1, 'id', 'The ID of the task')
3178
+ arg(2, 'name', 'The name of the task')
3179
+ end
3180
+
3181
+ def rule_taskId
3182
+ pattern(%w( !taskIdUnverifd ), lambda {
3183
+ id = @val[0]
3184
+ id = @taskprefix + '.' + id unless @taskprefix.empty?
3185
+ # In case we have a nested supplement, we need to prepend the parent ID.
3186
+ id = @property.fullId + '.' + id if @property && @property.is_a?(Task)
3187
+ if (task = @project.task(id)).nil?
3188
+ error('unknown_task', "Unknown task #{id}")
3189
+ end
3190
+ task
3191
+ })
3192
+ end
3193
+
3194
+ def rule_taskIdUnverifd
3195
+ singlePattern('$ABSOLUTE_ID')
3196
+ singlePattern('$ID')
3197
+ end
3198
+
3199
+ def rule_taskPeriod
3200
+ pattern(%w( _period !valInterval), lambda {
3201
+ @property['start', @scenarioIdx] = @val[1].start
3202
+ @property['end', @scenarioIdx] = @val[1].end
3203
+ })
3204
+ doc('period.task', <<'EOT'
3205
+ This property is a shortcut for setting the start and end property at the same
3206
+ time. In contrast to using these, it does not change the scheduling direction.
3207
+ EOT
3208
+ )
3209
+ end
3210
+
3211
+ def rule_taskPred
3212
+ pattern(%w( !taskPredHeader !taskDepBody ), lambda {
3213
+ @val[0]
3214
+ })
3215
+ end
3216
+
3217
+ def rule_taskPredHeader
3218
+ pattern(%w( !taskDepId ), lambda {
3219
+ @taskDependency = TaskDependency.new(@val[0], false)
3220
+ })
3221
+ end
3222
+
3223
+ def rule_taskPredList
3224
+ pattern(%w( !taskPred !morePredTasks ), lambda {
3225
+ [ @val[0] ] + @val[1]
3226
+ })
3227
+ end
3228
+
3229
+ def rule_taskReport
3230
+ pattern(%w( !taskReportHeader !reportBody ))
3231
+ doc('taskreport', <<'EOT'
3232
+ The report lists all tasks and their respective values in the GUI. The
3233
+ resources that are allocated to each task can be listed as well. In the
3234
+ commandline version it is simply ignored.
3235
+ EOT
3236
+ )
3237
+ end
3238
+
3239
+ def rule_taskReportHeader
3240
+ pattern(%w( _taskreport $STRING ), lambda {
3241
+ @report = Report.new(@project, @val[1], :gui, sourceFileInfo)
3242
+ @reportElement = TaskListRE.new(@report)
3243
+ })
3244
+ arg(1, 'file name', <<'EOT'
3245
+ The name of the report.
3246
+ EOT
3247
+ )
3248
+ end
3249
+
3250
+ def rule_taskScenarioAttributes
3251
+
3252
+ pattern(%w( _account $ID ), lambda {
3253
+ # TODO
3254
+ })
3255
+ doc('account.task', <<'EOT'
3256
+ This property has been deprecated. Use [[charge]] instead.
3257
+ EOT
3258
+ )
3259
+
3260
+ pattern(%w( !allocate ))
3261
+
3262
+ pattern(%w( _booking !taskBooking ))
3263
+ doc('booking.task', <<'EOT'
3264
+ Bookings can be used to report already completed work by specifying the exact
3265
+ time intervals a certain resource has worked on this task.
3266
+ EOT
3267
+ )
3268
+
3269
+ pattern(%w( _charge !number !chargeMode ), lambda {
3270
+ checkContainer('charge')
3271
+
3272
+ if @property['chargeset', @scenarioIdx].empty?
3273
+ error('task_without_chargeset',
3274
+ 'The task does not have a chargeset defined.')
3275
+ end
3276
+ case @val[2]
3277
+ when 'onstart'
3278
+ mode = :onStart
3279
+ amount = @val[1]
3280
+ when 'onend'
3281
+ mode = :onEnd
3282
+ amount = @val[1]
3283
+ when 'perhour'
3284
+ mode = :perDiem
3285
+ amount = @val[1] * 24
3286
+ when 'perday'
3287
+ mode = :perDiem
3288
+ amount = @val[1]
3289
+ when 'perweek'
3290
+ mode = :perDiem
3291
+ amount = @val[1] / 7.0
3292
+ end
3293
+ @property['charge', @scenarioIdx] =
3294
+ @property['charge', @scenarioIdx] +
3295
+ [ Charge.new(amount, mode, @property, @scenarioIdx) ]
3296
+ })
3297
+ doc('charge', <<'EOT'
3298
+ Specify a one-time or per-period charge to a certain account. The charge can
3299
+ occur at the start of the task, at the end of it, or continuously over the
3300
+ duration of the task. The accounts to be charged are determined by the
3301
+ [[chargeset]] setting of the task.
3302
+ EOT
3303
+ )
3304
+ arg(0, 'amount', 'The amount to charge')
3305
+
3306
+ pattern(%w( !chargeset ))
3307
+
3308
+ pattern(%w( _complete !number), lambda {
3309
+ if @val[1] < 0.0 || @val[1] > 100.0
3310
+ error('task_complete', "Complete value must be between 0 and 100",
3311
+ @property)
3312
+ end
3313
+ @property['complete', @scenarioIdx] = @val[1]
3314
+ })
3315
+ doc('complete', <<'EOT'
3316
+ Specifies what percentage of the task is already completed. This can be useful
3317
+ for project tracking. Reports with calendar elements may show the completed
3318
+ part of the task in a different color. The completion percentage has no impact
3319
+ on the scheduler. It's meant for documentation purposes only.
3320
+ Tasks may not have subtasks if this attribute is used.
3321
+ EOT
3322
+ )
3323
+ example('Complete', '1')
3324
+
3325
+ arg(1, 'percent', 'The percent value. It must be between 0 and 100.')
3326
+
3327
+ pattern(%w( _depends !taskDepList ), lambda {
3328
+ checkContainer('depends')
3329
+ @property['depends', @scenarioIdx] =
3330
+ @property['depends', @scenarioIdx] + @val[1]
3331
+ @property['forward', @scenarioIdx] = true
3332
+ })
3333
+ doc('depends', <<'EOT'
3334
+ Specifies that the task cannot start before the specified tasks have been
3335
+ finished.
3336
+
3337
+ By using the 'depends' attribute, the scheduling policy is automatically set
3338
+ to asap. If both depends and precedes are used, the last policy counts.
3339
+ EOT
3340
+ )
3341
+ example('Depends1')
3342
+ pattern(%w( _duration !calendarDuration ), lambda {
3343
+ checkContainer('duration')
3344
+ @property['duration', @scenarioIdx] = @val[1]
3345
+ })
3346
+ doc('duration', <<'EOT'
3347
+ Specifies the time the task should last. This is calendar time, not working
3348
+ time. 7d means one week. If resources are specified they are allocated when
3349
+ available. Availability of resources has no impact on the duration of the
3350
+ task. It will always be the specified duration.
3351
+
3352
+ Tasks may not have subtasks if this attribute is used.
3353
+ EOT
3354
+ )
3355
+ example('Durations')
3356
+ also(%w( effort length ))
3357
+
3358
+ pattern(%w( _effort !workingDuration ), lambda {
3359
+ checkContainer('effort')
3360
+ if @val[1] <= 0.0
3361
+ error('effort_zero', "Effort value must be larger than 0", @property)
3362
+ end
3363
+ @property['effort', @scenarioIdx] = @val[1]
3364
+ })
3365
+ doc('effort', <<'EOT'
3366
+ Specifies the effort needed to complete the task. An effort of 4d can be done
3367
+ with 2 full-time resources in 2 days. The task will not finish before the
3368
+ resources have contributed the specified effort. So the duration of the task
3369
+ will depend on the availability of the resources.
3370
+
3371
+ WARNING: In almost all real world projects effort is not the product of time
3372
+ and resources. This is only true if the task can be partitioned without adding
3373
+ any overhead. For more information about this read ''The Mythical Man-Month'' by
3374
+ Frederick P. Brooks, Jr.
3375
+
3376
+ Tasks may not have subtasks if this attribute is used.
3377
+ EOT
3378
+ )
3379
+ example('Durations')
3380
+ also(%w( duration length ))
3381
+
3382
+ pattern(%w( _end !valDate ), lambda {
3383
+ @property['end', @scenarioIdx] = @val[1]
3384
+ @property['forward', @scenarioIdx] = false
3385
+ })
3386
+ doc('end', <<'EOT'
3387
+ The end date of the task. When specified for the top-level (default) scenario
3388
+ this attributes also implicitly sets the scheduling policy of the tasks to
3389
+ alap.
3390
+
3391
+ If no end date is given for a task and the end is not specified by a
3392
+ dependency on another task, or by a start date plus a duration, the end date
3393
+ will be inherited from the enclosing tasks or the project end date.
3394
+ EOT
3395
+ )
3396
+ example('Export', '1')
3397
+ pattern(%w( _endcredit !number ), lambda {
3398
+ @property['charge', @scenarioIdx] =
3399
+ @property['charge', @scenarioIdx] +
3400
+ [ Charge.new(@val[1], :onEnd, @property, @scenarioIdx) ]
3401
+ })
3402
+ doc('endcredit', <<'EOT'
3403
+ Specifies an amount that is credited to the accounts specified by the
3404
+ [[chargeset]] attributes at the moment the tasks ends. This attribute has been
3405
+ deprecated and should no longer be used. Use [[charge]] instead.
3406
+ EOT
3407
+ )
3408
+ example('Account', '1')
3409
+ pattern(%w( !flags ))
3410
+ doc('flags.task', <<'EOT'
3411
+ Attach a set of flags. The flags can be used in logical expressions to filter
3412
+ properties from the reports.
3413
+ EOT
3414
+ )
3415
+
3416
+ pattern(%w( _length !workingDuration ), lambda {
3417
+ checkContainer('length')
3418
+ @property['length', @scenarioIdx] = @val[1]
3419
+ })
3420
+ doc('length', <<'EOT'
3421
+ Specifies the time the task occupies the resources. This is working time, not
3422
+ calendar time. 7d means 7 working days, not one week. Whether a day is
3423
+ considered a working day or not depends on the defined working hours and
3424
+ global vacations. A task with a length specification may have resource
3425
+ allocations. Resources are allocated when they are available. The availability
3426
+ has no impact on the duration of the task. A day where none of the specified
3427
+ resources is available is still considered a working day, if there is no
3428
+ global vacation or global working time defined.
3429
+
3430
+ Tasks may not have subtasks if this attribute is used.
3431
+ EOT
3432
+ )
3433
+ also(%w( duration effort ))
3434
+
3435
+ pattern(%w( !limits ), lambda {
3436
+ checkContainer('limits')
3437
+ @property['limits', @scenarioIdx] = @val[0]
3438
+ })
3439
+ doc('limits.task', <<'EOT'
3440
+ Set per-interval allocation limits for the task. This setting affects all allocations for this task.
3441
+ EOT
3442
+ )
3443
+
3444
+ pattern(%w( _maxend !valDate ), lambda {
3445
+ @property['maxend', @scenarioIdx] = @val[1]
3446
+ })
3447
+ doc('maxend', <<'EOT'
3448
+ Specifies the maximum wanted end time of the task. The value is not used
3449
+ during scheduling, but is checked after all tasks have been scheduled. If the
3450
+ end of the task is later than the specified value, then an error is reported.
3451
+ EOT
3452
+ )
3453
+
3454
+ pattern(%w( _maxstart !valDate ), lambda {
3455
+ @property['maxstart', @scenarioIdx] = @val[1]
3456
+ })
3457
+ doc('maxstart', <<'EOT'
3458
+ Specifies the maximum wanted start time of the task. The value is not used
3459
+ during scheduling, but is checked after all tasks have been scheduled. If the
3460
+ start of the task is later than the specified value, then an error is
3461
+ reported.
3462
+ EOT
3463
+ )
3464
+
3465
+ pattern(%w( _milestone ), lambda {
3466
+ checkContainer('limits')
3467
+ @property['milestone', @scenarioIdx] = true
3468
+ })
3469
+ doc('milestone', <<'EOT'
3470
+ Turns the task into a special task that has no duration. You may not specify a
3471
+ duration, length, effort or subtasks for a milestone task.
3472
+
3473
+ A task that only has a start or an end specification and no duration
3474
+ specification, inherited start or end dates, no dependencies or sub tasks,
3475
+ will be recognized as milestone automatically.
3476
+ EOT
3477
+ )
3478
+
3479
+ pattern(%w( _minend !valDate ), lambda {
3480
+ @property['minend', @scenarioIdx] = @val[1]
3481
+ })
3482
+ doc('minend', <<'EOT'
3483
+ Specifies the minimum wanted end time of the task. The value is not used
3484
+ during scheduling, but is checked after all tasks have been scheduled. If the
3485
+ end of the task is earlier than the specified value, then an error is
3486
+ reported.
3487
+ EOT
3488
+ )
3489
+
3490
+ pattern(%w( _minstart !valDate ), lambda {
3491
+ @property['minstart', @scenarioIdx] = @val[1]
3492
+ })
3493
+ doc('minstart', <<'EOT'
3494
+ Specifies the minimum wanted start time of the task. The value is not used
3495
+ during scheduling, but is checked after all tasks have been scheduled. If the
3496
+ start of the task is earlier than the specified value, then an error is
3497
+ reported.
3498
+ EOT
3499
+ )
3500
+
3501
+ pattern(%w( _startcredit !number ), lambda {
3502
+ @property['charge', @scenarioIdx] =
3503
+ @property['charge', @scenarioIdx] +
3504
+ [ Charge.new(@val[1], :onStart, @property, @scenarioIdx) ]
3505
+ })
3506
+ doc('startcredit', <<'EOT'
3507
+ Specifies an amount that is credited to the account specified by the
3508
+ [[chargeset]] attributes at the moment the tasks starts. This attribute has
3509
+ been deprecated and should no longer be used. Use [[charge]] instead.
3510
+ EOT
3511
+ )
3512
+ pattern(%w( !taskPeriod ))
3513
+
3514
+ pattern(%w( _precedes !taskPredList ), lambda {
3515
+ checkContainer('precedes')
3516
+ @property['precedes', @scenarioIdx] =
3517
+ @property['precedes', @scenarioIdx] + @val[1]
3518
+ @property['forward', @scenarioIdx] = false
3519
+ })
3520
+ doc('precedes', <<'EOT'
3521
+ Specifies that the tasks with the specified IDs cannot start before the task
3522
+ has been finished. If multiple IDs are specified, they must be separated by
3523
+ commas. IDs must be either global or relative. A relative ID starts with a
3524
+ number of '!'. Each '!' moves the scope to the parent task. Global IDs do not
3525
+ contain '!', but have IDs separated by dots.
3526
+
3527
+ By using the 'precedes' attribute, the scheduling policy is automatically set
3528
+ to alap. If both depends and precedes are used within a task, the last policy
3529
+ counts.
3530
+ EOT
3531
+ )
3532
+
3533
+ pattern(%w( _priority $INTEGER ), lambda {
3534
+ if @val[1] < 0 || @val[1] > 1000
3535
+ error('task_priority', "Priority must have a value between 0 and 1000",
3536
+ @property)
3537
+ end
3538
+ @property['priority', @scenarioIdx] = @val[1]
3539
+ })
3540
+ doc('priority', <<'EOT'
3541
+ Specifies the priority of the task. A task with higher priority is more
3542
+ likely to get the requested resources. The default priority value of all tasks
3543
+ is 500. Don't confuse the priority of a tasks with the importance or urgency
3544
+ of a task. It only increases the chances that the tasks gets the requested
3545
+ resources. It does not mean that the task happens earlier, though that is
3546
+ usually the effect you will see. It also does not have any effect on tasks
3547
+ that don't have any resources assigned (e.g. milestones).
3548
+
3549
+ This attribute is inherited by subtasks if specified prior to the definition
3550
+ of the subtask.
3551
+ EOT
3552
+ )
3553
+ arg(1, 'value', 'Priority value (1 - 1000)')
3554
+
3555
+ pattern(%w( _projectid $ID ), lambda {
3556
+ unless @project['projectids'].include?(@val[1])
3557
+ error('unknown_projectid', "Unknown project ID #{@val[1]}")
3558
+ end
3559
+ @property['projectid', @scenarioIdx] = @val[1]
3560
+ })
3561
+ doc('projectid.task', <<'EOT'
3562
+ In larger projects it may be desireable to work with different project IDs for
3563
+ parts of the project. This attribute assignes a new project ID to this task an
3564
+ all subsequently defined sub tasks. The project ID needs to be declared first using [[projectid]] or [[projectids]].
3565
+ EOT
3566
+ )
3567
+
3568
+ pattern(%w( _responsible !resourceList ), lambda {
3569
+ @property['responsible', @scenarioIdx] = @val[1]
3570
+ })
3571
+ doc('responsible', <<'EOT'
3572
+ The ID of the resource that is responsible for this task. This value is for
3573
+ documentation purposes only. It's not used by the scheduler.
3574
+ EOT
3575
+ )
3576
+
3577
+ pattern(%w( _scheduled ), lambda {
3578
+ @property['scheduled', @scenarioIdx] = true
3579
+ })
3580
+ doc('scheduled', <<'EOT'
3581
+ This is mostly for internal use. It specifies that the task can be ignored for
3582
+ scheduling in the scenario.
3583
+ EOT
3584
+ )
3585
+
3586
+ pattern(%w( _scheduling !schedulingDirection ), lambda {
3587
+ if @val[1] == 'alap'
3588
+ @property['forward', @scenarioIdx] = false
3589
+ elsif @val[1] == 'asap'
3590
+ @property['forward', @scenarioIdx] = true
3591
+ end
3592
+ })
3593
+ doc('scheduling', <<'EOT'
3594
+ Specifies the scheduling policy for the task. A task can be scheduled from
3595
+ start to end (As Soon As Possible, asap) or from end to start (As Late As
3596
+ Possible, alap).
3597
+
3598
+ A task can be scheduled from start to end (ASAP mode) when it has a hard
3599
+ (start) or soft (depends) criteria for the start time. A task can be scheduled
3600
+ from end to start (ALAP mode) when it has a hard (end) or soft (precedes)
3601
+ criteria for the end time.
3602
+
3603
+ Some task attributes set the scheduling policy implicitly. This attribute can
3604
+ be used to explicitly set the scheduling policy of the task to a certain
3605
+ direction. To avoid it being overwritten again by an implicit attribute this
3606
+ attribute should always be the last attribute of the task.
3607
+
3608
+ A random mixture of ASAP and ALAP tasks can have unexpected side effects on
3609
+ the scheduling of the project. It increases significantly the scheduling
3610
+ complexity and results in much longer scheduling times. Especially in projects
3611
+ with many hundreds of tasks the scheduling time of a project with a mixture of
3612
+ ASAP and ALAP times can be 2 to 10 times longer. When the projects contains
3613
+ chains of ALAP and ASAP tasks the tasks further down the dependency chain will
3614
+ be served much later than other non-chained task even when they have a much
3615
+ higher priority. This can result in situations where high priority tasks do
3616
+ not get their resources even though the parallel competing tasks have a much
3617
+ lower priority.
3618
+
3619
+ As a general rule, try to avoid ALAP tasks whenever possible. Have a close
3620
+ eye on tasks that have been switched implicitly to ALAP mode because the
3621
+ end attribute comes after the start attribute.
3622
+ EOT
3623
+ )
3624
+
3625
+ pattern(%w( _shift !shiftAssignments ), lambda {
3626
+ checkContainer('shift')
3627
+ })
3628
+ doc('shift.task', <<'EOT'
3629
+ This keyword has been deprecated. Please use [shifts.task shifts
3630
+ (task)] instead.
3631
+ EOT
3632
+ )
3633
+
3634
+ pattern(%w( _shifts !shiftAssignments ), lambda {
3635
+ checkContainer('shifts')
3636
+ })
3637
+ doc('shifts.task', <<'EOT'
3638
+ Limits the working time for this task during the during the specified interval
3639
+ to the working hours of the given shift. Multiple shifts can be defined, but
3640
+ shift intervals may not overlap. This is an additional working time limit to
3641
+ the working hours of the allocated resources. It does not replace the resource
3642
+ working hour restrictions. For a resource to be assigned to a time slot, both
3643
+ the task shifts as well as the resource working hours must declare the time slot as duty slot.
3644
+ EOT
3645
+ )
3646
+
3647
+ pattern(%w( _start !valDate), lambda {
3648
+ @property['start', @scenarioIdx] = @val[1]
3649
+ @property['forward', @scenarioIdx] = true
3650
+ })
3651
+ doc('start', <<'EOT'
3652
+ The start date of the task. When specified for the top-level (default)
3653
+ scenario this attribute also implicitly sets the scheduling policy of the task
3654
+ to asap.
3655
+
3656
+ If no start date is given for a task and the start is not specified by a
3657
+ dependency on another task, or by an end date plus a duration, the start date
3658
+ will be inherited from the enclosing tasks or the project start date.
3659
+ EOT
3660
+ )
3661
+ also(%w( end period.task maxstart minstart scheduling ))
3662
+ # Other attributes will be added automatically.
3663
+ end
3664
+
3665
+ def rule_timeformat
3666
+ pattern(%w( _timeformat $STRING ), lambda {
3667
+ @val[1]
3668
+ })
3669
+ doc('timeformat', <<'EOT'
3670
+ Determines how time specifications in reports look like.
3671
+ EOT
3672
+ )
3673
+ arg(1, 'format', <<'EOT'
3674
+ Ordinary characters placed in the format string are copied without
3675
+ conversion. Conversion specifiers are introduced by a `%' character, and are
3676
+ replaced in s as follows:
3677
+
3678
+ * ''''%a'''' The abbreviated weekday name according to the current locale.
3679
+
3680
+ * ''''%A'''' The full weekday name according to the current locale.
3681
+
3682
+ * ''''%b'''' The abbreviated month name according to the current locale.
3683
+
3684
+ * ''''%B'''' The full month name according to the current locale.
3685
+
3686
+ * ''''%c'''' The preferred date and time representation for the current locale.
3687
+
3688
+ * ''''%C'''' The century number (year/100) as a 2-digit integer. (SU)
3689
+
3690
+ * ''''%d'''' The day of the month as a decimal number (range 01 to 31).
3691
+
3692
+ * ''''%e'''' Like ''''%d'''', the day of the month as a decimal number, but a
3693
+ leading zero is replaced by a space. (SU)
3694
+
3695
+ * ''''%E'''' Modifier: use alternative format, see below. (SU)
3696
+
3697
+ * ''''%F'''' Equivalent to ''''%Y-%m-%d'''' (the ISO 8601 date format). (C99)
3698
+
3699
+ * ''''%G'''' The ISO 8601 year with century as a decimal number. The 4-digit
3700
+ year corresponding to the ISO week number (see %V). This has the same format
3701
+ and value as ''''%y'''', except that if the ISO week number belongs to the
3702
+ previous or next year, that year is used instead. (TZ)
3703
+
3704
+ * ''''%g'''' Like %G, but without century, i.e., with a 2-digit year (00-99).
3705
+ (TZ)
3706
+
3707
+ * ''''%h'''' Equivalent to ''''%b''''. (SU)
3708
+
3709
+ * ''''%H'''' The hour as a decimal number using a 24-hour clock (range 00 to
3710
+ 23).
3711
+
3712
+ * ''''%I'''' The hour as a decimal number using a 12-hour clock (range 01 to
3713
+ 12).
3714
+
3715
+ * ''''%j'''' The day of the year as a decimal number (range 001 to 366).
3716
+
3717
+ * ''''%k'''' The hour (24-hour clock) as a decimal number (range 0 to 23);
3718
+ single digits are preceded by a blank. (See also ''''%H''''.) (TZ)
3719
+
3720
+ * ''''%l'''' The hour (12-hour clock) as a decimal number (range 1 to 12);
3721
+ single digits are preceded by a blank. (See also ''''%I''''.) (TZ)
3722
+
3723
+ * ''''%m'''' The month as a decimal number (range 01 to 12).
3724
+
3725
+ * ''''%M'''' The minute as a decimal number (range 00 to 59).
3726
+
3727
+ * ''''%n'''' A newline character. (SU)
3728
+
3729
+ * ''''%O'''' Modifier: use alternative format, see below. (SU)
3730
+
3731
+ * ''''%p'''' Either 'AM' or 'PM' according to the given time value, or the
3732
+ corresponding strings for the current locale. Noon is treated as `pm' and
3733
+ midnight as 'am'.
3734
+
3735
+ * ''''%P'''' Like %p but in lowercase: 'am' or 'pm' or ''''%a''''
3736
+ corresponding string for the current locale. (GNU)
3737
+
3738
+ * ''''%r'''' The time in a.m. or p.m. notation. In the POSIX locale this is
3739
+ equivalent to ''''%I:%M:%S %p''''. (SU)
3740
+
3741
+ * ''''%R'''' The time in 24-hour notation (%H:%M). (SU) For a version
3742
+ including the seconds, see ''''%T'''' below.
3743
+
3744
+ * ''''%s'''' The number of seconds since the Epoch, i.e., since 1970-01-01
3745
+ 00:00:00 UTC. (TZ)
3746
+
3747
+ * ''''%S'''' The second as a decimal number (range 00 to 61).
3748
+
3749
+ * ''''%t'''' A tab character. (SU)
3750
+
3751
+ * ''''%T'''' The time in 24-hour notation (%H:%M:%S). (SU)
3752
+
3753
+ * ''''%u'''' The day of the week as a decimal, range 1 to 7, Monday being 1.
3754
+ See also ''''%w''''. (SU)
3755
+
3756
+ * ''''%U'''' The week number of the current year as a decimal number, range
3757
+ 00 to 53, starting with the first Sunday as the first day of week 01. See also
3758
+ ''''%V'''' and ''''%W''''.
3759
+
3760
+ * ''''%V'''' The ISO 8601:1988 week number of the current year as a decimal
3761
+ number, range 01 to 53, where week 1 is the first week that has at least 4
3762
+ days in the current year, and with Monday as the first day of the week. See
3763
+ also ''''%U'''' and ''''%W''''. %(SU)
3764
+
3765
+ * ''''%w'''' The day of the week as a decimal, range 0 to 6, Sunday being 0. See also ''''%u''''.
3766
+
3767
+ * ''''%W'''' The week number of the current %year as a decimal number, range
3768
+ 00 to 53, starting with the first Monday as the first day of week 01.
3769
+
3770
+ * ''''%x'''' The preferred date representation for the current locale without
3771
+ the time.
3772
+
3773
+ * ''''%X'''' The preferred time representation for the current locale without
3774
+ the date.
3775
+
3776
+ * ''''%y'''' The year as a decimal number without a century (range 00 to 99).
3777
+
3778
+ * ''''%Y'''' The year as a decimal number including the century.
3779
+
3780
+ * ''''%z'''' The time zone as hour offset from GMT. Required to emit
3781
+ RFC822-conformant dates (using ''''%a, %d %%b %Y %H:%M:%S %%z''''). (GNU)
3782
+
3783
+ * ''''%Z'''' The time zone or name or abbreviation.
3784
+
3785
+ * ''''%+'''' The date and time in date(1) format. (TZ)
3786
+
3787
+ * ''''%%'''' A literal ''''%'''' character.
3788
+
3789
+ Some conversion specifiers can be modified by preceding them by the E or O
3790
+ modifier to indicate that an alternative format should be used. If the
3791
+ alternative format or specification does not exist for the current locale, the
3792
+ behavior will be as if the unmodified conversion specification were used.
3793
+
3794
+ (SU) The Single Unix Specification mentions %Ec, %EC, %Ex, %%EX, %Ry, %EY,
3795
+ %Od, %Oe, %OH, %OI, %Om, %OM, %OS, %Ou, %OU, %OV, %Ow, %OW, %Oy, where the
3796
+ effect of the O modifier is to use alternative numeric symbols (say, Roman
3797
+ numerals), and that of the E modifier is to use a locale-dependent alternative
3798
+ representation.
3799
+
3800
+ This documentation of the timeformat attribute has been taken from the man page
3801
+ of the GNU strftime function.
3802
+ EOT
3803
+ )
3804
+
3805
+ end
3806
+
3807
+ def rule_timeInterval
3808
+ pattern([ '$TIME', '_ - ', '$TIME' ], lambda {
3809
+ if @val[0] >= @val[2]
3810
+ error('time_interval',
3811
+ "End time of interval must be larger than start time")
3812
+ end
3813
+ [ @val[0], @val[2] ]
3814
+ })
3815
+ end
3816
+
3817
+ def rule_timezone
3818
+ pattern(%w( _timezone $STRING ), lambda{
3819
+ # TODO
3820
+ })
3821
+ doc('timezone', <<'EOT'
3822
+ Sets the default timezone of the project. All times that have no time
3823
+ zones specified will be assumed to be in this timezone. The value must be a
3824
+ string just like those used for the TZ environment variable. Most
3825
+ Linux systems have a command line utility called tzselect to lookup
3826
+ possible values.
3827
+
3828
+ The project start and end time are not affected by this setting. You
3829
+ have to explicitly state the timezone for those dates or the system
3830
+ defaults are assumed.
3831
+ EOT
3832
+ )
3833
+ arg(1, 'zone', <<'EOT'
3834
+ Time zone to use. E. g. 'Europe/Berlin' or 'America/Denver'. Don't use the 3
3835
+ letter acronyms.
3836
+ EOT
3837
+ )
3838
+ end
3839
+
3840
+ def rule_vacationName
3841
+ optional
3842
+ pattern(%w( $STRING )) # We just throw the name away
3843
+ arg(0, 'name', 'An optional name for the vacation')
3844
+ end
3845
+
3846
+ def rule_valDate
3847
+ pattern(%w( !date ), lambda {
3848
+ if @val[0] < @project['start'] || @val[0] > @project['end']
3849
+ error('date_in_range', "Date must be within the project time frame " +
3850
+ "#{@project['start']} + - #{@project['end']}")
3851
+ end
3852
+ @val[0]
3853
+ })
3854
+ end
3855
+
3856
+ def rule_valIntervalOrDate
3857
+ pattern(%w( !date !intervalOptionalEnd ), lambda {
3858
+ if @val[1]
3859
+ mode = @val[1][0]
3860
+ endSpec = @val[1][1]
3861
+ if mode == 0
3862
+ iv = Interval.new(@val[0], endSpec)
3863
+ else
3864
+ iv = Interval.new(@val[0], @val[0] + endSpec)
3865
+ end
3866
+ else
3867
+ iv = Interval.new(@val[0], @val[0].sameTimeNextDay)
3868
+ end
3869
+ checkInterval(iv)
3870
+ iv
3871
+ })
3872
+ doc('interval4', <<'EOT'
3873
+ There are three ways to specify a date interval. The first is the most
3874
+ obvious. A date interval consists of a start and end DATE. Watch out for end
3875
+ dates without a time specification! Date specifications are 0 extended. An
3876
+ end date without a time is expanded to midnight that day. So the day of the
3877
+ end date is not included in the interval! The start and end dates must be separated by a hyphen character.
3878
+
3879
+ In the second form, the end date is omitted. A 24 hour interval is assumed.
3880
+
3881
+ The third form specifies the start date and an interval duration. The duration must be prefixed by a plus character.
3882
+
3883
+ The start and end date of the interval must be within the specified project
3884
+ time frame.
3885
+ EOT
3886
+ )
3887
+ end
3888
+
3889
+ def rule_valInterval
3890
+ pattern(%w( !date !intervalEnd ), lambda {
3891
+ mode = @val[1][0]
3892
+ endSpec = @val[1][1]
3893
+ if mode == 0
3894
+ unless @val[0] < endSpec
3895
+ error('start_before_end', "The end date (#{endSpec}) must be after " +
3896
+ "the start date (#{@val[0]}).")
3897
+ end
3898
+ iv = Interval.new(@val[0], endSpec)
3899
+ else
3900
+ iv = Interval.new(@val[0], @val[0] + endSpec)
3901
+ end
3902
+ checkInterval(iv)
3903
+ iv
3904
+ })
3905
+ doc('interval1', <<'EOT'
3906
+ There are two ways to specify a date interval. The start and end date must lie within the specified project period.
3907
+
3908
+ The first is the most obvious. A date interval consists of a start and end
3909
+ DATE. Watch out for end dates without a time specification! Date
3910
+ specifications are 0 extended. An end date without a time is expanded to
3911
+ midnight that day. So the day of the end date is not included in the interval!
3912
+ The start and end dates must be separated by a hyphen character.
3913
+
3914
+ In the second form specifies the start date and an interval duration. The
3915
+ duration must be prefixed by a plus character.
3916
+ EOT
3917
+ )
3918
+ end
3919
+
3920
+ def rule_valIntervals
3921
+ listRule('moreValIntervals', '!valIntervalOrDate')
3922
+ end
3923
+
3924
+ def rule_weekday
3925
+ pattern(%w( _sun ), lambda { 0 })
3926
+ pattern(%w( _mon ), lambda { 1 })
3927
+ pattern(%w( _tue ), lambda { 2 })
3928
+ pattern(%w( _wed ), lambda { 3 })
3929
+ pattern(%w( _thu ), lambda { 4 })
3930
+ pattern(%w( _fri ), lambda { 5 })
3931
+ pattern(%w( _sat ), lambda { 6 })
3932
+ end
3933
+
3934
+ def rule_weekDayInterval
3935
+ pattern(%w( !weekday !weekDayIntervalEnd ), lambda {
3936
+ weekdays = Array.new(7, false)
3937
+ if @val[1].nil?
3938
+ weekdays[@val[0]] = true
3939
+ else
3940
+ d = @val[0]
3941
+ loop do
3942
+ weekdays[d] = true
3943
+ break if d == @val[1]
3944
+ d = (d + 1) % 7
3945
+ end
3946
+ end
3947
+
3948
+ weekdays
3949
+ })
3950
+ arg(0, 'weekday', 'Weekday (sun - sat)')
3951
+ end
3952
+
3953
+ def rule_weekDayIntervalEnd
3954
+ optional
3955
+ pattern([ '_ - ', '!weekday' ], lambda {
3956
+ @val[1]
3957
+ })
3958
+ arg(1, 'end weekday',
3959
+ 'Weekday (sun - sat). It is included in the interval.')
3960
+ end
3961
+
3962
+ def rule_workingDuration
3963
+ pattern(%w( !number !durationUnit ), lambda {
3964
+ convFactors = [ 60, # minutes
3965
+ 60 * 60, # hours
3966
+ 60 * 60 * @project['dailyworkinghours'], # days
3967
+ 60 * 60 * @project['dailyworkinghours'] *
3968
+ (@project['yearlyworkingdays'] / 52.1429), # weeks
3969
+ 60 * 60 * @project['dailyworkinghours'] *
3970
+ (@project['yearlyworkingdays'] / 12), # months
3971
+ 60 * 60 * @project['dailyworkinghours'] *
3972
+ @project['yearlyworkingdays'] # years
3973
+ ]
3974
+ (@val[0] * convFactors[@val[1]] /
3975
+ @project['scheduleGranularity']).round.to_i
3976
+ })
3977
+ arg(0, 'value', 'A floating point or integer number')
3978
+ end
3979
+
3980
+ def rule_workinghours
3981
+ pattern(%w( _workinghours !listOfDays !listOfTimes), lambda {
3982
+ wh = @property.nil? ? @project['workinghours'] :
3983
+ @property['workinghours', @scenarioIdx]
3984
+ wh.timezone = @property.nil? ? @project['timezone'] :
3985
+ @property['timezone', @scenarioIdx]
3986
+ 7.times { |i| wh.setWorkingHours(i, @val[2]) if @val[1][i] }
3987
+ })
3988
+ end
3989
+
3990
+ def rule_workinghoursProject
3991
+ pattern(%w( !workinghours ))
3992
+ doc('workinghours.project', <<'EOT'
3993
+ Set the default working hours for all subsequent resource definitions.
3994
+ The working hours specification limits the availability of resources to
3995
+ certain time slots of week days.
3996
+ EOT
3997
+ )
3998
+ end
3999
+
4000
+ def rule_workinghoursResource
4001
+ pattern(%w( !workinghours ))
4002
+ doc('workinghours.resource', <<'EOT'
4003
+ Set the working hours for a specific resource. The working hours specification
4004
+ limits the availability of resources to certain time slots of week days.
4005
+ EOT
4006
+ )
4007
+ end
4008
+
4009
+ def rule_workinghoursShift
4010
+ pattern(%w( !workinghours ))
4011
+ doc('workinghours.shift', <<'EOT'
4012
+ Set the default working hours for the shift. The working hours specification
4013
+ limits the availability of resources or the activity on a task to certain time
4014
+ slots of week days.
4015
+ EOT
4016
+ )
4017
+ end
4018
+
4019
+ end
4020
+
4021
+ end
4022
+