mamemose 0.1.4 → 0.2.0
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 +4 -0
- data/lib/mamemose.rb +163 -111
- data/lib/mamemose/version.rb +1 -1
- metadata +2 -2
data/README.md
CHANGED
@@ -85,6 +85,10 @@ http://localhost:PORT/
|
|
85
85
|
- ポート。 http://localhost:PORT/ にアクセス。デフォルトは 20000
|
86
86
|
- `MARKDOWN_PATTERN`
|
87
87
|
- Markdown ドキュメントと見なすファイルパターンを正規表現で。デフォルトは `/\.(md|markdown)$/`
|
88
|
+
- `INDEX_PATTERN`
|
89
|
+
- 一覧ページ表示時に自動的に読み込むファイルパターンを正規表現で。
|
90
|
+
これにマッチするファイルは1つのディレクトリに複数置かないほうがいいです。
|
91
|
+
デフォルトは `/^README/`
|
88
92
|
- `RECENT_NUM`
|
89
93
|
- 「最近更新したファイル」を表示する数。デフォルトは 10
|
90
94
|
- `RECENT_PATTERN`
|
data/lib/mamemose.rb
CHANGED
@@ -18,6 +18,7 @@ IGNORE_FILES = ['.DS_Store','.AppleDouble','.LSOverride','Icon',/^\./,/~$/,
|
|
18
18
|
'.Spotlight-V100','.Trashes','Thumbs.db','ehthumbs.db',
|
19
19
|
'Desktop.ini','$RECYCLE.BIN',/^#/,'MathJax','syntaxhighlighter'] if !defined?(IGNORE_FILES)
|
20
20
|
MARKDOWN_PATTERN = /\.(md|markdown)$/ if !defined?(MARKDOWN_PATTERN)
|
21
|
+
INDEX_PATTERN = /^README/i
|
21
22
|
CUSTOM_HEADER = '' if !defined?(CUSTOM_HEADER)
|
22
23
|
CUSTOM_BODY = '' if !defined?(CUSTOM_BODY)
|
23
24
|
CUSTOM_FOOTER = '' if !defined?(CUSTOM_FOOTER)
|
@@ -40,117 +41,15 @@ class Mamemose::Server
|
|
40
41
|
res['Cache-Control'] = 'no-cache, no-store, must-revalidate'
|
41
42
|
res['Pragma'] = 'no-cache'
|
42
43
|
res['Expires'] = '0'
|
43
|
-
if req.path =~ /^\/search/
|
44
|
-
query = req.query
|
45
|
-
path = fullpath(query["path"])
|
46
|
-
q = URI.decode(query["q"])
|
47
|
-
q = q.force_encoding('utf-8') if q.respond_to?(:force_encoding)
|
48
|
-
|
49
|
-
found = {}
|
50
|
-
Find.find(path) do |file|
|
51
|
-
Find.prune if ignore?(file)
|
52
|
-
dir = File::dirname(file)
|
53
|
-
found[dir] = [] if !found[dir]
|
54
|
-
if markdown?(file)
|
55
|
-
open(file) do |f|
|
56
|
-
c = f.read + "\n" + file
|
57
|
-
found[dir] << [get_title(file,c), uri(file)] if !q.split(' ').map{|s| /#{s}/mi =~ c }.include?(nil)
|
58
|
-
end
|
59
|
-
elsif !q.split(' ').map{|s| /#{s}/ =~ File.basename(file)}.include?(nil)
|
60
|
-
found[dir] << [get_title(file),uri(file)]
|
61
|
-
end
|
62
|
-
end
|
63
|
-
|
64
|
-
title = "Search #{q} in #{showpath(query['path'])}"
|
65
|
-
title = title.force_encoding('utf-8') if title.respond_to?(:force_encoding)
|
66
|
-
body = title + "\n====\n"
|
67
|
-
found.reject{|key, value| value == []}.sort.each do |key, value|
|
68
|
-
body += "\n### in <a href='#{uri(key)}'>#{escape(uri(key))}</a>\n"
|
69
|
-
value.each do |v|
|
70
|
-
body += link_list(v[0], v[1])
|
71
|
-
end
|
72
|
-
end
|
73
|
-
|
74
|
-
res.body = header_html(title, uri(path), q) + markdown(body) + footer_html
|
75
|
-
res.content_type = CONTENT_TYPE
|
76
44
|
|
45
|
+
if req.path =~ /^\/search/
|
46
|
+
res = req_search(req, res)
|
47
|
+
elsif File.directory?(fullpath(req.path)) then
|
48
|
+
res = req_index(req, res)
|
49
|
+
elsif File.exists?(fullpath(req.path))
|
50
|
+
res = req_file(req, res)
|
77
51
|
else
|
78
|
-
|
79
|
-
filename = fullpath(req.path)
|
80
|
-
|
81
|
-
if File.directory?(filename) then
|
82
|
-
title = "Index of #{showpath(req.path)}"
|
83
|
-
body = title + "\n====\n"
|
84
|
-
|
85
|
-
recent = []
|
86
|
-
dirs = []
|
87
|
-
markdowns = []
|
88
|
-
files = []
|
89
|
-
|
90
|
-
if RECENT_NUM > 0 then
|
91
|
-
Find.find(filename) do |file|
|
92
|
-
Find.prune if ignore?(file)
|
93
|
-
recent << file if File.file?(file) && file =~ RECENT_PATTERN
|
94
|
-
end
|
95
|
-
recent = recent.sort_by{|file| File.mtime(file)}.reverse.slice(0,RECENT_NUM)
|
96
|
-
recent = recent.map{|file|
|
97
|
-
if markdown?(file) then
|
98
|
-
[get_title(file, open(file).read), uri(file)]
|
99
|
-
else
|
100
|
-
[escaped_basename(file), uri(file)]
|
101
|
-
end
|
102
|
-
}
|
103
|
-
else
|
104
|
-
recent = []
|
105
|
-
end
|
106
|
-
|
107
|
-
Dir.entries(filename).each do |i|
|
108
|
-
next if ignore?(i)
|
109
|
-
link = uri(File.join(filename, i))
|
110
|
-
if File.directory?(fullpath(link)) then
|
111
|
-
dirs << [escaped_basename(link) + File::SEPARATOR, link]
|
112
|
-
elsif markdown?(link)
|
113
|
-
File.open(fullpath(link)) do |f|
|
114
|
-
markdowns << [get_title(link, f.read), link]
|
115
|
-
end
|
116
|
-
else
|
117
|
-
files << [escaped_basename(link), link]
|
118
|
-
end
|
119
|
-
end
|
120
|
-
|
121
|
-
body += "\nRecent:\n---\n" if RECENT_NUM > 0
|
122
|
-
recent.each {|i| body += link_list(i[0], i[1])}
|
123
|
-
|
124
|
-
body += "\nDirectories:\n----\n"
|
125
|
-
dirs.each {|i| body += link_list(i[0], i[1])}
|
126
|
-
|
127
|
-
body += "\nMarkdown documents:\n----\n"
|
128
|
-
markdowns.each {|i| body += link_list(i[0], i[1])}
|
129
|
-
|
130
|
-
body += "\nOther files:\n----\n"
|
131
|
-
files.each {|i| body += link_list(i[0], i[1])}
|
132
|
-
|
133
|
-
res.body = header_html(title, req.path) + markdown(body) + footer_html
|
134
|
-
res.content_type = CONTENT_TYPE
|
135
|
-
|
136
|
-
elsif File.exists?(filename)
|
137
|
-
open(filename) do |file|
|
138
|
-
if markdown?(req.path)
|
139
|
-
str = file.read
|
140
|
-
title = get_title(filename, str)
|
141
|
-
res.body = header_html(title, req.path) + markdown(str) + footer_html(fullpath(req.path))
|
142
|
-
res.content_type = CONTENT_TYPE
|
143
|
-
else
|
144
|
-
res.body = file.read
|
145
|
-
res.content_type = WEBrick::HTTPUtils.mime_type(req.path, WEBrick::HTTPUtils::DefaultMimeTypes)
|
146
|
-
res.content_length = File.stat(filename).size
|
147
|
-
end
|
148
|
-
end
|
149
|
-
|
150
|
-
else
|
151
|
-
res.status = WEBrick::HTTPStatus::RC_NOT_FOUND
|
152
|
-
end
|
153
|
-
|
52
|
+
res.status = WEBrick::HTTPStatus::RC_NOT_FOUND
|
154
53
|
end
|
155
54
|
end
|
156
55
|
|
@@ -265,6 +164,11 @@ blockquote {
|
|
265
164
|
padding: 0.3em 0;
|
266
165
|
background-color: #f3fff3;
|
267
166
|
}
|
167
|
+
hr {
|
168
|
+
height: 1px;
|
169
|
+
border: none;
|
170
|
+
border-top: 1px solid black;
|
171
|
+
}
|
268
172
|
--></style>
|
269
173
|
<script>
|
270
174
|
function copy(text) {
|
@@ -297,7 +201,15 @@ HTML
|
|
297
201
|
end
|
298
202
|
|
299
203
|
def footer_html(filepath=nil)
|
300
|
-
|
204
|
+
if filepath
|
205
|
+
updated = File.basename(filepath)\
|
206
|
+
+ " [#{filesize(filepath)}]"\
|
207
|
+
+ " / Last Updated: "\
|
208
|
+
+ File.mtime(filepath).strftime("%Y-%m-%d %H:%M:%S")\
|
209
|
+
+ " / "
|
210
|
+
else
|
211
|
+
updated = ""
|
212
|
+
end
|
301
213
|
html = <<HTML
|
302
214
|
#{CUSTOM_FOOTER}
|
303
215
|
<footer>
|
@@ -310,6 +222,133 @@ HTML
|
|
310
222
|
return html
|
311
223
|
end
|
312
224
|
|
225
|
+
def req_search(req, res)
|
226
|
+
query = req.query
|
227
|
+
path = fullpath(query["path"])
|
228
|
+
q = URI.decode(query["q"])
|
229
|
+
q = q.force_encoding('utf-8') if q.respond_to?(:force_encoding)
|
230
|
+
|
231
|
+
found = find(path, q)
|
232
|
+
|
233
|
+
title = "Search #{q} in #{showpath(query['path'])}"
|
234
|
+
title = title.force_encoding('utf-8') if title.respond_to?(:force_encoding)
|
235
|
+
body = title + "\n====\n"
|
236
|
+
found.reject{|key, value| value == []}.sort.each do |key, value|
|
237
|
+
body += "\n### in <a href='#{uri(key)}'>#{escape(uri(key))}</a>\n"
|
238
|
+
value.each {|v| body += link_list(v[0], v[1])}
|
239
|
+
end
|
240
|
+
|
241
|
+
res.body = header_html(title, uri(path), q) + markdown(body) + footer_html
|
242
|
+
res.content_type = CONTENT_TYPE
|
243
|
+
return res
|
244
|
+
end
|
245
|
+
|
246
|
+
def req_index(req, res)
|
247
|
+
directory = fullpath(req.path)
|
248
|
+
title = "Index of #{showpath(req.path)}"
|
249
|
+
body = title + "\n====\n"
|
250
|
+
|
251
|
+
recent = recent_files(directory)
|
252
|
+
fs = directory_files(directory)
|
253
|
+
|
254
|
+
body += "\nRecent:\n---\n" if RECENT_NUM > 0
|
255
|
+
recent.each {|i| body += link_list(i[0], i[1])}
|
256
|
+
|
257
|
+
body += "\nDirectories:\n----\n"
|
258
|
+
fs[:dirs].each {|i| body += link_list(i[0], i[1])}
|
259
|
+
|
260
|
+
body += "\nMarkdown documents:\n----\n"
|
261
|
+
fs[:markdowns].each {|i| body += link_list(i[0], i[1])}
|
262
|
+
|
263
|
+
body += "\nOther files:\n----\n"
|
264
|
+
fs[:others].each {|i| body += link_list(i[0], i[1])}
|
265
|
+
|
266
|
+
if index = indexfile(directory)
|
267
|
+
body += "\n\n"
|
268
|
+
body += File.read(index)
|
269
|
+
end
|
270
|
+
|
271
|
+
res.body = header_html(title, req.path) + markdown(body) + footer_html(index)
|
272
|
+
res.content_type = CONTENT_TYPE
|
273
|
+
return res
|
274
|
+
end
|
275
|
+
|
276
|
+
def req_file(req, res)
|
277
|
+
filename = fullpath(req.path)
|
278
|
+
open(filename) do |file|
|
279
|
+
if markdown?(req.path)
|
280
|
+
str = file.read
|
281
|
+
title = get_title(filename, str)
|
282
|
+
res.body = header_html(title, req.path) + markdown(str) + footer_html(fullpath(req.path))
|
283
|
+
res.content_type = CONTENT_TYPE
|
284
|
+
else
|
285
|
+
res.body = file.read
|
286
|
+
res.content_type = WEBrick::HTTPUtils.mime_type(req.path, WEBrick::HTTPUtils::DefaultMimeTypes)
|
287
|
+
res.content_length = File.stat(filename).size
|
288
|
+
end
|
289
|
+
end
|
290
|
+
return res
|
291
|
+
end
|
292
|
+
|
293
|
+
def find(directory, query)
|
294
|
+
found = {}
|
295
|
+
Find.find(directory) do |file|
|
296
|
+
Find.prune if ignore?(file)
|
297
|
+
dir = File::dirname(file)
|
298
|
+
found[dir] = [] if !found[dir]
|
299
|
+
if markdown?(file)
|
300
|
+
open(file) do |f|
|
301
|
+
c = f.read + "\n" + file
|
302
|
+
found[dir] << [get_title(file,c), uri(file)] if !query.split(' ').map{|s| /#{s}/mi =~ c }.include?(nil)
|
303
|
+
end
|
304
|
+
elsif !query.split(' ').map{|s| /#{s}/ =~ File.basename(file)}.include?(nil)
|
305
|
+
found[dir] << [get_title(file),uri(file)]
|
306
|
+
end
|
307
|
+
end
|
308
|
+
return found
|
309
|
+
end
|
310
|
+
|
311
|
+
def recent_files(directory)
|
312
|
+
recent = []
|
313
|
+
if RECENT_NUM > 0 then
|
314
|
+
Find.find(directory) do |file|
|
315
|
+
Find.prune if ignore?(file)
|
316
|
+
recent << file if File.file?(file) && file =~ RECENT_PATTERN
|
317
|
+
end
|
318
|
+
recent = recent.sort_by{|file| File.mtime(file)}.reverse.slice(0,RECENT_NUM)
|
319
|
+
recent = recent.map{|file|
|
320
|
+
if markdown?(file) then
|
321
|
+
[get_title(file, open(file).read), uri(file)]
|
322
|
+
else
|
323
|
+
[escaped_basename(file), uri(file)]
|
324
|
+
end
|
325
|
+
}
|
326
|
+
else
|
327
|
+
recent = []
|
328
|
+
end
|
329
|
+
return recent
|
330
|
+
end
|
331
|
+
|
332
|
+
def directory_files(directory)
|
333
|
+
dirs = []
|
334
|
+
markdowns = []
|
335
|
+
others = []
|
336
|
+
Dir.entries(directory).each do |i|
|
337
|
+
next if ignore?(i)
|
338
|
+
link = uri(File.join(directory, i))
|
339
|
+
if File.directory?(fullpath(link)) then
|
340
|
+
dirs << [escaped_basename(link) + File::SEPARATOR, link]
|
341
|
+
elsif markdown?(link)
|
342
|
+
File.open(fullpath(link)) do |f|
|
343
|
+
markdowns << [get_title(link, f.read), link]
|
344
|
+
end
|
345
|
+
else
|
346
|
+
others << [escaped_basename(link), link]
|
347
|
+
end
|
348
|
+
end
|
349
|
+
return {:dirs=>dirs, :markdowns=>markdowns, :others=>others}
|
350
|
+
end
|
351
|
+
|
313
352
|
# returns escaped characters so that the markdown parser doesn't interpret it has special meaning.
|
314
353
|
def escape(text)
|
315
354
|
return text.gsub(/[\`*_{}\[\]()#+\-.!]/, "\\\\\\0")
|
@@ -343,10 +382,14 @@ HTML
|
|
343
382
|
|
344
383
|
def link_list(title, link)
|
345
384
|
file = fullpath(link)
|
346
|
-
str =
|
385
|
+
str = filesize(file)
|
347
386
|
return "- [#{title}](#{link}) <a class='filename' href=\"javascript:copy('#{docpath(link)}');\">[#{escaped_basename(link)}, #{str}]</a>\n"
|
348
387
|
end
|
349
388
|
|
389
|
+
def filesize(file)
|
390
|
+
File.file?(file) ? sprintf("%.1fKB", File.size(file) / 1024.0) : "dir"
|
391
|
+
end
|
392
|
+
|
350
393
|
def markdown?(file)
|
351
394
|
return file =~ MARKDOWN_PATTERN
|
352
395
|
end
|
@@ -366,6 +409,15 @@ HTML
|
|
366
409
|
return title =~ /^\s*$/ ? escaped_basename(filename) : title
|
367
410
|
end
|
368
411
|
|
412
|
+
def indexfile(dir)
|
413
|
+
Dir.entries(dir).each do |f|
|
414
|
+
if f =~ INDEX_PATTERN && markdown?(f)
|
415
|
+
return dir + File::SEPARATOR + f
|
416
|
+
end
|
417
|
+
end
|
418
|
+
return nil
|
419
|
+
end
|
420
|
+
|
369
421
|
def markdown(text)
|
370
422
|
markdown = Redcarpet::Markdown.new(HTMLwithSyntaxHighlighter,
|
371
423
|
{:strikethrough => true,
|
data/lib/mamemose/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mamemose
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-12-
|
12
|
+
date: 2012-12-23 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: redcarpet
|