How to show all overridden attributes


(Barry Weinstein) #1

Hi all,

I’m doing my best to do all styling and other attribute assignments at the prototype level, so as to maintain consistency in my model. Now and again an attribute override creeps in at the instance level. Is there a way to show all attributes that have been overridden to now and again review such things?

The file structure of the document would make it an hour’s work to do this with a little program which parses the xml. But, I’d like something a little more integrated with the Tinderbox program itself.

Regards,

Barry


(James Fallows) #2

Either of the Marks, Anderson or Bernstein, is likely to have The answer to this question.

But it feels like something for which there is a TB value on which you could base a search. Ie, there are lots of TB operations that involve some kind of test or sensing of default-vs-non-default values. As Mark A explains here, the $Attribute=; action resets an attribute to its default value. And the conditional assign operation – $Attribute|=somevaluechanges a value only if the default value is still in place. That is, it starts with a test for default-vs-otherwise.

Thus Tinderbox certainly has the tools to distinguish default values from others. I don’t know whether they’re accessible to use in an agent – but Mark B or Mark A would.


(Mark Anderson) #3

If you just want to reset a given attribute’s value use $AttributeName=;. If you want to test if a note has a local value (even if no value, but set locally) test hasLocalValue(). For instance, to find notes with a locally set Rule; try:

hasLocalValue("Rule")

Or for an agent to test notes using prototype ‘X’ with a locally set $OnAdd and to reset that attribute:

Query:$Prototype=="X" & hasLocalValue("OnAdd")
Action:$OnAdd=;


(Brian Crane) #4

hasLocalValue() is new to me and useful. At risk of going off thread: is there a simple reason why the attribute name doesn’t take a “$” here? And is this a rule that extends beyond this particular query?


(James Fallows) #5

Me too! I thought / assumed there was some attribute like that but didn’t know what it was called. Good to know.


(Barry Weinstein) #6

Thanks for the responses.

I don’t think hasLocalValue() is a solution to what I want, unless it’s part of some larger solution that satisfies the requirement. Perhaps I didn’t state it well.

I would like to right click on a notes and choose “Show all overridden attributes” from the context menu. In other words, show me all X such that hasLocalValue(X) is true. I would then review that list and see if any of those assignments should have been done on the note’s prototype instead to have broader impact. If I’ve been diligent, I would expect that nothing would need to change.

For example, I would expect positioning to have been overridden on every note, so the positioning attributes would be in the list, correctly so. But if I saw $Color in the list I would take a closer look. I typically want $Color to be overridden on a note that is a prototype and represents a classification of notes.


(Paul Walters) #7

As it is now, hasLocalValue takes a specific attribute as its argument. It is not a global query – i.e., hasLocalValue()==True is not a valid query.

(Consider why: a Tinderbox document can have hundreds of attributes – the results of the suggested query might be incomprehensible in a large document.)

On the other hand, if you think your errors are limited to a few attributes (e.g., $Color) then a stamp such as this works: $Color=;$Prototype=;$Prototype="[myPrototype]". What this does is zero-out the attribute that might be a problem, zeros out the prototype assignment, and resets the prototype and its settings to the defaults you want for that note.

This is a kludge. Because the query you want does not exist.


(Barry Weinstein) #8

Thanks Paul,

Yeah, I want the query only. I expect that as I get more experienced with Tinderbox I’ll rarely be wanting to fix things; I’ll just want to check that all is as expected.

Here’s another way it could be presented. Currently the attributes listing in the “Get Info…” dialog breaks things out by category. There could be another category (“Locally Assigned”) that shows the only the attributes with local values across all the categories.

In any case, it sounds like this is not available. I’ll write a program to do it, it won’t be hard. I’m going to assume there’s no Tinderbox API for developers, so I’ll write my code to read the Tinderbox file itself.

I’ll acknowledge that this requirement I have is mainly to cater for new user mistakes. Sometimes I try something on a note then undo it. Depending on how I do that I might leave an override that has the same value as its prototype’s attribute value. This will be undetected until I later change the prototype and find that some associated notes don’t change to conform to the prototype.


(eastgate) #9

In the Get Info attributes browser, immediate values are emboldened. So that’s one way to scan.


(Barry Weinstein) #10

Thanks for that.

I do see the bold presentation of attributes. That’s how I’ve been diagnosing my mistakes so far. I find it awkward as a mechanism for reviewing just the attributes that have been assigned. On the other hand, if there was away to select all categories of attributes at once, to see all the attributes in one list, then that would be closer to what I want.


(Mark Anderson) #11

Yes, because the argument is the name of the attribute, i.e. hasLocaleAttribute("SomeAttribute") for an attribute called ‘SomeAttribute’. If the argument were hasLocaleAttribute($SomeAttribute) then you’d be asking for (the presumed name of) an attribute stored in the attribute SomeAttribute.

This approach is used in a number of action codes and attributes. Off the top of my head: values(), $TableHeading, $KeyAttributes.


(eastgate) #12

$MyString is a string that is stored in the attribute named “MyString”.

Most of the time, “MyString” and “$MyString” are interchangeable; if you forget the ‘$’ in a context where your intention is clear, Tinderbox silently supplies it.

But in the case of values() or hasLocalValue(), we really mean that the argument is the name of the attribute, not the value stored in the attribute.


(Galen Menzel) #13

This isn’t correct, though it’s often how |= behaves. $Attribute |= somevalue will assign somevalue to $Attribute only when $Attribute's current value evaluates to false in a boolean context. Whether that value is a default value or not makes no difference.

As a quick counterexample, open a new Tinderbox document, and make a stamp with the action $Color |= "red". Applying this stamp to a new note will have no effect, even though the new note’s Color attribute still has its default value. This is because the default Color attribute for a new Tinderbox document is a non-empty string ("warm dark gray"), which evaluates to true in a boolean context.

By contrast, if you set a note’s Color to 0 (or to no value), and then apply the stamp, the note’s Color will then be set to "red".

Many attributes have a default value of the null value for their data type (0 for numbers, the empty string for strings, never for dates, etc.). These null values evaluate to false in a boolean context, so for these attributes, |= will act mostly as you’ve described. But for attributes such as Color, Width, and Container, which have non-false default values, |= will have no effect. If you really want to only override a default value, you have to use something like if(!hasLocalValue("Attribute")) {$Attribute = somevalue}.

As an aside, the |= operator page in aTbRef reads as incorrect to me. Specifically it states

In practical terms this means the left side, usually an attribute - is set to the right side value only if it is not already set at note level, i.e. its current value is either:

  • The default for that attribute data type (for a string attribute “”, for a number 0, for a date ‘never’, etc.)
  • A prototype-inherited value (which in effect is simply altering the default value)

The first bullet point is correct; as I understand it, the second one is not.

Furthermore, this example is given:

Consider three different notes and their $Color. The first is new and uncustomised, $Color is the default. The second has a prototype setting $Color to “green”. The third has been manually set to “bright blue” by the user. If this action is applied to all three notes:

$Color |= "bright red" 

then two of the three notes will recolour. The first is has a default $Color so changes. The second note is green, but only because that is the default inherited via its prototype; it too, is re-coloured as it currently uses a default value. The third note is bright blue and this was expressly set at note level. So, as the latter does not use a default value, it remains bright blue.

In fact, the action $Color |= "bright red" will have no effect on any of the notes, since in all three cases $Color is a non-false value. See the attached .tbx file, and note that the stamp with action $Color |= "red" has no effect on any of the notes.

or-equals-example.tbx (53.3 KB)


(James Fallows) #14

News to me! Thanks, and will await response from the TB gurus.


(Paul Walters) #15

True, for this example provided. Though – perhaps that is a glitch in 7.1.0 – and not the design?


(Mark Anderson) #16

The $Color example is wrong and for the reason stated in @galen’s answer: I think the error crept in circa the v5.0 baseline update of aTbRef when I merged some notes and the error’s rested unspotted since. I need to write a better example (to do).

Actually it is true, if the prototype is passing a value that evaluates to false. Thus make a prototype and set $Color to a non-default “” which equates to #00000 (black) and evaluates as false. A $Color |= "bright red" will set a note using the prototype to bright red because is the -inherited_ prototype value. That said I don’t think the current text aTbRef explains the nuance clearly.

Using colour was a bad strand for an example. I tend to use them as they help new, non-coding, users to more easily link cause (code) and effect (attribute value change). Also user-added String-type attributes default to a value of “”(i.e. false) so |+ is (or has been) a useful set-once-only mechanism. However, action code has got capable since that technique was first used and I think there are more flexible method as |= only works once in a correct scenario. Most new user will doubtless develop in the TBX they’ll actually use for their work and overlook the need to reset attributes after testing. So, they get unexpected apparent logic failures and have to be tallied through the obscure nature of booleans, etc.

So, I’ve marked the aTbRef article for re-writing.


(Mark Anderson) #17

OK, the logical OR assignment article has been re-written to reflect the errors discussed above (the logical AND assignment has also had an edit). I’ve also uploaded a refresh of the aTbRef zip file reflecting these changes.


(eastgate) #18

Yes: |= performs the assignment only if the attribute’s current value is false (false, the empty string, the empty set or list, 0 or the time never)


(Galen Menzel) #19

Hi Mark,

Thanks for the quick correction! A couple suggestions:

To make it easier to write rules succinctly, you may use the assignment:

$TheAttribute |= the_expression; 

…which sets $TheAttribute to true if it is already true OR if the_expression is true.

I find it a bit confusing to say that |= sets $TheAttribute to true, since in most cases it will not set $TheAttribute to boolean true. Perhaps something like "which sets $TheAttribute to the value of the_expression whenever $TheAttribute’s value is false" or something like that?

if $TheAttribute is set to a value evaluates (the left side of the code) as false. Therefore the_expression (the right side of the code) is evaluated. If the_expression evaluates as true $TheAttribute takes the value of the_expression. On subsequent iteration of the code $TheAttribute thus evaluates as true. But, if the_expression evaluated to false, both it and the overall action evaluate as false, i.e. $TheAttribute’s value remains unchanged.

As far as I can tell, $TheAttribute always takes on the value of the_expression, regardless of whether the_expression evaluates to true or false. As a quick example, create a new note and set its $Color to 0. Create a stamp with the action $Color|="". Applying this stamp will set that note’s color to "" (a different color value than 0), even though "" evaluates to false.


(Pat Maddox) #20

This stamp will help you find any $KeyAttributes which are overridden… maybe it’ll be a good starting point for solving your problem:

$MySet = ;
$KeyAttributes.each(A) {
  if(hasLocalValue(A) & A != "MySet") {
    $MySet = $MySet + A;
  }
};