giblish 0.3.1 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
@@ -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
 
@@ -1,3 +1,3 @@
1
1
  module Giblish
2
- VERSION = "0.3.1".freeze
2
+ VERSION = "0.4.0".freeze
3
3
  end
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.3.1
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-02-11 00:00:00.000000000 Z
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.7.1
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.7.1
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
- rubyforge_project:
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