mizuho 0.9.12 → 0.9.13
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.
- data/bin/mizuho +26 -0
- data/lib/mizuho.rb +1 -1
- data/lib/mizuho/generator.rb +133 -17
- data/lib/mizuho/id_map.rb +68 -36
- data/lib/mizuho/utils.rb +65 -0
- data/templates/mizuho.css +7 -1
- data/templates/toc.html +0 -0
- data/templates/topbar.css +9 -0
- data/templates/topbar.js +7 -0
- data/test/id_map_spec.rb +91 -108
- metadata +20 -2
data/bin/mizuho
CHANGED
|
@@ -1,4 +1,23 @@
|
|
|
1
1
|
#!/usr/bin/env ruby
|
|
2
|
+
# Copyright (c) 2008-2013 Hongli Lai
|
|
3
|
+
#
|
|
4
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
5
|
+
# of this software and associated documentation files (the "Software"), to deal
|
|
6
|
+
# in the Software without restriction, including without limitation the rights
|
|
7
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
8
|
+
# copies of the Software, and to permit persons to whom the Software is
|
|
9
|
+
# furnished to do so, subject to the following conditions:
|
|
10
|
+
#
|
|
11
|
+
# The above copyright notice and this permission notice shall be included in
|
|
12
|
+
# all copies or substantial portions of the Software.
|
|
13
|
+
#
|
|
14
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
15
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
16
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
17
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
18
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
19
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
20
|
+
# THE SOFTWARE.
|
|
2
21
|
require File.expand_path(File.dirname(__FILE__) + "/../lib/mizuho")
|
|
3
22
|
require 'optparse'
|
|
4
23
|
require 'rubygems'
|
|
@@ -45,6 +64,13 @@ parser = OptionParser.new do |opts|
|
|
|
45
64
|
opts.on("-o", "--output FILE", String, "Specify the output filename.") do |value|
|
|
46
65
|
options[:output] = value
|
|
47
66
|
end
|
|
67
|
+
opts.on("--index", "Generate a full-text index.") do
|
|
68
|
+
options[:index] = true
|
|
69
|
+
end
|
|
70
|
+
opts.on("--no-run", "Do not run Asciidoc. Developer option#{nl}" <<
|
|
71
|
+
"only, don't use.") do
|
|
72
|
+
options[:no_run] = true
|
|
73
|
+
end
|
|
48
74
|
end
|
|
49
75
|
begin
|
|
50
76
|
parser.parse!
|
data/lib/mizuho.rb
CHANGED
data/lib/mizuho/generator.rb
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Copyright (c) 2008-
|
|
1
|
+
# Copyright (c) 2008-2013 Hongli Lai
|
|
2
2
|
#
|
|
3
3
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
4
4
|
# of this software and associated documentation files (the "Software"), to deal
|
|
@@ -22,6 +22,7 @@ require 'nokogiri'
|
|
|
22
22
|
require 'mizuho'
|
|
23
23
|
require 'mizuho/source_highlight'
|
|
24
24
|
require 'mizuho/id_map'
|
|
25
|
+
require 'mizuho/utils'
|
|
25
26
|
|
|
26
27
|
module Mizuho
|
|
27
28
|
|
|
@@ -38,7 +39,10 @@ class Generator
|
|
|
38
39
|
@conf_file = options[:conf_file]
|
|
39
40
|
@attributes = options[:attributes] || []
|
|
40
41
|
@enable_topbar = options[:topbar]
|
|
42
|
+
@no_run = options[:no_run]
|
|
41
43
|
@commenting_system = options[:commenting_system]
|
|
44
|
+
@index = options[:index]
|
|
45
|
+
@index_filename = options[:index_filename] || default_index_filename(input)
|
|
42
46
|
if @commenting_system == 'juvia'
|
|
43
47
|
require_options(options, :juvia_url, :juvia_site_key)
|
|
44
48
|
end
|
|
@@ -53,7 +57,10 @@ class Generator
|
|
|
53
57
|
warn "No ID map file, generating one (#{@id_map_file})..."
|
|
54
58
|
end
|
|
55
59
|
end
|
|
56
|
-
|
|
60
|
+
if !@no_run
|
|
61
|
+
self.class.run_asciidoc(@input_file, @output_file, @icons_dir,
|
|
62
|
+
@conf_file, @attributes)
|
|
63
|
+
end
|
|
57
64
|
transform(@output_file)
|
|
58
65
|
if @commenting_system
|
|
59
66
|
@id_map.save(@id_map_file)
|
|
@@ -71,9 +78,7 @@ class Generator
|
|
|
71
78
|
args = [
|
|
72
79
|
"python", ASCIIDOC,
|
|
73
80
|
"-b", "html5",
|
|
74
|
-
"-a", "toc",
|
|
75
81
|
"-a", "theme=flask",
|
|
76
|
-
"-a", "toclevels=3",
|
|
77
82
|
"-a", "icons",
|
|
78
83
|
"-n"
|
|
79
84
|
]
|
|
@@ -112,6 +117,13 @@ private
|
|
|
112
117
|
File.basename(input, File.extname(input)) +
|
|
113
118
|
".idmap.txt"
|
|
114
119
|
end
|
|
120
|
+
|
|
121
|
+
def default_index_filename(input)
|
|
122
|
+
return File.dirname(input) +
|
|
123
|
+
"/" +
|
|
124
|
+
File.basename(input, File.extname(input)) +
|
|
125
|
+
".index.sqlite3"
|
|
126
|
+
end
|
|
115
127
|
|
|
116
128
|
def warn(message)
|
|
117
129
|
STDERR.puts(message)
|
|
@@ -119,36 +131,85 @@ private
|
|
|
119
131
|
|
|
120
132
|
def transform(filename)
|
|
121
133
|
File.open(filename, 'r+') do |f|
|
|
122
|
-
doc
|
|
123
|
-
head
|
|
124
|
-
body
|
|
134
|
+
doc = Nokogiri.HTML(f)
|
|
135
|
+
head = (doc / "head")[0]
|
|
136
|
+
body = (doc / "body")[0]
|
|
125
137
|
title = (doc / "title")[0].text
|
|
126
|
-
|
|
127
|
-
|
|
138
|
+
header_div = (doc / "#header")[0]
|
|
139
|
+
headers = (doc / "#content" / "h1, h2, h3, h4")
|
|
128
140
|
|
|
129
141
|
head.add_child(stylesheet_tag)
|
|
130
142
|
|
|
143
|
+
# Add commenting balloons.
|
|
131
144
|
if @commenting_system
|
|
132
|
-
|
|
145
|
+
titles = []
|
|
146
|
+
headers.each do |header|
|
|
147
|
+
if header['class'] !~ /float/
|
|
148
|
+
titles << header.text
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
@id_map.generate_associations(titles)
|
|
133
152
|
headers.each do |header|
|
|
134
|
-
header['
|
|
135
|
-
|
|
153
|
+
if header['class'] !~ /float/
|
|
154
|
+
titles << header.text
|
|
155
|
+
header['data-comment-topic'] = @id_map.associations[header.text]
|
|
156
|
+
header.add_previous_sibling(create_comment_balloon)
|
|
157
|
+
end
|
|
136
158
|
end
|
|
137
159
|
end
|
|
138
160
|
|
|
161
|
+
# Add top bar.
|
|
139
162
|
if @enable_topbar
|
|
140
163
|
body.children.first.add_previous_sibling(topbar(title))
|
|
141
164
|
end
|
|
165
|
+
|
|
166
|
+
# Add Mizuho Javascript.
|
|
142
167
|
body.add_child(javascript_tag)
|
|
143
|
-
|
|
144
|
-
|
|
168
|
+
|
|
169
|
+
# Move preamble from content area to header area.
|
|
170
|
+
if preamble = (doc / "#preamble")[0]
|
|
145
171
|
preamble.remove
|
|
146
|
-
|
|
147
|
-
preamble_copy['id'] = 'preamble'
|
|
172
|
+
header_div.add_child(preamble)
|
|
148
173
|
end
|
|
149
174
|
|
|
175
|
+
# Create a TOC after the preamble.
|
|
176
|
+
toc_div = header_div.add_child(%Q{<div id="toc"></div>})[0]
|
|
150
177
|
if @commenting_system
|
|
151
|
-
|
|
178
|
+
# Add a commenting balloon to the TOC title.
|
|
179
|
+
toc_div.add_child(create_comment_balloon)
|
|
180
|
+
end
|
|
181
|
+
toc_div.add_child(%Q{<div id="toctitle">Table of Contents</div>})
|
|
182
|
+
headers.each do |header|
|
|
183
|
+
if header['class'] !~ /float/
|
|
184
|
+
level = header.name.scan(/\d+/).first
|
|
185
|
+
div = toc_div.add_child("<div class=\"foo toclevel#{level}\"></div>")[0]
|
|
186
|
+
link = div.add_child("<a></a>")[0]
|
|
187
|
+
link['href'] = '#' + header['id']
|
|
188
|
+
link.content = header.text
|
|
189
|
+
end
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
if @enable_topbar
|
|
193
|
+
# Add invisible spans before each header so that anchor jumps
|
|
194
|
+
# don't hide the header behind the top bar.
|
|
195
|
+
# http://nicolasgallagher.com/jump-links-and-viewport-positioning/
|
|
196
|
+
headers.each do |header|
|
|
197
|
+
span = header.add_previous_sibling('<span class="anchor_helper"></span>')[0]
|
|
198
|
+
span['id'] = header['data-anchor'] = header['id']
|
|
199
|
+
header.remove_attribute('id')
|
|
200
|
+
end
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
if @index
|
|
204
|
+
# Add docid attributes to headers.
|
|
205
|
+
headers.each do |header|
|
|
206
|
+
next if header['class'] =~ /float/
|
|
207
|
+
docid = Utils.title_to_docid(header.text)
|
|
208
|
+
header['data-docid'] = docid.to_s
|
|
209
|
+
header['class'] = "#{header['class']} docid-#{docid}".strip
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
create_search_index(headers, @index_filename)
|
|
152
213
|
end
|
|
153
214
|
|
|
154
215
|
f.rewind
|
|
@@ -238,6 +299,61 @@ private
|
|
|
238
299
|
end
|
|
239
300
|
exit 1 if fail
|
|
240
301
|
end
|
|
302
|
+
|
|
303
|
+
def gather_content(header)
|
|
304
|
+
result = []
|
|
305
|
+
elem = header
|
|
306
|
+
while true
|
|
307
|
+
elem = elem.next_sibling
|
|
308
|
+
if !elem || elem.name =~ /^h/i
|
|
309
|
+
break
|
|
310
|
+
else
|
|
311
|
+
text = elem.text.strip
|
|
312
|
+
if !text.empty?
|
|
313
|
+
text.gsub!(/\r?\n/, " ")
|
|
314
|
+
result << text
|
|
315
|
+
end
|
|
316
|
+
end
|
|
317
|
+
end
|
|
318
|
+
return result.join(" ")
|
|
319
|
+
end
|
|
320
|
+
|
|
321
|
+
def create_search_index(headers, filename)
|
|
322
|
+
require 'sqlite3'
|
|
323
|
+
db = SQLite3::Database.new("#{filename}.tmp")
|
|
324
|
+
db.transaction do
|
|
325
|
+
db.execute(%q{
|
|
326
|
+
CREATE VIRTUAL TABLE book USING fts4(
|
|
327
|
+
title TEXT NOT NULL,
|
|
328
|
+
content TEXT NOT NULL,
|
|
329
|
+
content="",
|
|
330
|
+
tokenize=porter
|
|
331
|
+
)
|
|
332
|
+
})
|
|
333
|
+
db.execute(%q{
|
|
334
|
+
CREATE TABLE version(
|
|
335
|
+
version INTEGER NOT NULL
|
|
336
|
+
)
|
|
337
|
+
})
|
|
338
|
+
db.execute("INSERT INTO version VALUES(1)")
|
|
339
|
+
db.prepare("INSERT INTO book(docid, title, content) VALUES(?, ?, ?)") do |stmt|
|
|
340
|
+
headers.each do |header|
|
|
341
|
+
next if header['class'] =~ /float/
|
|
342
|
+
title = header.text.strip
|
|
343
|
+
docid = Utils.title_to_docid(title)
|
|
344
|
+
content = gather_content(header)
|
|
345
|
+
stmt.execute(docid, title, content)
|
|
346
|
+
end
|
|
347
|
+
end
|
|
348
|
+
end
|
|
349
|
+
db.execute("INSERT INTO book(book) VALUES('optimize')")
|
|
350
|
+
db.execute("VACUUM")
|
|
351
|
+
db.close
|
|
352
|
+
File.rename("#{filename}.tmp", filename)
|
|
353
|
+
rescue Exception => e
|
|
354
|
+
File.unlink("#{filename}.tmp") rescue nil
|
|
355
|
+
raise e
|
|
356
|
+
end
|
|
241
357
|
end
|
|
242
358
|
|
|
243
359
|
end
|
data/lib/mizuho/id_map.rb
CHANGED
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
# THE SOFTWARE.
|
|
20
20
|
|
|
21
21
|
require 'mizuho/fuzzystringmatch'
|
|
22
|
+
require 'mizuho/utils'
|
|
22
23
|
|
|
23
24
|
module Mizuho
|
|
24
25
|
|
|
@@ -26,6 +27,8 @@ class IdMap
|
|
|
26
27
|
class AlreadyAssociatedError < StandardError
|
|
27
28
|
end
|
|
28
29
|
|
|
30
|
+
include Utils
|
|
31
|
+
|
|
29
32
|
URANDOM = File.open("/dev/urandom", "rb")
|
|
30
33
|
MATCHER = JaroWinklerPure.new
|
|
31
34
|
BANNER =
|
|
@@ -43,17 +46,14 @@ class IdMap
|
|
|
43
46
|
"# and that Mizuho has found an ID which appears to be associated with that\n" <<
|
|
44
47
|
"# section. You should check whether it is correct, and if not, fix it.\n\n"
|
|
45
48
|
|
|
46
|
-
attr_reader :entries
|
|
49
|
+
attr_reader :entries, :associations
|
|
47
50
|
|
|
48
51
|
def initialize
|
|
49
52
|
@entries = {}
|
|
53
|
+
@associations = {}
|
|
50
54
|
#@namespace = slug(File.basename(filename, File.extname(filename)))
|
|
51
55
|
end
|
|
52
56
|
|
|
53
|
-
def [](title)
|
|
54
|
-
return @entries[title]
|
|
55
|
-
end
|
|
56
|
-
|
|
57
57
|
def load(filename_or_io)
|
|
58
58
|
@entries.clear
|
|
59
59
|
open_io(filename_or_io, :read) do |io|
|
|
@@ -101,16 +101,73 @@ class IdMap
|
|
|
101
101
|
f.write(output)
|
|
102
102
|
end
|
|
103
103
|
end
|
|
104
|
+
|
|
105
|
+
def generate_associations(titles)
|
|
106
|
+
@associations = {}
|
|
107
|
+
|
|
108
|
+
# Associate exact matches.
|
|
109
|
+
titles = titles.reject do |title|
|
|
110
|
+
if (entry = @entries[title]) && !entry.associated?
|
|
111
|
+
entry.associated = true
|
|
112
|
+
@associations[title] = entry.id
|
|
113
|
+
true
|
|
114
|
+
else
|
|
115
|
+
false
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
# For the remaining titles, associate with moved or similar-looking entry.
|
|
120
|
+
titles.reject! do |title|
|
|
121
|
+
if entry = find_moved(title)
|
|
122
|
+
@entries.delete(entry.title)
|
|
123
|
+
@entries[title] = entry
|
|
124
|
+
entry.title = title
|
|
125
|
+
entry.associated = true
|
|
126
|
+
entry.fuzzy = false
|
|
127
|
+
@associations[title] = entry.id
|
|
128
|
+
true
|
|
129
|
+
else
|
|
130
|
+
false
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
# For the remaining titles, associate with similar-looking entry.
|
|
135
|
+
titles.reject! do |title|
|
|
136
|
+
if entry = find_similar(title)
|
|
137
|
+
@entries.delete(entry.title)
|
|
138
|
+
@entries[title] = entry
|
|
139
|
+
entry.title = title
|
|
140
|
+
entry.associated = true
|
|
141
|
+
entry.fuzzy = true
|
|
142
|
+
@associations[title] = entry.id
|
|
143
|
+
true
|
|
144
|
+
else
|
|
145
|
+
false
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
# For the remaining titles, create new entries.
|
|
150
|
+
titles.each do |title|
|
|
151
|
+
id = create_unique_id(title)
|
|
152
|
+
add(title, id, false, true)
|
|
153
|
+
@associations[title] = id
|
|
154
|
+
end
|
|
155
|
+
end
|
|
104
156
|
|
|
105
|
-
def
|
|
157
|
+
def xassociate(title)
|
|
106
158
|
if entry = @entries[title]
|
|
107
159
|
if entry.associated?
|
|
108
|
-
raise AlreadyAssociatedError, "Cannot associate an already
|
|
160
|
+
raise AlreadyAssociatedError, "Cannot associate an already associated title (#{title.inspect})"
|
|
109
161
|
else
|
|
110
162
|
entry.associated = true
|
|
111
163
|
id = entry.id
|
|
112
164
|
end
|
|
113
165
|
elsif (moved_entry = find_moved(title)) || (similar_entry = find_similar(title))
|
|
166
|
+
if moved_entry
|
|
167
|
+
puts "moved entry: #{title.inspect} -> #{moved_entry.title.inspect}"
|
|
168
|
+
elsif similar_entry
|
|
169
|
+
puts "similar entry: #{title.inspect} -> #{similar_entry.title.inspect}"
|
|
170
|
+
end
|
|
114
171
|
entry = (moved_entry || similar_entry)
|
|
115
172
|
@entries.delete(entry.title)
|
|
116
173
|
@entries[title] = entry
|
|
@@ -152,11 +209,11 @@ private
|
|
|
152
209
|
alias associated? associated
|
|
153
210
|
|
|
154
211
|
def <=>(other)
|
|
155
|
-
if (a =
|
|
156
|
-
(b =
|
|
212
|
+
if (a = Utils.extract_chapter(title)) &&
|
|
213
|
+
(b = Utils.extract_chapter(other.title))
|
|
157
214
|
# Sort by chapter whenever possible.
|
|
158
|
-
a[0] =
|
|
159
|
-
b[0] =
|
|
215
|
+
a[0] = Utils.chapter_to_int_array(a[0])
|
|
216
|
+
b[0] = Utils.chapter_to_int_array(b[0])
|
|
160
217
|
return a <=> b
|
|
161
218
|
else
|
|
162
219
|
return title <=> other.title
|
|
@@ -232,31 +289,6 @@ private
|
|
|
232
289
|
end
|
|
233
290
|
end
|
|
234
291
|
|
|
235
|
-
# Given a title with a chapter number, e.g. "6.1 Installation using tarball",
|
|
236
|
-
# splits the two up.
|
|
237
|
-
def self.extract_chapter(title)
|
|
238
|
-
title =~ /^((\d+\.)*) (.+)$/
|
|
239
|
-
chapter = $1
|
|
240
|
-
pure_title = $3
|
|
241
|
-
if !chapter.nil? && !chapter.empty? && pure_title && !pure_title.empty?
|
|
242
|
-
return [chapter, pure_title]
|
|
243
|
-
else
|
|
244
|
-
return nil
|
|
245
|
-
end
|
|
246
|
-
end
|
|
247
|
-
|
|
248
|
-
def extract_chapter(title)
|
|
249
|
-
return IdMap.extract_chapter(title)
|
|
250
|
-
end
|
|
251
|
-
|
|
252
|
-
def self.chapter_to_int_array(chapter)
|
|
253
|
-
return chapter.split('.').map { |x| x.to_i }
|
|
254
|
-
end
|
|
255
|
-
|
|
256
|
-
def chapter_to_int_array(chapter)
|
|
257
|
-
return IdMap.chapter_to_int_array(chapter)
|
|
258
|
-
end
|
|
259
|
-
|
|
260
292
|
def slug(text)
|
|
261
293
|
text = text.downcase
|
|
262
294
|
text.gsub!(/^(\d+\.)+ /, '')
|
data/lib/mizuho/utils.rb
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# Copyright (c) 2013 Hongli Lai
|
|
2
|
+
#
|
|
3
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
4
|
+
# of this software and associated documentation files (the "Software"), to deal
|
|
5
|
+
# in the Software without restriction, including without limitation the rights
|
|
6
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
7
|
+
# copies of the Software, and to permit persons to whom the Software is
|
|
8
|
+
# furnished to do so, subject to the following conditions:
|
|
9
|
+
#
|
|
10
|
+
# The above copyright notice and this permission notice shall be included in
|
|
11
|
+
# all copies or substantial portions of the Software.
|
|
12
|
+
#
|
|
13
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
14
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
15
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
16
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
17
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
18
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
19
|
+
# THE SOFTWARE.
|
|
20
|
+
|
|
21
|
+
module Mizuho
|
|
22
|
+
|
|
23
|
+
module Utils
|
|
24
|
+
extend self
|
|
25
|
+
|
|
26
|
+
def self.included(klass)
|
|
27
|
+
# When included into another class, make sure that Utils
|
|
28
|
+
# methods are made private.
|
|
29
|
+
public_instance_methods(false).each do |method_name|
|
|
30
|
+
klass.send(:private, method_name)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Given a title with a chapter number, e.g. "6.1 Installation using tarball",
|
|
35
|
+
# splits the two up.
|
|
36
|
+
def extract_chapter(title)
|
|
37
|
+
title =~ /^((\d+\.)*) (.+)$/
|
|
38
|
+
chapter = $1
|
|
39
|
+
pure_title = $3
|
|
40
|
+
if !chapter.nil? && !chapter.empty? && pure_title && !pure_title.empty?
|
|
41
|
+
return [chapter, pure_title]
|
|
42
|
+
else
|
|
43
|
+
return nil
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def chapter_to_int_array(chapter)
|
|
48
|
+
return chapter.split('.').map { |x| x.to_i }
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def title_to_docid(title)
|
|
52
|
+
chapter, pure_title = extract_chapter(title)
|
|
53
|
+
p title
|
|
54
|
+
numbers = chapter_to_int_array(chapter)
|
|
55
|
+
result = 0
|
|
56
|
+
bit_offset = 0
|
|
57
|
+
numbers.each do |num|
|
|
58
|
+
result = result | (num << bit_offset)
|
|
59
|
+
bit_offset += 5
|
|
60
|
+
end
|
|
61
|
+
return result
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
end
|
data/templates/mizuho.css
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
body {
|
|
2
|
-
margin: 1em
|
|
2
|
+
margin: 1em auto 1em auto;
|
|
3
|
+
padding: 0 1em 0 1em;
|
|
4
|
+
max-width: 800px;
|
|
3
5
|
}
|
|
4
6
|
|
|
5
7
|
a.image {
|
|
@@ -78,6 +80,10 @@ a.image {
|
|
|
78
80
|
margin: 2em;
|
|
79
81
|
}
|
|
80
82
|
|
|
83
|
+
pre {
|
|
84
|
+
overflow: auto;
|
|
85
|
+
}
|
|
86
|
+
|
|
81
87
|
@media print {
|
|
82
88
|
body {
|
|
83
89
|
font-size: 18pt;
|
data/templates/toc.html
ADDED
|
File without changes
|
data/templates/topbar.css
CHANGED
|
@@ -114,3 +114,12 @@
|
|
|
114
114
|
border-bottom-left-radius: 0;
|
|
115
115
|
border-bottom-right-radius: 0;
|
|
116
116
|
}
|
|
117
|
+
|
|
118
|
+
/* http://nicolasgallagher.com/jump-links-and-viewport-positioning/ */
|
|
119
|
+
.anchor_helper {
|
|
120
|
+
position: relative;
|
|
121
|
+
display: block;
|
|
122
|
+
top: -50px;
|
|
123
|
+
width: 1px;
|
|
124
|
+
height: 1px;
|
|
125
|
+
}
|
data/templates/topbar.js
CHANGED
|
@@ -8,6 +8,7 @@ Mizuho.initializeTopBar = $.proxy(function() {
|
|
|
8
8
|
var isMobileDevice = this.isMobileDevice();
|
|
9
9
|
var timerId;
|
|
10
10
|
|
|
11
|
+
// Create the floating table of contents used in the top bar.
|
|
11
12
|
var $floattoc = $('<div id="floattoc"></div>').html($('#toc').html());
|
|
12
13
|
$floattoc.find('#toctitle').remove();
|
|
13
14
|
$floattoc.find('.comments').remove();
|
|
@@ -26,6 +27,8 @@ Mizuho.initializeTopBar = $.proxy(function() {
|
|
|
26
27
|
self.internalLinkClicked(this, event);
|
|
27
28
|
});
|
|
28
29
|
|
|
30
|
+
// Callback for when the user clicks on the Table of Contents
|
|
31
|
+
// button on the top bar.
|
|
29
32
|
function showFloatingToc() {
|
|
30
33
|
var scrollUpdateTimerId;
|
|
31
34
|
|
|
@@ -118,6 +121,9 @@ Mizuho.initializeTopBar = $.proxy(function() {
|
|
|
118
121
|
$window.bind('scroll', onScroll);
|
|
119
122
|
}
|
|
120
123
|
|
|
124
|
+
// Called whenever the user scrolls. Updates the title of the
|
|
125
|
+
// Table of Contents button in the top bar to the section that
|
|
126
|
+
// the user is currently reading.
|
|
121
127
|
function update() {
|
|
122
128
|
if ($title.offset().top + $title.height() < $document.scrollTop()) {
|
|
123
129
|
if (!$topbar.is(':visible')) {
|
|
@@ -161,6 +167,7 @@ Mizuho.initializeTopBar = $.proxy(function() {
|
|
|
161
167
|
}, 100);
|
|
162
168
|
}
|
|
163
169
|
|
|
170
|
+
|
|
164
171
|
if (isMobileDevice) {
|
|
165
172
|
// Mobile devices don't support position fixed.
|
|
166
173
|
$topbar.css('position', 'absolute');
|
data/test/id_map_spec.rb
CHANGED
|
@@ -29,133 +29,116 @@ describe IdMap do
|
|
|
29
29
|
@id_map = IdMap.new
|
|
30
30
|
end
|
|
31
31
|
|
|
32
|
-
describe "#
|
|
33
|
-
describe "if
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
it "returns a new unique ID" do
|
|
42
|
-
@id1.should_not == @id2
|
|
43
|
-
@id1.should_not == @id3
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
it "marks the entry as associated" do
|
|
47
|
-
@id_map["Installation"].should be_associated
|
|
48
|
-
@id_map["Installation on Linux"].should be_associated
|
|
49
|
-
@id_map["Configuration"].should be_associated
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
it "doesn't mark the corresponding entry as fuzzy" do
|
|
53
|
-
@id_map["Installation"].should_not be_fuzzy
|
|
54
|
-
@id_map["Installation on Linux"].should_not be_fuzzy
|
|
55
|
-
@id_map["Configuration"].should_not be_fuzzy
|
|
56
|
-
end
|
|
32
|
+
describe "#generate_associations" do
|
|
33
|
+
describe "if no similar titles exist in the map" do
|
|
34
|
+
before :each do
|
|
35
|
+
@id_map.generate_associations(["Installation",
|
|
36
|
+
"Installation on Linux", "Configuration"])
|
|
37
|
+
@id1 = @id_map.associations["Installation"]
|
|
38
|
+
@id2 = @id_map.associations["Installation on Linux"]
|
|
39
|
+
@id3 = @id_map.associations["Configuration"]
|
|
57
40
|
end
|
|
58
41
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
@entry2 = @id_map.add("5.6. Installation using a tarball", nil, false, false)
|
|
63
|
-
@entry3 = @id_map.add("6.0. Installation using a tarball", nil, false, false)
|
|
64
|
-
@id1 = @id_map.associate "5.4. Installation using a tarball"
|
|
65
|
-
@id2 = @id_map.associate "2.1. Installation using a tarball"
|
|
66
|
-
end
|
|
67
|
-
|
|
68
|
-
it "associates with the title whose section number is closest to the new section number" do
|
|
69
|
-
@id1.should == @entry2.id
|
|
70
|
-
@id2.should == @entry1.id
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
it "changes the original entries' titles" do
|
|
74
|
-
@entry1.title.should == "2.1. Installation using a tarball"
|
|
75
|
-
@entry2.title.should == "5.4. Installation using a tarball"
|
|
76
|
-
@entry3.title.should == "6.0. Installation using a tarball"
|
|
77
|
-
end
|
|
78
|
-
|
|
79
|
-
it "marks the corresponding entry as associated" do
|
|
80
|
-
@entry1.should be_associated
|
|
81
|
-
@entry2.should be_associated
|
|
82
|
-
@entry3.should_not be_associated
|
|
83
|
-
end
|
|
84
|
-
|
|
85
|
-
it "doesn't mark the corresponding entry as fuzzy" do
|
|
86
|
-
@entry1.should_not be_fuzzy
|
|
87
|
-
@entry2.should_not be_fuzzy
|
|
88
|
-
@entry3.should_not be_fuzzy
|
|
89
|
-
end
|
|
42
|
+
it "returns a new unique ID" do
|
|
43
|
+
@id1.should_not == @id2
|
|
44
|
+
@id1.should_not == @id3
|
|
90
45
|
end
|
|
91
46
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
end
|
|
97
|
-
|
|
98
|
-
it "associates with the most similar title and returns its ID" do
|
|
99
|
-
@id3 = @id_map.associate "Installation using tarball"
|
|
100
|
-
@id3.should == @entry1.id
|
|
101
|
-
@entry1.title.should == "Installation using tarball"
|
|
102
|
-
end
|
|
103
|
-
|
|
104
|
-
it "only associates with a title that hasn't been associated before" do
|
|
105
|
-
@entry1.associated = true
|
|
106
|
-
@id3 = @id_map.associate "Installation using tarball"
|
|
107
|
-
@id3.should == @entry2.id
|
|
108
|
-
end
|
|
109
|
-
|
|
110
|
-
it "marks the corresponding entry as associated" do
|
|
111
|
-
@id_map.associate "Installation using tarball"
|
|
112
|
-
@id_map["Installation using tarball"].should be_associated
|
|
113
|
-
end
|
|
114
|
-
|
|
115
|
-
it "marks the corresponding entry as fuzzy" do
|
|
116
|
-
@id_map.associate "Installation using tarball"
|
|
117
|
-
@id_map["Installation using tarball"].should be_fuzzy
|
|
118
|
-
end
|
|
47
|
+
it "marks the entry as associated" do
|
|
48
|
+
@id_map.entries["Installation"].should be_associated
|
|
49
|
+
@id_map.entries["Installation on Linux"].should be_associated
|
|
50
|
+
@id_map.entries["Configuration"].should be_associated
|
|
119
51
|
end
|
|
120
52
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
53
|
+
it "doesn't mark the corresponding entry as fuzzy" do
|
|
54
|
+
@id_map.entries["Installation"].should_not be_fuzzy
|
|
55
|
+
@id_map.entries["Installation on Linux"].should_not be_fuzzy
|
|
56
|
+
@id_map.entries["Configuration"].should_not be_fuzzy
|
|
125
57
|
end
|
|
126
58
|
end
|
|
127
59
|
|
|
128
|
-
describe "if the
|
|
60
|
+
describe "if the same title exists in the map, but with a different section number" do
|
|
129
61
|
before :each do
|
|
130
|
-
@
|
|
62
|
+
@entry1 = @id_map.add("1.2. Installation using a tarball", nil, false, false)
|
|
63
|
+
@entry2 = @id_map.add("5.6. Installation using a tarball", nil, false, false)
|
|
64
|
+
@entry3 = @id_map.add("6.0. Installation using a tarball", nil, false, false)
|
|
65
|
+
@id_map.generate_associations(["5.4. Installation using a tarball",
|
|
66
|
+
"2.1. Installation using a tarball"])
|
|
67
|
+
@id1 = @id_map.associations["5.4. Installation using a tarball"]
|
|
68
|
+
@id2 = @id_map.associations["2.1. Installation using a tarball"]
|
|
131
69
|
end
|
|
132
70
|
|
|
133
|
-
it "
|
|
134
|
-
|
|
135
|
-
|
|
71
|
+
it "associates with the title whose section number is closest to the new section number" do
|
|
72
|
+
@id1.should == @entry2.id
|
|
73
|
+
@id2.should == @entry1.id
|
|
136
74
|
end
|
|
137
75
|
|
|
138
|
-
it "
|
|
139
|
-
@
|
|
140
|
-
@
|
|
76
|
+
it "changes the original entries' titles" do
|
|
77
|
+
@entry1.title.should == "2.1. Installation using a tarball"
|
|
78
|
+
@entry2.title.should == "5.4. Installation using a tarball"
|
|
79
|
+
@entry3.title.should == "6.0. Installation using a tarball"
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
it "marks the corresponding entry as associated" do
|
|
83
|
+
@entry1.should be_associated
|
|
84
|
+
@entry2.should be_associated
|
|
85
|
+
@entry3.should_not be_associated
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
it "doesn't mark the corresponding entry as fuzzy" do
|
|
89
|
+
@entry1.should_not be_fuzzy
|
|
90
|
+
@entry2.should_not be_fuzzy
|
|
91
|
+
@entry3.should_not be_fuzzy
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
describe "if one or more similar titles exist in the map" do
|
|
96
|
+
before :each do
|
|
97
|
+
@entry1 = @id_map.add("Installation using a tarball", nil, false, false)
|
|
98
|
+
@entry2 = @id_map.add("Installation using a Linux tarball", nil, false, false)
|
|
141
99
|
end
|
|
142
100
|
|
|
143
|
-
it "
|
|
144
|
-
@id_map.
|
|
145
|
-
@
|
|
101
|
+
it "associates with the most similar title and returns its ID" do
|
|
102
|
+
@id_map.generate_associations(["Installation using tarball"])
|
|
103
|
+
@id3 = @id_map.associations["Installation using tarball"]
|
|
104
|
+
@id3.should == @entry1.id
|
|
105
|
+
@entry1.title.should == "Installation using tarball"
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
it "only associates with a title that hasn't been associated before" do
|
|
109
|
+
@entry1.associated = true
|
|
110
|
+
@id_map.generate_associations(["Installation using tarball"])
|
|
111
|
+
@id3 = @id_map.associations["Installation using tarball"]
|
|
112
|
+
@id3.should == @entry2.id
|
|
113
|
+
end
|
|
146
114
|
|
|
147
|
-
|
|
148
|
-
@id_map.
|
|
149
|
-
@
|
|
115
|
+
it "marks the corresponding entry as associated" do
|
|
116
|
+
@id_map.generate_associations(["Installation using tarball"])
|
|
117
|
+
@id_map.entries["Installation using tarball"].should be_associated
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
it "marks the corresponding entry as fuzzy" do
|
|
121
|
+
@id_map.generate_associations(["Installation using tarball"])
|
|
122
|
+
@id_map.entries["Installation using tarball"].should be_fuzzy
|
|
150
123
|
end
|
|
151
124
|
end
|
|
152
125
|
|
|
153
|
-
describe "if
|
|
154
|
-
it "
|
|
155
|
-
@
|
|
156
|
-
|
|
126
|
+
describe "if a one title has a similar match, but a later title has an exact match" do
|
|
127
|
+
it "associates the later title with the exact match, then associates the first title with the similar match" do
|
|
128
|
+
@id_map.add("Hello Dear World", "id-1", false, false)
|
|
129
|
+
@id_map.add("Hallaa Dear World", "id-2", false, false)
|
|
130
|
+
@id_map.generate_associations(["Helloo Dear World", "Hello Dear World"])
|
|
131
|
+
@id_map.associations["Helloo Dear World"].should == "id-2"
|
|
132
|
+
@id_map.associations["Hello Dear World"].should == "id-1"
|
|
157
133
|
end
|
|
158
134
|
end
|
|
135
|
+
|
|
136
|
+
specify "title matching is case-insensitive" do
|
|
137
|
+
entry1 = @id_map.add("INSTALLATION USING A TARBALL", nil, false, false)
|
|
138
|
+
@id_map.generate_associations(["installation using tarball"])
|
|
139
|
+
id = @id_map.associations["installation using tarball"]
|
|
140
|
+
id.should == entry1.id
|
|
141
|
+
end
|
|
159
142
|
end
|
|
160
143
|
|
|
161
144
|
describe "entries" do
|
|
@@ -193,17 +176,17 @@ describe IdMap do
|
|
|
193
176
|
|
|
194
177
|
@id_map.entries.should have(3).items
|
|
195
178
|
|
|
196
|
-
entry = @id_map["Installation"]
|
|
179
|
+
entry = @id_map.entries["Installation"]
|
|
197
180
|
entry.title.should == "Installation"
|
|
198
181
|
entry.id.should == "installation-1"
|
|
199
182
|
entry.should_not be_fuzzy
|
|
200
183
|
|
|
201
|
-
entry = @id_map["Configuration"]
|
|
184
|
+
entry = @id_map.entries["Configuration"]
|
|
202
185
|
entry.title.should == "Configuration"
|
|
203
186
|
entry.id.should == "configuration-2"
|
|
204
187
|
entry.should_not be_fuzzy
|
|
205
188
|
|
|
206
|
-
entry = @id_map["Troubleshooting"]
|
|
189
|
+
entry = @id_map.entries["Troubleshooting"]
|
|
207
190
|
entry.title.should == "Troubleshooting"
|
|
208
191
|
entry.id.should == "troubleshooting-1"
|
|
209
192
|
entry.should be_fuzzy
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: mizuho
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.9.
|
|
4
|
+
version: 0.9.13
|
|
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-
|
|
12
|
+
date: 2013-02-12 00:00:00.000000000 Z
|
|
13
13
|
dependencies:
|
|
14
14
|
- !ruby/object:Gem::Dependency
|
|
15
15
|
name: nokogiri
|
|
@@ -27,6 +27,22 @@ dependencies:
|
|
|
27
27
|
- - ! '>='
|
|
28
28
|
- !ruby/object:Gem::Version
|
|
29
29
|
version: '0'
|
|
30
|
+
- !ruby/object:Gem::Dependency
|
|
31
|
+
name: sqlite3
|
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
|
33
|
+
none: false
|
|
34
|
+
requirements:
|
|
35
|
+
- - ! '>='
|
|
36
|
+
- !ruby/object:Gem::Version
|
|
37
|
+
version: '0'
|
|
38
|
+
type: :runtime
|
|
39
|
+
prerelease: false
|
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
41
|
+
none: false
|
|
42
|
+
requirements:
|
|
43
|
+
- - ! '>='
|
|
44
|
+
- !ruby/object:Gem::Version
|
|
45
|
+
version: '0'
|
|
30
46
|
description: A documentation formatting tool. Mizuho converts Asciidoc input files
|
|
31
47
|
into nicely outputted HTML, possibly one file per chapter. Multiple templates are
|
|
32
48
|
supported, so you can write your own.
|
|
@@ -46,6 +62,7 @@ files:
|
|
|
46
62
|
- lib/mizuho/generator.rb
|
|
47
63
|
- lib/mizuho/id_map.rb
|
|
48
64
|
- lib/mizuho/source_highlight.rb
|
|
65
|
+
- lib/mizuho/utils.rb
|
|
49
66
|
- lib/mizuho.rb
|
|
50
67
|
- test/generator_spec.rb
|
|
51
68
|
- test/id_map_spec.rb
|
|
@@ -60,6 +77,7 @@ files:
|
|
|
60
77
|
- templates/juvia.js
|
|
61
78
|
- templates/mizuho.css
|
|
62
79
|
- templates/mizuho.js
|
|
80
|
+
- templates/toc.html
|
|
63
81
|
- templates/topbar.css
|
|
64
82
|
- templates/topbar.html
|
|
65
83
|
- templates/topbar.js
|