shinmun 0.2 → 0.5
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +145 -210
- data/Rakefile +21 -53
- data/assets/print.css +76 -0
- data/assets/styles.css +91 -0
- data/bin/shinmun +24 -7
- data/config.ru +16 -0
- data/lib/shinmun/blog.rb +113 -251
- data/lib/shinmun/bluecloth_coderay.rb +21 -0
- data/lib/shinmun/comment.rb +3 -30
- data/lib/shinmun/handlers.rb +19 -0
- data/lib/shinmun/helpers.rb +46 -80
- data/lib/shinmun/post.rb +67 -98
- data/lib/shinmun/routes.rb +61 -0
- data/lib/shinmun.rb +8 -14
- data/templates/404.rhtml +4 -0
- data/templates/_comment_form.rhtml +21 -0
- data/templates/_comments.rhtml +11 -0
- data/templates/archive.rhtml +11 -0
- data/templates/category.rhtml +11 -0
- data/templates/category.rxml +20 -0
- data/templates/index.rhtml +11 -0
- data/templates/index.rxml +21 -0
- data/templates/layout.rhtml +44 -0
- data/templates/page.rhtml +5 -0
- data/templates/post.rhtml +33 -0
- data/test/blog_spec.rb +156 -0
- data/test/post_spec.rb +32 -0
- metadata +51 -16
- data/.gitignore +0 -3
- data/LICENSE +0 -18
- data/lib/shinmun/admin_controller.rb +0 -161
- data/lib/shinmun/aggregations/delicious.rb +0 -57
- data/lib/shinmun/aggregations/flickr.rb +0 -81
- data/lib/shinmun/cache.rb +0 -59
- data/lib/shinmun/controller.rb +0 -135
- data/lib/shinmun/template.rb +0 -39
data/lib/shinmun/helpers.rb
CHANGED
@@ -2,85 +2,6 @@ module Shinmun
|
|
2
2
|
|
3
3
|
module Helpers
|
4
4
|
|
5
|
-
# Render a hash as attributes for a HTML tag.
|
6
|
-
def attributes(attributes)
|
7
|
-
attributes.map { |k, v| %Q{#{k}="#{v}"} }.join(' ')
|
8
|
-
end
|
9
|
-
|
10
|
-
# Render a HTML tag with given name.
|
11
|
-
# The last argument specifies the attributes of the tag.
|
12
|
-
# The second argument may be the content of the tag.
|
13
|
-
def tag(name, *args)
|
14
|
-
text, attributes = args.first.is_a?(Hash) ? [nil, args.first] : args
|
15
|
-
"<#{name} #{attributes(attributes)}>#{text}</#{name}>"
|
16
|
-
end
|
17
|
-
|
18
|
-
# Render stylesheet link tag
|
19
|
-
def stylesheet_link_tag(*names)
|
20
|
-
options = names.last.is_a?(Hash) ? names.pop : {}
|
21
|
-
options[:media] ||= 'screen'
|
22
|
-
names.map { |name|
|
23
|
-
mtime = File.mtime("assets/#{blog.stylesheets_path}/#{name}.css").to_i
|
24
|
-
path = "/#{blog.stylesheets_path}/#{name}.css?#{mtime}"
|
25
|
-
tag :link, :href => path, :rel => 'stylesheet', :media => options[:media]
|
26
|
-
}.join("\n")
|
27
|
-
end
|
28
|
-
|
29
|
-
# Render javascript tag
|
30
|
-
def javascript_tag(*names)
|
31
|
-
names.map { |name|
|
32
|
-
mtime = File.mtime("assets/#{blog.javascripts_path}/#{name}.js").to_i
|
33
|
-
path = "/#{blog.javascripts_path}/#{name}.js?#{mtime}"
|
34
|
-
tag :script, :src => path, :type => 'text/javascript'
|
35
|
-
}.join("\n")
|
36
|
-
end
|
37
|
-
|
38
|
-
# Render an image tag
|
39
|
-
def image_tag(file, options = {})
|
40
|
-
mtime = File.mtime("assets/#{blog.images_path}/#{file}").to_i
|
41
|
-
path = "/#{blog.images_path}/#{file}?#{mtime}"
|
42
|
-
tag :img, options.merge(:src => path)
|
43
|
-
end
|
44
|
-
|
45
|
-
# Render a link
|
46
|
-
def link_to(text, path, options = {})
|
47
|
-
tag :a, text, options.merge(:href => path)
|
48
|
-
end
|
49
|
-
|
50
|
-
# Render a link to a post
|
51
|
-
def post_link(post)
|
52
|
-
link_to post.title, "#{blog.base_path}/#{post.path}.html"
|
53
|
-
end
|
54
|
-
|
55
|
-
# Render a link to an archive page.
|
56
|
-
def archive_link(year, month)
|
57
|
-
link_to "#{Date::MONTHNAMES[month]} #{year}", "#{blog.base_path}/#{year}/#{month}/index.html"
|
58
|
-
end
|
59
|
-
|
60
|
-
# Render a date or time in a nice human readable format.
|
61
|
-
def date(time)
|
62
|
-
"%s %d, %d" % [Date::MONTHNAMES[time.month], time.day, time.year]
|
63
|
-
end
|
64
|
-
|
65
|
-
# Render a date or time in rfc822 format. This will be used for rss rendering.
|
66
|
-
def rfc822(time)
|
67
|
-
time.strftime("%a, %d %b %Y %H:%M:%S %z")
|
68
|
-
end
|
69
|
-
|
70
|
-
def markdown(text, *args)
|
71
|
-
BlueCloth.new(text, *args).to_html
|
72
|
-
rescue => e
|
73
|
-
"#{text}<br/><br/><strong style='color:red'>#{e.message}</strong>"
|
74
|
-
end
|
75
|
-
|
76
|
-
def strip_tags(str)
|
77
|
-
str.gsub(/<\/?[^>]*>/, "")
|
78
|
-
end
|
79
|
-
|
80
|
-
def urlify(string)
|
81
|
-
string.downcase.gsub(/[ -]+/, '-').gsub(/[^-a-z0-9_]+/, '')
|
82
|
-
end
|
83
|
-
|
84
5
|
# taken form ActionView::Helpers
|
85
6
|
def distance_of_time_in_words(from_time, to_time = 0, include_seconds = false)
|
86
7
|
from_time = from_time.to_time if from_time.respond_to?(:to_time)
|
@@ -111,6 +32,51 @@ module Shinmun
|
|
111
32
|
else "over #{(distance_in_minutes / 525600).round} years"
|
112
33
|
end
|
113
34
|
end
|
35
|
+
|
36
|
+
def post_path(post)
|
37
|
+
"#{base_path}/#{post.year}/#{post.month}/#{post.name}"
|
38
|
+
end
|
39
|
+
|
40
|
+
def archive_path(year, month)
|
41
|
+
"#{base_path}/#{year}/#{month}"
|
42
|
+
end
|
43
|
+
|
44
|
+
# Render a link to a post
|
45
|
+
def post_link(post)
|
46
|
+
link_to post.title, post_path(post)
|
47
|
+
end
|
48
|
+
|
49
|
+
# Render a link to an archive page.
|
50
|
+
def archive_link(year, month)
|
51
|
+
link_to "#{Date::MONTHNAMES[month]} #{year}", archive_path(year, month)
|
52
|
+
end
|
53
|
+
|
54
|
+
# Render a date or time in a nice human readable format.
|
55
|
+
def human_date(time)
|
56
|
+
"%s %d, %d" % [Date::MONTHNAMES[time.month], time.day, time.year]
|
57
|
+
end
|
58
|
+
|
59
|
+
# Render a date or time in rfc822 format.
|
60
|
+
def rfc822(time)
|
61
|
+
time.strftime("%a, %d %b %Y %H:%M:%S %z")
|
62
|
+
end
|
63
|
+
|
64
|
+
# Render a link for the navigation bar. If the text of the link
|
65
|
+
# matches the @header variable, the css class will be set to acitve.
|
66
|
+
def navi_link(text, path)
|
67
|
+
link_to text, path, :class => (request.path_info == path) ? 'active' : nil
|
68
|
+
end
|
69
|
+
|
70
|
+
def html_escape(s)
|
71
|
+
s.to_s.gsub(/>/, '>').gsub(/</n, '<')
|
72
|
+
end
|
73
|
+
|
74
|
+
def diff_line_class(line)
|
75
|
+
case line[0, 1]
|
76
|
+
when '+' then 'added'
|
77
|
+
when '-' then 'deleted'
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
114
81
|
end
|
115
|
-
|
116
82
|
end
|
data/lib/shinmun/post.rb
CHANGED
@@ -7,35 +7,50 @@ module Shinmun
|
|
7
7
|
# ---
|
8
8
|
# category: Ruby
|
9
9
|
# date: 2008-09-05
|
10
|
-
#
|
11
|
-
#
|
12
|
-
# =============================
|
13
|
-
#
|
10
|
+
# title: BlueCloth, a Markdown library
|
11
|
+
# ---
|
14
12
|
# This is the summary, which is by definition the first paragraph of the
|
15
13
|
# article. The summary shows up in list views and rss feeds.
|
16
14
|
#
|
17
15
|
class Post
|
18
16
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
name = name.to_s
|
23
|
-
define_method(name) { @head[name] }
|
24
|
-
define_method("#{name}=") {|v| @head[name] = v }
|
25
|
-
end
|
17
|
+
%w[title author date category tags].each do |name|
|
18
|
+
define_method(name) { head[name] }
|
19
|
+
define_method("#{name}=") {|v| head[name] = v }
|
26
20
|
end
|
27
21
|
|
28
|
-
attr_accessor :
|
29
|
-
head_accessor :author, :date, :category, :tags, :languages, :header
|
22
|
+
attr_accessor :dirname, :name, :type, :src, :head, :body, :summary, :body_html, :tag_list
|
30
23
|
|
31
24
|
# Initialize empty post and set specified attributes.
|
32
25
|
def initialize(attributes={})
|
33
26
|
@head = {}
|
34
27
|
@body = ''
|
35
28
|
|
36
|
-
|
29
|
+
attributes.each do |k, v|
|
37
30
|
send "#{k}=", v
|
38
31
|
end
|
32
|
+
|
33
|
+
@type ||= 'md'
|
34
|
+
|
35
|
+
parse(src) if src
|
36
|
+
|
37
|
+
raise "post without a title" if title.nil?
|
38
|
+
|
39
|
+
@name ||= title.downcase.gsub(/[ -]+/, '-').gsub(/[^-a-z0-9_]+/, '')
|
40
|
+
@dirname = date ? "posts/#{year}/#{month}" : 'pages'
|
41
|
+
end
|
42
|
+
|
43
|
+
def method_missing(id, *args)
|
44
|
+
key = id.to_s
|
45
|
+
if @head.has_key?(key)
|
46
|
+
@head[key]
|
47
|
+
else
|
48
|
+
raise NoMethodError, "undefined method `#{id}' for #{self}", caller(1)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def date=(date)
|
53
|
+
@head['date'] = String === date ? Date.parse(date) : date
|
39
54
|
end
|
40
55
|
|
41
56
|
# Shortcut for year of date
|
@@ -46,111 +61,51 @@ module Shinmun
|
|
46
61
|
# Shortcut for month of date
|
47
62
|
def month
|
48
63
|
date.month
|
49
|
-
end
|
64
|
+
end
|
50
65
|
|
51
66
|
def filename
|
52
|
-
"#{
|
67
|
+
"#{name}.#{type}"
|
53
68
|
end
|
54
69
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
70
|
+
def filename=(filename)
|
71
|
+
self.name, self.type = filename.split('.')
|
72
|
+
end
|
73
|
+
|
74
|
+
def path
|
75
|
+
dirname.to_s.empty? ? filename : "#{dirname}/#{filename}"
|
76
|
+
end
|
77
|
+
|
78
|
+
def path=(path)
|
79
|
+
list = path.split('/')
|
80
|
+
self.dirname = list[0..-2].join('/')
|
81
|
+
self.filename = list[-1]
|
64
82
|
end
|
65
83
|
|
66
84
|
# Split up the source into header and body. Load the header as
|
67
|
-
# yaml document.
|
85
|
+
# yaml document.
|
68
86
|
def parse(src)
|
69
|
-
|
70
|
-
if src =~ /---.*?\n(.*?)\n\n(.*)/m
|
87
|
+
if src =~ /\A---(.*?)---(.*)/m
|
71
88
|
@head = YAML.load($1)
|
72
89
|
@body = $2
|
73
90
|
else
|
74
|
-
|
91
|
+
raise ArgumentError, "yaml header not found in src"
|
75
92
|
end
|
76
93
|
|
77
|
-
@
|
78
|
-
@body_html = transform(body, type)
|
94
|
+
@body_html = transform(@body)
|
79
95
|
@summary = body_html.split("\n\n")[0]
|
96
|
+
@tag_list = tags.to_s.split(",").map { |s| s.strip }
|
97
|
+
@dirname = date ? "posts/#{year}/#{month}" : 'pages'
|
80
98
|
|
81
99
|
self
|
82
100
|
end
|
83
101
|
|
84
|
-
#
|
85
|
-
def parse_title
|
86
|
-
lines = body.split("\n")
|
87
|
-
|
88
|
-
case type
|
89
|
-
when 'md'
|
90
|
-
@title = lines.shift.sub(/(^#+|#+$)/,'').strip
|
91
|
-
lines.shift if lines.first.match(/^(=|-)+$/)
|
92
|
-
|
93
|
-
when 'html'
|
94
|
-
@title = lines.shift.sub(/(<h1>|\<\/h1>)/,'').strip
|
95
|
-
|
96
|
-
when 'tt'
|
97
|
-
@title = lines.shift.sub(/(^h1.)/,'').strip
|
98
|
-
end
|
99
|
-
|
100
|
-
@body = lines.join("\n")
|
101
|
-
end
|
102
|
-
|
103
|
-
# Convert to yaml for caching.
|
104
|
-
def to_yaml
|
105
|
-
head.merge('author' => author,
|
106
|
-
'path' => path,
|
107
|
-
'type' => type,
|
108
|
-
'title' => title,
|
109
|
-
'summary' => summary,
|
110
|
-
'body_html' => body_html).to_yaml
|
111
|
-
end
|
112
|
-
|
113
|
-
# Convert to string representation, used to create new posts.
|
102
|
+
# Convert to string representation
|
114
103
|
def dump
|
115
|
-
head
|
116
|
-
body = self.body.dup
|
117
|
-
|
118
|
-
if type == 'md'
|
119
|
-
body = title + "\n" + ("=" * title.size) + "\n\n" + body
|
120
|
-
end
|
121
|
-
|
122
|
-
head.each do |k, v|
|
123
|
-
head.delete(k) if v.nil? || v.empty?
|
124
|
-
end
|
125
|
-
|
126
|
-
if head.empty?
|
127
|
-
body
|
128
|
-
else
|
129
|
-
head.to_yaml + "\n\n" + body
|
130
|
-
end
|
104
|
+
head.to_yaml + "---" + body
|
131
105
|
end
|
132
106
|
|
133
|
-
|
134
|
-
|
135
|
-
end
|
136
|
-
|
137
|
-
def save
|
138
|
-
FileUtils.mkdir_p(File.dirname(filename))
|
139
|
-
File.open(filename, "w") { |io| io << dump }
|
140
|
-
self
|
141
|
-
end
|
142
|
-
|
143
|
-
# Variables used for templates.
|
144
|
-
def variables
|
145
|
-
head.merge(:author => author,
|
146
|
-
:path => path,
|
147
|
-
:title => title,
|
148
|
-
:body => body_html)
|
149
|
-
end
|
150
|
-
|
151
|
-
# Transform the body of this post according to given type.
|
152
|
-
# Defaults to Markdown.
|
153
|
-
def transform(src, type)
|
107
|
+
# Transform the body of this post. Defaults to Markdown.
|
108
|
+
def transform(src)
|
154
109
|
case type
|
155
110
|
when 'html'
|
156
111
|
RubyPants.new(src).to_html
|
@@ -161,6 +116,20 @@ module Shinmun
|
|
161
116
|
end
|
162
117
|
end
|
163
118
|
|
119
|
+
def eql?(obj)
|
120
|
+
self == obj
|
121
|
+
end
|
122
|
+
|
123
|
+
def ==(obj)
|
124
|
+
if Post === obj
|
125
|
+
if date
|
126
|
+
year == obj.year and month == obj.month and name == obj.name
|
127
|
+
else
|
128
|
+
name == obj.name
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
164
133
|
end
|
165
134
|
|
166
135
|
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
Shinmun::Blog.map do
|
2
|
+
|
3
|
+
category_feed '/categories/(.*)\.rss' do |category|
|
4
|
+
render 'category.rxml', find_category(category).merge(:layout => false)
|
5
|
+
end
|
6
|
+
|
7
|
+
category '/categories/(.*)' do |category|
|
8
|
+
render 'category.rhtml', find_category(category)
|
9
|
+
end
|
10
|
+
|
11
|
+
tag '/tags/(.*)' do |tag|
|
12
|
+
render 'category.rhtml', :name => "Tag: #{tag}", :posts => posts_with_tags(tag)
|
13
|
+
end
|
14
|
+
|
15
|
+
comments '/(\d+)/(\d+)/(.*)/comments' do |year, month, name|
|
16
|
+
post = find_post(year.to_i, month.to_i, name) or raise "post not found #{request.path_info}"
|
17
|
+
|
18
|
+
if params['preview']
|
19
|
+
comments = comments_for(post).push(Shinmun::Comment.new(params))
|
20
|
+
render 'post.rhtml', :post => post, :comments => comments
|
21
|
+
else
|
22
|
+
create_comment(post, params)
|
23
|
+
redirect post_path(post)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
post '/(\d+)/(\d+)/(.*)' do |year, month, name|
|
28
|
+
if post = find_post(year.to_i, month.to_i, name)
|
29
|
+
render 'post.rhtml', :post => post, :comments => comments_for(post)
|
30
|
+
else
|
31
|
+
render '404.rhtml', :path => request.path_info
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
archive '/(\d+)/(\d+)' do |year, month|
|
36
|
+
render 'archive.rhtml', :year => year.to_i, :month => month.to_i, :posts => posts_for_month(year.to_i, month.to_i)
|
37
|
+
end
|
38
|
+
|
39
|
+
feed '/index\.rss' do
|
40
|
+
render 'index.rxml', :layout => false
|
41
|
+
end
|
42
|
+
|
43
|
+
index '/$' do
|
44
|
+
render 'index.rhtml'
|
45
|
+
end
|
46
|
+
|
47
|
+
page '/(.*)' do |path|
|
48
|
+
path = path.gsub('..', '')
|
49
|
+
page = find_page(path)
|
50
|
+
|
51
|
+
if page
|
52
|
+
render 'page.rhtml', :page => page
|
53
|
+
|
54
|
+
elsif file = store[path]
|
55
|
+
text file
|
56
|
+
else
|
57
|
+
render '404.rhtml', :path => path
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
data/lib/shinmun.rb
CHANGED
@@ -1,23 +1,17 @@
|
|
1
1
|
require 'rubygems'
|
2
2
|
require 'fileutils'
|
3
|
-
require 'erb'
|
4
|
-
require 'yaml'
|
5
|
-
require 'time'
|
6
|
-
|
7
3
|
require 'bluecloth'
|
8
4
|
require 'rubypants'
|
5
|
+
require 'coderay'
|
6
|
+
require 'kontrol'
|
7
|
+
require 'git_store'
|
9
8
|
|
10
9
|
begin; require 'redcloth'; rescue LoadError; end
|
11
|
-
begin; require 'packr'; rescue LoadError; end
|
12
10
|
|
13
|
-
require 'shinmun/
|
14
|
-
require 'shinmun/post'
|
15
|
-
require 'shinmun/comment'
|
16
|
-
require 'shinmun/template'
|
11
|
+
require 'shinmun/bluecloth_coderay'
|
17
12
|
require 'shinmun/helpers'
|
13
|
+
require 'shinmun/handlers'
|
18
14
|
require 'shinmun/blog'
|
19
|
-
|
20
|
-
require 'shinmun/
|
21
|
-
require 'shinmun/
|
22
|
-
require 'shinmun/aggregations/flickr'
|
23
|
-
require 'shinmun/aggregations/fortythree'
|
15
|
+
require 'shinmun/routes'
|
16
|
+
require 'shinmun/post'
|
17
|
+
require 'shinmun/comment'
|
data/templates/404.rhtml
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
<div class="comment-form">
|
2
|
+
<form action="<%= post_path @post %>/comments" method="POST">
|
3
|
+
<p>
|
4
|
+
<label>Name</label><br/>
|
5
|
+
<input type="text" name="name" size="40" value="<%= @params['name'] %>"/>
|
6
|
+
</p>
|
7
|
+
<p>
|
8
|
+
<label>Website</label><br/>
|
9
|
+
<input type="text" name="website" size="40" value="<%= @params['website'] %>"/>
|
10
|
+
</p>
|
11
|
+
<p>
|
12
|
+
<label>Comment</label><br/>
|
13
|
+
<textarea name="text" cols="60" rows="10"><%= @params['text'] %></textarea>
|
14
|
+
</p>
|
15
|
+
<p>
|
16
|
+
<input type="submit" value="Post comment"/>
|
17
|
+
<input type="checkbox" name="preview" value="1"/>
|
18
|
+
Preview
|
19
|
+
</p>
|
20
|
+
</form>
|
21
|
+
</div>
|
@@ -0,0 +1,11 @@
|
|
1
|
+
<% for comment in @comments %>
|
2
|
+
<div class="comment">
|
3
|
+
<div class="top">
|
4
|
+
<%= comment.website.to_s.empty? ? comment.name : link_to(comment.name, comment.website) %> said
|
5
|
+
<%= distance_of_time_in_words(comment.time, Time.now, true) %> ago:
|
6
|
+
</div>
|
7
|
+
<div class="body">
|
8
|
+
<%= markdown(comment.text, :filter_html, :filter_styles) %>
|
9
|
+
</div>
|
10
|
+
</div>
|
11
|
+
<% end %>
|
@@ -0,0 +1,11 @@
|
|
1
|
+
<h1><%= "#{Date::MONTHNAMES[@month]} #{@year}" %></h1>
|
2
|
+
|
3
|
+
<div class="articles">
|
4
|
+
<% for post in @blog.posts_for_month(@year, @month) %>
|
5
|
+
<div class="article">
|
6
|
+
<div class="date"><%= human_date post.date %></div>
|
7
|
+
<h2><%= post_link post %></h2>
|
8
|
+
<%= post.summary %>
|
9
|
+
</div>
|
10
|
+
<% end %>
|
11
|
+
</div>
|
@@ -0,0 +1,20 @@
|
|
1
|
+
<?xml version="1.0" encoding="utf-8"?>
|
2
|
+
<rss version="2.0">
|
3
|
+
<channel>
|
4
|
+
<title><%= @name %></title>
|
5
|
+
<link><%= @blog.url %>/categories/<%= urlify @name %></link>
|
6
|
+
<language><%= @blog.language %></language>
|
7
|
+
<copyright><%= @blog.author %></copyright>
|
8
|
+
<pubDate><%= rfc822 Time.now %></pubDate>
|
9
|
+
<% for post in @posts[0, 20] %>
|
10
|
+
<item>
|
11
|
+
<title><%= post.title %></title>
|
12
|
+
<category><%= post.category %></category>
|
13
|
+
<description><%= strip_tags post.summary %></description>
|
14
|
+
<author><%= @author || @blog.author %></author>
|
15
|
+
<link><%= @blog.url %><%= post_path post %></link>
|
16
|
+
<pubDate><%= rfc822 post.date %></pubDate>
|
17
|
+
</item>
|
18
|
+
<% end %>
|
19
|
+
</channel>
|
20
|
+
</rss>
|
@@ -0,0 +1,21 @@
|
|
1
|
+
<?xml version="1.0" encoding="utf-8"?>
|
2
|
+
<rss version="2.0">
|
3
|
+
<channel>
|
4
|
+
<title><%= @blog.title %></title>
|
5
|
+
<link><%= @blog.url %></link>
|
6
|
+
<description><%= @blog.description %></description>
|
7
|
+
<language><%= @blog.language %></language>
|
8
|
+
<copyright><%= @blog.author %></copyright>
|
9
|
+
<pubDate><%= rfc822 Time.now %></pubDate>
|
10
|
+
<% for post in @blog.recent_posts %>
|
11
|
+
<item>
|
12
|
+
<title><%= post.title %></title>
|
13
|
+
<category><%= post.category %></category>
|
14
|
+
<description><%= strip_tags post.summary %></description>
|
15
|
+
<author><%= @author || @blog.author %></author>
|
16
|
+
<link><%= @blog.url %><%= post_path post %></link>
|
17
|
+
<pubDate><%= rfc822 post.date %></pubDate>
|
18
|
+
</item>
|
19
|
+
<% end %>
|
20
|
+
</channel>
|
21
|
+
</rss>
|
@@ -0,0 +1,44 @@
|
|
1
|
+
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
2
|
+
<html xmlns="http://www.w3.org/1999/xhtml">
|
3
|
+
<head>
|
4
|
+
<title><%= @blog.title %></title>
|
5
|
+
<meta http-equiv="Content-Language" content="English" />
|
6
|
+
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
7
|
+
<link rel="alternate" type="application/rss+xml" title="RSS" href="/index.rss" />
|
8
|
+
<link rel="stylesheet" media="screen" type="text/css" href="/assets/styles.css" />
|
9
|
+
<link rel="stylesheet" media="print" type="text/css" href="/assets/print.css" />
|
10
|
+
</head>
|
11
|
+
<body>
|
12
|
+
<div class="container">
|
13
|
+
<h3><a href="/"><%= @blog.title %></a> - <%= @blog.description %></h3>
|
14
|
+
|
15
|
+
<div class="menu">
|
16
|
+
<%= link_to 'Home', '/' %> -
|
17
|
+
<%= link_to 'About', '/about' %> -
|
18
|
+
<%= link_to 'Subscribe RSS', '/index.rss' %>
|
19
|
+
</div>
|
20
|
+
|
21
|
+
<%= @content %>
|
22
|
+
|
23
|
+
<hr/>
|
24
|
+
|
25
|
+
<p>
|
26
|
+
<h4>Categories</h4>
|
27
|
+
<ul>
|
28
|
+
<li><%= link_to 'Ruby', '/categories/ruby' %></li>
|
29
|
+
<li><%= link_to 'Javascript', '/categories/javascript' %></li>
|
30
|
+
</ul>
|
31
|
+
</p>
|
32
|
+
|
33
|
+
<p>
|
34
|
+
<h4>Archive</h4>
|
35
|
+
<ul>
|
36
|
+
<% for year, month in @blog.archives %>
|
37
|
+
<li><%= archive_link year, month %></li>
|
38
|
+
<% end %>
|
39
|
+
</ul>
|
40
|
+
</p>
|
41
|
+
|
42
|
+
</div>
|
43
|
+
</body>
|
44
|
+
</html>
|
@@ -0,0 +1,33 @@
|
|
1
|
+
<div class="article">
|
2
|
+
|
3
|
+
<h1><%= @post.title %></h1>
|
4
|
+
|
5
|
+
<div class="date">
|
6
|
+
<%= human_date @post.date %>
|
7
|
+
</div>
|
8
|
+
|
9
|
+
<%= @post.body_html %>
|
10
|
+
|
11
|
+
<p>
|
12
|
+
<% if @post.category %>
|
13
|
+
Posted in category <%= link_to @post.category, "/categories/#{urlify @post.category}" %>.
|
14
|
+
<% end %>
|
15
|
+
|
16
|
+
<% unless @post.tag_list.empty? %>
|
17
|
+
Tagged with <%= @post.tag_list.map {|tag| link_to tag, "/tags/#{tag}" }.join(', ') %>.
|
18
|
+
<% end %>
|
19
|
+
</p>
|
20
|
+
|
21
|
+
<% if @comments %>
|
22
|
+
<h2>Comments</h2>
|
23
|
+
|
24
|
+
<div class="comments">
|
25
|
+
<%= render '_comments.rhtml', :comments => @comments %>
|
26
|
+
</div>
|
27
|
+
<% end %>
|
28
|
+
|
29
|
+
<h2>Leave a comment</h2>
|
30
|
+
|
31
|
+
<%= render '_comment_form.rhtml', :post => @post %>
|
32
|
+
|
33
|
+
</div>
|