taskjuggler 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/COPYING +280 -0
- data/README +31 -0
- data/Rakefile +20 -0
- data/benchmarks/UTF-8-Strings.rb +58 -0
- data/benchmarks/allocate.tjp +30 -0
- data/benchmarks/booking.tjp +62 -0
- data/benchmarks/depends.tjp +112 -0
- data/benchmarks/htmltaskreport.tjp +45 -0
- data/benchmarks/runbench.rb +24 -0
- data/bin/tj3 +3 -0
- data/bin/tj3man +3 -0
- data/doc/classes/AppConfig.html +808 -0
- data/doc/classes/Arguments.html +226 -0
- data/doc/classes/String.html +395 -0
- data/doc/classes/TaskJuggler.html +1358 -0
- data/doc/classes/TaskJuggler/Account.html +257 -0
- data/doc/classes/TaskJuggler/AccountScenario.html +218 -0
- data/doc/classes/TaskJuggler/Allocation.html +419 -0
- data/doc/classes/TaskJuggler/AllocationAttribute.html +291 -0
- data/doc/classes/TaskJuggler/AttributeBase.html +608 -0
- data/doc/classes/TaskJuggler/AttributeDefinition.html +259 -0
- data/doc/classes/TaskJuggler/Booking.html +307 -0
- data/doc/classes/TaskJuggler/BookingListAttribute.html +263 -0
- data/doc/classes/TaskJuggler/BooleanAttribute.html +261 -0
- data/doc/classes/TaskJuggler/CSVFile.html +325 -0
- data/doc/classes/TaskJuggler/Charge.html +279 -0
- data/doc/classes/TaskJuggler/ChargeListAttribute.html +229 -0
- data/doc/classes/TaskJuggler/ChargeSet.html +440 -0
- data/doc/classes/TaskJuggler/ChargeSetListAttribute.html +276 -0
- data/doc/classes/TaskJuggler/ColumnTable.html +260 -0
- data/doc/classes/TaskJuggler/DateAttribute.html +194 -0
- data/doc/classes/TaskJuggler/DependencyListAttribute.html +267 -0
- data/doc/classes/TaskJuggler/DurationAttribute.html +229 -0
- data/doc/classes/TaskJuggler/FixnumAttribute.html +194 -0
- data/doc/classes/TaskJuggler/FlagListAttribute.html +263 -0
- data/doc/classes/TaskJuggler/FloatAttribute.html +229 -0
- data/doc/classes/TaskJuggler/GanttChart.html +667 -0
- data/doc/classes/TaskJuggler/GanttContainer.html +441 -0
- data/doc/classes/TaskJuggler/GanttHeader.html +280 -0
- data/doc/classes/TaskJuggler/GanttHeaderScaleItem.html +245 -0
- data/doc/classes/TaskJuggler/GanttLine.html +398 -0
- data/doc/classes/TaskJuggler/GanttLoadStack.html +327 -0
- data/doc/classes/TaskJuggler/GanttMilestone.html +415 -0
- data/doc/classes/TaskJuggler/GanttRouter.html +425 -0
- data/doc/classes/TaskJuggler/GanttTaskBar.html +429 -0
- data/doc/classes/TaskJuggler/HTMLDocument.html +240 -0
- data/doc/classes/TaskJuggler/HTMLGraphics.html +231 -0
- data/doc/classes/TaskJuggler/Interval.html +552 -0
- data/doc/classes/TaskJuggler/IntervalListAttribute.html +267 -0
- data/doc/classes/TaskJuggler/KeywordDocumentation.html +796 -0
- data/doc/classes/TaskJuggler/Limits.html +416 -0
- data/doc/classes/TaskJuggler/Limits/Limit.html +381 -0
- data/doc/classes/TaskJuggler/LimitsAttribute.html +261 -0
- data/doc/classes/TaskJuggler/Log.html +613 -0
- data/doc/classes/TaskJuggler/LogicalAttribute.html +226 -0
- data/doc/classes/TaskJuggler/LogicalExpression.html +251 -0
- data/doc/classes/TaskJuggler/LogicalFlag.html +229 -0
- data/doc/classes/TaskJuggler/LogicalFunction.html +324 -0
- data/doc/classes/TaskJuggler/LogicalOperation.html +299 -0
- data/doc/classes/TaskJuggler/Macro.html +194 -0
- data/doc/classes/TaskJuggler/MacroParser.html +360 -0
- data/doc/classes/TaskJuggler/MacroTable.html +366 -0
- data/doc/classes/TaskJuggler/Message.html +281 -0
- data/doc/classes/TaskJuggler/MessageHandler.html +215 -0
- data/doc/classes/TaskJuggler/Project.html +1606 -0
- data/doc/classes/TaskJuggler/ProjectFileParser.html +412 -0
- data/doc/classes/TaskJuggler/PropertyList.html +597 -0
- data/doc/classes/TaskJuggler/PropertySet.html +1200 -0
- data/doc/classes/TaskJuggler/PropertyTreeNode.html +1449 -0
- data/doc/classes/TaskJuggler/Query.html +600 -0
- data/doc/classes/TaskJuggler/RealFormat.html +252 -0
- data/doc/classes/TaskJuggler/ReferenceAttribute.html +194 -0
- data/doc/classes/TaskJuggler/Report.html +528 -0
- data/doc/classes/TaskJuggler/ReportElement.html +1070 -0
- data/doc/classes/TaskJuggler/ReportTable.html +497 -0
- data/doc/classes/TaskJuggler/ReportTableCell.html +518 -0
- data/doc/classes/TaskJuggler/ReportTableColumn.html +364 -0
- data/doc/classes/TaskJuggler/ReportTableElement.html +644 -0
- data/doc/classes/TaskJuggler/ReportTableLegend.html +343 -0
- data/doc/classes/TaskJuggler/ReportTableLine.html +431 -0
- data/doc/classes/TaskJuggler/Resource.html +211 -0
- data/doc/classes/TaskJuggler/ResourceListAttribute.html +267 -0
- data/doc/classes/TaskJuggler/ResourceListRE.html +249 -0
- data/doc/classes/TaskJuggler/ResourceScenario.html +1137 -0
- data/doc/classes/TaskJuggler/RichText.html +537 -0
- data/doc/classes/TaskJuggler/RichTextAttribute.html +229 -0
- data/doc/classes/TaskJuggler/RichTextDocument.html +418 -0
- data/doc/classes/TaskJuggler/RichTextElement.html +829 -0
- data/doc/classes/TaskJuggler/RichTextException.html +212 -0
- data/doc/classes/TaskJuggler/RichTextParser.html +317 -0
- data/doc/classes/TaskJuggler/RichTextProtocolExample.html +303 -0
- data/doc/classes/TaskJuggler/RichTextProtocolHandler.html +194 -0
- data/doc/classes/TaskJuggler/RichTextScanner.html +561 -0
- data/doc/classes/TaskJuggler/RichTextSnip.html +364 -0
- data/doc/classes/TaskJuggler/RichTextSyntaxRules.html +883 -0
- data/doc/classes/TaskJuggler/Scenario.html +163 -0
- data/doc/classes/TaskJuggler/ScenarioData.html +354 -0
- data/doc/classes/TaskJuggler/Scoreboard.html +638 -0
- data/doc/classes/TaskJuggler/Shift.html +255 -0
- data/doc/classes/TaskJuggler/ShiftAssignment.html +488 -0
- data/doc/classes/TaskJuggler/ShiftAssignments.html +715 -0
- data/doc/classes/TaskJuggler/ShiftAssignmentsAttribute.html +261 -0
- data/doc/classes/TaskJuggler/ShiftScenario.html +282 -0
- data/doc/classes/TaskJuggler/SourceFileInfo.html +247 -0
- data/doc/classes/TaskJuggler/StringAttribute.html +229 -0
- data/doc/classes/TaskJuggler/SymbolAttribute.html +194 -0
- data/doc/classes/TaskJuggler/SyntaxReference.html +516 -0
- data/doc/classes/TaskJuggler/TOCEntry.html +242 -0
- data/doc/classes/TaskJuggler/TableColumnDefinition.html +273 -0
- data/doc/classes/TaskJuggler/TableOfContents.html +256 -0
- data/doc/classes/TaskJuggler/Task.html +203 -0
- data/doc/classes/TaskJuggler/TaskDependency.html +251 -0
- data/doc/classes/TaskJuggler/TaskListAttribute.html +267 -0
- data/doc/classes/TaskJuggler/TaskListRE.html +250 -0
- data/doc/classes/TaskJuggler/TaskScenario.html +2206 -0
- data/doc/classes/TaskJuggler/TextParser.html +670 -0
- data/doc/classes/TaskJuggler/TextParser/Pattern.html +923 -0
- data/doc/classes/TaskJuggler/TextParser/Rule.html +779 -0
- data/doc/classes/TaskJuggler/TextParser/StackElement.html +267 -0
- data/doc/classes/TaskJuggler/TextParser/TextParserResultArray.html +212 -0
- data/doc/classes/TaskJuggler/TextParser/TokenDoc.html +221 -0
- data/doc/classes/TaskJuggler/TextScanner.html +708 -0
- data/doc/classes/TaskJuggler/TextScanner/BufferStreamHandle.html +355 -0
- data/doc/classes/TaskJuggler/TextScanner/FileStreamHandle.html +341 -0
- data/doc/classes/TaskJuggler/TextScanner/StreamHandle.html +260 -0
- data/doc/classes/TaskJuggler/TjException.html +185 -0
- data/doc/classes/TaskJuggler/TjTime.html +1845 -0
- data/doc/classes/TaskJuggler/TjpExample.html +310 -0
- data/doc/classes/TaskJuggler/TjpExportRE.html +329 -0
- data/doc/classes/TaskJuggler/TjpSyntaxRules.html +8928 -0
- data/doc/classes/TaskJuggler/UserManual.html +606 -0
- data/doc/classes/TaskJuggler/WorkingHours.html +582 -0
- data/doc/classes/TaskJuggler/WorkingHoursAttribute.html +284 -0
- data/doc/classes/TaskJuggler/XMLBlob.html +207 -0
- data/doc/classes/TaskJuggler/XMLComment.html +206 -0
- data/doc/classes/TaskJuggler/XMLDocument.html +293 -0
- data/doc/classes/TaskJuggler/XMLElement.html +341 -0
- data/doc/classes/TaskJuggler/XMLNamedText.html +174 -0
- data/doc/classes/TaskJuggler/XMLText.html +221 -0
- data/doc/files/COPYING.html +448 -0
- data/doc/files/README.html +134 -0
- data/doc/files/lib/AccountScenario_rb.html +116 -0
- data/doc/files/lib/Account_rb.html +118 -0
- data/doc/files/lib/Allocation_rb.html +118 -0
- data/doc/files/lib/AppConfig_rb.html +116 -0
- data/doc/files/lib/AttributeBase_rb.html +106 -0
- data/doc/files/lib/AttributeDefinition_rb.html +106 -0
- data/doc/files/lib/Attributes_rb.html +130 -0
- data/doc/files/lib/Booking_rb.html +106 -0
- data/doc/files/lib/ChargeSet_rb.html +116 -0
- data/doc/files/lib/Charge_rb.html +116 -0
- data/doc/files/lib/HTMLDocument_rb.html +116 -0
- data/doc/files/lib/Interval_rb.html +116 -0
- data/doc/files/lib/KeywordDocumentation_rb.html +122 -0
- data/doc/files/lib/Limits_rb.html +116 -0
- data/doc/files/lib/Log_rb.html +116 -0
- data/doc/files/lib/LogicalExpression_rb.html +122 -0
- data/doc/files/lib/LogicalFlag_rb.html +116 -0
- data/doc/files/lib/LogicalFunction_rb.html +116 -0
- data/doc/files/lib/LogicalOperation_rb.html +116 -0
- data/doc/files/lib/MacroParser_rb.html +118 -0
- data/doc/files/lib/MacroTable_rb.html +122 -0
- data/doc/files/lib/MessageHandler_rb.html +106 -0
- data/doc/files/lib/Message_rb.html +116 -0
- data/doc/files/lib/ProjectFileParser_rb.html +122 -0
- data/doc/files/lib/Project_rb.html +148 -0
- data/doc/files/lib/PropertyList_rb.html +106 -0
- data/doc/files/lib/PropertySet_rb.html +118 -0
- data/doc/files/lib/PropertyTreeNode_rb.html +106 -0
- data/doc/files/lib/Query_rb.html +116 -0
- data/doc/files/lib/RealFormat_rb.html +106 -0
- data/doc/files/lib/ResourceScenario_rb.html +116 -0
- data/doc/files/lib/Resource_rb.html +118 -0
- data/doc/files/lib/RichTextDocument_rb.html +120 -0
- data/doc/files/lib/RichTextElement_rb.html +120 -0
- data/doc/files/lib/RichTextParser_rb.html +120 -0
- data/doc/files/lib/RichTextProtocolExample_rb.html +120 -0
- data/doc/files/lib/RichTextProtocolHandler_rb.html +106 -0
- data/doc/files/lib/RichTextScanner_rb.html +116 -0
- data/doc/files/lib/RichTextSnip_rb.html +118 -0
- data/doc/files/lib/RichTextSyntaxRules_rb.html +106 -0
- data/doc/files/lib/RichText_rb.html +118 -0
- data/doc/files/lib/ScenarioData_rb.html +118 -0
- data/doc/files/lib/Scenario_rb.html +116 -0
- data/doc/files/lib/Scoreboard_rb.html +106 -0
- data/doc/files/lib/ShiftAssignments_rb.html +116 -0
- data/doc/files/lib/ShiftScenario_rb.html +116 -0
- data/doc/files/lib/Shift_rb.html +118 -0
- data/doc/files/lib/SourceFileInfo_rb.html +106 -0
- data/doc/files/lib/SyntaxReference_rb.html +122 -0
- data/doc/files/lib/TOCEntry_rb.html +118 -0
- data/doc/files/lib/TableColumnDefinition_rb.html +106 -0
- data/doc/files/lib/TableOfContents_rb.html +118 -0
- data/doc/files/lib/TaskDependency_rb.html +106 -0
- data/doc/files/lib/TaskJuggler_rb.html +120 -0
- data/doc/files/lib/TaskScenario_rb.html +116 -0
- data/doc/files/lib/Task_rb.html +118 -0
- data/doc/files/lib/TextParser/Pattern_rb.html +116 -0
- data/doc/files/lib/TextParser/Rule_rb.html +106 -0
- data/doc/files/lib/TextParser/StackElement_rb.html +106 -0
- data/doc/files/lib/TextParser/TokenDoc_rb.html +106 -0
- data/doc/files/lib/TextParser_rb.html +124 -0
- data/doc/files/lib/TextScanner_rb.html +128 -0
- data/doc/files/lib/Tj3Config_rb.html +118 -0
- data/doc/files/lib/TjException_rb.html +106 -0
- data/doc/files/lib/TjTime_rb.html +118 -0
- data/doc/files/lib/TjpExample_rb.html +116 -0
- data/doc/files/lib/TjpSyntaxRules_rb.html +106 -0
- data/doc/files/lib/UTF8String_rb.html +132 -0
- data/doc/files/lib/UserManual_rb.html +124 -0
- data/doc/files/lib/WorkingHours_rb.html +116 -0
- data/doc/files/lib/XMLDocument_rb.html +116 -0
- data/doc/files/lib/XMLElement_rb.html +116 -0
- data/doc/files/lib/reports/CSVFile_rb.html +116 -0
- data/doc/files/lib/reports/ColumnTable_rb.html +116 -0
- data/doc/files/lib/reports/GanttChart_rb.html +122 -0
- data/doc/files/lib/reports/GanttContainer_rb.html +116 -0
- data/doc/files/lib/reports/GanttHeaderScaleItem_rb.html +106 -0
- data/doc/files/lib/reports/GanttHeader_rb.html +116 -0
- data/doc/files/lib/reports/GanttLine_rb.html +126 -0
- data/doc/files/lib/reports/GanttLoadStack_rb.html +116 -0
- data/doc/files/lib/reports/GanttMilestone_rb.html +116 -0
- data/doc/files/lib/reports/GanttRouter_rb.html +106 -0
- data/doc/files/lib/reports/GanttTaskBar_rb.html +116 -0
- data/doc/files/lib/reports/HTMLGraphics_rb.html +106 -0
- data/doc/files/lib/reports/ReportElement_rb.html +118 -0
- data/doc/files/lib/reports/ReportTableCell_rb.html +106 -0
- data/doc/files/lib/reports/ReportTableColumn_rb.html +106 -0
- data/doc/files/lib/reports/ReportTableElement_rb.html +122 -0
- data/doc/files/lib/reports/ReportTableLegend_rb.html +106 -0
- data/doc/files/lib/reports/ReportTableLine_rb.html +116 -0
- data/doc/files/lib/reports/ReportTable_rb.html +118 -0
- data/doc/files/lib/reports/Report_rb.html +126 -0
- data/doc/files/lib/reports/ResourceListRE_rb.html +122 -0
- data/doc/files/lib/reports/TaskListRE_rb.html +122 -0
- data/doc/files/lib/reports/TjpExportRE_rb.html +116 -0
- data/doc/files/lib/taskjuggler3_rb.html +276 -0
- data/doc/files/lib/tj3man_rb.html +189 -0
- data/doc/fr_class_index.html +285 -0
- data/doc/fr_file_index.html +223 -0
- data/doc/fr_method_index.html +1953 -0
- data/doc/index.html +21 -0
- data/doc/rdoc-style.css +299 -0
- data/examples/tutorial.tjp +361 -0
- data/gem_spec.rb +30 -0
- data/lib/Account.rb +50 -0
- data/lib/AccountScenario.rb +39 -0
- data/lib/Allocation.rb +102 -0
- data/lib/AppConfig.rb +134 -0
- data/lib/AttributeBase.rb +131 -0
- data/lib/AttributeDefinition.rb +47 -0
- data/lib/Attributes.rb +478 -0
- data/lib/BatchProcessor.rb +209 -0
- data/lib/Booking.rb +59 -0
- data/lib/Charge.rb +71 -0
- data/lib/ChargeSet.rb +126 -0
- data/lib/HTMLDocument.rb +59 -0
- data/lib/Interval.rb +127 -0
- data/lib/KeywordDocumentation.rb +560 -0
- data/lib/Limits.rb +219 -0
- data/lib/Log.rb +160 -0
- data/lib/LogicalExpression.rb +71 -0
- data/lib/LogicalFlag.rb +34 -0
- data/lib/LogicalFunction.rb +102 -0
- data/lib/LogicalOperation.rb +118 -0
- data/lib/MacroParser.rb +77 -0
- data/lib/MacroTable.rb +84 -0
- data/lib/Message.rb +56 -0
- data/lib/MessageHandler.rb +34 -0
- data/lib/Project.rb +662 -0
- data/lib/ProjectFileParser.rb +333 -0
- data/lib/PropertyList.rb +181 -0
- data/lib/PropertySet.rb +304 -0
- data/lib/PropertyTreeNode.rb +461 -0
- data/lib/Query.rb +227 -0
- data/lib/RealFormat.rb +73 -0
- data/lib/Resource.rb +42 -0
- data/lib/ResourceScenario.rb +511 -0
- data/lib/RichText.rb +147 -0
- data/lib/RichTextDocument.rb +139 -0
- data/lib/RichTextElement.rb +391 -0
- data/lib/RichTextParser.rb +66 -0
- data/lib/RichTextProtocolExample.rb +65 -0
- data/lib/RichTextProtocolHandler.rb +35 -0
- data/lib/RichTextScanner.rb +390 -0
- data/lib/RichTextSnip.rb +104 -0
- data/lib/RichTextSyntaxRules.rb +265 -0
- data/lib/Scenario.rb +27 -0
- data/lib/ScenarioData.rb +65 -0
- data/lib/Scoreboard.rb +141 -0
- data/lib/Shift.rb +48 -0
- data/lib/ShiftAssignments.rb +291 -0
- data/lib/ShiftScenario.rb +46 -0
- data/lib/SourceFileInfo.rb +37 -0
- data/lib/SyntaxReference.rb +284 -0
- data/lib/TOCEntry.rb +76 -0
- data/lib/TableColumnDefinition.rb +54 -0
- data/lib/TableOfContents.rb +46 -0
- data/lib/Task.rb +37 -0
- data/lib/TaskDependency.rb +39 -0
- data/lib/TaskJuggler.rb +84 -0
- data/lib/TaskScenario.rb +1622 -0
- data/lib/TextParser.rb +416 -0
- data/lib/TextParser/Pattern.rb +263 -0
- data/lib/TextParser/Rule.rb +171 -0
- data/lib/TextParser/StackElement.rb +45 -0
- data/lib/TextParser/TokenDoc.rb +38 -0
- data/lib/TextScanner.rb +682 -0
- data/lib/Tj3Config.rb +27 -0
- data/lib/TjException.rb +27 -0
- data/lib/TjTime.rb +395 -0
- data/lib/TjpExample.rb +119 -0
- data/lib/TjpSyntaxRules.rb +4022 -0
- data/lib/UTF8String.rb +100 -0
- data/lib/UserManual.rb +282 -0
- data/lib/WorkingHours.rb +323 -0
- data/lib/XMLDocument.rb +54 -0
- data/lib/XMLElement.rb +175 -0
- data/lib/reports/CSVFile.rb +146 -0
- data/lib/reports/ColumnTable.rb +66 -0
- data/lib/reports/GanttChart.rb +308 -0
- data/lib/reports/GanttContainer.rb +107 -0
- data/lib/reports/GanttHeader.rb +141 -0
- data/lib/reports/GanttHeaderScaleItem.rb +42 -0
- data/lib/reports/GanttLine.rb +329 -0
- data/lib/reports/GanttLoadStack.rb +113 -0
- data/lib/reports/GanttMilestone.rb +80 -0
- data/lib/reports/GanttRouter.rb +375 -0
- data/lib/reports/GanttTaskBar.rb +95 -0
- data/lib/reports/HTMLGraphics.rb +65 -0
- data/lib/reports/Report.rb +344 -0
- data/lib/reports/ReportElement.rb +427 -0
- data/lib/reports/ReportTable.rb +144 -0
- data/lib/reports/ReportTableCell.rb +142 -0
- data/lib/reports/ReportTableColumn.rb +82 -0
- data/lib/reports/ReportTableElement.rb +852 -0
- data/lib/reports/ReportTableLegend.rb +167 -0
- data/lib/reports/ReportTableLine.rb +87 -0
- data/lib/reports/ResourceListRE.rb +72 -0
- data/lib/reports/TaskListRE.rb +73 -0
- data/lib/reports/TjpExportRE.rb +394 -0
- data/lib/taskjuggler3.rb +106 -0
- data/lib/tj3man.rb +88 -0
- data/manual/Day_To_Day_Juggling +168 -0
- data/manual/Getting_Started +61 -0
- data/manual/How_To_Contribute +185 -0
- data/manual/Installation +68 -0
- data/manual/Intro +102 -0
- data/manual/Reporting_Bugs +26 -0
- data/manual/Rich_Text_Attributes +90 -0
- data/manual/TaskJuggler_2x_Migration +40 -0
- data/manual/Tutorial +579 -0
- data/manual/fdl +450 -0
- data/prj_cfg.rb +43 -0
- data/setup.rb +1585 -0
- data/tasks/csts.rake +72 -0
- data/tasks/gem.rake +14 -0
- data/tasks/manual.rake +10 -0
- data/tasks/missing.rake +21 -0
- data/tasks/rcov.rake +14 -0
- data/tasks/rdoc.rake +17 -0
- data/tasks/rexml_fix.rb +16 -0
- data/tasks/rexml_fix_19.rb +49 -0
- data/tasks/show.rake +21 -0
- data/tasks/stats.rake +25 -0
- data/tasks/test.rake +11 -0
- data/test/MessageChecker.rb +53 -0
- data/test/TestSuite/CSV-Reports/celltext-Reference.csv +14 -0
- data/test/TestSuite/CSV-Reports/celltext.tjp +7 -0
- data/test/TestSuite/CSV-Reports/genrefs +6 -0
- data/test/TestSuite/CSV-Reports/project-1.tji +57 -0
- data/test/TestSuite/CSV-Reports/resourcereport-Reference.csv +4 -0
- data/test/TestSuite/CSV-Reports/resourcereport.tjp +10 -0
- data/test/TestSuite/CSV-Reports/resourcereport_with_tasks-Reference.csv +22 -0
- data/test/TestSuite/CSV-Reports/resourcereport_with_tasks.tjp +11 -0
- data/test/TestSuite/CSV-Reports/sortByTree-Reference.csv +14 -0
- data/test/TestSuite/CSV-Reports/sortByTree.tjp +8 -0
- data/test/TestSuite/CSV-Reports/sortBy_duration.down-Reference.csv +14 -0
- data/test/TestSuite/CSV-Reports/sortBy_duration.down.tjp +10 -0
- data/test/TestSuite/CSV-Reports/sortBy_effort.up-Reference.csv +14 -0
- data/test/TestSuite/CSV-Reports/sortBy_effort.up.tjp +10 -0
- data/test/TestSuite/CSV-Reports/sortBy_plan.start.down-Reference.csv +14 -0
- data/test/TestSuite/CSV-Reports/sortBy_plan.start.down.tjp +10 -0
- data/test/TestSuite/CSV-Reports/taskreport-Reference.csv +14 -0
- data/test/TestSuite/CSV-Reports/taskreport.tjp +10 -0
- data/test/TestSuite/CSV-Reports/taskreport_with_resources-Reference.csv +24 -0
- data/test/TestSuite/CSV-Reports/taskreport_with_resources.tjp +11 -0
- data/test/TestSuite/Scheduler/Correct/Allocate.tjp +86 -0
- data/test/TestSuite/Scheduler/Correct/AutomaticMilestones.tjp +63 -0
- data/test/TestSuite/Scheduler/Correct/Booking.tjp +161 -0
- data/test/TestSuite/Scheduler/Correct/Depends.tjp +50 -0
- data/test/TestSuite/Scheduler/Correct/Duration.tjp +34 -0
- data/test/TestSuite/Scheduler/Correct/InheritStartEnd.tjp +129 -0
- data/test/TestSuite/Scheduler/Correct/Limits.tjp +81 -0
- data/test/TestSuite/Scheduler/Correct/MultipleMandatories.tjp +43 -0
- data/test/TestSuite/Scheduler/Correct/Optimize-1.tjp +28 -0
- data/test/TestSuite/Scheduler/Correct/Optimize-2.tjp +33 -0
- data/test/TestSuite/Scheduler/Correct/Optimize-3.tjp +33 -0
- data/test/TestSuite/Scheduler/Correct/Optimize-4.tjp +34 -0
- data/test/TestSuite/Scheduler/Correct/Optimize-5.tjp +62 -0
- data/test/TestSuite/Scheduler/Correct/Precedes.tjp +50 -0
- data/test/TestSuite/Scheduler/Correct/Shift.tjp +102 -0
- data/test/TestSuite/Scheduler/Errors/account_no_leaf.tjp +13 -0
- data/test/TestSuite/Scheduler/Errors/booking_conflict.tjp +10 -0
- data/test/TestSuite/Scheduler/Errors/booking_no_duty.tjp +9 -0
- data/test/TestSuite/Scheduler/Errors/booking_on_vacation.tjp +9 -0
- data/test/TestSuite/Scheduler/Errors/container_booking.tjp +14 -0
- data/test/TestSuite/Scheduler/Errors/container_duration.tjp +11 -0
- data/test/TestSuite/Scheduler/Errors/effort_no_allocations.tjp +7 -0
- data/test/TestSuite/Scheduler/Errors/loop_detected_1.tjp +19 -0
- data/test/TestSuite/Scheduler/Errors/loop_detected_10.tjp +36 -0
- data/test/TestSuite/Scheduler/Errors/loop_detected_11.tjp +27 -0
- data/test/TestSuite/Scheduler/Errors/loop_detected_12.tjp +20 -0
- data/test/TestSuite/Scheduler/Errors/loop_detected_13.tjp +27 -0
- data/test/TestSuite/Scheduler/Errors/loop_detected_14.tjp +26 -0
- data/test/TestSuite/Scheduler/Errors/loop_detected_2.tjp +24 -0
- data/test/TestSuite/Scheduler/Errors/loop_detected_3.tjp +18 -0
- data/test/TestSuite/Scheduler/Errors/loop_detected_4.tjp +36 -0
- data/test/TestSuite/Scheduler/Errors/loop_detected_5.tjp +37 -0
- data/test/TestSuite/Scheduler/Errors/loop_detected_6.tjp +35 -0
- data/test/TestSuite/Scheduler/Errors/loop_detected_7.tjp +46 -0
- data/test/TestSuite/Scheduler/Errors/loop_detected_8.tjp +51 -0
- data/test/TestSuite/Scheduler/Errors/loop_detected_9.tjp +20 -0
- data/test/TestSuite/Scheduler/Errors/maxend.tjp +8 -0
- data/test/TestSuite/Scheduler/Errors/maxstart.tjp +8 -0
- data/test/TestSuite/Scheduler/Errors/milestone_booking.tjp +10 -0
- data/test/TestSuite/Scheduler/Errors/milestone_duration.tjp +8 -0
- data/test/TestSuite/Scheduler/Errors/milestone_start_end.tjp +8 -0
- data/test/TestSuite/Scheduler/Errors/minend.tjp +8 -0
- data/test/TestSuite/Scheduler/Errors/minstart.tjp +8 -0
- data/test/TestSuite/Scheduler/Errors/multiple_durations.tjp +11 -0
- data/test/TestSuite/Scheduler/Errors/no_tasks.tjp +6 -0
- data/test/TestSuite/Scheduler/Errors/not_scheduled.tjp +8 -0
- data/test/TestSuite/Scheduler/Errors/task_depend_child.tjp +10 -0
- data/test/TestSuite/Scheduler/Errors/task_depend_multi.tjp +13 -0
- data/test/TestSuite/Scheduler/Errors/task_depend_parent.tjp +11 -0
- data/test/TestSuite/Scheduler/Errors/task_depend_self.tjp +10 -0
- data/test/TestSuite/Scheduler/Errors/task_depend_unknown.tjp +10 -0
- data/test/TestSuite/Scheduler/Errors/task_overspecified_1.tjp +9 -0
- data/test/TestSuite/Scheduler/Errors/task_overspecified_2.tjp +14 -0
- data/test/TestSuite/Scheduler/Errors/task_overspecified_3.tjp +14 -0
- data/test/TestSuite/Scheduler/Errors/task_underspecified_1.tjp +8 -0
- data/test/TestSuite/Scheduler/Errors/task_underspecified_2.tjp +8 -0
- data/test/TestSuite/Scheduler/Errors/task_underspecified_3.tjp +9 -0
- data/test/TestSuite/Syntax/Correct/Account.tjp +53 -0
- data/test/TestSuite/Syntax/Correct/Allocate-1.tjp +24 -0
- data/test/TestSuite/Syntax/Correct/Alternative.tjp +13 -0
- data/test/TestSuite/Syntax/Correct/AutoMacros.tjp +14 -0
- data/test/TestSuite/Syntax/Correct/Booking.tjp +26 -0
- data/test/TestSuite/Syntax/Correct/Caption.tjp +33 -0
- data/test/TestSuite/Syntax/Correct/Celltext.tjp +28 -0
- data/test/TestSuite/Syntax/Correct/Comments.tjp +29 -0
- data/test/TestSuite/Syntax/Correct/Complete.tjp +16 -0
- data/test/TestSuite/Syntax/Correct/CompletedWork.tji +20 -0
- data/test/TestSuite/Syntax/Correct/CriticalPath.tjp +31 -0
- data/test/TestSuite/Syntax/Correct/Currencyformat.tjp +12 -0
- data/test/TestSuite/Syntax/Correct/CustomAttributes.tjp +14 -0
- data/test/TestSuite/Syntax/Correct/Depends1.tjp +22 -0
- data/test/TestSuite/Syntax/Correct/Durations.tjp +29 -0
- data/test/TestSuite/Syntax/Correct/Efficiency.tjp +19 -0
- data/test/TestSuite/Syntax/Correct/Export.tjp +40 -0
- data/test/TestSuite/Syntax/Correct/Flags.tjp +32 -0
- data/test/TestSuite/Syntax/Correct/Freeze.tjp +28 -0
- data/test/TestSuite/Syntax/Correct/Gap.tjp +15 -0
- data/test/TestSuite/Syntax/Correct/HtmlTaskReport.tjp +33 -0
- data/test/TestSuite/Syntax/Correct/Limits-1.tjp +71 -0
- data/test/TestSuite/Syntax/Correct/LoadUnits.tjp +31 -0
- data/test/TestSuite/Syntax/Correct/Macro-1.tjp +19 -0
- data/test/TestSuite/Syntax/Correct/Mandatory.tjp +17 -0
- data/test/TestSuite/Syntax/Correct/Milestone.tjp +12 -0
- data/test/TestSuite/Syntax/Correct/MinMax.tjp +17 -0
- data/test/TestSuite/Syntax/Correct/Numberformat.tjp +12 -0
- data/test/TestSuite/Syntax/Correct/Period.tjp +16 -0
- data/test/TestSuite/Syntax/Correct/Persistent.tjp +11 -0
- data/test/TestSuite/Syntax/Correct/Precedes1.tjp +17 -0
- data/test/TestSuite/Syntax/Correct/Priority.tjp +30 -0
- data/test/TestSuite/Syntax/Correct/Project.tjp +21 -0
- data/test/TestSuite/Syntax/Correct/ProjectIDs.tjp +23 -0
- data/test/TestSuite/Syntax/Correct/RawHTML.tjp +29 -0
- data/test/TestSuite/Syntax/Correct/Reports.tjp +54 -0
- data/test/TestSuite/Syntax/Correct/Resource.tjp +20 -0
- data/test/TestSuite/Syntax/Correct/Responsible.tjp +16 -0
- data/test/TestSuite/Syntax/Correct/Scenario.tjp +15 -0
- data/test/TestSuite/Syntax/Correct/Scheduling.tjp +26 -0
- data/test/TestSuite/Syntax/Correct/Select.tjp +27 -0
- data/test/TestSuite/Syntax/Correct/Shift.tjp +55 -0
- data/test/TestSuite/Syntax/Correct/Simple.tjp +25 -0
- data/test/TestSuite/Syntax/Correct/String.tjp +12 -0
- data/test/TestSuite/Syntax/Correct/Supplement.tjp +24 -0
- data/test/TestSuite/Syntax/Correct/TaskRoot.tjp +34 -0
- data/test/TestSuite/Syntax/Correct/TimeFrame.tjp +19 -0
- data/test/TestSuite/Syntax/Correct/Timezone.tjp +8 -0
- data/test/TestSuite/Syntax/Correct/Vacation.tjp +33 -0
- data/test/TestSuite/Syntax/Correct/csvtest +16 -0
- data/test/TestSuite/Syntax/Correct/manual2example.rb +24 -0
- data/test/TestSuite/Syntax/Correct/tutorial.tjp +485 -0
- data/test/TestSuite/Syntax/Errors/bad_include.tjp +11 -0
- data/test/TestSuite/Syntax/Errors/booking_group.tjp +14 -0
- data/test/TestSuite/Syntax/Errors/booking_milestone.tjp +13 -0
- data/test/TestSuite/Syntax/Errors/booking_no_leaf.tjp +13 -0
- data/test/TestSuite/Syntax/Errors/chargeset.tjp +14 -0
- data/test/TestSuite/Syntax/Errors/chargeset_master.tjp +15 -0
- data/test/TestSuite/Syntax/Errors/container_attribute.tjp +13 -0
- data/test/TestSuite/Syntax/Errors/cost_acct_no_top.tjp +24 -0
- data/test/TestSuite/Syntax/Errors/cost_rev_same.tjp +24 -0
- data/test/TestSuite/Syntax/Errors/date_in_range.tjp +7 -0
- data/test/TestSuite/Syntax/Errors/effort_zero.tjp +8 -0
- data/test/TestSuite/Syntax/Errors/empty.tjp +1 -0
- data/test/TestSuite/Syntax/Errors/export_bad_extn.tjp +9 -0
- data/test/TestSuite/Syntax/Errors/extend_id_cap.tjp +7 -0
- data/test/TestSuite/Syntax/Errors/interval_end_in_range.tjp +7 -0
- data/test/TestSuite/Syntax/Errors/interval_start_in_range.tjp +7 -0
- data/test/TestSuite/Syntax/Errors/leaf_resource_id_expected.tjp +12 -0
- data/test/TestSuite/Syntax/Errors/misaligned_date.tjp +7 -0
- data/test/TestSuite/Syntax/Errors/no_csv_suffix.tjp +10 -0
- data/test/TestSuite/Syntax/Errors/no_html_suffix.tjp +10 -0
- data/test/TestSuite/Syntax/Errors/operand_attribute.tjp +11 -0
- data/test/TestSuite/Syntax/Errors/operand_unkn_flag.tjp +11 -0
- data/test/TestSuite/Syntax/Errors/operand_unkn_scen.tjp +11 -0
- data/test/TestSuite/Syntax/Errors/overtime_range.tjp +13 -0
- data/test/TestSuite/Syntax/Errors/purge_no_list.tjp +8 -0
- data/test/TestSuite/Syntax/Errors/purge_unknown_id.tjp +8 -0
- data/test/TestSuite/Syntax/Errors/report_end.tjp +10 -0
- data/test/TestSuite/Syntax/Errors/report_redifinition.tjp +10 -0
- data/test/TestSuite/Syntax/Errors/report_start.tjp +10 -0
- data/test/TestSuite/Syntax/Errors/resource_exists.tjp +7 -0
- data/test/TestSuite/Syntax/Errors/resource_id_expected.tjp +8 -0
- data/test/TestSuite/Syntax/Errors/rev_acct_no_top.tjp +24 -0
- data/test/TestSuite/Syntax/Errors/scenario_exists.tjp +7 -0
- data/test/TestSuite/Syntax/Errors/shift_assignment_overlap.tjp +15 -0
- data/test/TestSuite/Syntax/Errors/shift_exists.tjp +7 -0
- data/test/TestSuite/Syntax/Errors/shift_id_expected.tjp +7 -0
- data/test/TestSuite/Syntax/Errors/sloppy_range.tjp +13 -0
- data/test/TestSuite/Syntax/Errors/sort_direction.tjp +11 -0
- data/test/TestSuite/Syntax/Errors/sort_unknown_scen.tjp +11 -0
- data/test/TestSuite/Syntax/Errors/sorting_crit_exptd1.tjp +11 -0
- data/test/TestSuite/Syntax/Errors/sorting_crit_exptd2.tjp +11 -0
- data/test/TestSuite/Syntax/Errors/sorting_wbs.tjp +11 -0
- data/test/TestSuite/Syntax/Errors/start_before_end1.tjp +7 -0
- data/test/TestSuite/Syntax/Errors/start_before_end2.tjp +6 -0
- data/test/TestSuite/Syntax/Errors/task_complete.tjp +8 -0
- data/test/TestSuite/Syntax/Errors/task_exists.tjp +7 -0
- data/test/TestSuite/Syntax/Errors/task_priority.tjp +8 -0
- data/test/TestSuite/Syntax/Errors/task_without_chargeset.tjp +9 -0
- data/test/TestSuite/Syntax/Errors/time_interval.tjp +12 -0
- data/test/TestSuite/Syntax/Errors/too_many_bangs.tjp +10 -0
- data/test/TestSuite/Syntax/Errors/undecl_flag.tjp +6 -0
- data/test/TestSuite/Syntax/Errors/unknown_projectid.tjp +7 -0
- data/test/TestSuite/Syntax/Errors/unknown_scenario_id.tjp +6 -0
- data/test/TestSuite/Syntax/Errors/unknown_scenario_idx.tjp +11 -0
- data/test/TestSuite/Syntax/Errors/unknown_task.tjp +10 -0
- data/test/all.rb +31 -0
- data/test/test_BatchProcessor.rb +54 -0
- data/test/test_CSV-Reports.rb +101 -0
- data/test/test_Limits.rb +104 -0
- data/test/test_LogicalExpression.rb +110 -0
- data/test/test_MacroTable.rb +51 -0
- data/test/test_Project.rb +57 -0
- data/test/test_PropertySet.rb +71 -0
- data/test/test_Query.rb +83 -0
- data/test/test_RealFormat.rb +83 -0
- data/test/test_RichText.rb +869 -0
- data/test/test_Scheduler.rb +42 -0
- data/test/test_ShiftAssignments.rb +77 -0
- data/test/test_Syntax.rb +41 -0
- data/test/test_TextScanner.rb +95 -0
- data/test/test_TjTime.rb +114 -0
- data/test/test_TjpExample.rb +169 -0
- data/test/test_UTF8String.rb +84 -0
- data/test/test_WorkingHours.rb +56 -0
- metadata +649 -0
data/lib/TjpExample.rb
ADDED
@@ -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
|
+
|