File Coverage

blib/lib/File/Spotlight.pm
Criterion Covered Total %
statement 10 12 83.3
branch n/a
condition n/a
subroutine 4 4 100.0
pod n/a
total 14 16 87.5


line stmt bran cond sub pod time code
1             package File::Spotlight;
2              
3 2     2   8150 use strict;
  2         6  
  2         85  
4 2     2   55 use 5.008_001;
  2         10  
  2         99  
5             our $VERSION = '0.05';
6              
7 2     2   19 use Carp;
  2         4  
  2         164  
8 2     2   949 use Mac::Spotlight::MDQuery ':constants';
  0            
  0            
9             use Mac::Spotlight::MDItem ':constants';
10             use Scalar::Util qw(blessed);
11              
12             sub new {
13             my $class = shift;
14             my($file) = @_;
15              
16             my $self = bless { path => $file }, $class;
17             $self->init() if $file;
18              
19             return $self;
20             }
21              
22             sub path {
23             my $self = shift;
24             if (@_) {
25             $self->{path} = shift;
26             $self->init;
27             }
28             $self->{path};
29             }
30              
31             sub init {
32             my $self = shift;
33              
34             my $plist = $self->parse_plist($self->path)
35             or croak "Can't open savedSearch file " . $self->path;
36              
37             my $query = $plist->{RawQuery};
38             $query = _get_value($query) if blessed $query;
39             my @search_paths = @{ $plist->{SearchCriteria}{FXScopeArrayOfPaths} || [] };
40              
41             $self->{query} = $query;
42             $self->{search_paths} = \@search_paths;
43             }
44              
45             sub list {
46             my $self = shift;
47              
48             if (@_) {
49             # backward compatiblity
50             $self = (ref $self)->new(@_);
51             }
52              
53             my @files;
54             for my $path (@{$self->{search_paths}}) {
55             $path = _get_value($path) if blessed $path;
56             push @files, $self->_run_mdfind($path, $self->{query});
57             }
58              
59             return @files;
60             }
61              
62             sub parse_plist {
63             my($self, $file) = @_;
64              
65             if (eval { require Mac::Tie::PList }) {
66             return Mac::Tie::PList->new_from_file($file);
67             } else {
68             require Mac::PropertyList;
69             Mac::PropertyList::parse_plist_file($file);
70             }
71             }
72              
73             sub _run_mdfind {
74             my($self, $path, $query) = @_;
75              
76             my $mq = Mac::Spotlight::MDQuery->new($query);
77             $mq->setScope( $self->_scope($path) );
78             $mq->execute;
79             $mq->stop;
80              
81             my @files;
82             for my $result ($mq->getResults) {
83             push @files, $result->get(kMDItemPath);
84             }
85              
86             return @files;
87             }
88              
89             # string => constant
90             my %scope = (
91             kMDQueryScopeHome => kMDQueryScopeHome,
92             kMDQueryScopeComputer => kMDQueryScopeComputer,
93             kMDQueryScopeNetwork => kMDQueryScopeNetwork,
94             );
95              
96             sub _scope {
97             my($self, $str) = @_;
98             $scope{$str};
99             }
100              
101             my %decode = (amp => '&', quot => '"', lt => '<', gt => '>');
102              
103             sub _get_value {
104             my $string = shift;
105              
106             # Mac::PropertyList doesn't decode XML escapes
107             $string = $string->value;
108             $string =~ s/&(amp|quot|lt|gt);/$decode{$1}/eg;
109              
110             return $string;
111             }
112              
113              
114             1;
115             __END__