dnote 0.8

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