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.
@@ -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