yard_ghurt 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CHANGELOG.md +22 -0
- data/Gemfile +25 -0
- data/LICENSE.txt +165 -0
- data/README.md +335 -0
- data/Rakefile +68 -0
- data/lib/yard_ghurt/anchor_links.rb +262 -0
- data/lib/yard_ghurt/gfm_fixer_task.rb +594 -0
- data/lib/yard_ghurt/ghp_syncer_task.rb +183 -0
- data/lib/yard_ghurt/util.rb +80 -0
- data/lib/yard_ghurt/version.rb +26 -0
- data/lib/yard_ghurt.rb +41 -0
- data/yard/templates/default/layout/html/footer.erb +5 -0
- data/yard_ghurt.gemspec +60 -0
- metadata +131 -0
@@ -0,0 +1,262 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# encoding: UTF-8
|
3
|
+
# frozen_string_literal: true
|
4
|
+
|
5
|
+
#--
|
6
|
+
# This file is part of YardGhurt.
|
7
|
+
# Copyright (c) 2019 Jonathan Bradley Whited (@esotericpig)
|
8
|
+
#
|
9
|
+
# YardGhurt is free software: you can redistribute it and/or modify
|
10
|
+
# it under the terms of the GNU Lesser General Public License as published by
|
11
|
+
# the Free Software Foundation, either version 3 of the License, or
|
12
|
+
# (at your option) any later version.
|
13
|
+
#
|
14
|
+
# YardGhurt is distributed in the hope that it will be useful,
|
15
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
16
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
17
|
+
# GNU Lesser General Public License for more details.
|
18
|
+
#
|
19
|
+
# You should have received a copy of the GNU Lesser General Public License
|
20
|
+
# along with YardGhurt. If not, see <https://www.gnu.org/licenses/>.
|
21
|
+
#++
|
22
|
+
|
23
|
+
|
24
|
+
require 'set'
|
25
|
+
require 'uri'
|
26
|
+
|
27
|
+
module YardGhurt
|
28
|
+
###
|
29
|
+
# A "database" of anchor links specific to GitHub Flavored Markdown (GFM) & YARDoc.
|
30
|
+
#
|
31
|
+
# You can use this by itself to view what anchor IDs would be generated:
|
32
|
+
# al = YardGhurt::AnchorLinks.new()
|
33
|
+
#
|
34
|
+
# puts al.to_github_anchor_id('This is a test!')
|
35
|
+
# puts al.to_yard_anchor_id('This is a test!')
|
36
|
+
#
|
37
|
+
# # Output:
|
38
|
+
# # ---
|
39
|
+
# # this-is-a-test
|
40
|
+
# # This_is_a_test_
|
41
|
+
#
|
42
|
+
# Be aware that YARDoc depends on a common number that will be incremented for all duplicates,
|
43
|
+
# while GFM's number is only local to each specific duplicate:
|
44
|
+
# al = YardGhurt::AnchorLinks.new()
|
45
|
+
# name = 'This is a test!'
|
46
|
+
#
|
47
|
+
# puts al.to_yard_anchor_id(name) # This_is_a_test_
|
48
|
+
# puts al.to_yard_anchor_id(name) # This_is_a_test_
|
49
|
+
#
|
50
|
+
# puts al.to_github_anchor_id(name) # this-is-a-test
|
51
|
+
# puts al.to_github_anchor_id(name) # this-is-a-test
|
52
|
+
#
|
53
|
+
# al << name # Officially add it to the database
|
54
|
+
#
|
55
|
+
# # Instead of being 0 & 0, will be 0 & 1 (incremented),
|
56
|
+
# # even without being added to the database
|
57
|
+
# puts al.to_yard_anchor_id(name) # This_is_a_test_0
|
58
|
+
# puts al.to_yard_anchor_id(name) # This_is_a_test_1
|
59
|
+
#
|
60
|
+
# puts al.to_github_anchor_id(name) # this-is-a-test-1
|
61
|
+
# puts al.to_github_anchor_id(name) # this-is-a-test-1
|
62
|
+
#
|
63
|
+
# name = 'This is another test!'
|
64
|
+
# al << name # Officially add it to the database
|
65
|
+
#
|
66
|
+
# # Instead of being 0 & 1, will be 2 & 3 (global increment),
|
67
|
+
# # even without being added to the database
|
68
|
+
# puts al.to_yard_anchor_id(name) # This_is_another_test_2
|
69
|
+
# puts al.to_yard_anchor_id(name) # This_is_another_test_3
|
70
|
+
#
|
71
|
+
# puts al.to_github_anchor_id(name) # this-is-another-test-1
|
72
|
+
# puts al.to_github_anchor_id(name) # this-is-another-test-1
|
73
|
+
#
|
74
|
+
# @author Jonathan Bradley Whited (@esotericpig)
|
75
|
+
# @since 1.0.0
|
76
|
+
#
|
77
|
+
# @see GFMFixerTask
|
78
|
+
###
|
79
|
+
class AnchorLinks
|
80
|
+
# @return [Hash] the GFM-style anchor IDs pointing to their YARDoc ID equivalents that have been added
|
81
|
+
attr_reader :anchor_ids
|
82
|
+
|
83
|
+
# @return [Set] the YARDoc anchor IDs that have been added
|
84
|
+
attr_accessor :yard_anchor_ids
|
85
|
+
|
86
|
+
# @return [Integer] the next YARDoc number to use if there is a duplicate anchor ID
|
87
|
+
attr_accessor :yard_dup_num
|
88
|
+
|
89
|
+
def initialize()
|
90
|
+
reset()
|
91
|
+
end
|
92
|
+
|
93
|
+
# Reset the database back to its fresh, pristine self,
|
94
|
+
# including common numbers for duplicates.
|
95
|
+
def reset()
|
96
|
+
@anchor_ids = {}
|
97
|
+
@yard_anchor_ids = Set.new()
|
98
|
+
@yard_dup_num = 0
|
99
|
+
end
|
100
|
+
|
101
|
+
# (see #add_anchor)
|
102
|
+
def <<(name)
|
103
|
+
return add_anchor(name)
|
104
|
+
end
|
105
|
+
|
106
|
+
# (see #store_anchor)
|
107
|
+
def []=(github_anchor_id,yard_anchor_id)
|
108
|
+
return store_anchor(github_anchor_id,yard_anchor_id)
|
109
|
+
end
|
110
|
+
|
111
|
+
# Convert +name+ (header text) to a GFM and YARDoc anchor ID and add the IDs to the database.
|
112
|
+
#
|
113
|
+
# @param name [String] the name (header text) to convert to anchor IDs and add to the database
|
114
|
+
#
|
115
|
+
# @return [self]
|
116
|
+
def add_anchor(name)
|
117
|
+
store_anchor(to_github_anchor_id(name),to_yard_anchor_id(name))
|
118
|
+
|
119
|
+
return self
|
120
|
+
end
|
121
|
+
|
122
|
+
# Merge +anchor_ids+ with {anchor_ids} and {yard_anchor_ids}.
|
123
|
+
#
|
124
|
+
# @param anchor_ids [Hash] the anchor IDs (of GFM anchor IDs to YARDoc anchor IDs) to merge
|
125
|
+
def merge_anchor_ids!(anchor_ids)
|
126
|
+
@anchor_ids.merge!(anchor_ids)
|
127
|
+
@yard_anchor_ids.merge(anchor_ids.values)
|
128
|
+
|
129
|
+
return @anchor_ids
|
130
|
+
end
|
131
|
+
|
132
|
+
# Store & associate key +github_anchor_id+ with value +yard_anchor_id+,
|
133
|
+
# and add +yard_anchor_id+ to the YARDoc anchor IDs.
|
134
|
+
#
|
135
|
+
# @param github_anchor_id [String] the GitHub anchor ID; the key
|
136
|
+
# @param yard_anchor_id [String] the YARDoc anchor ID; the value
|
137
|
+
#
|
138
|
+
# @return [String] the +yard_anchor_id+ added
|
139
|
+
def store_anchor(github_anchor_id,yard_anchor_id)
|
140
|
+
@anchor_ids[github_anchor_id] = yard_anchor_id
|
141
|
+
@yard_anchor_ids << yard_anchor_id
|
142
|
+
|
143
|
+
return yard_anchor_id
|
144
|
+
end
|
145
|
+
|
146
|
+
def anchor_ids=(anchor_ids)
|
147
|
+
@anchor_ids = anchor_ids
|
148
|
+
@yard_anchor_ids.merge(anchor_ids.values)
|
149
|
+
|
150
|
+
return @anchor_ids
|
151
|
+
end
|
152
|
+
|
153
|
+
# (see #anchor_id)
|
154
|
+
def [](github_anchor_id)
|
155
|
+
return anchor_id(github_anchor_id)
|
156
|
+
end
|
157
|
+
|
158
|
+
# Get the YARDoc anchor ID associated with this +github_anchor_id+.
|
159
|
+
#
|
160
|
+
# @param github_anchor_id [String] the GitHub anchor ID key to look up
|
161
|
+
#
|
162
|
+
# @return [String,nil] the YARDoc anchor ID associated with +github_anchor_id+
|
163
|
+
def anchor_id(github_anchor_id)
|
164
|
+
return @anchor_ids[github_anchor_id]
|
165
|
+
end
|
166
|
+
|
167
|
+
# Check if +id+ exists in the database of YARDoc anchor IDs
|
168
|
+
#
|
169
|
+
# @param id [String] the YARDoc anchor ID to check
|
170
|
+
#
|
171
|
+
# @return [true,false] whether this ID exists in the database of YARDoc anchor IDs
|
172
|
+
def yard_anchor_id?(id)
|
173
|
+
return @yard_anchor_ids.include?(id)
|
174
|
+
end
|
175
|
+
|
176
|
+
# Convert +name+ (header text) to a GitHub anchor ID.
|
177
|
+
#
|
178
|
+
# If the converted ID already exists in the database,
|
179
|
+
# then the ID will be updated according to GFM rules.
|
180
|
+
#
|
181
|
+
# @param name [String] the name (header text) to convert
|
182
|
+
#
|
183
|
+
# @return [String] the converted GitHub anchor ID for this database
|
184
|
+
#
|
185
|
+
# @see https://gist.github.com/asabaylus/3071099#gistcomment-2834467
|
186
|
+
# @see https://github.com/jch/html-pipeline/blob/master/lib/html/pipeline/toc_filter.rb
|
187
|
+
def to_github_anchor_id(name)
|
188
|
+
id = name.dup()
|
189
|
+
|
190
|
+
id.strip!()
|
191
|
+
id.gsub!(/&[^;]+;/,'') # Remove entities: &...;
|
192
|
+
id.gsub!(/[^\p{Word}\- ]/u,'')
|
193
|
+
id.tr!(' ','-')
|
194
|
+
|
195
|
+
if RUBY_VERSION >= '2.4'
|
196
|
+
id.downcase!(:ascii)
|
197
|
+
else
|
198
|
+
id.downcase!()
|
199
|
+
end
|
200
|
+
|
201
|
+
id = URI.escape(id) # For non-English languages
|
202
|
+
|
203
|
+
# Duplicates
|
204
|
+
dup_num = 1
|
205
|
+
orig_id = id.dup()
|
206
|
+
|
207
|
+
while @anchor_ids.key?(id)
|
208
|
+
id = "#{orig_id}-#{dup_num}"
|
209
|
+
dup_num += 1
|
210
|
+
end
|
211
|
+
|
212
|
+
return id
|
213
|
+
end
|
214
|
+
|
215
|
+
# Dumps the key-value database of GFM & YARDoc anchor IDs.
|
216
|
+
#
|
217
|
+
# @return [String] the database of anchor IDs as a String
|
218
|
+
def to_s()
|
219
|
+
s = ''.dup()
|
220
|
+
|
221
|
+
@anchor_ids.keys.sort_by{|key| key.to_s()}.each do |key|
|
222
|
+
s << "[#{key}] => '#{@anchor_ids[key]}'\n"
|
223
|
+
end
|
224
|
+
|
225
|
+
return s
|
226
|
+
end
|
227
|
+
|
228
|
+
# Convert +name+ (header text) to a YARDoc anchor ID.
|
229
|
+
#
|
230
|
+
# If the converted ID already exists in the database,
|
231
|
+
# then the ID will be updated according to YARDoc rules,
|
232
|
+
# which requires incrementing a common number variable.
|
233
|
+
#
|
234
|
+
# The logic for this is pulled from +doc/app.js#generateTOC()+,
|
235
|
+
# which you can generate using +rake yard+ or +yardoc+ on the command line.
|
236
|
+
#
|
237
|
+
# @note Be aware that this will increment a common number variable
|
238
|
+
# every time you call this with a duplicate.
|
239
|
+
#
|
240
|
+
# @param name [String] the name (header text) to convert
|
241
|
+
#
|
242
|
+
# @return [String] the converted YARDoc anchor ID for this database
|
243
|
+
def to_yard_anchor_id(name)
|
244
|
+
id = name.dup()
|
245
|
+
|
246
|
+
id.strip!()
|
247
|
+
id.gsub!(/&[^;]+;/,'_') # Replace entities: &...;
|
248
|
+
id.gsub!(/[^a-z0-9-]/i,'_')
|
249
|
+
id = URI.escape(id) # For non-English languages
|
250
|
+
|
251
|
+
# Duplicates
|
252
|
+
orig_id = id.dup()
|
253
|
+
|
254
|
+
while @yard_anchor_ids.include?(id)
|
255
|
+
id = "#{orig_id}#{@yard_dup_num}"
|
256
|
+
@yard_dup_num += 1
|
257
|
+
end
|
258
|
+
|
259
|
+
return id
|
260
|
+
end
|
261
|
+
end
|
262
|
+
end
|