Browse Source

EntryStore: by_prop(), props_for(), all_props(); property hashes

Adds a couple of hashes in the App::WRT::EntryStore::new() constructor
which stash arrays of properties for each entry, and arrays of entries
for each property, as File::Find works its way through the $entry_dir.

Uses props_for() in App::WRT::entry_topic_list() instead of dir_list().
This is maybe a tiny performance gain, but also probably more hassle
than it's worth unless other features are going to be built on these
methods (or other code that calls dir_list() simplified).

This also moves a chunk of logic out of EntryStore::all() and into the
constructor, and directly accesses $self->{source_files} in a couple of
methods instead of tossing around copies of the array.

I'm kind of iffy on whether any of this is worth doing.
Brennen Bearnes 5 months ago
parent
commit
9b7549ba10
3 changed files with 119 additions and 36 deletions
  1. 4
    12
      lib/App/WRT.pm
  2. 87
    23
      lib/App/WRT/EntryStore.pm
  3. 28
    1
      t/wrt_entrystore.t

+ 4
- 12
lib/App/WRT.pm View File

@@ -726,22 +726,14 @@ sub entry_topic_list {
726 726
   my $self = shift;
727 727
   my ($entry) = @_;
728 728
 
729
-  # Location of entry on local filesystem, and its URL:
730
-  my ($entry_loc, $entry_url) = $self->root_locations($entry);
731
-
732
-  my @tag_files;
733
-
734
-  # If it's a directory, look for some tag property files:
735
-  if (-d $entry_loc) {
736
-    @tag_files = dir_list($entry_loc, 'alpha', '^tag-.*[.]prop$');
737
-  }
729
+  my @tags = sort grep { m/^tag-.*/ } $self->{entries}->props_for($entry);
738 730
 
739
-  return '' unless @tag_files;
731
+  return '' unless @tags;
740 732
 
741 733
   return join ', ', map {
742
-    s/^tag-(.*)[.]prop$/$1/;
734
+    s/^tag-(.*)$/$1/;
743 735
     a($_, { href => $self->{url_root} . 'topics/' . $_ })
744
-  } @tag_files;
736
+  } @tags;
745 737
 }
746 738
 
747 739
 =item entry($entry)

+ 87
- 23
lib/App/WRT/EntryStore.pm View File

@@ -46,6 +46,10 @@ App::WRT::EntryStore - model the contents of a wrt repo's entry_dir
46 46
 
47 47
 Get a new EntryStore, using a given $entry_dir.
48 48
 
49
+Finds a list of entries for the given directory, and builds data structures
50
+which can be used to index into entries by depth, property, and next/previous
51
+entry.
52
+
49 53
 =cut
50 54
 
51 55
 sub new {
@@ -60,28 +64,9 @@ sub new {
60 64
 
61 65
   bless $self, $class;
62 66
 
63
-  $self->generate_date_hashes();
64
-
65
-  return $self;
66
-}
67
-
68
-=item all()
69
-
70
-Returns a list of all source files for the current entry archive (excepting
71
-index files, which are a special case - this part could use some work).
72
-
73
-This was originally in App::WRT::Renderer, so there may be some pitfalls here.
74
-
75
-=cut
76
-
77
-sub all {
78
-  my ($self) = shift;
79
-  my $entry_dir = $self->{entry_dir};
80
-
81
-  # Check if we already have a value cached:
82
-  return @{ $self->{source_files} } if defined $self->{source_files};
83
-
84 67
   my @source_files;
68
+  my %entry_properties;
69
+  my %property_entries;
85 70
   find(
86 71
     sub {
87 72
       # We skip index files, because they'll be rendered from the dir path:
@@ -89,6 +74,19 @@ sub all {
89 74
       if ($File::Find::name =~ m{^ \Q$entry_dir\E / (.*) $}x) {
90 75
         my $target = $1;
91 76
         push @source_files, $target;
77
+
78
+        # Build hashes of all properties of entries, and all entries of properties:
79
+        if ($target =~ m{(.*) / (.*) [.]prop $}x) {
80
+          my ($entry, $property) = ($1, $2);
81
+
82
+          $entry_properties{$entry} = []
83
+            unless defined $entry_properties{$entry};
84
+          push @{ $entry_properties{$entry} }, $property;
85
+
86
+          $property_entries{$property} = []
87
+            unless defined $property_entries{$property};
88
+          push @{ $property_entries{$property} }, $entry;
89
+        }
92 90
       }
93 91
     },
94 92
     $entry_dir
@@ -96,8 +94,26 @@ sub all {
96 94
 
97 95
   # Stash arrayref for future use:
98 96
   $self->{source_files} = \@source_files;
97
+  $self->{property_entries}   = \%property_entries;
98
+  $self->{entry_properties}   = \%entry_properties;
99
+
100
+  $self->generate_date_hashes();
101
+
102
+  return $self;
103
+}
104
+
105
+=item all()
106
+
107
+Returns a list of all source files for the current entry archive (excepting
108
+index files, which are a special case - this part could use some work).
109
+
110
+This was originally in App::WRT::Renderer, so there may be some pitfalls here.
99 111
 
100
-  return @source_files;
112
+=cut
113
+
114
+sub all {
115
+  my ($self) = shift;
116
+  return @{ $self->{source_files} };
101 117
 }
102 118
 
103 119
 =item dates_by_depth($depth)
@@ -140,7 +156,7 @@ sub dates_by_depth {
140 156
   my @by_depth = map  { $_->[0] }
141 157
                  sort { $a->[1] cmp $b->[1] }
142 158
                  map  { [$_, sortable_date_from_entry($_)] }
143
-                 grep m{^ $pattern $}x, $self->all();
159
+                 grep m{^ $pattern $}x, @{ $self->{source_files} };
144 160
 
145 161
   # Stash arrayref for future use:
146 162
   $self->{by_depth}->{$depth} = \@by_depth;
@@ -258,6 +274,54 @@ sub next {
258 274
   return $_[0]->{next_dates}->{ $_[1] };
259 275
 }
260 276
 
277
+=item by_prop($property)
278
+
279
+Return an array of any entries for the given property.
280
+
281
+=cut
282
+
283
+sub by_prop {
284
+  my $self = shift;
285
+  my ($property) = @_;
286
+
287
+  my @entries;
288
+  if (defined $self->{property_entries}{$property}) {
289
+    @entries = @{ $self->{property_entries}{$property} };
290
+  }
291
+
292
+  return @entries;
293
+}
294
+
295
+
296
+=item props_for($entry)
297
+
298
+Return an array of any properties for the given entry.
299
+
300
+=cut
301
+
302
+sub props_for {
303
+  my $self = shift;
304
+  my ($entry) = @_;
305
+
306
+  my @props;
307
+  if (defined $self->{entry_properties}{$entry}) {
308
+    @props = @{ $self->{entry_properties}{$entry} };
309
+  }
310
+
311
+  return @props;
312
+}
313
+
314
+=item all_props()
315
+
316
+Return an array of all properties.
317
+
318
+=cut
319
+
320
+sub all_props {
321
+  my $self = shift;
322
+  return keys %{ $self->{property_entries} };
323
+}
324
+
261 325
 =back
262 326
 
263 327
 =cut

+ 28
- 1
t/wrt_entrystore.t View File

@@ -5,7 +5,8 @@ use warnings;
5 5
 
6 6
 use lib 'lib';
7 7
 
8
-use Test::More tests => 7;
8
+use Data::Dumper;
9
+use Test::More tests => 11;
9 10
 use App::WRT;
10 11
 
11 12
 chdir 'example';
@@ -62,3 +63,29 @@ chdir 'example';
62 63
     $w->{entries}->previous('2014/1/2') eq '2014/1/1',
63 64
     'got a prev day for 2014/1/2'
64 65
   );
66
+
67
+# property finding by entry / entry finding by property
68
+  ok(
69
+    ($w->{entries}->by_prop('tag-something'))[0] eq '2014/1/2',
70
+    'found 2014/1/2 for tag-something.prop'
71
+  );
72
+
73
+  # diag(Dumper($w->{entries}->by_prop('something')));
74
+  # diag(scalar($w->{entries}->by_prop('something')));
75
+  ok(
76
+    scalar($w->{entries}->by_prop('something')) == 0,
77
+    'did not find any entries for something.prop'
78
+  );
79
+
80
+  ok(
81
+    'tag-something' eq ($w->{entries}->props_for('2014/1/2'))[0],
82
+    'found tag-something for 2014/1/2'
83
+  );
84
+
85
+  ok(
86
+    scalar($w->{entries}->all_props()) == 1,
87
+    'found 1 property for example repo'
88
+  );
89
+
90
+  # diag(Dumper($w->{entries}->{entry_properties}));
91
+  # diag(Dumper($w->{entries}->{property_entries}));