Pārlūkot izejas kodu

Merge pull request #47 from redline6561/user-defined-routing

User defined routing
Brit Butler 11 gadi atpakaļ
vecāks
revīzija
40d6e5bb2c

+ 8 - 2
NEWS.md

1
 ## Changes for 0.9.4 (2013-05-05):
1
 ## Changes for 0.9.4 (2013-05-05):
2
 
2
 
3
+* **SITE-BREAKING CHANGE**: Coleslaw now supports user-defined routing.
4
+  Instead of hard-coding the paths various content types are stored at,
5
+  they must be specified in the configuration file (.coleslawrc). Just
6
+  copy the `:routing` key from the [example][single_site.rc] to get
7
+  the old behavior.
3
 * Coleslaw no longer expects a particular repo layout. Use whatever
8
 * Coleslaw no longer expects a particular repo layout. Use whatever
4
   directory hierarchy you like.
9
   directory hierarchy you like.
5
 
10
 
69
 
74
 
70
 * Initial release.
75
 * Initial release.
71
 
76
 
72
-[hacking_guide]: https://github.com/redline6561/coleslaw/blob/master/docs/hacking.md
73
-[theming_guide]: https://github.com/redline6561/coleslaw/blob/master/docs/themes.md
77
+[hacking_guide]:  https://github.com/redline6561/coleslaw/blob/master/docs/hacking.md
78
+[theming_guide]:  https://github.com/redline6561/coleslaw/blob/master/docs/themes.md
79
+[single_site.rc]: https://github.com/redline6561/coleslaw/blob/master/examples/single-site.coleslawrc

+ 1 - 1
coleslaw.asd

1
 (defsystem #:coleslaw
1
 (defsystem #:coleslaw
2
   :name "coleslaw"
2
   :name "coleslaw"
3
   :description "Flexible Lisp Blogware"
3
   :description "Flexible Lisp Blogware"
4
-  :version "0.9.3"
4
+  :version "0.9.4-dev"
5
   :license "BSD"
5
   :license "BSD"
6
   :author "Brit Butler <redline6561@gmail.com>"
6
   :author "Brit Butler <redline6561@gmail.com>"
7
   :pathname "src/"
7
   :pathname "src/"

+ 1 - 13
docs/hacking.md

74
 
74
 
75
 - `page-url`: Generate a unique, relative path for the object on the site
75
 - `page-url`: Generate a unique, relative path for the object on the site
76
   sans file extension. An :around method adds that later. The `slug` slot
76
   sans file extension. An :around method adds that later. The `slug` slot
77
-  on the object is generally used to hold a portion of the unique
77
+  on the object is conventionally used to hold a portion of the unique
78
   identifier. i.e. `(format nil "posts/~a" (content-slug object))`.
78
   identifier. i.e. `(format nil "posts/~a" (content-slug object))`.
79
 - `render`: A method that calls the appropriate template with `theme-fn`,
79
 - `render`: A method that calls the appropriate template with `theme-fn`,
80
   passing it any needed arguments and returning rendered HTML.
80
   passing it any needed arguments and returning rendered HTML.
176
 function. There may be other areas where it was assumed tags/dates
176
 function. There may be other areas where it was assumed tags/dates
177
 will always be present.
177
 will always be present.
178
 
178
 
179
-### User-Defined Routing
180
-
181
-There is no reason *coleslaw* should be in charge of the site layout or
182
-should care. If all objects only used the *slug* slot in their `page-url`
183
-methods, there could be a :routing argument in the config containing
184
-a plist of `(:class "~{format string~}")` pairs. A default method could
185
-check the :class key under `(routing *config*)` if no specialized
186
-`page-url` was defined. This would have the additional benefit of
187
-localizing all the site routing in one place. New Content Types would
188
-probably `pushnew` a plist onto the config key in their `enable` function.
189
-This has been implemented on the branch `user-defined-routing`.
190
-
191
 ### New Content Type: Pages!
179
 ### New Content Type: Pages!
192
 
180
 
193
 Many users have requested a content type PAGE, for static pages. It
181
 Many users have requested a content type PAGE, for static pages. It

+ 12 - 0
examples/multi-site.coleslawrc

3
                                       :domain "http://blub.co.za"
3
                                       :domain "http://blub.co.za"
4
                                       :feeds ("lisp")
4
                                       :feeds ("lisp")
5
                                       :plugins ((mathjax))
5
                                       :plugins ((mathjax))
6
+                                      :routing ((:post           "posts/~a")
7
+                                                (:tag-index      "tag/~a")
8
+                                                (:month-index    "date/~a")
9
+                                                (:numeric-index  "~d")
10
+                                                (:feed           "~a.xml")
11
+                                                (:tag-feed       "tag/~a.xml"))
6
                                       :sitenav ((:url "http://twitter.com/ralph_moeritz" :name "Twitter")
12
                                       :sitenav ((:url "http://twitter.com/ralph_moeritz" :name "Twitter")
7
                                                 (:url "http://github.com/ralph-moeritz" :name "Code"))
13
                                                 (:url "http://github.com/ralph-moeritz" :name "Code"))
8
                                       :staging-dir "/tmp/coleslaw"
14
                                       :staging-dir "/tmp/coleslaw"
13
                                   :domain "http://musings.co.za"
19
                                   :domain "http://musings.co.za"
14
                                   :feeds ("opinion")
20
                                   :feeds ("opinion")
15
                                   :plugins ((mathjax))
21
                                   :plugins ((mathjax))
22
+                                  :routing ((:post           "posts/~a")
23
+                                            (:tag-index      "tag/~a")
24
+                                            (:month-index    "date/~a")
25
+                                            (:numeric-index  "~d")
26
+                                            (:feed           "~a.xml")
27
+                                            (:tag-feed       "tag/~a.xml"))
16
                                   :sitenav ((:url "http://twitter.com/ralph_moeritz" :name "Twitter")
28
                                   :sitenav ((:url "http://twitter.com/ralph_moeritz" :name "Twitter")
17
                                             (:url "http://github.com/ralph-moeritz" :name "Code"))
29
                                             (:url "http://github.com/ralph-moeritz" :name "Code"))
18
                                   :staging-dir "/tmp/coleslaw"
30
                                   :staging-dir "/tmp/coleslaw"

+ 6 - 0
examples/single-site.coleslawrc

7
            (disqus :shortname "my-site-name")
7
            (disqus :shortname "my-site-name")
8
            (analytics :tracking-code "foo"))
8
            (analytics :tracking-code "foo"))
9
  :repo "/home/git/tmp/improvedmeans/"
9
  :repo "/home/git/tmp/improvedmeans/"
10
+ :routing ((:post           "posts/~a")
11
+           (:tag-index      "tag/~a")
12
+           (:month-index    "date/~a")
13
+           (:numeric-index  "~d")
14
+           (:feed           "~a.xml")
15
+           (:tag-feed       "tag/~a.xml"))
10
  :sitenav ((:url "http://redlinernotes.com/" :name "Home")
16
  :sitenav ((:url "http://redlinernotes.com/" :name "Home")
11
            (:url "http://twitter.com/redline6561" :name "Twitter")
17
            (:url "http://twitter.com/redline6561" :name "Twitter")
12
            (:url "http://github.com/redline6561" :name "Code")
18
            (:url "http://github.com/redline6561" :name "Code")

+ 7 - 1
src/documents.lisp

27
 ;; Instance Methods
27
 ;; Instance Methods
28
 
28
 
29
 (defgeneric page-url (document)
29
 (defgeneric page-url (document)
30
-  (:documentation "The url to the DOCUMENT without the domain."))
30
+  (:documentation "The url to the DOCUMENT without the domain.")
31
+  (:method (document)
32
+    (let* ((class-name (class-name (class-of document)))
33
+           (route (assoc class-name (routing *config*))))
34
+      (if route
35
+          (format nil (second route) (slot-value document 'slug))
36
+          (error "No routing method found for: ~A" class-name)))))
31
 
37
 
32
 (defmethod page-url :around ((document t))
38
 (defmethod page-url :around ((document t))
33
   (let ((result (call-next-method)))
39
   (let ((result (call-next-method)))

+ 7 - 20
src/indexes.lisp

17
 
17
 
18
 (defclass tag-index (index) ())
18
 (defclass tag-index (index) ())
19
 
19
 
20
-(defmethod page-url ((object tag-index))
21
-  (format nil "tag/~a" (index-slug object)))
22
-
23
 (defmethod discover ((doc-type (eql (find-class 'tag-index))))
20
 (defmethod discover ((doc-type (eql (find-class 'tag-index))))
24
   (let ((content (by-date (find-all 'post))))
21
   (let ((content (by-date (find-all 'post))))
25
     (dolist (tag (all-tags))
22
     (dolist (tag (all-tags))
39
 
36
 
40
 (defclass month-index (index) ())
37
 (defclass month-index (index) ())
41
 
38
 
42
-(defmethod page-url ((object month-index))
43
-  (format nil "date/~a" (index-slug object)))
44
-
45
 (defmethod discover ((doc-type (eql (find-class 'month-index))))
39
 (defmethod discover ((doc-type (eql (find-class 'month-index))))
46
   (let ((content (by-date (find-all 'post))))
40
   (let ((content (by-date (find-all 'post))))
47
     (dolist (month (all-months))
41
     (dolist (month (all-months))
61
 
55
 
62
 (defclass numeric-index (index) ())
56
 (defclass numeric-index (index) ())
63
 
57
 
64
-(defmethod page-url ((object numeric-index))
65
-  (format nil "~d" (index-slug object)))
66
-
67
 (defmethod discover ((doc-type (eql (find-class 'numeric-index))))
58
 (defmethod discover ((doc-type (eql (find-class 'numeric-index))))
68
   (let ((content (by-date (find-all 'post))))
59
   (let ((content (by-date (find-all 'post))))
69
     (dotimes (i (ceiling (length content) 10))
60
     (dotimes (i (ceiling (length content) 10))
90
 (defclass feed (index)
81
 (defclass feed (index)
91
   ((format :initform nil :initarg :format :accessor feed-format)))
82
   ((format :initform nil :initarg :format :accessor feed-format)))
92
 
83
 
93
-(defmethod page-url ((object feed))
94
-  (format nil "~(~a~).xml" (feed-format object)))
95
-
96
 (defmethod discover ((doc-type (eql (find-class 'feed))))
84
 (defmethod discover ((doc-type (eql (find-class 'feed))))
97
-  (let ((content (take-up-to 10 (by-date (find-all 'post)))))
85
+  (let ((content (by-date (find-all 'post))))
98
     (dolist (format '(rss atom))
86
     (dolist (format '(rss atom))
99
-      (let ((feed (make-instance 'feed :content content :format format)))
87
+      (let ((feed (make-instance 'feed :format format
88
+                                 :content (take-up-to 10 content)
89
+                                 :slug (format nil "~(~a~)" format))))
100
         (add-document feed)))))
90
         (add-document feed)))))
101
 
91
 
102
 (defmethod publish ((doc-type (eql (find-class 'feed))))
92
 (defmethod publish ((doc-type (eql (find-class 'feed))))
107
 
97
 
108
 (defclass tag-feed (feed) ())
98
 (defclass tag-feed (feed) ())
109
 
99
 
110
-(defmethod page-url ((object tag-feed))
111
-  (format nil "tag/~a~(~a~).xml" (index-slug object) (feed-format object)))
112
-
113
 (defmethod discover ((doc-type (eql (find-class 'tag-feed))))
100
 (defmethod discover ((doc-type (eql (find-class 'tag-feed))))
114
   (let ((content (by-date (find-all 'post))))
101
   (let ((content (by-date (find-all 'post))))
115
     (dolist (tag (feeds *config*))
102
     (dolist (tag (feeds *config*))
116
       (let ((tagged (remove-if-not (lambda (x) (tag-p tag x)) content)))
103
       (let ((tagged (remove-if-not (lambda (x) (tag-p tag x)) content)))
117
         (dolist (format '(rss atom))
104
         (dolist (format '(rss atom))
118
-          (let ((feed (make-instance 'tag-feed :content (take-up-to 10 tagged)
119
-                                     :format format
120
-                                     :slug tag)))
105
+          (let ((feed (make-instance 'tag-feed :format format
106
+                                     :content (take-up-to 10 tagged)
107
+                                     :slug (format nil "~a-~(~a~)" tag format))))
121
             (add-document feed)))))))
108
             (add-document feed)))))))
122
 
109
 
123
 (defmethod publish ((doc-type (eql (find-class 'tag-feed))))
110
 (defmethod publish ((doc-type (eql (find-class 'tag-feed))))

+ 0 - 3
src/posts.lisp

21
                                   :prev prev
21
                                   :prev prev
22
                                   :next next)))
22
                                   :next next)))
23
 
23
 
24
-(defmethod page-url ((object post))
25
-  (format nil "posts/~a" (content-slug object)))
26
-
27
 (defmethod publish ((doc-type (eql (find-class 'post))))
24
 (defmethod publish ((doc-type (eql (find-class 'post))))
28
   (loop for (next post prev) on (append '(nil) (by-date (find-all 'post)))
25
   (loop for (next post prev) on (append '(nil) (by-date (find-all 'post)))
29
      while post do (write-document post nil :prev prev :next next)))
26
      while post do (write-document post nil :prev prev :next next)))