hobix 0.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (156) hide show
  1. data/COPYING +18 -0
  2. data/README +18 -0
  3. data/Rakefile +96 -0
  4. data/bin/hobix +94 -0
  5. data/contrib/blosxom-to-hobix.rb +253 -0
  6. data/contrib/txp-to-hobix.rb +56 -0
  7. data/contrib/webrick-all-mine.rb +20 -0
  8. data/doc/CHANGELOG +285 -0
  9. data/doc/rdoc/classes/Hobix/API.html +382 -0
  10. data/doc/rdoc/classes/Hobix/Article.html +111 -0
  11. data/doc/rdoc/classes/Hobix/BaseContent.html +692 -0
  12. data/doc/rdoc/classes/Hobix/BaseEntry.html +218 -0
  13. data/doc/rdoc/classes/Hobix/BaseFacet.html +205 -0
  14. data/doc/rdoc/classes/Hobix/BaseOutput.html +122 -0
  15. data/doc/rdoc/classes/Hobix/BasePlugin.html +201 -0
  16. data/doc/rdoc/classes/Hobix/BaseProperties/ClassMethods.html +243 -0
  17. data/doc/rdoc/classes/Hobix/BaseProperties.html +218 -0
  18. data/doc/rdoc/classes/Hobix/BasePublish.html +157 -0
  19. data/doc/rdoc/classes/Hobix/BaseStorage.html +417 -0
  20. data/doc/rdoc/classes/Hobix/BixWik/Entry.html +196 -0
  21. data/doc/rdoc/classes/Hobix/BixWik/IndexEntry.html +170 -0
  22. data/doc/rdoc/classes/Hobix/BixWik/WikiRedCloth.html +111 -0
  23. data/doc/rdoc/classes/Hobix/BixWik.html +418 -0
  24. data/doc/rdoc/classes/Hobix/BixWikPlugin.html +158 -0
  25. data/doc/rdoc/classes/Hobix/CommandLine.html +1970 -0
  26. data/doc/rdoc/classes/Hobix/Comment.html +113 -0
  27. data/doc/rdoc/classes/Hobix/Config.html +212 -0
  28. data/doc/rdoc/classes/Hobix/DataMarsh.html +667 -0
  29. data/doc/rdoc/classes/Hobix/Entry.html +178 -0
  30. data/doc/rdoc/classes/Hobix/EntryEnum.html +162 -0
  31. data/doc/rdoc/classes/Hobix/Enumerable.html +170 -0
  32. data/doc/rdoc/classes/Hobix/Facets/WikiEdit.html +180 -0
  33. data/doc/rdoc/classes/Hobix/Facets.html +111 -0
  34. data/doc/rdoc/classes/Hobix/LinkList.html +182 -0
  35. data/doc/rdoc/classes/Hobix/Out/Quick.html +412 -0
  36. data/doc/rdoc/classes/Hobix/Out.html +119 -0
  37. data/doc/rdoc/classes/Hobix/Page.html +381 -0
  38. data/doc/rdoc/classes/Hobix/Trackback.html +113 -0
  39. data/doc/rdoc/classes/Hobix/UriStr.html +198 -0
  40. data/doc/rdoc/classes/Hobix/WebApp/QueryString.html +207 -0
  41. data/doc/rdoc/classes/Hobix/WebApp/QueryValidationFailure.html +111 -0
  42. data/doc/rdoc/classes/Hobix/WebApp.html +1383 -0
  43. data/doc/rdoc/classes/Hobix/Weblog/AuthorNotFound.html +111 -0
  44. data/doc/rdoc/classes/Hobix/Weblog.html +2082 -0
  45. data/doc/rdoc/classes/Hobix.html +399 -0
  46. data/doc/rdoc/classes/Kernel.html +139 -0
  47. data/doc/rdoc/classes/Regexp.html +154 -0
  48. data/doc/rdoc/classes/YAML/Omap.html +144 -0
  49. data/doc/rdoc/classes/YAML.html +111 -0
  50. data/doc/rdoc/created.rid +1 -0
  51. data/doc/rdoc/files/COPYING.html +129 -0
  52. data/doc/rdoc/files/README.html +131 -0
  53. data/doc/rdoc/files/doc/CHANGELOG.html +101 -0
  54. data/doc/rdoc/files/lib/hobix/api_rb.html +119 -0
  55. data/doc/rdoc/files/lib/hobix/article_rb.html +126 -0
  56. data/doc/rdoc/files/lib/hobix/base_rb.html +128 -0
  57. data/doc/rdoc/files/lib/hobix/bixwik_rb.html +126 -0
  58. data/doc/rdoc/files/lib/hobix/commandline_rb.html +140 -0
  59. data/doc/rdoc/files/lib/hobix/comments_rb.html +126 -0
  60. data/doc/rdoc/files/lib/hobix/config_rb.html +125 -0
  61. data/doc/rdoc/files/lib/hobix/datamarsh_rb.html +108 -0
  62. data/doc/rdoc/files/lib/hobix/entry_rb.html +118 -0
  63. data/doc/rdoc/files/lib/hobix/linklist_rb.html +127 -0
  64. data/doc/rdoc/files/lib/hobix/publisher_rb.html +126 -0
  65. data/doc/rdoc/files/lib/hobix/trackbacks_rb.html +128 -0
  66. data/doc/rdoc/files/lib/hobix/webapp_rb.html +127 -0
  67. data/doc/rdoc/files/lib/hobix/weblog_rb.html +135 -0
  68. data/doc/rdoc/files/lib/hobix_rb.html +127 -0
  69. data/doc/rdoc/fr_class_index.html +67 -0
  70. data/doc/rdoc/fr_file_index.html +44 -0
  71. data/doc/rdoc/fr_method_index.html +307 -0
  72. data/doc/rdoc/index.html +24 -0
  73. data/doc/rdoc/rdoc-style.css +208 -0
  74. data/git_hobix_update.php +13 -0
  75. data/lib/hobix/api.rb +91 -0
  76. data/lib/hobix/article.rb +22 -0
  77. data/lib/hobix/base.rb +480 -0
  78. data/lib/hobix/bixwik.rb +200 -0
  79. data/lib/hobix/commandline.rb +677 -0
  80. data/lib/hobix/comments.rb +98 -0
  81. data/lib/hobix/config.rb +39 -0
  82. data/lib/hobix/datamarsh.rb +110 -0
  83. data/lib/hobix/entry.rb +84 -0
  84. data/lib/hobix/facets/comments.rb +99 -0
  85. data/lib/hobix/facets/publisher.rb +314 -0
  86. data/lib/hobix/facets/trackbacks.rb +80 -0
  87. data/lib/hobix/linklist.rb +81 -0
  88. data/lib/hobix/out/atom.rb +101 -0
  89. data/lib/hobix/out/erb.rb +64 -0
  90. data/lib/hobix/out/okaynews.rb +55 -0
  91. data/lib/hobix/out/quick.rb +314 -0
  92. data/lib/hobix/out/rdf.rb +97 -0
  93. data/lib/hobix/out/redrum.rb +26 -0
  94. data/lib/hobix/out/rss.rb +128 -0
  95. data/lib/hobix/plugin/akismet.rb +196 -0
  96. data/lib/hobix/plugin/bloglines.rb +73 -0
  97. data/lib/hobix/plugin/calendar.rb +212 -0
  98. data/lib/hobix/plugin/flickr.rb +110 -0
  99. data/lib/hobix/plugin/recent_comments.rb +84 -0
  100. data/lib/hobix/plugin/sections.rb +91 -0
  101. data/lib/hobix/plugin/tags.rb +60 -0
  102. data/lib/hobix/publish/ping.rb +53 -0
  103. data/lib/hobix/publish/replicate.rb +283 -0
  104. data/lib/hobix/publisher.rb +18 -0
  105. data/lib/hobix/search/dictionary.rb +141 -0
  106. data/lib/hobix/search/porter_stemmer.rb +203 -0
  107. data/lib/hobix/search/simple.rb +209 -0
  108. data/lib/hobix/search/vector.rb +100 -0
  109. data/lib/hobix/storage/filesys.rb +408 -0
  110. data/lib/hobix/trackbacks.rb +93 -0
  111. data/lib/hobix/util/objedit.rb +193 -0
  112. data/lib/hobix/util/patcher.rb +155 -0
  113. data/lib/hobix/webapp/cli.rb +195 -0
  114. data/lib/hobix/webapp/htmlform.rb +107 -0
  115. data/lib/hobix/webapp/message.rb +177 -0
  116. data/lib/hobix/webapp/urigen.rb +141 -0
  117. data/lib/hobix/webapp/webrick-servlet.rb +90 -0
  118. data/lib/hobix/webapp.rb +723 -0
  119. data/lib/hobix/weblog.rb +893 -0
  120. data/lib/hobix.rb +230 -0
  121. data/share/default-blog/hobix.yaml +16 -0
  122. data/share/default-blog/htdocs/site.css +174 -0
  123. data/share/default-blog/skel/entry.html.quick +0 -0
  124. data/share/default-blog/skel/index.atom.atom +0 -0
  125. data/share/default-blog/skel/index.html.quick-summary +0 -0
  126. data/share/default-blog/skel/index.xml.rss +0 -0
  127. data/share/default-blog/skel/index.yaml.okaynews +0 -0
  128. data/share/default-blog/skel/monthly.html.quick-archive +0 -0
  129. data/share/default-blog/skel/section.html.quick-archive +0 -0
  130. data/share/default-blog/skel/yearly.html.quick-archive +0 -0
  131. data/share/default-blog-modes.yaml +7 -0
  132. data/share/default-blog.apache-cgi.patch +8 -0
  133. data/share/default-blog.apache-ssi.patch +38 -0
  134. data/share/default-blog.apache2-ssi.patch +3 -0
  135. data/share/default-blog.cgi.patch +8 -0
  136. data/share/default-blog.comments.patch +5 -0
  137. data/share/default-blog.prototype.patch +766 -0
  138. data/share/default-blog.publisher.patch +5 -0
  139. data/share/default-blog.wiki.patch +29 -0
  140. data/share/publisher/css/control.css +90 -0
  141. data/share/publisher/css/form.css +238 -0
  142. data/share/publisher/css/form.import.css +72 -0
  143. data/share/publisher/css/main-menu.css +134 -0
  144. data/share/publisher/i/hobix-emblazen-1.png +0 -0
  145. data/share/publisher/i/hobix-emblazen-2.png +0 -0
  146. data/share/publisher/i/hobix-emblazen-3.png +0 -0
  147. data/share/publisher/i/hobix-emblazen-4.png +0 -0
  148. data/share/publisher/i/hobix-emblazen-5.png +0 -0
  149. data/share/publisher/i/hobix-emblazen-6.png +0 -0
  150. data/share/publisher/i/hobix-emblazen-7.png +0 -0
  151. data/share/publisher/index.erb +66 -0
  152. data/share/publisher/js/controls.js +261 -0
  153. data/share/publisher/js/dragdrop.js +476 -0
  154. data/share/publisher/js/effects.js +570 -0
  155. data/share/publisher/js/prototype.js +1011 -0
  156. metadata +230 -0
@@ -0,0 +1,314 @@
1
+ #
2
+ # = hobix/facets/publisher.rb
3
+ #
4
+ # Hobix command-line weblog system, web-based publishing interface.
5
+ #
6
+ # Copyright (c) 2003-2004 why the lucky stiff
7
+ #
8
+ # Written & maintained by why the lucky stiff <why@ruby-lang.org>
9
+ #
10
+ # This program is free software, released under a BSD license.
11
+ # See COPYING for details.
12
+ #
13
+ #--
14
+ # $Id$
15
+ #++
16
+
17
+ require 'erb'
18
+ require 'yaml'
19
+
20
+ module Hobix
21
+ module Facets
22
+
23
+ # The Publisher plugin adds a web interface for managing Hobix blogs.
24
+ # Basically, to add the publisher to your site, ensure the plugin
25
+ # is loaded within your hobix.yaml `requires' list:
26
+ #
27
+ # requires:
28
+ # - hobix/facets/publisher
29
+ #
30
+ class Publisher < BaseFacet
31
+ class MissingRequired < Exception; end
32
+
33
+ def initialize( weblog, defaults = {} )
34
+ @weblog = weblog
35
+ end
36
+ def get app
37
+ if app.respond_to? :action_uri
38
+ ns, method_id = app.action_uri.split( '/', 2 )
39
+ return false unless ( ns.nil? or ns == "publisher" )
40
+
41
+ case method_id
42
+ when /\.js$/
43
+ app.content_type = "text/javascript"
44
+ app.puts File.read( File.join( Hobix::SHARE_PATH, "publisher", method_id ) )
45
+ return true
46
+ when /\.css$/
47
+ app.content_type = "text/css"
48
+ app.puts File.read( File.join( Hobix::SHARE_PATH, "publisher", method_id ) )
49
+ return true
50
+ when /\.png$/
51
+ app.content_type = "image/png"
52
+ app.puts File.read( File.join( Hobix::SHARE_PATH, "publisher", method_id ) )
53
+ return true
54
+ end
55
+
56
+ # dispatch the url action
57
+ method_args = (method_id || "config").split( /\// )
58
+ method_id = "config"
59
+ method_args.length.downto(1) do |i|
60
+ if respond_to? "get_#{ method_args[0,i].join( '_' ) }"
61
+ method_id = "get_#{ method_args.slice!(0,i).join( '_' ) }"
62
+ break
63
+ end
64
+ end
65
+ method_args.unshift app
66
+ return false unless respond_to? method_id
67
+ @screen = method( method_id ).call( *method_args )
68
+ return true unless @screen
69
+
70
+ # Display publisher page
71
+ erb_src = File.read( File.join( Hobix::SHARE_PATH, "publisher/index.erb" ) )
72
+ app.content_type = 'text/html'
73
+ app.puts ::ERB.new( erb_src, nil, nil, "_hobixpublish" ).result( binding )
74
+ return true
75
+ end
76
+ end
77
+
78
+ def make_form( form )
79
+ form_erb = %q{
80
+ % current = nil
81
+ <style type="text/css">
82
+ <!--
83
+ ul.edit_as_map, ol.edit_as_omap {
84
+ list-style-image:none;
85
+ list-style-type:none;
86
+ margin-top:5px;
87
+ margin:0px;
88
+ padding:0px;
89
+ margin-left:140px;
90
+ }
91
+ ul.edit_as_map li, ol.edit_as_omap li {
92
+ padding: 3px 0px;
93
+ margin: 0px;
94
+ }
95
+ ol.edit_as_omap li .handle {
96
+ cursor: move;
97
+ }
98
+ -->
99
+ </style>
100
+ <script type="text/javascript" language="javascript">
101
+ // <![CDATA[
102
+ function sortable_to_csv(element) {
103
+ var element = $(element);
104
+ var options = {
105
+ tag: element.sortable.tag,
106
+ only: element.sortable.only,
107
+ name: element.id
108
+ }.extend(arguments[1] || {});
109
+
110
+ var items = $(element).childNodes;
111
+ var queryComponents = new Array();
112
+
113
+ for(var i=0; i<items.length; i++)
114
+ if(items[i].tagName && items[i].tagName==options.tag.toUpperCase() &&
115
+ (!options.only || (Element.Class.has(items[i], options.only))))
116
+ queryComponents.push(items[i].id.replace(element.id+'_',''));
117
+
118
+ return queryComponents;
119
+ }
120
+ // ]]>
121
+ </script>
122
+ <h2><%= form[:full_title] %></h2>
123
+ <form id="publisher_form" method="post" enctype="multipart/form-data">
124
+ <p><%= RedCloth.new( form[:intro] ).to_html %></p>
125
+ % form[:object].class.properties.each do |name, opts|
126
+ % next unless opts and opts[:edit_as]
127
+ % if sect = form[:object].class.prop_sections.detect { |k,v| v[:__sect] == current }
128
+ <fieldset>
129
+ <legend><%= sect[0] %></legend>
130
+ % end
131
+ % title = name.to_s.gsub( '_', ' ' ).capitalize
132
+ % val = form[:object].instance_variable_get( "@" + name.to_s )
133
+ % if name == :notes
134
+ <div class="notes">
135
+ <h4><%= title %></h4>
136
+ </div>
137
+ % else
138
+ <div class="<%= opts[:req] ? 'required' : 'optional' %>">
139
+ <label for="<%= name %>"><%= title %>:</label>
140
+ % case opts[:edit_as]
141
+ % when :password
142
+ <input type="password" name="<%= name %>" id="<%= name %>"
143
+ class="inputPassword" size="10" tabindex=""
144
+ maxlength="25" value="<%= val %>" />
145
+ % when :checkbox
146
+ <input type="checkbox" name="<%= name %>" id="<%= name %>"
147
+ class="inputCheckbox" tabindex="" value="1" />
148
+ % when :textarea
149
+ <textarea name="<%= name %>" id="<%= name %>" rows="<%= opts[:edit_rows] || 4 %>" cols="<%= opts[:edit_cols] || 36 %>" tabindex=""><%= val %></textarea>
150
+ % when :omap
151
+ <ol id="<%= name %>sort" class="edit_as_omap">
152
+ % val.each do |vkey, vval|
153
+ % vkey = vkey.keys.first if vkey.is_a? Hash
154
+ <li id="<%= name %>sort_<%= vkey %>" class="sorty" name="<%= vkey %>">
155
+ <span class="handle">&raquo;</span>
156
+ <%= vkey %>
157
+ <a href="<%= form[:app].absuri( :path_info => "/publisher/#{ @title }/edit/#{ name }/#{ vkey }" ) %>">edit</a>
158
+ <a href="<%= form[:app].absuri( :path_info => "/publisher/#{ @title }/del/#{ name }/#{ vkey }" ) %>">remove</a>
159
+ </li>
160
+ % end if val
161
+ <li class="new_item">
162
+ <span>&raquo;</span>
163
+ <input type="text" name="<%= name %>_new" id="<%= name %>_new" style="width:150px"
164
+ class="inputText" tabindex="" maxlength="255" value="" />
165
+ <a href="<%= form[:app].absuri( :path_info => "/publisher/#{ @title }/add/#{ name }" ) %>">add</a>
166
+ </li>
167
+ </ul>
168
+ <input type="hidden" name="<%= name %>" id="<%= name %>" value="" />
169
+ <script type="text/javascript" language="javascript">
170
+ // <![CDATA[
171
+ Sortable.create("<%= name %>sort", {handle:'handle', only: 'sorty', onUpdate:function () {
172
+ $("<%= name %>").value = sortable_to_csv(this.element).join(' ');
173
+ }});
174
+ // ]]>
175
+ </script>
176
+ % when :map
177
+ <ul id="<%= name %>_order" class="edit_as_map">
178
+ % val.each do |vkey, vval|
179
+ <li id="<%= name %>_<%= vkey %>">
180
+ <%= vkey %>
181
+ <a href="<%= form[:app].absuri( :path_info => "/publisher/#{ @title }/edit/#{ name }/#{ vkey }" ) %>">edit</a>
182
+ <a href="<%= form[:app].absuri( :path_info => "/publisher/#{ @title }/del/#{ name }/#{ vkey }" ) %>">remove</a>
183
+ </li>
184
+ % end if val
185
+ <li id="new_item">
186
+ <input type="text" name="<%= name %>_new" id="<%= name %>_new" style="width:150px"
187
+ class="inputText" tabindex="" maxlength="255" value="" />
188
+ <a href="<%= form[:app].absuri( :path_info => "/publisher/#{ @title }/add/#{ name }" ) %>">add</a>
189
+ </li>
190
+ </ul>
191
+ % else
192
+ <input type="text" name="<%= name %>" id="<%= name %>"
193
+ class="inputText" size="<%= opts[:edit_size] || 24 %>" tabindex=""
194
+ maxlength="255" value="<%= val %>" />
195
+ % end
196
+
197
+ % if opts.include? :notes
198
+ <small><%= fopts['notes'] %></small>
199
+ % end
200
+ % if form[:object].respond_to? "default_#{ name }"
201
+ <small><em>Defaults to <strong><%= form[:object].method( "default_#{ name }" ).call %></strong>.</em></small>
202
+ % end
203
+ </div>
204
+ % end
205
+ % current = name
206
+ % if form[:object].class.prop_sections.detect { |k,v| v[:__sect] == current }
207
+ </fieldset>
208
+ % end
209
+ % end
210
+ </fieldset>
211
+ <fieldset>
212
+ <div class="submit">
213
+ <div>
214
+
215
+ <input type="submit" class="inputSubmit" tabindex="" value="Submit &raquo;" />
216
+ <input type="submit" class="inputSubmit" tabindex="" value="Cancel" />
217
+ </div>
218
+ </div>
219
+ </fieldset>
220
+ </form>
221
+ }
222
+ return ::ERB.new( form_erb, 0, "%<>", "_hobixpublishFORM" ).result( binding )
223
+ end
224
+
225
+ def save_form( obj, app )
226
+ obj = obj.dup
227
+ missing = []
228
+ obj.class.properties.each do |name, opts|
229
+ next unless opts
230
+ next unless app._POST.has_key? name.to_s
231
+ val = app._POST[name.to_s]
232
+ val = nil if val and val.empty?
233
+ missing << name if val.nil? and opts[:req]
234
+
235
+ case opts[:edit_as]
236
+ when :omap
237
+ omap = obj.instance_variable_get( "@#{name}" )
238
+ sorted = val.to_s.split(/\s+/)
239
+ sorted.each { |item| omap << [item] unless omap.assoc(item) }
240
+ omap.sort_by { |item, val| sorted.index(item) || sorted.length }
241
+ when :map
242
+ map = obj.instance_variable_get( "@#{name}" )
243
+ val.to_s.split(/\s+/).each do |item|
244
+ map[item] ||= nil
245
+ end
246
+ else
247
+ obj.instance_variable_set( "@#{name}", val )
248
+ end
249
+ end
250
+ [obj, missing]
251
+ end
252
+
253
+ def red( str ); RedCloth.new( str ).to_html; end
254
+
255
+ def show_weblog_form( weblog, app )
256
+ make_form :app => app,
257
+ :full_title => 'Configure Your Weblahhg',
258
+ :intro => %q{
259
+ Generally speaking, you shouldn't have to alter many of your weblog settings.
260
+ Most of the below are available for those who really want to customize.
261
+
262
+ **Bold** fields are required.
263
+ }.gsub( /^ +/, '' ),
264
+ :object => weblog
265
+ end
266
+
267
+ def get_config( app )
268
+ @title = 'config'
269
+ case app.request_method
270
+ when "GET"
271
+ show_weblog_form( @weblog, app )
272
+ when "POST"
273
+ weblog, missing = save_form( @weblog, app )
274
+ # if missing.empty?
275
+ # weblog.save( weblog.hobix_yaml + ".edit" )
276
+ # red %{
277
+ # *Your configuraton has been saved.*
278
+ #
279
+ # Please note that this development version of Hobix isn't
280
+ # yet equipped to deal with re-sorting of the requires. I'm not that great with Prototype
281
+ # yet and I also want to write some code to sandbox the configuration, to check that the
282
+ # requires will load right before saving it.
283
+ # }
284
+ # else
285
+ # show_weblog_form( weblog, app )
286
+ # end
287
+ [weblog, missing].to_yaml
288
+ end
289
+ end
290
+
291
+ def get_entries( app, *entry_id )
292
+ @title = 'entries'
293
+ unless entry_id.empty?
294
+ e = @weblog.storage.load_entry( entry_id.join( '/' ) )
295
+ else
296
+ e = Hobix::Entry.new
297
+ end
298
+ case app.request_method
299
+ when "GET"
300
+ make_form :app => app,
301
+ :full_title => 'Post an Entry',
302
+ :intro => %q{
303
+ **Bold** fields are required.
304
+ }.gsub( /^ +/, '' ),
305
+ :object => e
306
+ when "POST"
307
+ e, missing = save_form( e, app )
308
+ e.inspect
309
+ end
310
+ end
311
+ end
312
+
313
+ end
314
+ end
@@ -0,0 +1,80 @@
1
+ #
2
+ # = hobix/facets/trackbacks.rb
3
+ #
4
+ # Hobix command-line weblog system, support for trackbacks.
5
+ #
6
+ # Copyright (c) 2003-2004 why the lucky stiff
7
+ #
8
+ # Written & maintained by why the lucky stiff <why@ruby-lang.org>
9
+ #
10
+ # This program is free software, released under a BSD license.
11
+ # See COPYING for details.
12
+ #
13
+ #--
14
+ # $Id$
15
+ #++
16
+
17
+ require 'hobix/entry'
18
+
19
+ module Hobix
20
+ module Facets
21
+
22
+ # The Trackbacks plugin adds support for the TrackBack specification
23
+ # (http://www.sixapart.com/pronet/docs/trackback_spec).
24
+ #
25
+ # Add this require to your hobix.yaml:
26
+ #
27
+ # requires:
28
+ # - hobix/trackbacks
29
+ #
30
+ class Trackbacks < BaseFacet
31
+ def self.trackback_fields; ['url','title', 'excerpt', 'blog_name']; end
32
+ def self.trackback_class; Hobix::Trackback; end
33
+
34
+ def initialize( weblog, defaults = {} )
35
+ @weblog = weblog
36
+ end
37
+ def get app
38
+ if app.respond_to? :action_uri
39
+ action, entry_id = app.action_uri.split( '/', 2 )
40
+ case action
41
+ when "trackback"
42
+ # Validate
43
+ on_entry = @weblog.storage.load_entry( entry_id ) rescue nil
44
+ return send_trackback_response( app, false, 'No such entry' ) if on_entry.nil?
45
+
46
+ # Create a trackback comment
47
+ trackback = Trackbacks.trackback_class.new do |t|
48
+ Trackbacks.trackback_fields.each do |tf|
49
+ t.method( "#{tf}=" ).call( app._POST[tf].to_s )
50
+ end
51
+ return send_trackback_response( app, false, 'Missing URL field' ) if (t.url || '').empty?
52
+ t.created = Time.now
53
+ t.ipaddress = app.remote_addr
54
+ end
55
+
56
+ # Save the trackback, upgen
57
+ @weblog.storage.append_to_attachment( entry_id, 'trackbacks', trackback )
58
+ @weblog.regenerate :update
59
+
60
+ # Send response
61
+ send_trackback_response( app, true )
62
+ return true
63
+ end
64
+ end
65
+ end
66
+
67
+ def send_trackback_response(app, ok = true, message = nil)
68
+ app.content_type = 'text/xml'
69
+ app.puts %{<?xml version="1.0" encoding="UTF-8"?>
70
+ <response>
71
+ <error>%d</error>
72
+ %s
73
+ </response>
74
+ } % [ok ? 0 : 1, message ? %{<message>#{message}</message>} : '']
75
+ true
76
+ end
77
+ end
78
+
79
+ end
80
+ end
@@ -0,0 +1,81 @@
1
+ #
2
+ # = hobix/linklist.rb
3
+ #
4
+ # Hobix command-line weblog system.
5
+ #
6
+ # Copyright (c) 2003-2004 why the lucky stiff
7
+ #
8
+ # Written & maintained by why the lucky stiff <why@ruby-lang.org>
9
+ #
10
+ # This program is free software, released under a BSD license.
11
+ # See COPYING for details.
12
+ #
13
+ #--
14
+ # $Id$
15
+ #++
16
+ require 'hobix/entry'
17
+ require 'redcloth'
18
+ require 'yaml'
19
+
20
+ # The LinkList class is an entry type for storing links. It's
21
+ # also a good example of how to subclass the Entry class so you
22
+ # can store your own kinds of entries.
23
+ #
24
+ # == Properties
25
+ #
26
+ # The LinkList responds to many of the same properties listed
27
+ # in the +Hobix::Entry+ class. The primary difference is that,
28
+ # instead of having a +content+ property, there is a +links+
29
+ # property.
30
+ #
31
+ # links:: Internally, this class stores a +YAML::Omap+, an
32
+ # Array of pairs. The links are kept in the order
33
+ # shown in the YAML file. They consist of a link
34
+ # title, paired with a URL.
35
+ #
36
+ # == Sample LinkList
37
+ #
38
+ # --- %YAML:1.0 !hobix.com,2004/linklist
39
+ # title: Hobix Links
40
+ # author: why
41
+ # created: 2004-05-30 18:53:00 -06:00
42
+ # links:
43
+ # - Hobix: http://hobix.com/
44
+ # - Learn Hobix: http://hobix.com/learn/
45
+ # - Textile Reference: http://hobix.com/textile/
46
+ #
47
+ module Hobix
48
+ class LinkList < BaseEntry
49
+
50
+ _ :links, :req => true, :edit_as => :textarea
51
+
52
+ # Converts the link list into a RedCloth string for display
53
+ # in templates.
54
+ def content
55
+ RedCloth.new(
56
+ @links.collect do |title, url|
57
+ "* \"#{ title }\":#{ url }"
58
+ end.join( "\n" )
59
+ )
60
+ end
61
+
62
+ # Adds support for enumeration.
63
+ def each
64
+ @links.each { |title, url| yield title, url }
65
+ end
66
+
67
+ # LinkLists currently output as YAML type family
68
+ # !hobix.com,2004/linklist.
69
+ yaml_type "tag:hobix.com,2004:linklist"
70
+ end
71
+ end
72
+
73
+ YAML::add_domain_type( 'hobix.com,2004', 'linklist' ) do |type, val|
74
+ ['tagline', 'summary'].each do |f|
75
+ val[f] = RedCloth.new( val[f].to_s ) if val[f]
76
+ end
77
+ if val['links'].class == ::Array
78
+ val['links'] = YAML::transfer( 'omap', val['links'] )
79
+ end
80
+ YAML::object_maker( Hobix::LinkList, val )
81
+ end
@@ -0,0 +1,101 @@
1
+ #
2
+ # = hobix/out/atom.rb
3
+ #
4
+ # Atom output for Hobix.
5
+ #
6
+ # Copyright (c) 2003-2004 why the lucky stiff
7
+ #
8
+ # Written & maintained by why the lucky stiff <why@ruby-lang.org>
9
+ #
10
+ # This program is free software, released under a BSD license.
11
+ # See COPYING for details.
12
+ #
13
+ #--
14
+ # $Id$
15
+ #++
16
+ require 'hobix/base'
17
+ require 'rexml/document'
18
+ require 'erb'
19
+ require 'uri'
20
+ require 'cgi'
21
+
22
+ module Hobix
23
+ module Out
24
+ module XmlQuick
25
+ def x( title, txt, attrs = nil )
26
+ e = REXML::Element.new title
27
+ e.attributes['xml:space'] = "preserve"
28
+ # self-quote to work around REXML quoting issues with HTML entities
29
+ REXML::Text.new ::ERB::Util.h( txt ), true, e, true if txt
30
+ attrs.each { |a,b| e.attributes[a] = b } if attrs
31
+ self << e
32
+ end
33
+ end
34
+ class Atom < Hobix::BaseOutput
35
+ def initialize( weblog )
36
+ @path = weblog.skel_path
37
+ end
38
+ def extension
39
+ "atom"
40
+ end
41
+ def load( file_name, vars )
42
+ rssdoc = REXML::Document.new( <<EOXML )
43
+ <feed
44
+ xmlns="http://www.w3.org/2005/Atom"
45
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
46
+ xml:lang="en">
47
+ <title></title>
48
+ <link rel="alternate" type="text/html" href="" />
49
+ <link rel="self" type="application/atom+xml" href="" />
50
+ <updated></updated>
51
+ <subtitle></subtitle>
52
+ <id></id>
53
+ <generator uri="http://hobix.com/" version="#{ Hobix::VERSION }">Hobix</generator>
54
+ <rights></rights>
55
+ </feed>
56
+ EOXML
57
+ uri = vars[:weblog].link
58
+ rssdoc << REXML::XMLDecl.new
59
+ rssdoc.elements['/feed/title'].text = vars[:weblog].title
60
+ alt_uri = vars[:weblog].link.to_s
61
+ REXML::XPath.first(rssdoc, '/atom:feed/atom:link[@rel="alternate"]',
62
+ { 'atom' => 'http://www.w3.org/2005/Atom' }).attributes['href'] = alt_uri
63
+ self_uri = "#{vars[:weblog].link}#{vars[:page].link}"
64
+ REXML::XPath.first(rssdoc, '/atom:feed/atom:link[@rel="self"]',
65
+ { 'atom' => 'http://www.w3.org/2005/Atom' }).attributes['href'] = self_uri
66
+ rssdoc.elements['/feed'].attributes['xml:base'] = self_uri
67
+ rssdoc.elements['/feed/subtitle'].text = vars[:weblog].tagline
68
+ rssdoc.elements['/feed/updated'].text = vars[:page].updated.strftime( "%Y-%m-%dT%H:%M:%SZ" )
69
+ rssdoc.elements['/feed/id'].text = "tag:#{ uri.host },#{ Time.now.year }:blog#{ uri.path }"
70
+ rssdoc.elements['/feed/rights'].text = vars[:weblog].copyright || "None"
71
+ ( vars[:entries] || [vars[:entry]] ).each do |e|
72
+ ele = REXML::Element.new 'entry'
73
+ ele.extend XmlQuick
74
+ ele.attributes['xml:base'] = e.link
75
+ ele.x( 'title', e.title )
76
+ ele.x( 'link', nil, {'rel' => 'alternate', 'type' => 'text/html', 'href' => e.link } )
77
+ ele.x( 'id', "tag:#{ uri.host },#{ Time.now.year }:blog#{ CGI.escape(uri.path) }entry#{ CGI.escape( "/#{ e.id }" ) }" )
78
+ ele.x( 'published', e.created.strftime( "%Y-%m-%dT%H:%M:%SZ" ) )
79
+ ele.x( 'updated', (e.modified || e.created).strftime( "%Y-%m-%dT%H:%M:%SZ" ) )
80
+ ele.x( 'dc:subject', e.section_id )
81
+ e.tags.find_all {|t| not (t.nil? or t == '') }.each do |t|
82
+ ele.x( 'category', '', { 'term' => t, 'scheme' => "http://hobix.com/tags" } )
83
+ end
84
+ ele.x( 'summary',
85
+ e.summary.to_html.gsub( /img src="\//, "img src=\"#{ vars[:weblog].link }/" ),
86
+ {'type' => 'html', 'mode' => 'escaped'} ) if e.respond_to? :summary and e.summary and !e.summary.empty?
87
+ author = vars[:weblog].authors[e.author]
88
+ ele_auth = REXML::Element.new 'author'
89
+ ele_auth.extend XmlQuick
90
+ ele_auth.x( 'name', author['name'] )
91
+ ele_auth.x( 'uri', author['url'] ) if author['url']
92
+ ele_auth.x( 'email', author['email'] ) if author['email']
93
+ ele << ele_auth
94
+ ele.x( 'content', e.content.to_html, {'type' => 'html'} )
95
+ rssdoc.elements['/feed'].add ele
96
+ end
97
+ rssdoc.to_s
98
+ end
99
+ end
100
+ end
101
+ end
@@ -0,0 +1,64 @@
1
+ #
2
+ # = hobix/out/erb.rb
3
+ #
4
+ # Hobix processing of ERB templates.
5
+ #
6
+ # Copyright (c) 2003-2004 why the lucky stiff
7
+ #
8
+ # Written & maintained by why the lucky stiff <why@ruby-lang.org>
9
+ #
10
+ # This program is free software, released under a BSD license.
11
+ # See COPYING for details.
12
+ #
13
+ #--
14
+ # $Id$
15
+ #++
16
+ require 'hobix/base'
17
+ require 'erb'
18
+
19
+ module Hobix
20
+ module Out
21
+ class ERBError < StandardError; end
22
+ class ERB < Hobix::BaseOutput
23
+ def initialize( weblog )
24
+ @path = weblog.skel_path
25
+ end
26
+ def extension
27
+ "erb"
28
+ end
29
+ def load( file_name, vars )
30
+ @bind = binding
31
+ vars.each do |k, v|
32
+ k.untaint
33
+ k_inspect = k.inspect.untaint
34
+ eval( "#{ k } = vars[#{ k_inspect }]", @bind )
35
+ end
36
+ @relpath = File.dirname( file_name )
37
+ @load_erb = import_erb( file_name )
38
+ begin
39
+ @load_erb.result( @bind )
40
+ rescue Exception => e
41
+ raise ERBError, "Error `#{ e.message }' in erb #{ file_name }."
42
+ end
43
+ end
44
+ def expand( fname )
45
+ if fname =~ /^\//
46
+ File.join( @path, fname )
47
+ else
48
+ File.join( @relpath, fname )
49
+ end
50
+ end
51
+ def import( fname, bindto = @bind )
52
+ import_erb( expand( fname ) ).result( bindto )
53
+ end
54
+ def import_erb(fname)
55
+ File.open(fname) do |fp|
56
+ src = fp.read.gsub( /<\+\s*([\w\.\/\\\-]+)\s*\+>/ ) do
57
+ File.read( expand( $1 ) )
58
+ end
59
+ ::ERB.new( src, nil, nil, "_hobixout#{ rand( 9999999 ) }" )
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end