memorack 0.1.2 → 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.
- checksums.yaml +4 -4
- data/HISTORY.md +15 -0
- data/README.md +17 -15
- data/VERSION +1 -1
- data/lib/memorack/builder.rb +36 -2
- data/lib/memorack/cli.rb +8 -5
- data/lib/memorack/config/macro.yml +2 -0
- data/lib/memorack/core.rb +339 -47
- data/lib/memorack/locales/en.yml +1 -0
- data/lib/memorack/locales/ja.yml +1 -0
- data/lib/memorack/locals.rb +31 -1
- data/lib/memorack/locals/app.rb +16 -0
- data/lib/memorack/locals/base.rb +84 -0
- data/lib/memorack/mdmenu.rb +3 -2
- data/lib/memorack/memoapp.rb +7 -2
- data/lib/memorack/pageinfo.rb +151 -0
- data/lib/memorack/plugin.rb +54 -0
- data/lib/memorack/plugins/formats/formats.rb +12 -0
- data/lib/memorack/plugins/formats/markdown.rb +32 -0
- data/lib/memorack/plugins/formats/org.rb +54 -0
- data/lib/memorack/template/.gitignore +1 -0
- data/lib/memorack/template/plugins/.gitkeep +0 -0
- data/lib/memorack/template/themes/custom/locales/.gitkeep +0 -0
- data/lib/memorack/template/themes/custom/macro.yml +2 -0
- data/lib/memorack/template/themes/custom/pages/.gitkeep +0 -0
- data/spec/memorack_spec.rb +115 -15
- data/spec/patches/git/0001-add-HISTORY.patch +15 -0
- data/spec/patches/git/0002-change-HISTORY.patch +19 -0
- data/spec/patches/git/0003-index.html.patch +75 -0
- data/spec/patches/macro.patch +20 -0
- data/spec/patches/plugin.patch +87 -0
- metadata +24 -2
data/lib/memorack/locales/en.yml
CHANGED
data/lib/memorack/locales/ja.yml
CHANGED
data/lib/memorack/locals.rb
CHANGED
@@ -5,35 +5,65 @@ module MemoRack
|
|
5
5
|
class Locals < Hash
|
6
6
|
alias :super_has_key? has_key?
|
7
7
|
|
8
|
+
# 値を取出す
|
8
9
|
def [](key)
|
9
10
|
return super if super_has_key?(key)
|
10
11
|
return context[key].call(self, key) if context[key]
|
12
|
+
return value(key) if value_method?(key)
|
11
13
|
|
12
14
|
super
|
13
15
|
end
|
14
16
|
|
17
|
+
# キーがあるか?
|
15
18
|
def has_key?(key)
|
19
|
+
return true if super
|
16
20
|
return true if context.has_key?(key)
|
17
|
-
|
21
|
+
return true if value_method?(key)
|
22
|
+
|
23
|
+
false
|
18
24
|
end
|
19
25
|
|
26
|
+
# マージ
|
20
27
|
def merge(hash)
|
21
28
|
new_hash = super
|
22
29
|
new_hash.context = context.dup
|
23
30
|
new_hash
|
24
31
|
end
|
25
32
|
|
33
|
+
# コールバック登録用のハッシュ
|
26
34
|
def context
|
27
35
|
@context ||= {}
|
28
36
|
end
|
29
37
|
|
38
|
+
# コールバック登録用のハッシュを代入する(merge用)
|
30
39
|
def context=(value)
|
31
40
|
@context = value
|
32
41
|
end
|
33
42
|
|
43
|
+
# キーにコールバックを登録する
|
34
44
|
def define_key(name, &block)
|
35
45
|
context[name] = block
|
36
46
|
end
|
47
|
+
|
48
|
+
# 値を取出すメソッドがあるか?
|
49
|
+
def value_method?(name)
|
50
|
+
respond_to?(Locals.value_method(name))
|
51
|
+
end
|
52
|
+
|
53
|
+
# 値をメソッドから取出す
|
54
|
+
def value(name)
|
55
|
+
send(Locals.value_method(name), name)
|
56
|
+
end
|
57
|
+
|
58
|
+
# 値を取出すメソッド名
|
59
|
+
def self.value_method(name)
|
60
|
+
:"value_#{name}"
|
61
|
+
end
|
62
|
+
|
63
|
+
# キーにメソッドを登録する
|
64
|
+
def self.define_key(name, &block)
|
65
|
+
define_method(value_method(name), &block)
|
66
|
+
end
|
37
67
|
end
|
38
68
|
|
39
69
|
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
require 'memorack/locals'
|
4
|
+
|
5
|
+
|
6
|
+
module MemoRack
|
7
|
+
|
8
|
+
class AppLocals < Locals
|
9
|
+
|
10
|
+
define_key(:name) { |key| MemoRack::name }
|
11
|
+
define_key(:version) { |key| MemoRack::VERSION }
|
12
|
+
define_key(:url) { |key| MemoRack::HOMEPAGE }
|
13
|
+
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
require 'memorack/locals'
|
4
|
+
require 'memorack/locals/app'
|
5
|
+
|
6
|
+
|
7
|
+
module MemoRack
|
8
|
+
|
9
|
+
class BaseLocals < Locals
|
10
|
+
|
11
|
+
attr_reader :app
|
12
|
+
|
13
|
+
def initialize(app, hash = nil, ifnone = nil)
|
14
|
+
super ifnone
|
15
|
+
|
16
|
+
@app = app
|
17
|
+
merge!(hash) if hash
|
18
|
+
|
19
|
+
self[:app] = AppLocals[]
|
20
|
+
end
|
21
|
+
|
22
|
+
define_key :__menu__ do |key|
|
23
|
+
@app.render_menu
|
24
|
+
end
|
25
|
+
|
26
|
+
define_key :subdirs do |key|
|
27
|
+
unless @subdirs
|
28
|
+
@subdirs = []
|
29
|
+
|
30
|
+
path_info = self[:path_info]
|
31
|
+
break unless path_info
|
32
|
+
|
33
|
+
href = self[:site][:url].to_s
|
34
|
+
|
35
|
+
File.dirname(path_info).split('/').each { |dir|
|
36
|
+
next if dir == '.'
|
37
|
+
href = File.join(href, dir)
|
38
|
+
next if dir.empty?
|
39
|
+
|
40
|
+
@subdirs << {name: dir, href: href}
|
41
|
+
}
|
42
|
+
end
|
43
|
+
|
44
|
+
@subdirs
|
45
|
+
end
|
46
|
+
|
47
|
+
define_key :topicpath do |key|
|
48
|
+
unless @topicpath
|
49
|
+
@topicpath = []
|
50
|
+
@topicpath << {name: self[:title], href: File.join(self[:site][:url].to_s, '')}
|
51
|
+
@topicpath += self[:subdirs] if self[:subdirs]
|
52
|
+
@topicpath << {name: self[:page][:name]} if self[:page][:name]
|
53
|
+
@topicpath.last[:last?] = true
|
54
|
+
end
|
55
|
+
|
56
|
+
@topicpath
|
57
|
+
end
|
58
|
+
|
59
|
+
define_key :pages do |key|
|
60
|
+
unless @pages
|
61
|
+
@pages = []
|
62
|
+
|
63
|
+
@app.pages.each { |path_info, path|
|
64
|
+
href = self[:site][:url].to_s
|
65
|
+
href = File.join(href, path_info)
|
66
|
+
href += @app.suffix unless @app.suffix.empty?
|
67
|
+
|
68
|
+
if plugin = PageInfo[path]
|
69
|
+
pageinfo = plugin.new(path, nil, {path_info: path_info})
|
70
|
+
name = pageinfo[:title]
|
71
|
+
end
|
72
|
+
|
73
|
+
name ||= File.basename(path_info)
|
74
|
+
|
75
|
+
@pages << {name: name, href: href}
|
76
|
+
}
|
77
|
+
end
|
78
|
+
|
79
|
+
@pages
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
data/lib/memorack/mdmenu.rb
CHANGED
@@ -122,11 +122,12 @@ class MdMenu
|
|
122
122
|
end
|
123
123
|
|
124
124
|
# 新規リンクを追加する
|
125
|
-
def generate(outfile = @file)
|
125
|
+
def generate(outfile = @file, &block)
|
126
126
|
len = @files.length
|
127
127
|
|
128
128
|
if 0 < len
|
129
129
|
outfile = nil if outfile && outfile.kind_of?(String) && File.exist?(outfile) && ! @config[:update]
|
130
|
+
block = lambda { |path| File.basename(path, '.*') } unless block
|
130
131
|
|
131
132
|
stdout(outfile, 'a') {
|
132
133
|
prefix = @config[:prefix]
|
@@ -134,7 +135,7 @@ class MdMenu
|
|
134
135
|
dirs = []
|
135
136
|
|
136
137
|
@files.each { |item|
|
137
|
-
title =
|
138
|
+
title = block.call(item[:path])
|
138
139
|
link = item[:link]
|
139
140
|
|
140
141
|
dir, dirs = each_subdir(File.dirname(link), dir, dirs) { |name, i|
|
data/lib/memorack/memoapp.rb
CHANGED
@@ -6,6 +6,7 @@ require 'rack'
|
|
6
6
|
require 'uri'
|
7
7
|
|
8
8
|
require 'memorack/core'
|
9
|
+
require 'memorack/pageinfo'
|
9
10
|
|
10
11
|
module MemoRack
|
11
12
|
class MemoApp < Core
|
@@ -25,6 +26,9 @@ module MemoRack
|
|
25
26
|
|
26
27
|
path_info = unescape_path_info(env)
|
27
28
|
|
29
|
+
# ロケールの更新
|
30
|
+
update_locale(env)
|
31
|
+
|
28
32
|
case path_info
|
29
33
|
when '/'
|
30
34
|
content = render_with_mustache :index, :markdown
|
@@ -40,7 +44,8 @@ module MemoRack
|
|
40
44
|
end
|
41
45
|
else
|
42
46
|
locals = {env: env, path_info: path_info}
|
43
|
-
content
|
47
|
+
content ||= render_content(path_info, locals)
|
48
|
+
content ||= render_page(path_info, locals)
|
44
49
|
end
|
45
50
|
|
46
51
|
return [200, {'Content-Type' => content_type}, [content.to_s]] if content
|
@@ -148,7 +153,7 @@ module MemoRack
|
|
148
153
|
|
149
154
|
# メニューを作成
|
150
155
|
template :menu do
|
151
|
-
contents.generate(StringIO.new).string
|
156
|
+
contents.generate(StringIO.new, &method(:content_name).to_proc).string
|
152
157
|
end
|
153
158
|
|
154
159
|
end
|
@@ -0,0 +1,151 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
require 'memorack/plugin'
|
4
|
+
require 'memorack/locals'
|
5
|
+
|
6
|
+
|
7
|
+
module MemoRack
|
8
|
+
class PageInfo < Locals
|
9
|
+
extend Plugin
|
10
|
+
|
11
|
+
attr_accessor :max_lines
|
12
|
+
|
13
|
+
def initialize(path, hash = nil, parent = {}, ifnone = nil)
|
14
|
+
super ifnone
|
15
|
+
|
16
|
+
@path = path
|
17
|
+
merge!(hash) if hash
|
18
|
+
|
19
|
+
@max_lines = 5
|
20
|
+
@parent = parent
|
21
|
+
end
|
22
|
+
|
23
|
+
def values
|
24
|
+
@values ||= {}
|
25
|
+
end
|
26
|
+
|
27
|
+
# ファイルを解析
|
28
|
+
def parse(*info_list)
|
29
|
+
methods = {}
|
30
|
+
|
31
|
+
info_list.each { |info|
|
32
|
+
m = "accept_#{info}"
|
33
|
+
methods[info] = m if respond_to?(m)
|
34
|
+
}
|
35
|
+
|
36
|
+
open(@path, 'r') { |file|
|
37
|
+
prev = nil
|
38
|
+
n = 1
|
39
|
+
|
40
|
+
until methods.empty?
|
41
|
+
break unless line = file.gets
|
42
|
+
break if parse_end?(line, n)
|
43
|
+
|
44
|
+
methods.each { |key, m|
|
45
|
+
v = send(m, line, prev)
|
46
|
+
if v
|
47
|
+
values[key] = v
|
48
|
+
methods.delete(key)
|
49
|
+
end
|
50
|
+
}
|
51
|
+
|
52
|
+
prev = line
|
53
|
+
n += 1
|
54
|
+
end
|
55
|
+
}
|
56
|
+
|
57
|
+
values[info_list.first]
|
58
|
+
end
|
59
|
+
|
60
|
+
# ファイル解析の終了か?
|
61
|
+
def parse_end?(line, n)
|
62
|
+
max_lines < n
|
63
|
+
end
|
64
|
+
|
65
|
+
# 実行アプリケーション
|
66
|
+
def app
|
67
|
+
begin
|
68
|
+
@parent.app
|
69
|
+
rescue
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
# git で管理されているか?
|
74
|
+
def git?
|
75
|
+
if @git == nil
|
76
|
+
@git ||= File.exists?(File.join(app.root, '.git'))
|
77
|
+
@git ||= File.exists?(File.join(app.root, '../.git'))
|
78
|
+
end
|
79
|
+
|
80
|
+
@git
|
81
|
+
end
|
82
|
+
|
83
|
+
# git log で更新日時一覧を取得する
|
84
|
+
def log
|
85
|
+
unless @log
|
86
|
+
@log = []
|
87
|
+
return @log unless git?
|
88
|
+
|
89
|
+
begin
|
90
|
+
dir, fname = File.split(@path)
|
91
|
+
Dir.chdir(dir) { |dir|
|
92
|
+
log << File::Stat.new(fname).mtime if `git status` =~ /modified:\s+#{fname}/
|
93
|
+
|
94
|
+
`git log --pretty='%ad' --date iso '#{fname}'`.each_line { |line|
|
95
|
+
@log << line
|
96
|
+
}
|
97
|
+
}
|
98
|
+
rescue
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
@log
|
103
|
+
end
|
104
|
+
|
105
|
+
# 値を Timeクラスに変換する
|
106
|
+
def value_to_time(value)
|
107
|
+
value = Time.parse(value) if value.kind_of?(String)
|
108
|
+
value
|
109
|
+
end
|
110
|
+
|
111
|
+
def self.define_keys(*keys, &block)
|
112
|
+
block = lambda { |key| values[key] || parse(key) } unless block
|
113
|
+
|
114
|
+
keys.each { |name|
|
115
|
+
define_key(name, &block)
|
116
|
+
}
|
117
|
+
end
|
118
|
+
|
119
|
+
define_keys :title
|
120
|
+
|
121
|
+
# 作成時間・更新時間
|
122
|
+
define_keys(:ctime, :mtime) { |key|
|
123
|
+
values[key] ||= key == :ctime && value_to_time(log.last) # log から作成時間を取得
|
124
|
+
values[key] ||= key == :mtime && value_to_time(log.first) # log から更新時間を取得
|
125
|
+
values[key] ||= File::Stat.new(@path).send(key) # なければファイル情報から取得
|
126
|
+
}
|
127
|
+
|
128
|
+
# 作成日・更新日
|
129
|
+
define_keys(:cdate, :mdate) { |key|
|
130
|
+
values[key] ||= self[:"#{key[0]}time"].strftime('%Y-%m-%d')
|
131
|
+
}
|
132
|
+
end
|
133
|
+
|
134
|
+
# デフォルト用
|
135
|
+
class PageInfoDefault < PageInfo
|
136
|
+
# 優先順位
|
137
|
+
def self.priority
|
138
|
+
-1
|
139
|
+
end
|
140
|
+
|
141
|
+
def self.member?(key, ext = nil)
|
142
|
+
ext != nil
|
143
|
+
end
|
144
|
+
|
145
|
+
define_key(:title) { |key|
|
146
|
+
values[:title] ||= I18n.t @parent[:path_info], scope: [:pages],
|
147
|
+
default: File.basename(@path, '.*')
|
148
|
+
}
|
149
|
+
end
|
150
|
+
|
151
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
require 'set'
|
4
|
+
|
5
|
+
|
6
|
+
module MemoRack
|
7
|
+
module Plugin
|
8
|
+
|
9
|
+
## extend Plugin で使用する
|
10
|
+
|
11
|
+
# サブクラスが追加されたらプラグインに登録する
|
12
|
+
def inherited(subclass)
|
13
|
+
plugins << subclass
|
14
|
+
end
|
15
|
+
|
16
|
+
# プラグイン一覧
|
17
|
+
def plugins
|
18
|
+
@plugins ||= SortedSet.new
|
19
|
+
end
|
20
|
+
|
21
|
+
# 優先順位
|
22
|
+
def priority
|
23
|
+
1
|
24
|
+
end
|
25
|
+
|
26
|
+
# プラグインの優先順位を比較する
|
27
|
+
def <=>(other)
|
28
|
+
r = - (self.priority <=> other.priority)
|
29
|
+
return r unless r == 0
|
30
|
+
|
31
|
+
self.to_s <=> other.to_s
|
32
|
+
end
|
33
|
+
|
34
|
+
def member?(key, ext = nil)
|
35
|
+
extnames.member?(ext)
|
36
|
+
end
|
37
|
+
|
38
|
+
def extnames
|
39
|
+
[]
|
40
|
+
end
|
41
|
+
|
42
|
+
# ファイル拡張子からプラグインをみつける
|
43
|
+
def [](key)
|
44
|
+
ext = File.extname(key)[1..-1]
|
45
|
+
|
46
|
+
plugins.each { |plugin|
|
47
|
+
return plugin if plugin.member?(key, ext)
|
48
|
+
}
|
49
|
+
|
50
|
+
nil
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
end
|