This module contains the rule definition for the TJP syntax. Every rule is put in a function who’s name must start with rule_. The functions are not necessary but make the file more readable and receptable to syntax folding.
# File lib/taskjuggler/TjpSyntaxRules.rb, line 21 21: def rule_absoluteTaskId 22: pattern(%( !taskIdUnverifd ), lambda { 23: id = (@taskprefix.empty? ? '' : @taskprefix + '.') + @val[0] 24: if (task = @project.task(id)).nil? 25: error('unknown_abs_task', "Unknown task #{id}", @sourceFileInfo[0]) 26: end 27: task 28: }) 29: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 31 31: def rule_account 32: pattern(%( !accountHeader !accountBody ), lambda { 33: @property = @property.parent 34: }) 35: doc('account', Declares an account. Accounts can be used to calculate costs of tasks or thewhole project. Account declaration may be nested, but only leaf accounts maybe used to track turnover. When the cost of a task is split over multipleaccounts they all must have the same top-level group account. Top-levelaccounts can be used for profit/loss calculations. The sub-account structureof a top-level account should be organized accordingly.Accounts have a global name space. All IDs must be unique within the accounts of the project. 36: ) 37: example('Account', '1') 38: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 49 49: def rule_accountAttributes 50: repeatable 51: optional 52: pattern(%( !account)) 53: pattern(%( !accountScenarioAttributes )) 54: pattern(%( !scenarioIdCol !accountScenarioAttributes ), lambda { 55: @scenarioIdx = 0 56: }) 57: # Other attributes will be added automatically. 58: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 60 60: def rule_accountBody 61: optionsRule('accountAttributes') 62: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 64 64: def rule_accountHeader 65: pattern(%( _account !optionalID $STRING ), lambda { 66: if @property.nil? && !@accountprefix.empty? 67: @property = @project.accout(@accountprefix) 68: end 69: if @val[1] && @project.account(@val[1]) 70: error('account_exists', "Account #{@val[1]} has already been defined.", 71: @sourceFileInfo[1], @property) 72: end 73: @property = Account.new(@project, @val[1], @val[2], @property) 74: @property.sourceFileInfo = @sourceFileInfo[0] 75: @property.inheritAttributes 76: @scenarioIdx = 0 77: }) 78: arg(2, 'name', 'A name or short description of the account') 79: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 81 81: def rule_accountId 82: pattern(%( $ID ), lambda { 83: id = @val[0] 84: id = @accountprefix + '.' + id unless @accountprefix.empty? 85: # In case we have a nested supplement, we need to prepend the parent ID. 86: id = @property.fullId + '.' + id if @property && @property.is_a?(Account) 87: if (account = @project.account(id)).nil? 88: error('unknown_account', "Unknown account #{id}", @sourceFileInfo[0]) 89: end 90: account 91: }) 92: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 94 94: def rule_accountScenarioAttributes 95: pattern(%( _credit !valDate $STRING !number ), lambda { 96: #@property['credit', @scenarioIdx] += 97: # AccountCredit.new(@val[1], @val[2], @val[3]) 98: }) 99: doc('credit', Book the specified amount to the account at the specified date. 100: ) 101: example('Account', '1') 102: arg(2, 'description', 'Short description of the transaction') 103: arg(3, 'amount', 'Amount to be booked.') 104: 105: pattern(%( !flags )) 106: doc('flags.account', Attach a set of flags. The flags can be used in logical expressions to filterproperties from the reports. 107: ) 108: 109: # Other attributes will be added automatically. 110: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 117 117: def rule_alertLevel 118: pattern(%( $ID ), lambda { 119: level = @project.alertLevelIndex(@val[0]) 120: unless level 121: error('bad_alert', "Unknown alert level #{@val[1]}. Must be " + 122: 'green, yellow or red', @sourceFileInfo[0]) 123: end 124: level 125: }) 126: doc('alert level', Specify the alert level for this entry. Supported values are green, yellow andred. The default value is green. This attribute is inteded to be used forstatus reporting. When used for a journal entry that is associated with aproperty, the value can be reported in the alert column. When multiple entrieshave been specified for the property, the entry with the date closest to thereport end date will be used. Container properties will inherit the highestalert level of all its sub properties unless it has an own journal entry datedcloser to the report end than all of its sub properties. 127: ) 128: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 139 139: def rule_allocate 140: pattern(%( _allocate !allocations ), lambda { 141: checkContainer('allocate') 142: # Don't use << operator here so the 'provided' flag gets set properly. 143: begin 144: @property['allocate', @scenarioIdx] = 145: @property['allocate', @scenarioIdx] + @val[1] 146: rescue AttributeOverwrite 147: # Adding multiple allocates for a task is a pretty common idiom. 148: end 149: }) 150: doc('allocate', Specify which resources should be allocated to the task. Theattributes provide numerous ways to control which resource is used and whenexactly it will be assigned to the task. Shifts and limits can be used torestrict the allocation to certain time intervals or to limit them to acertain maximum per time period. The purge statement can be used to removeinherited allocations or flags. 151: ) 152: example('Allocate-1', '1') 153: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 162 162: def rule_allocation 163: pattern(%( !allocationHeader !allocationBody ), lambda { 164: @val[0] 165: }) 166: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 168 168: def rule_allocationAttributes 169: optional 170: repeatable 171: 172: pattern(%( _alternative !resourceId !moreAlternatives ), lambda { 173: ([ @val[1] ] + (@val[2] ? @val[2] : [])).each do |candidate| 174: @allocate.addCandidate(candidate) 175: end 176: }) 177: doc('alternative', Specify which resources should be allocated to the task. The optionalattributes provide numerous ways to control which resource is used and whenexactly it will be assigned to the task. Shifts and limits can be used torestrict the allocation to certain time intervals or to limit them to acertain maximum per time period. 178: ) 179: example('Alternative', '1') 180: 181: pattern(%( !limits ), lambda { 182: limits = @property['limits', @scenarioIdx] = @val[0] 183: @allocate.candidates.each do |resource| 184: limits.limits.each do |l| 185: l.resource = resource if resource.leaf? 186: end 187: end 188: }) 189: doc('limits.allocate', 'This keyword is deprecated. Don\t use it anymore!') 190: 191: pattern(%( _select !allocationSelectionMode ), lambda { 192: @allocate.setSelectionMode(@val[1]) 193: }) 194: doc('select', The select functions controls which resource is picked from an allocation andit's alternatives. The selection is re-evaluated each time the resource usedin the previous time slot becomes unavailable.Even for non-persistent allocations a change in the resource selection onlyhappens if the resource used in the previous (or next for ASAP tasks) timeslot has become unavailable. 195: ) 196: 197: pattern(%( _persistent ), lambda { 198: @allocate.persistent = true 199: }) 200: doc('persistent', Specifies that once a resource is picked from the list of alternatives thisresource is used for the whole task. This is useful when several alternativeresources have been specified. Normally the selected resource can change aftereach break. A break is an interval of at least one timeslot where no resourceswere available. 201: ) 202: 203: pattern(%( _mandatory ), lambda { 204: @allocate.mandatory = true 205: }) 206: doc('mandatory', Makes a resource allocation mandatory. This means, that for each time slotonly then resources are allocated when all mandatory resources are available.So either all mandatory resources can be allocated for the time slot, or noresource will be allocated. 207: ) 208: pattern(%( _shift !allocationShiftAssignment )) 209: doc('shifts.allocate', Limits the allocations of resources during the specified interval to thespecified shift. Multiple shifts can be defined, but shift intervals may notoverlap. Allocation shifts are an additional restriction to the[[shifts.task|task shifts]] and [[shifts.resource|resource shifts]] or[[workinghours.resource|resource working hours]]. Allocations will only bemade for time slots that are specified as duty time in all relevant shifts.The restriction to the shift is only active during the specified timeinterval. Outside of this interval, no restrictions apply. 210: ) 211: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 247 247: def rule_allocationBody 248: optionsRule('allocationAttributes') 249: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 251 251: def rule_allocationHeader 252: pattern(%( !resourceId ), lambda { 253: @allocate = Allocation.new([ @val[0] ]) 254: }) 255: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 261 261: def rule_allocationSelectionMode 262: singlePattern('_maxloaded') 263: descr('Pick the available resource that has been used the most so far.') 264: 265: singlePattern('_minloaded') 266: descr('Pick the available resource that has been used the least so far.') 267: 268: singlePattern('_minallocated') 269: descr(Pick the resource that has the smallest allocation factor. Theallocation factor is calculated from the various allocations of the resourceacross the tasks. This is the default setting.) 270: ) 271: 272: singlePattern('_order') 273: descr('Pick the first available resource from the list.') 274: 275: singlePattern('_random') 276: descr('Pick a random resource from the list.') 277: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 283 283: def rule_allocationShiftAssignment 284: pattern(%( !shiftId !intervalsOptional ), lambda { 285: # Make sure we have a ShiftAssignment for the allocation. 286: if @allocate.shifts.nil? 287: @allocate.shifts = ShiftAssignments.new 288: @allocate.shifts.project = @project 289: end 290: 291: if @val[1].nil? 292: intervals = [ Interval.new(@project['start'], @project['end']) ] 293: else 294: intervals = @val[1] 295: end 296: intervals.each do |interval| 297: if !@allocate.shifts. 298: addAssignment(ShiftAssignment.new(@val[0].scenario(@scenarioIdx), 299: interval)) 300: error('shift_assignment_overlap', 301: 'Shifts may not overlap each other.', @sourceFileInfo[0]) 302: end 303: end 304: }) 305: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 257 257: def rule_allocations 258: listRule('moreAllocations', '!allocation') 259: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 307 307: def rule_argument 308: singlePattern('$ABSOLUTE_ID') 309: singlePattern('!date') 310: singlePattern('$ID') 311: singlePattern('$INTEGER') 312: singlePattern('$FLOAT') 313: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 315 315: def rule_argumentList 316: optional 317: pattern(%( _( !argumentListBody _) ), lambda { 318: @val[1].nil? ? [] : @val[1] 319: }) 320: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 322 322: def rule_argumentListBody 323: optional 324: pattern(%( !argument !moreArguments ), lambda { 325: [ @val[0] ] + (@val[1].nil? ? [] : @val[1]) 326: }) 327: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 340 340: def rule_balance 341: pattern(%( _balance !accountId !accountId ), lambda { 342: if @val[1].parent 343: error('cost_acct_no_top', 344: "The cost account #{@val[1].fullId} is not a top-level account.", 345: @sourceFileInfo[1]) 346: end 347: if @val[2].parent 348: error('rev_acct_no_top', 349: "The revenue account #{@val[2].fullId} is not a top-level " + 350: "account.", @sourceFileInfo[2]) 351: end 352: if @val[1] == @val[2] 353: error('cost_rev_same', 354: 'The cost and revenue accounts may not be the same.', 355: @sourceFileInfo[1]) 356: end 357: [ @val[1], @val[2] ] 358: }) 359: doc('balance', 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. 360: ) 361: arg(1, 'cost account', The top-level account that is used for all cost related charges. 362: ) 363: arg(2, 'revenue account', The top-level account that is used for all revenue related charges. 364: ) 365: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 373 373: def rule_bookingAttributes 374: optional 375: repeatable 376: 377: pattern(%( _overtime $INTEGER ), lambda { 378: if @val[1] < 0 || @val[1] > 2 379: error('overtime_range', 380: "Overtime value #{@val[1]} out of range (0 - 2).", 381: @sourceFileInfo[1], @property) 382: end 383: @booking.overtime = @val[1] 384: }) 385: doc('overtime.booking', This attribute enables bookings during off-hours and vacations. It implicitlysets the [[sloppy.booking|sloppy]] attribute accordingly. 386: ) 387: arg(1, 'value', * '''0''': You can only book available working time. (Default)* '''1''': You can book off-hours as well.* '''2''': You can book working time, off-hours and vacation time. 388: ) 389: 390: pattern(%( _sloppy $INTEGER ), lambda { 391: if @val[1] < 0 || @val[1] > 2 392: error('sloppy_range', 393: "Sloppyness value #{@val[1]} out of range (0 - 2).", 394: @sourceFileInfo[1], @property) 395: end 396: @booking.sloppy = @val[1] 397: }) 398: doc('sloppy.booking', Controls how strict TaskJuggler checks booking intervals for conflicts withworking periods and vacations. This attribute only affects the check forconflicts. No assignments will be made unless the [[overtime.booking|overtime]] attribute is set accordingly. 399: ) 400: arg(1, 'sloppyness', * '''0''': Period may not contain any off-duty hours, vacation or other taskassignments. (default)* '''1''': Period may contain off-duty hours, but no vacation time or othertask assignments.* '''2''': Period may contain off-duty hours and vacation time, but no othertask assignments. 401: ) 402: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 427 427: def rule_bookingBody 428: optionsRule('bookingAttributes') 429: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 431 431: def rule_calendarDuration 432: pattern(%( !number !durationUnit ), lambda { 433: convFactors = [ 60.0, # minutes 434: 60.0 * 60, # hours 435: 60.0 * 60 * 24, # days 436: 60.0 * 60 * 24 * 7, # weeks 437: 60.0 * 60 * 24 * 30.4167, # months 438: 60.0 * 60 * 24 * 365 # years 439: ] 440: ((@val[0] * convFactors[@val[1]]) / @project['scheduleGranularity']).to_i 441: }) 442: arg(0, 'value', 'A floating point or integer number') 443: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 484 484: def rule_chargeMode 485: singlePattern('_onstart') 486: descr('Charge the amount on starting the task.') 487: 488: singlePattern('_onend') 489: descr('Charge the amount on finishing the task.') 490: 491: singlePattern('_perhour') 492: descr('Charge the amount for every hour the task lasts.') 493: 494: singlePattern('_perday') 495: descr('Charge the amount for every day the task lasts.') 496: 497: singlePattern('_perweek') 498: descr('Charge the amount for every week the task lasts.') 499: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 501 501: def rule_chargeSetItem 502: pattern(%( !accountId !optionalPercent ), lambda { 503: [ @val[0], @val[1] ] 504: }) 505: arg(0, 'account', 'The ID of a previously defined leaf account.') 506: arg(1, 'share', 'A percentage between 0 and 100%') 507: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 445 445: def rule_chargeset 446: pattern(%( _chargeset !chargeSetItem !moreChargeSetItems ), lambda { 447: checkContainer('chargeset') 448: items = [ @val[1] ] 449: items += @val[2] if @val[2] 450: chargeSet = ChargeSet.new 451: begin 452: items.each do |item| 453: chargeSet.addAccount(item[0], item[1]) 454: end 455: chargeSet.complete 456: rescue TjException 457: error('chargeset', $!.message, @sourceFileInfo[0], @property) 458: end 459: masterAccounts = [] 460: @property['chargeset', @scenarioIdx].each do |set| 461: masterAccounts << set.master 462: end 463: if masterAccounts.include?(chargeSet.master) 464: error('chargeset_master', 465: "All charge sets for this task must have different top-level " + 466: "accounts.", @sourceFileInfo[0], @property) 467: end 468: @property['chargeset', @scenarioIdx] = 469: @property['chargeset', @scenarioIdx] + [ chargeSet ] 470: }) 471: doc('chargeset', A chargeset defines how the turnover associated with the task will be chargedto one or more accounts. A task may have any number of charge sets, but eachchargeset must deal with a different top-level account. A charge set consistsof one or more accounts. Each account must be a leaf account. The account IDmay be followed by a percentage value that determines the share for thisaccount. The total percentage of all accounts must be exactly 100%. If someaccounts don't have a percentage specification, the remainder to 100% isdistributed evenly to them. 472: ) 473: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 509 509: def rule_chartScale 510: singlePattern('_hour') 511: descr('Set chart resolution to 1 hour.') 512: 513: singlePattern('_day') 514: descr('Set chart resolution to 1 day.') 515: 516: singlePattern('_week') 517: descr('Set chart resolution to 1 week.') 518: 519: singlePattern('_month') 520: descr('Set chart resolution to 1 month.') 521: 522: singlePattern('_quarter') 523: descr('Set chart resolution to 1 quarter.') 524: 525: singlePattern('_year') 526: descr('Set chart resolution to 1 year.') 527: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 529 529: def rule_color 530: pattern(%( $STRING ), lambda { 531: col = @val[0] 532: unless /#[0-9A-Fa-f]{3}/ =~ col || /#[0-9A-Fa-f]{3}/ =~ col 533: error('bad_color', 534: "Color values must be specified as '#RGB' or '#RRGGBB' values", 535: @sourceFileInfo[0]) 536: end 537: col 538: }) 539: arg(0, 'color', The RGB color values of the color. The following formats are supported: #RGBand #RRGGBB. Where R, G, B are hexadecimal values. See[http://en.wikipedia.org/wiki/Web_colors Wikipedia] for more details. 540: ) 541: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 547 547: def rule_columnBody 548: optionsRule('columnOptions') 549: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 551 551: def rule_columnDef 552: pattern(%( !columnId !columnBody ), lambda { 553: @val[0] 554: }) 555: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 557 557: def rule_columnId 558: pattern(%( !reportableAttributes ), lambda { 559: title = TableReport.defaultColumnTitle(@val[0]) || 560: @project.attributeName(@val[0]) 561: @column = TableColumnDefinition.new(@val[0], title) 562: }) 563: doc('columnid', This is a comprehensive list of all pre-defined [[columns]]. In addition tothe listed IDs all user defined attributes can be used as column IDs. 564: ) 565: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 570 570: def rule_columnOptions 571: optional 572: repeatable 573: 574: pattern(%( _celltext !logicalExpression $STRING ), lambda { 575: @column.cellText.addPattern( 576: CellSettingPattern.new(newRichText(@val[2], @sourceFileInfo[2]), 577: @val[1])) 578: }) 579: doc('celltext.column', Specifies an alternative content that is used for the cells of the column.Usually such a text contains a query function. Otherwise all cells of thecolumn will have the same fixed value. The logical expression specifies forwhich cells the text should be used. If multiple celltext patterns areprovided for a column, the first matching one is taken for each cell. 580: ) 581: arg(1, 'text', 582: 'Alterntive cell text specified as [[Rich_Text_Attributes|Rich Text]]') 583: 584: pattern(%( _cellcolor !logicalExpression !color ), lambda { 585: @column.cellColor.addPattern( 586: CellSettingPattern.new(@val[2], @val[1])) 587: }) 588: doc('cellcolor.column', Specifies an alternative background color for the cells of this column. Thelogical expression specifies for which cells the color should be used. Ifmultiple cellcolor patterns are provided for a column, the firstmatching one is used for each cell. 589: ) 590: 591: pattern(%( _end !date ), lambda { 592: @column.end = @val[1] 593: }) 594: doc('end.column', Normally, columns with calculated values take the specified report period intoaccount when calculating their values. With this attribute, the user canspecify an end date for the period that should be used when calculating thevalues of this column. It does not have an impact on column with timeinvariant values. 595: ) 596: 597: pattern(%( _fontcolor !logicalExpression !color ), lambda { 598: @column.fontColor.addPattern( 599: CellSettingPattern.new(@val[2], @val[1])) 600: }) 601: doc('fontcolor.column', Specifies an alternative font color for the cells of this column. Thelogical expression specifies for which cells the color should be used. Ifmultiple fontcolor patterns are provided for a column, the firstmatching one is used for each cell. 602: ) 603: 604: pattern(%( _halign !logicalExpression !hAlignment ), lambda { 605: @column.hAlign.addPattern( 606: CellSettingPattern.new(@val[2], @val[1])) 607: }) 608: doc('halign.column', Specifies the horizontal alignment of the cell content. The logical expressionspecifies for which cells the alignment setting should be used. If multiplehalign patterns are provided for a column, the first matching one is used foreach cell. 609: ) 610: 611: pattern(%( _listitem $STRING ), lambda { 612: @column.listItem = @val[1] 613: }) 614: doc('listitem.column', Specifies a RichText pattern that is used to generate the text for the listitems. The pattern should contain at least one ''''<nowiki><</nowiki>-queryattribute='XXX'->'''' element that will be replaced with the value ofattribute XXX. For the replacement, the property of the query will be the listitem. 615: ) 616: 617: pattern(%( _listtype !listType ), lambda { 618: @column.listType = @val[1] 619: }) 620: also(%( listitem.column )) 621: doc('listtype.column', Specifies what type of list should be used. This attribute only affectscolumns that contain a list of items. 622: ) 623: 624: pattern(%( _period !interval ), lambda { 625: @column.start = @val[1].start 626: @column.end = @val[1].end 627: }) 628: doc('period.column', This property is a shortcut for setting the [[start.column|start]] and[[end.column|end]] property at the same time. 629: ) 630: 631: pattern(%( _scale !chartScale ), lambda { 632: @column.scale = @val[1] 633: }) 634: doc('scale.column', Specifies the scale that should be used for a chart column. This value is ignored for all other columns. 635: ) 636: 637: pattern(%( _start !date ), lambda { 638: @column.start = @val[1] 639: }) 640: doc('start.column', Normally, columns with calculated values take the specified report period intoaccount when calculating their values. With this attribute, the user canspecify a start date for the period that should be used when calculating thevalues of this column. It does not have an impact on column with timeinvariant values. 641: ) 642: 643: pattern(%( _title $STRING ), lambda { 644: @column.title = @val[1] 645: }) 646: doc('title.column', Specifies an alternative title for a report column. 647: ) 648: arg(1, 'text', 'The new column title.') 649: 650: pattern(%( _tooltip !logicalExpression $STRING ), lambda { 651: @column.tooltip.addPattern( 652: CellSettingPattern.new(newRichText(@val[2], @sourceFileInfo[2]), 653: @val[1])) 654: }) 655: doc('tooltip.column', Specifies an alternative content for the tooltip. This will replace theoriginal content of the tooltip that would be available for columns with textthat does not fit the column with. The logical expression specifies for whichcells the text should be used. If multiple tooltip patterns are provided for acolumn, the first matching one is taken for each cell. 656: ) 657: arg(2, 'text', The content of the tooltip. The text is interpreted as [[Rich_Text_Attributes|Rich Text]]. 658: ) 659: 660: pattern(%( _width !number ), lambda { 661: @column.width = @val[1] 662: }) 663: doc('width.column', Specifies the width of the column in screen pixels. If the content of thecolumn does not fit into this width, it will be cut off. In some cases ascrollbar is added or a tooltip window with the complete content is shown whenthe mouse is moved over the column. The latter is only supported ininteractive output formats. 664: ) 665: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 731 731: def rule_currencyFormat 732: pattern(%( _currencyformat $STRING $STRING $STRING $STRING $INTEGER ), 733: lambda { 734: RealFormat.new(@val.slice(1, 5)) 735: }) 736: doc('currencyformat', 737: 'These values specify the default format used for all currency ' + 738: 'values.') 739: example('Currencyformat') 740: arg(1, 'negativeprefix', 'Prefix for negative numbers') 741: arg(2, 'negativesuffix', 'Suffix for negative numbers') 742: arg(3, 'thousandsep', 'Separator used for every 3rd digit') 743: arg(4, 'fractionsep', 'Separator used to separate the fraction digits') 744: arg(5, 'fractiondigits', 'Number of fraction digits to show') 745: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 747 747: def rule_date 748: pattern(%( !dateCalcedOrNot ), lambda { 749: resolution = @project.nil? ? Project.maxScheduleGranularity : 750: @project['scheduleGranularity'] 751: if @val[0] % resolution != 0 752: error('misaligned_date', 753: "The date must be aligned to the timing resolution (" + 754: "#{resolution / 60} min) of the project.", 755: @sourceFileInfo[0]) 756: end 757: @val[0] 758: }) 759: doc('date', A DATE is an ISO-compliant date in the format''''<nowiki>YYYY-MM-DD[-hh:mm[:ss]][-TIMEZONE]</nowiki>''''. Hour, minutes,seconds, and the ''''TIMEZONE'''' are optional. If not specified, the valuesare set to 0. ''''TIMEZONE'''' must be an offset to GMT or UTC, specified as''''+HHMM'''' or ''''-HHMM''''. Dates must always be aligned with the[[timingresolution]].TaskJuggler also supports simple date calculations. You can add or substract agiven interval from a fixed date. %{2009-11-01 + 8m}This will result in an actual date of around 2009-07-01. Keep in mind that due to the varying lengths of months TaskJuggler cannot add exactly 8 calendar months. The date calculation functionality makes most sense when used with macros. %{${now} - 2w}This is result in a date 2 weeks earlier than the current (or specified) date.See [[duration]] for a complete list of supported time intervals. Don't forgetto put at least one space character after the date to prevent TaskJuggler frominterpreting the interval as an hour. 760: ) 761: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 784 784: def rule_dateCalcedOrNot 785: singlePattern('$DATE') 786: pattern(%( _% _{ $DATE !plusOrMinus !intervalDuration _} ), lambda { 787: @val[2] + ((@val[3] == '+' ? 1 : 1) * @val[4]) 788: }) 789: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 791 791: def rule_declareFlagList 792: listRule('moreDeclareFlagList', '$ID') 793: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 795 795: def rule_details 796: pattern(%( _details $STRING ), lambda { 797: return if @val[1].empty? 798: 799: rtTokenSetMore = 800: [ :LINEBREAK, :SPACE, :WORD, :BOLD, :ITALIC, :CODE, :BOLDITALIC, 801: :PRE, :HREF, :HREFEND, :REF, :REFEND, :HLINE, :TITLE2, :TITLE3, 802: :TITLE4, :TITLE2END, :TITLE3END, :TITLE4END, 803: :BULLET1, :BULLET2, :BULLET3, :BULLET4, :NUMBER1, :NUMBER2, :NUMBER3, 804: :NUMBER4 ] 805: if @val[1] == "Some more details\n" 806: error('ts_default_details', 807: "'Some more details' is not a valid value", 808: @sourceFileInfo[1]) 809: end 810: @journalEntry.details = newRichText(@val[1], @sourceFileInfo[1], 811: rtTokenSetMore) 812: }) 813: doc('details', This is a continuation of the [[summary]] of the journal or status entry. Itcan be several paragraphs long. 814: ) 815: arg(1, 'text', The text will be interpreted as [[Rich_Text_Attributes|Rich Text]]. Only asubset of the markup is supported for this attribute. You can use wordformatting, paragraphs, hyperlinks, lists, section and subsectionheaders. 816: ) 817: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 827 827: def rule_durationUnit 828: pattern(%( _min ), lambda { 0 }) 829: descr('minutes') 830: 831: pattern(%( _h ), lambda { 1 }) 832: descr('hours') 833: 834: pattern(%( _d ), lambda { 2 }) 835: descr('days') 836: 837: pattern(%( _w ), lambda { 3 }) 838: descr('weeks') 839: 840: pattern(%( _m ), lambda { 4 }) 841: descr('months') 842: 843: pattern(%( _y ), lambda { 5 }) 844: descr('years') 845: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 847 847: def rule_durationUnitOrPercent 848: pattern(%( _% ), lambda { 1 }) 849: descr('percentage of reported period') 850: 851: pattern(%( _min ), lambda { 0 }) 852: descr('minutes') 853: 854: pattern(%( _h ), lambda { 1 }) 855: descr('hours') 856: 857: pattern(%( _d ), lambda { 2 }) 858: descr('days') 859: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 861 861: def rule_export 862: pattern(%( !exportHeader !exportBody ), lambda { 863: @property = nil 864: }) 865: doc('export', The export report looks like a regular TaskJuggler file with the providedinput data complemented by the results of the scheduling process. The contentof the report can be controlled with the [[definitions]] attribute. In casethe file contains the project header, a ''''.tjp'''' extension is added to thefile name. Otherwise, a ''''.tji'''' extension is used.The [[resourceattributes]] and [[taskattributes]] attributes provide even morecontrol over the content of the file.The export report can be used to share certain tasks or milestones with otherprojects or to save past resource allocations as immutable part for futurescheduling runs. When an export report is included the project IDs of theincluded tasks must be declared first with the project id property. 866: ) 867: example('Export') 868: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 907 907: def rule_exportAttributes 908: optional 909: repeatable 910: 911: pattern(%( _definitions !exportDefinitions ), lambda { 912: @property.set('definitions', @val[1]) 913: }) 914: doc('definitions', This attributes controls what definitions will be contained in the report. Ifthe list includes ''project'', the generated file will have a ''''.tjp''''extension. Otherwise it will have a ''''.tji'''' extension.By default, the report contains everything and the generated files has a ''''.tjp'''' extension. 915: ) 916: allOrNothingListRule('exportDefinitions', 917: { 'flags' => 'Include flag definitions', 918: 'project' => 'Include project header', 919: 'projecids' => 'Include project IDs', 920: 'tasks' => 'Include task definitions', 921: 'resources' => 'Include resource definitions' }) 922: pattern(%( !hideresource )) 923: pattern(%( !hidetask )) 924: pattern(%( !reportEnd )) 925: pattern(%( !reportPeriod )) 926: pattern(%( !reportStart )) 927: 928: pattern(%( _resourceattributes !exportableResourceAttributes ), lambda { 929: @property.set('resourceAttributes', @val[1]) 930: }) 931: doc('resourceattributes', Define a list of resource attributes that should be included in the report. 932: ) 933: allOrNothingListRule('exportableResourceAttributes', 934: { 'vacation' => 'Include vacations', 935: 'workinghours' => 'Include working hours' }) 936: 937: pattern(%( !rollupresource )) 938: pattern(%( !rolluptask )) 939: 940: pattern(%( _scenarios !scenarioIdList ), lambda { 941: # Don't include disabled scenarios in the report 942: @val[1].delete_if { |sc| !@project.scenario(sc).get('active') } 943: @property.set('scenarios', @val[1]) 944: }) 945: doc('scenarios.export', List of scenarios that should be included in the report. By default, allscenarios will be included. This attribute can be used to limit the includedscenarios to a defined list. 946: ) 947: 948: pattern(%( _taskattributes !exportableTaskAttributes ), lambda { 949: @property.set('taskAttributes', @val[1]) 950: }) 951: doc('taskattributes', Define a list of task attributes that should be included in the report. 952: ) 953: allOrNothingListRule('exportableTaskAttributes', 954: { 'booking' => 'Include bookings', 955: 'complete' => 'Include completion values', 956: 'depends' => 'Include dependencies', 957: 'flags' => 'Include flags', 958: 'maxend' => 'Include maximum end dates', 959: 'maxstart' => 'Include maximum start dates', 960: 'minend' => 'Include minimum end dates', 961: 'minstart' => 'Include minimum start dates', 962: 'note' => 'Include notes', 963: 'priority' => 'Include priorities', 964: 'responsible' => 'Include responsible resource' }) 965: 966: pattern(%( _timezone !validTimeZone ), lambda { 967: @property.set('timezone', @val[1]) 968: }) 969: doc('timezone.export', 970: "Set the time zone to be used for all dates in the report.") 971: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 987 987: def rule_exportBody 988: optionsRule('exportAttributes') 989: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 884 884: def rule_exportHeader 885: pattern(%( _export !optionalID $STRING ), lambda { 886: report = newReport(@val[1], @val[2], :export, sourceFileInfo) 887: 888: # By default, we export all scenarios. 889: scenarios = Array.new(@project.scenarios.items) { |i| i } 890: scenarios.delete_if { |sc| !@project.scenario(sc).get('active') } 891: report.set('scenarios', scenarios) 892: # Show all tasks, sorted by seqno-up. 893: report.set('hideTask', LogicalExpression.new(LogicalOperation.new(0))) 894: report.set('sortTasks', [ [ 'seqno', true, 1 ] ]) 895: # Show all resources, sorted by seqno-up. 896: report.set('hideResource', 897: LogicalExpression.new(LogicalOperation.new(0))) 898: report.set('sortResources', [ [ 'seqno', true, 1 ] ]) 899: }) 900: arg(1, 'file name', The name of the report file to generate. It must end with a .tjp or .tjiextension, or use . to use the standard output channel. 901: ) 902: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 991 991: def rule_extendAttributes 992: optional 993: repeatable 994: 995: pattern(%( _date !extendId $STRING !extendOptionsBody ), lambda { 996: # Extend the propertySet definition and parser rules 997: if extendPropertySetDefinition(DateAttribute, nil) 998: @ruleToExtendWithScenario.addPattern(TextParser::Pattern.new( 999: [ '_' + @val[1], '!date' ], lambda { 1000: @property[@val[0], @scenarioIdx] = @val[1] 1001: })) 1002: else 1003: @ruleToExtend.addPattern(TextParser::Pattern.new( 1004: [ '_' + @val[1], '!date' ], lambda { 1005: @property.set(@val[0], @val[1]) 1006: })) 1007: end 1008: }) 1009: doc('date.extend', Extend the property with a new attribute of type date. 1010: ) 1011: arg(2, 'name', 'The name of the new attribute. It is used as header ' + 1012: 'in report columns and the like.') 1013: 1014: pattern(%( _reference !extendId $STRING !extendOptionsBody ), lambda { 1015: # Extend the propertySet definition and parser rules 1016: if extendPropertySetDefinition(ReferenceAttribute, nil) 1017: @ruleToExtendWithScenario.addPattern(TextParser::Pattern.new( 1018: [ '_' + @val[1], '$STRING', '!referenceBody' ], lambda { 1019: @property[@val[0], @scenarioIdx] = [ @val[1], @val[2] ] 1020: })) 1021: else 1022: @ruleToExtend.addPattern(TextParser::Pattern.new( 1023: [ '_' + @val[1], '$STRING', '!referenceBody' ], lambda { 1024: @property.set(@val[0], [ @val[1], @val[2] ]) 1025: })) 1026: end 1027: }) 1028: doc('reference.extend', Extend the property with a new attribute of type reference. A reference is aURL and an optional text that will be shown instead of the URL if needed. 1029: ) 1030: arg(2, 'name', 'The name of the new attribute. It is used as header ' + 1031: 'in report columns and the like.') 1032: 1033: pattern(%( _richtext !extendId $STRING !extendOptionsBody ), lambda { 1034: # Extend the propertySet definition and parser rules 1035: if extendPropertySetDefinition(RichTextAttribute, nil) 1036: @ruleToExtendWithScenario.addPattern(TextParser::Pattern.new( 1037: [ '_' + @val[1], '$STRING' ], lambda { 1038: @property[@val[0], @scenarioIdx] = 1039: newRichText(@val[1], @sourceFileInfo[1]) 1040: })) 1041: else 1042: @ruleToExtend.addPattern(TextParser::Pattern.new( 1043: [ '_' + @val[1], '$STRING' ], lambda { 1044: @property.set(@val[0], newRichText(@val[1], @sourceFileInfo[1])) 1045: })) 1046: end 1047: }) 1048: doc('richtext.extend', Extend the property with a new attribute of type [[Rich_Text_Attributes|RichText]]. 1049: ) 1050: arg(2, 'name', 'The name of the new attribute. It is used as header ' + 1051: 'in report columns and the like.') 1052: 1053: pattern(%( _text !extendId $STRING !extendOptionsBody ), lambda { 1054: # Extend the propertySet definition and parser rules 1055: if extendPropertySetDefinition(StringAttribute, nil) 1056: @ruleToExtendWithScenario.addPattern(TextParser::Pattern.new( 1057: [ '_' + @val[1], '$STRING' ], lambda { 1058: @property[@val[0], @scenarioIdx] = @val[1] 1059: })) 1060: else 1061: @ruleToExtend.addPattern(TextParser::Pattern.new( 1062: [ '_' + @val[1], '$STRING' ], lambda { 1063: @property.set(@val[0], @val[1]) 1064: })) 1065: end 1066: }) 1067: doc('text.extend', Extend the property with a new attribute of type text. A text is a charactersequence enclosed in single or double quotes. 1068: ) 1069: arg(2, 'name', 'The name of the new attribute. It is used as header ' + 1070: 'in report columns and the like.') 1071: 1072: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 1085 1085: def rule_extendBody 1086: optionsRule('extendAttributes') 1087: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 1089 1089: def rule_extendId 1090: pattern(%( $ID ), lambda { 1091: unless (AA..ZZ) === @val[0][0] 1092: error('extend_id_cap', 1093: "User defined attributes IDs must start with a capital letter", 1094: @sourceFileInfo[0]) 1095: end 1096: @val[0] 1097: }) 1098: arg(0, 'id', 'The ID of the new attribute. It can be used like the ' + 1099: 'built-in IDs.') 1100: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 1102 1102: def rule_extendOptions 1103: optional 1104: repeatable 1105: 1106: singlePattern('_inherit') 1107: doc('inherit.extend', If the this attribute is used, the property extension will be inherited bychild properties from their parent property. 1108: ) 1109: 1110: singlePattern('_scenariospecific') 1111: doc('scenariospecific.extend', If this attribute is used, the property extension is scenario specific. Adifferent value can be set for each scenario. 1112: ) 1113: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 1121 1121: def rule_extendOptionsBody 1122: optionsRule('extendOptions') 1123: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 1125 1125: def rule_extendProperty 1126: pattern(%( !extendPropertyId ), lambda { 1127: case @val[0] 1128: when 'task' 1129: @ruleToExtend = @rules[:taskAttributes] 1130: @ruleToExtendWithScenario = @rules[:taskScenarioAttributes] 1131: @propertySet = @project.tasks 1132: when 'resource' 1133: @ruleToExtend = @rules[:resourceAttributes] 1134: @ruleToExtendWithScenario = @rules[:resourceScenarioAttributes] 1135: @propertySet = @project.resources 1136: end 1137: }) 1138: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 1140 1140: def rule_extendPropertyId 1141: singlePattern('_task') 1142: singlePattern('_resource') 1143: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 1145 1145: def rule_fail 1146: pattern(%( _fail !logicalExpression ), lambda { 1147: begin 1148: @property.set('fail', @property.get('fail') + [ @val[1] ]) 1149: rescue AttributeOverwrite 1150: end 1151: }) 1152: doc('fail', The fail attribute adds a logical expression to the property. The conditiondescribed by the logical expression is checked after the scheduling and anerror is raised if the condition evaluates to true. This attribute isprimarily intended for testing purposes. 1153: ) 1154: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 1161 1161: def rule_flag 1162: pattern(%( $ID ), lambda { 1163: unless @project['flags'].include?(@val[0]) 1164: error('undecl_flag', "Undeclared flag '#{@val[0]}'", 1165: @sourceFileInfo[0]) 1166: end 1167: @val[0] 1168: }) 1169: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 1279 1279: def rule_flagList 1280: listRule('moreFlagList', '!flag') 1281: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 1171 1171: def rule_flagLogicalExpression 1172: pattern(%( !flagOperation ), lambda { 1173: LogicalExpression.new(@val[0], sourceFileInfo) 1174: }) 1175: doc('logicalflagexpression', A logical flag expression is a combination of operands and mathematicaloperations. The final result of a logical expression is always true or false.Logical expressions are used the reduce the properties in a report to acertain subset or to select alternatives for the cell content of a table. Whenused with attributes like [[hidejournalentry]] the logical expressionevaluates to true for a certain property, this property is hidden or rolled-upin the report.Operands must be previously declared flags or another logical expression.When you combine logical operations to a more complex expression, theoperators are evaluated from left to right. '''a | b & c''' is identical to'''(a | b) & c'''. It's highly recommended that you always use brackets tocontrol the evaluation sequence. Currently, TaskJuggler does not support theconcept of operator precedence or right-left associativity. This may change inthe future. 1176: ) 1177: also(%( functions )) 1178: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 1196 1196: def rule_flagOperand 1197: pattern(%( _( !flagOperation _) ), lambda { 1198: @val[1] 1199: }) 1200: pattern(%( _~ !flagOperand ), lambda { 1201: operation = LogicalOperation.new(@val[1]) 1202: operation.operator = '~' 1203: operation 1204: }) 1205: 1206: pattern(%( $ID ), lambda { 1207: unless @project['flags'].include?(@val[0]) 1208: error('operand_unkn_flag', "Undeclared flag '#{@val[0]}'", 1209: @sourceFileInfo[0]) 1210: end 1211: LogicalFlag.new(@val[0]) 1212: }) 1213: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 1215 1215: def rule_flagOperation 1216: pattern(%( !flagOperand !flagOperationChain ), lambda { 1217: operation = LogicalOperation.new(@val[0]) 1218: if @val[1] 1219: # Further operators/operands create an operation tree. 1220: @val[1].each do |ops| 1221: operation = LogicalOperation.new(operation) 1222: operation.operator = ops[0] 1223: operation.operand2 = ops[1] 1224: end 1225: end 1226: operation 1227: }) 1228: arg(0, 'operand', An operand is a declared flag. An operand can be a negated operand byprefixing a ~ charater or it can be another logical expression enclosed inbraces. 1229: ) 1230: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 1236 1236: def rule_flagOperationChain 1237: optional 1238: repeatable 1239: pattern(%( !flagOperatorAndOperand), lambda { 1240: @val[0] 1241: }) 1242: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 1256 1256: def rule_flagOperator 1257: singlePattern('_|') 1258: descr('The \or\ operator') 1259: 1260: singlePattern('_&') 1261: descr('The \and\ operator') 1262: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 1244 1244: def rule_flagOperatorAndOperand 1245: pattern(%( !flagOperator !flagOperand), lambda{ 1246: [ @val[0], @val[1] ] 1247: }) 1248: arg(1, 'operand', An operand is a declared flag. An operand can be a negated operand byprefixing a ~ charater or it can be another logical expression enclosed inbraces. 1249: ) 1250: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 1265 1265: def rule_flags 1266: pattern(%( _flags !flagList ), lambda { 1267: @val[1].each do |flag| 1268: next if @property['flags', @scenarioIdx].include?(flag) 1269: 1270: # We allow multiple instances of flag definitions. 1271: begin 1272: @property['flags', @scenarioIdx] << flag 1273: rescue AttributeOverwrite 1274: end 1275: end 1276: }) 1277: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 1283 1283: def rule_formats 1284: pattern(%( _formats !outputFormats ), lambda { 1285: @property.set('formats', @val[1]) 1286: }) 1287: doc('formats', This attribute defines for which output formats the report should begenerated. By default, this list is empty. Unless a formats attribute wasadded to a report definition, no output will be generated for this report.As reports are composable, a report may include other report definitions. Aformat definition is only needed for the outermost report that includes theothers. 1288: ) 1289: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 1344 1344: def rule_functionPatterns 1345: # This rule is not used by the parser. It's only for the documentation. 1346: pattern(%( _hasalert _( $INTEGER _, !date _) )) 1347: doc('hasalert', Will evaluate to true if the current property has a current alert message within the report time frame and with at least the provided alert level. 1348: ) 1349: arg(2, 'Level', 'The minimum required alert level to be considered.') 1350: 1351: pattern(%( _isactive _( $ID _) )) 1352: doc('isactive', Will evaluate to true for tasks and resources if they have bookings inthe scenario during the report time frame. 1353: ) 1354: arg(2, 'ID', 'A scenario ID') 1355: 1356: pattern(%( _ischildof _( $ID _) )) 1357: doc('ischildof', Will evaluate to true for tasks and resources if current property is a childof the provided parent property. 1358: ) 1359: arg(2, 'ID', 'The ID of the parent') 1360: 1361: pattern(%( _isdependencyof _( $ID _, $ID _, $INTEGER _) )) 1362: doc('isdependencyof', Will evaluate to true for tasks that depend on the specified task inthe specified scenario and are no more than distance tasks away. Ifdistance is 0, all dependencies are considered independent of theirdistance. 1363: ) 1364: arg(2, 'Task ID', 'The ID of a defined task') 1365: arg(4, 'Scenario ID', 'A scenario ID') 1366: arg(6, 'Distance', 'The maximum task distance to be considered') 1367: 1368: pattern(%( _isdutyof _( $ID _, $ID _) )) 1369: doc('isdutyof', Will evaluate to true for tasks that have the specified resourceassigned to it in the specified scenario. 1370: ) 1371: arg(2, 'Resource ID', 'The ID of a defined resource') 1372: arg(4, 'Scenario ID', 'A scenario ID') 1373: 1374: pattern(%( _isfeatureof _( $ID _, $ID _) )) 1375: doc('isfeatureof', If the provided task or any of its sub-tasks depend on this task or any of itssub-tasks, we call this task a feature of the provided task. 1376: ) 1377: arg(2, 'Task ID', 'The ID of a defined task') 1378: arg(4, 'Scenario ID', 'A scenario ID') 1379: 1380: pattern(['_isleaf', '_(', '_)' ]) 1381: doc('isleaf', 'The result is true if the property is not a container.') 1382: 1383: pattern(%( _ismilestone _( $ID _) )) 1384: doc('ismilestone', The result is true if the property is a milestone in the provided scenario. 1385: ) 1386: arg(2, 'Scenario ID', 'A scenario ID') 1387: 1388: pattern(%( _isongoing _( $ID _) )) 1389: doc('isongoing', Will evaluate to true for tasks that overlap with the report period in givenscenario. 1390: ) 1391: arg(2, 'ID', 'A scenario ID') 1392: 1393: pattern(['_isresource', '_(', '_)' ]) 1394: doc('isresource', 'The result is true if the property is a resource.') 1395: 1396: pattern(['_istask', '_(', '_)' ]) 1397: doc('istask', 'The result is true if the property is a task.') 1398: 1399: pattern(%( _treelevel _( _) )) 1400: doc('treelevel', Returns the nesting level of a property in the property tree.Top level properties have a level of 1, their children 2 and so on. 1401: ) 1402: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 1299 1299: def rule_functions 1300: # This rule is not used by the parser. It's only for the documentation. 1301: pattern(%( !functionsBody )) 1302: doc('functions', The following functions are supported in logical expressions. These functionsare evaluated in logical conditions such as hidetask or rollupresource. Forthe evaluation, implicit and explicit parameters are used.All functions may operate on the current property and the scope property. Thescope property is the enclosing property in reports with nested properties.Imagine e. g a task report with nested resources. When the function is calledfor a task line, the task is the property and we don't have a scope property.When the function is called for a resource line, the resource is the propertyand the enclosing task is the scope property.These number of arguments that are passed in brackets to the function dependson the specific function. See the reference for details on each function.All functions can be suffixed with an underscore character. In that case, thefunction is operating on the scope property as if it were the property. Theoriginal property is ignored in that case. In our task report example fromabove, calling a function with an appended dash would mean that a taskline would be evaluated for the enclosing resource.In the example below you can see how this can be used. To generate a taskreport that lists all assigned leaf resources for leaf task lines only we usethe expression hideresource ~(isleaf() & isleaf_())The tilde in front of the bracketed expression means not that expression. Inother words: show resources that are leaf resources and show them for leaftasks only. The regular form isleaf() (without the appended underscore)operates on the resource. The isleaf_() variant operates on theenclosing task. 1303: ) 1304: example('LogicalFunction', '1') 1305: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 1339 1339: def rule_functionsBody 1340: # This rule is not used by the parser. It's only for the documentation. 1341: optionsRule('functionPatterns') 1342: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 1431 1431: def rule_hAlignment 1432: pattern(%( _center ), lambda { 1433: :center 1434: }) 1435: doc('halign.center', 'Center the cell content') 1436: 1437: pattern(%( _left ), lambda { 1438: :left 1439: }) 1440: doc('halign.left', 'Left align the cell content') 1441: 1442: pattern(%( _right ), lambda { 1443: :right 1444: }) 1445: doc('halign.right', 'Right align the cell content') 1446: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 1448 1448: def rule_headline 1449: pattern(%( _headline $STRING ), lambda { 1450: @property.set('headline', newRichText(@val[1], @sourceFileInfo[1])) 1451: }) 1452: doc('headline', Specifies the headline for a report. 1453: ) 1454: arg(1, 'text', The text used for the headline. It is interpreted as[[Rich_Text_Attributes|Rich Text]]. 1455: ) 1456: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 1463 1463: def rule_hidejournalentry 1464: pattern(%( _hidejournalentry !flagLogicalExpression ), lambda { 1465: @property.set('hideJournalEntry', @val[1]) 1466: }) 1467: doc('hidejournalentry', Do not include journal entries that match the specified logical expression. 1468: ) 1469: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 1473 1473: def rule_hideresource 1474: pattern(%( _hideresource !logicalExpression ), lambda { 1475: @property.set('hideResource', @val[1]) 1476: }) 1477: doc('hideresource', Do not include resources that match the specified logical expression. If thereport is sorted in ''''tree'''' mode (default) then enclosing resources arelisted even if the expression matches the resource. 1478: ) 1479: also(%( sortresources )) 1480: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 1486 1486: def rule_hidetask 1487: pattern(%( _hidetask !logicalExpression ), lambda { 1488: @property.set('hideTask', @val[1]) 1489: }) 1490: doc('hidetask', Do not include tasks that match the specified logical expression. If thereport is sorted in ''''tree'''' mode (default) then enclosing tasks arelisted even if the expression matches the task. 1491: ) 1492: also(%( sorttasks )) 1493: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 1499 1499: def rule_idOrAbsoluteId 1500: singlePattern('$ID') 1501: singlePattern('$ABSOLUTE_ID') 1502: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 1504 1504: def rule_includeAttributes 1505: optionsRule('includeAttributesBody') 1506: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 1508 1508: def rule_includeAttributesBody 1509: optional 1510: repeatable 1511: 1512: pattern(%( _accountprefix !accountId ), lambda { 1513: @accountprefix = @val[1].fullId 1514: }) 1515: doc('accountprefix', This attribute can be used to insert the accounts of the included file assub-account of the account specified by ID. The parent account must already bedefined. 1516: ) 1517: arg(1, 'account ID', 'The absolute ID of an already defined account') 1518: 1519: pattern(%( _reportprefix !reportId ), lambda { 1520: @reportprefix = @val[1].fullId 1521: }) 1522: doc('reportprefix', This attribute can be used to insert the reports of the included file assub-report of the report specified by ID. The parent report must alreadybe defined. 1523: ) 1524: arg(1, 'report ID', 'The absolute ID of an already defined report.') 1525: 1526: pattern(%( _resourceprefix !resourceId ), lambda { 1527: @resourceprefix = @val[1].fullId 1528: }) 1529: doc('resourceprefix', This attribute can be used to insert the resources of the included file assub-resource of the resource specified by ID. The parent resource must alreadybe defined. 1530: ) 1531: arg(1, 'resource ID', 'The ID of an already defined resource') 1532: 1533: pattern(%( _taskprefix !taskId ), lambda { 1534: @taskprefix = @val[1].fullId 1535: }) 1536: doc('taskprefix', This attribute can be used to insert the tasks of the included file assub-task of the task specified by ID. The parent task must already be defined. 1537: ) 1538: arg(1, 'task ID', 'The absolute ID of an already defined task.') 1539: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 1556 1556: def rule_includeFile 1557: pattern(%( !includeFileName ), lambda { 1558: unless @project 1559: error('include_before_project', 1560: "You must declare the project header before you include other " + 1561: "files.") 1562: end 1563: @project.inputFiles << @scanner.include(@val[0], @sourceFileInfo[0]) do 1564: popFileStack 1565: end 1566: }) 1567: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 1569 1569: def rule_includeFileName 1570: pattern(%( $STRING ), lambda { 1571: unless @val[0][4, 4] == '.tji' 1572: error('bad_include_suffix', "Included files must have a '.tji'" + 1573: "extension: '#{@val[0]}'", 1574: @sourceFileInfo[0]) 1575: end 1576: pushFileStack 1577: @val[0] 1578: }) 1579: arg(0, 'filename', Name of the file to include. This must have a ''''.tji'''' extension. The namemay have an absolute or relative path. You need to use ''''/'''' characters toseparate directories. 1580: ) 1581: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 1587 1587: def rule_includeProperties 1588: pattern(%( !includeFileName !includeAttributes ), lambda { 1589: @project.inputFiles << @scanner.include(@val[0], @sourceFileInfo[0]) do 1590: popFileStack 1591: end 1592: }) 1593: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 1627 1627: def rule_interval 1628: pattern(%( !date !intervalEnd ), lambda { 1629: mode = @val[1][0] 1630: endSpec = @val[1][1] 1631: if mode == 0 1632: unless @val[0] < endSpec 1633: error('start_before_end', "The end date (#{endSpec}) must be after " + 1634: "the start date (#{@val[0]}).", @sourceFileInfo[0]) 1635: end 1636: Interval.new(@val[0], endSpec) 1637: else 1638: Interval.new(@val[0], @val[0] + endSpec) 1639: end 1640: }) 1641: doc('interval2', There are two ways to specify a date interval. The first is the mostobvious. A date interval consists of a start and end DATE. Watch out for enddates without a time specification! Date specifications are 0 extended. Anend date without a time is expanded to midnight that day. So the day of theend date is not included in the interval! The start and end dates must be separated by a hyphen character.In the second form specifies the start date and an interval duration. Theduration must be prefixed by a plus character. 1642: ) 1643: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 1654 1654: def rule_intervalDuration 1655: pattern(%( !number !durationUnit ), lambda { 1656: convFactors = [ 60, # minutes 1657: 60 * 60, # hours 1658: 60 * 60 * 24, # days 1659: 60 * 60 * 24 * 7, # weeks 1660: 60 * 60 * 24 * 30.4167, # months 1661: 60 * 60 * 24 * 365 # years 1662: ] 1663: if @val[0] == 0.0 1664: error('zero_duration', "The interval duration may not be 0.", 1665: @sourceFileInfo[1]) 1666: end 1667: duration = @val[0] * convFactors[@val[1]] 1668: resolution = @project.nil? ? 60 * 60 : @project['scheduleGranularity'] 1669: # Make sure the interval aligns with the timing resolution. 1670: (duration / resolution).to_i * resolution 1671: }) 1672: arg(0, 'duration', 'The duration of the interval. May not be 0.') 1673: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 1675 1675: def rule_intervalEnd 1676: pattern([ '_-', '!date' ], lambda { 1677: [ 0, @val[1] ] 1678: }) 1679: 1680: pattern(%( _+ !intervalDuration ), lambda { 1681: [ 1, @val[1] ] 1682: }) 1683: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 1685 1685: def rule_intervalOptionalEnd 1686: optional 1687: pattern([ '_-', '!date' ], lambda { 1688: [ 0, @val[1] ] 1689: }) 1690: 1691: pattern(%( _+ !intervalDuration ), lambda { 1692: [ 1, @val[1] ] 1693: }) 1694: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 1595 1595: def rule_intervalOrDate 1596: pattern(%( !date !intervalOptionalEnd ), lambda { 1597: if @val[1] 1598: mode = @val[1][0] 1599: endSpec = @val[1][1] 1600: if mode == 0 1601: unless @val[0] < endSpec 1602: error('start_before_end', "The end date (#{endSpec}) must be " + 1603: "after the start date (#{@val[0]}).", @sourceFileInfo[0]) 1604: end 1605: Interval.new(@val[0], endSpec) 1606: else 1607: Interval.new(@val[0], @val[0] + endSpec) 1608: end 1609: else 1610: Interval.new(@val[0], @val[0].sameTimeNextDay) 1611: end 1612: }) 1613: doc('interval3', There are three ways to specify a date interval. The first is the mostobvious. A date interval consists of a start and end DATE. Watch out for enddates without a time specification! Date specifications are 0 extended. Anend date without a time is expanded to midnight that day. So the day of theend date is not included in the interval! The start and end dates must be separated by a hyphen character.In the second form, the end date is omitted. A 24 hour interval is assumed.The third form specifies the start date and an interval duration. The duration must be prefixed by a plus character. 1614: ) 1615: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 1696 1696: def rule_intervals 1697: listRule('moreIntervals', '!intervalOrDate') 1698: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 1700 1700: def rule_intervalsOptional 1701: optional 1702: singlePattern('!intervals') 1703: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 1705 1705: def rule_journalEntry 1706: pattern(%( !journalEntryHeader !journalEntryBody ), lambda { 1707: @val[0] 1708: }) 1709: doc('journalentry', This attribute adds an entry to the journal of the project. A journal can beused to record events, decisions or news that happened at a particular momentduring the project. Depending on the context, a journal entry may or may notbe associated with a specific property or author.A journal entry can consists of up to three parts. The headline is mandatoryand should be only 5 to 10 words long. The introduction is optional and shouldbe only one or two sentences long. All other details should be put into thethird part.Depending on the context, journal entries are listed with headlines only, asheadlines plus introduction or in full. 1710: ) 1711: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 1726 1726: def rule_journalEntryAttributes 1727: optional 1728: repeatable 1729: 1730: pattern(%( _alert $ID ), lambda { 1731: level = @project.alertLevelIndex(@val[1]) 1732: unless level 1733: error('bad_alert', "Unknown alert level #{@val[1]}. Must be " + 1734: 'green, yellow or red', @sourceFileInfo[0]) 1735: end 1736: @journalEntry.alertLevel = level 1737: }) 1738: doc('alert', Specify the alert level for this entry. Supported values are green, yellow andred. The default value is green. This attribute is inteded to be used forstatus reporting. When used for a journal entry that is associated with aproperty, the value can be reported in the alert column. When multiple entrieshave been specified for the property, the entry with the date closest to thereport end date will be used. Container properties will inherit the highestalert level of all its sub properties unless it has an own journal entry datedcloser to the report end than all of its sub properties. 1739: ) 1740: 1741: pattern(%( !author )) 1742: 1743: pattern(%( _flags !flagList ), lambda { 1744: @val[1].each do |flag| 1745: next if @journalEntry.flags.include?(flag) 1746: 1747: @journalEntry.flags << flag 1748: end 1749: }) 1750: doc('flags.journalentry', Journal entries can have flags attached to them. These can be used toinclude only entries in a report that have a certain flag. 1751: ) 1752: 1753: pattern(%( !summary )) 1754: 1755: pattern(%( !details )) 1756: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 1770 1770: def rule_journalEntryBody 1771: optionsRule('journalEntryAttributes') 1772: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 1774 1774: def rule_journalEntryHeader 1775: pattern(%( _journalentry !valDate $STRING ), lambda { 1776: @journalEntry = JournalEntry.new(@project['journal'], @val[1], @val[2], 1777: @property, @sourceFileInfo[0]) 1778: }) 1779: arg(2, 'headline', The headline of the journal entry. It will be interpreted as[[Rich_Text_Attributes|Rich Text]]. 1780: ) 1781: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 1785 1785: def rule_leafResourceId 1786: pattern(%( !resourceId ), lambda { 1787: resource = @val[0] 1788: unless resource.leaf? 1789: error('leaf_resource_id_expected', 1790: "#{resource.id} is not a leaf resource.", @sourceFileInfo[0]) 1791: end 1792: resource 1793: }) 1794: arg(0, 'resource', 'The ID of a leaf resource') 1795: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 1797 1797: def rule_limitAttributes 1798: optionsRule('limitAttributesBody') 1799: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 1801 1801: def rule_limitAttributesBody 1802: optional 1803: repeatable 1804: 1805: pattern(%( _end !valDate ), lambda { 1806: @limitInterval.end = @val[1] 1807: }) 1808: doc('end.limit', The end date of the limit interval. It must be within the project time frame. 1809: ) 1810: 1811: pattern(%( _period !valInterval ), lambda { 1812: @limitInterval = @val[1] 1813: }) 1814: doc('period.limit', This property is a shortcut for setting the start and end dates of the limitinterval. Both dates must be within the project time frame. 1815: ) 1816: 1817: pattern(%( _resources !resourceLeafList ), lambda { 1818: @limitResources = @val[1] 1819: }) 1820: doc('resources.limit', When [[limits]] are used in a [[task]] context, the limits can be restrictedto a list of resources that are allocated to the task. In that case eachlisted resource will not be allocated more than the specified upper limit.Lower limits have no impact on the scheduler but do generate a warning whennot met. All specified resources must be leaf resources. 1821: ) 1822: example('Limits-1', '5') 1823: 1824: pattern(%( _start !valDate ), lambda { 1825: @limitInterval.start = @val[1] 1826: }) 1827: doc('start.limit', The start date of the limit interval. It must be within the project time frame. 1828: ) 1829: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 1844 1844: def rule_limitValue 1845: pattern([ '!workingDuration' ], lambda { 1846: @limitInterval = Interval.new(@project['start'], @project['end']) 1847: @limitResources = [] 1848: @val[0] 1849: }) 1850: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 1852 1852: def rule_limits 1853: pattern(%( !limitsHeader !limitsBody ), lambda { 1854: @val[0] 1855: }) 1856: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 1858 1858: def rule_limitsAttributes 1859: optional 1860: repeatable 1861: 1862: pattern(%( _dailymax !limitValue !limitAttributes), lambda { 1863: setLimit(@val[0], @val[1], @limitInterval) 1864: }) 1865: doc('dailymax', Set a maximum limit for each calendar day. 1866: ) 1867: example('Limits-1', '1') 1868: 1869: pattern(%( _dailymin !limitValue !limitAttributes), lambda { 1870: setLimit(@val[0], @val[1], @limitInterval) 1871: }) 1872: doc('dailymin', Minimum required effort for any calendar day. This value cannot be guaranteed bythe scheduler. It is only checked after the schedule is complete. In case theminium required amount has not been reached, a warning will be generated. 1873: ) 1874: example('Limits-1', '4') 1875: 1876: pattern(%( _maximum !limitValue !limitAttributes), lambda { 1877: setLimit(@val[0], @val[1], @limitInterval) 1878: }) 1879: doc('maximum', Set a maximum limit for the specified period. You must ensure that the overalleffort can be achieved! 1880: ) 1881: 1882: pattern(%( _minimum !limitValue !limitAttributes), lambda { 1883: setLimit(@val[0], @val[1], @limitInterval) 1884: }) 1885: doc('minimum', Set a minim limit for each calendar month. This will only result in a warningif not met. 1886: ) 1887: 1888: pattern(%( _monthlymax !limitValue !limitAttributes), lambda { 1889: setLimit(@val[0], @val[1], @limitInterval) 1890: }) 1891: doc('monthlymax', Set a maximum limit for each calendar month. 1892: ) 1893: 1894: pattern(%( _monthlymin !limitValue !limitAttributes), lambda { 1895: setLimit(@val[0], @val[1], @limitInterval) 1896: }) 1897: doc('monthlymin', Minimum required effort for any calendar month. This value cannot beguaranteed by the scheduler. It is only checked after the schedule iscomplete. In case the minium required amount has not been reached, a warningwill be generated. 1898: ) 1899: 1900: pattern(%( _weeklymax !limitValue !limitAttributes), lambda { 1901: setLimit(@val[0], @val[1], @limitInterval) 1902: }) 1903: doc('weeklymax', Set a maximum limit for each calendar week. 1904: ) 1905: 1906: pattern(%( _weeklymin !limitValue !limitAttributes), lambda { 1907: setLimit(@val[0], @val[1], @limitInterval) 1908: }) 1909: doc('weeklymin', Minimum required effort for any calendar week. This value cannot be guaranteed bythe scheduler. It is only checked after the schedule is complete. In case theminium required amount has not been reached, a warning will be generated. 1910: ) 1911: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 1938 1938: def rule_limitsBody 1939: optionsRule('limitsAttributes') 1940: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 1942 1942: def rule_limitsHeader 1943: pattern(%( _limits ), lambda { 1944: @limits = Limits.new 1945: @limits.setProject(@project) 1946: @limits 1947: }) 1948: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 1950 1950: def rule_listOfDays 1951: pattern(%( !weekDayInterval !moreListOfDays), lambda { 1952: weekDays = Array.new(7, false) 1953: ([ @val[0] ] + (@val[1] ? @val[1] : [])).each do |dayList| 1954: 7.times { |i| weekDays[i] = true if dayList[i] } 1955: end 1956: weekDays 1957: }) 1958: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 1960 1960: def rule_listOfTimes 1961: pattern(%( _off ), lambda { 1962: [ ] 1963: }) 1964: pattern(%( !timeInterval !moreTimeIntervals ), lambda { 1965: [ @val[0] ] + (@val[1].nil? ? [] : @val[1]) 1966: }) 1967: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 1969 1969: def rule_listType 1970: pattern([ '_bullets' ], lambda { :bullets }) 1971: descr('List items as bullet list') 1972: 1973: pattern([ '_comma' ], lambda { :comma }) 1974: descr('List items as comma separated list') 1975: 1976: pattern([ '_numbered' ], lambda { :numbered }) 1977: descr('List items as numbered list') 1978: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 1980 1980: def rule_loadunit 1981: pattern([ '_days' ], lambda { :days }) 1982: descr('Display all load and duration values as days.') 1983: 1984: pattern([ '_hours' ], lambda { :hours }) 1985: descr('Display all load and duration values as hours.') 1986: 1987: pattern([ '_longauto'] , lambda { :longauto }) 1988: descr(Automatically select the unit that produces the shortest and most readablevalue. The unit name will not be abbreviated. 1989: ) 1990: 1991: pattern([ '_minutes' ], lambda { :minutes }) 1992: descr('Display all load and duration values as minutes.') 1993: 1994: pattern([ '_months' ], lambda { :months }) 1995: descr('Display all load and duration values as monts.') 1996: 1997: pattern([ '_shortauto' ], lambda { :shortauto }) 1998: descr(Automatically select the unit that produces the shortest and most readablevalue. The unit name will be abbreviated. 1999: ) 2000: 2001: pattern([ '_weeks' ], lambda { :weeks }) 2002: descr('Display all load and duration values as weeks.') 2003: 2004: pattern([ '_years' ], lambda { :years }) 2005: descr('Display all load and duration values as years.') 2006: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 2014 2014: def rule_logicalExpression 2015: pattern(%( !operation ), lambda { 2016: LogicalExpression.new(@val[0], sourceFileInfo) 2017: }) 2018: doc('logicalexpression', A logical expression is a combination of operands and mathematical operations.The final result of a logical expression is always true or false. Logicalexpressions are used the reduce the properties in a report to a certain subsetor to select alternatives for the cell content of a table. When used withattributes like [[hidetask]] or [[hideresource]] the logical expressionevaluates to true for a certain property, this property is hidden or rolled-upin the report.Operands can be previously declared flags, built-in [[functions]], propertyattributes (specified as scenario.attribute) or another logical expression.When you combine logical operations to a more complex expression, theoperators are evaluated from left to right. '''a | b & c''' is identical to'''(a | b) & c'''. It's highly recommended that you always use brackets tocontrol the evaluation sequence. Currently, TaskJuggler does not support theconcept of operator precedence or right-left associativity. This may change inthe future.An operand can also be just a number. 0 evaluates to false, all other numbersto true. 2019: ) 2020: also(%( functions )) 2021: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 2043 2043: def rule_macro 2044: pattern(%( _macro $ID $MACRO ), lambda { 2045: if @scanner.macroDefined?(@val[1]) 2046: warning('marco_redefinition', "Redefining macro #{@val[1]}") 2047: end 2048: @scanner.addMacro(TextParser::Macro.new(@val[1], @val[2], 2049: @sourceFileInfo[0])) 2050: }) 2051: doc('macro', Defines a text fragment that can later be inserted by using the specified ID.To insert the text fragment anywhere in the text you need to write ${ID}.Thebody is not optional. It must be enclosed in square brackets. Macros can bedeclared like this: macro FOO [ This text ]If later ''''${FOO}'''' is found in the project file, it is expanded to''''This text''''.Macros may have arguments. Arguments are accessed with special macros withnumbers as names. The number specifies the index of the argument. macro FOO [ This ${1} text ]will expand to ''''This stupid text'''' if called as ''''${FOO "stupid"}''''.Macros may call other macros. All macro arguments must be enclosed by doublequotes. In case the argument contains a double quote, it must be escaped by aslash (''''/'''').User defined macro IDs must have at least one uppercase letter as alllowercase letter IDs are reserved for built-in macros.To terminate the macro definition, the ''''<nowiki>]</nowiki>'''' must be thelast character in the line. If there are any other characters trailing it(even spaces or comments) the ''''<nowiki>]</nowiki>'''' will not beconsidered the end of the macro definition.In macro calls the macro names can be prefixed by a question mark. In thiscase the macro will expand to nothing if the macro is not defined. Otherwisethe undefined macro would be flagged with an error message.The macro call ${?foo}will expand to nothing if foo is undefined. 2052: ) 2053: example('Macro-1') 2054: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 2100 2100: def rule_moreAlternatives 2101: commaListRule('!resourceId') 2102: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 2104 2104: def rule_moreArguments 2105: commaListRule('!argument') 2106: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 2094 2094: def rule_moreBangs 2095: optional 2096: repeatable 2097: singlePattern('_!') 2098: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 2108 2108: def rule_moreChargeSetItems 2109: commaListRule('!chargeSetItem') 2110: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 2112 2112: def rule_moreColumnDef 2113: commaListRule('!columnDef') 2114: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 2116 2116: def rule_moreDepTasks 2117: commaListRule('!taskDep') 2118: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 2120 2120: def rule_moreLeafResources 2121: commaListRule('!resourceLeafList') 2122: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 2124 2124: def rule_moreListOfDays 2125: commaListRule('!weekDayInterval') 2126: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 2128 2128: def rule_moreOutputFormats 2129: commaListRule('!outputFormat') 2130: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 2136 2136: def rule_morePredTasks 2137: commaListRule('!taskPred') 2138: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 2132 2132: def rule_moreProjectIDs 2133: commaListRule('$ID') 2134: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 2140 2140: def rule_moreSortCriteria 2141: commaListRule('!sortNonTree') 2142: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 2144 2144: def rule_moreTimeIntervals 2145: commaListRule('!timeInterval') 2146: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 2236 2236: def rule_nikuReport 2237: pattern(%( !nikuReportHeader !nikuReportBody ), lambda { 2238: @property = nil 2239: }) 2240: doc('nikureport', This report generates an XML file to be imported into the enterprise resourcemanagement software Clarity(R) from Computer Associates(R). The files containsallocation curves for the specified resources. All tasks with identical userdefined attributes ''''ClarityPID'''' and ''''ClarityPNAME'''' are bundledinto a Clarity project. The resulting XML file can be imported into Claritywith the xog-in tool. 2241: ) 2242: example('Niku') 2243: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 2188 2188: def rule_nikuReportAttributes 2189: optional 2190: repeatable 2191: 2192: pattern(%( !formats )) 2193: pattern(%( !headline )) 2194: pattern(%( !hideresource )) 2195: pattern(%( !hidetask )) 2196: 2197: pattern(%( !numberFormat ), lambda { 2198: @property.set('numberFormat', @val[0]) 2199: }) 2200: 2201: pattern(%( !reportEnd )) 2202: pattern(%( !reportPeriod )) 2203: pattern(%( !reportStart )) 2204: pattern(%( !reportTitle )) 2205: 2206: pattern(%( _timeoff $STRING $STRING ), lambda { 2207: @property.set('timeOffId', @val[1]) 2208: @property.set('timeOffName', @val[2]) 2209: }) 2210: doc('timeoff.nikureport', Set the Clarity project ID and name that the vacation time will be reported to. 2211: ) 2212: arg(1, 'ID', 'The Clarity project ID') 2213: arg(2, 'Name', 'The Clarity project name') 2214: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 2218 2218: def rule_nikuReportBody 2219: pattern(%( _{ !nikuReportAttributes _} ), lambda { 2220: 2221: }) 2222: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 2224 2224: def rule_nikuReportHeader 2225: pattern(%( _nikureport !optionalID $STRING ), lambda { 2226: newReport(@val[1], @val[2], :niku, sourceFileInfo) 2227: @property.set('numberFormat', RealFormat.new(['-', '', '', '.', 2])) 2228: }) 2229: arg(1, 'file name', The name of the time sheet report file to generate. It must end with a .tjiextension, or use . to use the standard output channel. 2230: ) 2231: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 2252 2252: def rule_nodeId 2253: pattern(%( !idOrAbsoluteId !subNodeId ), lambda { 2254: case @property.typeSpec 2255: when :taskreport 2256: if (p1 = @project.task(@val[0])).nil? 2257: error('unknown_main_node', 2258: "Unknown task ID #{@val[0]}", @sourceFileInfo[0]) 2259: end 2260: if @val[1] 2261: if (p2 = @project.resource(@val[1])).nil? 2262: error('unknown_sub_node', 2263: "Unknown resource ID #{@val[0]}", @sourceFileInfo[0]) 2264: end 2265: return [ p2, p1 ] 2266: end 2267: return [ p1, nil ] 2268: when :resourcereport 2269: if (p1 = @project.task(@val[0])).nil? 2270: error('unknown_main_node', 2271: "Unknown task ID #{@val[0]}", @sourceFileInfo[0]) 2272: end 2273: if @val[1] 2274: if (p2 = @project.resource(@val[1])).nil? 2275: error('unknown_sub_node', 2276: "Unknown resource ID #{@val[0]}", @sourceFileInfo[0]) 2277: end 2278: return [ p2, p1 ] 2279: end 2280: return [ p1, nil ] 2281: end 2282: 2283: raise "Node list is not supported for this report type: " + 2284: "#{@property.typeSpec}" 2285: }) 2286: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 2288 2288: def rule_nodeIdList 2289: listRule('moreNodeIdList', '!nodeId') 2290: pattern([ '_-' ], lambda { 2291: [] 2292: }) 2293: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 2295 2295: def rule_number 2296: singlePattern('$INTEGER') 2297: singlePattern('$FLOAT') 2298: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 2300 2300: def rule_numberFormat 2301: pattern(%( _numberformat $STRING $STRING $STRING $STRING $INTEGER ), 2302: lambda { 2303: RealFormat.new(@val.slice(1, 5)) 2304: }) 2305: doc('numberformat', 2306: 'These values specify the default format used for all numerical ' + 2307: 'real values.') 2308: arg(1, 'negativeprefix', 'Prefix for negative numbers') 2309: arg(2, 'negativesuffix', 'Suffix for negative numbers') 2310: arg(3, 'thousandsep', 'Separator used for every 3rd digit') 2311: arg(4, 'fractionsep', 'Separator used to separate the fraction digits') 2312: arg(5, 'fractiondigits', 'Number of fraction digits to show') 2313: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 2315 2315: def rule_operand 2316: pattern(%( _( !operation _) ), lambda { 2317: @val[1] 2318: }) 2319: pattern(%( _~ !operand ), lambda { 2320: operation = LogicalOperation.new(@val[1]) 2321: operation.operator = '~' 2322: operation 2323: }) 2324: 2325: pattern(%( $ABSOLUTE_ID ), lambda { 2326: if @val[0].count('.') > 1 2327: error('operand_attribute', 2328: 'Attributes must be specified as <scenarioID>.<attribute>', 2329: @sourceFileInfo[0]) 2330: end 2331: scenario, attribute = @val[0].split('.') 2332: if (scenarioIdx = @project.scenarioIdx(scenario)).nil? 2333: error('operand_unkn_scen', "Unknown scenario ID #{scenario}", 2334: @sourceFileInfo[0]) 2335: end 2336: LogicalAttribute.new(attribute, @project.scenario(scenarioIdx)) 2337: }) 2338: pattern(%( !date ), lambda { 2339: LogicalOperation.new(@val[0]) 2340: }) 2341: pattern(%( $ID !argumentList ), lambda { 2342: if @val[1].nil? 2343: unless @project['flags'].include?(@val[0]) 2344: error('operand_unkn_flag', "Undeclared flag '#{@val[0]}'", 2345: @sourceFileInfo[0]) 2346: end 2347: LogicalFlag.new(@val[0]) 2348: else 2349: func = LogicalFunction.new(@val[0]) 2350: res = func.setArgumentsAndCheck(@val[1]) 2351: unless res.nil? 2352: error(*res) 2353: end 2354: func 2355: end 2356: }) 2357: pattern(%( $INTEGER ), lambda { 2358: LogicalOperation.new(@val[0]) 2359: }) 2360: pattern(%( $FLOAT ), lambda { 2361: LogicalOperation.new(@val[0]) 2362: }) 2363: pattern(%( $STRING ), lambda { 2364: LogicalOperation.new(@val[0]) 2365: }) 2366: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 2368 2368: def rule_operation 2369: pattern(%( !operand !operationChain ), lambda { 2370: operation = LogicalOperation.new(@val[0]) 2371: if @val[1] 2372: # Further operators/operands create an operation tree. 2373: @val[1].each do |ops| 2374: operation = LogicalOperation.new(operation) 2375: operation.operator = ops[0] 2376: operation.operand2 = ops[1] 2377: end 2378: end 2379: operation 2380: }) 2381: arg(0, 'operand', An operand can consist of a date, a text string, a [[functions|function]], aproperty attribute or a numerical value. It can also be the name of a declaredflag. Use the ''''scenario_id.attribute'''' notation to use an attribute of thecurrently evaluated property. The scenario ID always has to be specified, alsofor non-scenario specific attributes. This is necessary to distinguish themfrom flags.An operand can be a negated operand by prefixing a ~ charater or it can beanother logical expression enclosed in braces. 2382: ) 2383: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 2395 2395: def rule_operationChain 2396: optional 2397: repeatable 2398: pattern(%( !operatorAndOperand), lambda { 2399: @val[0] 2400: }) 2401: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 2413 2413: def rule_operator 2414: singlePattern('_|') 2415: descr('The \or\ operator') 2416: 2417: singlePattern('_&') 2418: descr('The \and\ operator') 2419: 2420: singlePattern('_>') 2421: descr('The \greater than\ operator') 2422: 2423: singlePattern('_<') 2424: descr('The \smaller than\ operator') 2425: 2426: singlePattern('_=') 2427: descr('The \equal\ operator') 2428: 2429: singlePattern('_>=') 2430: descr('The \greater-or-equal\ operator') 2431: 2432: singlePattern('_<=') 2433: descr('The \smaller-or-equal\ operator') 2434: 2435: singlePattern('_!=') 2436: descr('The \not-equal\ operator') 2437: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 2403 2403: def rule_operatorAndOperand 2404: pattern(%( !operator !operand), lambda{ 2405: [ @val[0], @val[1] ] 2406: }) 2407: arg(1, 'operand', 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. 2408: ) 2409: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 2439 2439: def rule_optionalID 2440: optional 2441: pattern(%( $ID ), lambda { 2442: @val[0] 2443: }) 2444: arg(0, 'id', An optional ID. If you ever want to reference this property, you must specifyyour own unique ID. If no ID is specified one will be automatically generated.These IDs may become visible in reports, but may change at any time. You maynever rely on automatically generated IDs. 2445: ) 2446: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 2453 2453: def rule_optionalPercent 2454: optional 2455: pattern(%( !number _% ), lambda { 2456: @val[0] / 100.0 2457: }) 2458: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 2460 2460: def rule_optionalVersion 2461: optional 2462: pattern(%( $STRING ), lambda { 2463: @val[0] 2464: }) 2465: arg(0, 'version', An optional version ID. This can be something simple as "4.2" or an ID tag ofa revision control system. If not specified, it defaults to "1.0". 2466: ) 2467: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 2472 2472: def rule_outputFormat 2473: pattern(%( _csv ), lambda { 2474: :csv 2475: }) 2476: descr(The report lists the resources and their respective values ascolon-separated-value (CSV) format. Due to the very simple nature of the CSVformat, only a small subset of features will be supported for CSV output.Including tasks or listing multiple scenarios will result in very difficult toread reports. 2477: ) 2478: 2479: pattern(%( _html ), lambda { 2480: :html 2481: }) 2482: descr('Generate a web page (HTML file)') 2483: 2484: pattern(%( _niku ), lambda { 2485: :niku 2486: }) 2487: descr('Generate a XOG XML file to be used with Clarity.') 2488: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 2496 2496: def rule_outputFormats 2497: pattern(%( !outputFormat !moreOutputFormats ), lambda { 2498: [ @val[0] ] + (@val[1].nil? ? [] : @val[1]) 2499: }) 2500: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 2502 2502: def rule_plusOrMinus 2503: singlePattern('_+') 2504: singlePattern('_-') 2505: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 2507 2507: def rule_project 2508: pattern(%( !projectProlog !projectDeclaration !properties . ), lambda { 2509: @val[1] 2510: }) 2511: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 2513 2513: def rule_projectBody 2514: optionsRule('projectBodyAttributes') 2515: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 2517 2517: def rule_projectBodyAttributes 2518: repeatable 2519: optional 2520: 2521: pattern(%( !currencyFormat ), lambda { 2522: @project['currencyFormat'] = @val[0] 2523: }) 2524: 2525: pattern(%( _currency $STRING ), lambda { 2526: @project['currency'] = @val[1] 2527: }) 2528: doc('currency', 'The default currency unit.') 2529: example('Account') 2530: arg(1, 'symbol', 'Currency symbol') 2531: 2532: pattern(%( _dailyworkinghours !number ), lambda { 2533: @project['dailyworkinghours'] = @val[1] 2534: }) 2535: doc('dailyworkinghours', Set the average number of working hours per day. This is used asthe base to convert working hours into working days. This affectsfor example the length task attribute. The default value is 8 hoursand should work for most Western countries. The value you specify should matchthe settings you specified as your default [[workinghours.project|workinghours]]. 2536: ) 2537: example('Project') 2538: arg(1, 'hours', 'Average number of working hours per working day') 2539: 2540: pattern(%( _extend !extendProperty !extendBody ), lambda { 2541: updateParserTables 2542: }) 2543: doc('extend', Often it is desirable to collect more information in the project file than isnecessary for task scheduling and resource allocation. To add such informationto tasks, resources or accounts the user can extend these properties withuser-defined attributes. The new attributes can be of various types such astext, date or reference to capture various types of data. Optionally the usercan specify if the attribute value should be inherited from the enclosingproperty. 2544: ) 2545: example('CustomAttributes') 2546: 2547: pattern(%( !projectBodyInclude )) 2548: 2549: pattern(%( !journalEntry )) 2550: 2551: pattern(%( _now !date ), lambda { 2552: @project['now'] = @val[1] 2553: @scanner.addMacro(TextParser::Macro.new('now', @val[1].to_s, 2554: @sourceFileInfo[0])) 2555: @scanner.addMacro(TextParser::Macro.new( 2556: 'today', @val[1].to_s(@project['timeFormat']), @sourceFileInfo[0])) 2557: }) 2558: doc('now', Specify the date that TaskJuggler uses for calculation as currentdate. If no value is specified, the current value of the systemclock is used. 2559: ) 2560: arg(1, 'date', 'Alternative date to be used as current date for all ' + 2561: 'computations') 2562: 2563: pattern(%( !numberFormat ), lambda { 2564: @project['numberFormat'] = @val[0] 2565: }) 2566: 2567: pattern(%( !scenario )) 2568: pattern(%( _shorttimeformat $STRING ), lambda { 2569: @project['shortTimeFormat'] = @val[1] 2570: }) 2571: doc('shorttimeformat', 2572: 'Specifies time format for time short specifications. This is normal' + 2573: 'just the hour and minutes.') 2574: arg(1, 'format', 'strftime like format string') 2575: 2576: pattern(%( !timeformat ), lambda { 2577: @project['timeFormat'] = @val[0] 2578: }) 2579: 2580: pattern(%( !timezone ), lambda { 2581: @val[0] 2582: }) 2583: 2584: pattern(%( _timingresolution $INTEGER _min ), lambda { 2585: goodValues = [ 5, 10, 15, 20, 30, 60 ] 2586: unless goodValues.include?(@val[1]) 2587: error('bad_timing_res', 2588: "Timing resolution must be one of #{goodValues.join(', ')} min.", 2589: @sourceFileInfo[1]) 2590: end 2591: if @val[1] > (Project.maxScheduleGranularity / 60) 2592: error('too_large_timing_res', 2593: 'The maximum allowed timing resolution for the timezone is ' + 2594: "#{Project.maxScheduleGranularity / 60} minutes.", 2595: @sourceFileInfo[1]) 2596: end 2597: @project['scheduleGranularity'] = @val[1] * 60 2598: }) 2599: doc('timingresolution', Sets the minimum timing resolution. The smaller the value, the longer thescheduling process lasts and the more memory the application needs. Thedefault and maximum value is 1 hour. The smallest value is 5 min.This value is a pretty fundamental setting of TaskJuggler. It has a severeimpact on memory usage and scheduling performance. You should set this valueto the minimum required resolution. Make sure that all values that you specifyare aligned with the resolution.Changing the timing resolution will reset the [[workinghours.project|workinghours]] to the default times. It's recommended that this is the very firstoption in the project header section.Do not use this option after you've set the time zone! 2600: ) 2601: 2602: pattern(%( _trackingscenario !scenarioId ), lambda { 2603: @project['trackingScenarioIdx'] = @val[1] 2604: # The tracking scenario and all child scenarios will always be scheduled 2605: # in projection mode. 2606: @project.scenario(@val[1]).all.each do |scenario| 2607: scenario.set('projection', true) 2608: end 2609: }) 2610: doc('trackingscenario', Specifies which scenario is used to capture what actually has happened withthe project. All sub-scenarios of this scenario inherit the bookings of thetracking scenario and may not have any bookings of their own. The trackingscenario must also be specified to use time and status sheet reports.The tracking scenario and all scenarios derived from it will be scheduled inprojection mode. This means that the scheduler will only add bookings afterthe current date or the date specified by [[now]]. It is assumed that allallocations prior to this date have been provided as [[booking.task|task bookings]] or [[booking.resource|resource bookings]]. 2611: ) 2612: example('TimeSheet1', '2') 2613: 2614: pattern(%( _weekstartsmonday ), lambda { 2615: @project['weekStartsMonday'] = true 2616: }) 2617: doc('weekstartsmonday', 2618: 'Specify that you want to base all week calculation on weeks ' + 2619: 'starting on Monday. This is common in many European countries.') 2620: 2621: pattern(%( _weekstartssunday ), lambda { 2622: @project['weekStartsMonday'] = false 2623: }) 2624: doc('weekstartssunday', 2625: 'Specify that you want to base all week calculation on weeks ' + 2626: 'starting on Sunday. This is common in the United States of America.') 2627: 2628: pattern(%( !workinghoursProject )) 2629: pattern(%( _yearlyworkingdays !number ), lambda { 2630: @project['yearlyworkingdays'] = @val[1] 2631: }) 2632: doc('yearlyworkingdays', Specifies the number of average working days per year. This should correlateto the specified workinghours and vacation. It affects the conversion ofworking hours, working days, working weeks, working months and working yearsinto each other.When public holidays and vacations are disregarded, this value should be equalto the number of working days per week times 52.1428 (the average number ofweeks per year). E. g. for a culture with 5 working days it is 260.714 (thedefault), for 6 working days it is 312.8568 and for 7 working days it is365. 2633: ) 2634: arg(1, 'days', 'Number of average working days for a year') 2635: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 2786 2786: def rule_projectBodyInclude 2787: pattern(%( _include !includeFile !projectBodyAttributes . )) 2788: lastSyntaxToken(1) 2789: doc('include.project', Includes the specified file name as if its contents would be writteninstead of the include property. The only exception is the includestatement itself. When the included files contains other includestatements or report definitions, the filenames are relative to filewhere they are defined in.The included files may only contain content that may be present in a projectheader section.If the include statement is the last statement in the file it must have the option block. The option block can be empty, but the curly braces must be present. 2790: ) 2791: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 2692 2692: def rule_projectDeclaration 2693: pattern(%( !projectHeader !projectBody ), lambda { 2694: # If the user has specified a tracking scenario, we mark all children of 2695: # that scenario to disallow own bookings. These scenarios will inherit 2696: # their bookings from the tracking scenario. 2697: if (idx = @project['trackingScenarioIdx']) 2698: @project.scenario(idx).allLeaves(true).each do |scenario| 2699: scenario.set('ownbookings', false) 2700: end 2701: end 2702: @val[0] 2703: }) 2704: doc('project', The project property is mandatory and should be the first propertyin a project file. It is used to capture basic attributes such asthe project id, name and the expected time frame.Be aware that the dates for the project period default to UTC times. See [[interval2]] for details. 2705: ) 2706: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 2714 2714: def rule_projectHeader 2715: pattern(%( _project !optionalID $STRING !optionalVersion !interval ), lambda { 2716: @project = Project.new(@val[1], @val[2], @val[3], @messageHandler) 2717: @project['start'] = @val[4].start 2718: @project['end'] = @val[4].end 2719: @projectId = @val[1] 2720: setGlobalMacros 2721: @property = nil 2722: @reportCounter = 0 2723: @project 2724: }) 2725: arg(2, 'name', 'The name of the project') 2726: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 2728 2728: def rule_projectIDs 2729: pattern(%( $ID !moreProjectIDs ), lambda { 2730: [ @val[0] ] + (@val[1].nil? ? [] : @val[1]) 2731: }) 2732: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 2763 2763: def rule_projectProlog 2764: optional 2765: repeatable 2766: pattern(%( !prologInclude )) 2767: pattern(%( !macro )) 2768: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 2770 2770: def rule_projectProperties 2771: # This rule is not defining actual syntax. It's only used for the 2772: # documentation. 2773: pattern(%( !projectPropertiesBody )) 2774: doc('properties', The project properties. Every project must consists of at least one task. The other properties are optional. To save the scheduled data at least one output generating property should be used. 2775: ) 2776: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 2780 2780: def rule_projectPropertiesBody 2781: # This rule is not defining actual syntax. It's only used for the 2782: # documentation. 2783: optionsRule('properties') 2784: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 2734 2734: def rule_projection 2735: optionsRule('projectionAttributes') 2736: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 2738 2738: def rule_projectionAttributes 2739: optional 2740: repeatable 2741: pattern(%( _sloppy ), lambda { 2742: warning('projection_sloppy', 2743: 'The sloppy projection mode has been deprecated. The ' + 2744: 'functionality is no longer supported.') 2745: }) 2746: doc('sloppy.projection', The sloppy projection mode has been deprecated. Please use[[trackingscenario]] feature instead. 2747: ) 2748: 2749: pattern(%( _strict ), lambda { 2750: warning('projection_strict', 2751: 'The strict mode is now always used.') 2752: }) 2753: doc('strict.projection', The strict projection mode has been deprecated. Please use[[trackingscenario]] feature instead. 2754: ) 2755: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 2804 2804: def rule_prologInclude 2805: pattern(%( _include !includeFile !projectProlog . )) 2806: lastSyntaxToken(1) 2807: doc('include.macro', Includes the specified file name as if its contents would be writteninstead of the include property. The only exception is the includestatement itself. When the included files contains other includestatements or report definitions, the filenames are relative to filewhere they are defined in.The included file may only contain macro definitions. 2808: ) 2809: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 2819 2819: def rule_properties 2820: pattern(%( !propertiesBody )) 2821: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 2823 2823: def rule_propertiesBody 2824: repeatable 2825: optional 2826: 2827: pattern(%( !account )) 2828: 2829: pattern(%( _copyright $STRING ), lambda { 2830: @project['copyright'] = @val[1] 2831: }) 2832: doc('copyright', Set a copyright notice for the project file and its content. This copyright notice will be added to all reports that can support it. 2833: ) 2834: example('Caption', '2') 2835: 2836: pattern(%( !balance ), lambda { 2837: @project['costAccount'] = @val[0][0] 2838: @project['revenueAccount'] = @val[0][1] 2839: }) 2840: 2841: pattern(%( !export )) 2842: 2843: pattern(%( _flags !declareFlagList ), lambda { 2844: unless @project['flags'].include?(@val[1]) 2845: @project['flags'] += @val[1] 2846: end 2847: }) 2848: doc('flags', Declare one or more flag for later use. Flags can be used to mark tasks, resources or other properties to filter them in reports. 2849: ) 2850: 2851: pattern(%( !propertiesInclude )) 2852: 2853: pattern(%( !limits ), lambda { 2854: @project['limits'] = @val[0] 2855: }) 2856: doc('limits', Set per-interval allocation limits for the following resource definitions.The limits can be overwritten in each resource definition and the globallimits can be changed later. 2857: ) 2858: 2859: pattern(%( !macro )) 2860: 2861: pattern(%( !nikuReport )) 2862: 2863: pattern(%( !navigator )) 2864: 2865: pattern(%( _projectid $ID ), lambda { 2866: @project['projectids'] << @val[1] 2867: @project['projectids'].uniq! 2868: @project['projectid'] = @projectId = @val[1] 2869: }) 2870: doc('projectid', This declares a new project id and activates it. All subsequenttask definitions will inherit this ID. The tasks of a project can havedifferent IDs. This is particularly helpful if the project is merged fromseveral sub projects that each have their own ID. 2871: ) 2872: 2873: pattern(%( _projectids !projectIDs ), lambda { 2874: @project['projectids'] += @val[1] 2875: @project['projectids'].uniq! 2876: }) 2877: doc('projectids', 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. 2878: ) 2879: 2880: pattern(%( _rate !number ), lambda { 2881: @project['rate'] = @val[1].to_f 2882: }) 2883: doc('rate', Set the default rate for all subsequently defined resources. The rate describes the daily cost of a resource. 2884: ) 2885: 2886: pattern(%( !report )) 2887: pattern(%( !resource )) 2888: pattern(%( !shift )) 2889: pattern(%( !statusSheet )) 2890: pattern(%( !statusSheetReport )) 2891: 2892: pattern(%( _supplement !supplement )) 2893: doc('supplement', The supplement keyword provides a mechanism to add more attributes to alreadydefined accounts, tasks or resources. The additional attributes must obey thesame rules as in regular task or resource definitions and must be enclosed bycurly braces.This construct is primarily meant for situations where the information about atask or resource is split over several files. E. g. the vacation dates for theresources may be in a separate file that was generated by some other tool. 2894: ) 2895: example('Supplement') 2896: 2897: pattern(%( !task )) 2898: pattern(%( !timeSheet )) 2899: pattern(%( !timeSheetReport )) 2900: pattern(%( _vacation !vacationName !intervals ), lambda { 2901: begin 2902: @project['vacations'] = @project['vacations'] + @val[2] 2903: rescue AttributeOverwrite 2904: end 2905: }) 2906: doc('vacation', Specify a global vacation period for all subsequently defined resources. Avacation can also be used to block out the time before a resource joined orafter it left. For employees changing their work schedule from full-time topart-time, or vice versa, please refer to the 'Shift' property. 2907: ) 2908: arg(1, 'name', 'Name or purpose of the vacation') 2909: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 2942 2942: def rule_propertiesFile 2943: pattern(%( !propertiesBody . )) 2944: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 2946 2946: def rule_propertiesInclude 2947: pattern(%( _include !includeProperties !properties . ), lambda { 2948: }) 2949: doc('include.properties', Includes the specified file name as if its contents would be writteninstead of the include property. The only exception is the includestatement itself. When the included files contains other includestatements or report definitions, the filenames are relative to filewhere they are defined in. include commands can be used in the projectheader, at global scope or between property declarations of tasks,resources, and accounts.For technical reasons you have to supply the optional pair of curlybrackets if the include is followed immediately by a macro call thatis defined within the included file. 2950: ) 2951: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 2965 2965: def rule_purge 2966: pattern(%( _purge $ID ), lambda { 2967: if (attributeDefinition = @property.attributeDefinition(@val[1])).nil? 2968: error('purge_unknown_id', 2969: "#{@val[1]} is not a known attribute for this property", 2970: @sourceFileInfo[1]) 2971: end 2972: if attributeDefinition.scenarioSpecific 2973: attr = @property[@val[1], 0] 2974: else 2975: attr = @property.get(@val[1]) 2976: end 2977: unless attr.is_a?(Array) 2978: error('purge_no_list', 2979: "#{@val[1]} is not a list attribute. Only those can be purged.", 2980: @sourceFileInfo[1]) 2981: end 2982: @property.getAttribute(@val[1], @scenarioIdx).reset 2983: }) 2984: doc('purge', List attributes, like regular attributes, can inherit their values from theenclosing property. By defining more values for such a list attribute, the newvalues will be appended to the existing ones. The purge statement clears sucha list atribute. A subsequent definition for the attribute within the propertywill then add their values to an empty list. 2985: ) 2986: arg(1, 'attribute', 'Any name of a list attribute') 2987: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 2995 2995: def rule_referenceAttributes 2996: optional 2997: repeatable 2998: pattern(%( _label $STRING ), lambda { 2999: @val[1] 3000: }) 3001: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 3003 3003: def rule_referenceBody 3004: optionsRule('referenceAttributes') 3005: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 3007 3007: def rule_relativeId 3008: pattern(%( _! !moreBangs !idOrAbsoluteId ), lambda { 3009: str = '!' 3010: if @val[1] 3011: @val[1].each { |bang| str += bang } 3012: end 3013: str += @val[2] 3014: str 3015: }) 3016: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 3018 3018: def rule_report 3019: pattern(%( !reportHeader !reportBody ), lambda { 3020: @property = @property.parent 3021: }) 3022: doc('report', Reports are used to store and vizualize the results of a scheduled project.The content, the output format and the appearance of a report can be adjustedwith report attributes. Reports can be nested to create structured documenttrees. As with other properties, the resource attributes can be inherited fromthe enclosing report or the project.By default, report definitions do not generate any files. With more complexprojects, most report definitions will be used to describe elements ofcomposed reports. If you want to generate a file from this report, you mustspecify the list of [[formats]] that you want to generate. The report namewill then be used as a base name to create the file. The suffix will beappended based on the generated format.Reports have a local name space. All IDs must be unique within the reportsthat belong to the same enclosing report. To reference a report for inclusioninto another report, you need to specify the full report ID. This is composedof the report ID, prefixed by a dot-separated list of all parent report IDs. 3023: ) 3024: also(%( resourcereport taskreport textreport )) 3025: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 3374 3374: def rule_reportAttributes 3375: optional 3376: repeatable 3377: 3378: pattern(%( !balance ), lambda { 3379: @property.set('costAccount', @val[0][0]) 3380: @property.set('revenueAccount', @val[0][1]) 3381: }) 3382: 3383: pattern(%( _caption $STRING ), lambda { 3384: @property.set('caption', newRichText(@val[1], @sourceFileInfo[1])) 3385: }) 3386: doc('caption', The caption will be embedded in the footer of the table or data segment. Thetext will be interpreted as [[Rich_Text_Attributes|Rich Text]]. 3387: ) 3388: arg(1, 'text', 'The caption text.') 3389: example('Caption', '1') 3390: 3391: pattern(%( _center $STRING ), lambda { 3392: @property.set('center', newRichText(@val[1], @sourceFileInfo[1])) 3393: }) 3394: doc('center', This attribute defines the center section of the [[textreport]]. The text willbe interpreted as [[Rich_Text_Attributes|Rich Text]]. 3395: ) 3396: arg(1, 'text', 'The text') 3397: 3398: pattern(%( _columns !columnDef !moreColumnDef ), lambda { 3399: columns = [ @val[1] ] 3400: columns += @val[2] if @val[2] 3401: @property.set('columns', columns) 3402: }) 3403: doc('columns', Specifies which columns shall be included in a report. Some columns showvalues that are constant over the course of the project. Other columns showcalculated values that depend on the time period that was chosen for thereport. 3404: ) 3405: 3406: pattern(%( !currencyFormat ), lambda { 3407: @property.set('currencyFormat', @val[0]) 3408: }) 3409: 3410: pattern(%( !reportEnd )) 3411: 3412: pattern(%( _epilog $STRING ), lambda { 3413: @property.set('epilog', newRichText(@val[1], @sourceFileInfo[1])) 3414: }) 3415: doc('epilog', Define a text section that is printed right after the actual report data. Thetext will be interpreted as [[Rich_Text_Attributes|Rich Text]]. 3416: ) 3417: also(%( footer header prolog )) 3418: 3419: pattern(%( !flags )) 3420: doc('flags.report', Attach a set of flags. The flags can be used in logical expressions to filterproperties from the reports. 3421: ) 3422: 3423: pattern(%( _footer $STRING ), lambda { 3424: @property.set('footer', newRichText(@val[1], @sourceFileInfo[1])) 3425: }) 3426: doc('footer', Define a text section that is put at the bottom of the report. Thetext will be interpreted as [[Rich_Text_Attributes|Rich Text]]. 3427: ) 3428: also(%( epilog header prolog )) 3429: 3430: pattern(%( !formats )) 3431: 3432: pattern(%( _header $STRING ), lambda { 3433: @property.set('header', newRichText(@val[1], @sourceFileInfo[1])) 3434: }) 3435: doc('header', Define a text section that is put at the top of the report. Thetext will be interpreted as [[Rich_Text_Attributes|Rich Text]]. 3436: ) 3437: also(%( epilog footer prolog )) 3438: 3439: pattern(%( !headline )) 3440: pattern(%( !hidejournalentry )) 3441: pattern(%( !hideresource )) 3442: 3443: pattern(%( !hidetask )) 3444: 3445: pattern(%( _left $STRING ), lambda { 3446: @property.set('left', newRichText(@val[1], @sourceFileInfo[1])) 3447: }) 3448: doc('left', This attribute defines the left margin section of the [[textreport]]. The textwill be interpreted as [[Rich_Text_Attributes|Rich Text]]. The margin will notspan the [[header]] or [[footer]] sections. 3449: ) 3450: 3451: pattern(%( _loadunit !loadunit ), lambda { 3452: @property.set('loadUnit', @val[1]) 3453: }) 3454: doc('loadunit', Determines what unit should be used to display all load values in this report. 3455: ) 3456: 3457: pattern(%( !numberFormat ), lambda { 3458: @property.set('numberFormat', @val[0]) 3459: }) 3460: 3461: pattern(%( !reportPeriod )) 3462: 3463: pattern(%( _prolog $STRING ), lambda { 3464: @property.set('prolog', newRichText(@val[1], @sourceFileInfo[1])) 3465: }) 3466: doc('prolog', Define a text section that is printed right before the actual report data. Thetext will be interpreted as [[Rich_Text_Attributes|Rich Text]]. 3467: ) 3468: also(%( epilog footer header )) 3469: 3470: pattern(%( _opennodes !nodeIdList ), lambda { 3471: @property.set('openNodes', @val[1]) 3472: }) 3473: doc('opennodes', 'For internal use only!') 3474: 3475: pattern(%( !report )) 3476: 3477: pattern(%( _right $STRING ), lambda { 3478: @property.set('right', newRichText(@val[1], @sourceFileInfo[1])) 3479: }) 3480: doc('right', This attribute defines the right margin section of the [[textreport]]. The textwill be interpreted as [[Rich_Text_Attributes|Rich Text]]. The margin will notspan the [[header]] or [[footer]] sections. 3481: ) 3482: 3483: pattern(%( !rollupresource )) 3484: pattern(%( !rolluptask )) 3485: 3486: pattern(%( _scenarios !scenarioIdList ), lambda { 3487: # Don't include disabled scenarios in the report 3488: @val[1].delete_if { |sc| !@project.scenario(sc).get('active') } 3489: @property.set('scenarios', @val[1]) 3490: }) 3491: doc('scenarios', List of scenarios that should be included in the report. By default, only thetop-level scenario will be included. You can use this attribute to includedata from the defined set of scenarios. Not all reports support reporting datafrom multiple scenarios. They will only include data from the first one in thelist. 3492: ) 3493: 3494: pattern(%( _selfcontained !yesNo ), lambda { 3495: @property.set('selfcontained', @val[1]) 3496: }) 3497: doc('selfcontained', Try to generate selfcontained output files when the format supports this. E.g. for HTML reports, the style sheet will be included and no icons will beused. 3498: ) 3499: 3500: pattern(%( !sortResources )) 3501: pattern(%( !sortTasks )) 3502: 3503: pattern(%( !reportStart )) 3504: 3505: pattern(%( _resourceroot !resourceId), lambda { 3506: if @val[1].leaf? 3507: error('resourceroot_leaf', 3508: "#{@val[1].fullId} is not a group resource", 3509: @sourceFileInfo[1]) 3510: end 3511: @property.set('resourceRoot', @val[1]) 3512: }) 3513: doc('resourceroot', Only resources below the specified root-level resources are exported. Theexported resources will have the ID of the root-level resource stripped fromtheir ID, so that the sub-resourcess of the root-level resource becometop-level resources in the report file. 3514: ) 3515: example('ResourceRoot') 3516: 3517: pattern(%( _taskroot !taskId), lambda { 3518: if @val[1].leaf? 3519: error('taskroot_leaf', 3520: "#{@val[1].fullId} is not a container task", 3521: @sourceFileInfo[1]) 3522: end 3523: @property.set('taskRoot', @val[1]) 3524: }) 3525: doc('taskroot', Only tasks below the specified root-level tasks are exported. The exportedtasks will have the ID of the root-level task stripped from their ID, so thatthe sub-tasks of the root-level task become top-level tasks in the reportfile. 3526: ) 3527: example('TaskRoot') 3528: 3529: pattern(%( !timeformat ), lambda { 3530: @property.set('timeFormat', @val[0]) 3531: }) 3532: 3533: pattern(%( _timezone !validTimeZone ), lambda { 3534: @property.set('timezone', @val[1]) 3535: }) 3536: doc('timezone.report', Sets the time zone used for all dates in the report. This setting is ignoredif the report is embedded into another report. Embedded in this context meansthe report is part of another generated report. It does not mean that thereport definition is a sub report of another report definition. 3537: ) 3538: 3539: pattern(%( !reportTitle )) 3540: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 3670 3670: def rule_reportBody 3671: optionsRule('reportAttributes') 3672: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 3603 3603: def rule_reportEnd 3604: pattern(%( _end !date ), lambda { 3605: if @val[1] < @property.get('start') 3606: error('report_end', 3607: "End date must be before start date #{@property.get('start')}", 3608: @sourceFileInfo[1]) 3609: end 3610: @property.set('end', @val[1]) 3611: }) 3612: doc('end.report', Specifies the end date of the report. In task reports only tasks that startbefore this end date are listed. 3613: ) 3614: example('Export', '2') 3615: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 3674 3674: def rule_reportHeader 3675: pattern(%( !reportType !optionalID $STRING ), lambda { 3676: if @property.nil? && !@reportprefix.empty? 3677: @property = @project.report(@reportprefix) 3678: end 3679: if @val[1] 3680: id = (@property ? @property.fullId + '.' : '') + @val[1] 3681: if @project.report(id) 3682: error('report_exists', "report #{id} has already been defined.", 3683: @sourceFileInfo[1], @property) 3684: end 3685: end 3686: @property = Report.new(@project, @val[1], @val[2], @property) 3687: @property.sourceFileInfo = @sourceFileInfo[0] 3688: @property.inheritAttributes 3689: case @val[0] 3690: when 'taskreport' 3691: @property.typeSpec = :taskreport 3692: unless @property.modified?('columns') 3693: # Set the default columns for this report. 3694: %( bsi name start end effort chart ).each do |col| 3695: @property.get('columns') << 3696: TableColumnDefinition.new(col, columnTitle(col)) 3697: end 3698: end 3699: # Show all tasks, sorted by tree, start-up, seqno-up. 3700: unless @property.modified?('hideTask') 3701: @property.set('hideTask', 3702: LogicalExpression.new(LogicalOperation.new(0))) 3703: end 3704: unless @property.modified?('softTask') 3705: @property.set('sortTasks', 3706: [ [ 'tree', true, 1 ], 3707: [ 'start', true, 0 ], 3708: [ 'seqno', true, 1 ] ]) 3709: end 3710: # Show no resources, but set sorting to id-up. 3711: unless @property.modified?('hideResource') 3712: @property.set('hideResource', 3713: LogicalExpression.new(LogicalOperation.new(1))) 3714: end 3715: unless @property.modified?('sortResources') 3716: @property.set('sortResources', [ [ 'id', true, 1 ] ]) 3717: end 3718: when 'resourcereport' 3719: @property.typeSpec = :resourcereport 3720: if @property.modified?('columns') 3721: # Set the default columns for this report. 3722: %( no name ).each do |col| 3723: @property.get('columns') << 3724: TableColumnDefinition.new(col, columnTitle(col)) 3725: end 3726: end 3727: # Show all resources, sorted by tree and id-up. 3728: unless @property.modified?('hideResource') 3729: @property.set('hideResource', 3730: LogicalExpression.new(LogicalOperation.new(0))) 3731: end 3732: unless @property.modified?('sortResources') 3733: @property.set('sortResources', [ [ 'tree', true, 1 ], 3734: [ 'id', true, 1 ] ]) 3735: end 3736: # Hide all resources, but set sorting to tree, start-up, seqno-up. 3737: unless @property.modified?('hideTask') 3738: @property.set('hideTask', 3739: LogicalExpression.new(LogicalOperation.new(1))) 3740: end 3741: unless @property.modified?('sortTasks') 3742: @property.set('sortTasks', 3743: [ [ 'tree', true, 1 ], 3744: [ 'start', true, 0 ], 3745: [ 'seqno', true, 1 ] ]) 3746: end 3747: when 'textreport' 3748: @property.typeSpec = :textreport 3749: else 3750: raise "Unsupported report type #{@val[0]}" 3751: end 3752: }) 3753: arg(2, 'name', The name of the report. This will be the base name for generated output files.The suffix will depend on the specified [[formats]].It will also be used innavigation bars. 3754: ) 3755: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 3619 3619: def rule_reportId 3620: pattern(%( !reportIdUnverifd ), lambda { 3621: id = @val[0] 3622: if @property && @property.is_a?(Report) 3623: id = @property.fullId + '.' + id 3624: else 3625: id = @reportprefix + '.' + id unless @reportprefix.empty? 3626: end 3627: # In case we have a nested supplement, we need to prepend the parent ID. 3628: if (report = @project.report(id)).nil? 3629: error('report_id_expected', "#{id} is not a defined report.", 3630: @sourceFileInfo[0]) 3631: end 3632: report 3633: }) 3634: arg(0, 'report', 'The ID of a defined report') 3635: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 3637 3637: def rule_reportIdUnverifd 3638: singlePattern('$ABSOLUTE_ID') 3639: singlePattern('$ID') 3640: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 3642 3642: def rule_reportPeriod 3643: pattern(%( _period !interval ), lambda { 3644: @property.set('start', @val[1].start) 3645: @property.set('end', @val[1].end) 3646: }) 3647: doc('period.report', This property is a shortcut for setting the start and end property at thesame time. 3648: ) 3649: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 3654 3654: def rule_reportStart 3655: pattern(%( _start !date ), lambda { 3656: if @val[1] > @property.get('end') 3657: error('report_start', 3658: "Start date must be before end date #{@property.get('end')}", 3659: @sourceFileInfo[1]) 3660: end 3661: @property.set('start', @val[1]) 3662: }) 3663: doc('start.report', Specifies the start date of the report. In task reports only tasks that endafter this end date are listed. 3664: ) 3665: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 3761 3761: def rule_reportTitle 3762: pattern(%( _title $STRING ), lambda { 3763: @property.set('title', @val[1]) 3764: }) 3765: doc('title', The title of the report will be used in external references to the report. Itwill not show up in the reports directly. It's used e. g. by [[navigator]]. 3766: ) 3767: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 3772 3772: def rule_reportType 3773: singlePattern('_resourcereport') 3774: doc('resourcereport', The report lists resources and their respective values in a table. The taskthat are the resources are allocated to can be listed as well. To reduce thelist of included resources, you can use the [[hideresource]],[[rollupresource]] or [[resourceroot]] attributes. The order of the task canbe controlled with [[sortresources]]. If the first sorting criteria is treesorting, the parent resources will always be included to form the tree.Tree sorting is the default. You need to change it if you do not want certainparent resources to be included in the report.The tasks that the resources are allocated to can be included as well. Use the[[hidetask]] attribute for this. See [[report]] for a complete list ofattributes and the full syntax for this keyword. 3775: ) 3776: singlePattern('_taskreport') 3777: doc('taskreport', The report lists tasks and their respective values in a table. To reduce thelist of included tasks, you can use the [[hidetask]], [[rolluptask]] or[[taskroot]] attributes. The order of the task can be controlled with[[sorttasks]]. If the first sorting criteria is tree sorting, the parent taskswill always be included to form the tree. Tree sorting is the default. Youneed to change it if you do not want certain parent tasks to be included inthe report.The resources that are allocated to each task can be listed as well. Use the[[hideresource]] attribute for this. See [[report]] for a complete list ofattributes and the full syntax for this keyword. 3778: ) 3779: singlePattern('_textreport') 3780: doc('textreport', This report consists of 5 RichText sections, a header, a center section with aleft and right margin and a footer. The sections may contain the output ofother defined reports. See [[report]] for further details. 3781: ) 3782: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 3046 3046: def rule_reportableAttributes 3047: singlePattern('_alert') 3048: descr(The alert level of the property that was reported with the date closest to theend date of the report. Container properties that don't have their own alertlevel reported with a date equal or newer than the alert levels of all theirsub properties will get the highest alert level of their direct subproperties. 3049: ) 3050: 3051: singlePattern('_alertmessages') 3052: descr(The headlines, the summary and the details of the message from the journalentries that caused the current alert level to be larger than the defaul levelfor this task or any of its sub tasks. 3053: ) 3054: 3055: singlePattern('_alertsummaries') 3056: descr(The headlines and the summary message from the journal entries that caused thecurrent alert level to be larger than the default for this task or any of itssub tasks. 3057: ) 3058: 3059: singlePattern('_alerttrend') 3060: descr(Shows how the alert level at the end of the report period compares to thealert level at the begining of the report period. Possible values are up, downor flat. 3061: ) 3062: 3063: singlePattern('_chart') 3064: descr(A Gantt chart. This column type requires all lines to have the same fixedheight. This does not work well with rich text columns in some browsers. Someshow a scrollbar for the compressed table cells, others don't. It isrecommended, that you don't use rich text columns in conjuction with the chartcolumn. 3065: ) 3066: 3067: singlePattern('_complete') 3068: descr('The completion degree of a task') 3069: 3070: pattern([ '_completed' ], lambda { 3071: 'complete' 3072: }) 3073: descr('Deprecated alias for complete') 3074: 3075: singlePattern('_criticalness') 3076: descr('A measure for how much effort the resource is allocated for, or' + 3077: 'how strained the allocated resources of a task are') 3078: 3079: singlePattern('_cost') 3080: descr(The cost of the task or resource. The use of this column requires that a costaccount has been set for the report using the [[balance]] attribute. 3081: ) 3082: 3083: singlePattern('_daily') 3084: descr('A group of columns with one column for each day') 3085: 3086: singlePattern('_directreports') 3087: descr(The resources that have this resource assigned as manager.The list can be customized by the [listitem.column listitem] attribute. 3088: ) 3089: 3090: singlePattern('_duration') 3091: descr('The duration of a task') 3092: 3093: singlePattern('_duties') 3094: descr('List of tasks that the resource is allocated to') 3095: 3096: singlePattern('_efficiency') 3097: descr('Measure for how efficient a resource can perform tasks') 3098: 3099: singlePattern('_effort') 3100: descr('The allocated effort during the reporting period') 3101: 3102: singlePattern('_effortdone') 3103: descr('The already completed effort as of now') 3104: 3105: singlePattern('_effortleft') 3106: descr('The remaining allocated effort as of now') 3107: 3108: singlePattern('_email') 3109: descr('The email address of a resource') 3110: 3111: singlePattern('_end') 3112: descr('The end date of a task') 3113: 3114: singlePattern('_flags') 3115: descr('List of attached flags') 3116: 3117: singlePattern('_followers') 3118: descr(A list of tasks that depend on the current task. The list contains the names,the IDs, the date and the type of dependency. For the type the followingsymbols are used for <nowiki><dep></nowiki>.* '''<nowiki>]->[</nowiki>''': End-to-Start dependency* '''<nowiki>[->[</nowiki>''': Start-to-Start dependency* '''<nowiki>]->]</nowiki>''': End-to-End dependency* '''<nowiki>[->]</nowiki>''': Start-to-End dependencyThe list can be customized by the [listitem.column listitem] attribute.The dependency symbol can be generated via the ''''dependency'''' attributeinthe query, the target date via the ''''date'''' attribute. 3119: ) 3120: 3121: singlePattern('_freetime') 3122: descr(The amount of unallocated work time of a resource during the reporting period. 3123: ) 3124: 3125: singlePattern('_freework') 3126: descr(The amount of unallocated work capacity of a resource during the reportingperiod. This is the product of unallocated work time times the efficiency ofthe resource. 3127: ) 3128: 3129: singlePattern('_fte') 3130: descr('The Full-Time-Equivalent of a resource or group') 3131: 3132: singlePattern('_headcount') 3133: descr('The headcount number of the resource or group') 3134: 3135: pattern([ '_hierarchindex' ], lambda { 3136: 'bsi' 3137: }) 3138: descr('Deprecated alias for bsi') 3139: 3140: singlePattern('_hourly') 3141: descr('A group of columns with one column for each hour') 3142: 3143: singlePattern('_id') 3144: descr('The id of the item') 3145: 3146: singlePattern('_index') 3147: descr('The index of the item based on the nesting hierachy') 3148: 3149: singlePattern('_inputs') 3150: descr(A list of milestones that are a prerequiste for the current task. Forcontainer tasks it will also include the inputs of the child tasks. Inputs maynot have any predecessors.The list can be customized by the [listitem.column listitem] attribute. 3151: ) 3152: 3153: singlePattern('_journal') 3154: descr(The journal entries for the task or resource for the reported interval. 3155: ) 3156: 3157: singlePattern('_journal_sub') 3158: descr(The journal entries for the task or resource and all its subtasks or resourcesfor the reported interval. 3159: ) 3160: 3161: singlePattern('_journalmessages') 3162: descr(The headlines, the summary and the details of the message from the journalentries that caused the current alert level for this task. 3163: ) 3164: 3165: singlePattern('_journalsummaries') 3166: descr(The headlines and the summary message from the journal entries that caused thecurrent alert level for this task. 3167: ) 3168: 3169: singlePattern('_line') 3170: descr('The line number in the report') 3171: 3172: singlePattern('_managers') 3173: descr(A list of managers that the resource reports to.The list can be customized by the [listitem.column listitem] attribute. 3174: ) 3175: 3176: singlePattern('_maxend') 3177: descr('The latest allowed end of a task') 3178: 3179: singlePattern('_maxstart') 3180: descr('The lastest allowed start of a task') 3181: 3182: singlePattern('_minend') 3183: descr('The earliest allowed end of a task') 3184: 3185: singlePattern('_minstart') 3186: descr('The earliest allowed start of a task') 3187: 3188: singlePattern('_monthly') 3189: descr('A group of columns with one column for each month') 3190: 3191: singlePattern('_no') 3192: descr('The object line number in the report (Cannot be used for sorting!)') 3193: 3194: singlePattern('_name') 3195: descr('The name or description of the item') 3196: 3197: singlePattern('_note') 3198: descr('The note attached to a task') 3199: 3200: singlePattern('_pathcriticalness') 3201: descr('The criticalness of the task with respect to all the paths that ' + 3202: 'it is a part of.') 3203: 3204: singlePattern('_precursors') 3205: descr(A list of tasks the current task depends on. The list contains the names, theIDs, the date and the type of dependency. For the type the following symbolsare used* '''<nowiki>]->[</nowiki>''': End-to-Start dependency* '''<nowiki>[->[</nowiki>''': Start-to-Start dependency* '''<nowiki>]->]</nowiki>''': End-to-End dependency* '''<nowiki>[->]</nowiki>''': Start-to-End dependencyThe list can be customized by the [listitem.column listitem] attribute.The dependency symbol can be generated via the ''''dependency'''' attributeinthe query, the target date via the ''''date'''' attribute. 3206: ) 3207: 3208: singlePattern('_priority') 3209: descr('The priority of a task') 3210: 3211: singlePattern('_quarterly') 3212: descr('A group of columns with one column for each quarter') 3213: 3214: singlePattern('_rate') 3215: descr('The daily cost of a resource.') 3216: 3217: singlePattern('_reports') 3218: descr(All resources that have this resource assigned as a direct or indirect manager.The list can be customized by the [listitem.column listitem] attribute. 3219: ) 3220: 3221: singlePattern('_resources') 3222: descr(A list of resources that are assigned to the task in the report time frame.The list can be customized by the [listitem.column listitem] attribute. 3223: ) 3224: 3225: singlePattern('_responsible') 3226: descr(The responsible people for this task.The list can be customized by the [listitem.column listitem] attribute. 3227: ) 3228: 3229: singlePattern('_revenue') 3230: descr(The revenue of the task or resource. The use of this column requires that arevenue account has been set for the report using the [[balance]] attribute. 3231: ) 3232: 3233: singlePattern('_scenario') 3234: descr('The name of the scenario') 3235: 3236: singlePattern('_seqno') 3237: descr('The index of the item based on the declaration order') 3238: 3239: singlePattern('_start') 3240: descr('The start date of the task') 3241: 3242: singlePattern('_status') 3243: descr(The status of a task. It is determined based on the current date or the datespecified by [[now]]. 3244: ) 3245: 3246: singlePattern('_targets') 3247: descr(A list of milestones that depend on the current task. For container tasks itwill also include the targets of the child tasks. Targets may not have anyfollower tasks.The list can be customized by the [listitem.column listitem] attribute. 3248: ) 3249: 3250: pattern([ '_wbs' ], lambda { 3251: 'bsi' 3252: }) 3253: descr('Deprecated alias for bsi.') 3254: 3255: singlePattern('_bsi') 3256: descr('The hierarchical or work breakdown structure index') 3257: 3258: singlePattern('_weekly') 3259: descr('A group of columns with one column for each week') 3260: 3261: singlePattern('_yearly') 3262: descr('A group of columns with one column for each year') 3263: 3264: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 3813 3813: def rule_resource 3814: pattern(%( !resourceHeader !resourceBody ), lambda { 3815: @property = @property.parent 3816: }) 3817: doc('resource', Tasks that have an effort specification need to have at least one resourceassigned to do the work. Use this property to define resources or groups ofresources.Resources have a global name space. All IDs must be unique within the resourcesof the project. 3818: ) 3819: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 3828 3828: def rule_resourceAttributes 3829: repeatable 3830: optional 3831: pattern(%( _email $STRING ), lambda { 3832: @property.set('email', @val[1]) 3833: }) 3834: doc('email', 3835: 'The email address of the resource.') 3836: 3837: pattern(%( !journalEntry )) 3838: pattern(%( !purge )) 3839: pattern(%( !resource )) 3840: pattern(%( !resourceScenarioAttributes )) 3841: pattern(%( !scenarioIdCol !resourceScenarioAttributes ), lambda { 3842: @scenarioIdx = 0 3843: }) 3844: 3845: pattern(%( _supplement !resourceId !resourceBody ), lambda { 3846: @property = @property.parent 3847: }) 3848: doc('supplement.resource', The supplement keyword provides a mechanism to add more attributes to alreadydefined resources. The additional attributes must obey the same rules as inregular resource definitions and must be enclosed by curly braces.This construct is primarily meant for situations where the information about aresource is split over several files. E. g. the vacation dates for theresources may be in a separate file that was generated by some other tool. 3849: ) 3850: example('Supplement', 'resource') 3851: 3852: # Other attributes will be added automatically. 3853: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 3863 3863: def rule_resourceBody 3864: optionsRule('resourceAttributes') 3865: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 3867 3867: def rule_resourceBooking 3868: pattern(%( !resourceBookingHeader !bookingBody ), lambda { 3869: unless @project.scenario(@scenarioIdx).get('ownbookings') 3870: error('no_own_resource_booking', 3871: "The scenario #{@project.scenario(@scenarioIdx).fullId} " + 3872: 'inherits its bookings from the tracking ' + 3873: 'scenario. You cannot specificy additional bookings for it.') 3874: end 3875: @val[0].task.addBooking(@scenarioIdx, @val[0]) 3876: }) 3877: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 3879 3879: def rule_resourceBookingHeader 3880: pattern(%( !taskId !valIntervals ), lambda { 3881: checkBooking(@val[0], @property) 3882: @booking = Booking.new(@property, @val[0], @val[1]) 3883: @booking.sourceFileInfo = @sourceFileInfo[0] 3884: @booking 3885: }) 3886: arg(0, 'id', 'Absolute ID of a defined task') 3887: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 3901 3901: def rule_resourceHeader 3902: pattern(%( _resource !optionalID $STRING ), lambda { 3903: if @property.nil? && !@resourceprefix.empty? 3904: @property = @project.resource(@resourceprefix) 3905: end 3906: if @val[1] && @project.resource(@val[1]) 3907: error('resource_exists', 3908: "Resource #{@val[1]} has already been defined.", 3909: @sourceFileInfo[1], @property) 3910: end 3911: @property = Resource.new(@project, @val[1], @val[2], @property) 3912: @property.sourceFileInfo = @sourceFileInfo[0] 3913: @property.inheritAttributes 3914: @scenarioIdx = 0 3915: }) 3916: # arg(1, 'id', <<'EOT' 3917: #The ID of the resource. Resources have a global name space. The ID must be 3918: #unique within the whole project. 3919: #EOT 3920: # ) 3921: arg(2, 'name', 'The name of the resource') 3922: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 3889 3889: def rule_resourceId 3890: pattern(%( $ID ), lambda { 3891: id = (@resourceprefix.empty? ? '' : @resourceprefix + '.') + @val[0] 3892: if (resource = @project.resource(id)).nil? 3893: error('resource_id_expected', "#{id} is not a defined resource.", 3894: @sourceFileInfo[0]) 3895: end 3896: resource 3897: }) 3898: arg(0, 'resource', 'The ID of a defined resource') 3899: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 3924 3924: def rule_resourceLeafList 3925: pattern(%( !leafResourceId !moreLeafResources ), lambda { 3926: [ @val[0] ] + (@val[1].nil? ? [] : @val[1]) 3927: }) 3928: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 3930 3930: def rule_resourceList 3931: listRule('moreResources', '!resourceId') 3932: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 3934 3934: def rule_resourceScenarioAttributes 3935: pattern(%( _efficiency !number ), lambda { 3936: @property['efficiency', @scenarioIdx] = @val[1] 3937: }) 3938: doc('efficiency', The efficiency of a resource can be used for two purposes. First you can useit as a crude way to model a team. A team of 5 people should have anefficiency of 5.0. Keep in mind that you cannot track the members of the teamindividually if you use this feature. They always act as a group.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.All resources that do not contribute effort to the task, should have anefficiency of 0.0. A typical example would be a conference room. It's necessary for a meeting, but it does not contribute any work. 3939: ) 3940: example('Efficiency') 3941: pattern(%( !flags )) 3942: doc('flags.resource', Attach a set of flags. The flags can be used in logical expressions to filterproperties from the reports. 3943: ) 3944: 3945: pattern(%( _booking !resourceBooking )) 3946: doc('booking.resource', The booking attribute can be used to report actually completed work. A taskwith bookings must be [[scheduling|scheduled]] in ''''asap'''' mode. If thescenario is not the [[trackingscenario|tracking scenario]] or derived from it,the scheduler will not allocate resources prior to the current date or thedate specified with [[now]] when a task has at least one booking.Bookings are only valid in the scenario they have been defined in. They willin general not be passed to any other scenario. If you have defined a[[trackingscenario|tracking scenario]], the bookings of this scenario will bepassed to all the derived scenarios of the tracking scenario.The sloppy attribute can be used when you want to skip non-working time orother allocations automatically. If it's not given, all bookings must onlycover working time for the resource.The booking attributes is designed to capture the exact amount of completedwork. This attribute is not really intended to specify completed effort byhand. Usually, booking statements are generated by [[export]] reports. The[[sloppy.booking|sloppy]] and [[overtime.booking|overtime]] attributes areonly kludge for users who want to write them manually.Bookings can be used to report already completed work by specifying the exacttime intervals a certain resource has worked on this task.Bookings can be defined in the task or resource context. If you move tasksaround very often, put your bookings in the task context. 3947: ) 3948: also(%( scheduling booking.task )) 3949: example('Booking') 3950: 3951: pattern(%( !fail )) 3952: 3953: pattern(%( !limits ), lambda { 3954: @property['limits', @scenarioIdx] = @val[0] 3955: }) 3956: doc('limits.resource', Set per-interval usage limits for the resource. 3957: ) 3958: example('Limits-1', '6') 3959: 3960: pattern(%( _managers !resourceList ), lambda { 3961: @property['managers', @scenarioIdx] = 3962: @property['managers', @scenarioIdx] + @val[1] 3963: }) 3964: doc('managers', Defines one or more resources to be the manager who is responsible for thisresource. Managers must be leaf resources. This attribute does not impact thescheduling. It can only be used for documentation purposes.You must only specify direct managers here. Do not list higher level managershere. If necessary, use the [[purge]] attribute to clearinherited managers. For most use cases, there should be only one manager. ButTaskJuggler is not limited to just one manager. Dotted reporting lines can becaptured as well as long as the managers are not reporting to each other. 3965: ) 3966: also(%( statussheet )) 3967: example('Manager') 3968: 3969: 3970: pattern(%( _rate !number ), lambda { 3971: @property['rate', @scenarioIdx] = @val[1] 3972: }) 3973: doc('rate.resource', The rate specifies the daily cost of the resource. 3974: ) 3975: 3976: pattern(%( _shift !shiftAssignments )) 3977: doc('shift.resource', This keyword has been deprecated. Please use [[shifts.resource|shifts(resource)]] instead. 3978: ) 3979: 3980: pattern(%( _shifts !shiftAssignments )) 3981: doc('shifts.resource', Limits the working time of a resource to a defined shift during the specifiedinterval. Multiple shifts can be defined, but shift intervals may not overlap.In case a shift is defined for a certain interval, the shift working hoursreplace the standard resource working hours for this interval. 3982: ) 3983: 3984: pattern(%( _vacation !vacationName !intervals ), lambda { 3985: begin 3986: @property['vacations', @scenarioIdx] = 3987: @property['vacations', @scenarioIdx ] + @val[2] 3988: rescue AttributeOverwrite 3989: end 3990: }) 3991: doc('vacation.resource', Specify a vacation period for the resource. It can also be used to block outthe time before a resource joined or after it left. For employees changingtheir work schedule from full-time to part-time, or vice versa, please referto the 'Shift' property. 3992: ) 3993: 3994: pattern(%( !warn )) 3995: 3996: pattern(%( !workinghoursResource )) 3997: # Other attributes will be added automatically. 3998: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 4066 4066: def rule_rollupresource 4067: pattern(%( _rollupresource !logicalExpression ), lambda { 4068: @property.set('rollupResource', @val[1]) 4069: }) 4070: doc('rollupresource', Do not show sub-resources of resources that match the specified logicalexpression. 4071: ) 4072: example('RollupResource') 4073: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 4078 4078: def rule_rolluptask 4079: pattern(%( _rolluptask !logicalExpression ), lambda { 4080: @property.set('rollupTask', @val[1]) 4081: }) 4082: doc('rolluptask', Do not show sub-tasks of tasks that match the specified logical expression. 4083: ) 4084: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 4089 4089: def rule_scenario 4090: pattern(%( !scenarioHeader !scenarioBody ), lambda { 4091: @property = @property.parent 4092: }) 4093: doc('scenario', Defines a new project scenario. By default, the project has only one scenariocalled ''''plan''''. To do plan vs. actual comparisons or to do awhat-if-analysis, you can define a set of scenarios. There can only be onetop-level scenario. Additional scenarios are either derived from thistop-level scenario or other scenarios.Each nested scenario is a variation of the enclosing scenario. All scenariosshare the same set of properties (task, resources, etc.) but the attributesthat are listed as scenario specific may differ between the variousscenarios. A nested scenario uses all attributes from the enclosing scenariounless the user has specified a different value for this attribute.By default, the scheduler assigns resources to task beginning with the projectstart date. If the scenario is switched to projection mode, no assignmentswill be made prior to the current date or the date specified by [[now]]. Inthis case, TaskJuggler assumes, that all assignements prior to thecurrent date have been provided by [[booking.task]] statements. 4094: ) 4095: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 4115 4115: def rule_scenarioAttributes 4116: optional 4117: repeatable 4118: 4119: pattern(%( _active !yesNo), lambda { 4120: @property.set('active', @val[1]) 4121: }) 4122: doc('active', Enable the scenario to be scheduled or not. By default, all scenarios will bescheduled. If a scenario is marked as inactive, it not be scheduled and willbe ignored in the reports. 4123: ) 4124: pattern(%( _disabled ), lambda { 4125: @property.set('active', false) 4126: }) 4127: doc('disabled', This attribute is deprecated. Please use [active] instead.Disable the scenario for scheduling. The default for the top-levelscenario is to be enabled. 4128: ) 4129: example('Scenario') 4130: pattern(%( _enabled ), lambda { 4131: @property.set('active', true) 4132: }) 4133: doc('enabled', This attribute is deprecated. Please use [active] instead.Enable the scenario for scheduling. This is the default for the top-levelscenario. 4134: ) 4135: 4136: pattern(%( _projection !projection ), lambda { 4137: warning('projection', 4138: 'The \projection\ keyword has been deprecated. Please use ' + 4139: '[[trackingscenario]] feature instead.') 4140: }) 4141: doc('projection', This keyword has been deprecated! Don't use it anymore!Projection mode is now automatically enabled as soon as a scenario hasbookings. 4142: ) 4143: 4144: pattern(%( !scenario )) 4145: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 4166 4166: def rule_scenarioBody 4167: optionsRule('scenarioAttributes') 4168: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 4170 4170: def rule_scenarioHeader 4171: 4172: pattern(%( _scenario $ID $STRING ), lambda { 4173: # If this is the top-level scenario, we must delete the default scenario 4174: # first. 4175: @project.scenarios.clearProperties if @property.nil? 4176: if @project.scenario(@val[1]) 4177: error('scenario_exists', 4178: "Scenario #{@val[1]} has already been defined.", 4179: @sourceFileInfo[1]) 4180: end 4181: @property = Scenario.new(@project, @val[1], @val[2], @property) 4182: @property.inheritAttributes 4183: }) 4184: arg(1, 'id', 'The ID of the scenario') 4185: arg(2, 'name', 'The name of the scenario') 4186: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 4188 4188: def rule_scenarioId 4189: pattern(%( $ID ), lambda { 4190: if (@scenarioIdx = @project.scenarioIdx(@val[0])).nil? 4191: error('unknown_scenario_id', "Unknown scenario: #{@val[0]}", 4192: @sourceFileInfo[0]) 4193: end 4194: @scenarioIdx 4195: }) 4196: arg(0, 'scenario', 'ID of a defined scenario') 4197: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 4199 4199: def rule_scenarioIdCol 4200: pattern(%( $ID_WITH_COLON ), lambda { 4201: if (@scenarioIdx = @project.scenarioIdx(@val[0])).nil? 4202: error('unknown_scenario_id', "Unknown scenario: @val[0]", 4203: @sourceFileInfo[0]) 4204: end 4205: }) 4206: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 4208 4208: def rule_scenarioIdList 4209: listRule('moreScnarioIdList', '!scenarioIdx') 4210: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 4212 4212: def rule_scenarioIdx 4213: pattern(%( $ID ), lambda { 4214: if (scenarioIdx = @project.scenarioIdx(@val[0])).nil? 4215: error('unknown_scenario_idx', "Unknown scenario #{@val[0]}", 4216: @sourceFileInfo[0]) 4217: end 4218: scenarioIdx 4219: }) 4220: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 4222 4222: def rule_schedulingDirection 4223: singlePattern('_alap') 4224: singlePattern('_asap') 4225: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 4227 4227: def rule_shift 4228: pattern(%( !shiftHeader !shiftBody ), lambda { 4229: @property = @property.parent 4230: }) 4231: doc('shift', A shift combines several workhours related settings in a reusable entity.Besides the weekly working hours it can also hold information such asvacations and a time zone.Shifts have a global name space. All IDs must be unique within the shifts ofthe project. 4232: ) 4233: also(%( shifts.task shifts.resource )) 4234: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 4243 4243: def rule_shiftAssignment 4244: pattern(%( !shiftId !intervalsOptional ), lambda { 4245: # Make sure we have a ShiftAssignment for the property. 4246: sa = @property['shifts', @scenarioIdx] || ShiftAssignments.new 4247: sa.project = @project 4248: 4249: if @val[1].nil? 4250: intervals = [ Interval.new(@project['start'], @project['end']) ] 4251: else 4252: intervals = @val[1] 4253: end 4254: intervals.each do |interval| 4255: if !sa.addAssignment(ShiftAssignment.new(@val[0].scenario(@scenarioIdx), 4256: interval)) 4257: error('shift_assignment_overlap', 4258: 'Shifts may not overlap each other.', 4259: @sourceFileInfo[0], @property) 4260: end 4261: end 4262: # Set same value again to set the 'provided' state for the attribute. 4263: begin 4264: @property['shifts', @scenarioIdx] = sa 4265: rescue AttributeOverwrite 4266: # Multiple shift assignments are a common idiom, so don't warn about 4267: # them. 4268: end 4269: }) 4270: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 4272 4272: def rule_shiftAssignments 4273: listRule('moreShiftAssignments', '!shiftAssignment') 4274: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 4276 4276: def rule_shiftAttributes 4277: optional 4278: repeatable 4279: 4280: pattern(%( !shift )) 4281: pattern(%( !shiftScenarioAttributes )) 4282: pattern(%( !scenarioIdCol !shiftScenarioAttributes ), lambda { 4283: @scenarioIdx = 0 4284: }) 4285: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 4287 4287: def rule_shiftBody 4288: optionsRule('shiftAttributes') 4289: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 4291 4291: def rule_shiftHeader 4292: pattern(%( _shift !optionalID $STRING ), lambda { 4293: if @val[1] && @project.shift(@val[1]) 4294: error('shift_exists', "Shift #{@val[1]} has already been defined.", 4295: @sourceFileInfo[1]) 4296: end 4297: @property = Shift.new(@project, @val[1], @val[2], @property) 4298: @property.sourceFileInfo = @sourceFileInfo[0] 4299: @property.inheritAttributes 4300: @scenarioIdx = 0 4301: }) 4302: arg(2, 'name', 'The name of the shift') 4303: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 4305 4305: def rule_shiftId 4306: pattern(%( $ID ), lambda { 4307: if (shift = @project.shift(@val[0])).nil? 4308: error('shift_id_expected', "#{@val[0]} is not a defined shift.", 4309: @sourceFileInfo[0]) 4310: end 4311: shift 4312: }) 4313: arg(0, 'shift', 'The ID of a defined shift') 4314: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 4316 4316: def rule_shiftScenarioAttributes 4317: pattern(%( _replace ), lambda { 4318: @property['replace', @scenarioIdx] = true 4319: }) 4320: doc('replace', 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. 4321: ) 4322: 4323: pattern(%( _timezone !validTimeZone ), lambda { 4324: @property['timezone', @scenarioIdx] = @val[1] 4325: }) 4326: doc('timezone.shift', Sets the time zone of the shift. The working hours of the shift are assumed tobe within the specified time zone. The time zone does not effect the vactioninterval. The latter is assumed to be within the project time zone.TaskJuggler stores all dates internally as UTC. Since all events must alignwith the [[timingresolution|timing resolution]] for time zones you may have tochange the timing resolution appropriately. The time zone difference comparedto UTC must be a multiple of the used timing resolution. 4327: ) 4328: arg(1, 'zone', Time zone to use. E. g. 'Europe/Berlin' or 'America/Denver'. Don't use the 3letter acronyms. See[http://en.wikipedia.org/wiki/List_of_zoneinfo_time_zones Wikipedia] forpossible values. 4329: ) 4330: 4331: pattern(%( _vacation !vacationName !intervalsOptional ), lambda { 4332: @property['vacations', @scenarioIdx] = 4333: @property['vacations', @scenarioIdx ] + @val[2] 4334: }) 4335: doc('vacation.shift', Specify a vacation period associated with this shift. 4336: ) 4337: 4338: pattern(%( !workinghoursShift )) 4339: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 4359 4359: def rule_sortCriteria 4360: pattern([ "!sortCriterium", "!moreSortCriteria" ], lambda { 4361: [ @val[0] ] + (@val[1].nil? ? [] : @val[1]) 4362: }) 4363: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 4365 4365: def rule_sortCriterium 4366: pattern(%( !sortTree ), lambda { 4367: @val[0] 4368: }) 4369: pattern(%( !sortNonTree ), lambda { 4370: @val[0] 4371: }) 4372: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 4374 4374: def rule_sortNonTree 4375: pattern(%( $ABSOLUTE_ID ), lambda { 4376: args = @val[0].split('.') 4377: case args.length 4378: when 2 4379: # <attribute>.<up|down> 4380: scenario = 1 4381: direction = args[1] == 'up' 4382: attribute = args[0] 4383: when 3 4384: # <scenario>.<attribute>.<up|down> 4385: if (scenario = @project.scenarioIdx(args[0])).nil? 4386: error('sort_unknown_scen', 4387: "Unknown scenario #{args[0]} in sorting criterium", 4388: @sourceFileInfo[0]) 4389: end 4390: attribute = args[1] 4391: if args[2] != 'up' && args[2] != 'down' 4392: error('sort_direction', "Sorting direction must be 'up' or 'down'", 4393: @sourceFileInfo[0]) 4394: end 4395: direction = args[2] == 'up' 4396: else 4397: error('sorting_crit_exptd1', 4398: "Sorting criterium expected (e.g. tree, start.up or " + 4399: "plan.end.down).", @sourceFileInfo[0]) 4400: end 4401: if attribute == 'bsi' 4402: error('sorting_bsi', 4403: "Sorting by bsi is not supported. Please use 'tree' " + 4404: '(without appended .up or .down) instead.', 4405: @sourceFileInfo[0]) 4406: end 4407: [ attribute, direction, scenario ] 4408: }) 4409: arg(0, 'criteria', The sorting criteria must consist of a property attribute ID. See [[columnid]]for a complete list of available attributes. The ID must be suffixed by '.up'or '.down' to determine the sorting direction. Optionally the ID may beprefixed with a scenario ID and a dot to determine the scenario that should beused for sorting. So, possible values are 'plan.start.up' or 'priority.down'. 4410: ) 4411: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 4419 4419: def rule_sortResources 4420: pattern(%( _sortresources !sortCriteria ), lambda { 4421: @property.set('sortResources', @val[1]) 4422: }) 4423: doc('sortresources', Determines how the resources are sorted in the report. Multiple criteria can bespecified as a comma separated list. If one criteria is not sufficient to sorta group of resources, the next criteria will be used to sort the resources inthis group. 4424: ) 4425: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 4432 4432: def rule_sortTasks 4433: pattern(%( _sorttasks !sortCriteria ), lambda { 4434: @property.set('sortTasks', @val[1]) 4435: }) 4436: doc('sorttasks', Determines how the tasks are sorted in the report. Multiple criteria can bespecified as comma separated list. If one criteria is not sufficient to sort agroup of tasks, the next criteria will be used to sort the tasks withinthis group. 4437: ) 4438: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 4445 4445: def rule_sortTree 4446: pattern(%( $ID ), lambda { 4447: if @val[0] != 'tree' 4448: error('sorting_crit_exptd2', 4449: "Sorting criterium expected (e.g. tree, start.up or " + 4450: "plan.end.down).", @sourceFileInfo[0]) 4451: end 4452: [ 'tree', true, 1 ] 4453: }) 4454: arg(0, 'tree', 4455: 'Use \tree\ as first criteria to keep the breakdown structure.') 4456: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 4486 4486: def rule_ssReportAttributes 4487: optional 4488: repeatable 4489: 4490: pattern(%( !hideresource )) 4491: pattern(%( !hidetask )) 4492: pattern(%( !reportEnd )) 4493: pattern(%( !reportPeriod )) 4494: pattern(%( !reportStart )) 4495: pattern(%( !sortResources )) 4496: pattern(%( !sortTasks )) 4497: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 4499 4499: def rule_ssReportBody 4500: optionsRule('ssReportAttributes') 4501: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 4457 4457: def rule_ssReportHeader 4458: pattern(%( _statussheetreport !optionalID $STRING ), lambda { 4459: if (fileName = @val[2]) != '.' 4460: if @project.reports[fileName] 4461: error('report_redefinition', 4462: "A report with the name '#{fileName}' has already been " + 4463: "defined.", @sourceFileInfo[2]) 4464: end 4465: else 4466: fileName = "statusSheet#{@project.reports.length + 1}" 4467: end 4468: report = newReport(@val[1], fileName, :statusSheet, sourceFileInfo) 4469: report.set('scenarios', [ 0 ]) 4470: # Show all tasks, sorted by id-up. 4471: report.set('hideTask', LogicalExpression.new(LogicalOperation.new(0))) 4472: report.set('sortTasks', [ [ 'id', true, 1 ] ]) 4473: # Show all resources, sorted by seqno-up. 4474: report.set('hideResource', LogicalExpression.new(LogicalOperation.new(0))) 4475: report.set('sortResources', [ [ 'seqno', true, 1 ] ]) 4476: report.set('loadUnit', :hours) 4477: report.set('definitions', []) 4478: }) 4479: arg(1, 'file name', The name of the status sheet report file to generate. It must end with a .tjiextension, or use . to use the standard output channel. 4480: ) 4481: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 4542 4542: def rule_ssStatus 4543: pattern(%( !ssStatusHeader !ssStatusBody )) 4544: doc('status.statussheet', The status attribute can be used to describe the current status of the task orresource. The content of the status messages is added to the project journal. 4545: ) 4546: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 4503 4503: def rule_ssStatusAttributes 4504: optional 4505: repeatable 4506: 4507: pattern(%( !author )) 4508: pattern(%( !details )) 4509: 4510: pattern(%( _flags !flagList ), lambda { 4511: @val[1].each do |flag| 4512: next if @journalEntry.flags.include?(flag) 4513: 4514: @journalEntry.flags << flag 4515: end 4516: }) 4517: doc('flags.statussheet', Status sheet entries can have flags attached to them. These can be used toinclude only entries in a report that have a certain flag. 4518: ) 4519: 4520: pattern(%( !summary )) 4521: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 4526 4526: def rule_ssStatusBody 4527: optional 4528: pattern(%( _{ !ssStatusAttributes _} )) 4529: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 4531 4531: def rule_ssStatusHeader 4532: pattern(%( _status !alertLevel $STRING ), lambda { 4533: @journalEntry = JournalEntry.new(@project['journal'], @sheetEnd, 4534: @val[2], @property, 4535: @sourceFileInfo[0]) 4536: @journalEntry.alertLevel = @val[1] 4537: @journalEntry.author = @sheetAuthor 4538: 4539: }) 4540: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 4551 4551: def rule_statusSheet 4552: pattern(%( !statusSheetHeader !statusSheetBody ), lambda { 4553: [ @sheetAuthor, @sheetStart, @sheetEnd ] 4554: }) 4555: doc('statussheet', A status sheet can be used to capture the status of various tasks outside ofthe regular task tree definition. It is intended for use by managers thatdon't directly work with the full project plan, but need to report the currentstatus of each task or task-tree that they are responsible for. 4556: ) 4557: example('StatusSheet') 4558: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 4565 4565: def rule_statusSheetAttributes 4566: optional 4567: repeatable 4568: 4569: pattern(%( !statusSheetTask )) 4570: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 4572 4572: def rule_statusSheetBody 4573: optionsRule('statusSheetAttributes') 4574: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 4576 4576: def rule_statusSheetFile 4577: pattern(%( !statusSheet . ), lambda { 4578: @val[0] 4579: }) 4580: lastSyntaxToken(1) 4581: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 4584 4584: def rule_statusSheetHeader 4585: pattern(%( _statussheet !resourceId !valIntervalOrDate ), lambda { 4586: unless (scenarioIdx = @project['trackingScenarioIdx']) 4587: error('ss_no_tracking_scenario', 4588: 'No trackingscenario defined.') 4589: end 4590: @sheetAuthor = @val[1] 4591: @sheetStart = @val[2].start 4592: @sheetEnd = @val[2].end 4593: }) 4594: arg(1, 'reporter', The ID of a defined resource. This identifies the status reporter. Unless thestatus entries provide a different author, the sheet author will be used asstatus entry author. 4595: ) 4596: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 4602 4602: def rule_statusSheetReport 4603: pattern(%( !ssReportHeader !ssReportBody ), lambda { 4604: @property = nil 4605: }) 4606: doc('statussheetreport', A status sheet report is a template for a status sheet. It collects all thestatus information of the top-level task that a resource is responsible for.This report is typically used by managers or team leads to review the timesheet status information and destill it down to a summary that can beforwarded to the next person in the reporting chain. The report will be forthe specified [trackingscenario]. 4607: ) 4608: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 4617 4617: def rule_statusSheetTask 4618: pattern(%( !statusSheetTaskHeader !statusSheetTaskBody), lambda { 4619: @property = @propertyStack.pop 4620: }) 4621: doc('task.statussheet', Opens the task with the specified ID to add a status report. Child task can beopened inside this context by specifying their relative ID to this parent. 4622: ) 4623: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 4628 4628: def rule_statusSheetTaskAttributes 4629: optional 4630: repeatable 4631: pattern(%( !ssStatus )) 4632: pattern(%( !statusSheetTask ), lambda { 4633: }) 4634: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 4636 4636: def rule_statusSheetTaskBody 4637: optionsRule('statusSheetTaskAttributes') 4638: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 4640 4640: def rule_statusSheetTaskHeader 4641: pattern(%( _task !taskId ), lambda { 4642: if @property 4643: @propertyStack.push(@property) 4644: else 4645: @propertyStack = [] 4646: end 4647: @property = @val[1] 4648: }) 4649: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 4651 4651: def rule_subNodeId 4652: optional 4653: pattern(%( _: !idOrAbsoluteId ), lambda { 4654: @val[1] 4655: }) 4656: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 4658 4658: def rule_summary 4659: pattern(%( _summary $STRING ), lambda { 4660: return if @val[1].empty? 4661: 4662: if @val[1].length > 480 4663: error('ts_summary_too_long', 4664: "The summary text must be 480 characters long or shorter. " + 4665: "This text has #{@val[1].length} characters.", 4666: @sourceFileInfo[1]) 4667: end 4668: if @val[1] == "A summary text\n" 4669: error('ts_default_summary', 4670: "'A summary text' is not a valid summary", 4671: @sourceFileInfo[1]) 4672: end 4673: rtTokenSetIntro = 4674: [ :LINEBREAK, :SPACE, :WORD, :BOLD, :ITALIC, :CODE, :BOLDITALIC, 4675: :HREF, :HREFEND ] 4676: @journalEntry.summary = newRichText(@val[1], @sourceFileInfo[1], 4677: rtTokenSetIntro) 4678: }) 4679: doc('summary', This is the introductory part of the journal or status entry. It shouldonly summarize the full entry but should contain more details than theheadline. The text including formatting characters must be 240 characters longor less. 4680: ) 4681: arg(1, 'text', The text will be interpreted as [[Rich_Text_Attributes|Rich Text]]. Only asmall subset of the markup is supported for this attribute. You can use wordformatting, hyperlinks and paragraphs. 4682: ) 4683: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 4694 4694: def rule_supplement 4695: pattern(%( !supplementAccount !accountBody ), lambda { 4696: @property = nil 4697: }) 4698: pattern(%( !supplementReport !reportBody ), lambda { 4699: @property = nil 4700: }) 4701: pattern(%( !supplementResource !resourceBody ), lambda { 4702: @property = nil 4703: }) 4704: pattern(%( !supplementTask !taskBody ), lambda { 4705: @property = nil 4706: }) 4707: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 4709 4709: def rule_supplementAccount 4710: pattern(%( _account !accountId ), lambda { 4711: @property = @val[1] 4712: }) 4713: arg(1, 'account ID', 'The ID of an already defined account.') 4714: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 4716 4716: def rule_supplementReport 4717: pattern(%( _report !reportId ), lambda { 4718: @property = @val[1] 4719: }) 4720: arg(1, 'report ID', 'The ID of an already defined report.') 4721: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 4723 4723: def rule_supplementResource 4724: pattern(%( _resource !resourceId ), lambda { 4725: @property = @val[1] 4726: }) 4727: arg(1, 'resource ID', 'The ID of an already defined resource.') 4728: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 4730 4730: def rule_supplementTask 4731: pattern(%( _task !taskId ), lambda { 4732: @property = @val[1] 4733: }) 4734: arg(1, 'task ID', 'The ID of an already defined task.') 4735: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 4737 4737: def rule_task 4738: pattern(%( !taskHeader !taskBody ), lambda { 4739: @property = @property.parent 4740: }) 4741: doc('task', Tasks are the central elements of a project plan. Use a task to specify thevarious steps and phases of the project. Depending on the attributes of thattask, a task can be a container task, a milestone or a regular leaf task. Thelatter may have resources assigned. By specifying dependencies the user canforce a certain sequence of tasks.Tasks have a local name space. All IDs must be unique within the tasksthat belong to the same enclosing task. 4742: ) 4743: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 4754 4754: def rule_taskAttributes 4755: repeatable 4756: optional 4757: 4758: pattern(%( _adopt !taskList ), lambda { 4759: @val[1].each do |task| 4760: @property.adopt(task) 4761: end 4762: }) 4763: doc('adopt.task', Add a previously defined task to the sub-tasks of this task. This can be usedto create virtual sub projects that contain of task trees that were defined assub tasks of other tasks. Adopted tasks don't inherit anything from their stepparents. However, the adopting task is scheduled to fit all adopted childs aswell.The adopting task and the adopted task must not share a common top-level task.Adopted tasks may not have overlaping sub trees.'''This feature is experimental right now. Don't use it!'''. 4764: ) 4765: 4766: pattern(%( !journalEntry )) 4767: 4768: pattern(%( _note $STRING ), lambda { 4769: @property.set('note', newRichText(@val[1], @sourceFileInfo[1])) 4770: }) 4771: doc('note.task', Attach a note to the task. This is usually a more detailed specification ofwhat the task is about. 4772: ) 4773: 4774: pattern(%( !purge )) 4775: 4776: pattern(%( _supplement !supplementTask !taskBody ), lambda { 4777: @property = @property.parent 4778: }) 4779: doc('supplement.task', The supplement keyword provides a mechanism to add more attributes to alreadydefined tasks. The additional attributes must obey the same rules as inregular task definitions and must be enclosed by curly braces.This construct is primarily meant for situations where the information about atask is split over several files. E. g. the vacation dates for theresources may be in a separate file that was generated by some other tool. 4780: ) 4781: example('Supplement', 'task') 4782: 4783: pattern(%( !task )) 4784: pattern(%( !taskScenarioAttributes )) 4785: pattern(%( !scenarioIdCol !taskScenarioAttributes ), lambda { 4786: @scenarioIdx = 0 4787: }) 4788: # Other attributes will be added automatically. 4789: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 4813 4813: def rule_taskBody 4814: optionsRule('taskAttributes') 4815: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 4817 4817: def rule_taskBooking 4818: pattern(%( !taskBookingHeader !bookingBody ), lambda { 4819: unless @project.scenario(@scenarioIdx).get('ownbookings') 4820: error('no_own_task_booking', 4821: "The scenario #{@project.scenario(@scenarioIdx).fullId} " + 4822: 'inherits its bookings from the tracking ' + 4823: 'scenario. You cannot specificy additional bookings for it.') 4824: end 4825: @val[0].task.addBooking(@scenarioIdx, @val[0]) 4826: }) 4827: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 4829 4829: def rule_taskBookingHeader 4830: pattern(%( !resourceId !valIntervals ), lambda { 4831: checkBooking(@property, @val[0]) 4832: @booking = Booking.new(@val[0], @property, @val[1]) 4833: @booking.sourceFileInfo = @sourceFileInfo[0] 4834: @booking 4835: }) 4836: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 4838 4838: def rule_taskDep 4839: pattern(%( !taskDepHeader !taskDepBody ), lambda { 4840: @val[0] 4841: }) 4842: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 4844 4844: def rule_taskDepAttributes 4845: optional 4846: repeatable 4847: 4848: pattern(%( _gapduration !intervalDuration ), lambda { 4849: @taskDependency.gapDuration = @val[1] 4850: }) 4851: doc('gapduration', Specifies the minimum required gap between the end of a preceding task and thestart of this task, or the start of a following task and the end of this task.This is calendar time, not working time. 7d means one week. 4852: ) 4853: 4854: pattern(%( _gaplength !workingDuration ), lambda { 4855: @taskDependency.gapLength = @val[1] 4856: }) 4857: doc('gaplength', Specifies the minimum required gap between the end of a preceding task and thestart of this task, or the start of a following task and the end of this task.This is working time, not calendar time. 7d means 7 working days, not oneweek. Whether a day is considered a working day or not depends on the definedworking hours and global vacations. 4858: ) 4859: 4860: pattern(%( _onend ), lambda { 4861: @taskDependency.onEnd = true 4862: }) 4863: doc('onend', The target of the dependency is the end of the task. 4864: ) 4865: 4866: pattern(%( _onstart ), lambda { 4867: @taskDependency.onEnd = false 4868: }) 4869: doc('onstart', The target of the dependency is the start of the task. 4870: ) 4871: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 4887 4887: def rule_taskDepBody 4888: optionsRule('taskDepAttributes') 4889: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 4891 4891: def rule_taskDepHeader 4892: pattern(%( !taskDepId ), lambda { 4893: @taskDependency = TaskDependency.new(@val[0], true) 4894: }) 4895: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 4897 4897: def rule_taskDepId 4898: singlePattern('$ABSOLUTE_ID') 4899: arg(0, 'ABSOLUTE ID', A reference using the full qualified ID of a task. The IDs of all enclosingparent tasks must be prepended to the task ID and separated with a dot, e.g.''''proj.plan.doc''''. 4900: ) 4901: 4902: singlePattern('$ID') 4903: arg(0, 'ID', 'Just the ID of the task without and parent IDs.') 4904: 4905: pattern(%( !relativeId ), lambda { 4906: task = @property 4907: id = @val[0] 4908: while task && id[0] == !! 4909: id = id.slice(1, id.length) 4910: task = task.parent 4911: end 4912: error('too_many_bangs', 4913: "Too many '!' for relative task in this context.", 4914: @sourceFileInfo[0], @property) if id[0] == !! 4915: if task 4916: task.fullId + '.' + id 4917: else 4918: id 4919: end 4920: }) 4921: arg(0, 'RELATIVE ID', A relative task ID always starts with one or more exclamation marks and isfollowed by a task ID. Each exclamation mark lifts the scope where the ID islooked for to the enclosing task. The ID may contain some of the parent IDsseparated by dots, e. g. ''''!!plan.doc''''. 4922: ) 4923: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 4934 4934: def rule_taskDepList 4935: pattern(%( !taskDep !moreDepTasks ), lambda { 4936: [ @val[0] ] + (@val[1].nil? ? [] : @val[1]) 4937: }) 4938: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 4940 4940: def rule_taskHeader 4941: pattern(%( _task !optionalID $STRING ), lambda { 4942: if @property.nil? && !@taskprefix.empty? 4943: @property = @project.task(@taskprefix) 4944: end 4945: if @val[1] 4946: id = (@property ? @property.fullId + '.' : '') + @val[1] 4947: if @project.task(id) 4948: error('task_exists', "Task #{id} has already been defined.", 4949: @sourceFileInfo[0]) 4950: end 4951: end 4952: @property = Task.new(@project, @val[1], @val[2], @property) 4953: @property['projectid', 0] = @projectId 4954: @property.sourceFileInfo = @sourceFileInfo[0] 4955: @property.inheritAttributes 4956: @scenarioIdx = 0 4957: }) 4958: arg(2, 'name', 'The name of the task') 4959: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 4961 4961: def rule_taskId 4962: pattern(%( !taskIdUnverifd ), lambda { 4963: id = @val[0] 4964: if @property && @property.is_a?(Task) 4965: # In case we have a nested supplement, we need to prepend the parent ID. 4966: id = @property.fullId + '.' + id 4967: else 4968: id = @taskprefix + '.' + id unless @taskprefix.empty? 4969: end 4970: if (task = @project.task(id)).nil? 4971: error('unknown_task', "Unknown task #{id}", @sourceFileInfo[0]) 4972: end 4973: task 4974: }) 4975: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 4977 4977: def rule_taskIdUnverifd 4978: singlePattern('$ABSOLUTE_ID') 4979: singlePattern('$ID') 4980: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 4982 4982: def rule_taskList 4983: listRule('moreTasks', '!absoluteTaskId') 4984: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 4986 4986: def rule_taskPeriod 4987: pattern(%( _period !valInterval), lambda { 4988: @property['start', @scenarioIdx] = @val[1].start 4989: @property['end', @scenarioIdx] = @val[1].end 4990: }) 4991: doc('period.task', This property is a shortcut for setting the start and end property at the sametime. In contrast to using these, it does not change the scheduling direction. 4992: ) 4993: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 4998 4998: def rule_taskPred 4999: pattern(%( !taskPredHeader !taskDepBody ), lambda { 5000: @val[0] 5001: }) 5002: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 5004 5004: def rule_taskPredHeader 5005: pattern(%( !taskDepId ), lambda { 5006: @taskDependency = TaskDependency.new(@val[0], false) 5007: }) 5008: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 5010 5010: def rule_taskPredList 5011: pattern(%( !taskPred !morePredTasks ), lambda { 5012: [ @val[0] ] + (@val[1].nil? ? [] : @val[1]) 5013: }) 5014: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 5016 5016: def rule_taskScenarioAttributes 5017: 5018: pattern(%( _account $ID ), lambda { 5019: # TODO 5020: }) 5021: doc('account.task', This property has been deprecated. Use [[charge]] instead. 5022: ) 5023: 5024: pattern(%( !allocate )) 5025: 5026: pattern(%( _booking !taskBooking )) 5027: doc('booking.task', The booking attribute can be used to report actually completed work. A taskwith bookings must be [[scheduling|scheduled]] in ''''asap'''' mode. If thescenario is not the [[trackingscenario|tracking scenario]] or derived from it,the scheduler will not allocate resources prior to the current date or thedate specified with [[now]] when a task has at least one booking.Bookings are only valid in the scenario they have been defined in. They willin general not be passed to any other scenario. If you have defined a[[trackingscenario|tracking scenario]], the bookings of this scenario will bepassed to all the derived scenarios of the tracking scenario.The sloppy attribute can be used when you want to skip non-working time orother allocations automatically. If it's not given, all bookings must onlycover working time for the resource.The booking attributes is designed to capture the exact amount of completedwork. This attribute is not really intended to specify completed effort byhand. Usually, booking statements are generated by [[export]] reports. The[[sloppy.booking|sloppy]] and [[overtime.booking|overtime]] attributes areonly kludge for users who want to write them manually.Bookings can be used to report already completed work by specifying the exacttime intervals a certain resource has worked on this task.Bookings can be defined in the task or resource context. If you move tasksaround very often, put your bookings in the task context. 5028: ) 5029: also(%( booking.resource )) 5030: example('Booking') 5031: 5032: pattern(%( _charge !number !chargeMode ), lambda { 5033: checkContainer('charge') 5034: 5035: if @property['chargeset', @scenarioIdx].empty? 5036: error('task_without_chargeset', 5037: 'The task does not have a chargeset defined.', 5038: @sourceFileInfo[0], @property) 5039: end 5040: case @val[2] 5041: when 'onstart' 5042: mode = :onStart 5043: amount = @val[1] 5044: when 'onend' 5045: mode = :onEnd 5046: amount = @val[1] 5047: when 'perhour' 5048: mode = :perDiem 5049: amount = @val[1] * 24 5050: when 'perday' 5051: mode = :perDiem 5052: amount = @val[1] 5053: when 'perweek' 5054: mode = :perDiem 5055: amount = @val[1] / 7.0 5056: end 5057: # Multiple 'charge' attributes are allowed. 5058: begin 5059: @property['charge', @scenarioIdx] += 5060: [ Charge.new(amount, mode, @property, @scenarioIdx) ] 5061: rescue AttributeOverwrite 5062: end 5063: }) 5064: doc('charge', Specify a one-time or per-period charge to a certain account. The charge canoccur at the start of the task, at the end of it, or continuously over theduration of the task. The accounts to be charged are determined by the[[chargeset]] setting of the task. 5065: ) 5066: arg(1, 'amount', 'The amount to charge') 5067: 5068: pattern(%( !chargeset )) 5069: 5070: pattern(%( _complete !number), lambda { 5071: if @val[1] < 0.0 || @val[1] > 100.0 5072: error('task_complete', "Complete value must be between 0 and 100", 5073: @sourceFileInfo[1], @property) 5074: end 5075: @property['complete', @scenarioIdx] = @val[1] 5076: }) 5077: doc('complete', Specifies what percentage of the task is already completed. This can be usefulfor project tracking. Reports with calendar elements may show the completedpart of the task in a different color. The completion percentage has no impacton the scheduler. It's meant for documentation purposes only.Tasks may not have subtasks if this attribute is used. 5078: ) 5079: example('Complete', '1') 5080: 5081: arg(1, 'percent', 'The percent value. It must be between 0 and 100.') 5082: 5083: pattern(%( _depends !taskDepList ), lambda { 5084: checkContainer('depends') 5085: begin 5086: @property['depends', @scenarioIdx] = 5087: @property['depends', @scenarioIdx] + @val[1] 5088: @property['forward', @scenarioIdx] = true 5089: rescue AttributeOverwrite 5090: end 5091: }) 5092: doc('depends', Specifies that the task cannot start before the specified tasks have beenfinished.By using the 'depends' attribute, the scheduling policy is automatically setto asap. If both depends and precedes are used, the last policy counts. 5093: ) 5094: example('Depends1') 5095: pattern(%( _duration !calendarDuration ), lambda { 5096: setDurationAttribute('duration', @val[1]) 5097: }) 5098: doc('duration', Specifies the time the task should last. This is calendar time, not workingtime. 7d means one week. If resources are specified they are allocated whenavailable. Availability of resources has no impact on the duration of thetask. It will always be the specified duration.Tasks may not have subtasks if this attribute is used. Setting this attributewill reset the [[effort]] and [[length]] attributes. 5099: ) 5100: example('Durations') 5101: also(%( effort length )) 5102: 5103: pattern(%( _effort !workingDuration ), lambda { 5104: if @val[1] <= 0.0 5105: error('effort_zero', "Effort value must be larger than 0", 5106: @sourceFileInfo[1], @property) 5107: end 5108: setDurationAttribute('effort', @val[1]) 5109: }) 5110: doc('effort', Specifies the effort needed to complete the task. An effort of 4d can be donewith 2 full-time resources in 2 days. The task will not finish before theresources have contributed the specified effort. So the duration of the taskwill depend on the availability of the resources.WARNING: In almost all real world projects effort is not the product of timeand resources. This is only true if the task can be partitioned without addingany overhead. For more information about this read ''The Mythical Man-Month'' byFrederick P. Brooks, Jr.Tasks may not have subtasks if this attribute is used. Setting this attributewill reset the [[duration]] and [[length]] attributes. 5111: ) 5112: example('Durations') 5113: also(%( duration length )) 5114: 5115: pattern(%( _end !valDate ), lambda { 5116: @property['end', @scenarioIdx] = @val[1] 5117: begin 5118: @property['forward', @scenarioIdx] = false 5119: rescue AttributeOverwrite 5120: end 5121: }) 5122: doc('end', The end attribute provides a guideline to the scheduler when the task shouldend. It will never end later, but it may end earlier when allocatedresources are not available that long. When an end date is provided for acontainer task, it will be passed down to ALAP task that don't have a welldefined end criteria.Setting an end date will implicitely set the scheduling policy for this taskto ALAP. 5123: ) 5124: example('Export', '1') 5125: pattern(%( _endcredit !number ), lambda { 5126: @property['charge', @scenarioIdx] = 5127: @property['charge', @scenarioIdx] + 5128: [ Charge.new(@val[1], :onEnd, @property, @scenarioIdx) ] 5129: }) 5130: doc('endcredit', Specifies an amount that is credited to the accounts specified by the[[chargeset]] attributes at the moment the tasks ends. This attribute has beendeprecated and should no longer be used. Use [[charge]] instead. 5131: ) 5132: example('Account', '1') 5133: pattern(%( !flags )) 5134: doc('flags.task', Attach a set of flags. The flags can be used in logical expressions to filterproperties from the reports. 5135: ) 5136: 5137: pattern(%( !fail )) 5138: 5139: pattern(%( _length !workingDuration ), lambda { 5140: setDurationAttribute('length', @val[1]) 5141: }) 5142: doc('length', Specifies the global working time to be used for this task. The value isspecified in working time, not calendar time. 7d means 7 working days, or 7times 8 hours (assuming default settings), not one week.A task with a length specification may have resource allocations. Resourcesare allocated when they are available. There is no guarantee that the taskwill get any resources allocated. The availability of resources has no impacton the duration of the task. A time slot where none of the specified resourcesis available is still considered working time, if there is no global vacationand global working hours are defined accordingly.For the length calculation, only the global working hours and the globalvacations matter. If a resource has additinal working hours defined, it'squite possible that a task with a length of 5d will have an allocated effortlarger than 40 hours. Resource working hours only have an impact on whether anallocation is made or not for a particular time slot. They don't effect theresulting duration of the task.Tasks may not have subtasks if this attribute is used. Setting this attributewill reset the [[duration]], [[effort]] and [[milestone]] attributes. 5143: ) 5144: also(%( duration effort )) 5145: 5146: pattern(%( !limits ), lambda { 5147: checkContainer('limits') 5148: @property['limits', @scenarioIdx] = @val[0] 5149: }) 5150: doc('limits.task', Set per-interval allocation limits for the task. This setting affects all allocations for this task. 5151: ) 5152: example('Limits-1', '2') 5153: 5154: pattern(%( _maxend !valDate ), lambda { 5155: @property['maxend', @scenarioIdx] = @val[1] 5156: }) 5157: doc('maxend', Specifies the maximum wanted end time of the task. The value is not usedduring scheduling, but is checked after all tasks have been scheduled. If theend of the task is later than the specified value, then an error is reported. 5158: ) 5159: 5160: pattern(%( _maxstart !valDate ), lambda { 5161: @property['maxstart', @scenarioIdx] = @val[1] 5162: }) 5163: doc('maxstart', Specifies the maximum wanted start time of the task. The value is not usedduring scheduling, but is checked after all tasks have been scheduled. If thestart of the task is later than the specified value, then an error isreported. 5164: ) 5165: 5166: pattern(%( _milestone ), lambda { 5167: setDurationAttribute('milestone') 5168: }) 5169: doc('milestone', Turns the task into a special task that has no duration. You may not specify aduration, length, effort or subtasks for a milestone task.A task that only has a start or an end specification and no durationspecification, inherited start or end dates, no dependencies or sub tasks,will be recognized as milestone automatically. 5170: ) 5171: 5172: pattern(%( _minend !valDate ), lambda { 5173: @property['minend', @scenarioIdx] = @val[1] 5174: }) 5175: doc('minend', Specifies the minimum wanted end time of the task. The value is not usedduring scheduling, but is checked after all tasks have been scheduled. If theend of the task is earlier than the specified value, then an error isreported. 5176: ) 5177: 5178: pattern(%( _minstart !valDate ), lambda { 5179: @property['minstart', @scenarioIdx] = @val[1] 5180: }) 5181: doc('minstart', Specifies the minimum wanted start time of the task. The value is not usedduring scheduling, but is checked after all tasks have been scheduled. If thestart of the task is earlier than the specified value, then an error isreported. 5182: ) 5183: 5184: pattern(%( _startcredit !number ), lambda { 5185: @property['charge', @scenarioIdx] += 5186: [ Charge.new(@val[1], :onStart, @property, @scenarioIdx) ] 5187: }) 5188: doc('startcredit', Specifies an amount that is credited to the account specified by the[[chargeset]] attributes at the moment the tasks starts. This attribute hasbeen deprecated and should no longer be used. Use [[charge]] instead. 5189: ) 5190: pattern(%( !taskPeriod )) 5191: 5192: pattern(%( _precedes !taskPredList ), lambda { 5193: checkContainer('precedes') 5194: begin 5195: @property['precedes', @scenarioIdx] += @val[1] 5196: @property['forward', @scenarioIdx] = false 5197: rescue AttributeOverwrite 5198: end 5199: }) 5200: doc('precedes', Specifies that the tasks with the specified IDs cannot start before the taskhas been finished. If multiple IDs are specified, they must be separated bycommas. IDs must be either global or relative. A relative ID starts with anumber of '!'. Each '!' moves the scope to the parent task. Global IDs do notcontain '!', but have IDs separated by dots.By using the 'precedes' attribute, the scheduling policy is automatically setto alap. If both depends and precedes are used within a task, the last policycounts. 5201: ) 5202: 5203: pattern(%( _priority $INTEGER ), lambda { 5204: if @val[1] < 0 || @val[1] > 1000 5205: error('task_priority', "Priority must have a value between 0 and 1000", 5206: @sourceFileInfo[1], @property) 5207: end 5208: @property['priority', @scenarioIdx] = @val[1] 5209: }) 5210: doc('priority', Specifies the priority of the task. A task with higher priority is morelikely to get the requested resources. The default priority value of all tasksis 500. Don't confuse the priority of a tasks with the importance or urgencyof a task. It only increases the chances that the tasks gets the requestedresources. It does not mean that the task happens earlier, though that isusually the effect you will see. It also does not have any effect on tasksthat don't have any resources assigned (e.g. milestones).For milestones it will raise or lower the chances that task leading up themilestone will get their resources over task with equal priority that competefor the same resources.This attribute is inherited by subtasks if specified prior to the definitionof the subtask. 5211: ) 5212: arg(1, 'value', 'Priority value (1 - 1000)') 5213: example('Priority') 5214: 5215: pattern(%( _projectid $ID ), lambda { 5216: unless @project['projectids'].include?(@val[1]) 5217: error('unknown_projectid', "Unknown project ID #{@val[1]}", 5218: @sourceFileInfo[1]) 5219: end 5220: begin 5221: @property['projectid', @scenarioIdx] = @val[1] 5222: rescue AttributeOverwrite 5223: # This attribute always overwrites the implicitely provided ID. 5224: end 5225: }) 5226: doc('projectid.task', In larger projects it may be desireable to work with different project IDs forparts of the project. This attribute assignes a new project ID to this task anall subsequently defined sub tasks. The project ID needs to be declared first using [[projectid]] or [[projectids]]. 5227: ) 5228: 5229: pattern(%( _responsible !resourceList ), lambda { 5230: @property['responsible', @scenarioIdx] += @val[1] 5231: @property['responsible', @scenarioIdx].uniq! 5232: }) 5233: doc('responsible', The ID of the resource that is responsible for this task. This value is fordocumentation purposes only. It's not used by the scheduler. 5234: ) 5235: 5236: pattern(%( _scheduled ), lambda { 5237: if (@property['milestone', @scenarioIdx] && 5238: @property['start', @scenarioIdx].nil? && 5239: @property['end', @scenarioIdx].nil?) || 5240: (!@property['milestone', @scenarioIdx] && 5241: (@property['start', @scenarioIdx].nil? || 5242: @property['end', @scenarioIdx].nil?)) 5243: error('not_scheduled', 5244: "Task #{@property.fullId} is marked as scheduled but does not " + 5245: 'have a fixed start and end date.', 5246: @sourceFileInfo[0], @property) 5247: end 5248: @property['scheduled', @scenarioIdx] = true 5249: }) 5250: doc('scheduled', This is mostly for internal use. It specifies that the task can be ignored forscheduling in the scenario. 5251: ) 5252: 5253: pattern(%( _scheduling !schedulingDirection ), lambda { 5254: if @val[1] == 'alap' 5255: begin 5256: @property['forward', @scenarioIdx] = false 5257: rescue AttributeOverwrite 5258: end 5259: elsif @val[1] == 'asap' 5260: begin 5261: @property['forward', @scenarioIdx] = true 5262: rescue AttributeOverwrite 5263: end 5264: end 5265: }) 5266: doc('scheduling', Specifies the scheduling policy for the task. A task can be scheduled fromstart to end (As Soon As Possible, asap) or from end to start (As Late AsPossible, alap).A task can be scheduled from start to end (ASAP mode) when it has a hard(start) or soft (depends) criteria for the start time. A task can be scheduledfrom end to start (ALAP mode) when it has a hard (end) or soft (precedes)criteria for the end time.Some task attributes set the scheduling policy implicitly. This attribute canbe used to explicitly set the scheduling policy of the task to a certaindirection. To avoid it being overwritten again by an implicit attribute thisattribute should always be the last attribute of the task.A random mixture of ASAP and ALAP tasks can have unexpected side effects onthe scheduling of the project. It increases significantly the schedulingcomplexity and results in much longer scheduling times. Especially in projectswith many hundreds of tasks the scheduling time of a project with a mixture ofASAP and ALAP times can be 2 to 10 times longer. When the projects containschains of ALAP and ASAP tasks the tasks further down the dependency chain willbe served much later than other non-chained task even when they have a muchhigher priority. This can result in situations where high priority tasks donot get their resources even though the parallel competing tasks have a muchlower priority.As a general rule, try to avoid ALAP tasks whenever possible. Have a closeeye on tasks that have been switched implicitly to ALAP mode because theend attribute comes after the start attribute. 5267: ) 5268: 5269: pattern(%( _shift !shiftAssignments ), lambda { 5270: checkContainer('shift') 5271: }) 5272: doc('shift.task', This keyword has been deprecated. Please use [[shifts.task|shifts(task)]] instead. 5273: ) 5274: 5275: pattern(%( _shifts !shiftAssignments ), lambda { 5276: checkContainer('shifts') 5277: }) 5278: doc('shifts.task', Limits the working time for this task during the during the specified intervalto the working hours of the given shift. Multiple shifts can be defined, butshift intervals may not overlap. This is an additional working timerestriction ontop of the working hours of the allocated resources. It does notreplace the resource working hour restrictions. For a resource to be assignedto a time slot, both the respective task shift as well as the resource workinghours must declare the time slot as duty slot. 5279: ) 5280: 5281: pattern(%( _start !valDate), lambda { 5282: @property['start', @scenarioIdx] = @val[1] 5283: begin 5284: @property['forward', @scenarioIdx] = true 5285: rescue AttributeOverwrite 5286: end 5287: }) 5288: doc('start', The start attribute provides a guideline to the scheduler when the task shouldstart. It will never start earlier, but it may start later when allocatedresources are not available immediately. When a start date is provided for acontainer task, it will be passed down to ASAP task that don't have a welldefined start criteria.Setting a start date will implicitely set the scheduling policy for this taskto ASAP. 5289: ) 5290: also(%( end period.task maxstart minstart scheduling )) 5291: 5292: pattern(%( !warn )) 5293: 5294: # Other attributes will be added automatically. 5295: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 5658 5658: def rule_timeInterval 5659: pattern([ '$TIME', '_-', '$TIME' ], lambda { 5660: if @val[0] >= @val[2] 5661: error('time_interval', 5662: "End time of interval must be larger than start time", 5663: @sourceFileInfo[0]) 5664: end 5665: [ @val[0], @val[2] ] 5666: }) 5667: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 5669 5669: def rule_timeSheet 5670: pattern(%( !timeSheetHeader !timeSheetBody ), lambda { 5671: @timeSheet 5672: }) 5673: doc('timesheet', A time sheet record can be used to capture the current status of the tasksassigned to a specific resource and the achieved progress for a given periodof time. The status is assumed to be for the end of this time period. Theremust be a separate time sheet record for each resource per period. Differentresources can use different reporting periods and reports for the sameresource may have different reporting periods as long as they don't overlap.For the time after the last time sheet, TaskJuggler will project the resultbased on the plan data. For periods without a time sheet record prior to thelast record for this resource, TaskJuggler assumes that no work has been done.The work is booked for the scenario specified by [[trackingscenario]].The intended use for time sheets is to have all resources report a time sheetevery day, week or month. All time sheets can be added to the project plan.The status information is always used to determin the current status of theproject. The [[work]], [[remaining]] and [[end.timesheet|end]] attributes areignored if there are also [[booking.task|bookings]] for the resource in thetime sheet period. The non-ignored attributes of the time sheets will beconverted into [[booking.task|booking]] statements internally. These bookingscan then be [[export|exported]] into a file which can then be added to theproject again. This way, you can use time sheets to incrementally recordprogress of your project. There is a possibility that time sheets conflictwith other data in the plan. In case TaskJuggler cannot automatically resolvethem, these conflicts have to be manually resolved by either changing the planor the time sheet.The status messages are interpreted as [[journalentry|journal entries]]. Thealert level will be evaluated and the current state of the project can be putinto a dashboard using the ''''alert'''' and ''''alertmessage'''' [[columnid|columns]].Currently, the provided effort values and dates are not yet used toautomatically update the plan data. This feature will be added in futureversions. 5674: ) 5675: example('TimeSheet1', '1') 5676: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 5712 5712: def rule_timeSheetAttributes 5713: optional 5714: repeatable 5715: 5716: pattern(%( !tsNewTaskHeader !tsTaskBody ), lambda { 5717: @property = nil 5718: @timeSheetRecord = nil 5719: }) 5720: doc('newtask', The keyword can be used add a new task to the project. If the task ID requiresfurther parent task that don't exist yet, these tasks will be created as well.If the task exists already, an error is generated. The new task can be usedimmediately to report progress and status against it. 5721: ) 5722: example('TimeSheet1', '3') 5723: 5724: pattern(%( _shift !shiftId ), lambda { 5725: #TODO 5726: }) 5727: doc('shift.timesheet', Specifies an alternative [[shift]] for the time sheet period. This shift willoverride any existing working hour definitions for the resource. It will notoverride already declared [[vacation|vacations]] though.The primary use of this feature is to let the resources report different totalwork time for the report period. 5728: ) 5729: 5730: pattern(%( !tsStatus )) 5731: 5732: pattern(%( !tsTaskHeader !tsTaskBody ), lambda { 5733: @property = nil 5734: @timeSheetRecord = nil 5735: }) 5736: doc('task.timesheet', Specifies an existing task that progress and status should be reportedagainst. 5737: ) 5738: example('TimeSheet1', '4') 5739: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 5763 5763: def rule_timeSheetBody 5764: pattern(%( _{ !timeSheetAttributes _} ), lambda { 5765: 5766: }) 5767: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 5756 5756: def rule_timeSheetFile 5757: pattern(%( !timeSheet . ), lambda { 5758: @val[0] 5759: }) 5760: lastSyntaxToken(1) 5761: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 5769 5769: def rule_timeSheetHeader 5770: pattern(%( _timesheet !resourceId !valIntervalOrDate ), lambda { 5771: @sheetAuthor = @val[1] 5772: @property = nil 5773: unless @sheetAuthor.leaf? 5774: error('ts_group_author', 5775: 'A resource group cannot file a time sheet', 5776: @sourceFileInfo[1]) 5777: end 5778: unless (scenarioIdx = @project['trackingScenarioIdx']) 5779: error('ts_no_tracking_scenario', 5780: 'No trackingscenario defined.') 5781: end 5782: # Currently time sheets are hardcoded for scenario 0. 5783: @timeSheet = TimeSheet.new(@sheetAuthor, @val[2], scenarioIdx) 5784: @timeSheet.sourceFileInfo = @sourceFileInfo[0] 5785: @project.timeSheets << @timeSheet 5786: }) 5787: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 5789 5789: def rule_timeSheetReport 5790: pattern(%( !tsReportHeader !tsReportBody ), lambda { 5791: @property = nil 5792: }) 5793: doc('timesheetreport', For projects that flow mostly according to plan, TaskJuggler already knowsmuch of the information that should be contained in the time sheets. With thisproperty, you can generate a report that contains drafts of the time sheetsfor one or more resources. The time sheet drafts will be for thespecified report period and the specified [trackingscenario]. 5794: ) 5795: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 5516 5516: def rule_timeformat 5517: pattern(%( _timeformat $STRING ), lambda { 5518: @val[1] 5519: }) 5520: doc('timeformat', Determines how time specifications in reports look like. 5521: ) 5522: arg(1, 'format', Ordinary characters placed in the format string are copied withoutconversion. Conversion specifiers are introduced by a `%' character, and arereplaced in s as follows:* ''''%a'''' The abbreviated weekday name according to the current locale.* ''''%A'''' The full weekday name according to the current locale.* ''''%b'''' The abbreviated month name according to the current locale.* ''''%B'''' The full month name according to the current locale.* ''''%c'''' The preferred date and time representation for the current locale.* ''''%C'''' The century number (year/100) as a 2-digit integer. (SU)* ''''%d'''' The day of the month as a decimal number (range 01 to 31).* ''''%e'''' Like ''''%d'''', the day of the month as a decimal number, but aleading zero is replaced by a space. (SU)* ''''%E'''' Modifier: use alternative format, see below. (SU)* ''''%F'''' Equivalent to ''''%Y-%m-%d'''' (the ISO 8601 date format). (C99)* ''''%G'''' The ISO 8601 year with century as a decimal number. The 4-digityear corresponding to the ISO week number (see %V). This has the same formatand value as ''''%y'''', except that if the ISO week number belongs to theprevious or next year, that year is used instead. (TZ)* ''''%g'''' Like %G, but without century, i.e., with a 2-digit year (00-99).(TZ)* ''''%h'''' Equivalent to ''''%b''''. (SU)* ''''%H'''' The hour as a decimal number using a 24-hour clock (range 00 to23).* ''''%I'''' The hour as a decimal number using a 12-hour clock (range 01 to12).* ''''%j'''' The day of the year as a decimal number (range 001 to 366).* ''''%k'''' The hour (24-hour clock) as a decimal number (range 0 to 23);single digits are preceded by a blank. (See also ''''%H''''.) (TZ)* ''''%l'''' The hour (12-hour clock) as a decimal number (range 1 to 12);single digits are preceded by a blank. (See also ''''%I''''.) (TZ)* ''''%m'''' The month as a decimal number (range 01 to 12).* ''''%M'''' The minute as a decimal number (range 00 to 59).* ''''%n'''' A newline character. (SU)* ''''%O'''' Modifier: use alternative format, see below. (SU)* ''''%p'''' Either 'AM' or 'PM' according to the given time value, or thecorresponding strings for the current locale. Noon is treated as `pm' andmidnight as 'am'.* ''''%P'''' Like %p but in lowercase: 'am' or 'pm' or ''''%a''''corresponding string for the current locale. (GNU)* ''''%r'''' The time in a.m. or p.m. notation. In the POSIX locale this isequivalent to ''''%I:%M:%S %p''''. (SU)* ''''%R'''' The time in 24-hour notation (%H:%M). (SU) For a versionincluding the seconds, see ''''%T'''' below.* ''''%s'''' The number of seconds since the Epoch, i.e., since 1970-01-0100:00:00 UTC. (TZ)* ''''%S'''' The second as a decimal number (range 00 to 61).* ''''%t'''' A tab character. (SU)* ''''%T'''' The time in 24-hour notation (%H:%M:%S). (SU)* ''''%u'''' The day of the week as a decimal, range 1 to 7, Monday being 1.See also ''''%w''''. (SU)* ''''%U'''' The week number of the current year as a decimal number, range00 to 53, starting with the first Sunday as the first day of week 01. See also''''%V'''' and ''''%W''''.* ''''%V'''' The ISO 8601:1988 week number of the current year as a decimalnumber, range 01 to 53, where week 1 is the first week that has at least 4days in the current year, and with Monday as the first day of the week. Seealso ''''%U'''' and ''''%W''''. %(SU)* ''''%w'''' The day of the week as a decimal, range 0 to 6, Sunday being 0. See also ''''%u''''.* ''''%W'''' The week number of the current %year as a decimal number, range00 to 53, starting with the first Monday as the first day of week 01.* ''''%x'''' The preferred date representation for the current locale withoutthe time.* ''''%X'''' The preferred time representation for the current locale withoutthe date.* ''''%y'''' The year as a decimal number without a century (range 00 to 99).* ''''%Y'''' The year as a decimal number including the century.* ''''%z'''' The time zone as hour offset from GMT. Required to emitRFC822-conformant dates (using ''''%a, %d %%b %Y %H:%M:%S %%z''''). (GNU)* ''''%Z'''' The time zone or name or abbreviation.* ''''%+'''' The date and time in date(1) format. (TZ)* ''''%%'''' A literal ''''%'''' character.Some conversion specifiers can be modified by preceding them by the E or Omodifier to indicate that an alternative format should be used. If thealternative format or specification does not exist for the current locale, thebehavior will be as if the unmodified conversion specification were used.(SU) The Single Unix Specification mentions %Ec, %EC, %Ex, %%EX, %Ry, %EY,%Od, %Oe, %OH, %OI, %Om, %OM, %OS, %Ou, %OU, %OV, %Ow, %OW, %Oy, where theeffect of the O modifier is to use alternative numeric symbols (say, Romannumerals), and that of the E modifier is to use a locale-dependent alternativerepresentation.This documentation of the timeformat attribute has been taken from the man pageof the GNU strftime function. 5523: ) 5524: 5525: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 5803 5803: def rule_timezone 5804: pattern(%( _timezone !validTimeZone ), lambda{ 5805: TjTime.setTimeZone(@val[1]) 5806: @project['timezone'] = @val[1] 5807: }) 5808: doc('timezone', Sets the default time zone of the project. All dates and times that have notime zones specified will be assumed to be in this time zone. If no time zoneis specified for the project, UTC is assumed.The project start and end time are not affected by this setting. They arealways considered to be UTC unless specified differently.In case the specified time zone is not hour-aligned with UTC, the[[timingresolution]] will automatically be decreased accordingly. Do notchange the timingresolution after you've set the time zone!Changing the time zone will reset the [[workinghours.project|working hours]]to the default times. It's recommended that you declare your working hoursafter the time zone. 5809: ) 5810: arg(1, 'zone', Time zone to use. E. g. 'Europe/Berlin' or 'America/Denver'. Don't use the 3letter acronyms. See[http://en.wikipedia.org/wiki/List_of_zoneinfo_time_zones Wikipedia] forpossible values. 5811: ) 5812: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 5834 5834: def rule_tsNewTaskHeader 5835: pattern(%( _newtask !taskIdUnverifd $STRING ), lambda { 5836: @timeSheetRecord = TimeSheetRecord.new(@timeSheet, @val[1]) 5837: @timeSheetRecord.name = @val[2] 5838: @timeSheetRecord.sourceFileInfo = @sourceFileInfo[0] 5839: }) 5840: arg(1, 'task', 'ID of the new task') 5841: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 5862 5862: def rule_tsReportAttributes 5863: optional 5864: repeatable 5865: 5866: pattern(%( !hideresource )) 5867: pattern(%( !reportEnd )) 5868: pattern(%( !reportPeriod )) 5869: pattern(%( !reportStart )) 5870: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 5872 5872: def rule_tsReportBody 5873: optionsRule('tsReportAttributes') 5874: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 5842 5842: def rule_tsReportHeader 5843: pattern(%( _timesheetreport !optionalID $STRING ), lambda { 5844: report = newReport(@val[1], @val[2], :timeSheet, sourceFileInfo) 5845: report.set('scenarios', [ 0 ]) 5846: # Show all tasks, sorted by seqno-up. 5847: report.set('hideTask', LogicalExpression.new(LogicalOperation.new(0))) 5848: report.set('sortTasks', [ [ 'seqno', true, 1 ] ]) 5849: # Show all resources, sorted by seqno-up. 5850: report.set('hideResource', LogicalExpression.new(LogicalOperation.new(0))) 5851: report.set('sortResources', [ [ 'seqno', true, 1 ] ]) 5852: report.set('loadUnit', :hours) 5853: report.set('definitions', []) 5854: }) 5855: arg(1, 'file name', The name of the time sheet report file to generate. It must end with a .tjiextension, or use . to use the standard output channel. 5856: ) 5857: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 5927 5927: def rule_tsStatus 5928: pattern(%( !tsStatusHeader !tsStatusBody )) 5929: doc('status.timesheet', The status attribute can be used to describe the current status of the task orresource. The content of the status messages is added to the project journal. 5930: ) 5931: arg(2, 'headline', A short headline for the status. Must be 60 characters or shorter. 5932: ) 5933: example('TimeSheet1', '4') 5934: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 5876 5876: def rule_tsStatusAttributes 5877: optional 5878: repeatable 5879: 5880: pattern(%( !details )) 5881: 5882: pattern(%( _flags !flagList ), lambda { 5883: @val[1].each do |flag| 5884: next if @journalEntry.flags.include?(flag) 5885: 5886: @journalEntry.flags << flag 5887: end 5888: }) 5889: doc('flags.timesheet', Time sheet entries can have flags attached to them. These can be used toinclude only entries in a report that have a certain flag. 5890: ) 5891: 5892: pattern(%( !summary )) 5893: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 5898 5898: def rule_tsStatusBody 5899: optional 5900: pattern(%( _{ !tsStatusAttributes _} )) 5901: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 5903 5903: def rule_tsStatusHeader 5904: pattern(%( _status !alertLevel $STRING ), lambda { 5905: if @val[2].length > 120 5906: error('ts_headline_too_long', 5907: "The headline must be 120 or less characters long. This one " + 5908: "has #{@val[2].length} characters.", @sourceFileInfo[2]) 5909: end 5910: if @val[2] == 'Your headline here!' 5911: error('ts_no_headline', 5912: "'Your headline here!' is not a valid headline", 5913: @sourceFileInfo[2]) 5914: end 5915: @journalEntry = JournalEntry.new(@project['journal'], 5916: @timeSheet.interval.end, 5917: @val[2], 5918: @property || @timeSheet.resource, 5919: @sourceFileInfo[0]) 5920: @journalEntry.alertLevel = @val[1] 5921: @journalEntry.timeSheetRecord = @timeSheetRecord 5922: @journalEntry.author = @sheetAuthor 5923: @timeSheetRecord.status = @journalEntry if @timeSheetRecord 5924: }) 5925: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 5941 5941: def rule_tsTaskAttributes 5942: optional 5943: repeatable 5944: 5945: pattern(%( _end !valDate ), lambda { 5946: if @val[1] < @timeSheet.interval.start 5947: error('ts_end_too_early', 5948: "The expected task end date must be after the start date of " + 5949: "this time sheet report.", @sourceFileInfo[1]) 5950: end 5951: @timeSheetRecord.expectedEnd = @val[1] 5952: }) 5953: doc('end.timesheet', The expected end date for the task. This can only be used for duration basedtask. For effort based task [[remaining]] has to be used. 5954: ) 5955: example('TimeSheet1', '5') 5956: 5957: pattern(%( _priority $INTEGER ), lambda { 5958: priority = @val[1] 5959: if priority < 1 || priority > 1000 5960: error('ts_bad_priority', 5961: "Priority value #{priority} must be between 1 and 1000.", 5962: @sourceFileInfo[1]) 5963: end 5964: @timeSheetRecord.priority = priority 5965: }) 5966: doc('priority.timesheet', The priority is a value between 1 and 1000. It is used to determine thesequence of task when converting [[work]] to [[booking.task|bookings]]. Tasksthat need to finish earlier in the period should have a high priority, tasksthat end later in the period should have a low priority. For tasks that don'tget finished in the reported period the priority should be set to 1. 5967: ) 5968: 5969: pattern(%( _remaining !workingDuration ), lambda { 5970: @timeSheetRecord.remaining = @val[1] 5971: }) 5972: doc('remaining', The remaining effort for the task. This value is ignored if there are[[booking.task|bookings]] for the resource that overlap with the time sheetperiod. If there are no bookings, the value is compared with the [[effort]]specification of the task. If there a mismatch between the accumulated effortspecified with bookings, [[work]] and [[remaining]] on one side and thespecified [[effort]] on the other, a warning is generated.This attribute can only be used with tasks that are effort based. Durationbased tasks need to have an [[end.timesheet|end]] attribute. 5973: ) 5974: example('TimeSheet1', '6') 5975: 5976: pattern(%( !tsStatus )) 5977: 5978: pattern(%( _work !workingDurationPercent ), lambda { 5979: @timeSheetRecord.work = @val[1] 5980: }) 5981: doc('work', The amount of time that the resource has spend with the task during thereported period. This value is ignored when there are[[booking.task|bookings]] for the resource overlapping with the time sheetperiod. If there are no bookings, TaskJuggler will try to convert the workspecification into bookings internally before the actual scheduling isstarted.Every task listed in the time sheet needs to have a work attribute. The totalaccumulated work time that is reported must match exactly the total workinghours for the resource for that period.If a resource has no vacation during the week that is reported and it has aregular 40 hour work week, exactly 40 hours total or 5 working days have to bereported. 5982: ) 5983: example('TimeSheet1', '4') 5984: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 6020 6020: def rule_tsTaskBody 6021: pattern(%( _{ !tsTaskAttributes _} )) 6022: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 6024 6024: def rule_tsTaskHeader 6025: pattern(%( _task !taskId ), lambda { 6026: @property = @val[1] 6027: unless @property.leaf? 6028: error('ts_task_not_leaf', 6029: 'You cannot specify a task that has sub tasks here.', 6030: @sourceFileInfo[1], @property) 6031: end 6032: 6033: @timeSheetRecord = TimeSheetRecord.new(@timeSheet, @property) 6034: @timeSheetRecord.sourceFileInfo = @sourceFileInfo[0] 6035: }) 6036: arg(1, 'task', 'ID of an already existing task') 6037: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 6039 6039: def rule_vacationName 6040: optional 6041: pattern(%( $STRING )) # We just throw the name away 6042: arg(0, 'name', 'An optional name for the vacation') 6043: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 6045 6045: def rule_valDate 6046: pattern(%( !date ), lambda { 6047: if @val[0] < @project['start'] || @val[0] > @project['end'] 6048: error('date_in_range', 6049: "Date #{@val[0]} must be within the project time frame " + 6050: "#{@project['start']} - #{@project['end']}", 6051: @sourceFileInfo[0]) 6052: end 6053: @val[0] 6054: }) 6055: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 6105 6105: def rule_valInterval 6106: pattern(%( !date !intervalEnd ), lambda { 6107: mode = @val[1][0] 6108: endSpec = @val[1][1] 6109: if mode == 0 6110: unless @val[0] < endSpec 6111: error('start_before_end', "The end date (#{endSpec}) must be after " + 6112: "the start date (#{@val[0]}).", @sourceFileInfo[1]) 6113: end 6114: iv = Interval.new(@val[0], endSpec) 6115: else 6116: iv = Interval.new(@val[0], @val[0] + endSpec) 6117: end 6118: checkInterval(iv) 6119: iv 6120: }) 6121: doc('interval1', There are two ways to specify a date interval. The start and end date must lie within the specified project period.The first is the most obvious. A date interval consists of a start and endDATE. Watch out for end dates without a time specification! Datespecifications are 0 extended. An end date without a time is expanded tomidnight that day. So the day of the end date is not included in the interval!The start and end dates must be separated by a hyphen character.In the second form specifies the start date and an interval duration. Theduration must be prefixed by a plus character. 6122: ) 6123: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 6067 6067: def rule_valIntervalOrDate 6068: pattern(%( !date !intervalOptionalEnd ), lambda { 6069: if @val[1] 6070: mode = @val[1][0] 6071: endSpec = @val[1][1] 6072: if mode == 0 6073: unless @val[0] < endSpec 6074: error('start_before_end', "The end date (#{endSpec}) must be " + 6075: "after the start date (#{@val[0]}).", 6076: @sourceFileInfo[1]) 6077: end 6078: iv = Interval.new(@val[0], endSpec) 6079: else 6080: iv = Interval.new(@val[0], @val[0] + endSpec) 6081: end 6082: else 6083: iv = Interval.new(@val[0], @val[0].sameTimeNextDay) 6084: end 6085: checkInterval(iv) 6086: iv 6087: }) 6088: doc('interval4', There are three ways to specify a date interval. The first is the mostobvious. A date interval consists of a start and end DATE. Watch out for enddates without a time specification! Date specifications are 0 extended. Anend date without a time is expanded to midnight that day. So the day of theend date is not included in the interval! The start and end dates must be separated by a hyphen character.In the second form, the end date is omitted. A 24 hour interval is assumed.The third form specifies the start date and an interval duration. The duration must be prefixed by a plus character.The start and end date of the interval must be within the specified projecttime frame. 6089: ) 6090: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 6136 6136: def rule_valIntervals 6137: listRule('moreValIntervals', '!valIntervalOrDate') 6138: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 6057 6057: def rule_validTimeZone 6058: pattern(%( $STRING ), lambda { 6059: unless TjTime.checkTimeZone(@val[0]) 6060: error('bad_time_zone', "#{@val[0]} is not a known time zone", 6061: @sourceFileInfo[0]) 6062: end 6063: @val[0] 6064: }) 6065: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 6140 6140: def rule_warn 6141: pattern(%( _warn !logicalExpression ), lambda { 6142: begin 6143: @property.set('warn', @property.get('warn') + [ @val[1] ]) 6144: rescue AttributeOverwrite 6145: end 6146: }) 6147: doc('warn', The warn attribute adds a logical expression to the property. The conditiondescribed by the logical expression is checked after the scheduling and anwarning is generated if the condition evaluates to true. This attribute isprimarily intended for testing purposes. 6148: ) 6149: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 6167 6167: def rule_weekDayInterval 6168: pattern(%( !weekday !weekDayIntervalEnd ), lambda { 6169: weekdays = Array.new(7, false) 6170: if @val[1].nil? 6171: weekdays[@val[0]] = true 6172: else 6173: d = @val[0] 6174: loop do 6175: weekdays[d] = true 6176: break if d == @val[1] 6177: d = (d + 1) % 7 6178: end 6179: end 6180: 6181: weekdays 6182: }) 6183: arg(0, 'weekday', 'Weekday (sun - sat)') 6184: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 6186 6186: def rule_weekDayIntervalEnd 6187: optional 6188: pattern([ '_-', '!weekday' ], lambda { 6189: @val[1] 6190: }) 6191: arg(1, 'end weekday', 6192: 'Weekday (sun - sat). It is included in the interval.') 6193: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 6157 6157: def rule_weekday 6158: pattern(%( _sun ), lambda { 0 }) 6159: pattern(%( _mon ), lambda { 1 }) 6160: pattern(%( _tue ), lambda { 2 }) 6161: pattern(%( _wed ), lambda { 3 }) 6162: pattern(%( _thu ), lambda { 4 }) 6163: pattern(%( _fri ), lambda { 5 }) 6164: pattern(%( _sat ), lambda { 6 }) 6165: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 6195 6195: def rule_workingDuration 6196: pattern(%( !number !durationUnit ), lambda { 6197: convFactors = [ 60, # minutes 6198: 60 * 60, # hours 6199: 60 * 60 * @project['dailyworkinghours'], # days 6200: 60 * 60 * @project['dailyworkinghours'] * 6201: (@project['yearlyworkingdays'] / 52.1429), # weeks 6202: 60 * 60 * @project['dailyworkinghours'] * 6203: (@project['yearlyworkingdays'] / 12), # months 6204: 60 * 60 * @project['dailyworkinghours'] * 6205: @project['yearlyworkingdays'] # years 6206: ] 6207: # The result will always be in number of time slots. 6208: (@val[0] * convFactors[@val[1]] / 6209: @project['scheduleGranularity']).round.to_i 6210: }) 6211: arg(0, 'value', 'A floating point or integer number') 6212: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 6214 6214: def rule_workingDurationPercent 6215: pattern(%( !number !durationUnitOrPercent ), lambda { 6216: if @val[1] >= 0 6217: # Absolute value in minutes, hours or days. 6218: convFactors = [ 60, # minutes 6219: 60 * 60, # hours 6220: 60 * 60 * @project['dailyworkinghours'] # days 6221: ] 6222: # The result will always be in number of time slots. 6223: (@val[0] * convFactors[@val[1]] / 6224: @project['scheduleGranularity']).round.to_i 6225: else 6226: # Percentage values are always returned as Float in the rage of 0.0 to 6227: # 1.0. 6228: if @val[0] < 0.0 || @val[0] > 100.0 6229: error('illegal_percentage', 6230: "Percentage values must be between 0 and 100%.", 6231: @sourceFileInfo[1]) 6232: end 6233: @val[0] / 100.0 6234: end 6235: }) 6236: arg(0, 'value', 'A floating point or integer number') 6237: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 6239 6239: def rule_workinghours 6240: pattern(%( _workinghours !listOfDays !listOfTimes), lambda { 6241: if @property.nil? 6242: # We are changing global working hours. 6243: wh = @project['workinghours'] 6244: else 6245: unless (wh = @property['workinghours', @scenarioIdx]) 6246: # The property does not have it's own WorkingHours yet. 6247: wh = WorkingHours.new(@project['workinghours']) 6248: @property['workinghours', @scenarioIdx] = wh 6249: end 6250: end 6251: wh.timezone = @project['timezone'] 6252: 7.times { |i| wh.setWorkingHours(i, @val[2]) if @val[1][i] } 6253: }) 6254: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 6256 6256: def rule_workinghoursProject 6257: pattern(%( !workinghours )) 6258: doc('workinghours.project', Set the default working hours for all subsequent resource definitions. Thestandard working hours are 9:00am - 12:00am, 1:00pm - 18:00pm, Monday toFriday. The working hours specification limits the availability of resourcesto certain time slots of week days.These default working hours can be replaced with other working hours forindividual resources. 6259: ) 6260: also(%( dailyworkinghours workinghours.resource workinghours.shift )) 6261: example('Project') 6262: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 6272 6272: def rule_workinghoursResource 6273: pattern(%( !workinghours )) 6274: doc('workinghours.resource', Set the working hours for a specific resource. The working hours specificationlimits the availability of resources to certain time slots of week days. 6275: ) 6276: also(%( workinghours.project workinghours.shift )) 6277: end
# File lib/taskjuggler/TjpSyntaxRules.rb, line 6282 6282: def rule_workinghoursShift 6283: pattern(%( !workinghours )) 6284: doc('workinghours.shift', Set the working hours for the shift. The working hours specification limitsthe availability of resources or the activity on a task to certain timeslots of week days.The shift working hours will replace the default or resource working hours forthe specified time frame when assigning the shift to a resource.In case the shift is used for a task, resources are only assigned during theworking hours of this shift and during the working hours of the allocatedresource. Allocations only happen when both the task shift and the resourcework hours allow work to happen. 6285: ) 6286: also(%( workinghours.project workinghours.resource )) 6287: end
Disabled; run with --debug to generate this.
Generated with the Darkfish Rdoc Generator 1.1.6.