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