I have an AppleScript that I'm trying to modularize for future use. Working fine: a script that steps through nested Finder folders recursively. What I want: that script to call another subroutine with its own parameters.
Sample code (with a working recurse function), where I'm using commented pseudocode for the parts I need help with:
on recurseFolders_runSubroutine(thisItem, subName, subParameters, notify)
global itemcount
try
set itemcount to itemcount + 1
on error
set itemcount to 1
end try
tell application "Finder"
if notify then display notification ("Recursing into folder ") & name of thisItem with title "Entering Folder"
if kind of thisItem is "Folder" then
set subItems to every item in thisItem
set countItems to count subItems
repeat with i from 1 to countItems
set subItem to item i of subItems
my recurseFolders_runSubroutine(subItem, subName, subParameters, notify, itemcount)
end repeat
else
-- tell script ("subName" & .scpt) to [call subroutine named subName with the parameters, presumably passed in a list]
end if
end tell
end recurseFolders_runSubroutine
I tried it with a few variations on run script with a text string to call the function, but then I can't pass the list of subparameters as a list. Am I missing something?
Related
I want to have the possibility to stop a function launched by a button by pushing an other button. More precisely, I want to stop a while loop by changing a parameter :
stop=%F
while ... & stop<>%T
...
end
I tried to write a callback function that change a variable to stop the while :
function callback(handles)
stop=%T
end
but the action isn't triggered before the end of the previous one.
I guess there must be something to do with some threads but i don't have this knowledge in scilab.
You have two solutions. The first one with a prioritary expression callback:
b = uicontrol("style","pushbutton","callback","stop=%t","callback_type",10);
stop = %f;
while ~stop
sleep(1)
end
the second one with a prioritary function callback:
function fun()
stop = %t;
stop = resume(stop);
end
b = uicontrol("style","pushbutton","callback","fun","callback_type",12);
stop = %f;
while ~stop
sleep(1)
end
In the second case you have to use resume to return the local variable stop in the main workspace. Making callback prioritary is a must to interrupt waiting loops.
Description:
I am Writing/Editing a LinqToProgress query engine. So far simple functions within progress is simple to replicate, such as "A" >= "B" or Lookup(A, B) > 1, simple one liners that give boolean conditions. However to implement more advance function or custom functions I will need to be able to write multiline statements that can be plugged into conditions, meaning the inline function should be able to give a boolean result when you use DISP ( myFunc ) in the ABL ScratchPad (Using Eclipse) or similar programs.
Issue:
I need to convert the code between the //Start Here and //End Here to an inline boolean result.
DEF VAR i AS INT NO-UNDO.
DEF VAR LIST AS CHAR NO-UNDO INIT "one,two,three,four".
DEF VAR LIST2 AS CHAR NO-UNDO INIT "one,three,five".
DISP(
// Start Here
DO i=1 TO NUM-ENTRIES(LIST):
IF LOOKUP(ENTRY(i, LIST),LIST2) > 0 THEN RETURN TRUE.
END.
RETURN FALSE.
// End Here
)
Currently the code throws an error.
White space after colon ends statement. I tried looking for solutions on multiline statements/inline functions but so far found nothing.
Constraints:
Everything written needs to be contained within the Disp function.
I can't use previously created functions.
You should introduce a method or function that contains your code block. The ABL does not support statements and blocks as an expression.
Is there a pattern for a fire and forget mechanism in Ada? When I call a task entry, I don't want the caller to be blocked until the message has been processed. I would like the task to be asynchronous. What I've tried is
loop
select
accept xxx(params) do
-- save the parameters in a queue
end accept;
...
else
-- pick the next item off the queue and process it
end select;
end loop;
It looks like a clumsy mechanism. Maybe fire and forget is the wrong term. I've also tried one task filling up the queue and another taking entries off the queue. Is there a better way of implementing asynchronous tasks in Ada.
If you’re using Ada 2012, the way to go would be to use Ada.Containers.Unbounded_Synchronized_Queues (or the Bounded version): your user code calls Enqueue, your server task calls Dequeue which blocks if the queue is empty.
If not, the normal approach would be to use your own protected object to encapsulate a queue (which is how the Ada 2012 packages do it). Something like
package Parameters is new Ada.Containers.Vectors (Positive, Parameter);
protected Queue is
procedure Put (P : Parameter);
entry Get (P : out Parameter);
private
The_Queue : Parameters.Vector;
end Queue;
protected body Queue is
procedure Put (P : Parameter) is
begin
The_Queue.Append (P);
end Put;
entry Get (P : out Parameter) when not The_Queue.Is_Empty is
begin
P := The_Queue.First_Element;
The_Queue.Delete_First;
end Get;
end Queue;
and then
task body Server is
P : Parameter;
begin
loop
Queue.Get (P);
-- process P
end loop;
end Server;
I have a function that returns a string for a particular item, and I need to call that function numerous times and combine those strings into one. The combined string is bounded. I've made sure to fill it when space characters when it initializes but I keep getting "length check failed" errors. Is there something basic I'm doing wrong here?
FOR I IN 1..Collection.Size LOOP
Combined_String := combined_string & Tostring(Collection.Book(I));
END LOOP;
Unbounded_String is probably the easiest way to go:
with Ada.Strings.Unbounded;
use Ada.Strings.unbounded;
...
Temp_Unbounded_String : Unbounded_String; -- Is empty by default.
...
for I in 1 .. Collection.Size loop
Append(Temp_Unbounded_String, ToString(Collection.Book(I));
end loop;
If you then need to have the result placed in your fixed length standard string:
declare
Temp_String : constant String := To_String(Temp_Unbounded_String);
begin
-- Beware! If the length of the Temp_String is greater than that of the
-- fixed-length string, a Constraint_Error will be raised. Some verification
-- of source and target string lengths must be performed!
Combined_String(Temp_String'Range) := Temp_String;
end;
Alternatively, you can use the Ada.Strings.Fixed Move() procedure to bring the Unbounded_String into the target fixed-length string:
Ada.Strings.Fixed.Move(To_String(Temp_Unbounded_String), Combined_String);
In this case, if the source string is "too long", by default a Length_Error exception is raised. There are other parameters to Move() that can modify the behavior in that situation, see the provided link on Move for more detail.
In order to assign Combined_String, you must assign the full correct length at once. You can't "build up" a string and assign it that way in Ada.
Without seeing the rest of your code, I think Ada.Strings.Unbounded is probably what you should be using.
I know this is an ancient question, but now that Ada 2012 is out I thought I'd share an idiom I've been finding myself using...
declare
function Concatenate(i: Collection'index)
is
(tostring(Collection(i) &
if (i = Collection'last) then
("")
else
(Concatenate(i+1))
);
s: string := Concatenate(Collection'first);
begin
Put_Line(s);
end;
Typed off the top of my head, so it'll be full of typos; and if you want it to work on empty collections you'll need to tweak the logic (should be obvious).
Ada 2012's expression functions are awesome!
Ada works best when you can use perfectly-sized arrays and strings. This works wonderfully for 99% of string uses, but causes problems any time you need to progressively build a string from something else.
Given that, I'd really like to know why you need that combined string.
If you really need it like that, there are two good ways I know of to do it. The first is to use "unbounded" (dynamically-sized) strings from Ada.Strings.Unbounded, as Dave and Marc C suggested.
The other is to use a bit of functional programming (in this case, recursion) to create your fixed string. Eg:
function Combined_String (String_Collection : in String_Collection_Type) return String is
begin
if String_Collection'length = 1 then
return String_Collection(String_Collection'first);
end if;
return String_Collection(String_Collection'first) &
Combined_String (String_Collection'first + 1 .. String_Collection'last);
end Combined_String;
I don't know what type you used for Collection, so I'm making some guesses. In particular, I'm assuming its an unconstrained array of fixed strings. If it's not, you will need to replace some of the above code with whatever your container uses to return its bounds, access elements, and perform slicing.
From AdaPower.com:
function Next_Line(File : in Ada.Text_IO.File_Type :=
Ada.Text_Io.Standard_Input) return String is
Answer : String(1..256);
Last : Natural;
begin
Ada.Text_IO.Get_Line(File => File,
Item => Answer,
Last => Last);
if Last = Answer'Last then
return Answer & Next_Line(File);
else
return Answer(1..Last);
end if;
end Next_Line;
As you can see, this method builds a string (using Get_Line) of unlimited* length from the file it's reading from. So what you'll need to do, in order to keep what you have is something on the order of:
function Combined_String (String_Collection : in String_Collection_Type)
Return String is
begin
if String_Collection'length = 1 then
Return String_Collection(String_Collection'First).All;
end if;
Recursion:
Declare
Data : String:= String_Collection(String_Collection'First).All;
SubType Constraint is Positive Range
Positive'Succ(String_Collection'First)..String_Collection'Last;
Begin
Return Data & Combined_String( String_Collection(Constraint'Range) );
End Recursion;
end Combined_String;
Assuming that String_Collection is defined as:
Type String_Collection is Array (Positive Range <>) of Access String;
*Actually limited by Integer'Range, IIRC
[This is a simplified example]
I have a collection ("myCollection") in which exists three entries: ("hello", "goodbye", "welcome"). I want to iterate through the collection and if in the collection there is the entry "welcome" I want to take one action, if that entry doesn't exist I want to do something else. Like this (pseudo):
For Each entry in myCollection
If entry="welcome" Then
DoSomething()
End If
Next (If Not MsgBox("Bad!"))
Suggestions?
Try this:
Dim found as Boolean = false
For Each entry in myCollection
If entry="welcome" Then
DoSomething()
found = True
Exit For ' Assumes only want to DoSomething for one "welcome" '
End If
Next
If Not found Then
MsgBox("Bad!")
End If `enter code here`
Alternatively the LINQ version may look more succinct:
If myCollection.Contains("welcome") Then
DoSomething()
Else
MsgBox("Bad!")
End If