Thursday, December 14, 2017

#1 2017-11-14 02:49:18 pm

Joy
Member
From:: South Tirol
Registered: 2008-07-04
Posts: 539
Website

collecting all sub-handlers invoked by the first

It's easy to get the contents of a handler-block and the my-handler-blocks referencing to the first block, as I can build it in an "mechanical" way.

But I wanna get all sub-handler-blocks connected to the first handler-block
eg. lets say handler block 1 contains 2 my handler, those my-handlers contain more my handler - I need to collect all blocks connected to the first block), and therefore my code needs to be dynamic, looking recursively not just in down to two levels

I'm wondering how to approach my problem. Maybe with those incredible sorting routines of Nigel Garvey? (sweat) How to deal with them?

Offline

 

#2 2017-11-14 08:51:26 pm

DJ Bazzie Wazzie
Member
From:: the Netherlands
Registered: 2004-10-20
Posts: 2727
Website

Re: collecting all sub-handlers invoked by the first

Joy wrote:

It's easy to get the contents of a handler-block and the my-handler-blocks referencing to the first block, as I can build it in an "mechanical" way.



Can you provide some example code here to clarify what you mean? An handler-block is nothing more than code between the on handlerName and end handlerName placeholders. I assume you're referring to something else than a handler-block, right?

Joy wrote:

lets say handler block 1 contains 2 my handler, those my-handlers contain more my handler - I need to collect all blocks connected to the first block), and therefore my code needs to be dynamic, looking recursively not just in down to two levels



Don't you mean inheritance in script objects? I mean something like this where you create the parenting chain at run time and not at compile time?

Applescript:

on createParent(_parent)
   script --anonymous
       property parent : _parent
       property description : "parent"
       
       on getDescription()
           return my description
       end getDescription
   end script
end createParent

on createChild(_parent)
   script --anonymous
       property parent : _parent
       property description : "child object"
       
       on getDescription()
           return description
       end getDescription
       
       on getParentDescription()
           parent's getDescription()
       end getParentDescription
   end script
end createChild

set p to createParent(me)
set c1 to createChild(p)
set c2 to createChild(p)

return {p's getDescription(), c1's getParentDescription(), c2's getParentDescription()}

Offline

 

#3 2017-11-14 09:59:30 pm

t.spoon
Member
From:: BFE, Massachusetts
Registered: 2013-01-13
Posts: 211

Re: collecting all sub-handlers invoked by the first

To me it sounds like he's just asking for a meta-script that would pull a handler and all additional handlers the first handler depends on (regardless of how deep the nesting goes) out of a script.

IE:
-you run a script
- it asks you to select the script you'd like to operate on
- it presents a list of all handlers in that script and asks you to select one
- it creates a new script file that contains the handler you selected, and every other handler referenced by the one you selected, and every handler referenced by those handlers, recursive until all possible dependencies are included.

Let me know if that's correct... if so, it doesn't sound all that bad to script... except I'm thinking it might be hard to detect and avoid possible loop situations.

- Tom.


Hackintosh built February, 2012 |  Mac OS Sierra
GIGABYTE GA-Z68X-UD3H-B3 | Core i5 2500k | 16 GB DDR3 | GIGABYTE Geforce 1050 TI 4GB
250 GB Samsung 850 EVO | 4 TB RAID
Dell Ultrasharp U3011 | Dell Ultrasharp 2007FPb

Offline

 

#4 2017-11-17 05:07:12 am

Joy
Member
From:: South Tirol
Registered: 2008-07-04
Posts: 539
Website

Re: collecting all sub-handlers invoked by the first

DJ Bazzie Wazzie
cool
t.spoon was right with his assumption

Offline

 

#5 2017-11-18 01:15:46 pm

Joy
Member
From:: South Tirol
Registered: 2008-07-04
Posts: 539
Website

Re: collecting all sub-handlers invoked by the first

This is the piece of code i wrote. Its not a final solution, but a limited code, as its not good to collect more than a handler and its sub-handlers. Stopping there - need some input how to improve that and collect all handlers.:o

Applescript:

set Appscr_app to "Script Editor"
tell application Appscr_app
   tell document 2 #1
       #collect handlers
       set all_ppr to paragraphs
       set dd to 0
       set ls to {}
       repeat with a in all_ppr
           set dd to dd + 1
           set a to a as text
           if a begins with "on " then
               if "(" is in a then
                   set get_routine to text 4 thru ((offset of "(" in a) - 1) of a
               else
                   set get_routine to text 4 thru -2 of a
               end if
               if number of words of get_routine = 2 then
                   set get_routine to word 1 of get_routine
               end if
               
               copy (dd & " • " & get_routine as text) to end of ls
           end if
       end repeat
       
       #set ls to ls as text
       #return nrhdl
       if ls is "" then return
       
       activate
       set ch to choose from list ls with prompt "Wähle Block den Ihr kopieren wollt..." default items (item 1 of ls)
       if ch is false then return
       set ch to ch as text
       set get_offset to (offset of " • " in ch)
       set find_parag to text 1 thru (get_offset - 1) of ch as number
       set handlerNm to text (get_offset + 3) thru -1 of ch as text
       set cc_all_ppr to number of items in all_ppr
       set {copy_handler, my_hdlLs} to {{}, {}}
       repeat with b from find_parag to cc_all_ppr
           set get_parag to item b of all_ppr
           if get_parag begins with "end " & handlerNm then
               copy get_parag to end of copy_handler
               exit repeat
           else
               if " my " is in get_parag or "my " is in get_parag and "(" is in get_parag then
                   copy b to end of my_hdlLs
               end if
               copy get_parag to end of copy_handler
           end if
       end repeat
       set copy_handler to (copy_handler as text)
       #return copy_handler
   end tell
   
   #copy all my handlers connected to our handler if any
   set copy_handler to (copy_handler as text)
   if my_hdlLs is not {} then
       #log my_hdlLs
       repeat with a in (my_hdlLs as list) #just paragraph numbers
           set get_ppg to (item a of all_ppr)
           #log get_ppg
           set all_words to words of get_ppg
           #log all_words
           
           #find my in a paragraph
           set dd to 0
           repeat with b in all_words
               set dd to dd + 1
               set b to b as text
               if b is "my" then
                   set handlerVar to item (dd + 1) of all_words
                   exit repeat
               end if
           end repeat
           #log handlerVar
           
           set bb to 0
           repeat with c in ls
               set c to c as text
               set bb to bb + 1
               if handlerVar is in c then
                   set get_offset to (offset of " • " in c)
                   set handlerNm to text (get_offset + 3) thru -1 of c as text
                   set find_parag to text 1 thru (get_offset - 1) of c as number
                   exit repeat
               end if
           end repeat
           #log handlerNm
           #log find_parag
           
           set copy_Myhandler to {}
           repeat with d from find_parag to cc_all_ppr
               set get_parag to item d of all_ppr
               if get_parag begins with "end " & handlerNm then
                   copy get_parag to end of copy_Myhandler
                   exit repeat
               else
                   copy get_parag to end of copy_Myhandler
               end if
           end repeat
           #exit repeat
           set copy_handler to copy_handler & return & (copy_Myhandler as text)
       end repeat
       
   end if
   #return copy_handler
   
   set res to make new document with properties {contents:copy_handler}
   compile res
end tell

Offline

 

#6 2017-11-19 10:06:15 am

Nigel Garvey
Moderator
From:: Warwickshire, England
Registered: 2002-11-20
Posts: 4452

Re: collecting all sub-handlers invoked by the first

Here's an effort using the Satimage OSAX. It could no doubt be done with ASObjC instead, but with more code. Caveats at the top:

Applescript:

(*
   Choose a handler from a script document in Script Editor and copy it and any other handlers used during its execution to a new document.
   
   THIS SCRIPT REQUIRES THE SATIMAGE OSAX (<http://www.satimage.fr/software/en/downloads/downloads_companion_osaxen.html>).
   It's only intended for use where all the handlers are at the top level of the source script. It's not recommended for handlers in script objects, although it may sometimes work with them.
   Not fully proofed against text values or barred labels containing characters which might fool the regices.
   Only handlers are inserted into the new script. Any required properties, 'use' statements, or script objects are your own problem!
*)


on getHandlerAndSubhandlers(scriptText)
   script o
       property handlerMatches : missing value
       property handlerCount : missing value
       property handlerTextList : missing value
       property matchIndexList : missing value
       
       on doTheBusiness(scriptText)
           -- Get the text of all the handlers in the script and, as separate entities, the text after "end " in their last lines.
           set handlerMatches to (find text "(?m)^[ \\t]*+(?:on (?!error)|to )([[:alnum:]_\\|]++)(?:.(?!end \\1))++.end (\\1[^\\R]*+)" in scriptText using {0, 2} regexpflag {"MULTILINE"} with regexp, string result and all occurrences)
           -- Build a list of the "end" labels to present to the user.
           set labelList to {}
           set handlerCount to (count handlerMatches)
           repeat with i from 1 to handlerCount
               set thisMatch to item i of handlerMatches
               set end of labelList to (i as text) & " • " & end of thisMatch
           end repeat
           if (labelList is {}) then display dialog "\"No handlers found in the script.\" in German!" buttons {"OK"} default button 1 cancel button 1 with icon stop
           
           -- Get the user's choice of "top" handler and start a list of handler texts with it.
           set cflResult to (choose from list labelList with prompt "Wähle Block den Ihr kopieren wollt..." default items {item 1 of labelList})
           if (cflResult is false) then error number -128
           set chosenHandlerMatchIndex to (word 1 of beginning of cflResult) as integer
           set chosenHandlerMatch to item chosenHandlerMatchIndex of handlerMatches
           set chosenHandlerText to beginning of chosenHandlerMatch
           set handlerTextList to {chosenHandlerText}
           set matchIndexList to {chosenHandlerMatchIndex}
           
           -- Add the texts of any other handlers called during the execution of the chosen one.
           addSubhandlers()
           
           -- Return a single text containing all the handler texts collected.
           return (join handlerTextList using (linefeed & linefeed))
       end doTheBusiness
       
       on addSubhandlers() -- Recursive handler to identify and add any subhandlers called by the most recent addition to handlerTextList.
           set callingHandlerText to item -1 of handlerTextList
           repeat with i from 1 to handlerCount
               -- Only check handlers which aren't in handlerTextList already.
               if (i is not in matchIndexList) then
                   -- Get the full text and "end" label of each.
                   set thisMatch to item i of my handlerMatches
                   set {thisHandlerText, handlerEndLabel} to thisMatch
                   -- Make up a suitable regex to identify any call to this handler in the current calling handler.
                   if (handlerEndLabel contains ":") then
                       -- Interleaved parameters. All must be in the call.
                       set handlerCallRegex to (change {"[|(){}]", ":", " $"} into {"\\\\\\0", ":(?:\"[^\"]*+\"|\\\\{[^\\\\}]*+\\\\}|\\\\([^\\\\)]*+\\\\)|\\\\|[^\\\\|]*+\\\\||[^[:space:]]++) ", "(?:(?! )|(?= [-#(]))"} in handlerEndLabel with regexp)
                   else
                       -- Not interleaved parameters. Check for parenthesis in the top line of the handler.
                       set handlerTopLine to paragraph 1 of thisHandlerText
                       if (handlerTopLine contains "(") then
                           -- Positional parameters. The handler label must be followed by parenthesis in the call.
                           set handlerCallRegex to handlerEndLabel & "\\([^\\)]*+\\)"
                       else
                           -- Labelled parameters. The handler label and the first parameter label must both be in the call.
                           set handlerCallRegex to (change "^\\s*+(?:on|to) ([^ ]++)( [^ ]++).++" into "\\1.*\\2" in handlerTopLine with regexp)
                       end if
                   end if
                   -- Apply the regex to the text of the calling handler. If any hits, store this subhandler text and recurse to check _its_ subhandlers.
                   if ((find text handlerCallRegex in callingHandlerText with regexp and all occurrences) is not {}) then
                       set end of my handlerTextList to thisHandlerText
                       set end of my matchIndexList to i
                       addSubhandlers()
                   end if
               end if
           end repeat
       end addSubhandlers
   end script
   
   return o's doTheBusiness(scriptText)
end getHandlerAndSubhandlers

tell application "Script Editor" to set scriptText to text of document 2 #1
set extractedHandlersText to getHandlerAndSubhandlers(scriptText)
tell application "Script Editor" to compile (make new document with properties {text:extractedHandlersText})

Edit: Minor improvements and fixes.

Last edited by Nigel Garvey (2017-11-20 11:22:07 am)


NG

Offline

 

#7 2017-11-20 11:24:55 am

Nigel Garvey
Moderator
From:: Warwickshire, England
Registered: 2002-11-20
Posts: 4452

Re: collecting all sub-handlers invoked by the first

I wrote:

It could no doubt be done with ASObjC instead…


As here:

Applescript:

(*
   Choose a handler from a script document in Script Editor and copy it and any other handlers used during its execution to a new document.
   
   This version of the script uses ASObjC and required Mac OS 10.10 (Yosemite) or later.
   It's only intended for use where all the handlers are at the top level of the source script. It's not recommended for handlers in script objects, although it may sometimes work with them.
   Not fully proofed against text values or barred labels containing characters which might fool the regices.
   Only handlers are inserted into the new script. Any required properties, 'use' statements, or script objects are your own problem!
*)


on getHandlerAndSubhandlers(scriptText)
   script o
       use AppleScript version "2.4" -- Yosemite (10.10) or later
       use framework "Foundation"
       use scripting additions
       
       property |⌘| : current application
       property scriptNSString : missing value
       property handlerMatches : missing value
       property handlerCount : missing value
       property handlerTextArray : missing value
       property matchIndexList : missing value
       
       on doTheBusiness(scriptText)
           set scriptNSString to |⌘|'s class "NSString"'s stringWithString:(scriptText)
           -- Get the text of all the handlers in the script and, as separate entities, the text after "end " in their last lines.
           set handlerMatchRegex to |⌘|'s class "NSRegularExpression"'s regularExpressionWithPattern:("(?ms)^[ \\t]*+(?:on (?!error)|to )([[:alnum:]_\\|]++)(?:.(?!end \\1))++.end (?-s)(\\1.*+)$") options:(0) |error|:(missing value)
           set handlerMatches to handlerMatchRegex's matchesInString:(scriptNSString) options:(0) range:({0, scriptNSString's |length|()})
           -- Build a list of the "end" labels to present to the user.
           set labelList to {}
           set handlerCount to handlerMatches's |count|()
           repeat with i from 1 to handlerCount
               set thisMatch to item i of handlerMatches
               set thisLabelRange to (thisMatch's rangeAtIndex:(2))
               set end of labelList to (i as text) & " • " & (scriptNSString's substringWithRange:(thisLabelRange)) -- Automatic coercion of NSString to text.
           end repeat
           if (labelList is {}) then display dialog "\"No handlers found in the script.\" in German!" buttons {"OK"} default button 1 cancel button 1 with icon stop
           
           -- Get the user's choice of "top" handler and start a list of handler texts with it.
           set cflResult to (choose from list labelList with prompt "Wähle Block den Ihr kopieren wollt..." default items {item 1 of labelList})
           if (cflResult is false) then error number -128
           set chosenHandlerMatchIndex to (word 1 of beginning of cflResult) as integer
           set chosenHandlerMatch to item chosenHandlerMatchIndex of handlerMatches
           set chosenHandlerText to scriptNSString's substringWithRange:(chosenHandlerMatch's range())
           set handlerTextArray to |⌘|'s class "NSMutableArray"'s arrayWithObject:(chosenHandlerText)
           set matchIndexList to {chosenHandlerMatchIndex}
           
           -- Add the texts of any other handlers called during the execution of the chosen one.
           addSubhandlers()
           
           -- Return a single text containing all the handler texts collected.
           return (handlerTextArray's componentsJoinedByString:(linefeed & linefeed)) as text
       end doTheBusiness
       
       on addSubhandlers()
           set callingHandlerText to handlerTextArray's lastObject()
           repeat with i from 1 to handlerCount
               -- Only check handlers which aren't in handlerTextArray already.
               if (i is not in matchIndexList) then
                   -- Get the full text and "end" label of each.
                   set thisMatch to item i of handlerMatches
                   set thisHandlerText to (scriptNSString's substringWithRange:(thisMatch's range()))
                   set handlerEndLabel to (scriptNSString's substringWithRange:(thisMatch's rangeAtIndex:(2)))
                   -- Make up a suitable regex to identify any call to this handler in the current calling handler.
                   if ((handlerEndLabel's containsString:(":")) as boolean) then
                       -- Interleaved parameters. All must be in the call.
                       set handlerCallRegex to (handlerEndLabel's stringByReplacingOccurrencesOfString:("[|(){}]") withString:("\\\\$0") options:(|⌘|'s NSRegularExpressionSearch) range:({0, handlerEndLabel's |length|()}))
                       set handlerCallRegex to (handlerCallRegex's stringByReplacingOccurrencesOfString:(":") withString:(":(?:\"[^\"]*+\"|\\\\{[^\\\\}]*+\\\\}|\\\\([^\\\\)]*+\\\\)|\\\\|[^\\\\|]*+\\\\||[^[:space:]]++) ") options:(|⌘|'s NSRegularExpressionSearch) range:({0, handlerCallRegex's |length|()}))
                       set handlerCallRegex to (handlerCallRegex's stringByReplacingOccurrencesOfString:(" $") withString:("(?:(?! )|(?= [-#(]))") options:(|⌘|'s NSRegularExpressionSearch) range:({0, handlerCallRegex's |length|()}))
                   else
                       -- Not interleaved parameters. Check for parenthesis in the top line of the handler.
                       set handlerTopLineRange to (thisHandlerText's rangeOfString:(".+") options:(|⌘|'s NSRegularExpressionSearch) range:({0, thisHandlerText's |length|()}))
                       if ((thisHandlerText's rangeOfString:("(") options:(0) range:(handlerTopLineRange))'s |length|() > 0) then
                           -- Positional parameters. The handler label must be followed by parenthesis in the call.
                           set handlerCallRegex to (handlerEndLabel's stringByAppendingString:("\\([^\\)]*+\\)"))
                       else
                           -- Labelled parameters. The handler label and the first parameter label must both be in the call.
                           set handlerTopLine to (thisHandlerText's substringWithRange:(handlerTopLineRange))
                           set handlerCallRegex to (handlerTopLine's stringByReplacingOccurrencesOfString:("^\\s*+(?:on|to) ([^ ]++)( [^ ]++).++") withString:("$1.*$2") options:(|⌘|'s NSRegularExpressionSearch) range:(handlerTopLineRange))
                       end if
                   end if
                   -- Apply the regex to the text of the calling handler. If any hits, store this subhandler text and recurse to check _its_ subhandlers.
                   if ((callingHandlerText's rangeOfString:(handlerCallRegex) options:(|⌘|'s NSRegularExpressionSearch) range:({0, callingHandlerText's |length|()}))'s |length|() > 0) then
                       tell handlerTextArray to addObject:(thisHandlerText)
                       set end of matchIndexList to i
                       addSubhandlers()
                   end if
               end if
           end repeat
       end addSubhandlers
   end script
   
   return o's doTheBusiness(scriptText)
end getHandlerAndSubhandlers

tell application "Script Editor" to set scriptText to text of document 2 #1
set extractedHandlersText to getHandlerAndSubhandlers(scriptText)
tell application "Script Editor" to compile (make new document with properties {text:extractedHandlersText})


NG

Offline

 

#8 2017-11-20 06:55:33 pm

Joy
Member
From:: South Tirol
Registered: 2008-07-04
Posts: 539
Website

Re: collecting all sub-handlers invoked by the first

@ Nigel Garvey
  cool
Just awesome - it looks like a lot more work if done in pure AppleScript . OKk stop here, it's just a thought and no request at all- as I'm very happy to get more ApplescriptObjC under my hands to study... Which is a step in the future. It seems to me like going back in time when I studied AppleScript for the first time yikes yikes

Offline

 

Board footer

Powered by FluxBB

RSS (new topics) RSS (active topics)