docwu 0.0.1 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +25 -13
- data/bin/docwu +5 -0
- data/lib/docwu/config.rb +30 -17
- data/lib/docwu/folder.rb +98 -14
- data/lib/docwu/post.rb +119 -37
- data/lib/docwu/render.rb +42 -5
- data/lib/docwu/route.rb +6 -0
- data/lib/docwu/server.rb +10 -6
- data/lib/docwu/topic.rb +93 -0
- data/lib/docwu/utils.rb +163 -1
- data/lib/docwu/version.rb +1 -1
- data/lib/docwu/worker.rb +57 -56
- data/lib/docwu.rb +94 -5
- metadata +27 -8
- data/lib/docwu/category.rb +0 -0
data/README.md
CHANGED
@@ -1,24 +1,36 @@
|
|
1
1
|
# doc wu
|
2
2
|
|
3
|
-
This project rocks and uses MIT-LICENSE.
|
3
|
+
This project rocks and uses MIT-LICENSE. Docwu mains Documents Work Up!
|
4
4
|
|
5
5
|
## A markdown doc generations
|
6
6
|
|
7
7
|
## 结构
|
8
8
|
|
9
9
|
```
|
10
|
-
workspace
|
10
|
+
- workspace
|
11
11
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
12
|
+
▾ assets/
|
13
|
+
▸ files/
|
14
|
+
▸ images/
|
15
|
+
▾ javascripts/
|
16
|
+
application.js
|
17
|
+
document_folder.js
|
18
|
+
document_post.js
|
19
|
+
▾ stylesheets/
|
20
|
+
application.css
|
21
|
+
document_folder.css
|
22
|
+
document_post.css
|
23
|
+
▸ doc/
|
24
|
+
▾ layouts/
|
25
|
+
▸ partials/
|
26
|
+
folder.mustache
|
27
|
+
post.mustache
|
28
|
+
▾ pages/
|
29
|
+
index.markdown
|
30
|
+
.gitignore
|
31
|
+
config.yml
|
32
|
+
Gemfile
|
33
|
+
Gemfile.lock
|
34
|
+
worker*
|
23
35
|
|
24
36
|
```
|
data/bin/docwu
ADDED
data/lib/docwu/config.rb
CHANGED
@@ -12,34 +12,47 @@ module Docwu
|
|
12
12
|
end
|
13
13
|
end
|
14
14
|
|
15
|
-
#
|
16
|
-
# src_paths
|
17
|
-
# asset_paths
|
18
|
-
# layout_paths
|
19
|
-
# output_path
|
20
|
-
#
|
21
15
|
class Config
|
22
|
-
attr_reader :src_paths, :asset_paths, :layout_paths, :output_path, :data
|
16
|
+
# attr_reader :src_paths, :asset_paths, :layout_paths, :output_path, :data
|
23
17
|
|
24
|
-
|
25
|
-
|
18
|
+
attr_reader :routes, :params, :worker, :workspace, :docwu_env, :logger
|
19
|
+
|
20
|
+
def logger= a
|
21
|
+
@logger ||= (a || ::Logger.new(STDOUT))
|
22
|
+
end
|
23
|
+
|
24
|
+
def routes= a
|
25
|
+
@routes ||= a
|
26
|
+
end
|
27
|
+
|
28
|
+
def params= a={}
|
29
|
+
@params ||= a
|
26
30
|
end
|
27
31
|
|
28
|
-
def
|
29
|
-
@
|
32
|
+
def worker= a
|
33
|
+
@worker ||= a
|
30
34
|
end
|
31
35
|
|
32
|
-
def
|
33
|
-
@
|
36
|
+
def workspace= a
|
37
|
+
@workspace ||= a
|
34
38
|
end
|
35
39
|
|
36
|
-
def
|
37
|
-
@
|
40
|
+
def docwu_env= a
|
41
|
+
@docwu_env ||= 'development'
|
38
42
|
end
|
39
43
|
|
40
|
-
def
|
41
|
-
@
|
44
|
+
def topics_path
|
45
|
+
@topics_path ||= ("#{self.workspace}/topics")
|
42
46
|
end
|
47
|
+
|
48
|
+
def layouts_path
|
49
|
+
@layouts_path ||= ("#{self.workspace}/layouts")
|
50
|
+
end
|
51
|
+
|
52
|
+
def deploy_path
|
53
|
+
@deploy_path ||= ("#{self.workspace}/_deploy")
|
54
|
+
end
|
55
|
+
|
43
56
|
end
|
44
57
|
end
|
45
58
|
|
data/lib/docwu/folder.rb
CHANGED
@@ -1,42 +1,111 @@
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
1
2
|
module Docwu
|
2
3
|
class Folder
|
3
4
|
# 一个文件夹下面可能会有很多文件或文件夹的
|
4
|
-
attr_reader :posts, :folders, :parent, :
|
5
|
+
attr_reader :posts, :folders, :parent, :worker, :name,
|
6
|
+
:dest, :path, :src, :url, :index_post, :index_dest,
|
7
|
+
:parents, :content_data
|
5
8
|
|
6
9
|
def initialize attrs={}
|
7
|
-
@path = attrs[:path]
|
8
10
|
@worker = attrs[:worker]
|
9
11
|
@parent = attrs[:parent]
|
10
|
-
@house = attrs[:house]
|
11
12
|
|
12
|
-
@
|
13
|
+
@parents = if @parent.nil?
|
14
|
+
[]
|
15
|
+
else
|
16
|
+
@parent.parents.dup << @parent
|
17
|
+
end
|
18
|
+
|
19
|
+
@src = attrs[:src]
|
20
|
+
@path = attrs[:path]
|
21
|
+
@url = "/#{@path}/index.html"
|
22
|
+
|
23
|
+
@name = ::Docwu::Utils.filename(@path)
|
24
|
+
|
25
|
+
@dest = "#{self.worker.deploy_path}/#{self.path}"
|
26
|
+
@index_dest = "#{self.dest}/index.html"
|
27
|
+
# -------------------------------------
|
13
28
|
|
14
29
|
@posts = []
|
15
30
|
@folders = []
|
16
31
|
|
17
|
-
::Dir.glob("#{self.
|
18
|
-
|
32
|
+
::Dir.glob("#{self.src}/*").each do |_src|
|
33
|
+
_name = "#{_src.sub("#{self.src}/", '')}"
|
34
|
+
|
35
|
+
if File.exists?(_src)
|
36
|
+
if File.file?(_src) # 如果一个文件
|
37
|
+
_post = ::Docwu::Post.new(:src => _src, :parent => self, :worker => self.worker, :path => "#{self.path}/#{_name}")
|
19
38
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
39
|
+
if _post.index?
|
40
|
+
@index_post = _post
|
41
|
+
else
|
42
|
+
@posts << _post
|
43
|
+
end
|
44
|
+
elsif File.directory?(_src) # 如果是一个文件夹
|
45
|
+
@folders << self.class.new(:src => _src, :parent => self, :worker => self.worker, :path => "#{self.path}/#{_name}")
|
25
46
|
end
|
26
47
|
end
|
27
48
|
end
|
49
|
+
|
50
|
+
self.posts.sort! { |a, b| b.ranking <=> a.ranking }
|
51
|
+
self.posts.sort! { |a, b| b.datetime <=> a.datetime }
|
52
|
+
|
53
|
+
# TODO: 是否从index文件中读取data呢?
|
54
|
+
end
|
55
|
+
|
56
|
+
def parent_datas
|
57
|
+
self.parents.map(&:to_data)
|
58
|
+
end
|
59
|
+
|
60
|
+
# 转为数据
|
61
|
+
def to_data
|
62
|
+
{
|
63
|
+
'name' => self.name,
|
64
|
+
'url' => self.url,
|
65
|
+
'title' => self.name,
|
66
|
+
'folders' => self.folders.map(&:to_data),
|
67
|
+
'posts' => self.posts.map(&:to_data)
|
68
|
+
}
|
69
|
+
end
|
70
|
+
|
71
|
+
def index_page_data
|
72
|
+
if self.has_index?
|
73
|
+
self.index_post.page_data
|
74
|
+
else
|
75
|
+
{}
|
76
|
+
end
|
28
77
|
end
|
29
78
|
|
30
|
-
def generate
|
79
|
+
def generate
|
80
|
+
_prepare_data
|
81
|
+
|
82
|
+
# TODO: index : 需要生成首页!
|
83
|
+
_template = if self.has_index?
|
84
|
+
self.worker.layouts[self.index_post.layout]
|
85
|
+
end
|
86
|
+
|
87
|
+
_template ||= self.worker.layouts['folder']
|
88
|
+
|
89
|
+
::Docwu::Render.generate(
|
90
|
+
:content_data => self.content_data,
|
91
|
+
:dest => self.index_dest,
|
92
|
+
:template => _template
|
93
|
+
)
|
94
|
+
|
31
95
|
self.folders.each do |folder|
|
32
|
-
folder.generate
|
96
|
+
folder.generate
|
33
97
|
end
|
34
98
|
|
35
99
|
self.posts.each do |post|
|
36
|
-
post.generate
|
100
|
+
post.generate
|
37
101
|
end
|
38
102
|
end
|
39
103
|
|
104
|
+
# 有首页文件了
|
105
|
+
def has_index?
|
106
|
+
!!(self.index_post)
|
107
|
+
end
|
108
|
+
|
40
109
|
def folder?
|
41
110
|
true
|
42
111
|
end
|
@@ -47,5 +116,20 @@ module Docwu
|
|
47
116
|
|
48
117
|
private
|
49
118
|
|
119
|
+
def _prepare_data
|
120
|
+
@content_data = ::Docwu::Utils.hash_deep_merge(self.worker.data, {
|
121
|
+
'reader' => {
|
122
|
+
'folder' => self.to_data,
|
123
|
+
'folders' => self.parent_datas
|
124
|
+
}
|
125
|
+
})
|
126
|
+
|
127
|
+
# puts ""
|
128
|
+
# puts ""
|
129
|
+
# puts ""
|
130
|
+
# puts ""
|
131
|
+
# pp @content_data
|
132
|
+
end
|
133
|
+
|
50
134
|
end
|
51
135
|
end
|
data/lib/docwu/post.rb
CHANGED
@@ -1,61 +1,132 @@
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
1
2
|
module Docwu
|
2
3
|
class Post
|
3
4
|
# 一个文件夹下面可能会有很多文件或文件夹的
|
4
|
-
attr_reader :parent,
|
5
|
+
attr_reader :parent,
|
6
|
+
:worker, # worker对象
|
7
|
+
:content_data,
|
8
|
+
:dest, # 目标地址
|
9
|
+
:path, # 访问地址
|
10
|
+
:src, # 原文件地址
|
11
|
+
:url, # URL 地址
|
12
|
+
:content_type,
|
13
|
+
:name,
|
14
|
+
:file_name, # 文件名
|
15
|
+
:datetime,
|
16
|
+
:ranking
|
17
|
+
|
18
|
+
def parents
|
19
|
+
if self.parent.nil?
|
20
|
+
[]
|
21
|
+
else
|
22
|
+
self.parent.parents.dup << self.parent
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def parent_datas
|
27
|
+
self.parents.map(&:to_data)
|
28
|
+
end
|
5
29
|
|
6
30
|
def initialize attrs={}
|
7
|
-
@path = attrs[:path]
|
8
|
-
@house = attrs[:house]
|
9
31
|
@parent = attrs[:parent]
|
32
|
+
|
10
33
|
@worker = attrs[:worker]
|
11
34
|
|
12
|
-
@
|
35
|
+
@src = attrs[:src]
|
13
36
|
|
14
37
|
_parse_content = self.parse_content
|
15
38
|
|
16
|
-
|
39
|
+
# 将合并来自worker的数据
|
40
|
+
@content_data = ::Docwu::Utils.hash_deep_merge(self.worker.data, 'page' => _parse_content[:data]) # 来自页面的数据
|
41
|
+
|
42
|
+
@content_type = @content_data['content_type'] || 'html'
|
43
|
+
|
44
|
+
_extend_name = case self.content_type
|
45
|
+
when 'html'
|
46
|
+
'html'
|
47
|
+
else
|
48
|
+
'html'
|
49
|
+
end
|
50
|
+
|
51
|
+
# URL ---------------------------------
|
52
|
+
_filename_extless = ::Docwu::Utils.filename_extless(attrs[:path])
|
53
|
+
|
54
|
+
@path = "#{_filename_extless}.#{_extend_name}"
|
55
|
+
@url = "/#{@path}"
|
56
|
+
@dest = "#{self.worker.deploy_path}/#{self.path}"
|
57
|
+
|
58
|
+
@file_name = ::Docwu::Utils.filename(_filename_extless)
|
17
59
|
|
18
|
-
self.
|
60
|
+
@name = self.file_name
|
61
|
+
@datetime = self.page_data['datetime'] # 创建时间
|
62
|
+
@ranking = self.page_data['ranking'].to_i # 创建时间
|
63
|
+
|
64
|
+
# puts "post to: -----------------> desc: #{self.dest}"
|
65
|
+
# puts " src: #{self.src}"
|
66
|
+
# puts " path: #{self.path}"
|
67
|
+
# puts " url: #{self.url}"
|
68
|
+
# -------------------------------------
|
69
|
+
end
|
70
|
+
|
71
|
+
def template
|
72
|
+
self.worker.layouts[self.layout] || self.worker.layouts['post'] || self.worker.layouts['application']
|
73
|
+
end
|
74
|
+
|
75
|
+
# 是否是首页?
|
76
|
+
def index?
|
77
|
+
self.file_name == 'index'
|
19
78
|
end
|
20
79
|
|
21
80
|
def layout
|
22
|
-
self.
|
81
|
+
self.page_data['layout']
|
82
|
+
end
|
83
|
+
|
84
|
+
def outline
|
85
|
+
@outline ||= self.page_data['outline'].to_s
|
86
|
+
end
|
87
|
+
|
88
|
+
def to_data
|
89
|
+
introduction_size = 32
|
90
|
+
|
91
|
+
introduction = "#{self.outline[0, introduction_size]}#{' ...' if self.outline.size > introduction_size}"
|
92
|
+
|
93
|
+
{
|
94
|
+
'name' => self.name,
|
95
|
+
'url' => self.url,
|
96
|
+
'title' => self.title,
|
97
|
+
'outline' => self.outline,
|
98
|
+
'introduction' => introduction
|
99
|
+
}
|
100
|
+
end
|
101
|
+
|
102
|
+
# 页面数据
|
103
|
+
def page_data
|
104
|
+
self.content_data['page'] ||= {}
|
105
|
+
end
|
106
|
+
|
107
|
+
def title
|
108
|
+
self.page_data['title'] || self.url
|
23
109
|
end
|
24
110
|
|
25
111
|
# 渲染
|
26
|
-
def generate
|
112
|
+
def generate
|
113
|
+
_prepare_data
|
114
|
+
|
27
115
|
_parse_content = self.parse_content
|
28
116
|
|
29
117
|
_content_text = _parse_content[:text]
|
30
118
|
|
31
|
-
_template = ::Docwu::Utils.read_file(self.layout)
|
32
|
-
|
33
119
|
_path = self.path
|
34
|
-
_dest = self.dest
|
35
|
-
|
36
|
-
puts " -> generate post: form #{_path} to #{_dest}"
|
37
|
-
puts " layout: #{self.layout}"
|
120
|
+
_dest = self.dest
|
38
121
|
|
39
122
|
::Docwu::Render.generate(
|
40
123
|
:content_text => _content_text,
|
41
124
|
:content_data => self.content_data,
|
42
125
|
:dest => _dest,
|
43
|
-
:template =>
|
126
|
+
:template => self.template
|
44
127
|
)
|
45
128
|
end
|
46
129
|
|
47
|
-
def dest space
|
48
|
-
_dest = "#{self.worker.output_path}"
|
49
|
-
|
50
|
-
if space
|
51
|
-
_dest << "/#{space}"
|
52
|
-
end
|
53
|
-
|
54
|
-
_dest << self.dir
|
55
|
-
|
56
|
-
_dest
|
57
|
-
end
|
58
|
-
|
59
130
|
def folder?
|
60
131
|
false
|
61
132
|
end
|
@@ -63,23 +134,34 @@ module Docwu
|
|
63
134
|
def post?
|
64
135
|
true
|
65
136
|
end
|
66
|
-
|
137
|
+
|
67
138
|
# 解析正文
|
68
139
|
def parse_content
|
69
|
-
_content = ::File.read(self.
|
140
|
+
_content = ::File.read(self.src)
|
141
|
+
|
142
|
+
::Docwu::Utils.parse_marked_content(_content)
|
143
|
+
end
|
144
|
+
|
145
|
+
def has_folder?
|
146
|
+
self.parent.is_a?(::Docwu::Folder)
|
147
|
+
end
|
148
|
+
|
149
|
+
private
|
70
150
|
|
71
|
-
|
72
|
-
|
151
|
+
def _prepare_data
|
152
|
+
self.content_data['reader'] ||= {}
|
73
153
|
|
74
|
-
|
154
|
+
_data = {
|
155
|
+
'folders' => self.parent_datas,
|
156
|
+
'post' => self.to_data
|
157
|
+
}
|
75
158
|
|
76
|
-
if
|
77
|
-
|
78
|
-
# 从上下文中读取配置
|
79
|
-
_content_data.merge!(::YAML.load(_parse_content[1]))
|
159
|
+
if self.has_folder?
|
160
|
+
(_data['folder'] ||= {}).merge!(self.parent.to_data)
|
80
161
|
end
|
81
162
|
|
82
|
-
|
163
|
+
# 合并, datas
|
164
|
+
self.content_data['reader'].merge!(_data)
|
83
165
|
end
|
84
166
|
end
|
85
167
|
end
|
data/lib/docwu/render.rb
CHANGED
@@ -1,3 +1,8 @@
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
2
|
+
require 'redcarpet'
|
3
|
+
require 'coderay'
|
4
|
+
require "nokogiri"
|
5
|
+
|
1
6
|
module Docwu
|
2
7
|
class Render
|
3
8
|
class << self
|
@@ -6,30 +11,62 @@ module Docwu
|
|
6
11
|
end
|
7
12
|
end
|
8
13
|
|
14
|
+
#
|
15
|
+
# usage:
|
16
|
+
# ::Docwu::Render.generate(
|
17
|
+
# :content_data => ''
|
18
|
+
# )
|
19
|
+
# options:
|
20
|
+
# - content_data
|
21
|
+
# - content_text
|
22
|
+
# - dest
|
23
|
+
# - template
|
24
|
+
#
|
9
25
|
def generate(options={})
|
10
26
|
content_data = options[:content_data] || {}
|
11
27
|
content_text = options[:content_text] || ''
|
12
28
|
content_result = ''
|
13
29
|
dest = options[:dest]
|
30
|
+
template = options[:template]
|
14
31
|
|
15
32
|
# 读取标记类型
|
16
33
|
marktype = (content_data['marktype'] || 'markdown').to_s
|
17
|
-
|
34
|
+
|
35
|
+
# 目录
|
36
|
+
_catalogs = []
|
18
37
|
|
19
38
|
case marktype
|
20
39
|
when 'markdown'
|
21
40
|
_mark_options = [:hard_wrap, :autolink, :no_intraemphasis, :fenced_code, :gh_blockcode]
|
22
41
|
|
23
|
-
|
42
|
+
_html = ::RedcarpetCompat.new(content_text, *_mark_options).to_html
|
43
|
+
|
44
|
+
# 获取一个html代码的目录结果
|
45
|
+
_catalogs_result = ::Docwu::Utils.html_catalogable(_html)
|
46
|
+
|
47
|
+
_catalogs = _catalogs_result['catalogs']
|
48
|
+
|
49
|
+
content_result << ::Docwu::Utils.syntax_highlighter(_catalogs_result['html'])
|
24
50
|
else
|
25
51
|
# FIXME: no
|
26
52
|
end
|
27
53
|
|
28
|
-
content_data['
|
54
|
+
content_data['page'] ||= {}
|
55
|
+
|
56
|
+
# 正文
|
57
|
+
content_data['page']['content'] = content_result
|
58
|
+
content_data['page']['content_present?'] = content_result.size > 0
|
59
|
+
|
60
|
+
# 目录
|
61
|
+
content_data['page']['catalogs'] = _catalogs
|
62
|
+
|
63
|
+
::Docwu::Utils.formated_hashed!(content_data)
|
64
|
+
|
65
|
+
# pp content_data
|
66
|
+
# puts "#{template}"
|
29
67
|
|
30
|
-
puts " --------------------> write to: #{dest}, #{content_result}"
|
31
68
|
# 页面的内容
|
32
|
-
|
69
|
+
::Docwu::Utils.write_file dest, ::MustacheRender::Mustache.render(template, content_data)
|
33
70
|
end
|
34
71
|
|
35
72
|
end
|
data/lib/docwu/route.rb
ADDED
data/lib/docwu/server.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
1
2
|
# http://tobyho.com/2009/09/16/http-server-in-5-lines-with/
|
2
3
|
# https://github.com/rack/rack/blob/master/lib/rack/handler/thin.rb
|
3
4
|
# https://github.com/macournoyer/thin/blob/master/lib/thin/server.rb
|
@@ -10,21 +11,24 @@ module Docwu
|
|
10
11
|
#
|
11
12
|
# Rack::Handler::Thin.run(staticMe, :port => 8080
|
12
13
|
|
14
|
+
require 'thin'
|
13
15
|
require 'rack'
|
14
16
|
|
15
|
-
def self.process(options={})
|
16
|
-
options['destination'] ||= ::Docwu.config.
|
17
|
+
def self.process(options={}, &block)
|
18
|
+
options['destination'] ||= ::Docwu.config.deploy_path
|
17
19
|
destination = options['destination']
|
18
20
|
FileUtils.mkdir_p(destination)
|
19
21
|
|
20
|
-
options['port'] ||= 5656
|
21
|
-
options['host'] ||= '0.0.0.0'
|
22
|
-
|
23
22
|
staticMe = Rack::Builder.new do
|
24
23
|
run Rack::Directory.new(destination)
|
25
24
|
end
|
26
25
|
|
27
|
-
|
26
|
+
pp options
|
27
|
+
|
28
|
+
::Thin::Server.start(options.delete(:Host), options.delete(:Port), staticMe, options, &block)
|
29
|
+
|
30
|
+
# Rack::Handler::Thin.run(staticMe, options)
|
31
|
+
|
28
32
|
# Rack::Handler::WEBrick.run(staticMe, :Port => options['port'], :Host => options['host'])
|
29
33
|
# Rack::Handler::Mongrel.run(staticMe, :Port => options['port'], :Host => options['host'])
|
30
34
|
end
|
data/lib/docwu/topic.rb
ADDED
@@ -0,0 +1,93 @@
|
|
1
|
+
module Docwu
|
2
|
+
class Topic
|
3
|
+
attr_reader :worker, :dest, :path, :src, :url, :content_data, :file_name, :name, :title
|
4
|
+
|
5
|
+
def initialize attrs={}
|
6
|
+
@worker = attrs[:worker]
|
7
|
+
|
8
|
+
@path = attrs[:path]
|
9
|
+
@src = attrs[:src]
|
10
|
+
|
11
|
+
_parse_content = self.parse_content
|
12
|
+
|
13
|
+
# 将合并来自worker的数据
|
14
|
+
@content_data = ::Docwu::Utils.hash_deep_merge(self.worker.data, 'page' => _parse_content[:data]) # 来自页面的数据
|
15
|
+
|
16
|
+
# URL ---------------------------------
|
17
|
+
_filename_extless = ::Docwu::Utils.filename_extless(self.path)
|
18
|
+
|
19
|
+
@url = "/#{@path}"
|
20
|
+
@dest = "#{self.worker.deploy_path}/#{self.path}"
|
21
|
+
|
22
|
+
@file_name = ::Docwu::Utils.filename(_filename_extless)
|
23
|
+
|
24
|
+
@name = self.content_data['page']['name'] || self.file_name
|
25
|
+
|
26
|
+
# -------------------------------------
|
27
|
+
end
|
28
|
+
|
29
|
+
# 页面数据
|
30
|
+
def page_data
|
31
|
+
self.content_data['page'] ||= {}
|
32
|
+
end
|
33
|
+
|
34
|
+
def title
|
35
|
+
self.page_data['title'] || self.url
|
36
|
+
end
|
37
|
+
|
38
|
+
def url
|
39
|
+
self.path
|
40
|
+
end
|
41
|
+
|
42
|
+
def to_data
|
43
|
+
{
|
44
|
+
'name' => self.name,
|
45
|
+
'url' => self.url,
|
46
|
+
'title' => self.title
|
47
|
+
}
|
48
|
+
end
|
49
|
+
|
50
|
+
def generate
|
51
|
+
_prepare_data
|
52
|
+
|
53
|
+
_parse_content = self.parse_content
|
54
|
+
|
55
|
+
_content_text = _parse_content[:text]
|
56
|
+
|
57
|
+
::Docwu::Render.generate(
|
58
|
+
:content_text => _content_text,
|
59
|
+
:content_data => self.content_data,
|
60
|
+
:dest => self.dest,
|
61
|
+
:template => self.template
|
62
|
+
)
|
63
|
+
end
|
64
|
+
|
65
|
+
def layout
|
66
|
+
self.page_data['layout']
|
67
|
+
end
|
68
|
+
|
69
|
+
def template
|
70
|
+
self.worker.layouts[self.layout] || self.worker.layouts['topic'] || self.worker.layouts['application']
|
71
|
+
end
|
72
|
+
|
73
|
+
# 解析正文
|
74
|
+
def parse_content
|
75
|
+
_content = ::File.read(self.src)
|
76
|
+
|
77
|
+
::Docwu::Utils.parse_marked_content(_content)
|
78
|
+
end
|
79
|
+
|
80
|
+
private
|
81
|
+
|
82
|
+
def _prepare_data
|
83
|
+
self.content_data['reader'] ||= {}
|
84
|
+
|
85
|
+
_data = {
|
86
|
+
'topic' => self.to_data
|
87
|
+
}
|
88
|
+
|
89
|
+
# 合并, datas
|
90
|
+
self.content_data['reader'].merge!(_data)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
data/lib/docwu/utils.rb
CHANGED
@@ -1,12 +1,64 @@
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
1
2
|
module Docwu
|
2
3
|
class Utils
|
3
4
|
class << self
|
5
|
+
def hash_deep_merge(hash, other_hash)
|
6
|
+
hash.merge(other_hash) do |key, oldval, newval|
|
7
|
+
oldval = oldval.to_hash if oldval.respond_to?(:to_hash)
|
8
|
+
newval = newval.to_hash if newval.respond_to?(:to_hash)
|
9
|
+
oldval.class.to_s == 'Hash' && newval.class.to_s == 'Hash' ? self.hash_deep_merge(oldval, newval) : newval
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def hash_deep_merge!(hash, other_hash)
|
14
|
+
hash.replace(self.hash_deep_merge(hash, other_hash))
|
15
|
+
end
|
16
|
+
|
17
|
+
def formated_hashed! hash={}
|
18
|
+
hash.replace(self.formated_hashed(hash))
|
19
|
+
end
|
20
|
+
|
21
|
+
# 将hash中所有非hash的类型,转为hash, 以便前端调用
|
22
|
+
def formated_hashed hash={}
|
23
|
+
_res = {}
|
24
|
+
|
25
|
+
hash.each do |key, value|
|
26
|
+
if value.is_a?(Array)
|
27
|
+
_res[key] = value.map do |_val|
|
28
|
+
if _val.is_a?(Hash)
|
29
|
+
self.formated_hashed(_val)
|
30
|
+
else
|
31
|
+
{'value' => _val}
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
_res["#{key}_any?"] = value.any?
|
36
|
+
_res["#{key}_count"] = value.size
|
37
|
+
|
38
|
+
elsif value.is_a?(Hash)
|
39
|
+
_res[key] = self.formated_hashed(value)
|
40
|
+
else
|
41
|
+
_res[key] = value
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
_res
|
46
|
+
end
|
47
|
+
|
48
|
+
# 获取文件名
|
49
|
+
def filename path=''
|
50
|
+
path.split('/').last
|
51
|
+
end
|
52
|
+
|
53
|
+
def filename_extless _path=''
|
54
|
+
_path.chomp(File.extname(_path))
|
55
|
+
end
|
4
56
|
|
5
57
|
def read_file path
|
6
58
|
::File.read(path)
|
7
59
|
end
|
8
60
|
|
9
|
-
def write_file
|
61
|
+
def write_file dst, content=''
|
10
62
|
::FileUtils.mkdir_p(::File.dirname(dst))
|
11
63
|
|
12
64
|
file = ::File.new(dst, 'w')
|
@@ -20,7 +72,117 @@ module Docwu
|
|
20
72
|
::FileUtils.cp_r(src, dst)
|
21
73
|
end
|
22
74
|
|
75
|
+
def syntax_highlighter(html)
|
76
|
+
doc = ::Nokogiri::HTML(html)
|
77
|
+
|
78
|
+
doc.search("//pre").each do |pre|
|
79
|
+
lang = pre.attr('lang')
|
80
|
+
|
81
|
+
if lang
|
82
|
+
_lang_class = pre.attr('class').to_s.split(' ').select {|_itm| _itm.include?('lang-') }.first
|
83
|
+
|
84
|
+
if _lang_class
|
85
|
+
lang = _lang_class.gsub('lang-', '')
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
# debugger
|
90
|
+
if pre_code=pre.css('code')
|
91
|
+
lang = pre_code.attr('class').to_s
|
92
|
+
end
|
93
|
+
|
94
|
+
unless lang
|
95
|
+
lang = :text
|
96
|
+
end
|
97
|
+
|
98
|
+
text = pre.text.rstrip
|
99
|
+
|
100
|
+
begin
|
101
|
+
pre.replace ::CodeRay.scan(text, lang).div.to_s
|
102
|
+
rescue Exception => error
|
103
|
+
# TODO: error log
|
104
|
+
# puts "#{__FILE__} syntax_highlighter error: \ntext => #{text} \nlang => #{lang}\n origin error:#{error}"
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
doc.css('body').inner_html.to_s
|
109
|
+
end
|
110
|
+
|
111
|
+
# 解析 mark
|
112
|
+
def parse_marked_content src_content=''
|
113
|
+
_content_text = ''
|
114
|
+
_content_data = {}
|
115
|
+
|
116
|
+
# 读取页面的配置
|
117
|
+
content_lines = src_content.split(/\n/) # 根据换行分割
|
118
|
+
|
119
|
+
_data_lines = []
|
120
|
+
_text_lines = []
|
121
|
+
|
122
|
+
_data_num_a = -1
|
123
|
+
_data_num_b = -1
|
124
|
+
|
125
|
+
content_lines.each_with_index do |line, index|
|
126
|
+
if line =~ /--+/
|
127
|
+
if _data_num_a == -1
|
128
|
+
_data_num_a = index
|
129
|
+
elsif _data_num_b == -1
|
130
|
+
_data_num_b = index
|
131
|
+
else
|
132
|
+
break
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
if _data_num_a > -1 && _data_num_b > -1
|
138
|
+
# 说明有配置信息
|
139
|
+
_yaml = ::YAML.load(content_lines[_data_num_a + 1, _data_num_b -1].join("\n"))
|
140
|
+
|
141
|
+
if _yaml.is_a?(Hash)
|
142
|
+
_content_data.merge!(_yaml)
|
143
|
+
end
|
144
|
+
|
145
|
+
_content_text = content_lines[_data_num_b + 1, content_lines.size].join("\n")
|
146
|
+
else # 无页面配置信息
|
147
|
+
_content_text = src_content
|
148
|
+
end
|
149
|
+
|
150
|
+
{:data => _content_data, :text => _content_text}
|
151
|
+
|
152
|
+
end
|
153
|
+
|
154
|
+
# 获取一个html代码的目录结果
|
155
|
+
def html_catalogable html=''
|
156
|
+
doc = ::Nokogiri::HTML(html)
|
157
|
+
|
158
|
+
paths = doc.xpath('//h1|//h2|//h3|//h4|//h5|//h6')
|
159
|
+
|
160
|
+
index = 1
|
161
|
+
|
162
|
+
catalogs = paths.map do |path|
|
163
|
+
_name = path.name
|
164
|
+
_text = path.text
|
165
|
+
|
166
|
+
_anchor = "markup-#{_name}-#{index}"
|
167
|
+
|
168
|
+
index += 1
|
169
|
+
|
170
|
+
path.replace("<#{_name}><a name='#{_anchor}'></a>#{_text}</#{_name}>")
|
171
|
+
|
172
|
+
{
|
173
|
+
'text' => _text,
|
174
|
+
'name' => _name,
|
175
|
+
'anchor' => _anchor
|
176
|
+
}
|
177
|
+
end
|
178
|
+
|
179
|
+
{
|
180
|
+
'catalogs' => catalogs,
|
181
|
+
'html' => doc.css('body').inner_html.to_s
|
182
|
+
}
|
183
|
+
end
|
23
184
|
end
|
185
|
+
|
24
186
|
end
|
25
187
|
end
|
26
188
|
|
data/lib/docwu/version.rb
CHANGED
data/lib/docwu/worker.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
# -*- encoding : utf-8 -*-
|
2
|
+
require 'date'
|
2
3
|
module Docwu
|
3
4
|
class Worker
|
4
5
|
|
@@ -26,95 +27,95 @@ module Docwu
|
|
26
27
|
# - layouts:
|
27
28
|
# - application.mustache
|
28
29
|
#
|
29
|
-
# data:
|
30
|
-
# src_paths
|
31
|
-
# asset_paths
|
32
|
-
# layout_paths
|
33
|
-
# output_path
|
34
|
-
#
|
35
|
-
attr_reader :src_paths, # 源文件地址们
|
36
|
-
:output_path, # 要输出的路径
|
37
|
-
:folders, # 项目文件夹们
|
38
|
-
:asset_paths, # assets路径
|
39
|
-
:layouts, # layouts路径
|
40
|
-
:data # 数据
|
41
30
|
|
42
|
-
|
43
|
-
@data = attrs[:data] || Docwu.config.data || {}
|
44
|
-
@src_paths = attrs[:src_paths] || Docwu.config.src_paths
|
31
|
+
attr_reader :layouts, :data, :deploy_path, :folders, :topics
|
45
32
|
|
46
|
-
|
47
|
-
@
|
48
|
-
@layouts = {}
|
33
|
+
def initialize
|
34
|
+
@deploy_path = ::Docwu.config.deploy_path # 部署路径
|
49
35
|
|
50
|
-
|
51
|
-
|
36
|
+
@data = {
|
37
|
+
'worker' => {
|
38
|
+
'copyright' => {
|
39
|
+
'year' => ::Date.today.year,
|
40
|
+
'content' => 'document world util',
|
41
|
+
'name' => 'Doc WU'
|
42
|
+
}
|
43
|
+
}
|
44
|
+
}
|
52
45
|
|
53
|
-
(
|
54
|
-
if File.exists?(_path) && File.directory?(_path)
|
55
|
-
@asset_paths < _path
|
56
|
-
end
|
57
|
-
end
|
46
|
+
::Docwu::Utils.hash_deep_merge!(@data['worker'], ::Docwu.config.worker)
|
58
47
|
|
59
|
-
|
48
|
+
self.data['page'] ||= {}
|
60
49
|
|
61
|
-
|
62
|
-
@src_paths.each do |_space, _path|
|
63
|
-
_asset_path = "#{_path}/assets"
|
50
|
+
self.data['reader'] ||= {}
|
64
51
|
|
65
|
-
|
66
|
-
|
67
|
-
|
52
|
+
# 关于目录
|
53
|
+
@folders = []
|
54
|
+
@layouts = {}
|
55
|
+
@topics = []
|
68
56
|
|
69
|
-
|
57
|
+
# 布局模板
|
58
|
+
::Docwu.config.routes['layouts'].each do |name, path|
|
59
|
+
_path = "#{::Docwu.config.layouts_path}/#{path}"
|
70
60
|
|
71
|
-
if File.exists?(
|
72
|
-
|
61
|
+
if File.exists?(_path) && File.file?(_path)
|
62
|
+
@layouts[name] = File.read(_path)
|
73
63
|
end
|
64
|
+
end
|
74
65
|
|
75
|
-
|
76
|
-
|
77
|
-
|
66
|
+
# 原文件, 目标路径
|
67
|
+
::Docwu.config.routes['topics'].each do |src, path|
|
68
|
+
_src_path = "#{::Docwu.config.topics_path}/#{src}"
|
78
69
|
|
79
|
-
if File.exists?(
|
80
|
-
@
|
70
|
+
if File.exists?(_src_path) && File.file?(_src_path)
|
71
|
+
@topics << ::Docwu::Topic.new(:src => _src_path, :path => path, :worker => self)
|
81
72
|
end
|
82
73
|
end
|
83
74
|
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
75
|
+
# 计算出当前所有的 folders 源, 目标
|
76
|
+
::Docwu.config.routes['folders'].each do |_src, _path|
|
77
|
+
_folder_src = "#{plain_path("/#{_src}")}"
|
78
|
+
|
79
|
+
if File.exists?(_folder_src) && File.directory?(_folder_src)
|
80
|
+
@folders << ::Docwu::Folder.new(:src => _folder_src, :worker => self, :path => _path)
|
89
81
|
end
|
90
82
|
end
|
91
83
|
|
92
|
-
|
84
|
+
# TODO: add 更多的全局数据
|
85
|
+
|
86
|
+
self.data['reader'].merge!(
|
87
|
+
'global' => {
|
88
|
+
'folders' => self.folders_data
|
89
|
+
}
|
90
|
+
)
|
93
91
|
|
94
|
-
# puts self.output_path
|
95
|
-
# puts self.folders
|
96
|
-
# puts self.layouts
|
97
|
-
# puts self.asset_paths
|
98
92
|
end
|
99
93
|
|
100
94
|
# 输出:
|
101
95
|
# TODO: 先生成临时目录, 然后 -> deploy
|
102
96
|
def generate
|
103
97
|
# 删除要输出的路径
|
104
|
-
FileUtils.rm_rf(self.
|
98
|
+
FileUtils.rm_rf(self.deploy_path)
|
105
99
|
|
106
100
|
# 复制 assets 文件进去
|
107
|
-
self.
|
108
|
-
|
101
|
+
FileUtils.cp_r("#{plain_path('/assets')}", "#{self.deploy_path}/")
|
102
|
+
|
103
|
+
self.folders.each do |folder|
|
104
|
+
folder.generate
|
109
105
|
end
|
110
106
|
|
111
|
-
self.
|
112
|
-
|
107
|
+
self.topics.each do |topic|
|
108
|
+
topic.generate
|
113
109
|
end
|
110
|
+
end
|
114
111
|
|
112
|
+
def plain_path(path)
|
113
|
+
"#{::Docwu.config.workspace}#{path}"
|
115
114
|
end
|
116
115
|
|
117
|
-
|
116
|
+
def folders_data
|
117
|
+
self.folders.map(&:to_data)
|
118
|
+
end
|
118
119
|
|
119
120
|
end
|
120
121
|
end
|
data/lib/docwu.rb
CHANGED
@@ -1,23 +1,112 @@
|
|
1
1
|
# -*- encoding : utf-8 -*-
|
2
2
|
require "#{File.dirname(__FILE__)}/docwu/config"
|
3
|
+
require "#{File.dirname(__FILE__)}/docwu/route" # 定制页面路由器
|
4
|
+
require "#{File.dirname(__FILE__)}/docwu/topic"
|
3
5
|
require "#{File.dirname(__FILE__)}/docwu/utils"
|
4
6
|
require "#{File.dirname(__FILE__)}/docwu/worker"
|
5
7
|
require "#{File.dirname(__FILE__)}/docwu/render"
|
6
8
|
require "#{File.dirname(__FILE__)}/docwu/folder"
|
7
9
|
require "#{File.dirname(__FILE__)}/docwu/post"
|
8
|
-
require "#{File.dirname(__FILE__)}/docwu/category"
|
9
10
|
require "#{File.dirname(__FILE__)}/docwu/server"
|
10
11
|
|
11
|
-
require '
|
12
|
-
require 'coderay'
|
12
|
+
require 'pp'
|
13
13
|
require 'yaml'
|
14
14
|
require 'fileutils'
|
15
15
|
require 'mustache_render'
|
16
|
+
require 'logger'
|
16
17
|
|
17
18
|
module Docwu
|
18
19
|
|
19
|
-
|
20
|
-
|
20
|
+
# 程序开始
|
21
|
+
def self.start(workspace)
|
22
|
+
_start_time = Time.now
|
23
|
+
|
24
|
+
args = ARGV
|
25
|
+
|
26
|
+
_command = args.shift
|
27
|
+
|
28
|
+
_useful_cmds = ['g', 'generate', 's', 'server', '-h', '--help']
|
29
|
+
|
30
|
+
unless _useful_cmds.include?(_command)
|
31
|
+
raise "command #{_command} is not available, not in (#{_useful_cmds.join('|')})"
|
32
|
+
end
|
33
|
+
|
34
|
+
_default_params = {
|
35
|
+
'-p' => [5656],
|
36
|
+
'-a' => ['0.0.0.0'],
|
37
|
+
'-c' => ["#{workspace}/config.yml"],
|
38
|
+
'DOCWU_ENV' => ['development'],
|
39
|
+
'-d' => [(args.delete('-d') == '-d')]
|
40
|
+
}
|
41
|
+
|
42
|
+
if ['--help', '-h'].include?(_command)
|
43
|
+
puts "docwu:"
|
44
|
+
|
45
|
+
_default_params.each do |_cmd, _cfg|
|
46
|
+
puts " #{_cmd}, #{_cfg[1]} (default: #{_cfg[0]})"
|
47
|
+
end
|
48
|
+
|
49
|
+
exit
|
50
|
+
end
|
51
|
+
|
52
|
+
# 获取参数
|
53
|
+
params = Hash[args.each_slice(2).to_a]
|
54
|
+
|
55
|
+
_default_params.each do |_k, _v|
|
56
|
+
params[_k] = params[_k] || _v.first
|
57
|
+
end
|
58
|
+
|
59
|
+
params['-p'] = params['-p'].to_i
|
60
|
+
|
61
|
+
# 需要生成
|
62
|
+
_need_generate = ['g', 'generate', 's', 'server'].include?(_command)
|
63
|
+
|
64
|
+
# 需要开启server
|
65
|
+
_need_server = ['s', 'server'].include?(_command)
|
66
|
+
|
67
|
+
_config_file = params['-c']
|
68
|
+
|
69
|
+
_config = {}
|
70
|
+
|
71
|
+
if File.exists?(_config_file) && File.file?(_config_file)
|
72
|
+
_yml = YAML.load(File.read(_config_file))
|
73
|
+
|
74
|
+
if _yml.is_a?(Hash)
|
75
|
+
_config.merge!(_yml['docwu'] || {})
|
76
|
+
end
|
77
|
+
else
|
78
|
+
raise "#{_config_file} not exists!"
|
79
|
+
end
|
80
|
+
|
81
|
+
_logger = ::Logger.new(STDOUT)
|
82
|
+
_logger.level = ::Logger::INFO
|
83
|
+
|
84
|
+
# docwu 的配置
|
85
|
+
::Docwu.configure do |config|
|
86
|
+
config.logger = _logger
|
87
|
+
config.params = params.freeze
|
88
|
+
config.routes = (_config['routes'] || {}).freeze
|
89
|
+
config.worker = (_config['worker'] || {}).freeze
|
90
|
+
config.workspace = "#{workspace}".freeze
|
91
|
+
end
|
92
|
+
|
93
|
+
::MustacheRender.configure do |config|
|
94
|
+
config.file_template_root_path = ::Docwu.config.layouts_path
|
95
|
+
config.logger = ::Docwu.config.logger
|
96
|
+
end
|
97
|
+
|
98
|
+
if _need_generate
|
99
|
+
::Docwu::Worker.new.generate
|
100
|
+
|
101
|
+
_logger.info("generate: success, #{Time.now - _start_time}")
|
102
|
+
end
|
103
|
+
|
104
|
+
if _need_server
|
105
|
+
::Docwu::Server.process(
|
106
|
+
:Port => ::Docwu.config.params['-p'],
|
107
|
+
:Host => ::Docwu.config.params['-a']
|
108
|
+
)
|
109
|
+
end
|
21
110
|
end
|
22
111
|
|
23
112
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: docwu
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.3
|
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: 2013-08-
|
12
|
+
date: 2013-08-30 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: redcarpet
|
@@ -75,27 +75,46 @@ dependencies:
|
|
75
75
|
- - ">="
|
76
76
|
- !ruby/object:Gem::Version
|
77
77
|
version: '0'
|
78
|
-
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: nokogiri
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ">="
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '0'
|
86
|
+
type: :runtime
|
87
|
+
prerelease: false
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ">="
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '0'
|
94
|
+
description: Description of Doc Work UP.
|
79
95
|
email:
|
80
96
|
- andywang7259@gmail.com
|
81
|
-
executables:
|
97
|
+
executables:
|
98
|
+
- docwu
|
82
99
|
extensions: []
|
83
100
|
extra_rdoc_files: []
|
84
101
|
files:
|
85
102
|
- lib/docwu/server.rb
|
103
|
+
- lib/docwu/route.rb
|
86
104
|
- lib/docwu/render.rb
|
87
105
|
- lib/docwu/config.rb
|
88
106
|
- lib/docwu/utils.rb
|
89
107
|
- lib/docwu/version.rb
|
108
|
+
- lib/docwu/topic.rb
|
90
109
|
- lib/docwu/worker.rb
|
91
110
|
- lib/docwu/post.rb
|
92
|
-
- lib/docwu/category.rb
|
93
111
|
- lib/docwu/folder.rb
|
94
112
|
- lib/docwu.rb
|
95
113
|
- lib/tasks/docwu_tasks.rake
|
96
114
|
- MIT-LICENSE
|
97
115
|
- Rakefile
|
98
116
|
- README.md
|
117
|
+
- bin/docwu
|
99
118
|
homepage: http://github.com/xiuxian123/docwu
|
100
119
|
licenses: []
|
101
120
|
post_install_message:
|
@@ -110,7 +129,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
110
129
|
version: '0'
|
111
130
|
segments:
|
112
131
|
- 0
|
113
|
-
hash: -
|
132
|
+
hash: -3240824084123490041
|
114
133
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
115
134
|
none: false
|
116
135
|
requirements:
|
@@ -119,11 +138,11 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
119
138
|
version: '0'
|
120
139
|
segments:
|
121
140
|
- 0
|
122
|
-
hash: -
|
141
|
+
hash: -3240824084123490041
|
123
142
|
requirements: []
|
124
143
|
rubyforge_project:
|
125
144
|
rubygems_version: 1.8.25
|
126
145
|
signing_key:
|
127
146
|
specification_version: 3
|
128
|
-
summary: Summary of
|
147
|
+
summary: Summary of Doc Work UP.
|
129
148
|
test_files: []
|
data/lib/docwu/category.rb
DELETED
File without changes
|