Entries.pm 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. # ------------------------------------------------------------------------------
  2. # (C) Crown copyright Met Office. All rights reserved.
  3. # For further details please refer to the file COPYRIGHT.txt
  4. # which you should have received as part of this distribution.
  5. # ------------------------------------------------------------------------------
  6. use strict;
  7. use warnings;
  8. package Fcm::Keyword::Entries;
  9. use Carp qw{croak};
  10. use Fcm::Util::ClassLoader;
  11. sub new {
  12. my ($class, $args_ref) = @_;
  13. return bless(
  14. {
  15. entry_class => 'Fcm::Keyword::Entry',
  16. entry_by => {key => {}, value => {}},
  17. has_loaded_entries_from => {},
  18. loaders => [],
  19. ($args_ref && ref($args_ref) eq 'HASH' ? %{$args_ref} : ()),
  20. },
  21. $class,
  22. );
  23. }
  24. ################################################################################
  25. # Returns the class of entries stored by this entries list
  26. sub get_entry_class {
  27. my ($self) = @_;
  28. return $self->{entry_class};
  29. }
  30. ################################################################################
  31. # Returns all entries
  32. sub get_all_entries {
  33. my ($self) = @_;
  34. if (!%{$self->{entry_by}{key}}) {
  35. # Nothing set, attempt to load entries
  36. $self->load_entries();
  37. }
  38. if (wantarray()) {
  39. return values(%{$self->{entry_by}{key}});
  40. }
  41. else {
  42. return [values(%{$self->{entry_by}{key}})];
  43. }
  44. }
  45. ################################################################################
  46. # Methods: get_entry_by_*
  47. for my $name (
  48. ### Returns an entry with a matching key
  49. 'key',
  50. ### Returns an entry with a matching value
  51. 'value'
  52. ) {
  53. no strict qw{refs};
  54. my $method = "get_entry_by_$name";
  55. *$method = sub {
  56. my ($self, $search_key) = @_;
  57. if (!defined($search_key)) {
  58. return;
  59. }
  60. my $sk = ($name eq 'key') ? uc($search_key) : $search_key;
  61. if (!exists($self->{entry_by}{$name}{$sk})) {
  62. $self->load_entries($name, $sk);
  63. }
  64. if (exists($self->{entry_by}{$name}{$sk})) {
  65. return $self->{entry_by}{$name}{$sk};
  66. }
  67. else {
  68. return;
  69. }
  70. }
  71. }
  72. ################################################################################
  73. # Adds an entry
  74. sub add_entry {
  75. my ($self, $key, $value, $args_ref) = @_;
  76. Fcm::Util::ClassLoader::load($self->get_entry_class());
  77. my $entry = $self->get_entry_class()->new({
  78. key => uc($key),
  79. value => $value,
  80. ($args_ref && ref($args_ref) eq 'HASH' ? %{$args_ref} : ()),
  81. });
  82. $self->{entry_by}{key}{uc($key)} = $entry;
  83. $self->{entry_by}{value}{$value} = $entry;
  84. return $entry;
  85. }
  86. ################################################################################
  87. # Returns the loaders for this entries list
  88. sub get_loaders {
  89. my ($self) = @_;
  90. return (wantarray() ? @{$self->{loaders}} : $self->{loaders});
  91. }
  92. ################################################################################
  93. # Loads entries using its loaders
  94. sub load_entries {
  95. my ($self, $name, $search_key) = @_;
  96. LOADER:
  97. for my $loader ($self->get_loaders()) {
  98. if ($self->{has_loaded_entries_from}{$loader->get_source()}) {
  99. next LOADER;
  100. }
  101. $self->{has_loaded_entries_from}{$loader->get_source()}
  102. = $loader->load_to($self);
  103. if ($name && exists($self->{entry_by}{$name}{$search_key})) {
  104. last LOADER;
  105. }
  106. }
  107. }
  108. 1;
  109. __END__
  110. =head1 NAME
  111. Fcm::Keyword::Entries
  112. =head1 SYNOPSIS
  113. use Fcm::Keyword::Entries;
  114. my $entries = Fcm::Keyword::Entries->new({
  115. entry_class => $entry_class,
  116. loaders => \@loaders,
  117. });
  118. $entry = $entries->get_entry_by_key($key);
  119. $entry = $entries->get_entry_by_value($value);
  120. for my $entry ($entries->get_entries()) {
  121. # ...
  122. }
  123. $entries->add_entry($key, $value);
  124. =head1 DESCRIPTION
  125. This module is used to manipulate FCM keyword entries. It is used by
  126. L<Fcm::Keyword|Fcm::Keyword> to store keyword entries, which are
  127. L<Fcm::Keyword::Entry|Fcm::Keyword::Entry> objects.
  128. =head1 METHODS
  129. =over 4
  130. =item C<new({entry_class =E<gt> $entry_class, loaders =E<gt> \@loaders})>
  131. Constructor. The argument should be a reference to hash, where:
  132. I<entry_class> is a string representing the class name of entries in this
  133. object. The class must be a sub-class of
  134. L<Fcm::Keyword::Entry|Fcm::Keyword::Entry>. The default is
  135. "L<Fcm::Keyword::Entry|Fcm::Keyword::Entry>".
  136. I<loaders> is a reference to an array of
  137. L<Fcm::Keyword::Loader|Fcm::Keyword::Loader> objects, which will be used to
  138. load entries into this object. The default is an empty array.
  139. =item add_entry($key,$value)
  140. Adds an entry. Returns the added entry. (Keys are converted to uppercases
  141. automatically.)
  142. =item get_all_entries()
  143. Returns all entries that are currently loaded.
  144. =item get_entry_by_key($key)
  145. Return an entry, whose key matches $key. (Search is case-insensitive.) Returns
  146. undef if there is no matching entry.
  147. =item get_entry_by_value($value)
  148. Return an entry, whose value matches $value. (Search is case-sensitive.)
  149. Returns undef if there is no matching entry.
  150. =item get_loaders()
  151. Returns the loaders for loading entries.
  152. =item load_entries()
  153. Loads entries from its loaders, as returned by get_loaders(). This method can
  154. also be triggered by get_all_entries(), if the entry list is empty, or by
  155. get_entry_by_key($key) and get_entry_by_value($value) methods, if there is no
  156. matching entry in the current lookup lists.
  157. =back
  158. =head1 TO DO
  159. Handle duplicated entries in add_entry($key,$value).
  160. =head1 SEE ALSO
  161. L<Fcm::Keyword|Fcm::Keyword>,
  162. L<Fcm::Keyword::Entry|Fcm::Keyword::Entry>,
  163. L<Fcm::Keyword::Loader|Fcm::Keyword::Loader>
  164. =head1 COPYRIGHT
  165. E<169> Crown copyright Met Office. All rights reserved.
  166. =cut