hobix 0.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/bin/hobix +90 -0
- data/lib/hobix/api.rb +91 -0
- data/lib/hobix/article.rb +22 -0
- data/lib/hobix/base.rb +477 -0
- data/lib/hobix/bixwik.rb +200 -0
- data/lib/hobix/commandline.rb +661 -0
- data/lib/hobix/comments.rb +99 -0
- data/lib/hobix/config.rb +39 -0
- data/lib/hobix/datamarsh.rb +110 -0
- data/lib/hobix/entry.rb +83 -0
- data/lib/hobix/facets/comments.rb +74 -0
- data/lib/hobix/facets/publisher.rb +314 -0
- data/lib/hobix/facets/trackbacks.rb +80 -0
- data/lib/hobix/linklist.rb +76 -0
- data/lib/hobix/out/atom.rb +92 -0
- data/lib/hobix/out/erb.rb +64 -0
- data/lib/hobix/out/okaynews.rb +55 -0
- data/lib/hobix/out/quick.rb +312 -0
- data/lib/hobix/out/rdf.rb +97 -0
- data/lib/hobix/out/redrum.rb +26 -0
- data/lib/hobix/out/rss.rb +115 -0
- data/lib/hobix/plugin/bloglines.rb +73 -0
- data/lib/hobix/plugin/calendar.rb +220 -0
- data/lib/hobix/plugin/flickr.rb +110 -0
- data/lib/hobix/plugin/recent_comments.rb +82 -0
- data/lib/hobix/plugin/sections.rb +91 -0
- data/lib/hobix/plugin/tags.rb +60 -0
- data/lib/hobix/publish/ping.rb +53 -0
- data/lib/hobix/publish/replicate.rb +283 -0
- data/lib/hobix/publisher.rb +18 -0
- data/lib/hobix/search/dictionary.rb +141 -0
- data/lib/hobix/search/porter_stemmer.rb +203 -0
- data/lib/hobix/search/simple.rb +209 -0
- data/lib/hobix/search/vector.rb +100 -0
- data/lib/hobix/storage/filesys.rb +398 -0
- data/lib/hobix/trackbacks.rb +94 -0
- data/lib/hobix/util/objedit.rb +193 -0
- data/lib/hobix/util/patcher.rb +155 -0
- data/lib/hobix/webapp/cli.rb +195 -0
- data/lib/hobix/webapp/htmlform.rb +107 -0
- data/lib/hobix/webapp/message.rb +177 -0
- data/lib/hobix/webapp/urigen.rb +141 -0
- data/lib/hobix/webapp/webrick-servlet.rb +90 -0
- data/lib/hobix/webapp.rb +723 -0
- data/lib/hobix/weblog.rb +860 -0
- data/lib/hobix.rb +223 -0
- metadata +87 -0
@@ -0,0 +1,99 @@
|
|
1
|
+
#
|
2
|
+
# = hobix/comments.rb
|
3
|
+
#
|
4
|
+
# Hobix command-line weblog system, API for comments.
|
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/facets/comments'
|
18
|
+
|
19
|
+
module Hobix
|
20
|
+
module Out
|
21
|
+
class Quick
|
22
|
+
append_def :head_tags_erb, %{
|
23
|
+
<meta http-equiv="Pragma" content="no-cache" />
|
24
|
+
<meta http-equiv="Expires" content="-1" />
|
25
|
+
<script type="text/javascript" src="<%= weblog.expand_path( '/js/prototype.js' ) %>"></script>
|
26
|
+
<script type="text/javascript">
|
27
|
+
function quickRedReference() {
|
28
|
+
window.open(
|
29
|
+
"http://hobix.com/textile/quick.html",
|
30
|
+
"redRef",
|
31
|
+
"height=600,width=550,channelmode=0,dependent=0," +
|
32
|
+
"directories=0,fullscreen=0,location=0,menubar=0," +
|
33
|
+
"resizable=0,scrollbars=1,status=1,toolbar=0"
|
34
|
+
);
|
35
|
+
}
|
36
|
+
</script>
|
37
|
+
}
|
38
|
+
|
39
|
+
append_def :entry_erb, %{
|
40
|
+
<% if entry and not defined? entries %>
|
41
|
+
<+ entry_comment +>
|
42
|
+
<+ entry_comment_form +>
|
43
|
+
<% end %>
|
44
|
+
}
|
45
|
+
|
46
|
+
def entry_comment_erb; %{
|
47
|
+
<% entry_id = entry.id %>
|
48
|
+
<a name="comments"></a>
|
49
|
+
<div id="comments">
|
50
|
+
<% comments = weblog.storage.load_attached( entry_id, "comments" ) rescue [] %>
|
51
|
+
<% comments.each do |comment| %>
|
52
|
+
<div class="entry">
|
53
|
+
<div class="entryAttrib">
|
54
|
+
<div class="entryAuthor"><h3><%= comment.author %></h3></div>
|
55
|
+
<div class="entryTime">said on <%= comment.created.strftime( "<nobr>%d %b %Y</nobr> at <nobr>%I:%M %p</nobr>" ) %></div>
|
56
|
+
</div>
|
57
|
+
<div class="entryContentOuter"><div class="entryContent"><%= comment.content.to_html %></div></div>
|
58
|
+
</div>
|
59
|
+
<% end %>
|
60
|
+
} end
|
61
|
+
|
62
|
+
def entry_comment_form_erb; %{
|
63
|
+
<div class="entry">
|
64
|
+
<form id="userComment" method="post" action="/control/comment/<%= entry_id %>">
|
65
|
+
<div class="entryAttrib">
|
66
|
+
<div class="entryAuthor"><input name="<%= Hobix::Facets::Comments.form_field 'author' %>" type="textbox" size="15" maxlength="50" /></div>
|
67
|
+
<div id="liveTime" class="entryTime">said on <nobr>DD Mon YYYY</nobr> <nobr>at HH:MM AM</nobr></div>
|
68
|
+
</div>
|
69
|
+
<div class="entryContentOuter"><div class="entryContent">
|
70
|
+
<textarea name="<%= Hobix::Facets::Comments.form_field 'content' %>" rows="6" cols="50"></textarea>
|
71
|
+
<p><input type="button" name="pleasePreview" value="preview"
|
72
|
+
onClick="new Ajax.Request('/control/preview', {parameters: Form.serialize('userComment'), onComplete: function(req) { $('textilePreview').innerHTML = req.responseText }})" />
|
73
|
+
<input type="submit" name="<%= Hobix::Facets::Comments.form_field 'submit' %>" value=">>" />
|
74
|
+
<small>* do <a href="javascript:quickRedReference();">fancy stuff</a> in your comment.</small>
|
75
|
+
</p>
|
76
|
+
<div id="textileWrap"><!-- <h4>PREVIEW PANE</h4> -->
|
77
|
+
<div id="textilePreview"></div>
|
78
|
+
</div>
|
79
|
+
</div>
|
80
|
+
</div></div>
|
81
|
+
|
82
|
+
</form>
|
83
|
+
</div>
|
84
|
+
} end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
class Comment < BaseContent
|
89
|
+
_! "Comment Information"
|
90
|
+
_ :author, :req => true, :edit_as => :text, :search => :prefix
|
91
|
+
_ :created, :edit_as => :datetime
|
92
|
+
_ :url, :edit_as => :text
|
93
|
+
_ :email, :edit_as => :text
|
94
|
+
_ :content, :edit_as => :textarea, :search => :fulltext, :text_processor => true
|
95
|
+
_ :ipaddress, :edit_as => :text
|
96
|
+
|
97
|
+
yaml_type "tag:hobix.com,2005:comment"
|
98
|
+
end
|
99
|
+
end
|
data/lib/hobix/config.rb
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
#
|
2
|
+
# = hobix/config.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
|
+
|
17
|
+
require 'yaml'
|
18
|
+
|
19
|
+
module Hobix
|
20
|
+
class Config
|
21
|
+
attr_accessor :weblogs, :username, :personal,
|
22
|
+
:post_upgen, :use_editor
|
23
|
+
def initialize
|
24
|
+
@username = ENV['USER'] unless @username
|
25
|
+
self
|
26
|
+
end
|
27
|
+
def Config.load( conf_file )
|
28
|
+
c = YAML::load( File::open( conf_file ) )
|
29
|
+
c.keys.each do |k|
|
30
|
+
if k =~ /\s/
|
31
|
+
k_ = k.gsub( /\s/, '_' )
|
32
|
+
c[k_] = c.delete( k )
|
33
|
+
end
|
34
|
+
end
|
35
|
+
c = YAML::object_maker( Hobix::Config, c )
|
36
|
+
c.initialize
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,110 @@
|
|
1
|
+
require 'dbm'
|
2
|
+
#
|
3
|
+
# Marshal + DBM = DataMarsh
|
4
|
+
# - Same interface as DBM class
|
5
|
+
#
|
6
|
+
module Hobix
|
7
|
+
|
8
|
+
class DataMarsh < ::DBM
|
9
|
+
VERSION = "0.1"
|
10
|
+
def []( key )
|
11
|
+
fetch( key )
|
12
|
+
end
|
13
|
+
def []=( key, val )
|
14
|
+
store( key, val )
|
15
|
+
end
|
16
|
+
def fetch( keystr, ifnone = nil )
|
17
|
+
begin
|
18
|
+
val = super( keystr )
|
19
|
+
return Marshal::load( val ) if String === val
|
20
|
+
rescue IndexError
|
21
|
+
end
|
22
|
+
if block_given?
|
23
|
+
yield keystr
|
24
|
+
else
|
25
|
+
ifnone
|
26
|
+
end
|
27
|
+
end
|
28
|
+
def index( keystr )
|
29
|
+
super( keystr.to_yaml )
|
30
|
+
end
|
31
|
+
def values_at( *keys )
|
32
|
+
keys.collect { |k| fetch( k ) }
|
33
|
+
end
|
34
|
+
def delete( key )
|
35
|
+
v = super( key )
|
36
|
+
if String === v
|
37
|
+
v = Marshal::load( v )
|
38
|
+
end
|
39
|
+
v
|
40
|
+
end
|
41
|
+
def delete_if
|
42
|
+
del_keys = keys.dup
|
43
|
+
del_keys.delete_if { |k| yield( k, fetch( k ) ) == false }
|
44
|
+
del_keys.each { |k| delete( k ) }
|
45
|
+
self
|
46
|
+
end
|
47
|
+
def reject
|
48
|
+
hsh = self.to_hash
|
49
|
+
hsh.reject { |k,v| yield k, v }
|
50
|
+
end
|
51
|
+
def each_pair
|
52
|
+
keys.each { |k| yield k, fetch( k ) }
|
53
|
+
self
|
54
|
+
end
|
55
|
+
def each_value
|
56
|
+
super { |v| yield Marshal::load( v ) }
|
57
|
+
self
|
58
|
+
end
|
59
|
+
def values
|
60
|
+
super.collect { |v| Marshal::load( v ) }
|
61
|
+
end
|
62
|
+
def has_value?( val )
|
63
|
+
each_value { |v| return true if v == val }
|
64
|
+
return false
|
65
|
+
end
|
66
|
+
def invert
|
67
|
+
h = {}
|
68
|
+
keys.each { |k| h[ self.fetch( k ) ] = k }
|
69
|
+
h
|
70
|
+
end
|
71
|
+
def replace( hsh )
|
72
|
+
clear
|
73
|
+
update( hsh )
|
74
|
+
end
|
75
|
+
def shift
|
76
|
+
a = super
|
77
|
+
a[1] = Marshal::load( a[1] ) if a
|
78
|
+
a
|
79
|
+
end
|
80
|
+
def select( *keys )
|
81
|
+
if block_given?
|
82
|
+
self.keys.collect { |k| v = self[k]; [k, v] if yield k, v }.compact
|
83
|
+
else
|
84
|
+
values_at( *keys )
|
85
|
+
end
|
86
|
+
end
|
87
|
+
def store( key, val )
|
88
|
+
super( key, val.to_yaml )
|
89
|
+
val
|
90
|
+
end
|
91
|
+
def update( hsh )
|
92
|
+
hsh.keys.each do |k|
|
93
|
+
self.store( k, hsh.fetch( k ) )
|
94
|
+
end
|
95
|
+
self
|
96
|
+
end
|
97
|
+
def to_a
|
98
|
+
a = []
|
99
|
+
keys.each { |k| a.push [ k, self.fetch( k ) ] }
|
100
|
+
a
|
101
|
+
end
|
102
|
+
def to_hash
|
103
|
+
h = {}
|
104
|
+
keys.each { |k| h[ k ] = self.fetch( k ) }
|
105
|
+
h
|
106
|
+
end
|
107
|
+
alias :each :each_pair
|
108
|
+
end
|
109
|
+
|
110
|
+
end
|
data/lib/hobix/entry.rb
ADDED
@@ -0,0 +1,83 @@
|
|
1
|
+
#
|
2
|
+
# = hobix/entry.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
|
+
|
17
|
+
module Hobix
|
18
|
+
# The Entry class stores complete data for an entry on the site. All
|
19
|
+
# entry extensions should behave like this class as well.
|
20
|
+
#
|
21
|
+
# == Properties
|
22
|
+
#
|
23
|
+
# At the very least, entry data should support the following
|
24
|
+
# accessors.
|
25
|
+
#
|
26
|
+
# id:: The id (or shortName) for this entry. Includes
|
27
|
+
# the basic entry path.
|
28
|
+
# link:: The full URL to this entry from the weblog.
|
29
|
+
# title:: The heading for this entry.
|
30
|
+
# tagline:: The subheading for this entry.
|
31
|
+
# tags:: A list of free-tagged categories.
|
32
|
+
# author:: The author's username.
|
33
|
+
# contributors:: An Array of contributors' usernames.
|
34
|
+
# modified:: A modification time.
|
35
|
+
# created:: The time the Entry was initially created.
|
36
|
+
# summary:: A brief description of this entry. Can be used
|
37
|
+
# for an abbreviated text of a long article.
|
38
|
+
# content:: The full text of the entry.
|
39
|
+
#
|
40
|
+
# The following read-only properties are also available:
|
41
|
+
#
|
42
|
+
# day_id:: The day ID can act as a path where other
|
43
|
+
# entry, posted on the same day, are stored.
|
44
|
+
# month_id:: A path for the month's entries.
|
45
|
+
# year_id:: A path for the year's entries.
|
46
|
+
class Entry < BaseEntry
|
47
|
+
|
48
|
+
_ :title, :req => true, :edit_as => :text, :search => :fulltext
|
49
|
+
_ :tagline, :edit_as => :text, :search => :fulltext, :text_processor => true
|
50
|
+
_ :summary, :edit_as => :textarea, :search => :fulltext, :text_processor => true
|
51
|
+
_ :content, :req => true, :edit_as => :textarea, :search => :fulltext, :text_processor => true
|
52
|
+
|
53
|
+
# Hobix::Entry objects are typed in YAML as !hobix.com,2004/entry
|
54
|
+
# objects. This type is virtually identical to !okay/news/feed objects,
|
55
|
+
# which are documented at http://yaml.kwiki.org/?OkayNews.
|
56
|
+
yaml_type "tag:okay.yaml.org,2002:news/entry#1.0"
|
57
|
+
yaml_type "tag:hobix.com,2004:entry"
|
58
|
+
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
module Hobix
|
63
|
+
# The EntryEnum class is mixed into an Array of entries just before
|
64
|
+
# passing on to a template. This Enumerator-like module provides some
|
65
|
+
# common iteration of entries.
|
66
|
+
module EntryEnum
|
67
|
+
# Calls the block with two arguments: (1) a Time object with
|
68
|
+
# the earliest date of an issued post for that day; (2) an
|
69
|
+
# Array of entries posted that day, in chronological order.
|
70
|
+
def each_day
|
71
|
+
last_day, day = nil, []
|
72
|
+
each do |e|
|
73
|
+
if last_day and last_day != e.day_id
|
74
|
+
yield day.first.created, day
|
75
|
+
day = []
|
76
|
+
end
|
77
|
+
last_day = e.day_id
|
78
|
+
day << e
|
79
|
+
end
|
80
|
+
yield day.first.created, day if last_day
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
#
|
2
|
+
# = hobix/facets/comments.rb
|
3
|
+
#
|
4
|
+
# Hobix command-line weblog system, API for comments.
|
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 Comments plugin adds a remote API for adding comments.
|
23
|
+
# Basically, to add comments to your site, ensure the plugin
|
24
|
+
# is loaded within your hobix.yaml `requires' list:
|
25
|
+
#
|
26
|
+
# requires:
|
27
|
+
# - hobix/facets/comments
|
28
|
+
#
|
29
|
+
class Comments < BaseFacet
|
30
|
+
def self.form_field( name ); "hobix_comment:#{ name }" end
|
31
|
+
def self.comment_fields; ['author', 'content']; end
|
32
|
+
def self.comment_class; Hobix::Comment 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 "comment"
|
42
|
+
# Create the comment entry
|
43
|
+
on_entry = @weblog.storage.load_entry( entry_id )
|
44
|
+
comment = Comments.comment_class.new do |c|
|
45
|
+
Comments.comment_fields.each do |cf|
|
46
|
+
getf = Comments.form_field cf
|
47
|
+
if app._POST[getf].to_s.empty?
|
48
|
+
app.puts "Missing field `#{ getf }'. Please back up and try again."
|
49
|
+
return true
|
50
|
+
end
|
51
|
+
c.method( "#{ cf }=" ).call( app._POST[getf] )
|
52
|
+
end
|
53
|
+
c.created = Time.now
|
54
|
+
c.ipaddress = app.remote_addr
|
55
|
+
end
|
56
|
+
|
57
|
+
# Save the comment, upgen
|
58
|
+
@weblog.storage.append_to_attachment( entry_id, 'comments', comment )
|
59
|
+
@weblog.regenerate :update
|
60
|
+
|
61
|
+
# Redirect
|
62
|
+
link = @weblog.output_entry_map[entry_id]
|
63
|
+
app.setup_redirection( 302, link[:page].link )
|
64
|
+
return true
|
65
|
+
when "preview"
|
66
|
+
app.puts RedCloth.new( app._POST[Comments.form_field('content')] ).to_html
|
67
|
+
return true
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
74
|
+
end
|