]>
Commit | Line | Data |
---|---|---|
1 | package Zeal::Docset; | |
2 | ||
3 | use 5.014000; | |
4 | use strict; | |
5 | use warnings; | |
6 | ||
7 | our $VERSION = '0.000_001'; | |
8 | ||
9 | use parent qw/Class::Accessor::Fast/; | |
10 | __PACKAGE__->mk_ro_accessors(qw/path plist dbh name id family/); | |
11 | ||
12 | use Carp qw/carp/; | |
13 | use Cwd qw/realpath/; | |
14 | use File::Spec::Functions qw/catfile catdir rel2abs/; | |
15 | use HTTP::Tiny; | |
16 | ||
17 | use DBI; | |
18 | use File::Slurp qw/read_file/; | |
19 | use Mac::PropertyList::SAX qw/parse_plist_file/; | |
20 | ||
21 | use Zeal::Document; | |
22 | ||
23 | sub new { | |
24 | my ($class, $path) = @_; | |
25 | $path = realpath $path; | |
26 | my $plpath = catfile $path, 'Contents', 'Info.plist'; | |
27 | my $dbpath = catfile $path, 'Contents', 'Resources', 'docSet.dsidx'; | |
28 | my $plist = parse_plist_file($plpath)->as_perl; | |
29 | carp 'This is not a Dash docset' unless $plist->{isDashDocset}; | |
30 | ||
31 | bless { | |
32 | path => $path, | |
33 | plist => $plist, | |
34 | dbh => DBI->connect("dbi:SQLite:dbname=$dbpath", '', ''), | |
35 | name => $plist->{CFBundleName}, | |
36 | id => $plist->{CFBundleIdentifier}, | |
37 | family => $plist->{DocSetPlatformFamily}, | |
38 | }, $class | |
39 | } | |
40 | ||
41 | sub _blessdocs { | |
42 | my ($self, $docsref) = @_; | |
43 | map { Zeal::Document->new(+{%$_, docset => $self}) } @$docsref; | |
44 | } | |
45 | ||
46 | sub fetch { | |
47 | my ($self, $path) = @_; | |
48 | return HTTP::Tiny->new->get($path)->{content} if $path =~ /^http:/s; | |
49 | my $docroot = catdir $self->path, 'Contents', 'Resources', 'Documents'; | |
50 | $path = rel2abs $path, $docroot; | |
51 | scalar read_file $path | |
52 | } | |
53 | ||
54 | sub query { | |
55 | my ($self, $cond) = @_; | |
56 | my $query = 'SELECT * FROM searchIndex WHERE name LIKE ?'; | |
57 | my $res = $self->dbh->selectall_arrayref($query, {Slice => {}}, $cond); | |
58 | my @results = $self->_blessdocs($res); | |
59 | wantarray ? @results : $results[0] | |
60 | } | |
61 | ||
62 | sub get { | |
63 | my ($self, $cond) = @_; | |
64 | $self->query($cond)->fetch | |
65 | } | |
66 | ||
67 | sub list { | |
68 | my ($self) = @_; | |
69 | my $query = 'SELECT * FROM searchIndex'; | |
70 | my $res = $self->dbh->selectall_arrayref($query, {Slice => {}}); | |
71 | $self->_blessdocs($res) | |
72 | } | |
73 | ||
74 | 1; | |
75 | __END__ | |
76 | ||
77 | =encoding utf-8 | |
78 | ||
79 | =head1 NAME | |
80 | ||
81 | Zeal::Docset - Class representing a Dash/Zeal docset | |
82 | ||
83 | =head1 SYNOPSIS | |
84 | ||
85 | use Zeal::Docset; | |
86 | my $ds = Zeal::Docset->new('/home/mgv/docsets/Perl.docset'); | |
87 | say $ds->$path; # /home/mgv/docsets/Perl.docset | |
88 | say $ds->name; # Perl | |
89 | say $ds->id; # perl | |
90 | say $ds->family; # perl | |
91 | ||
92 | # In SQL LIKE, % is .* and _ is . | |
93 | my @matches = $ds->query('perlopen%'); # finds perlopenbsd and perlopentut | |
94 | my $doc = $ds->query('perlsec'); # A Zeal::Document object for perlsec | |
95 | my $html = $ds->get('perls_c'); # HTML documentation of perlsec | |
96 | my @docs = $ds->list; # all documents | |
97 | ||
98 | =head1 DESCRIPTION | |
99 | ||
100 | Dash is an offline API documentation browser. Zeal::Docset is a class | |
101 | representing a Dash/Zeal docset. | |
102 | ||
103 | Available methods: | |
104 | ||
105 | =over | |
106 | ||
107 | =item Zeal::Docset->B<new>(I<$path>) | |
108 | ||
109 | Create a Zeal::Docset object from a given docset. I<$path> should be | |
110 | the path to a F<something.docset> directory. | |
111 | ||
112 | =item $ds->B<path> | |
113 | ||
114 | The path to the docset folder. | |
115 | ||
116 | =item $ds->B<plist> | |
117 | ||
118 | A hashref with the contents of Info.plist. | |
119 | ||
120 | =item $ds->B<dbh> | |
121 | ||
122 | A DBI database handle to the docSet.dsidx index. | |
123 | ||
124 | =item $ds->B<name> | |
125 | ||
126 | The name of this docset. Equivalent to | |
127 | C<< $ds->plist->{CFBundleName} >> | |
128 | ||
129 | =item $ds->B<id> | |
130 | ||
131 | The identifier of this docset. Equivalent to | |
132 | C<< $ds->plist->{CFBundleIdentifier} >> | |
133 | ||
134 | =item $ds->B<family> | |
135 | ||
136 | The family this docset belongs to. Dash uses this as the keyword for | |
137 | restricting searches to a particular family of docsets. Equivalent to | |
138 | C<< $ds->plist->{DocSetPlatformFamily} >> | |
139 | ||
140 | =item $ds->B<fetch>(I<$path>) | |
141 | ||
142 | Internal method for fetching the HTML content of a document. I<$path> | |
143 | is either the path to the document relative to C<< $ds->B<path> >> or | |
144 | a HTTP URL. | |
145 | ||
146 | =item $ds->B<query>(I<$cond>) | |
147 | ||
148 | In list context, return all documents (L<Zeal::Document> instances) | |
149 | matching I<$cond>. In scalar context, return one such document. | |
150 | I<$cond> is a SQL LIKE condition. | |
151 | ||
152 | =item $ds->B<get>(I<$cond>) | |
153 | ||
154 | The HTML content of one document that matches I<$cond>. | |
155 | I<$cond> is a SQL LIKE condition. | |
156 | ||
157 | This method is shorthand for C<< $ds->query(I<$cond>)->fetch >>. | |
158 | ||
159 | =item $ds->B<list> | |
160 | ||
161 | The list of all documents (L<Zeal::Document> instances) in this | |
162 | docset. | |
163 | ||
164 | =back | |
165 | ||
166 | =head1 SEE ALSO | |
167 | ||
168 | L<Zeal>, L<http://kapeli.com/dash>, L<http://zealdocs.org> | |
169 | ||
170 | =head1 AUTHOR | |
171 | ||
172 | Marius Gavrilescu, E<lt>marius@ieval.roE<gt> | |
173 | ||
174 | =head1 COPYRIGHT AND LICENSE | |
175 | ||
176 | Copyright (C) 2014 by Marius Gavrilescu | |
177 | ||
178 | This library is free software; you can redistribute it and/or modify | |
179 | it under the same terms as Perl itself, either Perl version 5.20.1 or, | |
180 | at your option, any later version of Perl 5 you may have available. | |
181 | ||
182 | ||
183 | =cut |