shinmun 0.2 → 0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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/assets/styles.css
ADDED
@@ -0,0 +1,91 @@
|
|
1
|
+
html, body, div, span, object, iframe, h1, h2, h3, h4, h5, h6, p,
|
2
|
+
blockquote, pre, a, abbr, acronym, address, del, dfn, img,
|
3
|
+
q, fieldset, form, label, legend, table,
|
4
|
+
caption, tbody, tfoot, thead, tr, th, td {
|
5
|
+
margin: 0;
|
6
|
+
padding: 0;
|
7
|
+
border: 0;
|
8
|
+
font-weight: inherit;
|
9
|
+
font-style: inherit;
|
10
|
+
font-size: 100%;
|
11
|
+
font-family: inherit;
|
12
|
+
vertical-align: baseline;
|
13
|
+
}
|
14
|
+
|
15
|
+
body {
|
16
|
+
line-height: 1.5;
|
17
|
+
background: #fff;
|
18
|
+
margin:0.5em 0;
|
19
|
+
font-size: 80%;
|
20
|
+
color: #222;
|
21
|
+
font-family: Arial, sans-serif;
|
22
|
+
}
|
23
|
+
|
24
|
+
p {
|
25
|
+
margin-bottom: 1em;
|
26
|
+
}
|
27
|
+
|
28
|
+
a {
|
29
|
+
color: #444;
|
30
|
+
}
|
31
|
+
|
32
|
+
a:visited {
|
33
|
+
color: #444;
|
34
|
+
}
|
35
|
+
|
36
|
+
h1 a, h2 a, h3 a, h4 a, h5 a, h6 a {
|
37
|
+
text-decoration: none;
|
38
|
+
}
|
39
|
+
|
40
|
+
h1 { font-size: 2em; line-height: 1; margin-top: 1em; margin-bottom: 1em; }
|
41
|
+
h2 { font-size: 1.5em; margin-top: 0.75em; margin-bottom: 0.75em; }
|
42
|
+
h3 { font-size: 1.3em; line-height: 1; margin-top: 1.7em; margin-bottom: 1em; }
|
43
|
+
h4 { font-size: 1.2em; line-height: 1.25; margin-top: 1.25em; margin-bottom: 1.25em; }
|
44
|
+
h5 { font-size: 1em; font-weight: bold; margin-bottom: 1.5em; }
|
45
|
+
h6 { font-size: 1em; font-weight: bold; }
|
46
|
+
|
47
|
+
hr {
|
48
|
+
height: 1px;
|
49
|
+
color: #ccc;
|
50
|
+
}
|
51
|
+
|
52
|
+
.container {
|
53
|
+
width: 600px;
|
54
|
+
margin: 0 auto;
|
55
|
+
}
|
56
|
+
|
57
|
+
.article {
|
58
|
+
}
|
59
|
+
|
60
|
+
.article h2 {
|
61
|
+
margin-top:0px;
|
62
|
+
}
|
63
|
+
|
64
|
+
.article .date {
|
65
|
+
color: #666;
|
66
|
+
}
|
67
|
+
|
68
|
+
.article .tags a {
|
69
|
+
color: #69c;
|
70
|
+
text-decoration: none;
|
71
|
+
}
|
72
|
+
|
73
|
+
.comments {
|
74
|
+
margin-bottom: 2em;
|
75
|
+
}
|
76
|
+
|
77
|
+
.comments .comment, .preview .comment {
|
78
|
+
margin-top: 2em;
|
79
|
+
border: 1px solid #ccc;
|
80
|
+
}
|
81
|
+
|
82
|
+
.comments .comment .top, .preview .comment .top {
|
83
|
+
background: #F0F0F0;
|
84
|
+
color: #333;
|
85
|
+
padding: 3px 5px;
|
86
|
+
}
|
87
|
+
|
88
|
+
.comments .comment .body, .preview .comment .body {
|
89
|
+
background: #F8F8F8;
|
90
|
+
padding: 3px 5px;
|
91
|
+
}
|
data/bin/shinmun
CHANGED
@@ -2,16 +2,33 @@
|
|
2
2
|
|
3
3
|
require 'shinmun'
|
4
4
|
|
5
|
-
|
5
|
+
ENV['RACK_ENV'] = 'production'
|
6
6
|
|
7
7
|
case ARGV[0]
|
8
|
-
when '
|
9
|
-
|
8
|
+
when 'init'
|
9
|
+
Shinmun::Blog.init ARGV[1]
|
10
10
|
|
11
|
-
when '
|
12
|
-
blog.
|
11
|
+
when 'post'
|
12
|
+
blog = Shinmun::Blog.new('.')
|
13
|
+
post = blog.create_post(:title => ARGV[1], :date => Date.today)
|
14
|
+
path = blog.post_file(post)
|
15
|
+
|
16
|
+
`git checkout master posts`
|
17
|
+
|
18
|
+
exec "#{ENV['EDITOR']} #{path}"
|
13
19
|
|
14
|
-
when '
|
15
|
-
blog.
|
20
|
+
when 'page'
|
21
|
+
blog = Shinmun::Blog.new('.')
|
22
|
+
post = blog.create_page(:title => ARGV[1])
|
23
|
+
path = blog.post_file(post)
|
16
24
|
|
25
|
+
`git checkout master pages`
|
26
|
+
|
27
|
+
exec "#{ENV['EDITOR']} #{path}"
|
28
|
+
|
29
|
+
else
|
30
|
+
puts "Usage:"
|
31
|
+
puts " shinmun init dir - creates a new blog"
|
32
|
+
puts " shinmun post 'Title of the post' - create a new post"
|
33
|
+
puts " shinmun page 'Title of the page' - create a new page"
|
17
34
|
end
|
data/config.ru
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'shinmun'
|
2
|
+
|
3
|
+
use Rack::Session::Cookie
|
4
|
+
use Rack::Reloader
|
5
|
+
|
6
|
+
blog = Shinmun::Blog.new(File.dirname(__FILE__))
|
7
|
+
|
8
|
+
blog.config = {
|
9
|
+
:language => 'en',
|
10
|
+
:title => "Blog Title",
|
11
|
+
:author => "The Author",
|
12
|
+
:categories => ["Ruby", "Javascript"],
|
13
|
+
:description => "Blog description"
|
14
|
+
}
|
15
|
+
|
16
|
+
run blog
|
data/lib/shinmun/blog.rb
CHANGED
@@ -1,319 +1,181 @@
|
|
1
1
|
module Shinmun
|
2
|
+
ROOT = File.expand_path(File.dirname(__FILE__) + '/../..')
|
2
3
|
|
3
|
-
class Blog
|
4
|
+
class Blog < Kontrol::Application
|
5
|
+
include Helpers
|
4
6
|
|
5
|
-
|
6
|
-
def self.config_reader(file, *names)
|
7
|
-
names.each do |name|
|
8
|
-
name = name.to_s
|
9
|
-
define_method(name) { @config[file][name] }
|
10
|
-
end
|
11
|
-
end
|
12
|
-
|
13
|
-
attr_reader :root, :posts, :pages, :aggregations
|
14
|
-
|
15
|
-
config_reader 'config/assets.yml', :javascript_files, :stylesheet_files, :base_path, :images_path, :javascripts_path, :stylesheets_path
|
16
|
-
config_reader 'config/blog.yml', :title, :description, :language, :author, :url, :repository
|
17
|
-
config_reader 'config/categories.yml', :categories
|
18
|
-
|
19
|
-
# Initialize the blog, load the config file and write the index files.
|
20
|
-
def initialize
|
21
|
-
@config = Cache.new do |file|
|
22
|
-
YAML.load(File.read(file))
|
23
|
-
end
|
24
|
-
|
25
|
-
@stylesheets = Cache.new
|
26
|
-
|
27
|
-
@templates = Cache.new do |file|
|
28
|
-
ERB.new(File.read(file))
|
29
|
-
end
|
30
|
-
|
31
|
-
@javascripts = Cache.new do |file|
|
32
|
-
script = File.read(file)
|
33
|
-
script = Packr.pack(script) if defined?(Packr)
|
34
|
-
"/* #{file} */\n #{script}\n"
|
35
|
-
end
|
36
|
-
|
37
|
-
@posts_cache = Cache.new do |file|
|
38
|
-
Post.new(:filename => file).load
|
39
|
-
end
|
40
|
-
|
41
|
-
@pages_cache = Cache.new do |file|
|
42
|
-
Post.new(:filename => file).load
|
43
|
-
end
|
44
|
-
|
45
|
-
Dir['pages/**/*'].each do |file|
|
46
|
-
@pages_cache.load(file) if File.file?(file) and file[-1, 1] != '~'
|
47
|
-
end
|
48
|
-
|
49
|
-
Dir['posts/**/*'].each do |file|
|
50
|
-
@posts_cache.load(file) if File.file?(file) and file[-1, 1] != '~'
|
51
|
-
end
|
52
|
-
|
53
|
-
@config.load('config/aggregations.yml')
|
54
|
-
@config.load('config/assets.yml')
|
55
|
-
@config.load('config/blog.yml')
|
56
|
-
@config.load('config/categories.yml')
|
7
|
+
attr_accessor :config, :store, :posts, :pages
|
57
8
|
|
58
|
-
|
59
|
-
|
60
|
-
load_aggregations
|
61
|
-
|
62
|
-
Thread.start do
|
63
|
-
sleep 300
|
64
|
-
load_aggregations
|
65
|
-
end
|
9
|
+
%w[ base_path title description language author categories ].each do |name|
|
10
|
+
define_method(name) { @config[name.to_sym] }
|
66
11
|
end
|
67
12
|
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
end
|
72
|
-
end
|
73
|
-
|
74
|
-
# Reload config, assets and posts.
|
75
|
-
def reload
|
76
|
-
if @config.dirty? || @templates.dirty?
|
77
|
-
@config.reload!
|
78
|
-
@templates.reload!
|
79
|
-
@posts_cache.reload!
|
80
|
-
@pages_cache.reload!
|
81
|
-
else
|
82
|
-
@config.reload_dirty!
|
83
|
-
@templates.reload_dirty!
|
84
|
-
@posts_cache.reload_dirty!
|
85
|
-
@pages_cache.reload_dirty!
|
86
|
-
end
|
87
|
-
|
88
|
-
@posts = @posts_cache.values.sort_by { |p| p.date }.reverse
|
89
|
-
@pages = @pages_cache.values
|
13
|
+
# Initialize the blog
|
14
|
+
def initialize(path)
|
15
|
+
super
|
90
16
|
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
17
|
+
@config = {}
|
18
|
+
@store = GitStore.new(path)
|
19
|
+
@store.handler['md'] = PostHandler.new
|
20
|
+
@store.handler['rhtml'] = ERBHandler.new
|
21
|
+
@store.handler['rxml'] = ERBHandler.new
|
95
22
|
end
|
96
23
|
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
end
|
24
|
+
def self.init(path)
|
25
|
+
path = File.expand_path(path)
|
26
|
+
Dir.mkdir(path)
|
101
27
|
|
102
|
-
|
103
|
-
|
104
|
-
|
28
|
+
FileUtils.cp_r "#{ROOT}/assets", path
|
29
|
+
FileUtils.cp_r "#{ROOT}/templates", path
|
30
|
+
FileUtils.cp "#{ROOT}/config.ru", path
|
105
31
|
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
for file in javascript_files
|
111
|
-
io << @javascripts["assets/#{javascripts_path}/#{file.strip}.js"] << "\n\n"
|
112
|
-
end
|
113
|
-
end
|
114
|
-
end
|
115
|
-
|
116
|
-
# Pack the stylesheets and write them to one file called 'all.css'.
|
117
|
-
def pack_stylesheets
|
118
|
-
@stylesheets.reload_dirty!
|
119
|
-
File.open("assets/#{stylesheets_path}/all.css", "wb") do |io|
|
120
|
-
for file in stylesheet_files
|
121
|
-
io << @stylesheets["assets/#{stylesheets_path}/#{file.strip}.css"] << "\n\n"
|
122
|
-
end
|
123
|
-
end
|
124
|
-
end
|
32
|
+
Dir.mkdir("#{path}/posts")
|
33
|
+
Dir.mkdir("#{path}/pages")
|
34
|
+
Dir.mkdir("#{path}/comments")
|
35
|
+
Dir.mkdir("#{path}/public")
|
125
36
|
|
126
|
-
|
127
|
-
def write_file(path, data)
|
128
|
-
FileUtils.mkdir_p("public/#{base_path}/#{File.dirname path}")
|
37
|
+
FileUtils.ln_s("../assets", "#{path}/public/assets")
|
129
38
|
|
130
|
-
|
131
|
-
|
132
|
-
|
39
|
+
Dir.chdir(path) do
|
40
|
+
`git init`
|
41
|
+
`git add .`
|
42
|
+
`git commit -m 'init'`
|
43
|
+
end
|
133
44
|
end
|
134
45
|
|
135
|
-
|
136
|
-
|
137
|
-
posts.select { |p| p.year == year and p.month == month }
|
46
|
+
def load_template(file)
|
47
|
+
store['templates/' + file]
|
138
48
|
end
|
139
49
|
|
140
|
-
|
141
|
-
|
142
|
-
name = category['name']
|
143
|
-
posts.select { |p| p.category == name }
|
50
|
+
def render(name, vars = {})
|
51
|
+
super(name, vars.merge(:blog => self))
|
144
52
|
end
|
145
53
|
|
146
|
-
|
147
|
-
|
148
|
-
return [] if tags.nil?
|
149
|
-
tags = tags.split(',').map { |t| t.strip } if tags.is_a?(String)
|
150
|
-
posts.select do |post|
|
151
|
-
tags.any? do |tag|
|
152
|
-
post.tags.to_s.include?(tag)
|
153
|
-
end
|
154
|
-
end
|
54
|
+
def pages
|
55
|
+
store.tree('pages').values.select { |v| Post === v }
|
155
56
|
end
|
156
57
|
|
157
|
-
|
158
|
-
|
159
|
-
posts.map { |p| [p.year, p.month] }.uniq.sort
|
58
|
+
def posts
|
59
|
+
store.tree('posts').values.select { |v| Post === v }.sort_by { |p| p.date.to_s }.reverse
|
160
60
|
end
|
161
61
|
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
name = urlify(title)
|
166
|
-
path = "#{date.year}/#{date.month}/#{name}.md"
|
167
|
-
|
168
|
-
if File.exist?(file)
|
169
|
-
raise "#{file} exists"
|
62
|
+
def call(env)
|
63
|
+
if ENV['RACK_ENV'] == 'production'
|
64
|
+
store.load if store.changed?
|
170
65
|
else
|
171
|
-
|
172
|
-
:title => title,
|
173
|
-
:date => date).save
|
66
|
+
store.load(true)
|
174
67
|
end
|
68
|
+
|
69
|
+
super
|
175
70
|
end
|
176
71
|
|
177
|
-
def
|
178
|
-
|
72
|
+
def url
|
73
|
+
"http://#{request.host}"
|
179
74
|
end
|
180
75
|
|
181
|
-
def
|
182
|
-
|
76
|
+
def symbolize_keys(hash)
|
77
|
+
hash.inject({}) do |h, (k, v)|
|
78
|
+
h[k.to_sym] = v
|
79
|
+
h
|
80
|
+
end
|
183
81
|
end
|
184
82
|
|
185
|
-
def
|
186
|
-
|
187
|
-
categories.find { |c| urlify(c['name']) == category }
|
83
|
+
def transaction(message, &block)
|
84
|
+
store.transaction(message, &block)
|
188
85
|
end
|
189
86
|
|
190
|
-
|
191
|
-
|
192
|
-
template = Template.new(@templates["templates/#{name}"], name)
|
193
|
-
template.set_variables(vars)
|
194
|
-
template.render
|
87
|
+
def post_file(post)
|
88
|
+
'posts' + post_path(post) + '.' + post.type
|
195
89
|
end
|
196
90
|
|
197
|
-
def
|
198
|
-
|
91
|
+
def page_file(post)
|
92
|
+
'pages' + page_path(post) + '.' + post.type
|
199
93
|
end
|
200
94
|
|
201
|
-
|
202
|
-
|
203
|
-
render_layout(vars.merge(:content => render_template(name, vars.merge(:blog => self))))
|
95
|
+
def comment_file(post)
|
96
|
+
'comments/' + post_path(post) + '.yml'
|
204
97
|
end
|
205
98
|
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
end
|
99
|
+
def create_post(attr)
|
100
|
+
post = Post.new(attr)
|
101
|
+
path = post_file(post)
|
210
102
|
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
end
|
103
|
+
transaction "create post `#{post.title}'" do
|
104
|
+
store[path] = post
|
105
|
+
end
|
215
106
|
|
216
|
-
|
217
|
-
def render_comments(comments)
|
218
|
-
render_template('comments.rhtml', :comments => comments)
|
107
|
+
post
|
219
108
|
end
|
220
109
|
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
:header => 'Home',
|
225
|
-
:posts => posts)
|
226
|
-
end
|
110
|
+
def create_page(attr)
|
111
|
+
post = Post.new(attr)
|
112
|
+
path = page_file(post)
|
227
113
|
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
render("category.rhtml",
|
232
|
-
:header => category['name'],
|
233
|
-
:category => category,
|
234
|
-
:posts => posts)
|
235
|
-
end
|
114
|
+
transaction "create page `#{post.title}'" do
|
115
|
+
store[path] = post
|
116
|
+
end
|
236
117
|
|
237
|
-
|
238
|
-
def render_month(year, month)
|
239
|
-
path = "#{year}/#{month}"
|
240
|
-
month_name = Date::MONTHNAMES[month]
|
241
|
-
posts = posts_for_month(year, month)
|
242
|
-
render("month.rhtml",
|
243
|
-
:header => "#{month_name} #{year}",
|
244
|
-
:year => year,
|
245
|
-
:month => month_name,
|
246
|
-
:posts => posts)
|
118
|
+
post
|
247
119
|
end
|
248
120
|
|
249
|
-
|
250
|
-
|
251
|
-
render_template("index.rxml",
|
252
|
-
:blog => self,
|
253
|
-
:posts => posts)
|
121
|
+
def comments_for(post)
|
122
|
+
store[comment_file post] || []
|
254
123
|
end
|
255
124
|
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
125
|
+
def create_comment(post, params)
|
126
|
+
path = comment_file(post)
|
127
|
+
comments = comments_for(post)
|
128
|
+
comment = Comment.new(params)
|
129
|
+
|
130
|
+
transaction "new comment for `#{post.title}'" do
|
131
|
+
store[path] = comments + [comment]
|
132
|
+
end
|
133
|
+
|
134
|
+
comment
|
262
135
|
end
|
263
136
|
|
264
|
-
def
|
265
|
-
|
137
|
+
def find_page(name)
|
138
|
+
pages.find { |p| p.name == name }
|
266
139
|
end
|
267
140
|
|
268
|
-
|
269
|
-
|
270
|
-
for page in pages
|
271
|
-
write_file("#{page.path}.html", render_page(page))
|
272
|
-
end
|
141
|
+
def find_post(year, month, name)
|
142
|
+
posts.find { |p| p.year == year and p.month == month and p.name == name }
|
273
143
|
end
|
274
144
|
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
145
|
+
def find_category(permalink)
|
146
|
+
name = categories.find { |name| urlify(name) == permalink }
|
147
|
+
|
148
|
+
{ :name => name,
|
149
|
+
:posts => posts.select { |p| p.category == name },
|
150
|
+
:permalink => permalink }
|
280
151
|
end
|
281
152
|
|
282
|
-
|
283
|
-
|
284
|
-
for year, month in months
|
285
|
-
write_file("#{year}/#{month}/index.html", render_month(year, month))
|
286
|
-
end
|
153
|
+
def recent_posts
|
154
|
+
posts[0, 20]
|
287
155
|
end
|
288
156
|
|
289
|
-
#
|
290
|
-
def
|
291
|
-
|
292
|
-
write_file("categories/#{urlify category['name']}.html", render_category(category))
|
293
|
-
end
|
157
|
+
# Return all posts for a given month.
|
158
|
+
def posts_for_month(year, month)
|
159
|
+
posts.select { |p| p.year == year and p.month == month }
|
294
160
|
end
|
295
161
|
|
296
|
-
#
|
297
|
-
def
|
298
|
-
|
299
|
-
|
300
|
-
|
162
|
+
# Return all posts with any of given tags.
|
163
|
+
def posts_with_tags(tags)
|
164
|
+
return [] if tags.nil? or tags.empty?
|
165
|
+
tags = tags.split(',').map { |t| t.strip } if tags.is_a?(String)
|
166
|
+
|
167
|
+
posts.select do |post|
|
168
|
+
tags.any? do |tag|
|
169
|
+
post.tag_list.include?(tag)
|
170
|
+
end
|
301
171
|
end
|
302
172
|
end
|
303
173
|
|
304
|
-
#
|
305
|
-
def
|
306
|
-
|
307
|
-
reload
|
308
|
-
|
309
|
-
write_index_page
|
310
|
-
write_pages
|
311
|
-
write_posts
|
312
|
-
write_archives
|
313
|
-
write_categories
|
314
|
-
write_feeds
|
174
|
+
# Return all archives as tuples of [year, month].
|
175
|
+
def archives
|
176
|
+
posts.map { |p| [p.year, p.month] }.uniq.sort
|
315
177
|
end
|
316
178
|
|
317
179
|
end
|
318
|
-
|
180
|
+
|
319
181
|
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
class BlueCloth
|
2
|
+
|
3
|
+
def transform_code_blocks( str, rs )
|
4
|
+
@log.debug " Transforming code blocks"
|
5
|
+
|
6
|
+
str.gsub(CodeBlockRegexp) {|block|
|
7
|
+
codeblock = $1
|
8
|
+
remainder = $2
|
9
|
+
|
10
|
+
# Generate the codeblock
|
11
|
+
if codeblock =~ /^(?:[ ]{4}|\t)@@(.*?)\n\n(.*)\n\n/m
|
12
|
+
"\n\n<pre class='highlight'>%s</pre>\n\n%s" %
|
13
|
+
[CodeRay.scan(outdent($2), $1).html(:css => :style, :line_numbers => :list).delete("\n"), remainder]
|
14
|
+
else
|
15
|
+
"\n\n<pre><code>%s\n</code></pre>\n\n%s" %
|
16
|
+
[encode_code(outdent(codeblock), rs).rstrip, remainder]
|
17
|
+
end
|
18
|
+
}
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
data/lib/shinmun/comment.rb
CHANGED
@@ -1,42 +1,15 @@
|
|
1
1
|
module Shinmun
|
2
2
|
|
3
3
|
class Comment
|
4
|
-
|
4
|
+
|
5
5
|
attr_accessor :time, :name, :email, :website, :text
|
6
6
|
|
7
7
|
def initialize(attributes)
|
8
8
|
for k, v in attributes
|
9
|
-
send
|
9
|
+
send("#{k}=", v) if respond_to?("#{k}=")
|
10
10
|
end
|
11
|
-
end
|
12
|
-
|
13
|
-
def self.read(path)
|
14
|
-
file = "comments/#{path}"
|
15
|
-
comments = []
|
16
11
|
|
17
|
-
|
18
|
-
File.open(file, "r") do |io|
|
19
|
-
io.flock(File::LOCK_SH)
|
20
|
-
YAML.each_document(io) do |comment|
|
21
|
-
comments << comment
|
22
|
-
end
|
23
|
-
io.flock(File::LOCK_UN)
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
comments
|
28
|
-
end
|
29
|
-
|
30
|
-
def self.write(path, comment)
|
31
|
-
file = "comments/#{path}"
|
32
|
-
|
33
|
-
FileUtils.mkdir_p(File.dirname(file))
|
34
|
-
|
35
|
-
File.open(file, "a") do |io|
|
36
|
-
io.flock(File::LOCK_EX)
|
37
|
-
io.puts(comment.to_yaml)
|
38
|
-
io.flock(File::LOCK_UN)
|
39
|
-
end
|
12
|
+
self.time ||= Time.now
|
40
13
|
end
|
41
14
|
|
42
15
|
end
|