giblish 0.3.1 → 0.4.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 +4 -4
- data/.ruby-version +1 -1
- data/README.adoc +32 -11
- data/Rakefile +3 -1
- data/giblish.gemspec +1 -1
- data/lib/giblish-search.rb +444 -0
- data/lib/giblish/buildgraph.rb +1 -1
- data/lib/giblish/buildindex.rb +58 -31
- data/lib/giblish/cmdline.rb +27 -0
- data/lib/giblish/core.rb +66 -7
- data/lib/giblish/docid.rb +3 -27
- data/lib/giblish/docinfo.rb +32 -17
- data/lib/giblish/indexheadings.rb +163 -0
- data/lib/giblish/utils.rb +59 -3
- data/lib/giblish/version.rb +1 -1
- metadata +7 -6
@@ -0,0 +1,163 @@
|
|
1
|
+
require "json"
|
2
|
+
require "pathname"
|
3
|
+
require "asciidoctor"
|
4
|
+
require "asciidoctor/extensions"
|
5
|
+
require_relative "./utils"
|
6
|
+
|
7
|
+
module Giblish
|
8
|
+
|
9
|
+
# This hook is called by Asciidoctor once for each document _before_
|
10
|
+
# Asciidoctor processes the adoc content.
|
11
|
+
#
|
12
|
+
# It indexes all headings found in all documents in the tree.
|
13
|
+
# The resulting index can be serialized to a JSON file file
|
14
|
+
# with the following format:
|
15
|
+
#
|
16
|
+
# {
|
17
|
+
# file_infos : [{
|
18
|
+
# filepath : filepath_1,
|
19
|
+
# title : Title,
|
20
|
+
# sections : [{
|
21
|
+
# id : section_id_1,
|
22
|
+
# title : section_title_1,
|
23
|
+
# line_no : line_no
|
24
|
+
# },
|
25
|
+
# {
|
26
|
+
# id : section_id_1,
|
27
|
+
# title : section_title_1,
|
28
|
+
# line_no : line_no
|
29
|
+
# },
|
30
|
+
# ...
|
31
|
+
# ]
|
32
|
+
# },
|
33
|
+
# {
|
34
|
+
# filepath : filepath_1,
|
35
|
+
# ...
|
36
|
+
# }]
|
37
|
+
# }
|
38
|
+
class IndexHeadings < Asciidoctor::Extensions::Preprocessor
|
39
|
+
|
40
|
+
# Use a class-global heading_index dict since asciidoctor creates a new instance
|
41
|
+
# of this class for each processed file
|
42
|
+
@heading_index = {"file_infos" => []}
|
43
|
+
|
44
|
+
class << self
|
45
|
+
def heading_index
|
46
|
+
@heading_index
|
47
|
+
end
|
48
|
+
|
49
|
+
def clear_index
|
50
|
+
@heading_index = {"file_infos" => []}
|
51
|
+
end
|
52
|
+
|
53
|
+
# write the index to a file in dst_dir and remove the base_dir
|
54
|
+
# part of the path for each filename
|
55
|
+
def serialize(dst_dir, base_dir = "")
|
56
|
+
dst_dir = Pathname.new(dst_dir) unless dst_dir.respond_to?(:join)
|
57
|
+
base_dir = Pathname.new(base_dir) unless base_dir.respond_to?(:join)
|
58
|
+
|
59
|
+
if base_dir.to_s.empty?
|
60
|
+
heading_index
|
61
|
+
else
|
62
|
+
# remove the base_dir part of the file path
|
63
|
+
heading_index["file_infos"].each do |file_info|
|
64
|
+
file_info["filepath"] = Pathname.new(file_info["filepath"])
|
65
|
+
.relative_path_from(base_dir)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
Giblog.logger.info { "writing json to #{dst_dir.join("heading_index.json").to_s}" }
|
70
|
+
File.open(dst_dir.join("heading_index.json").to_s,"w") do |f|
|
71
|
+
f.write(heading_index.to_json)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def process(document, reader)
|
77
|
+
# Add doc as a source dependency for doc ids
|
78
|
+
src_path = document.attributes["docfile"]
|
79
|
+
|
80
|
+
# Note: the nil check is there to prevent us adding generated
|
81
|
+
# asciidoc docs that does not exist in the file system (e.g. the
|
82
|
+
# generated index pages). This is a bit hackish and should maybe be
|
83
|
+
# done differently
|
84
|
+
return if src_path.nil?
|
85
|
+
|
86
|
+
# get the title from thw raw text (asciidoctor has not yet
|
87
|
+
# processed the text)
|
88
|
+
title = find_title reader.lines
|
89
|
+
|
90
|
+
# Index all headings in the doc
|
91
|
+
Giblog.logger.debug { "indexing headings in #{src_path}" }
|
92
|
+
sections = []
|
93
|
+
file_info_hash = {
|
94
|
+
"filepath" => src_path,
|
95
|
+
"title" => title,
|
96
|
+
"sections" => sections
|
97
|
+
}
|
98
|
+
|
99
|
+
# build the 'sections' array
|
100
|
+
line_no = 1
|
101
|
+
regex = Regexp.new(/^=+\s+(.*)$/)
|
102
|
+
reader.lines.each do |line|
|
103
|
+
m = regex.match(line)
|
104
|
+
if m
|
105
|
+
# We found a heading, index it
|
106
|
+
section = { "id" => get_unique_id(file_info_hash, m[1]) }
|
107
|
+
section["title"] = m[1].strip
|
108
|
+
section["line_no"] = line_no
|
109
|
+
sections << section
|
110
|
+
end
|
111
|
+
line_no += 1
|
112
|
+
end
|
113
|
+
|
114
|
+
heading_index["file_infos"] << file_info_hash
|
115
|
+
reader
|
116
|
+
end
|
117
|
+
|
118
|
+
private
|
119
|
+
|
120
|
+
def find_title(lines)
|
121
|
+
title = "No title Found!"
|
122
|
+
Giblish.process_header_lines(lines) do |line|
|
123
|
+
m = /^=+(.*)$/.match(line)
|
124
|
+
if m
|
125
|
+
# We found a decent title
|
126
|
+
title = m[1].strip
|
127
|
+
end
|
128
|
+
end
|
129
|
+
title
|
130
|
+
end
|
131
|
+
|
132
|
+
def get_unique_id(doc_heading_dict, heading_str)
|
133
|
+
id_base = Giblish.to_valid_id(heading_str)
|
134
|
+
return id_base if !doc_heading_dict.key? id_base
|
135
|
+
|
136
|
+
# handle the case with several sections with the same name
|
137
|
+
idx = 1
|
138
|
+
heading_id = ""
|
139
|
+
loop do
|
140
|
+
idx += 1
|
141
|
+
heading_id = "#{id_base}_#{idx}"
|
142
|
+
# some code here
|
143
|
+
break unless doc_heading_dict.key? heading_id
|
144
|
+
end
|
145
|
+
return heading_id
|
146
|
+
end
|
147
|
+
|
148
|
+
# Helper method to shorten calls to the heading_index from instance methods
|
149
|
+
def heading_index
|
150
|
+
self.class.heading_index
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
|
155
|
+
# Helper method to register the docid preprocessor extension with
|
156
|
+
# the asciidoctor engine.
|
157
|
+
def register_index_heading_extension
|
158
|
+
Asciidoctor::Extensions.register do
|
159
|
+
preprocessor IndexHeadings
|
160
|
+
end
|
161
|
+
end
|
162
|
+
module_function :register_index_heading_extension
|
163
|
+
end
|
data/lib/giblish/utils.rb
CHANGED
@@ -38,12 +38,16 @@ module Giblish
|
|
38
38
|
# tree
|
39
39
|
# resource_dir - a string or pathname with the directory containing
|
40
40
|
# resources
|
41
|
-
def initialize(src_root, dst_root, resource_dir = nil)
|
41
|
+
def initialize(src_root, dst_root, resource_dir = nil, web_root = false)
|
42
42
|
# Make sure that the source root exists in the file system
|
43
43
|
@src_root_abs = Pathname.new(src_root).realpath
|
44
44
|
self.dst_root_abs = dst_root
|
45
|
+
|
45
46
|
# Make sure that the resource dir exists if user gives a path to it
|
46
47
|
resource_dir && (@resource_dir_abs = Pathname.new(resource_dir).realpath)
|
48
|
+
|
49
|
+
# Set web root if given by user
|
50
|
+
@web_root_abs = web_root ? Pathname.new(web_root) : nil
|
47
51
|
end
|
48
52
|
|
49
53
|
def dst_root_abs=(dst_root)
|
@@ -67,6 +71,13 @@ module Giblish
|
|
67
71
|
src_abs.relative_path_from(@src_root_abs)
|
68
72
|
end
|
69
73
|
|
74
|
+
def reldir_from_web_root(in_path)
|
75
|
+
p = in_path.is_a?(Pathname) ? in_path : Pathname.new(in_path)
|
76
|
+
return p if @web_root_abs.nil?
|
77
|
+
|
78
|
+
p.relative_path_from(@web_root_abs)
|
79
|
+
end
|
80
|
+
|
70
81
|
def adoc_output_file(infile_path, extension)
|
71
82
|
# Get absolute source dir path
|
72
83
|
src_dir_abs = self.class.closest_dir infile_path
|
@@ -152,6 +163,50 @@ module Giblish
|
|
152
163
|
end
|
153
164
|
end
|
154
165
|
|
166
|
+
# Helper method that provides the user with a way of processing only the
|
167
|
+
# lines within the asciidoc header block.
|
168
|
+
# The user must return nil to get the next line.
|
169
|
+
#
|
170
|
+
# ex:
|
171
|
+
# process_header_lines(file_path) do |line|
|
172
|
+
# if line == "Quack!"
|
173
|
+
# puts "Donald!"
|
174
|
+
# 1
|
175
|
+
# else
|
176
|
+
# nil
|
177
|
+
# end
|
178
|
+
# end
|
179
|
+
def process_header_lines(lines)
|
180
|
+
state = "before_header"
|
181
|
+
lines.each do |line|
|
182
|
+
case state
|
183
|
+
when "before_header" then (state = "in_header" if line =~ /^[=+]^.*$/ || yield(line))
|
184
|
+
when "in_header" then (state = "done" if line =~ /^\s*$/ || yield(line))
|
185
|
+
when "done" then break
|
186
|
+
end
|
187
|
+
end
|
188
|
+
end
|
189
|
+
module_function :process_header_lines
|
190
|
+
|
191
|
+
# Helper method that provides the user with a way of processing only the
|
192
|
+
# lines within the asciidoc header block.
|
193
|
+
# The user must return nil to get the next line.
|
194
|
+
#
|
195
|
+
# ex:
|
196
|
+
# process_header_lines_from_file(file_path) do |line|
|
197
|
+
# if line == "Quack!"
|
198
|
+
# puts "Donald!"
|
199
|
+
# 1
|
200
|
+
# else
|
201
|
+
# nil
|
202
|
+
# end
|
203
|
+
# end
|
204
|
+
def process_header_lines_from_file(path)
|
205
|
+
lines = File.readlines(path)
|
206
|
+
process_header_lines(lines,&Proc.new)
|
207
|
+
end
|
208
|
+
module_function :process_header_lines_from_file
|
209
|
+
|
155
210
|
# runs the supplied block but redirect stderr to a string
|
156
211
|
# returns the string containing stderr contents
|
157
212
|
def with_captured_stderr
|
@@ -166,8 +221,9 @@ module Giblish
|
|
166
221
|
|
167
222
|
# transforms strings to valid asciidoctor id strings
|
168
223
|
def to_valid_id(input_str)
|
169
|
-
id_str = "_#{input_str.downcase}"
|
170
|
-
id_str.gsub(%r{[^a-z0-9]+},"_")
|
224
|
+
id_str = "_#{input_str.strip.downcase}"
|
225
|
+
id_str.gsub!(%r{[^a-z0-9]+},"_")
|
226
|
+
id_str.chomp('_')
|
171
227
|
end
|
172
228
|
module_function :to_valid_id
|
173
229
|
|
data/lib/giblish/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: giblish
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Anders Rillbert
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-
|
11
|
+
date: 2019-03-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -61,7 +61,7 @@ dependencies:
|
|
61
61
|
version: '1.5'
|
62
62
|
- - ">="
|
63
63
|
- !ruby/object:Gem::Version
|
64
|
-
version: 1.5.
|
64
|
+
version: 1.5.8
|
65
65
|
type: :runtime
|
66
66
|
prerelease: false
|
67
67
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -71,7 +71,7 @@ dependencies:
|
|
71
71
|
version: '1.5'
|
72
72
|
- - ">="
|
73
73
|
- !ruby/object:Gem::Version
|
74
|
-
version: 1.5.
|
74
|
+
version: 1.5.8
|
75
75
|
- !ruby/object:Gem::Dependency
|
76
76
|
name: asciidoctor-diagram
|
77
77
|
requirement: !ruby/object:Gem::Requirement
|
@@ -169,6 +169,7 @@ files:
|
|
169
169
|
- data/testdocs/wellformed/source_highlighting/highlight_source.adoc
|
170
170
|
- exe/giblish
|
171
171
|
- giblish.gemspec
|
172
|
+
- lib/giblish-search.rb
|
172
173
|
- lib/giblish.rb
|
173
174
|
- lib/giblish/application.rb
|
174
175
|
- lib/giblish/buildgraph.rb
|
@@ -179,6 +180,7 @@ files:
|
|
179
180
|
- lib/giblish/docid.rb
|
180
181
|
- lib/giblish/docinfo.rb
|
181
182
|
- lib/giblish/gititf.rb
|
183
|
+
- lib/giblish/indexheadings.rb
|
182
184
|
- lib/giblish/pathtree.rb
|
183
185
|
- lib/giblish/utils.rb
|
184
186
|
- lib/giblish/version.rb
|
@@ -210,8 +212,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
210
212
|
- !ruby/object:Gem::Version
|
211
213
|
version: '0'
|
212
214
|
requirements: []
|
213
|
-
|
214
|
-
rubygems_version: 2.7.6
|
215
|
+
rubygems_version: 3.0.1
|
215
216
|
signing_key:
|
216
217
|
specification_version: 4
|
217
218
|
summary: A tool for publishing asciidoc docs stored in git repos
|