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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 6e66f5b1c38568ebc3011b2210c3b890fa0a8e36
4
- data.tar.gz: 006b12c2a64d34170e3a7f3b1543c1dd61120222
3
+ metadata.gz: 86c45efe555619b9ccb0baf170a9ec452f0fa52e
4
+ data.tar.gz: b012723ff47cef6d9887501fd28c88d3d6a5fcfc
5
5
  SHA512:
6
- metadata.gz: e6e4612436e39a618a59681f0db052f8069a05eb1d332ab754fddfc0cc4ba2371981ab77bf2e42f328d5f55e2025180ce73f0ad9d7370d4bb9bc28d65b3dfe81
7
- data.tar.gz: 44cfe752ef03701a381582aa26a1020320a161eb061b06b1d6c2a5864f901dca55c145056b3ad12b395e655e12247eb99995ac378b242e8cdf63065e5c9612e8
6
+ metadata.gz: 5ca5bf21735546d0371a71efebad1c902b869283495a26b4c276442e0cb949169ddafd894479590c3d77bebf5c82479a9548346607f1f9321301a9e6f6390c21
7
+ data.tar.gz: dbfa869e5a135c9d5244d7b92cb65aab7634786b8a0361c643e2b9039de285074ab65f88834f60a3396d8a58013da548bf82c00517bb07c0d3d5ac0fad560f5b
data/HISTORY.md CHANGED
@@ -1,5 +1,20 @@
1
1
  ## History
2
2
 
3
+ ### v0.2.0 / 2013-05-12
4
+
5
+ * plugin
6
+ * macro
7
+ * pages
8
+ * add `page.html` for content template
9
+ * support user domain themes/plugins folder (ex. `~/.etc/memorack/themes/`)
10
+ * yaml support for configuration (ex. `config.yml`)
11
+ * page title from content headline (markdown/org only)
12
+ * page title from locale (pages)
13
+ * page created/modified time
14
+ * to optional path of server subcommand (default: `content`)
15
+ * add option `--index` of build subcommand
16
+ * change default values
17
+
3
18
  ### v0.1.2 / 2013-05-06
4
19
 
5
20
  * build not remove .git/.hg/.svn/.cvs direcotry
data/README.md CHANGED
@@ -22,8 +22,8 @@ Or install it yourself as:
22
22
  $ memorack theme # Show theme list
23
23
  $ memorack theme THEME # Show theme info
24
24
  $ memorack theme -c THEME # Copy theme
25
- $ memorack server PATH # Instant Server
26
- $ memorack build [PATH] # Build static site
25
+ $ memorack server [PATH] # Instant Server
26
+ $ memorack build [PATH] # Build static site
27
27
 
28
28
  Standard startup
29
29
 
@@ -67,12 +67,16 @@ Template
67
67
  ├── .powenv -- for pow + rbenv
68
68
  ├── Gemfile -- `bundle install`
69
69
  ├── config.ru -- for rack application
70
- ├── content -- Content directory for memo
70
+ ├── content/ -- Content directory for memo
71
71
  │   └── README.md -- Sample file(remove it)
72
- └── themes
73
- └── custom -- Default theme
72
+ ├── plugins/ -- Plugins directory
73
+ └── themes/
74
+ └── custom/ -- Default theme
74
75
  ├── config.json -- Configuration
75
- └── index.md -- Description(Show by top page)
76
+ ├── index.md -- Description(Show by top page)
77
+ ├── locales/ -- Locales directory
78
+ ├── macro.yml -- Macro
79
+ └── pages/ -- Pages directory
76
80
 
77
81
  ## Customization
78
82
 
@@ -87,18 +91,18 @@ Template
87
91
 
88
92
  Directory
89
93
 
90
- └── themes
91
- └── custom
94
+ └── themes/
95
+ └── custom/
92
96
  ├── config.json
93
97
  ├── index.html <-- Edit layout
94
98
  └── index.md
95
99
 
96
100
  ### Logo
97
101
 
98
- └── themes
99
- └── custom
102
+ └── themes/
103
+ └── custom/
100
104
  ├── config.json <-- Add "logo": "/img/logo.png"
101
- ├── img
105
+ ├── img/
102
106
  │ └── logo.png <-- Add image file
103
107
  ├── index.html <-- Add <img id="logo" src="{{logo}}" />
104
108
  └── index.md
@@ -107,8 +111,8 @@ Directory
107
111
 
108
112
  Download [highlight.js](http://softwaremaniacs.org/soft/highlight/en/)
109
113
 
110
- └── themes
111
- └── custom
114
+ └── themes/
115
+ └── custom/
112
116
  ├── config.json
113
117
  ├── highlight.js <-- `unzip highlight.zip`
114
118
  ├── index.html <-- Add code
@@ -130,7 +134,6 @@ Edit `config.json`
130
134
 
131
135
  {
132
136
  "formats": ["markdown", "org"],
133
- "requires": ["org-ruby"],
134
137
  ...
135
138
  }
136
139
 
@@ -156,7 +159,6 @@ Special variables -- `{{{VAR}}}`
156
159
  * Template comments translate english
157
160
  * Add customizing tips
158
161
  * More test program
159
- * Plugin
160
162
  * Generate EPUB3
161
163
 
162
164
  ## Contributing
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.2
1
+ 0.2.0
@@ -15,6 +15,7 @@ module MemoRack
15
15
  prefix: '/',
16
16
  suffix: '.html',
17
17
  uri_escape: true,
18
+ env: ENV,
18
19
  }
19
20
 
20
21
  DEFAULT_KEEPS = ['.git', '.hg', '.svn', '.csv']
@@ -25,12 +26,18 @@ module MemoRack
25
26
 
26
27
  url = @site[:url]
27
28
  options[:prefix] = File.join(url, options[:prefix]) unless url.empty?
29
+ @suffix = options[:suffix]
28
30
 
29
31
  output = File.expand_path(options[:output])
30
32
  dir_init(output, keeps)
31
33
 
32
34
  @contents = contents(options)
33
35
  @templates = Set.new @contents.files.collect { |file| file[:path] }
36
+ @directories = Set.new @templates.collect { |path| File.dirname(path) }
37
+ @directories.delete('.')
38
+
39
+ # ロケールの更新
40
+ update_locale(options[:env])
34
41
 
35
42
  # トップページを作成する
36
43
  content_write(:index, '.html', output) { |template|
@@ -40,12 +47,24 @@ module MemoRack
40
47
  suffix = options[:suffix]
41
48
  suffix = '/index.html' if ['', '/'].member?(suffix)
42
49
 
50
+ # サブディレクトリの index.html を出力する
51
+ build_index(@directories, output, &callback) if options[:index] || @options[:index]
52
+
53
+ # 固定ページのレンダリングを行う
54
+ pages.each { |path_info, path|
55
+ callback.call(path_info) if callback
56
+
57
+ content_write(path_info, suffix, output) { |template|
58
+ render_page template, {path_info: path_info}
59
+ }
60
+ }
61
+
43
62
  # コンテンツのレンダリングを行う
44
63
  @templates.each { |path|
45
64
  callback.call(path) if callback
46
65
 
47
66
  content_write(path, suffix, output) { |template|
48
- render_content(template)
67
+ render_content template, {path_info: path}, nil
49
68
  }
50
69
  }
51
70
 
@@ -157,6 +176,21 @@ module MemoRack
157
176
  }
158
177
  end
159
178
 
179
+ # サブディレクトリの index.html を出力する
180
+ def build_index(directories, output, &callback)
181
+ # . は取除く
182
+ directories.delete('.')
183
+
184
+ # index.html を出力する
185
+ directories.each { |path|
186
+ callback.call(path) if callback
187
+
188
+ content_write(path, '/index.html', output) { |template|
189
+ render_content template, {path_info: path}, nil
190
+ }
191
+ }
192
+ end
193
+
160
194
  #### テンプレート
161
195
 
162
196
  # インデックスを作成
@@ -170,7 +204,7 @@ module MemoRack
170
204
 
171
205
  # メニューを作成
172
206
  template :menu do
173
- @contents.generate(StringIO.new).string
207
+ @contents.generate(StringIO.new, &method(:content_name).to_proc).string
174
208
  end
175
209
 
176
210
  end
@@ -27,7 +27,7 @@ module MemoRack
27
27
  opts.banner = <<-BANNER.gsub(/^\t+/,'')
28
28
  Usage: #{opts.program_name} create [options] PATH
29
29
  #{opts.program_name} theme [options] [THEME]
30
- #{opts.program_name} server [options] PATH
30
+ #{opts.program_name} server [options] [PATH]
31
31
  #{opts.program_name} build [options] [PATH]
32
32
  BANNER
33
33
 
@@ -150,9 +150,9 @@ module MemoRack
150
150
  }
151
151
 
152
152
  # サーバーの実行
153
- define_options(:server, '[options] PATH') { |opts, argv, options|
153
+ define_options(:server, '[options] [PATH]') { |opts, argv, options|
154
154
  default_options = {
155
- theme: 'oreilly',
155
+ theme: 'custom',
156
156
 
157
157
  server: {
158
158
  environment: ENV['RACK_ENV'] || 'development',
@@ -172,7 +172,6 @@ module MemoRack
172
172
  opts.on("-h", "--help", t(:help)) { abort opts.help }
173
173
 
174
174
  opts.parse!(argv)
175
- abort opts.help if argv.empty?
176
175
  }
177
176
 
178
177
  # 静的サイトのビルド
@@ -184,6 +183,7 @@ module MemoRack
184
183
 
185
184
  local: false,
186
185
  prettify: false,
186
+ index: false,
187
187
  }
188
188
 
189
189
  options.merge!(default_options)
@@ -199,6 +199,8 @@ module MemoRack
199
199
  t(:local)) { options[:local] = true }
200
200
  opts.on("--prettify",
201
201
  t(:prettify)) { options[:prettify] = true }
202
+ opts.on("--index",
203
+ t(:index)) { options[:index] = true }
202
204
  opts.on("-h", "--help", t(:help)) { abort opts.help }
203
205
 
204
206
  opts.parse!(argv)
@@ -271,7 +273,8 @@ module MemoRack
271
273
 
272
274
  # サーバーの実行
273
275
  def memorack_server(options, *argv)
274
- path = argv.shift
276
+ path ||= argv.shift
277
+ path ||= 'content'
275
278
  abort "Directory not exists '#{path}'" unless File.exists?(path)
276
279
  abort "Not directory '#{path}'" unless File.directory?(path)
277
280
 
@@ -0,0 +1,2 @@
1
+ page:
2
+ title: '{{#content?}}{{page.name}} | {{/content?}}{{title}}'
@@ -1,21 +1,25 @@
1
1
  # -*- encoding: utf-8 -*-
2
2
 
3
+ require 'yaml'
3
4
  require 'pathname'
4
5
  require 'rubygems'
6
+ require 'i18n'
5
7
 
6
8
  require 'memorack/tilt-mustache'
7
- require 'memorack/locals'
8
9
  require 'memorack/mdmenu'
10
+ require 'memorack/locals'
11
+ require 'memorack/locals/base'
12
+
9
13
 
10
14
  module MemoRack
11
15
  class Core
12
- attr_reader :themes, :options_chain
16
+ attr_reader :themes, :options_chain, :suffix, :root
13
17
 
14
18
  DEFAULT_APP_OPTIONS = {
15
19
  root: 'content/',
16
20
  themes_folder: 'themes/',
17
21
  tmpdir: 'tmp/',
18
- theme: 'basic',
22
+ theme: 'oreilly',
19
23
  markdown: 'redcarpet',
20
24
  formats: ['markdown'],
21
25
  css: nil,
@@ -38,10 +42,19 @@ module MemoRack
38
42
 
39
43
  DEFAULT_OPTIONS = DEFAULT_APP_OPTIONS.merge(DEFAULT_TEMPLATE_OPTIONS).merge(DEFAULT_LOCALS)
40
44
 
45
+ def self.app
46
+ @@app
47
+ end
48
+
41
49
  def initialize(options={})
50
+ @@app = self
51
+
42
52
  options = DEFAULT_OPTIONS.merge(to_sym_keys(options))
43
53
 
44
- @themes_folders = [options[:themes_folder], File.expand_path('../themes/', __FILE__)]
54
+ @themes_folders = [options[:themes_folder], folder(:themes, :user), folder(:themes)]
55
+ @themes_folders.delete nil
56
+ @themes_folders.reject! { |folder| ! File.directory?(folder) }
57
+
45
58
  read_config(options[:theme], options)
46
59
  read_config(DEFAULT_APP_OPTIONS[:theme], options) if @themes.empty?
47
60
 
@@ -55,12 +68,38 @@ module MemoRack
55
68
  @options.delete(key)
56
69
  }
57
70
 
71
+ # プラグインの読込み
72
+ load_plugins
73
+
74
+ # ロケールの読込み
75
+ I18n.load_path = @locale_paths
76
+ I18n.backend.load_translations
77
+
58
78
  @requires.each { |lib| require lib }
59
79
  @locals = default_locals(@options)
60
80
 
61
81
  use_engine(@markdown)
62
82
  end
63
83
 
84
+ # フォルダ(ディレクトリ)を取得する
85
+ def folder(name, domain = :app)
86
+ @folders ||= {}
87
+ @folders[domain] ||= {}
88
+
89
+ unless @folders[domain][name]
90
+ case domain
91
+ when :user
92
+ dir = File.join(ENV['HOME'], '.etc/memorack')
93
+ when :app
94
+ dir = File.dirname(__FILE__)
95
+ else
96
+ return nil
97
+ end
98
+ end
99
+
100
+ @folders[domain][name] ||= File.expand_path(name.to_s, dir)
101
+ end
102
+
64
103
  # テーマのパスを取得する
65
104
  def theme_path(theme)
66
105
  return nil unless theme
@@ -75,28 +114,44 @@ module MemoRack
75
114
 
76
115
  # デフォルトの locals を生成する
77
116
  def default_locals(locals = {})
78
- locals = Locals[locals]
79
-
80
- locals[:site] ||= @site
81
-
82
- locals[:app] ||= Locals[]
83
- locals[:app][:name] ||= MemoRack::name
84
- locals[:app][:version] ||= MemoRack::VERSION
85
- locals[:app][:url] ||= MemoRack::HOMEPAGE
117
+ locals = BaseLocals.new(self, locals)
118
+ locals[:site] ||= @site
119
+ locals
120
+ end
86
121
 
87
- locals.define_key(:__menu__) { |hash, key|
88
- @menu = nil unless @directory_watcher # ファイル監視していない場合はメニューを初期化
89
- @menu ||= render :markdown, :menu, @options
90
- }
122
+ # json/yaml のデータを読込む
123
+ def read_data(name, exts = ['json', 'yml', 'yaml'])
124
+ begin
125
+ exts.each { |ext|
126
+ path = [name, ext].join('.')
127
+ if File.readable?(path)
128
+ data = File.read(path)
129
+
130
+ case ext
131
+ when 'json'
132
+ hash = JSON.parse(data)
133
+ when 'yml', 'yaml'
134
+ hash = YAML.load(data)
135
+ end
136
+
137
+ data = to_sym_keys(hash) if hash
138
+ return data
139
+ end
140
+ }
141
+ rescue
142
+ end
91
143
 
92
- locals
144
+ nil
93
145
  end
94
146
 
95
147
  # 設定ファイルを読込む
96
148
  def read_config(theme, options = {})
97
149
  @themes ||= []
98
150
  @options_chain = []
99
- @theme_chain = []
151
+ @locale_paths = []
152
+ @macro_chain = []
153
+ @macro = {}
154
+ @plugins = Set.new
100
155
 
101
156
  begin
102
157
  require 'json'
@@ -106,26 +161,112 @@ module MemoRack
106
161
  break unless dir
107
162
  break if @themes.member?(dir)
108
163
 
109
- # テーマ・チェインに追加
110
- @themes << File.join(dir, '')
111
-
112
- # config の読込み
113
- path = File.join(dir, 'config.json')
114
- break unless File.readable?(path)
115
-
116
- data = File.read(path)
117
- @options_chain << to_sym_keys(JSON.parse(data))
118
-
119
- theme = @options_chain.last[:theme]
164
+ # 設定ファイルのデータをチェインに追加
165
+ theme = add_config_chain(dir, theme)
120
166
  end
121
167
  rescue
122
168
  end
123
169
 
170
+ # デフォルトの設定をチェインに追加
171
+ add_config_chain(File.expand_path('../config', __FILE__))
172
+
173
+ # マクロをマージ
174
+ @macro_chain.reverse.each { |macro| @macro.merge!(macro) }
175
+
124
176
  # オプションをマージ
125
177
  @options_chain.reverse.each { |opts| options.merge!(opts) }
126
178
  options
127
179
  end
128
180
 
181
+ # 設定ファイルのデータをチェインに追加
182
+ def add_config_chain(dir, theme = nil)
183
+ # テーマ・チェインに追加
184
+ @themes << File.join(dir, '') if theme
185
+
186
+ # config の読込み
187
+ config = read_data(File.join(dir, 'config'))
188
+
189
+ if config
190
+ @options_chain << config
191
+ theme = config[:theme]
192
+ end
193
+
194
+ # macro の読込み
195
+ macro = read_data(File.join(dir, 'macro'))
196
+ @macro_chain << macro if macro && macro.kind_of?(Hash)
197
+
198
+ # locale の読込み
199
+ @locale_paths += Dir[File.expand_path('locales/*.yml', dir)]
200
+
201
+ theme
202
+ end
203
+
204
+ # locale を env情報で更新する
205
+ def update_locale(env = ENV)
206
+ locale ||= env['HTTP_ACCEPT_LANGUAGE']
207
+ locale ||= env['LANG'] if env['LANG']
208
+ locale = locale[0, 2].to_sym if locale
209
+ I18n.locale = locale if I18n.available_locales.include?(locale)
210
+ end
211
+
212
+ # プラグイン・フォルダを取得する
213
+ def plugins_folders
214
+ unless @plugins_folders
215
+ @plugins_folders = ['plugins/', folder(:plugins, :user), folder(:plugins)]
216
+ @plugins_folders.delete nil
217
+ @plugins_folders.reject! { |folder| ! File.directory?(folder) }
218
+
219
+ @themes.each { |theme|
220
+ path = File.join(theme, 'plugins/')
221
+ @plugins_folders.unshift path if File.directory?(path)
222
+ }
223
+ end
224
+
225
+ @plugins_folders
226
+ end
227
+
228
+ # プラグインを読込む
229
+ def load_plugins
230
+ plugins_folders.reverse.each { |folder|
231
+ Dir.glob(File.join(folder, '*')) { |path|
232
+ name = path.gsub(%r[^#{folder}/], '')
233
+ load_plugin(name, path)
234
+ }
235
+ }
236
+ end
237
+
238
+ # プラグインファイルを読込む
239
+ def load_plugin(name, path)
240
+ loaded = false
241
+
242
+ if File.directory?(path)
243
+ path = File.join(path, File.basename(path) + '.rb')
244
+
245
+ if File.exists?(path)
246
+ require_relative(path)
247
+ loaded = true
248
+ end
249
+ elsif path =~ /\.rb$/
250
+ require_relative(File.expand_path(path))
251
+ loaded = true
252
+ end
253
+
254
+ if loaded
255
+ @plugins << name
256
+ end
257
+ end
258
+
259
+ # プラグインを読込む(読込み済みのものは読込まない)
260
+ def require_plugin(plugin)
261
+ return if @plugins.include?(plugin)
262
+
263
+ plugins_folders.reverse.each { |folder|
264
+ path = File.join(folder, plugin)
265
+ load_plugin(folder, path) if File.exist?(path)
266
+ load_plugin(folder, path + '.rb') if File.exist?(path + '.rb')
267
+ }
268
+ end
269
+
129
270
  # テンプレートエンジンを使用できるようにする
130
271
  def use_engine(engine)
131
272
  require engine if engine
@@ -139,6 +280,29 @@ module MemoRack
139
280
  @css_exts ||= Set.new ['css', *@css]
140
281
  end
141
282
 
283
+ # テーマから固定ページのファイルを収集する
284
+ def pages
285
+ unless @pages
286
+ @pages = {}
287
+
288
+ @themes.each { |theme|
289
+ folder = File.join(theme, 'pages/')
290
+
291
+ if Dir.exists?(folder)
292
+ Dir.chdir(folder) { |dir|
293
+ Dir.glob(File.join('**/*')) { |path|
294
+ path_info, ext = split_extname(path)
295
+ path_info = File.join('', path_info)
296
+ @pages[path_info] ||= File.expand_path(path)
297
+ }
298
+ }
299
+ end
300
+ }
301
+ end
302
+
303
+ @pages
304
+ end
305
+
142
306
  # ファイルを探す
143
307
  def file_search(template, options = {}, exts = enable_exts)
144
308
  options = {views: @root}.merge(options)
@@ -161,13 +325,16 @@ module MemoRack
161
325
  return nil
162
326
  end
163
327
 
328
+ dir = options[:views]
329
+ dir = File.join(dir, options[:folder]) if options[:folder]
330
+
164
331
  if exts
165
332
  exts.each { |ext|
166
- path = File.join(options[:views], "#{template}.#{ext}")
333
+ path = File.join(dir, "#{template}.#{ext}")
167
334
  return path if File.exists?(path)
168
335
  }
169
336
  else
170
- path = File.join(options[:views], template)
337
+ path = File.join(dir, template)
171
338
  return path if File.exists?(path)
172
339
  end
173
340
 
@@ -217,7 +384,8 @@ module MemoRack
217
384
  # レイアウトに mustache を適用してテンプレートエンジンでレンダリングする
218
385
  def render_with_mustache(template, engine = :markdown, options = {}, locals = {})
219
386
  begin
220
- mustache_templ = options[:mustache] || 'index.html'
387
+ mustache_templ = []
388
+ mustache_templ << options[:mustache] if options[:mustache]
221
389
 
222
390
  options = @options.merge(options)
223
391
  locals = @locals.merge(locals)
@@ -225,47 +393,160 @@ module MemoRack
225
393
  locals.define_key(:__content__) { |hash, key|
226
394
  if engine
227
395
  render engine, template, options
396
+ elsif locals[:directory?]
397
+ # ディレクトリ
398
+ nil
228
399
  else
229
400
  template
230
401
  end
231
402
  }
232
403
 
233
- locals[:content] = true unless template == :index
404
+ locals[:directory?] = true if template.kind_of?(Pathname) && template.directory?
405
+ locals[:content?] = true unless template == :index || locals[:directory?]
234
406
  locals[:page] = page = Locals[locals[:page] || {}]
235
407
 
408
+ if template.kind_of?(Pathname)
409
+ path = template.to_s
410
+ plugin = PageInfo[path]
411
+ locals[:page] = page = plugin.new(path, page, locals) if plugin
412
+ end
413
+
236
414
  page.define_key(:name) { |hash, key|
237
- unless template == :index
415
+ if hash.kind_of?(PageInfo)
416
+ hash.value(:title)
417
+ elsif template != :index
238
418
  fname = locals[:path_info]
239
419
  fname ||= template.to_s.force_encoding('UTF-8')
240
420
  File.basename(fname)
241
421
  end
242
422
  }
243
423
 
244
- page.define_key(:title) { |hash, key|
245
- page_title = home_title = locals[:title]
246
- page_name = hash[:name]
247
- page_title = "#{page_name} | #{home_title}" if page_name
424
+ # マクロを組込む
425
+ embed_macro(locals, @macro)
426
+
427
+ # HTMLページをレンダリングする
428
+ if engine && engine.to_sym == :html
429
+ unless template.kind_of?(Pathname)
430
+ path = file_search(template, @options, [engine])
431
+ return nil unless path
432
+ template = Pathname.new(path)
433
+ end
434
+
435
+ locals.define_key(:__content__) { |hash, key| }
436
+ return render :mustache, template, {views: @themes}, locals
437
+ end
438
+
439
+ mustache_templ << 'page.html' if locals[:content?]
440
+ mustache_templ << 'index.html'
248
441
 
249
- page_title
442
+ mustache_templ.each { |templ|
443
+ path = file_search(templ, {views: @themes}, nil)
444
+ next unless path
445
+
446
+ path = Pathname.new(path)
447
+ return render :mustache, path, {views: @themes}, locals
250
448
  }
251
449
 
252
- render :mustache, mustache_templ, {views: @themes}, locals
450
+ raise "Not found template #{mustache_templ}"
253
451
  rescue => e
254
452
  e.to_s
255
453
  end
256
454
  end
257
455
 
456
+ # Localsクラス 変換する
457
+ def value_to_locals(value)
458
+ case value
459
+ when Locals
460
+ when Hash
461
+ value = Locals[value]
462
+ else
463
+ value = Locals[]
464
+ end
465
+
466
+ value
467
+ end
468
+
469
+ # マクロを組込む
470
+ def embed_macro(hash, macro, options = {}, locals = hash)
471
+ macro.each { |key, value|
472
+ case value
473
+ when Hash
474
+ if hash[key].kind_of?(Array)
475
+ embed_macro_for_array(hash[key], value, options, locals)
476
+ else
477
+ hash[key] = value_to_locals(hash[key])
478
+ embed_macro(hash[key], value, options, locals)
479
+ end
480
+ when Array
481
+ hash[key] = [] unless hash[key]
482
+ a = hash[key]
483
+
484
+ if a.kind_of?(Array)
485
+ value.each_with_index { |item, index|
486
+ if item.kind_of?(Hash)
487
+ a[index] = value_to_locals(a[index])
488
+ embed_macro(a[index], item, options, locals)
489
+ else
490
+ a[index] = item
491
+ end
492
+ }
493
+ end
494
+ else
495
+ hash.define_key(key) { |hash, key|
496
+ if value
497
+ #render :mustache, value, {}, locals
498
+
499
+ engine = Tilt.new('.mustache', {}) { value }
500
+ engine.render({}, locals).force_encoding('UTF-8')
501
+ end
502
+ }
503
+ end
504
+ }
505
+ end
506
+
507
+ # マクロを配列に組込む
508
+ def embed_macro_for_array(array, macro, options = {}, locals)
509
+ array.each_with_index { |item, index|
510
+ if item.kind_of?(Array)
511
+ embed_macro_for_array(item, macro, options, locals)
512
+ else
513
+ array[index] = value_to_locals(item)
514
+ embed_macro(array[index], macro, options)
515
+ end
516
+ }
517
+ end
518
+
519
+ # メニューをレンダリングする
520
+ def render_menu
521
+ @menu = nil unless @directory_watcher # ファイル監視していない場合はメニューを初期化
522
+ @menu ||= render :markdown, :menu, @options
523
+ end
524
+
525
+ # 固定ページをレンダリングする
526
+ def render_page(path_info, locals = {})
527
+ path_info = path_info.gsub(%r[(/|.html)$], '')
528
+ path = pages[path_info]
529
+ return nil unless path
530
+
531
+ ext = split_extname(path)[1]
532
+ content = render_with_mustache Pathname.new(path), ext, {}, locals
533
+ end
534
+
258
535
  # コンテンツをレンダリングする
259
- def render_content(path_info, locals = {})
536
+ def render_content(path_info, locals = {}, exts = enable_exts)
537
+ path = File.join(@root, path_info)
538
+
539
+ if File.directory?(path)
540
+ return render_with_mustache Pathname.new(path), nil, {}, locals
541
+ end
542
+
260
543
  path, ext = split_extname(path_info)
261
544
 
262
- if @suffix == ''
263
- fullpath = file_search(path_info, @options)
545
+ fullpath = file_search(path_info, @options, exts)
264
546
 
265
- if fullpath
266
- path = path_info
267
- ext = split_extname(fullpath)[1]
268
- end
547
+ if fullpath
548
+ path = path_info
549
+ ext = split_extname(fullpath)[1]
269
550
  end
270
551
 
271
552
  return nil unless ext && Tilt.registered?(ext)
@@ -355,6 +636,17 @@ module MemoRack
355
636
  mdmenu
356
637
  end
357
638
 
639
+ # パスからコンテント名を取得する
640
+ def content_name(path)
641
+ plugin = PageInfo[path]
642
+
643
+ if plugin
644
+ plugin.new(File.expand_path(path, @root))[:title]
645
+ else
646
+ File.basename(path, '.*')
647
+ end
648
+ end
649
+
358
650
  # テンプレート名
359
651
  def self.template_method(name)
360
652
  name.kind_of?(Symbol) && "template_#{name}".to_sym