memorack 0.1.2 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -9,3 +9,4 @@ en:
9
9
  url: "Site URL (default: %{url})"
10
10
  local: "Site URL is output directory"
11
11
  prettify: "prettify URL"
12
+ index: "output index.html of sub directory"
@@ -9,3 +9,4 @@ ja:
9
9
  url: "サイトURL (省略値: %{url})"
10
10
  local: "サイトURLをアウトプットディレクトリにする"
11
11
  prettify: "綺麗なURLになるように生成する"
12
+ index: "サブディレクトリの index.html を出力する"
@@ -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
- super
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
@@ -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 = File.basename(item[:path], '.*')
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|
@@ -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 = render_content(path_info, locals)
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
@@ -0,0 +1,12 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+
4
+ module MemoRack
5
+
6
+ Core.app.instance_eval do
7
+ @formats.each { |format|
8
+ require_plugin(File.join('formats', format))
9
+ }
10
+ end
11
+
12
+ end