Browse Source

fix memoization issue and update readme

Leonardo 7 years ago
parent
commit
36b7a59b67
2 changed files with 89 additions and 75 deletions
  1. 38 37
      glossary/glossary.py
  2. 51 38
      glossary/readme.md

+ 38 - 37
glossary/glossary.py

@@ -4,8 +4,8 @@ and pages, and adds a `definitions` variable visible to all page templates.
 
 """
 
-from pelican import signals, contents
-from bs4 import BeautifulSoup
+import bs4
+from pelican import signals
 
 
 class Definitions():
@@ -13,57 +13,58 @@ class Definitions():
     exclude = []
 
 
-def extract_definitions(content):
-    soup = BeautifulSoup(content.content, 'html.parser')
-
-    for def_list in soup.find_all('dl'):
-        defns = []
-        for def_title in def_list.find_all('dt'):
-            if def_title.text not in Definitions.exclude:
-                defns.append(
-                    {'title': get_title(def_title),
-                     'link': get_link(def_title, content.url),
-                     'definition': get_def(def_title),
-                     'source': content})
+def make_title(def_title):
+    return def_title.text
 
-        for defn in defns:
-            defn['see_also'] = [also for also in defns if also is not defn]
 
-        Definitions.definitions += defns
+def make_def(def_title):
+    return ''.join(str(t) for t in def_title.find_next('dd').contents)
 
 
-def get_title(def_title):
-    return def_title.text
+def make_anchor(def_title):
+    return def_title.text.lower().replace(' ', '-')
 
 
-def get_link(def_title, url):
-    a_tag = def_title.findChild('a')
-    if a_tag and a_tag['href']:
-        return url + a_tag['href']
-    else:
-        return None
+def set_definitions(generator, metadata):
+    generator.context['definitions'] = Definitions.definitions
 
 
-def get_def(def_title):
-    return ''.join(str(t) for t in def_title.find_next('dd').contents)
+def get_excludes(pelican):
+    Definitions.exclude = pelican.settings.get('GLOSSARY_EXCLUDE', [])
 
 
 def parse_content(content):
-    if isinstance(content, contents.Static) or not content.content:
-        return
-    else:
-        return extract_definitions(content)
+    soup = bs4.BeautifulSoup(content._content, 'html.parser')
 
+    for def_list in soup.find_all('dl'):
+        defns = []
+        for def_title in def_list.find_all('dt'):
+            if def_title.text not in Definitions.exclude:
+                anchor_name = make_anchor(def_title)
+                anchor_tag = bs4.Tag(name="a", attrs={'name': anchor_name})
+                index = def_list.parent.index(def_list)-1
+                def_list.parent.insert(index, anchor_tag)
 
-def set_definitions(generator, metadata):
-    generator.context['definitions'] = Definitions.definitions
+                defns.append(
+                    {'title': make_title(def_title),
+                     'definition': make_def(def_title),
+                     'anchor': anchor_name,
+                     'source': content})
+
+        for defn in defns:
+            defn['see_also'] = [d for d in defns if d is not defn]
+
+        Definitions.definitions += defns
+
+    content._content = str(soup)
 
 
-def get_excludes(generator, metadata):
-    Definitions.exclude = generator.context.get('GLOSSARY_EXCLUDE', [])
+def parse_articles(generator):
+    for article in generator.articles:
+        parse_content(article)
 
 
 def register():
-    signals.article_generator_context.connect(get_excludes)
-    signals.content_object_init.connect(parse_content)
+    signals.initialized.connect(get_excludes)
+    signals.article_generator_finalized.connect(parse_articles)
     signals.page_generator_context.connect(set_definitions)

+ 51 - 38
glossary/readme.md

@@ -1,85 +1,98 @@
 # Glossary
 
-Builds a glossary page containing definition lists found in articles and
-pages.
+Builds a glossary page containing definition lists found in articles.
 
 
 ## Example
 
-If you have an article or page that generates the following:
+If you have an article (Markdown or ReST) that generates the following:
 
 file `defns.html` titled "My definitions"
 ```
 <dl>
-  <dt><a href="some-link.html">My Term</a></dt>
+  <dt>My Term</dt>
   <dd>This is definition for My Term.</dd>
   <dt>Another Term</dt>
   <dd>And another definition.</dd>
 </dl>
 ```
 
-This plugin will extract all such definitions and put them inside the
+This plugin will do two things. First, it will add an anchor to the
+beginning of the <dl> tag, like so:
+
+file `defns.html` titled "My definitions"
+```
+<a name="another-term"></a>
+<a name="my-term"></a>
+<dl>
+  <dt>My Term</dt>
+  <dd>This is definition for My Term.</dd>
+  <dt>Another Term</dt>
+  <dd>And another definition.</dd>
+</dl>
+```
+
+Second, it will extract all such definitions and put them inside the
 `definitions` variable in the pelican context. It will be seen by all page
 templates.
 
 The `definitions` variable will have the following attributes:
 + `title`, the definition title, inside <dt> tags,
 + `definition`, the definition, inside <dd> tags,
-+ `link`, if the <dt> tags enclose a <a> tag, it will be stored here, or
-  None,
++ `anchor`, the text inside the `name` attribute for the anchor link,
 + `source`, the article or page that contains this definition list,
-+ `see_also`, containing a list of dicts just like this, made from other
-  definitions in the same list.
++ `see_also`, containing a list of objects just like this one, made from
+  other definitions in the same list.
 
 For example, for the above html code, the `definitions` variable would look
 like the following:
 
 ```
-definitions = [dict1, dict2]
-dict1.title = "My Term"
-dict1.definition = "This is definition for My Term."
-dict1.link = 'some-link.html'
-dict1.source = <content Object referring to "My definitions">
-dict1.see_also = [dict2]
-
-dict2.title = "Another Term"
-dict2.definition = "And another definition."
-dict2.link = None
-dict2.source = <content Object referring to "My definitions">
-dict2.see_also = [dict1]
+definitions = [obj1, obj2]
+obj1.title = "My Term"
+obj1.definition = "This is definition for My Term."
+obj1.anchor = 'my-term'
+obj1.source = <Content object pointing to "My definitions" file>
+obj1.see_also = [obj2]
+
+obj2.title = "Another Term"
+obj2.definition = "And another definition."
+obj2.link = 'another-term'
+obj2.source = <Content object pointing to "My definitions" file>
+obj2.see_also = [obj1]
 ```
 
-Note the `link` attribute does not necessarily point to `source.url`.
-
 
 ## Usage
 
 Next is an example usage of the `definitions` variable.
 
+glossary.html
 ```
 {% for def in definitions | sort(attribute='title') %}
 <dl>
-  <dt>{{ def.title }}</dt>
+  <a name="{{ def.anchor }}"></a>
+  <dt><h4>{{ def.title }}</h4></dt>
   <dd>
     <p>{{ def.definition }}</p>
-    <p>
-    Defined in:
-    {% if def.link %}<a href="{{ def.link }}">{% endif %}
-    {{ def.source.title }}
-    {% if def.link %}</a>{% endif %}.
-
-    {% if def.see_also %}
-    See also:
-    {% for also in def.see_also %}
-    <a href="{{ also.link }}">{{ also.title }}</a>
-    {% endfor%}
-    {% endif %}
-    </p>
+    <p><i>
+      <span>Defined in: <a href="{{ def.source.url }}#{{ def.anchor }}">{{ def.source.title }}</a>.</span>
+      {% if def.see_also %}
+      <span> See also: </span>
+      {% for also in def.see_also %}
+      <span><a href="{{ output_file }}#{{ also.anchor }}">{{ also.title }}</a>{% if not loop.last %}, {% else %}.{% endif %}</span>
+      {% endfor%}
+      {% endif %}
+    </i></p>
   </dd>
 </dl>
-{% endfor %}
 ```
 
+This example generates new anchors in the glossary page, so that navigation
+through the `see also` links is done inside the same page, as well as link
+to the source page (with the correct anchor too).
+>>>>>>> Stashed changes
+
 ## Notes
 
 + The `glossary` plugin supports the use of a `GLOSSARY_EXCLUDE` setting,