previous chapter contents page top page next chapter

Rule

February 14, 1995Defined in Rule.Def 
Inherits from Object
        

Class Description

Magic Cap rules allow a user to customize the behavior of objects in the system. For example, the in box has rules that describe actions that can be taken when mail is received. The in box also has rules that can collect mail at certain times of day. Some of the rules play sounds when certain kinds of mail arrive. Other rules control how the user interacts with the mail service.

Some rules can be customized. All rules can be enabled and disabled.

Remember that if the documentation and the software (especially the definition files) disagree, always trust the software.

Related Classes

For each rule you create, you'll need instances of classes RuleTemplate, RuleAction or LocalRuleAction, and RuleQualifier or LocalRuleQualifier. This chapter gives you the basic information on using objects of each of these classes. For detailed information on each class, see its chapter.

Class Rule has two subclasses that help you create specialized rules: class ConditionalRule and class ScheduledRule.

Use class ConditionalRule when your rule is meaningful only in certain circumstances. Conditional rules are rules that appear only when a condition condition applies. This condition must be met before the system will display the rule in the RuleView window.

Use class ScheduledRule to perform actions at certain times. This subclass has additional fields for ScheduledTime and TimedEvent objects.

Programming Information

Instantiate: sometimes
Subclass: rarely
Call its methods: sometimes

You'll probably never create a rule programmatically. Instead, you'll put rule objects and the required ancillary objects into place in your object definition files. The next sections of this chapter describe how you can create rules, install them into your package, and hook them up to system actions.

Adding Rules To Your Package

To add a set of rules to your package, use the rules field of your scene additions object. Here's an example of a scene additions object that includes rules:

Instance SceneAdditions 12;
         commands: nilObject;
            rules: (ObjectList "My Rule Lists" 14);
            tools: nilObject;
           stamps: nilObject;
   stampBankNames: nilObject;
stampBankContents: nilObject;
End Instance;

For more information on scene additions, see the chapter on class SceneAddition.

You should include two lists of rules in your scene additions. The first list is the set of rules available to users who aren't in construction mode. The second list is the set of rules available to users who've turned on construction mode. The "My Rule Lists" list would contain two other lists, like this:

Instance ObjectList "My Rule Lists" 14;
        length: 2;
        entry1: (DenseObjectList 15); // Standard mode rules
        entry2: (DenseObjectList 16); // Authoring mode rules
End Instance;

These two lists of rules must be dense object lists. They almost always have several rules in common. The construction mode list usually adds some rules tailored for expert users. Here are two sample lists:

Instance DenseObjectList 15; //normal mode list
         length: 4;
         entry1: (Rule 17);
         entry2: (Rule 30);
         entry3: (ConditionalRule 40);
         entry4: (ScheduledRule 54);
End Instance;

Instance DenseObjectList 16; //authoring mode list
         length: 5;
         entry1: (Rule 17);
         entry2: (Rule 30);
         entry3: (ConditionalRule 40);
         entry4: (ScheduledRule 54);
         entry5: (Rule `Expert Feature' 64);
End Instance;

Triggering Rules

In order for your rules to have an effect, you must usually trigger them in the appropriate circumstances. (Some rules take effect when the user enables them, and do nothing otherwise. Those rules don't need to be triggered.) To trigger your rules, you use a trigger object.

Trigger objects contain a list of rules that should be invoked when PostTrigger is called. Rules that appear in this list should point their ruleTrigger field back to the Trigger object that contains them. Do this so that when the user makes a copy of the rule, the new copy can be added to the correct Trigger.

Use trigger lists to invoke rules. Don't invoke rules directly. If you invoke rules without using trigger lists, you won't reap the benefits of the rule framework. If your users make copies of your rules, the copies won't ever be invoked.

Trigger lists are just object lists. The entries in the list should be the rules you want to take effect when this trigger is "pulled." For convenience, you might want to make package indexicals for your trigger list objects.

Here's an example of a trigger object:

Instance Trigger 16; // iNewCardInOutboxTrigger
         length: 2;
          entry: (Rule 17);
          entry: (Rule 30);
End Instance;

When a new card arrives in the outbox, the rules in this trigger list should be triggered in the order they appear in this list. Order sometimes matters! It's your responsibility to trigger your new rules in your code. You can take advantage of triggers the system posts by adding your rules to existing trigger lists. (Sometimes you have to post even those triggers yourself. For example, anybody who puts a card into the out box is responsible for posting the out box trigger.) See the the section onSystem Triggers later in this chapter for a list of trigger indexicals defined by Magic Cap.


Version note: Class Trigger is a small class. It inherits its interface from class ObjectList. It defines just one method of its own, the PostTrigger method. This version of this document omits complete documentation of class Trigger.


If you're triggering your rules yourself, call PostTrigger on the trigger list. To use the trigger list in the example, your code would look like this:

PostTrigger(iNewCardInOutboxTrigger, newCard);

PostTrigger calls InvokeRule on each rule in the trigger list. Each rule therefore has a chance to decide if it applies to the new card in the outbox. Rules that have qualifiers call QualifyRule as part of their decision process. In the out box example, QualifyRule would be called like this:

qualified = QualifyRule(qualifier, newCard, rule);

QualifyRule returns true if a rule qualifies and false if it doesn't. If a rule decides it applies, it calls PerformRule on its action, like this:

PerformRule(action, newCard, rule);

You don't have to call QualifyRule and PerformRule yourself; they're called by the rules framework.

Methods defined by class Rule

Class Rule defines the following methods:

Method Description
CopyData Copy information from one rule to another; called by system when rules are copied
ControlList Get the template's control list, if this rule has a template
InvokeRule Perform the rule's action if the rule passes its qualification test
UpdateText Update the rule's text description using the rule template, if the rule has a template
Finalize Overridden to remove the rule from its trigger list
ConditionPasses Return true; subclass ConditionalRule overrides this method to impose a condition on the rule

Description of attributes

Class Rule defines the following attributes:

Attribute Type Description
CanCopy Boolean Test whether this rule can be copied by the user
CanDelete Boolean Test whether object can be thrown away
Description Object The getter and setter for the description field
Enabled Boolean Test whether rule is currently in force
RuleAction RuleAction The getter and setter for the RuleAction field
RuleQualifier RuleQualifier The getter and setter for the RuleQualifier field

Fields defined by class Rule

Class Rule defines the following fields:

Field Type Description
ruleFlags Unsigned Flags that control various aspects of rule behavior
ruleTemplate Object An object containing the generic rule text and the controls to edit the rule
ruleTrigger Object The trigger object that lists this rule
description Object The text description of the rule, as displayed to the user
ruleAction RuleAction Action to perform when the rule is enabled
ruleQualifier RuleQualifier An extra condition that must be met before a rule action is performed

The ruleFlags describe how the rule responds to user actions, among other things. See the section on rule flags later in the chapter for a list of available flags.

The other fields are described in detail in the sections immediately following this one.

What's in a Rule?

Rules have three major components: a description, an action, and a qualifier. Editable rules have an additional template component.

The rule's description is the text the user sees in the rule view window. You'll use a text object to contain the description.

The RuleAction is the action the rule performs. The rule action object specifies the type of the action, the object to act on, and the operation to call on that object. See the chapter on class LocalRuleAction for details on creating the common action types.

The RuleQualifier specifies a condition that must be met before the action will be taken. See the chapter on class LocalRuleQualifier for details on creating the common qualifier objects.

The next sections give you examples of each of these pieces and show you how to construct rules from them.

Creating Simple Rules

Simple rules aren't editable. The user just taps their text to turn them on and off. These rules are the easiest to construct. To make simple rules, you need only four pieces:

You don't need rule templates for simple rules, since templates describe how rules are edited.

Here's the rule that sends everything in the outbox as soon as the outbox contains an urgent message:

Instance Rule 17;
      ruleFlags: 0x40400000;
   ruleTemplate: nilObject;
    ruleTrigger: iNewCardInOutboxTrigger;
    description: (Text 18);
     ruleAction: (LocalRuleAction 19);
  ruleQualifier: (LocalRuleQualifier 20);
End Instance;

Instance Text 18;
           text: 'Send everything in the out box as soon \
as it contains an urgent message.';
End Instance;

Instance LocalRuleAction 19;
     actionType: 7; // actionDoOperation
   actionObject: iOutBoxStack;
     actionData: operation_AddToSendQueue;
End Instance;

Instance LocalRuleQualifier 20;
  qualifierType: 2; // qualifyMailAttribute
qualifierObject: (MailAttribute 'urgent' 3651);
  qualifierData: 0;
End Instance;

The rule trigger is the trigger that's posted when a new card is put in the outbox. (Anybody who puts a card in the out box is responsible for calling PostTrigger on the trigger list.) If the rule is enabled, it's checked to see if it meets its qualifier condition. The qualifier object for this rule checks the card's mail attributes. In this case, the card is checked to see if it's urgent. If the card is urgent, it's added to the send queue and immediately mailed.

Creating Editable Rules

Editable rules have one, two, or three pieces that can be customized by the user. For example, they might play a sound chosen by the user when a certain action takes place. You can edit these pieces of your rule:

The rule template tells the system how to use controls to edit your rule and how to construct a text object that describes the current state of your rule.

To make editable rules, you need

Here's the rule that sends everything in the out box as soon as it contains a certain number of messages:

Instance Rule 30;
      ruleFlags: 0x40400000;
   ruleTemplate: (RuleTemplate 31);
    ruleTrigger: iNewCardInOutboxTrigger;
    description: (Text 32);
     ruleAction: (LocalRuleAction 35);
  ruleQualifier: (LocalRuleQualifier 37);
End Instance;

Instance RuleTemplate 31;
      ruleFlags: 0x80000000;
   ruleTemplate: nilObject;
    ruleTrigger: nilObject;
    description: (Text 33);
     ruleAction: nilObject;
  ruleQualifier: nilObject;
    controlList: (ObjectList 34);
        mapping: (TextMapping 38);
numQualifierControls: 0;
End Instance;

Instance Text 32; // the complete rule text
           text: 'Send everything in the out box as soon as it contains at least 
1 item(s).';
End Instance;

Instance Text 33; // template text
           text: 'Send everything in the out box as soon as it contains at least 
/number/ item(s).';
End Instance;

Instance ObjectList 34; // template controls
         length: 1;
          entry: (Meter 'number of items' 36);
End Instance;

Instance LocalRuleAction 35; 
     actionType: 7;
   actionObject: iOutBoxStack;
     actionData: operation_AddToSendQueue;
End Instance;

Instance Meter 'number of items' 36;
// meter definition goes here (elided for brevity)
End Instance;

Instance LocalRuleQualifier 37;
  qualifierType: 7;
qualifierObject: iOutBoxStack;
  qualifierData: 1;
End Instance;

The description field contains a text object holding the text the user sees when the Rule icon in the magic lamp window is tapped. For Rule objects, this will be the specific text for the rule. In the example, this text is "Send everything in the out box as soon as it contains at least 1 item(s)." The text field of a RuleTemplate object contains the more generic description of the rule, used with the text mapping object. In the example, this text is "Send everything in the out box as soon as it contains at least /number/ item(s)." The chapter on class RuleTemplate describes text mappings in detail.

Your template's control list should list one control for every aspect of the rule that can be changed. You should also have one text mapping piece for every editable aspect.

For a complete description of rule templates, see the chapter on class RuleTemplate.

System Triggers

You might want to add your rule to one of the system trigger lists instead of using your own trigger list. The system defines these indexicals for its trigger lists:

Trigger When triggered
iMessageArrivedTrigger A new card arrives in the inbox (for example, would trigger rules that play sounds, file automatically, or delete automatically)
iMessageSentTrigger A message is sent
iTaskAlarmTrigger A task alarm goes off (usually triggers rules that control how the alarm is signalled to the user)
iIncomingCallTrigger The phone rings
iPhoneLineConnectedTrigger The user has plugged a phone line into the Magic Cap device
iEmptyTrashTrigger The trash is emptied (only pulled if an object was actually deleted)
iNewCardInOutboxTrigger A new card has just been put into the outbox (often triggers rules that decide when to send the contents of the outbox)
iPurgeFileCabinetTrigger The File Cabinet has items more than a week old (used to prompt the user to delete the old items)
iPurgeDatebookTrigger The Datebook has items more than a week old (used to prompt the user to delete the old items)
iPurgePhoneLogTrigger The Phone Log has items more than a week old (used to prompt the user to delete the old items.

Add your own rule to one of these trigger lists the same way you add any object to an object list: with a call to AddTo. Your call might look like this:

AddTo(iEmptyTrashTrigger, myTrashRule);

Remember that order matters. It would matter particularly for this trigger. Your rule might only get its chance to act after other trash rules have deleted the trigger object!

Rule Flags

Class Rule defines a number of flags you can set in your rule's ruleFlags field. This section describes those flags.

isTemplate

#define isTemplateMask        0x80000000

This flag is reserved by the system. Please don't use it.

isEnabled

#define isEnabledMask         0x40000000

The system sets this flag for rules that are enabled. Set this flag if you want your rule to be enabled by default.

The Enabled and SetEnabled methods check and set this flag. The InvokeRule method checks this flag, and only performs the rule's action if it's set. Many other methods also check this flag.

actionOnTap

#define actionOnTapMask       0x20000000

Set this flag if you'd like your rule's action to take place when the user taps your rule in the rule view. You'd set this flag for rules that are customization options. For example, the rule in the datebook that shows the moon phases in the monthly calendar sets this flag. The moons should be shown or hidden at the same time the user enables or disables the rule. Another example is the rule that turns daylight savings time on. This rule should take effect (and change the time) when the user enables it.

hasAttribute

#define hasAttributeMask             0x10000000

Set this flag for rules that use the action type actionSetAttribute. This flag is checked by UpdateEnabled when it's updating rules that might have changed outside the rules interface.

sceneAttribute

#define sceneAttributeMask            0x08000000

Set this flag to change the way the action type actionSetAttribute works. If this flag is set, the rule's action will set an attribute of the current scene to the value of your rule's action object. If this flag isn't set, the action sets an attribute of the action object to the value of the action data. For details, see the description of the actionSetAttribute action type in the chapter on class LocalRuleAction.

isDirty

#define isDirtyMask                    0x04000000

The system sets the isDirty flag for cloud rules the user has changed. Rules that set this flag will be included in the next message informing the cloud of changes to cloud rules. You shouldn't set this flag for your rules.

isCloud

#define isCloudMask                    0x02000000

Set this flag if your rule is a cloud rule; that is, if your rule is the Magic Cap interface to a rule that affects the user's account in a Telescript mail service. You won't need this flag unless you're a Telescript developer.

intrinsicUseActionObj

#define intrinsicUseActionObjMask    0x01000000

Set this flag to change the way the action type actionDoIntrinsicOperation works. If this flag is set, the system passes the action object to IntrinsicByNumber. If this flag isn't set, the system passes the trigger data. For details, see the description of the actionDoIntrinsicOperation action type in the chapter on class LocalRuleAction.

performWhenChanged

#define performWhenChangedMask    0x00800000

Set this flag if your rule action should be performed when the rule is changed by the user. If this flag is set, the system will call PerformRule when the user taps the accept button after changing the rule.

ruleNoCopy

#define ruleNoCopyMask                0x00400000
#define ruleNoCopyBit                22

Set this flag for rules that you don't want the user to copy.

The CanCopy and SetCanCopy methods check and set this flag. RuleView_SetEditMode hides the rule view's copy button if the current rule can't be copied.

ruleInitiallyEnabled

#define ruleInitiallyEnabledMask    0x00200000

The system keeps track of which rules were intially enabled using this flag. Please don't set it yourself.

ruleNoTextUpdate

#define ruleNoTextUpdateMask     0x00100000

This rule is set for certain cloud rules. If this flag isn't set, class RuleView will call UpdateText on a rule when displaying the rule. Don't set this flag unless you're writing a cloud rule.

ruleCanDelete

#define ruleCanDeleteMask       0x00080000
#define ruleCanDeleteBit        19

Set this flag if your rule can be deleted by the user. The CanDelete and SetCanDelete methods check and set this flag.

ruleActionOnConditionList

#define ruleActionOnConditionListMask    0x00080000

This flag is reserved by the system. Please don't set it.

Method Descriptions

InvokeRule

operation InvokeRule(triggerData: Unsigned)

Call: sometimes
Override: rarely

The system calls InvokeRule on each rule in a trigger list when PostTrigger is called on the list. InvokeRule performs the rule's action if the rule passes its qualifier test.

If the rule doesn't have a qualifier, the rule automatically qualifies. Otherwise, InvokeRule calls QualifyRule to check if the rule meets its qualification. If the rule qualifies, InvokeRule calls PerformRule like this:

PerformRule(Field(self, ruleAction), triggerData, self);

ConditionPasses

operation ConditionPasses(): Boolean;

Call: rarely
Override: rarely

The RuleView class calls ConditionPasses from its FilterConditionalRules method. If the rule's condition passes, the rule view includes the rule in its display list. Otherwise, the rule doesn't appear.

Rule_ConditionPasses returns true by default. Class ConditionalRule overrides this method to pass along the ConditionPasses call to the rule's condition. For more information on conditional rules, see the section on Related Classes earlier in this chapter.

UpdateText

operation UpdateText()

Call: rarely
Override: rarely

The system calls UpdateText when the user has edited the rule or when it changes the rule programmatically. UpdateText creates a current text description for editable rules, which have descriptions that might change. UpdateText does nothing if the rule doesn't have a template or a text mapping.

If the rule does have a template and a text mapping, UpdateText calls ComputeRuleText on both the rule's qualifier object and its action object, to give both a chance to map text appropriately. See the description of text mappings in the chapter on class RuleTemplate for details on how the text description is created.