Applescript functions - function

Is there a difference between the on and to keywords when declaring functions in applescript? Seems like they're interchangeable from what I've seen. Is that the case or would one be more useful than the other in some situations?

on and to are equivalent. See https://developer.apple.com/library/mac/documentation/AppleScript/Conceptual/AppleScriptLangGuide/reference/ASLR_handlers.html:
( on | to ) handlerName ¬
[ [ of | in ] directParamName ] ¬
[ ASLabel userParamName ]... ¬
[ given userLabel:userParamName [, userLabel:userParamName ]...]
[ statement ]...
end [ handlerName ]

Related

jq with multiple select statements and an array

I've got some JSON like the following (I've filtered the output here):
[
{
"Tags": [
{
"Key": "Name",
"Value": "example1"
},
{
"Key": "Irrelevant",
"Value": "irrelevant"
}
],
"c7n:MatchedFilters": [
"tag: example_tag_rule"
],
"another_key": "another_value_I_dont_want"
},
{
"Tags": [
{
"Key": "Name",
"Value": "example2"
}
],
"c7n:MatchedFilters": [
"tag:example_tag_rule",
"tag: example_tag_rule2"
]
}
]
I'd like to create a csv file with the value within the Name key and all of the "c7n:MatchedFilters" in the array. I've made a few attempts but still can't get quite the output I expect. There's some example code and the output below:
#Prints the key that I'm after.
cat new.jq | jq '.[] | [.Tags[], {"c7n:MatchedFilters"}] | .[] | select(.Key=="Name")|.Value'
"example1"
"example2"
#Prints all the filters in an array I'm after.
cat new.jq | jq -r '.[] | [.Tags[], {"c7n:MatchedFilters"}] | .[] | select(."c7n:MatchedFilters") | .[]'
[
"tag: example_tag_rule"
]
[
"tag:example_tag_rule",
"tag: example_tag_rule2"
]
#Prints *all* the tags (including ones I don't want) and all the filters in the array I'm after.
cat new.jq | jq '.[] | [.Tags[], {"c7n:MatchedFilters"}] | select((.[].Key=="Name") and (.[]."c7n:MatchedFilters"))'
[
{
"Key": "Name",
"Value": "example1"
},
{
"Key": "Irrelevant",
"Value": "irrelevant"
},
{
"c7n:MatchedFilters": [
"tag: example_tag_rule"
]
}
]
[
{
"Key": "Name",
"Value": "example2"
},
{
"c7n:MatchedFilters": [
"tag:example_tag_rule",
"tag: example_tag_rule2"
]
}
]
I hope this makes sense, let me know if I've missed anything.
Your attempts are not working because you start out with [.Tags[], {"c7n:MatchedFilters"}] to construct one array containing all the tags and an object containing the filters. You are then struggling to find a way to process this entire array at once because it jumbles together these unrelated things without any distinction. You will find it much easier if you don't combine them in the first place!
You want to find the single tag with a Key of "Name". Here's one way to find that:
first(
.Tags[]|
select(.Key=="Name")
).Value as $name
By using a variable binding we can save it for later and worry about constructing the array separately.
You say (in the comments) that you just want to concatenate the filters with spaces. You can do that easily enough:
(
."c7n:MatchedFilters"|
join(" ")
) as $filters
You can combine all this together like follows. Note that each variable binding leaves the input stream unchanged, so it's easy to compose everything.
jq --raw-output '
.[]|
first(
.Tags[]|
select(.Key=="Name")
).Value as $name|
(
."c7n:MatchedFilters"|
join(" ")
) as $filters|
[$name, $filters]|
#csv
Hopefully that's easy enough to read and separates out each concept. We break up the array into a stream of objects. For each object, we find the name and bind it to $name, we concatenate the filters and bind them to $filters, then we construct an array containing both, then we convert the array to a CSV string.
We don't need to use variables. We could just have a big array constructor wrapped around the expression to find the name and the expression to find the filters. But I hope you can see the variables make things a bit flatter and easier to understand.

is the order of the fields important when writing to a sheet?

I need to write to a google sheet using rest.
I have generated the following json:
{
"majorDimension": "ROWS",
"values": [
[
"foo",
"foo",
"foo",
"foo"
],
[
"foo",
"foo",
"foo",
"foo"
]
],
"range": "Sheet1!A1:D5"
}
as stated here: https://developers.google.com/sheets/api/samples/writing the order is "range","majorDimension" and "values". Is the order important or will it work even if the order is different ?
Answer is : no. You can put majorDimension, values and range in the order that you want.
As Marios Karamanis stated the order of the range definition is important.

Catch and handle (differently) different exceptions for the same block, with an ensure

I know from the MOOC documentation that it's possible to have the same handler for multiple exceptions that can occur during some block, e.g.:
[ do some work ]
on: ZeroDivide, Warning
do: [ :ex | what you want ]
In the same document, there's an example with ensure to make sure code is always executed (despite any exceptions):
[ doSomething ] ensure: [ alwaysExecuteThis ]
However, I would like something like:
[ do some work ]
on: ZeroDivide
do: [ :zeroDivide | handle it ]
on: Warning
do: [ :warning | handle it ]
ensure: [ alwaysExecuteThis ]
Admittedly, this is my Java experience influencing how I want to use Pharo.
It seems it's possible using nested blocks:
[ [ [ [ doSomething here ]
on: ZeroDivide
do: [ :zeroEx | 'zeroExc' crLog ] ]
on: Warning
do: [ :warning | 'warning' crLog ] ]
ensure: [ 'ensure' crLog ] ]
Try adding this method to BlockClosure:
on: exception1
do: block1
on: exception2
do: block2
^self on: exception1 , exception2 do: [:ex |
(exception1 handles: ex)
ifTrue: [block1 value: ex]
ifFalse: [block2 value: ex]]
Note that exception1 and exception2 can be subclasses of Exception or instances of ExceptionSet (created with #,).

Convert this JSON to a tree and find the path to parent

data= {
"saturn": [
"planet",
"american_car",
"car"
],
"american_car": [
"car",
"gas_driven_automobile"
],
"planet": [
"large_object",
"celestial_body"
],
"large_object": [],
"gas_driven_automobile": [
"gas_powered_road_vehicle",
"car"
],
"car": [
"vehicle",
"motor_vehicle"
],
"vehicle": [],
"motor_vehicle": [],
"gas_powered_road_vehicle": [],
"celestial_body": []
};
I need to write an algorithm where if I give the input "saturn" I need to get all the possible paths from saturn to different parents. for example,
saturn ->planet ->large_object
saturn ->american_car->car->vehicle
saturn ->american_car->car->motor_vehicle
saturn ->american_car->gas_driven_automobile->gas_powered_road_vehicle
saturn ->american_car->gas_driven_automobile->car->vehicle
and all the other possible paths.
I was thinking of somehow converting this to a tree and then using a library to calculate the path from the child to the parent.
Working on writing an algorithm, can't figure out how to start off on converting this to a tree.
Using jq, you can simply define a recursive function:
def parents($key):
if has($key)
then if .[$key] == [] then [] else .[$key][] as $k | [$k] + parents($k) end
else []
end;
To use it to produce the "->"-style output, invoke jq with the -r command-line option, and call the above function like so:
["saturn"] + parents("saturn")
| join(" -> ")
More economically
def lineages($key):
[$key] + (lineages(.[$key][]) // []);
lineages("saturn") | join(" -> ")

How to retrieve recursive path to a specific key (not displaying the parents' key name, but the value from a different key of each parent)

I have the following JSON
[
{
"name": "alpha"
},
{
"fields": [
{
"name": "beta_sub_1"
},
{
"name": "beta_sub_2"
}
],
"name": "beta"
},
{
"fields": [
{
"fields": [
{
"name": "gamma_sub_sub_1"
}
],
"name": "gamma_sub_1"
}
],
"name": "gamma"
}
]
and I would like to get the paths of "name" needed to get to each "name" values. Considering the above code, I would like the following result:
"alpha"
"beta.beta_sub_1"
"beta.beta_sub_2"
"beta"
"gamma.gamma_sub_1.gamma_sub_sub_1"
"gamma.gamma_sub_1"
"gamma"
I've been searching around but I couldn't get to this result. So far, I have this:
tostream as [$p,$v] | select($p[-1] == "name" and $v != null) | "\([$p[0,1]] | join(".")).\($v)"
but this gives me the path with the key name of the parents (and doesn't keep all the intermediary parents.
"0.name.alpha"
"1.fields.beta_sub_1"
"1.fields.beta_sub_2"
"1.name.beta"
"2.fields.gamma_sub_sub_1"
"2.fields.gamma_sub_1"
"2.name.gamma"
Any ideas?
P.S.: I've been searching for very detailed doc on jq but couldn't find anything good enough. If anyone has any recommendations, I'd appreciate.
The problem description does not seem to match the sample input and output, but the following jq program produces the required output:
def descend:
select( type == "object" and has("name") )
| if has("fields") then ([.name] + (.fields[] | descend)) else empty end,
[.name] ;
.[]
| descend
| join(".")
With your input, and using the -r command-line option, this produces:
alpha
beta.beta_sub_1
beta.beta_sub_2
beta
gamma.gamma_sub_1.gamma_sub_sub_1
gamma.gamma_sub_1
gamma
Resources
Apart from the jq manual, FAQ, and Cookbook, you might find the following helpful:
"jq Language Description"
"A Stream-Oriented Introduction to jq"