Welcome, Guest. Please Login or Register
Tinderbox
  News:
Looking for tech support? Contact info@eastgate.com
  HomeHelpSearchLoginRegister  
 
Pages: 1 2 
Send Topic Print
Toward Code Macros (Read 6816 times)
Ted Goranson
Full Member
*
Offline



Posts: 119
Virginia Beach VA
Toward Code Macros
Aug 22nd, 2011, 2:03pm
 
I have code fragments that get reused. I’d like to start using a custom function, aka code macro.

My intended strategy is to place the long form of the code in the text of a note. It would then nominally be called as $Text(MyNoteName).

So, supposing I have a rule with a bunch of code unique to this note plus this boilerplate that is common to many notes. How would this be included?

Back to top
 
 
WWW TedGoranson   IP Logged
Mark Anderson
YaBB Administrator
*
Offline

User - not staff!

Posts: 4568
Southsea, UK
Re: Toward Code Macros
Reply #1 - Aug 22nd, 2011, 2:29pm
 
Actually, this came up in a slightly different form just this weekend in the topic "Listing all individual entries in an attribute?" (start reading at post #7.

Started another way you wish to leverage the ease of use of a code-note but you need to be able to pass it a variable. Currently, this is not possible. However, you can do a similar task via a macro. Sadly, macros can't be stored in/called from notes (feature request!), though you could use a code-note to draft the code and copy paste the code to the macro box (Macros tab of attributes palette).

~~~~~~~~

An idea... I've not time to test this right now, but perhaps you could pass a single variable to a code note. Rough idea: with a code code, we call it like eval($Text("My Code note")), but what if we used .replace() and macro-like replacement target strings. Thus instead of a '$1' type placeholder we use an unlikely string, say "ZZZZ". We put this everywhere we want to insert the input variable. Now we call eval($Text("My Code note").replace("ZZZZ","my input")). So first the target note does a delete on it's $Text which is then evaluate Not as flexible as a macro, but something you could try if you've only one input variable.

Before someone moans that the above is 'hard', I'm not suggesting it is simple - but it is something do-able today. Put another way, if someone really needs this now, it won't seem so hard.  Wink

Back to top
 
 

--
Mark Anderson
TB user and Wiki Gardener
aTbRef v5
(TB consulting - email me)
WWW shoantel   IP Logged
Ted Goranson
Full Member
*
Offline



Posts: 119
Virginia Beach VA
Re: Toward Code Macros
Reply #2 - Aug 22nd, 2011, 2:38pm
 
Actually Mark, I wanted to do the simple version first; referencing a code note in the midst of other code, but without passing a variable.

I’ll try eval($Text(“My Code Note”))

Then I’ll try the replace trick.
Back to top
 
 
WWW TedGoranson   IP Logged
Mark Anderson
YaBB Administrator
*
Offline

User - not staff!

Posts: 4568
Southsea, UK
Re: Toward Code Macros
Reply #3 - Aug 22nd, 2011, 2:51pm
 
If it's literally just boilerplate text, then you can just call $Text for that note. By contrast, if there is action code in the note the eval() call will give you the action code result of what's in that $Text.

If you get to going the latter route, do an initial test with something simple so you know the basic principle works.  That way, when - as we all do, you dive in with the fiendishly complex code you actually want to use and it fails, you've some point of confidence to lean on.
Back to top
 
 

--
Mark Anderson
TB user and Wiki Gardener
aTbRef v5
(TB consulting - email me)
WWW shoantel   IP Logged
Mark Anderson
YaBB Administrator
*
Offline

User - not staff!

Posts: 4568
Southsea, UK
Re: Toward Code Macros
Reply #4 - Aug 22nd, 2011, 4:18pm
 
OK, here's a trivial example of my last idea above.

Add a Number attribute $MyNumber and a String $MyString. Now add a now note "mathstest" - I also gave mine the build-in prototype "code" for good measure. Set the note's $Text to :

  4 + ("ZZZZ").toNumber

Why the 'toNumber'? Well, replace() uses strings and here I want to do some simple maths. The "string".toNumber tells TB to treat the number-string as if it were a number.

Now in another note add this rule (split on lines here for clarity):

$MyString = $Text("mathstest").replace("ZZZZ","6")
$MyNumber = eval($Text("mathstest").replace("ZZZZ","6"))


$MyString is now:   4 + "6".toNumber
$MyNumber is now:   10

Anyway, there's a simple proof of concept.
Back to top
 
 

--
Mark Anderson
TB user and Wiki Gardener
aTbRef v5
(TB consulting - email me)
WWW shoantel   IP Logged
Sumner Gerard
Full Member
*
Offline



Posts: 347

Re: Toward Code Macros
Reply #5 - Aug 22nd, 2011, 5:12pm
 
Quote:
simple version first; referencing a code note in the midst of other code, but without passing a variable


Not long ago I discovered I could place blocks of code in code notes DoThis and DoThat then run the code from this stamp:

action($Text("DoThis"));action($Text("DoThat")).


Assume same approach will work in rules too.
Back to top
 
 
  IP Logged
Mark Anderson
YaBB Administrator
*
Offline

User - not staff!

Posts: 4568
Southsea, UK
Re: Toward Code Macros
Reply #6 - Aug 22nd, 2011, 5:48pm
 
Stamps can be used to hold run blocks of code but won't take on-demand input variables.

The stamps/macros pre-date action code and are from a point where export capabilities were much simpler. For now, if it is necessary to use a large block of code using one or more inputs, the do() macro method is the only sensible way to go. Insert/run blocks of code without inputs either a stamp or 'code note' can be used.
Back to top
 
 

--
Mark Anderson
TB user and Wiki Gardener
aTbRef v5
(TB consulting - email me)
WWW shoantel   IP Logged
Ted Goranson
Full Member
*
Offline



Posts: 119
Virginia Beach VA
Re: Toward Code Macros
Reply #7 - Aug 22nd, 2011, 8:45pm
 
Sorry to be daft on this.

My immediate problem is that I want to call code notes without passing variables.

I have a code note that has a rule that assigns the text of that note to the rule of another.

In that code note, I wish to reference other code notes, so that the text of the Original Code Note contains statements such as:

$Text("secondary note 1");
$Text("secondary note 1");

But of course this does not work, nor does

eval($Text("secondary note 1"));
eval($Text("secondary note 1"));

I also tried putting the code in macros and placing this in the Original Code Note:

do("macro 1");
do("macro 2");

But Sumner's suggestion DOES WORK!

action($Text("secondary note 1"));
action($Text("secondary note 1"));

So there is something at a fundamental level that I am missing.

+++++

My long term problem is that I would like to pass variables.

If I understand it right, a stamp can only be evoked manually and you cannot pass variables.

The do(AMacro[SerialArg1, SerialArg2]); command seems ideal.

and it seems similar to $Text("ANote").replace("DenotedArg1","DenotedArg2");

But when in a passed rule, I suppose it needs to be:

action($Text("ANote").replace("DenotedArg1","ReplacedArg1"));

right?
Back to top
 
 
WWW TedGoranson   IP Logged
Sumner Gerard
Full Member
*
Offline



Posts: 347

Re: Toward Code Macros
Reply #8 - Aug 23rd, 2011, 12:43am
 
Originally I didn't realize that the 'do' in macro doesn't actually 'do' an action. It 'just' assembles text, though, as MarkA has demonstrated, in pretty powerful ways.  

To actually 'do' something, i.e. run the assembled text as action code, what I do is try:

$OutputAttribute=eval(do(macroname,$InputAttribute1,$InputAttribute2...))

Or, if the assignment to the "output" variable is done within the macro, I try:

action(do(macroname,$InputAttribute,$InputAttribute2...))

And, I run a block of code in a code note with action($Text("cNameOfCodeNote")).



Here, the code in the 'multintern' macro is $MyResult=$1*$2 and in 'mult' is simply $1 * $2

I now realize macros aren't mysterious things mainly useful for exporting to web pages and such. Combined with eval() and action() they can be used very much like a function in a spreadsheet. And it's easy to "roll your own"!

And by combining stamps with action() and code notes, it's easy to set up a user-defined menu.

I've attached a test tbx with examples including the above and others that helped me begin to understand the possibilities.

Look forward to more on the .replace technique from the master.
Back to top
 
 
  IP Logged
Mark Anderson
YaBB Administrator
*
Offline

User - not staff!

Posts: 4568
Southsea, UK
Re: Toward Code Macros
Reply #9 - Aug 23rd, 2011, 3:43am
 
This thread is getting very complex - we're discussing edge cases for tasks for which operators were likely never envisaged (or tested for such) and at the same time nuances of the context of invoking them ... and then trying to applying certainties.

Meanwhile, Eastgate's engineering efforts are focused heavily on other TB matters right now (stuff people really want too) and so I don't think it useful to make this edge case stuff a priority at this time. I'm sure this will get resolved, but probably not right now.

I'll try and nibble away at some issues, perhaps in more bite size posts.

Back to top
 
 

--
Mark Anderson
TB user and Wiki Gardener
aTbRef v5
(TB consulting - email me)
WWW shoantel   IP Logged
Mark Anderson
YaBB Administrator
*
Offline

User - not staff!

Posts: 4568
Southsea, UK
Re: Toward Code Macros
Reply #10 - Aug 23rd, 2011, 3:47am
 
Quote:
Originally I didn't realize that the 'do' in macro doesn't actually 'do' an action.


do() is a port of ^do()^. The latter was a method of inserting modified boilerplate or things like inline <img> tags where multiple inputs are needed: filename, height, width, title/alt, class, id, ....etc. As such, do() returns the contents of the macro with inline substitutions for regex-style $-references; the first input after the macro's name - i.e. the second param -> $1, the third param  -> $2, etc. See the docs for more on macro syntax.

So action code expands and ^do()^ becomes do(), the code is tested in basic form and it sits on the shelf, little used. Fast forward: now we want to pass parameters to snippets of code -  as if in functions. Would that we could use eval($Text("some note"), arg1, arg2...). But we can't. Out comes do(), but it seems that in transferring from an export to action context some evaluations don't occur as envisaged. Using eval(do()) is a slight band-aid. Actually I don't think eval() should be required but for reasons stated above getting a detailed answer just now is difficult. Still, we're exploring the 'do-able' so if an eval() wrapper fixes the problem, that will do until better syntax comes along.

Later: I meant to add, that in discussion off forum, it does seem do() was intended evaluate (action) code inside the macro but doesn't currently (v5.9.3). My hunch is do() still assumes code inline is export code which, of course, is something now deprecated in general use (export code in an action code context that is).
Back to top
 
 

--
Mark Anderson
TB user and Wiki Gardener
aTbRef v5
(TB consulting - email me)
WWW shoantel   IP Logged
Mark Anderson
YaBB Administrator
*
Offline

User - not staff!

Posts: 4568
Southsea, UK
Re: Toward Code Macros
Reply #11 - Aug 23rd, 2011, 4:12am
 
eval() vs action(). As concisely as I can put it, they do the same but eval() returns something and action() doesn't:

$ReturnValue = eval( [some code] )
action( [some code] )


The temptation comes - and here Im' as guilty as the next person -  of using these as a crowbar to force TB to produce a result for which syntax appears missing.

Let's pick a trivial task, the sum of 2 plus 3 (5).  For eval() use, we'll make the $Text of 'test1': 2 + 3. $ReturnValue is a user String attribute just added to hold the result (such a name sometimes fools learners into thinking it is some built-in feature). Now in note "X", we run this rule:

$ReturnValue = eval($Text("test1"))

The $ReturnValue of  note X [sic] is now "5". Change the rule to

action($Text("test1"))

Nothing happens in either 'X' or in 'test1'. No, the $Text of 'test1' doesn't become "5". Why? We're not evaluating the contents of $Text, we're running is as action code. Although '2 + 3' is valid action code maths addition it doesn't tell us what to do with the result so action() has no outcome.

The pont of the above is that context matters. Avoid using eval() and action() as the tool of last resort without first stopping to consider context.

Why eval() failed and action() worked for Ted I can't say but without more detail or a TBX example it's hard to say why and whether the result is correct or some form of false positive (which is a slight worry bead I have).
Back to top
 
 

--
Mark Anderson
TB user and Wiki Gardener
aTbRef v5
(TB consulting - email me)
WWW shoantel   IP Logged
Sumner Gerard
Full Member
*
Offline



Posts: 347

Re: Toward Code Macros
Reply #12 - Aug 23rd, 2011, 8:49am
 
Quote:
This thread is getting very complex - we're discussing edge cases

Pretty central to some things I do, and I think Ted is trying to do. And not complex, certainly less complex than many things I've seen discussed on the forum. These actually have made life much simpler for me. action(), eval() and do() in conjunction with stamps and code notes are very convenient and could be better documented at some point to remove the mystery.

Quote:
Eastgate's engineering efforts are focused heavily on other TB matters right now (stuff people really want too

Don't think Eastgate needs to do anything here.  Works great as is, once it's understood what do() does do and doesn't do.... At some point some sort of  loop(item, DoThisWithEachListItem) would be nice.

Quote:
it does seem do() was intended evaluate (action) code inside the macro but doesn't currently

Gee, I hope not. There are times when one "just" needs to assemble a string. There are other times when one wants to assemble it and then run it as code. Things are pretty good the way they are. All one has to do is place the do() in an eval() or action() and lots of things are possible.


Quote:
eval() returns something and action() doesn't

That seems to be the crucial point, which aTbRef covers and my simple examples illustrate.

In the '2+3' example, if one has just '2+3' in $Text then I use $ReturnValue=eval($Text("test1")).  

If the "entire" action code '$MyResult=2+3' is in $Text then I use action($Text("test1")).

eval() won't show anything or seem to do anything unless the user specifies a place to put the result, whereas action() will run "complete" code that already specifies where the result is to go.

Is that not as it should be? And how TB is designed?

Back to top
 
 
  IP Logged
Mark Anderson
YaBB Administrator
*
Offline

User - not staff!

Posts: 4568
Southsea, UK
Re: Toward Code Macros
Reply #13 - Aug 23rd, 2011, 9:52am
 
What I means by complex was at one and the same time discussing the syntax of operators whose exact design intent is not documented (and can't be unambiguously worked out be the user) at the same time as the context of execution. The second adds a second layer of false positive/negative outcomes in an app that (by design) avoids giving error messages.  It means this aspect of use is definitely really for those with a good degree of TB action code experience under their belt. My little example above was deliberately ludicrously simple so as to give a working base off which to try more real world things.

For me, the confusion around eval() & macros arose in the context of Alex Strick's problem (in the main forum) where we were coercing a list of strings into a string of macros and wanting the (correct) evaluated output. It proved the context of the eval() call makes quite a difference.

I've made a note to cross-reference do() and eval() in aTbref. The info to capture there is that do() returns a string with multiple verbatim substitutions of between and nine input strings for $-placeholders ($1-$9). Any action/export code within the macro or the input is not evaluated. Ergo if you need to insert an evaluation of an input, you must evaluate the input before passing the result to the macro. Wrapping an eval() call around do() will evaluate the whole macro output string. Whether the latter will suffice probably boils down to thinking how many layers of nested evaluation are involved and/or how complex the evaluation is. Judicious addition of parentheses around nested evaluations may help. Until you know so from experience, don't assume eval(do()) will evaluate the way you assume it will; sometimes there's more than one valid answer - depending on your starting assumptions. Also, with more complex tasks, be alive to the possibility of no/single/double quoted strings being handled differently. The two quote type, correctly nested, should parse the same way but this is the area where you may hit an edge case in the app's parsing and you may need to check with support.

I'd agree that for the average users (and for the convenience of expert users as well) some of these constructs would be more accessible if some of the self assembly (correct nesting, etc.) were wrapped up in some new codes. I've already mailed in an idea to let do() use a note name/path as a valid input for the macro name argument. IOW, TB would look at stored macros and if no match is found, then use the $Text of the note cited as its macro code.  If nothing else, that would help me be able to read/structure my macro code more clearly!

[edit - typos]
Back to top
 
« Last Edit: Sep 18th, 2012, 6:42am by Mark Anderson »  

--
Mark Anderson
TB user and Wiki Gardener
aTbRef v5
(TB consulting - email me)
WWW shoantel   IP Logged
Mark Anderson
YaBB Administrator
*
Offline

User - not staff!

Posts: 4568
Southsea, UK
Re: Toward Code Macros
Reply #14 - Aug 23rd, 2011, 10:03am
 
Quote:
In that code note, I wish to reference other code notes, so that the text of the Original Code Note contains statements such as:

$Text("secondary note 1");
$Text("secondary note 1");

But of course this does not work, nor does

eval($Text("secondary note 1"));
eval($Text("secondary note 1"));

I also tried putting the code in macros and placing this in the Original Code Note:

do("macro 1");
do("macro 2");

But Sumner's suggestion DOES WORK!

action($Text("secondary note 1"));
action($Text("secondary note 1"));

So there is something at a fundamental level that I am missing.

In any note's text, this:

  $Text("secondary note 1");

does nothing as it needs to be evaluated to access whatever's in the referred-to $Text. This also fails:

  eval($Text("secondary note 1"));

because what you want is the output of eval() which hasn't been assigned to something. Not tested, but you could probably do:

  $TempString = eval($Text("secondary note 1")); --> do something with $TempString.

The reason for the failure of this should now be clear:

  do("macro 1");

You need to do one of:

$SomeAttribute = eval(do("macro 1")); -- if an output is needed
action(do("macro 1")); --> if no output is expected and the action has all necessary data to perform it's work.

The trickier part comes when we want to pass a value to a macro, the more so if that value is itself calculated in some way.
Back to top
 
 

--
Mark Anderson
TB user and Wiki Gardener
aTbRef v5
(TB consulting - email me)
WWW shoantel   IP Logged
Pages: 1 2 
Send Topic Print