summaryrefslogtreecommitdiff
path: root/examples/redis-unstable/utils/generate-module-api-doc.rb
diff options
context:
space:
mode:
Diffstat (limited to 'examples/redis-unstable/utils/generate-module-api-doc.rb')
-rwxr-xr-xexamples/redis-unstable/utils/generate-module-api-doc.rb195
1 files changed, 0 insertions, 195 deletions
diff --git a/examples/redis-unstable/utils/generate-module-api-doc.rb b/examples/redis-unstable/utils/generate-module-api-doc.rb
deleted file mode 100755
index cd45c93..0000000
--- a/examples/redis-unstable/utils/generate-module-api-doc.rb
+++ /dev/null
@@ -1,195 +0,0 @@
1#!/usr/bin/env ruby
2# coding: utf-8
3# gendoc.rb -- Converts the top-comments inside module.c to modules API
4# reference documentation in markdown format.
5
6# Convert the C comment to markdown
7def markdown(s)
8 s = s.gsub(/\*\/$/,"")
9 s = s.gsub(/^ ?\* ?/,"")
10 s = s.gsub(/^\/\*\*? ?/,"")
11 s.chop! while s[-1] == "\n" || s[-1] == " "
12 lines = s.split("\n")
13 newlines = []
14 # Fix some markdown
15 lines.each{|l|
16 # Rewrite RM_Xyz() to RedisModule_Xyz().
17 l = l.gsub(/(?<![A-Z_])RM_(?=[A-Z])/, 'RedisModule_')
18 # Fix more markdown, except in code blocks indented by 4 spaces, which we
19 # don't want to mess with.
20 if not l.start_with?(' ')
21 # Add backquotes around RedisModule functions and type where missing.
22 l = l.gsub(/(?<!`)RedisModule[A-z]+(?:\*?\(\))?/){|x| "`#{x}`"}
23 # Add backquotes around c functions like malloc() where missing.
24 l = l.gsub(/(?<![`A-z.])[a-z_]+\(\)/, '`\0`')
25 # Add backquotes around macro and var names containing underscores.
26 l = l.gsub(/(?<![`A-z\*])[A-Za-z]+_[A-Za-z0-9_]+/){|x| "`#{x}`"}
27 # Link URLs preceded by space or newline (not already linked)
28 l = l.gsub(/(^| )(https?:\/\/[A-Za-z0-9_\/\.\-]+[A-Za-z0-9\/])/,
29 '\1[\2](\2)')
30 # Replace double-dash with unicode ndash
31 l = l.gsub(/ -- /, ' – ')
32 end
33 # Link function names to their definition within the page
34 l = l.gsub(/`(RedisModule_[A-z0-9]+)[()]*`/) {|x|
35 $index[$1] ? "[#{x}](\##{$1})" : x
36 }
37 newlines << l
38 }
39 return newlines.join("\n")
40end
41
42# Linebreak a prototype longer than 80 characters on the commas, but only
43# between balanced parentheses so that we don't linebreak args which are
44# function pointers, and then aligning each arg under each other.
45def linebreak_proto(proto, indent)
46 if proto.bytesize <= 80
47 return proto
48 end
49 parts = proto.split(/,\s*/);
50 if parts.length == 1
51 return proto;
52 end
53 align_pos = proto.index("(") + 1;
54 align = " " * align_pos
55 result = parts.shift;
56 bracket_balance = 0;
57 parts.each{|part|
58 if bracket_balance == 0
59 result += ",\n" + indent + align
60 else
61 result += ", "
62 end
63 result += part
64 bracket_balance += part.count("(") - part.count(")")
65 }
66 return result;
67end
68
69# Given the source code array and the index at which an exported symbol was
70# detected, extracts and outputs the documentation.
71def docufy(src,i)
72 m = /RM_[A-z0-9]+/.match(src[i])
73 name = m[0]
74 name = name.sub("RM_","RedisModule_")
75 proto = src[i].sub("{","").strip+";\n"
76 proto = proto.sub("RM_","RedisModule_")
77 proto = linebreak_proto(proto, " ");
78 # Add a link target with the function name. (We don't trust the exact id of
79 # the generated one, which depends on the Markdown implementation.)
80 puts "<span id=\"#{name}\"></span>\n\n"
81 puts "### `#{name}`\n\n"
82 puts " #{proto}\n"
83 puts "**Available since:** #{$since[name] or "unreleased"}\n\n"
84 comment = ""
85 while true
86 i = i-1
87 comment = src[i]+comment
88 break if src[i] =~ /\/\*/
89 end
90 comment = markdown(comment)
91 puts comment+"\n\n"
92end
93
94# Print a comment from line until */ is found, as markdown.
95def section_doc(src, i)
96 name = get_section_heading(src, i)
97 comment = "<span id=\"#{section_name_to_id(name)}\"></span>\n\n"
98 while true
99 # append line, except if it's a horizontal divider
100 comment = comment + src[i] if src[i] !~ /^[\/ ]?\*{1,2} ?-{50,}/
101 break if src[i] =~ /\*\//
102 i = i+1
103 end
104 comment = markdown(comment)
105 puts comment+"\n\n"
106end
107
108# generates an id suitable for links within the page
109def section_name_to_id(name)
110 return "section-" +
111 name.strip.downcase.gsub(/[^a-z0-9]+/, '-').gsub(/^-+|-+$/, '')
112end
113
114# Returns the name of the first section heading in the comment block for which
115# is_section_doc(src, i) is true
116def get_section_heading(src, i)
117 if src[i] =~ /^\/\*\*? \#+ *(.*)/
118 heading = $1
119 elsif src[i+1] =~ /^ ?\* \#+ *(.*)/
120 heading = $1
121 end
122 return heading.gsub(' -- ', ' – ')
123end
124
125# Returns true if the line is the start of a generic documentation section. Such
126# section must start with the # symbol, i.e. a markdown heading, on the first or
127# the second line.
128def is_section_doc(src, i)
129 return src[i] =~ /^\/\*\*? \#/ ||
130 (src[i] =~ /^\/\*/ && src[i+1] =~ /^ ?\* \#/)
131end
132
133def is_func_line(src, i)
134 line = src[i]
135 return line =~ /RM_/ &&
136 line[0] != ' ' && line[0] != '#' && line[0] != '/' &&
137 src[i-1] =~ /\*\//
138end
139
140puts "<!-- This file is generated from module.c using\n"
141puts " redis/redis:utils/generate-module-api-doc.rb -->\n\n"
142src = File.open(File.dirname(__FILE__) ++ "/../src/module.c").to_a
143
144# Build function index
145$index = {}
146src.each_with_index do |line,i|
147 if is_func_line(src, i)
148 line =~ /RM_([A-z0-9]+)/
149 name = "RedisModule_#{$1}"
150 $index[name] = true
151 end
152end
153
154# Populate the 'since' map (name => version) if we're in a git repo.
155$since = {}
156git_dir = File.dirname(__FILE__) ++ "/../.git"
157if File.directory?(git_dir) && `which git` != ""
158 `git --git-dir="#{git_dir}" tag --sort=v:refname`.each_line do |version|
159 next if version !~ /^(\d+)\.\d+\.\d+?$/ || $1.to_i < 4
160 version.chomp!
161 `git --git-dir="#{git_dir}" cat-file blob "#{version}:src/module.c"`.each_line do |line|
162 if line =~ /^\w.*[ \*]RM_([A-z0-9]+)/
163 name = "RedisModule_#{$1}"
164 if ! $since[name]
165 $since[name] = version
166 end
167 end
168 end
169 end
170end
171
172# Print TOC
173puts "## Sections\n\n"
174src.each_with_index do |_line,i|
175 if is_section_doc(src, i)
176 name = get_section_heading(src, i)
177 puts "* [#{name}](\##{section_name_to_id(name)})\n"
178 end
179end
180puts "* [Function index](#section-function-index)\n\n"
181
182# Docufy: Print function prototype and markdown docs
183src.each_with_index do |_line,i|
184 if is_func_line(src, i)
185 docufy(src, i)
186 elsif is_section_doc(src, i)
187 section_doc(src, i)
188 end
189end
190
191# Print function index
192puts "<span id=\"section-function-index\"></span>\n\n"
193puts "## Function index\n\n"
194$index.keys.sort.each{|x| puts "* [`#{x}`](\##{x})\n"}
195puts "\n"