Scripting Bridge && filteredArrayUsingPredicate

  • Anybody using Scripting Bridge with filteredArrayUsingPredicate ???

    I've tried Apple's example code -- it's the last code snippet in
    "Scripting Bridge Release Notes for Mac OS X v10.5"    http://developer.apple.com/releasenotes/ScriptingAutomation/RN-ScriptingBri
    dge/index.html


    But it does not work.  Looked around the web and don't see any other
    examples.  Has anyone gotten filteredArray to work?

    Error in statement 3:
        FinderApplication *finder = [SBApplication
    applicationWithBundleIdentifier:@"com.apple.finder"];
        NSPredicate *startsWithM = [NSPredicate
    predicateWithFormat:@"name BEGINSWITH 'M'"];
    >>> SBElementArray *desiredDisks = [[finder disks]
    filteredArrayUsingPredicate:startsWithM];
        NSArray *nameArray = [desiredDisks
    arrayByApplyingSelector:@selector(name)];

    Generates this compile warning:
        warning: initialization from distinct Objective-C type

    And this error when run:
        Apple event returned an error.  Event =
    'core'\'getd'{ '----':'obj '{ 'want':'prop', 'from':'obj
    '{ 'want':'cdis', 'from':'null'(), 'form':'test',
    'seld':'cmpd'{ 'relo':'bgwt', 'obj1':'obj '{ 'want':'prop',
    'from':'exmn'($$), 'form':'prop', 'seld':'pnam' },
    'obj2':'utxt'("M") } }, 'form':'prop', 'seld':'pnam' } }
    Error info = {
        ErrorNumber = -1728;
  • led248 wrote:

    > Anybody using Scripting Bridge with filteredArrayUsingPredicate ???
    >
    > I've tried Apple's example code -- it's the last code snippet in
    > "Scripting Bridge Release Notes for Mac OS X v10.5"    http://developer.apple.com/releasenotes/ScriptingAutomation/RN-ScriptingBri
    dge/index.html

    >
    > But it does not work.
    > [...]
    > NSPredicate *startsWithM = [NSPredicate
    > predicateWithFormat:@"name BEGINSWITH 'M'"];
    >>
    > SBElementArray *desiredDisks = [[finder disks]
    > filteredArrayUsingPredicate:startsWithM];
    > NSArray *nameArray = [desiredDisks
    > arrayByApplyingSelector:@selector(name)];
    > [...]
    > ErrorNumber = -1728;

    Error -1728 = object(s) not found. It's up to individual applications
    to decide how to behave in response to a given command, and for
    whatever reason, the Finder elects to raise an error rather than
    return an empty list if the 'name of (every disk whose name starts
    with "M")' query fails to match anything. By comparison, a similar
    query in TextEdit, e.g. 'name of (every document whose name starts
    with "d")', would return an empty list on no matches. Blame Apple for
    failing to provide scriptable application developers with adequate
    design guidelines, particularly in the pre-SIG days. As a result, it's
    up to users to figure out exactly how individual applications'
    scripting interfaces behave in order to control them effectively.

    In this case, you can either trap the error raised and recover
    accordingly, or use the 'exists' command to check if the query will
    match anything before trying to obtain the actual data. e.g. Using
    objc-appscript:

        // To create a Finder glue:  osaglue FN Finder

        FNApplication *finder;
        FNReference *ref;
        NSArray *diskNames;

        finder = [[FNApplication alloc] initWithBundleID:
    @"com.apple.finder"];

        ref = [[[finder disks] byTest: [[FNIts name] beginsWith: @"M"]]
    name];

        if ([[[ref exists] send] boolValue])
            diskNames = [[ref get] send];
        else
            diskNames = [NSArray array];

        NSLog(@"%@", diskNames);

        [finder release];

    HTH

    has
    --
    http://appscript.sourceforge.net
    http://rb-appscript.rubyforge.org
  • Thank you, HAS!  You are absolutely correct.  Apple's sample code does
    work IF I change the NSPredicate so that it finds at least one match.

    Because the compiler throws a warning on Apple's sample code, I
    assumed that the runtime error was its logical erroneous result, and I
    didn't give much credence to the output.  It never would have crossed
    my mind that zero matches would result in an error!  And the sample
    code will almost certainly error out -- unless you happen to have a
    mounted disk whose name starts with 'M".  You gotta be kidding.

    Now that I know that the code (kinda) works, and I will have to tack
    on error check gobbledygook, I still don't know what that compiler
    warning is about:

      SBElementArray *desiredDisks = [[finder disks]
    filteredArrayUsingPredicate:startsWithM];
      warning: initialization from distinct Objective-C type

    If I initialize desiredDisks as an NSArray (as signatured in the
    header file) the warning goes away.  But then the next line will fail
    because arrayByApplyingSelector: will only work on an SBElementArray,
    not an NSArray:

        NSArray *nameArray = [desiredDisks
    arrayByApplyingSelector:@selector(name)];
        warning: 'NSArray' may not respond to '-arrayByApplyingSelector:'

    After spending a little time with Leopard Scripting Bridge, I've gotta
    say that I'm pretty disappointed.  It's just not ready for prime time
    -- language, tools, docs, even the overall premise (and promise) seems
    pretty flimsy.  I'll have to spend some time with appscript in its
    various flavors, or just continue to make do with, sigh... AppleScript.

    Anyone having a better time with SB?

    On Dec 27, 2007, at 4:16 AM, has wrote:

    > led248 wrote:
    >
    >> Anybody using Scripting Bridge with filteredArrayUsingPredicate ???
    >>
    >> I've tried Apple's example code -- it's the last code snippet in
    >> "Scripting Bridge Release Notes for Mac OS X v10.5"    http://developer.apple.com/releasenotes/ScriptingAutomation/RN-ScriptingBri
    dge/index.html

    >>
    >> But it does not work.
    >> [...]
    >> NSPredicate *startsWithM = [NSPredicate
    >> predicateWithFormat:@"name BEGINSWITH 'M'"];
    >>>
    >> SBElementArray *desiredDisks = [[finder disks]
    >> filteredArrayUsingPredicate:startsWithM];
    >> NSArray *nameArray = [desiredDisks
    >> arrayByApplyingSelector:@selector(name)];
    >> [...]
    >> ErrorNumber = -1728;
    >
    >
    > Error -1728 = object(s) not found. It's up to individual
    > applications to decide how to behave in response to a given command,
    > and for whatever reason, the Finder elects to raise an error rather
    > than return an empty list if the 'name of (every disk whose name
    > starts with "M")' query fails to match anything. By comparison, a
    > similar query in TextEdit, e.g. 'name of (every document whose name
    > starts with "d")', would return an empty list on no matches. Blame
    > Apple for failing to provide scriptable application developers with
    > adequate design guidelines, particularly in the pre-SIG days. As a
    > result, it's up to users to figure out exactly how individual
    > applications' scripting interfaces behave in order to control them
    > effectively.
    >
    > In this case, you can either trap the error raised and recover
    > accordingly, or use the 'exists' command to check if the query will
    > match anything before trying to obtain the actual data. e.g. Using
    > objc-appscript:
    >
    > // To create a Finder glue:  osaglue FN Finder
    >
    > FNApplication *finder;
    > FNReference *ref;
    > NSArray *diskNames;
    >
    > finder = [[FNApplication alloc] initWithBundleID:
    > @"com.apple.finder"];
    >
    > ref = [[[finder disks] byTest: [[FNIts name] beginsWith: @"M"]]
    > name];
    >
    > if ([[[ref exists] send] boolValue])
    > diskNames = [[ref get] send];
    > else
    > diskNames = [NSArray array];
    >
    > NSLog(@"%@", diskNames);
    >
    > [finder release];
    >
    > HTH
    >
    > has
    > --
    > http://appscript.sourceforge.net
    > http://rb-appscript.rubyforge.org
    >
  • led248 wrote:

    > Thank you, HAS!  You are absolutely correct.  Apple's sample code does
    > work IF I change the NSPredicate so that it finds at least one match.
    > [...]
    > It never would have crossed
    > my mind that zero matches would result in an error!

    It's not obvious, and the behaviour you get varies depending on the
    form of query used. e.g.:

    get every disk whose name starts with "M" --> {}
    get name of every application file of desktop --> {}
    get name of (every file whose name starts with "Z") of desktop -->
    error -1728

    Most likely it's a design oversight rather than a deliberate feature.
    Alas, this sort of thing is pretty much par for the course in the
    AppleScript world, and something you just have to deal with if you're
    to get things done.

    > And the sample
    > code will almost certainly error out -- unless you happen to have a
    > mounted disk whose name starts with 'M".  You gotta be kidding.

    Nope, it wasn't a very well thought-out example. (Although it mightn't
    have been quite so bad if SB didn't turn every little application
    error into an OMFG!!!!1!1!! ObjC exception.)

    > Now that I know that the code (kinda) works, and I will have to tack
    > on error check gobbledygook, I still don't know what that compiler
    > warning is about:
    >
    > SBElementArray *desiredDisks = [[finder disks]
    > filteredArrayUsingPredicate:startsWithM];
    > warning: initialization from distinct Objective-C type

    The compiler warning (gotta love that old-timey gcc crypticness) is
    apparently due to the -filteredArrayUsingPredicate: method returning
    an SBElementArray* when its result is declared as NSArray*. Not very
    clever. To eliminate the warning, type the variable as id or cast the
    method's result to the right type (SBElementArray*) before assigning
    it. Or just use objc-appscript (caveat its current alpha status),
    which doesn't tie itself in such knots in the first place.

    HTH

    has
    --
    http://appscript.sourceforge.net
    http://rb-appscript.rubyforge.org
  • On a similar note, I recently stumbled upon what appears to be another
    major flaw in filteredArrayUsingPredicate:. If the predicate is set to
    match an empty string "" (a common enough operation when dealing with
    meta tags, for example in iTunes), filteredArrayUsingPredicate: always
    returns an empty array, regardless if the objects in the unfiltered
    array matches the predicate or not.

    I use array filtering all over the place, so unless I'm overlooking
    something really simple, this means I have to manually check the
    passed in criteria on every single occasion, and deal with empty
    strings manually, building new SBElementArrays from scratch (as you
    cannot remove an object from an SBElementArray, although it is
    declared as a subclass of NSMutableArray). Sigh...

    This leads me to another question: how do I create a new
    SBElementArray? I tried adding SBObjects (iTunesTracks) directly from
    the SBElementArray to a NSMutableArray, but the class of this new
    array is everything but a SBElementArray. I got NSMutableIndexSets,
    SBRelativeHumHumSomething and all sorts of weird things, depending on
    the construction. I also tried initializing new SBObjects with the
    data/properties from the original SBObjects, but that failed miserably
    as well.

    F.

    On Dec 28, 2007 7:35 PM, has <hengist.podd...> wrote:
    > led248 wrote:
    >
    >> Thank you, HAS!  You are absolutely correct.  Apple's sample code does
    >> work IF I change the NSPredicate so that it finds at least one match.
    >> [...]
    >> It never would have crossed
    >> my mind that zero matches would result in an error!
    >
    > It's not obvious, and the behaviour you get varies depending on the
    > form of query used. e.g.:
    >
    > get every disk whose name starts with "M" --> {}
    > get name of every application file of desktop --> {}
    > get name of (every file whose name starts with "Z") of desktop -->
    > error -1728
    >
    > Most likely it's a design oversight rather than a deliberate feature.
    > Alas, this sort of thing is pretty much par for the course in the
    > AppleScript world, and something you just have to deal with if you're
    > to get things done.
    >
    >
    >> And the sample
    >> code will almost certainly error out -- unless you happen to have a
    >> mounted disk whose name starts with 'M".  You gotta be kidding.
    >
    > Nope, it wasn't a very well thought-out example. (Although it mightn't
    > have been quite so bad if SB didn't turn every little application
    > error into an OMFG!!!!1!1!! ObjC exception.)
    >
    >
    >> Now that I know that the code (kinda) works, and I will have to tack
    >> on error check gobbledygook, I still don't know what that compiler
    >> warning is about:
    >>
    >> SBElementArray *desiredDisks = [[finder disks]
    >> filteredArrayUsingPredicate:startsWithM];
    >> warning: initialization from distinct Objective-C type
    >
    > The compiler warning (gotta love that old-timey gcc crypticness) is
    > apparently due to the -filteredArrayUsingPredicate: method returning
    > an SBElementArray* when its result is declared as NSArray*. Not very
    > clever. To eliminate the warning, type the variable as id or cast the
    > method's result to the right type (SBElementArray*) before assigning
    > it. Or just use objc-appscript (caveat its current alpha status),
    > which doesn't tie itself in such knots in the first place.
    >
    >
    > HTH
    >
    > has
    > --
    > http://appscript.sourceforge.net
    > http://rb-appscript.rubyforge.org
    >
  • On 29 Dec 2007, at 16:28, <slasktrattenator...> wrote:

    > On a similar note, I recently stumbled upon what appears to be another
    > major flaw in filteredArrayUsingPredicate:. If the predicate is set to
    > match an empty string "" (a common enough operation when dealing with
    > meta tags, for example in iTunes), filteredArrayUsingPredicate: always
    > returns an empty array, regardless if the objects in the unfiltered
    > array matches the predicate or not.

    Seems to work here. One reason you might not get matches is if you're
    using an empty string where some other value is expected (integer,
    'missing value' constant, etc).

    > (as you
    > cannot remove an object from an SBElementArray, although it is
    > declared as a subclass of NSMutableArray)

    Deleting elements should be done via the application's 'delete'
    command. For whatever reasons, the familiar -[NSMutableArray
    removeObject...] methods aren't mapped to Apple events.

    > This leads me to another question: how do I create a new
    > SBElementArray?

    You don't. They're returned by SB when it needs to represent one-to-
    many relationships.

    The thing to realise about Scripting Bridge is that it bears precious
    little resemblance to the way that Apple event IPC actually works. SB
    goes to considerable lengths to pretend that it's a typical object-
    oriented mechanism a-la COM or DO. But it's not: it's RPC plus simple
    relational queries, and you don't have to scratch too deep before the
    faux-object-oriented facade starts to come apart. Google around if you
    want to read some of my other rants on the subject.

    Anyway, my advice FWIW would be: 1. learn how Apple event IPC really
    works, and 2. use appscript to do it. Yes, there's a bit more of a
    learning curve with this approach, since appscript approaches Apple
    event IPC on its own terms and doesn't try to sweep its complexities
    and warts under the rug and pretend they don't exist. But that's the
    nature of the AppleScript beast, and if you want to work with it
    effectively then it's something you just gotta deal with.

    HTH

    has
    --
    http://appscript.sourceforge.net
    http://rb-appscript.rubyforge.org
  • On Jan 2, 2008 2:40 PM, has <hengist.podd...> wrote:
    > On 29 Dec 2007, at 16:28, <slasktrattenator...> wrote:
    >
    >> On a similar note, I recently stumbled upon what appears to be another
    >> major flaw in filteredArrayUsingPredicate:. If the predicate is set to
    >> match an empty string "" (a common enough operation when dealing with
    >> meta tags, for example in iTunes), filteredArrayUsingPredicate: always
    >> returns an empty array, regardless if the objects in the unfiltered
    >> array matches the predicate or not.
    >
    > Seems to work here. One reason you might not get matches is if you're
    > using an empty string where some other value is expected (integer,
    > 'missing value' constant, etc).

    Really? How did you accomplish that? I'd love to see a working
    example. The snippet below does not return a match no matter how I
    format the predicate. track_array contains an object whose album is a
    verified empty string (""):

    theAlbum = @"";
    predicate = [NSPredicate predicateWithFormat:@"album like[cd] %@", theAlbum];
    track_array = (SBElementArray *)[track_array
    filteredArrayUsingPredicate:predicate];

    > Deleting elements should be done via the application's 'delete'
    > command. For whatever reasons, the familiar -[NSMutableArray
    > removeObject...] methods aren't mapped to Apple events.

    Thanks, that works. Hopefully I won't have to deal with these case
    manually, though, if what you say above is correct.

    > Google around if you
    > want to read some of my other rants on the subject.

    I did, very interesting. Thanks.

    > Anyway, my advice FWIW would be: 1. learn how Apple event IPC really
    > works, and 2. use appscript to do it.

    Cool. I hadn't heard about appscript before. I'll play around with it
    later and see how it compares.

    > Yes, there's a bit more of a
    > learning curve with this approach, since appscript approaches Apple
    > event IPC on its own terms and doesn't try to sweep its complexities
    > and warts under the rug and pretend they don't exist. But that's the
    > nature of the AppleScript beast, and if you want to work with it
    > effectively then it's something you just gotta deal with.
    >
    >
    > HTH
    >
    > has
    > --
    > http://appscript.sourceforge.net
    > http://rb-appscript.rubyforge.org
    >
    >
  • On 2 Jan 2008, at 16:58, <slasktrattenator...> wrote:

    >>> On a similar note, I recently stumbled upon what appears to be
    >>> another
    >>> major flaw in filteredArrayUsingPredicate:. If the predicate is
    >>> set to
    >>> match an empty string "" (a common enough operation when dealing
    >>> with
    >>> meta tags, for example in iTunes), filteredArrayUsingPredicate:
    >>> always
    >>> returns an empty array, regardless if the objects in the unfiltered
    >>> array matches the predicate or not.
    >>
    >> Seems to work here. One reason you might not get matches is if you're
    >> using an empty string where some other value is expected (integer,
    >> 'missing value' constant, etc).
    >
    > Really? How did you accomplish that? I'd love to see a working
    > example.

    The following works here, picking up all tracks that lack an album name:

    #####################

    #!/usr/bin/ruby

    require 'osx/cocoa'
    include OSX
    OSX.require_framework 'ScriptingBridge'

    iTunes =
    SBApplication.applicationWithBundleIdentifier("com.apple.itunes")

    the_album = ""

    track_array =
    iTunes.sources.objectAtIndex(0).playlists.objectAtIndex(0).tracks

    predicate = NSPredicate.predicateWithFormat("album like[cd] %@",
    the_album)

    track_array = track_array.filteredArrayUsingPredicate(predicate)

    puts track_array.arrayByApplyingSelector(:name)

    #####################

    (
        "Track 01",
        "Track 01",
        "Track 02",
        "Track 02",
        "Track 03",
        "Track 03",
        "Track 04",
        "Track 04",
        "Track 05",
        "Track 05",
        ...
    )

    #####################

    If in doubt, check against AppleScript to see if the problem is with
    the bridge or with the target application, e.g.:

    tell app "iTunes" to name of (every track whose album is "") of
    playlist 1 of source 1

    I'll also add a caveat that I don't yet know much about how SB applies
    predicates - I think it maps at least some tests to Apple event
    equivalents, but none of this stuff is publicly documented so it's
    hard to know what's going on behind the scenes.

    >> Anyway, my advice FWIW would be: 1. learn how Apple event IPC really
    >> works, and 2. use appscript to do it.
    >
    > Cool. I hadn't heard about appscript before. I'll play around with it
    > later and see how it compares.

    As I've said elsewhere, objc-appscript is still officially alphaware
    so the usual caveats apply. There's still a few implementation details
    to take care of; however, the basic architecture is already quite
    solid since it's based on the proven Python appscript design, and the
    high-level API is settling down now so there shouldn't be much more
    disturbance from your POV.

    For example:

    // To create iTunes glue: osaglue  -o ITGlue  -p IT  iTunes

    #import <Foundation/Foundation.h>
    #import "ITGlue/ITGlue.h"

    int main (int argc, const char * argv[]) {
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

    ITApplication *itunes;
    ITReference *ref;
    NSError *err;
    NSString *albumName;
    NSArray *trackNames;

    albumName = @"";

    itunes = [[ITApplication alloc] initWithBundleID: @"com.apple.itunes"];

    ref = [[[[[itunes playlists] at: 1] tracks] byTest: [[ITIts album]
    equals: albumName]] name];

    trackNames = [[ref get] sendWithError: &err];

    if (!trackNames)
      NSLog(@"Error: %@", err);
    else
      NSLog(@"Result: %@", trackNames);

    [itunes release];
    [pool drain];
    return 0;
    }

    HTH

    has
    --
    http://appscript.sourceforge.net
    http://rb-appscript.rubyforge.org
  • So it's a Cocoa thing then?? Jesus...

    theArtist = @"Beatles";
    theAlbum = @"";

    track_array = (SBElementArray *)[libraryPlaylist searchFor:theArtist
    only:'kSrR']; //artists

    // Filter by artist, we get a track in the array
    predicate = [NSPredicate predicateWithFormat:@"artist like[cd] %@", theArtist];
    track_array = (SBElementArray *)[track_array
    filteredArrayUsingPredicate:predicate];

    nameArray = [track_array arrayByApplyingSelector:@selector(name)];
    NSLog(@"%@", nameArray); // => ("I Feel Fine")

    // Filter again by album, no go...
    predicate = [NSPredicate predicateWithFormat:@"album like[cd] %@", theAlbum];
    track_array = (SBElementArray *)[track_array
    filteredArrayUsingPredicate:predicate];

    nameArray = [track_array arrayByApplyingSelector:@selector(name)];
    NSLog(@"%@", nameArray); // =>  () Nothing here!!

    On Jan 2, 2008 8:34 PM, has <hengist.podd...> wrote:
    > On 2 Jan 2008, at 16:58, <slasktrattenator...> wrote:
    >
    >>>> On a similar note, I recently stumbled upon what appears to be
    >>>> another
    >>>> major flaw in filteredArrayUsingPredicate:. If the predicate is
    >>>> set to
    >>>> match an empty string "" (a common enough operation when dealing
    >>>> with
    >>>> meta tags, for example in iTunes), filteredArrayUsingPredicate:
    >>>> always
    >>>> returns an empty array, regardless if the objects in the unfiltered
    >>>> array matches the predicate or not.
    >>>
    >>> Seems to work here. One reason you might not get matches is if you're
    >>> using an empty string where some other value is expected (integer,
    >>> 'missing value' constant, etc).
    >>
    >> Really? How did you accomplish that? I'd love to see a working
    >> example.
    >
    > The following works here, picking up all tracks that lack an album name:
    >
    > #####################
    >
    > #!/usr/bin/ruby
    >
    > require 'osx/cocoa'
    > include OSX
    > OSX.require_framework 'ScriptingBridge'
    >
    > iTunes =
    > SBApplication.applicationWithBundleIdentifier("com.apple.itunes")
    >
    > the_album = ""
    >
    > track_array =
    > iTunes.sources.objectAtIndex(0).playlists.objectAtIndex(0).tracks
    >
    > predicate = NSPredicate.predicateWithFormat("album like[cd] %@",
    > the_album)
    >
    > track_array = track_array.filteredArrayUsingPredicate(predicate)
    >
    > puts track_array.arrayByApplyingSelector(:name)
    >
    > #####################
    >
    > (
    > "Track 01",
    > "Track 01",
    > "Track 02",
    > "Track 02",
    > "Track 03",
    > "Track 03",
    > "Track 04",
    > "Track 04",
    > "Track 05",
    > "Track 05",
    > ...
    > )
    >
    > #####################
    >
    >
    > If in doubt, check against AppleScript to see if the problem is with
    > the bridge or with the target application, e.g.:
    >
    > tell app "iTunes" to name of (every track whose album is "") of
    > playlist 1 of source 1
    >
    >
    > I'll also add a caveat that I don't yet know much about how SB applies
    > predicates - I think it maps at least some tests to Apple event
    > equivalents, but none of this stuff is publicly documented so it's
    > hard to know what's going on behind the scenes.
    >
    >
    >>> Anyway, my advice FWIW would be: 1. learn how Apple event IPC really
    >>> works, and 2. use appscript to do it.
    >>
    >> Cool. I hadn't heard about appscript before. I'll play around with it
    >> later and see how it compares.
    >
    >
    > As I've said elsewhere, objc-appscript is still officially alphaware
    > so the usual caveats apply. There's still a few implementation details
    > to take care of; however, the basic architecture is already quite
    > solid since it's based on the proven Python appscript design, and the
    > high-level API is settling down now so there shouldn't be much more
    > disturbance from your POV.
    >
    > For example:
    >
    > // To create iTunes glue: osaglue  -o ITGlue  -p IT  iTunes
    >
    > #import <Foundation/Foundation.h>
    > #import "ITGlue/ITGlue.h"
    >
    > int main (int argc, const char * argv[]) {
    > NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
    >
    > ITApplication *itunes;
    > ITReference *ref;
    > NSError *err;
    > NSString *albumName;
    > NSArray *trackNames;
    >
    > albumName = @"";
    >
    > itunes = [[ITApplication alloc] initWithBundleID: @"com.apple.itunes"];
    >
    > ref = [[[[[itunes playlists] at: 1] tracks] byTest: [[ITIts album]
    > equals: albumName]] name];
    >
    > trackNames = [[ref get] sendWithError: &err];
    >
    > if (!trackNames)
    > NSLog(@"Error: %@", err);
    > else
    > NSLog(@"Result: %@", trackNames);
    >
    > [itunes release];
    > [pool drain];
    > return 0;
    >
    > }
    >
    >
    > HTH
    >
    > has
    > --
    > http://appscript.sourceforge.net
    > http://rb-appscript.rubyforge.org
    >
    >
  • On 2 Jan 2008, at 22:31, <slasktrattenator...> wrote:

    > So it's a Cocoa thing then?? Jesus...

    Nope, your code below does something different to mine. (I just used
    Ruby as it's a bit quicker to work in.)

    > theArtist = @"Beatles";
    > theAlbum = @"";
    >
    > track_array = (SBElementArray *)[libraryPlaylist searchFor:theArtist
    > only:'kSrR']; //artists
    >
    > // Filter by artist, we get a track in the array
    > predicate = [NSPredicate predicateWithFormat:@"artist like[cd] %@",
    > theArtist];
    > track_array = (SBElementArray *)[track_array
    > filteredArrayUsingPredicate:predicate];
    >
    > nameArray = [track_array arrayByApplyingSelector:@selector(name)];
    > NSLog(@"%@", nameArray); // => ("I Feel Fine")
    >
    > // Filter again by album, no go...
    > predicate = [NSPredicate predicateWithFormat:@"album like[cd] %@",
    > theAlbum];
    > track_array = (SBElementArray *)[track_array
    > filteredArrayUsingPredicate:predicate];
    >
    > nameArray = [track_array arrayByApplyingSelector:@selector(name)];
    > NSLog(@"%@", nameArray); // =>  () Nothing here!!

    You're applying the second filter to the SBElementArray object
    returned by the first filter, which in turn is operating on the
    SBElementArray returned by the -searchFor: command. That sort of thing
    might be perfectly logical and work just fine in the Cocoa world - but
    remember what I said about Scripting Bridge just being a thin faux-OO
    facade over the real Apple event IPC mechanism. You shouldn't assume
    that just because it's dressed up to look like familiar Cocoa APIs it
    will actually behave like them.

    To be honest, I couldn't tell you exactly what the above code is
    actually doing, short of turning on AEDebug and deducing SB's actions
    based on the events it's sending. This sort of intentional obfuscation
    drove me batty in AppleScript; I can't see it being any more popular
    amongst Cocoa users.

    ...

    Anyway, if you want to apply two conditional tests to a multi-item
    reference, they should be combined into a single logical AND test
    first, for example [1]:

    artistName = @"Ella Fitzgerald";
    albumName = @"";

    itunes = [[ITApplication alloc] initWithBundleID: @"com.apple.itunes"];

    test = [
      [[ITIts artist] equals: artistName]
      AND:
      [[ITIts album] equals: albumName]
      ];

    ref = [[[[[itunes playlists] at: 1] tracks] byTest: test] name];

    trackNames = [[ref get] send];

    HTH

    has

    [1] Note: requires revision 418 or later due to a bug I just
    discovered in the -AND: method. Caveat alphaware, as I may have
    mentioned already. :p
    --
    http://appscript.sourceforge.net
    http://rb-appscript.rubyforge.org
  • Thanks for taking the time, has. Sounds like my best option is to
    check for empty strings, iterate over the search result if necessary
    and manually delete non-matching objects from the SBElementArray.
    Constantly sucking in each and every track from iTunes is a speed
    penalty I just cannot accept.

    On Jan 3, 2008 2:17 AM, has <hengist.podd...> wrote:
    >
    > On 2 Jan 2008, at 22:31, <slasktrattenator...> wrote:
    >
    >> So it's a Cocoa thing then?? Jesus...
    >
    > Nope, your code below does something different to mine. (I just used
    > Ruby as it's a bit quicker to work in.)
    >
    >> theArtist = @"Beatles";
    >> theAlbum = @"";
    >>
    >> track_array = (SBElementArray *)[libraryPlaylist searchFor:theArtist
    >> only:'kSrR']; //artists
    >>
    >> // Filter by artist, we get a track in the array
    >> predicate = [NSPredicate predicateWithFormat:@"artist like[cd] %@",
    >> theArtist];
    >> track_array = (SBElementArray *)[track_array
    >> filteredArrayUsingPredicate:predicate];
    >>
    >> nameArray = [track_array arrayByApplyingSelector:@selector(name)];
    >> NSLog(@"%@", nameArray); // => ("I Feel Fine")
    >>
    >> // Filter again by album, no go...
    >> predicate = [NSPredicate predicateWithFormat:@"album like[cd] %@",
    >> theAlbum];
    >> track_array = (SBElementArray *)[track_array
    >> filteredArrayUsingPredicate:predicate];
    >>
    >> nameArray = [track_array arrayByApplyingSelector:@selector(name)];
    >> NSLog(@"%@", nameArray); // =>  () Nothing here!!
    >
    >
    > You're applying the second filter to the SBElementArray object
    > returned by the first filter, which in turn is operating on the
    > SBElementArray returned by the -searchFor: command. That sort of thing
    > might be perfectly logical and work just fine in the Cocoa world - but
    > remember what I said about Scripting Bridge just being a thin faux-OO
    > facade over the real Apple event IPC mechanism. You shouldn't assume
    > that just because it's dressed up to look like familiar Cocoa APIs it
    > will actually behave like them.
    >
    > To be honest, I couldn't tell you exactly what the above code is
    > actually doing, short of turning on AEDebug and deducing SB's actions
    > based on the events it's sending. This sort of intentional obfuscation
    > drove me batty in AppleScript; I can't see it being any more popular
    > amongst Cocoa users.
    >
    > ...
    >
    > Anyway, if you want to apply two conditional tests to a multi-item
    > reference, they should be combined into a single logical AND test
    > first, for example [1]:
    >
    >
    > artistName = @"Ella Fitzgerald";
    > albumName = @"";
    >
    > itunes = [[ITApplication alloc] initWithBundleID: @"com.apple.itunes"];
    >
    > test = [
    > [[ITIts artist] equals: artistName]
    > AND:
    > [[ITIts album] equals: albumName]
    > ];
    >
    > ref = [[[[[itunes playlists] at: 1] tracks] byTest: test] name];
    >
    > trackNames = [[ref get] send];
    >
    >
    > HTH
    >
    > has
    >
    > [1] Note: requires revision 418 or later due to a bug I just
    > discovered in the -AND: method. Caveat alphaware, as I may have
    > mentioned already. :p
    > --
    >
    > http://appscript.sourceforge.net
    > http://rb-appscript.rubyforge.org
    >
    >
  • On 3 Jan 2008, at 02:14, <slasktrattenator...> wrote:

    > Thanks for taking the time, has. Sounds like my best option is to
    > check for empty strings, iterate over the search result if necessary
    > and manually delete non-matching objects from the SBElementArray.

    IMO, your best option would be to use appscript. Appscript objects
    look and behave like appscript objects, Cocoa objects look and behave
    like Cocoa objects, and neither goes around pretending to be something
    it's not, so you can actually see what's going on when you use it. But
    that's your choice, of course.

    If you do use SB, bear in mind that calling 'delete' on an SBObject
    will delete the corresponding object in iTunes, which I suspect isn't
    what you're actually meaning to do.

    For a non-trivial task such as this, since you're still in the process
    of figuring out SB I would suggest you write your iTunes-related stuff
    in AppleScript first and test and debug that till you're happy it
    works as intended. You can then port it over to SB, checking the SB
    version to make sure it behaves the same as the original AppleScript
    version. For information on AEDebug, which is handy for observing the
    Apple events being sent between applications, see:

    http://developer.apple.com/technotes/tn2004/tn2124.html#SECAE

    If you need advice on how to perform specific operations on iTunes,
    ask here or on AppleScript-users describing in general terms the task
    you want to perform. The AS-users folks will be able to provide
    AppleScript-based answers which you can translate as necessary, and
    I'm happy to provide AppleScript/appscript-based answers (within the
    limits of my iTunes knowledge) although I've little patience for
    Scripting Bridge-specific issues past the point I start scratching my
    own head at it.

    HTH

    has
    --
    http://appscript.sourceforge.net
    http://rb-appscript.rubyforge.org
previous month december 2007 next month
MTWTFSS
          1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
31            
Go to today