dnote 0.8

Sign up to get free protection for your applications and to get access to all the features.
data/MANIFEST ADDED
@@ -0,0 +1,17 @@
1
+ README.rdoc
2
+ bin/dnote
3
+ lib/dnote
4
+ lib/dnote.rb
5
+ lib/dnote/notes.rb
6
+ lib/dnote/template
7
+ lib/dnote/template/index.html
8
+ lib/dnote/template/notes.rdoc
9
+ lib/dnote/template/notes.xml
10
+ meta/contact
11
+ meta/package
12
+ meta/project
13
+ meta/released
14
+ meta/repository
15
+ meta/summary
16
+ meta/title
17
+ meta/version
data/README.rdoc ADDED
@@ -0,0 +1,50 @@
1
+ = D'Note
2
+
3
+ * http://proutils.github.com/dnote
4
+ * http://github.com/proutils/dnote
5
+
6
+
7
+ == DESCRIPTION
8
+
9
+ Extract developement notes from source code and make some pretty RDoc and/or HTML
10
+ formatted files out of them.
11
+
12
+
13
+ == SYNOPSIS
14
+
15
+ Developer notes it the source code must be formate as follows:
16
+
17
+ # TYPE: description ...
18
+ # ... cont ...
19
+
20
+ All notes must be separated by a blank line. Eg.
21
+
22
+ # TYPE: description ...
23
+ #
24
+ # TYPE: description ...
25
+
26
+ Without the blank line the second note will be taken to be part of the first.
27
+ Any description that takes up more than one line must remain flush to the left
28
+ margin (if the first line is flush to the left margin too) b/c RDoc will mistake
29
+ of formatting the remaining lines as a +pre+ block it if is not. So...
30
+
31
+ # TYPE: ... description ...
32
+ # continue ...
33
+
34
+ Alternately the whole note can be a +pre+ block by indenting them. Then the
35
+ layout if freed-up.
36
+
37
+ # This is a description of something...
38
+ #
39
+ # TYPE: description ...
40
+ # continued ...
41
+
42
+
43
+ == COPYRIGHTS
44
+
45
+ (GPL Licensed)
46
+
47
+ Copyright (c) 2006, 2009 Thomas Sawyer
48
+
49
+ [INSERT NOTICE HERE]
50
+
data/bin/dnote ADDED
@@ -0,0 +1,59 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'optparse'
4
+ require 'dnote'
5
+
6
+ options = {}
7
+
8
+ opts = OptionParser.new do |opt|
9
+
10
+ opt.banner = "Usage: dnote [OPTIONS] path1 [path2 ...]"
11
+
12
+ opt.on("--label", "debug and verbose modes combined") do |lbl|
13
+ options[:labels] ||= []
14
+ options[:labels] << lbl
15
+ end
16
+
17
+ opt.on("--output", "-o [DIR]", "folder to store output") do |out|
18
+ options[:output] = out
19
+ end
20
+
21
+ opt.on("--debug", "debug mode") do
22
+ $DEBUG = true
23
+ end
24
+
25
+ opt.on("--verbose", "-v", "verbose mode") do
26
+ options[:verbose] = true
27
+ end
28
+
29
+ opt.on("--quiet", "-q", "surpress output") do
30
+ options[:quiet] = true
31
+ end
32
+
33
+ opt.on("--noop", "-n", "pretend mode") do
34
+ options[:quiet] = true
35
+ end
36
+
37
+ opt.on("--dryrun", "noop and verbose modes combined") do
38
+ options[:verbose] = true
39
+ options[:noop] = true
40
+ end
41
+
42
+ opt.on("--trace", "debug and verbose modes combined") do
43
+ $DEBUG = true
44
+ options[:verbose] = true
45
+ end
46
+
47
+ opt.on_tail('--help', '-h', "show this help information") do
48
+ puts self
49
+ exit
50
+ end
51
+
52
+ end
53
+
54
+ opts.parse!
55
+
56
+ paths = ARGV.dup
57
+ dnote = DNote.new(paths, options)
58
+ dnote.document
59
+
data/lib/dnote.rb ADDED
@@ -0,0 +1,10 @@
1
+ require 'dnote/notes'
2
+
3
+ module DNote
4
+ VERSION = "0.8" #:till: VERSION = "<%= version %>"
5
+
6
+ def self.new(*args)
7
+ Notes.new(*args)
8
+ end
9
+ end
10
+
@@ -0,0 +1,394 @@
1
+ require 'rexml/text'
2
+ require 'pathname'
3
+ require 'erb'
4
+ #require 'reap/project/scm'
5
+
6
+ module DNote
7
+
8
+ # = Developer Notes
9
+ #
10
+ # This class goes through you source files and compiles
11
+ # an list of any labeled comments. Labels are single word
12
+ # prefixes to a comment ending in a colon.
13
+ #
14
+ # By default the labels supported are TODO, FIXME, OPTIMIZE and DEPRECATE.
15
+ #
16
+ # Output is a set of files in XML and RDoc's simple
17
+ # markup format.
18
+ #
19
+ # TODO: Add ability to read header notes. They oftern
20
+ # have a outline format, rather then the single line.
21
+ #
22
+ # TODO: Need good CSS file.
23
+ #
24
+ # TODO: Need XSL?
25
+ #
26
+ class Notes
27
+
28
+ # Default note labels to look for in source code.
29
+ DEFAULT_LABELS = ['TODO', 'FIXME', 'OPTIMIZE', 'DEPRECATE']
30
+
31
+ #
32
+ DEFAULT_OUTPUT = Pathname.new('log/notes')
33
+
34
+ #
35
+ attr_accessor :title
36
+
37
+ # Non-Operative
38
+ attr_accessor :noop
39
+
40
+ # Verbose
41
+ attr_accessor :verbose
42
+
43
+ # Paths to search.
44
+ attr_accessor :paths
45
+
46
+ # Labels to document. Defaults are: TODO, FIXME, OPTIMIZE and DEPRECATE.
47
+ attr_accessor :labels
48
+
49
+ # Directory to save output. Defaults to standard log directory.
50
+ attr_accessor :output
51
+
52
+ # Format (xml, html, text).
53
+ # TODO: HTML format is not usable yet.
54
+ #attr_accessor :format
55
+
56
+ #
57
+ def initialize(paths, options={})
58
+ initialize_defaults
59
+
60
+ if paths.empty?
61
+ if file = File.exist?('meta/loadpath')
62
+ paths = YAML.load(File.new(file)).to_list
63
+ paths = Array === paths ? paths : paths.split(/\s+/)
64
+ elsif file = File.exist?('lib')
65
+ paths = ['lib']
66
+ else
67
+ paths = ['**/*.rb']
68
+ end
69
+ end
70
+
71
+ @paths = paths
72
+
73
+ options.each do |k, v|
74
+ __send__("#{k}=", v)
75
+ end
76
+ end
77
+
78
+ #
79
+ def initialize_defaults
80
+ @paths = ['lib']
81
+ @output = DEFAULT_OUTPUT
82
+ @labels = DEFAULT_LABELS
83
+ @title = "Developer's Notes"
84
+ #@format = 'xml'
85
+ end
86
+
87
+ #
88
+ def noop?
89
+ @noop
90
+ end
91
+
92
+ #
93
+ def verbose?
94
+ @verbose
95
+ end
96
+
97
+ #
98
+ def notes
99
+ @notes
100
+ end
101
+
102
+ #
103
+ def counts
104
+ @counts
105
+ end
106
+
107
+ #
108
+ def templates
109
+ Dir[File.join(File.dirname(__FILE__), 'template/*')]
110
+ end
111
+
112
+ # Scans source code for developer notes and writes them to
113
+ # well organized files.
114
+ #
115
+ def document
116
+ paths = self.paths
117
+ output = self.output
118
+
119
+ parse
120
+
121
+ #paths = paths.to_list
122
+
123
+ #labels = labels.split(',') if String === labels
124
+ #labels = [labels].flatten.compact
125
+
126
+ #records, counts = extract(labels, loadpath)
127
+ #records = organize(records)
128
+
129
+ #case format.to_s
130
+ #when 'rdoc', 'txt', 'text'
131
+ # text = format_rd(records)
132
+ #else
133
+ # text = format_xml(records)
134
+ #end
135
+
136
+ if notes.empty?
137
+ puts "No #{labels.join(', ')} notes."
138
+ else
139
+ templates.each do |template|
140
+ erb = ERB.new(File.read(template))
141
+ text = erb.result(binding)
142
+ #text = format_notes(notes, format)
143
+ file = write(File.basename(template), text)
144
+ #file = file #Pathname.new(file).relative_path_from(Pathname.pwd) #project.root
145
+ puts "Updated #{file}"
146
+ end
147
+ puts(counts.map{|l,n| "#{n} #{l}s"}.join(', '))
148
+ end
149
+ end
150
+
151
+ # Reset output directory, marking it as out-of-date.
152
+ def reset
153
+ if File.directory?(output)
154
+ File.utime(0,0,output)
155
+ puts "marked #{output}"
156
+ end
157
+ end
158
+
159
+ # Remove output directory.
160
+ def clean
161
+ if File.directory?(output)
162
+ fu.rm_r(output)
163
+ puts "removed #{output}"
164
+ end
165
+ end
166
+
167
+ #
168
+ def labels=(labels)
169
+ @labels = (
170
+ case labels
171
+ when String
172
+ labels.split(/[:;,]/)
173
+ else
174
+ labels = [labels].flatten.compact.uniq
175
+ end
176
+ )
177
+ end
178
+
179
+ #
180
+ def output=(output)
181
+ raise "output cannot be root" if File.expand_path(output) == "/"
182
+ @output = Pathname.new(output)
183
+ end
184
+
185
+ private
186
+
187
+ # Gather and count notes. This returns two elements,
188
+ # a hash in the form of label=>notes and a counts hash.
189
+ #
190
+ def parse
191
+ #
192
+ files = self.paths.map do |path|
193
+ if File.directory?(path)
194
+ Dir.glob(File.join(path, '**/*'))
195
+ else
196
+ Dir.glob(path)
197
+ end
198
+ end.flatten.uniq
199
+
200
+ #
201
+ records, counts = [], Hash.new(0)
202
+
203
+ # iterate through files extracting notes
204
+ files.each do |fname|
205
+ next unless File.file?(fname)
206
+ #next unless fname =~ /\.rb$/ # TODO should this be done?
207
+ File.open(fname) do |f|
208
+ line_no, save, text = 0, nil, nil
209
+ while line = f.gets
210
+ line_no += 1
211
+ labels.each do |label|
212
+ if line =~ /^\s*#\s*#{Regexp.escape(label)}[:]?\s*(.*?)$/
213
+ file = fname
214
+ text = ''
215
+ save = {'label'=>label,'file'=>file,'line'=>line_no,'note'=>text}
216
+ records << save
217
+ counts[label] += 1
218
+ end
219
+ end
220
+ if text
221
+ if line =~ /^\s*[#]{0,1}\s*$/ or line !~ /^\s*#/ or line =~ /^\s*#[+][+]/
222
+ text.strip!
223
+ text = nil
224
+ #records << save
225
+ else
226
+ text << line.gsub(/^\s*#\s*/,'')
227
+ end
228
+ end
229
+ end
230
+ end
231
+ end
232
+ # organize the notes
233
+ notes = organize(records)
234
+ #
235
+ @notes, @counts = notes, counts
236
+ end
237
+
238
+ # Organize records in heirarchical form.
239
+ #
240
+ def organize(records)
241
+ orecs = {}
242
+ records.each do |record|
243
+ label = record['label']
244
+ file = record['file']
245
+ line = record['line']
246
+ note = record['note'].rstrip
247
+ orecs[label] ||= {}
248
+ orecs[label][file] ||= []
249
+ orecs[label][file] << [line, note]
250
+ end
251
+ orecs
252
+ end
253
+
254
+ #
255
+ #def format_notes(notes, type=:rdoc)
256
+ # send("format_#{type}", notes)
257
+ #end
258
+
259
+ # Format notes in XML format.
260
+ #
261
+ def notes_xml
262
+ xml = []
263
+ xml << "<notes>"
264
+ notes.each do |label, per_file|
265
+ xml << %[<set label="#{label}">]
266
+ per_file.each do |file, line_notes|
267
+ xml << %[<file src="#{file}">]
268
+ line_notes.sort!{ |a,b| a[0] <=> b[0] }
269
+ line_notes.each do |line, note|
270
+ note = REXML::Text.normalize(note)
271
+ xml << %[<note line="#{line}" type="#{label}">#{note}</note>]
272
+ end
273
+ xml << %[</file>]
274
+ end
275
+ xml << %[</set>]
276
+ end
277
+ xml << "</notes>"
278
+ return xml.join("\n")
279
+ end
280
+
281
+ # Format notes in RDoc format.
282
+ #
283
+ def notes_rdoc
284
+ out = []
285
+ out << "= Development Notes"
286
+ notes.each do |label, per_file|
287
+ out << %[\n== #{label}]
288
+ per_file.each do |file, line_notes|
289
+ out << %[\n=== file://#{file}]
290
+ line_notes.sort!{ |a,b| a[0] <=> b[0] }
291
+ line_notes.each do |line, note|
292
+ out << %[* #{note} (#{line})]
293
+ end
294
+ end
295
+ end
296
+ return out.join("\n")
297
+ end
298
+
299
+ # HTML format.
300
+ #
301
+ def notes_html
302
+ xml = []
303
+ xml << %[<div class="notes">]
304
+ notes.each do |label, per_file|
305
+ xml << %[<h2>#{label}</h2>\n<ol class="set #{label.downcase}">]
306
+ per_file.each do |file, line_notes|
307
+ xml << %[<li><h3><a href="#{file}">#{file}</a></h3><ol class="file" href="#{file}">]
308
+ line_notes.sort!{ |a,b| a[0] <=> b[0] }
309
+ line_notes.each do |line, note|
310
+ note = REXML::Text.normalize(note)
311
+ xml << %[<li class="note #{label.downcase}" ref="#{line}">#{note} <sup>#{line}</sup></li>]
312
+ end
313
+ xml << %[</ol></li>]
314
+ end
315
+ xml << %[</div>]
316
+ end
317
+ xml << "</div>"
318
+ return xml.join("\n")
319
+ end
320
+
321
+ # Save notes.
322
+ #
323
+ def write(file, text)
324
+ file = output + file
325
+ fu.mkdir_p(output)
326
+ File.open(file, 'w') { |f| f << text } unless noop?
327
+ file
328
+ end
329
+
330
+ #
331
+ def fu
332
+ @fu ||= (
333
+ if noop? and verbose?
334
+ FileUtils::DryRun
335
+ elsif noop
336
+ FileUtils::Noop
337
+ elsif verbose
338
+ FileUtils::Verbose
339
+ else
340
+ FileUtils
341
+ end
342
+ )
343
+ end
344
+
345
+ end
346
+
347
+ end
348
+
349
+ # out = ''
350
+ #
351
+ # case format
352
+ # when 'yaml'
353
+ # out << records.to_yaml
354
+ # when 'list'
355
+ # records.each do |record|
356
+ # out << "* #{record['note']}\n"
357
+ # end
358
+ # else #when 'rdoc'
359
+ # labels.each do |label|
360
+ # recs = records.select{ |r| r['label'] == label }
361
+ # next if recs.empty?
362
+ # out << "\n= #{label}\n"
363
+ # last_file = nil
364
+ # recs.sort!{ |a,b| a['file'] <=> b['file'] }
365
+ # recs.each do |record|
366
+ # if last_file != record['file']
367
+ # out << "\n"
368
+ # last_file = record['file']
369
+ # out << "file://#{record['file']}\n"
370
+ # end
371
+ # out << "* #{record['note'].rstrip} (#{record['line']})\n"
372
+ # end
373
+ # end
374
+ # out << "\n---\n"
375
+ # out << counts.collect{|l,n| "#{n} #{l}s"}.join(' ')
376
+ # out << "\n"
377
+ # end
378
+
379
+ # # List TODO notes. Same as notes --label=TODO.
380
+ #
381
+ # def todo( options={} )
382
+ # options = options.to_openhash
383
+ # options.label = 'TODO'
384
+ # notes(options)
385
+ # end
386
+ #
387
+ # # List FIXME notes. Same as notes --label=FIXME.
388
+ #
389
+ # def fixme( options={} )
390
+ # options = options.to_openhash
391
+ # options.label = 'FIXME'
392
+ # notes(options)
393
+ # end
394
+
@@ -0,0 +1,30 @@
1
+ <html>
2
+ <head>
3
+ <title><%= title %></title>
4
+ <style>
5
+ body { margin: 0; padding: 0; }
6
+ .main {
7
+ width: 800px;
8
+ margin: 0 auto;
9
+ border: 1px solid #ccc;
10
+ padding: 0 20px 20px 20px;
11
+ }
12
+ h1 { margin: 25px 0; }
13
+ h2,h3,h4 { margin: 5px 0; padding: 0; color: 880044; }
14
+ h3 { color: 004488; }
15
+ h4 { color: 888844; }
16
+ ul { margin: 0; padding: 0; text-align: left; }
17
+ li { margin: 0; padding: 0; text-align: left; }
18
+ </style>
19
+ </head>
20
+ <body>
21
+ <div class="main">
22
+
23
+ <h1><%= title %></h1>
24
+
25
+ <%= notes_html %>
26
+
27
+ </div>
28
+ </boby>
29
+ </html>
30
+
@@ -0,0 +1 @@
1
+ <%= notes_rdoc %>
@@ -0,0 +1 @@
1
+ <%= notes_xml %>
data/meta/contact ADDED
@@ -0,0 +1 @@
1
+ http://googlegroups.com/group/proutils
data/meta/package ADDED
@@ -0,0 +1 @@
1
+ dnote
data/meta/project ADDED
@@ -0,0 +1 @@
1
+ proutils
data/meta/released ADDED
@@ -0,0 +1 @@
1
+ 2009-10-06
data/meta/repository ADDED
@@ -0,0 +1 @@
1
+ git://github.com/proutils/dnote.git
data/meta/summary ADDED
@@ -0,0 +1 @@
1
+ Extract developer notes from source code.
data/meta/title ADDED
@@ -0,0 +1 @@
1
+ D'Note
data/meta/version ADDED
@@ -0,0 +1 @@
1
+ 0.8
metadata ADDED
@@ -0,0 +1,75 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: dnote
3
+ version: !ruby/object:Gem::Version
4
+ version: "0.8"
5
+ platform: ruby
6
+ authors: []
7
+
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-10-09 00:00:00 -04:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description: |-
17
+ Extract developement notes from source code and make some pretty RDoc and/or HTML
18
+ formatted files out of them.
19
+ email: http://googlegroups.com/group/proutils
20
+ executables:
21
+ - dnote
22
+ extensions: []
23
+
24
+ extra_rdoc_files:
25
+ - MANIFEST
26
+ - README.rdoc
27
+ files:
28
+ - README.rdoc
29
+ - bin/dnote
30
+ - lib/dnote.rb
31
+ - lib/dnote/notes.rb
32
+ - lib/dnote/template/index.html
33
+ - lib/dnote/template/notes.rdoc
34
+ - lib/dnote/template/notes.xml
35
+ - meta/contact
36
+ - meta/package
37
+ - meta/project
38
+ - meta/released
39
+ - meta/repository
40
+ - meta/summary
41
+ - meta/title
42
+ - meta/version
43
+ - MANIFEST
44
+ has_rdoc: true
45
+ homepage:
46
+ licenses: []
47
+
48
+ post_install_message:
49
+ rdoc_options:
50
+ - --inline-source
51
+ - --title
52
+ - dnote api
53
+ require_paths:
54
+ - lib
55
+ required_ruby_version: !ruby/object:Gem::Requirement
56
+ requirements:
57
+ - - ">="
58
+ - !ruby/object:Gem::Version
59
+ version: "0"
60
+ version:
61
+ required_rubygems_version: !ruby/object:Gem::Requirement
62
+ requirements:
63
+ - - ">="
64
+ - !ruby/object:Gem::Version
65
+ version: "0"
66
+ version:
67
+ requirements: []
68
+
69
+ rubyforge_project: dnote
70
+ rubygems_version: 1.3.5
71
+ signing_key:
72
+ specification_version: 3
73
+ summary: Extract developer notes from source code.
74
+ test_files: []
75
+