File Coverage

blib/lib/Text/Mining/Corpus.pm
Criterion Covered Total %
statement 3 3 100.0
branch n/a
condition n/a
subroutine 1 1 100.0
pod n/a
total 4 4 100.0


line stmt bran cond sub pod time code
1             package Text::Mining::Corpus;
2 2     2   24396 use base qw(Text::Mining::Corpus::Base);
  2         4  
  2         1780  
3             use Class::Std;
4             use Class::Std::Utils;
5             use Text::Mining::Corpus::Document;
6              
7             use warnings;
8             use strict;
9             use Carp;
10              
11             use version; our $VERSION = qv('0.0.8');
12              
13             {
14             my %id_of : ATTR( );
15             my %name_of : ATTR( );
16             my %desc_of : ATTR( );
17             my %path_of : ATTR( );
18              
19             sub BUILD {
20             my ($self, $ident, $arg_ref) = @_;
21            
22             if (defined $arg_ref->{corpus_id}) { $self->_get_corpus($arg_ref); }
23             elsif (defined $arg_ref->{corpus_name}) {
24             # Check if already exists
25             my $corpus_id = $self->get_corpus_id_from_name($arg_ref);
26             if ( $corpus_id ) {
27             $arg_ref->{corpus_id} = $corpus_id;
28             $self->_get_corpus($arg_ref);
29             } else {
30             # Insert new corpus
31             $self->insert( $arg_ref );
32             }
33             }
34              
35             return;
36             }
37              
38             #sub submit_document { my ( $self, $arg_ref ) = @_; $arg_ref->{corpus_id} = $id_of{ident $self}; return Text::Librarian::SubmitDocument->new( $arg_ref ); }
39             #sub submit_document { my ( $self, $arg_ref ) = @_; $arg_ref->{corpus_id} = $id_of{ident $self}; return Text::Mining::Corpus::Document->new( $arg_ref ); }
40             #sub delete_submitted_document { my ( $self, $arg_ref ) = @_; return Text::Librarian::SubmitDocument->delete( $arg_ref ); }
41             sub delete_submitted_document { my ( $self, $arg_ref ) = @_; return Text::Mining::Corpus::Document->delete( $arg_ref ); }
42              
43             sub get_id { my ($self) = @_; return $id_of{ident $self}; }
44             sub get_corpus_id { my ($self) = @_; return $id_of{ident $self}; }
45             sub get_name { my ($self) = @_; return $name_of{ident $self}; }
46             sub get_path { my ($self) = @_; return $path_of{ident $self}; }
47             sub get_desc { my ($self) = @_; return $desc_of{ident $self}; }
48             sub get_data_dir { my ($self) = @_; return $self->_get_data_dir( $id_of{ident $self} ); }
49              
50             sub set_name { my ($self, $value) = @_; $name_of{ident $self} = $value; return $self; }
51             sub set_desc { my ($self, $value) = @_; $desc_of{ident $self} = $value; return $self; }
52             sub set_path { my ($self, $value) = @_; $path_of{ident $self} = $value; return $self; }
53              
54             sub submit_document {
55             my ( $self, $arg_ref ) = @_;
56             $arg_ref->{corpus_id} = $self->get_corpus_id();
57             return Text::Mining::Corpus::Document->new( $arg_ref );
58             }
59              
60             sub _get_corpus {
61             my ($self, $arg_ref) = @_;
62             my $ident = ident $self;
63              
64             my $sql = "select corpus_id, corpus_name, corpus_desc, corpus_path ";
65             $sql .= "from corpuses ";
66             $sql .= "where corpus_id = '$arg_ref->{corpus_id}'";
67              
68             ($id_of{$ident},
69             $name_of{$ident},
70             $desc_of{$ident},
71             $path_of{$ident}) = $self->library()->sqlexec( $sql, '@' );
72             }
73              
74             sub update {
75             my ( $self, $arg_ref ) = @_;
76             my $ident = ident $self;
77             my @updates = ();
78              
79             if ( defined $arg_ref->{corpus_name} ) { $self->set_name( $arg_ref->{corpus_name} ); push @updates, "corpus_name = '" . $self->_html_to_sql( $arg_ref->{corpus_name} ) . "'"; }
80             if ( defined $arg_ref->{corpus_desc} ) { $self->set_desc( $arg_ref->{corpus_desc} ); push @updates, "corpus_desc = '" . $self->_html_to_sql( $arg_ref->{corpus_desc} ) . "'"; }
81             if ( defined $arg_ref->{corpus_path} ) { $self->set_path( $arg_ref->{corpus_path} ); push @updates, "corpus_path = '" . $self->_html_to_sql( $arg_ref->{corpus_path} ) . "'"; }
82              
83             my $sql = "update corpuses set " . join( ', ', @updates ) . " where corpus_id = '$id_of{$ident}'";
84             $self->library()->sqlexec( $sql );
85             }
86              
87             sub insert {
88             my ($self, $arg_ref) = @_;
89             my $ident = ident $self;
90              
91             # Save the values
92             $name_of{$ident} = $arg_ref->{corpus_name};
93             $desc_of{$ident} = $arg_ref->{corpus_desc} ? $arg_ref->{corpus_desc} : $arg_ref->{corpus_name};
94              
95             # Insert base values
96             foreach ('corpus_name', 'corpus_desc') { $arg_ref->{$_} = $self->_html_to_sql( $arg_ref->{$_} || '' ); }
97             my $sql = "insert into corpuses (corpus_name, corpus_desc) ";
98             $sql .= "values ( '$arg_ref->{corpus_name}', '$arg_ref->{corpus_desc}') ";
99             $self->library()->sqlexec( $sql );
100              
101             # Get the new corpus_id
102             $sql = "select LAST_INSERT_ID()";
103             ( $id_of{$ident} ) = $self->library()->sqlexec( $sql, '@' );
104              
105             # Update the path
106             $path_of{$ident} = $arg_ref->{corpus_path} ? $arg_ref->{corpus_path} : $self->_default_corpus_path();
107             $sql = "update corpuses set corpus_path = '" . $path_of{$ident} . "' ";
108             $sql .= "where corpus_id = '" . $id_of{$ident} . "'";
109             $self->library()->sqlexec( $sql );
110              
111             # Make sure the path exists
112             $self->check_path();
113             }
114              
115             sub delete {
116             my ( $self, $arg_ref ) = @_;
117             my $id = defined($arg_ref->{corpus_id}) ? $arg_ref->{corpus_id} : $id_of{ident $self};
118             $self->library()->sqlexec( "delete from corpuses where corpus_id = '$id'" );
119             $self->library()->sqlexec( "delete from submitted_documents where corpus_id = '$id'" );
120             }
121              
122             sub clean {
123             my ( $self ) = @_;
124             my @dirs = $self->_get_dirs( $self->get_data_dir() );
125             foreach my $dir ( @dirs ) { $self->clean_directory( $dir ); }
126             }
127              
128             sub clean_directory {
129             my ( $self, $dir ) = @_;
130             my @files = $self->_get_files( $dir );
131             my @sub_dirs = $self->_get_dirs( $dir, 0 );
132             my $file_count = scalar(@files);
133             my $dir_count = scalar(@sub_dirs);
134              
135             if ($file_count + $dir_count == 0) { rmdir($dir); }
136              
137             foreach my $file ( @files ) { if (! ($file =~ m/\.zip$/i) ) { $self->clean_document( $dir . '/' . $file ); } }
138             foreach my $sub_dir ( @sub_dirs ) { $self->clean_directory( $sub_dir ); }
139             }
140              
141             sub clean_document {
142             my ( $self, $file ) = @_;
143             my @parts = split(/\//, $file);
144             my $root_dir = $self->_get_root_dir();
145             my $file_name = pop( @parts );
146             $file_name =~ m/^([\w\.%-]*)\.([\w%-]*)$/;
147             my $path = join( '/', @parts );
148             $path =~ s/$root_dir\/documents\/corpus_\d+//;
149             foreach ($path, $file_name) { $_ = $self->_html_to_sql($_); }
150             my $sql = "select submitted_document_id, corpus_id from submitted_documents ";
151             $sql .= "where document_path = '$path' ";
152             $sql .= " and document_file_name = '$file_name' ";
153             my ( $id, $corpus_id ) = $self->library()->sqlexec( $sql, '@' );
154              
155             if (! $id ) { print STDERR " Unlinking $file \n"; unlink( $file ); }
156             }
157              
158             sub compress {
159             my ( $self, $arg_ref ) = @_;
160             my $data_dir = $self->get_data_dir();
161             my @dirs = $self->_get_dirs( $data_dir, 0 );
162             foreach my $dir ( @dirs ) { $self->compress_directory( $dir ); }
163             }
164              
165             sub compress_directory {
166             my ( $self, $dir ) = @_;
167             my @files = $self->_get_files( $dir );
168             my @sub_dirs = $self->_get_dirs( $dir, 0 );
169             my $file_count = scalar(@files);
170             my $dir_count = scalar(@sub_dirs);
171              
172             if ($file_count + $dir_count == 0) { rmdir($dir); }
173              
174             foreach my $file ( @files ) { if (! ($file =~ m/\.zip$/i) ) { $self->compress_document( $dir . '/' . $file ); } }
175             foreach my $sub_dir ( @sub_dirs ) { $self->compress_directory( $sub_dir ); }
176             }
177              
178             sub compress_document {
179             my ( $self, $file ) = @_;
180             my @parts = split(/\//, $file);
181             my $root_dir = $self->_get_root_dir();
182             my $file_name = pop( @parts );
183             $file_name =~ m/^([\w\.%-]*)\.([\w%-]*)$/;
184             my $file_root = $1;
185             my $path = join( '/', @parts );
186             $path =~ s/$root_dir\/documents\/corpus_(\d+)//;
187             my $corpus_id = $1;
188              
189             my $zip_file = $root_dir . '/documents/corpus_' . $corpus_id . $path . '/' . $file_root . '.zip';
190             `zip -q $zip_file $file`;
191             unlink( $file );
192              
193             my @stat = stat("$root_dir$path/$file_root.zip");
194             my $bytes = $stat[7] || '0';
195              
196             my $sql = "update submitted_documents set compressed_file_name = '$file_root.zip', compressed_bytes = '$bytes' ";
197             $sql .= "where document_path = '$path' ";
198             $sql .= " and document_file_name = '$file_name' ";
199             $self->library()->sqlexec( $sql );
200             }
201              
202             sub decompress {
203             my ( $self, $arg_ref ) = @_;
204             my $data_dir = $self->get_data_dir();
205             my @dirs = $self->_get_dirs( $data_dir, 0 );
206             foreach my $dir ( @dirs ) { $self->decompress_directory( $dir ); }
207             }
208              
209             sub decompress_directory {
210             my ( $self, $dir ) = @_;
211             my @files = $self->_get_files( $dir );
212             my @sub_dirs = $self->_get_dirs( $dir, 0 );
213              
214             foreach my $file ( @files ) {
215             if ($file =~ m/\.zip$/i) { $self->decompress_document( $dir . '/' . $file ); } }
216             foreach my $sub_dir ( @sub_dirs ) {
217             $self->decompress_directory( $sub_dir ); }
218             }
219              
220             sub decompress_document {
221             my ( $self, $zip_file ) = @_;
222             `unzip -q -d/ $zip_file`;
223             unlink( $zip_file );
224             }
225              
226             sub import_urls {
227             my ( $self, $arg_ref ) = @_;
228             my $ident = ident $self;
229             my $corpus_id = $id_of{$ident};
230             my $user_id = $arg_ref->{submitted_by_user_id};
231             my $source_type = $arg_ref->{source_type};
232             my @urls = ();
233             my $record_count = 0;
234            
235             if ($source_type eq 'files' ) { @urls = $self->_parse_urls_from_files( $arg_ref ); }
236             else { print STDERR " Warning: no valid source_type for \$corpus->import_url()\n"; }
237            
238             my @insert_values = ();
239             foreach my $url (@urls) {
240             foreach ($url) { $_ = $self->_html_to_sql($_); }
241             my $sql = "select submitted_urls.submitted_url_id from submitted_urls ";
242             $sql .= " where submitted_urls.submitted_url = '$url'";
243             my ( $url_id ) = $self->library()->sqlexec( $sql, '@' );
244            
245             if (! $url_id) {
246             my @path = split(/\//, $url); shift(@path); shift(@path);
247             my $file = pop(@path);
248             my $path = '';
249            
250             foreach ($path, $file) { $_ = $self->_html_to_sql($_); }
251             push @insert_values, "($corpus_id, $user_id, '$url')";
252            
253             if (@insert_values == 100) {
254             $record_count += 100;
255             my $url_sql = "insert into submitted_urls (corpus_id, submitted_by_user_id, submitted_url ) ";
256             $url_sql .= "values " . join( ',', @insert_values ) . ";";
257             $self->library()->sqlexec( $url_sql );
258             @insert_values = ();
259             }
260             }
261             }
262             if ( @insert_values ) {
263             $record_count += scalar( @insert_values );
264             my $url_sql = "insert into submitted_urls (corpus_id, submitted_by_user_id, submitted_url ) ";
265             $url_sql .= "values " . join( ',', @insert_values ) . ";";
266             $self->library()->sqlexec( $url_sql );
267             }
268             return $record_count;
269             }
270              
271             sub _parse_urls_from_files {
272             my ( $self, $arg_ref ) = @_;
273             my $ident = ident $self;
274             my $source_dir = $arg_ref->{source_dir} ? $arg_ref->{source_dir} : $self->_get_root_dir() . '/document_sources/corpus_' . $id_of{$ident};
275             my $link_type = $arg_ref->{link_type};
276             my %link = ();
277            
278             my @files = $self->_get_files( $source_dir );
279              
280             foreach my $file (@files) {
281             my $content = $self->_get_file_text($source_dir . "/$file");
282             my $parser = HTML::LinkExtor->new(); $parser->parse($content)->eof;
283             my @links = $parser->links;
284            
285             foreach my $linkarray (@links) {
286             my @elements = @$linkarray;
287             my $elt_type = shift @elements;
288            
289             while (@elements) {
290             my ($attr_name, $attr_value) = splice(@elements, 0, 2);
291             if ($attr_value =~ m/^http(.*)$link_type$/i) { $link{$attr_value}++; }
292             }
293             }
294             }
295             return sort keys %link;
296             }
297             }
298              
299             1; # Magic true value required at end of module
300             __END__