dnote 1.1.4 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. data/HISTORY +29 -0
  2. data/bin/dnote +2 -2
  3. data/lib/dnote.rb +2 -3
  4. data/lib/dnote/format.rb +26 -69
  5. data/lib/dnote/note.rb +57 -0
  6. data/lib/dnote/notes.rb +158 -97
  7. data/lib/dnote/session.rb +277 -0
  8. data/lib/dnote/templates/html.erb +4 -4
  9. data/lib/dnote/templates/html/file.erb +40 -0
  10. data/lib/dnote/templates/html/label.erb +41 -0
  11. data/lib/dnote/templates/html/list.erb +33 -0
  12. data/lib/dnote/templates/json.erb +8 -0
  13. data/lib/dnote/templates/json/file.erb +8 -0
  14. data/lib/dnote/templates/json/label.erb +8 -0
  15. data/lib/dnote/templates/json/list.erb +8 -0
  16. data/lib/dnote/templates/md.erb +18 -0
  17. data/lib/dnote/templates/md/file.erb +13 -0
  18. data/lib/dnote/templates/md/label.erb +18 -0
  19. data/lib/dnote/templates/md/list.erb +9 -0
  20. data/lib/dnote/templates/rdoc.erb +3 -3
  21. data/lib/dnote/templates/rdoc/file.erb +9 -0
  22. data/lib/dnote/templates/rdoc/label.erb +11 -0
  23. data/lib/dnote/templates/rdoc/list.erb +6 -0
  24. data/lib/dnote/templates/soap.erb +4 -0
  25. data/lib/dnote/templates/soap/file.erb +4 -0
  26. data/lib/dnote/templates/soap/label.erb +4 -0
  27. data/lib/dnote/templates/soap/list.erb +4 -0
  28. data/lib/dnote/templates/text.erb +11 -0
  29. data/lib/dnote/templates/text/file.erb +10 -0
  30. data/lib/dnote/templates/text/label.erb +11 -0
  31. data/lib/dnote/templates/text/list.erb +7 -0
  32. data/lib/dnote/templates/xml.erb +6 -6
  33. data/lib/dnote/templates/xml/file.erb +15 -0
  34. data/lib/dnote/templates/xml/label.erb +15 -0
  35. data/lib/dnote/templates/xml/list.erb +6 -0
  36. data/lib/dnote/templates/xoxo.erb +4 -0
  37. data/lib/dnote/templates/xoxo/file.erb +4 -0
  38. data/lib/dnote/templates/xoxo/label.erb +4 -0
  39. data/lib/dnote/templates/xoxo/list.erb +6 -0
  40. data/lib/dnote/templates/yaml.erb +1 -0
  41. data/lib/dnote/templates/yaml/file.erb +1 -0
  42. data/lib/dnote/templates/yaml/label.erb +1 -0
  43. data/lib/dnote/templates/yaml/list.erb +1 -0
  44. data/lib/plugins/syckle/dnote.rb +35 -8
  45. data/meta/version +1 -1
  46. data/test/cases/notes_case.rb +20 -31
  47. metadata +44 -14
  48. data/MANIFEST +0 -33
  49. data/lib/dnote/command.rb +0 -134
  50. data/lib/dnote/site.rb +0 -140
  51. data/lib/dnote/templates/gnu.erb +0 -8
  52. data/lib/dnote/templates/markdown.erb +0 -17
data/HISTORY CHANGED
@@ -1,5 +1,34 @@
1
1
  = RELEASE HISTORY
2
2
 
3
+ == 1.2 / 2010-02-18
4
+
5
+ By request this release adds additional formats, allowing notes to be
6
+ sorted by filename as well a label. In addition, paths can now be
7
+ excluded from the search. To implement these changes it was necessary
8
+ to makes some significant under-the-hood adjustments, and this required
9
+ making some adjustments to the design of the templates and the
10
+ command-line interface.
11
+
12
+ If are using any of your own custom templates you will have to make
13
+ adjustments accordingly --which basically entails exchanging +notes.each+
14
+ for +notes.by_label_file.each+. Also, notice that the serialization formats
15
+ have changed accordingly to match the improved underlying model.
16
+
17
+ On the command-line, the format type itself is no longer used as the
18
+ option name, e.g. "--yaml", but instead use "-f", e.g. "-f yaml". This
19
+ opens DNote up to many more templates. Use "-T" to get a list of all
20
+ template format available.
21
+
22
+ Changes:
23
+
24
+ * Improve underlying model by adding a Note class.
25
+ * Add --exclude and --ignore options.
26
+ * Add new formats and rename "gnu" formats to "text".
27
+ * Use --format/-f to designate formats.
28
+ * Renamed --template/-t option to --custom/-c.
29
+ * Add --templates/-T to list all format templates.
30
+
31
+
3
32
  == 1.1 / 2010-02-06
4
33
 
5
34
  This relase primarily adjusts the way output it rendered
data/bin/dnote CHANGED
@@ -1,4 +1,4 @@
1
1
  #!/usr/bin/env ruby
2
- require "dnote/command"
3
- DNote.run
2
+ require "dnote"
3
+ DNote::Session.main(*ARGV)
4
4
 
@@ -1,8 +1,7 @@
1
1
  module DNote
2
- VERSION = "1.1.3" #:till: VERSION = "<%= version %>"
2
+ VERSION = "1.2.0" #:till: VERSION = "<%= version %>"
3
3
 
4
- require 'dnote/notes'
5
- require 'dnote/format'
4
+ require 'dnote/session'
6
5
 
7
6
  # NOTE: Toying with the idea of making DNote a class.
8
7
 
@@ -24,6 +24,9 @@ module DNote
24
24
  #
25
25
  attr_accessor :format
26
26
 
27
+ #
28
+ attr_accessor :subtype
29
+
27
30
  #
28
31
  attr_accessor :output
29
32
 
@@ -38,12 +41,12 @@ module DNote
38
41
 
39
42
  #
40
43
  def initialize(notes, options={})
41
- @notes = notes
42
- @format = :gnu
43
- @title = "Developer's Notes"
44
- options.each do |k,v|
45
- __send__("#{k}=", v) if v
46
- end
44
+ @notes = notes
45
+ @format = 'text'
46
+ @subtype = 'label'
47
+ @title = "Developer's Notes"
48
+ options.each{ |k,v| __send__("#{k}=", v) if v }
49
+ yield(self) if block_given?
47
50
  end
48
51
 
49
52
  #
@@ -51,78 +54,32 @@ module DNote
51
54
  if notes.empty?
52
55
  $stderr << "No #{notes.labels.join(', ')} notes.\n"
53
56
  else
54
- raise ArgumentError unless respond_to?("render_#{format}")
55
- __send__("render_#{format}")
57
+ case format
58
+ when 'custom'
59
+ render_custom
60
+ else
61
+ render_template
62
+ end
56
63
  end
57
64
  end
58
65
 
59
- # S E R I A L I Z A T I O N
60
-
61
- def render_yaml
62
- result = notes.to_yaml
63
- publish(result)
64
- end
65
-
66
- def render_json
67
- result = notes.to_json
68
- publish(result)
69
- end
70
-
71
- # M L M A R K U P
72
-
73
- def render_soap
74
- result = notes.to_soap
75
- publish(result)
76
- end
77
-
78
- def render_xoxo
79
- result = notes.to_xoxo
80
- publish(result)
81
- end
82
-
83
- def render_xml
84
- template = File.join(File.dirname(__FILE__), 'templates/xml.erb')
85
- result = erb(template)
86
- publish(result)
87
- end
88
-
89
- def render_html
90
- template = File.join(File.dirname(__FILE__), 'templates/html.erb')
91
- result = erb(template)
92
- publish(result)
93
- end
94
-
95
- def render_index
96
- template = File.join(File.dirname(__FILE__), 'templates/html.erb')
97
- result = erb(template)
98
- publish(result, 'index.html')
99
- end
100
-
101
- # W I K I M A R K U P
102
-
103
- def render_gnu
104
- template = File.join(File.dirname(__FILE__), 'templates/gnu.erb')
105
- result = erb(template)
106
- publish(result)
107
- end
66
+ # C U S T O M
108
67
 
109
- def render_rdoc
110
- template = File.join(File.dirname(__FILE__), 'templates/rdoc.erb')
111
- result = erb(template)
112
- publish(result)
113
- end
114
-
115
- def render_markdown
116
- template = File.join(File.dirname(__FILE__), 'templates/markdown.erb')
68
+ #
69
+ def render_custom
70
+ #raise ArgumentError unless File.exist?(template)
117
71
  result = erb(template)
118
- publish(result)
72
+ publish(result)
119
73
  end
120
74
 
121
- # C U S T O M T E M P L A T E
75
+ # T E M P L A T E
122
76
 
123
- def render_custom
77
+ #
78
+ def render_template
79
+ template = File.join(File.dirname(__FILE__), 'templates', "#{format}.erb")
80
+ raise "No such format - #{format}" unless File.exist?(template)
124
81
  result = erb(template)
125
- publish(result)
82
+ publish(result)
126
83
  end
127
84
 
128
85
  private
@@ -0,0 +1,57 @@
1
+ module DNote
2
+
3
+ #
4
+ class Note
5
+ attr :file
6
+ attr :label
7
+ attr :line
8
+ attr :text
9
+
10
+ def initialize(file, label, line, text)
11
+ @file = file
12
+ @label = label
13
+ @line = line
14
+ @text = text.rstrip
15
+ end
16
+
17
+ #
18
+ def to_s
19
+ "#{label}: #{text}"
20
+ end
21
+
22
+ #
23
+ def to_str
24
+ "#{label}: #{text}"
25
+ end
26
+
27
+ #
28
+ def textline
29
+ text.gsub("\n", " ")
30
+ end
31
+
32
+ # Sort by file name and line number.
33
+ def <=>(other)
34
+ s = file <=> other.file
35
+ return s unless s == 0
36
+ line <=> other.line
37
+ end
38
+
39
+ def to_h
40
+ { 'label'=>label, 'text'=>textline, 'file'=>file, 'line'=>line }
41
+ end
42
+
43
+ def to_h_raw
44
+ { 'label'=>label, 'text'=>text, 'file'=>file, 'line'=>line }
45
+ end
46
+
47
+ def to_json(*args)
48
+ to_h_raw.to_json(*args)
49
+ end
50
+
51
+ def to_yaml(*args)
52
+ to_h_raw.to_yaml(*args)
53
+ end
54
+ end
55
+
56
+ end
57
+
@@ -1,15 +1,16 @@
1
1
  require 'pathname'
2
+ require 'dnote/note'
2
3
 
3
4
  module DNote
4
5
 
5
6
  # = Developer Notes
6
7
  #
7
8
  # This class goes through you source files and compiles a list
8
- # of any labeled comments. Labels are single word prefixes to
9
- # a comment ending in a colon.
9
+ # of any labeled comments. Labels are all-cap single word prefixes
10
+ # to a comment ending in a colon.
10
11
  #
11
- # By default the labels supported are TODO, FIXME, OPTIMIZE
12
- # and DEPRECATE.
12
+ # Special labels do require the colon. By default these are +TODO+,
13
+ # +FIXME+, +OPTIMIZE+ and +DEPRECATE+.
13
14
  #
14
15
  #--
15
16
  # TODO: Add ability to read header notes. They often
@@ -21,59 +22,58 @@ module DNote
21
22
  # Default paths (all ruby scripts).
22
23
  DEFAULT_PATHS = ["**/*.rb"]
23
24
 
24
- # Default note labels to look for in source code.
25
+ # Default note labels to look for in source code. (NOT CURRENTLY USED!)
25
26
  DEFAULT_LABELS = ['TODO', 'FIXME', 'OPTIMIZE', 'DEPRECATE']
26
27
 
27
- # Paths to search.
28
- attr_accessor :paths
28
+ # Files to search for notes.
29
+ attr_accessor :files
29
30
 
30
- # Labels to document. Defaults are: TODO, FIXME, OPTIMIZE and DEPRECATE.
31
+ # Labels to document. Defaults are: +TODO+, +FIXME+, +OPTIMIZE+ and +DEPRECATE+.
31
32
  attr_accessor :labels
32
33
 
33
- #
34
- def initialize(paths, labels=nil)
35
- @paths = [paths || DEFAULT_PATHS ].flatten
36
- @labels = [labels || DEFAULT_LABELS].flatten
34
+ # Require label colon? Default is +true+.
35
+ attr_accessor :colon
36
+
37
+ # New set of notes for give +files+ and optional special labels.
38
+ def initialize(files, options={})
39
+ @files = [files].flatten
40
+ @labels = [options[:labels]].flatten.compact
41
+ @colon = options[:colon].nil? ? true : options[:colon]
37
42
  parse
38
43
  end
39
44
 
40
- #
45
+ # Array of notes.
41
46
  def notes
42
47
  @notes
43
48
  end
44
49
 
45
- #
50
+ # Notes counts by label.
46
51
  def counts
47
- @counts
52
+ @counts ||= (
53
+ h = {}
54
+ by_label.each do |label, notes|
55
+ h[label] = notes.size
56
+ end
57
+ h
58
+ )
48
59
  end
49
60
 
50
- #
61
+ # Iterate through notes.
51
62
  def each(&block)
52
63
  notes.each(&block)
53
64
  end
54
65
 
55
- #
66
+ # No notes?
56
67
  def empty?
57
68
  notes.empty?
58
69
  end
59
70
 
60
- #
61
- def labels=(labels)
62
- @labels = (
63
- case labels
64
- when String
65
- labels.split(/[:;,]/)
66
- else
67
- labels = [labels].flatten.compact.uniq.map{ |s| s.to_s }
68
- end
69
- )
70
- end
71
-
72
- # Gather and count notes. This returns two elements,
73
- # a hash in the form of label=>notes and a counts hash.
74
-
71
+ # Gather notes.
72
+ #--
73
+ # TODO: Play gold with Notes#parse.
74
+ #++
75
75
  def parse
76
- records, counts = [], Hash.new(0)
76
+ records = []
77
77
  files.each do |fname|
78
78
  next unless File.file?(fname)
79
79
  #next unless fname =~ /\.rb$/ # TODO: should this be done?
@@ -81,13 +81,12 @@ module DNote
81
81
  lineno, save, text = 0, nil, nil
82
82
  while line = f.gets
83
83
  lineno += 1
84
- save = match_common(line, lineno, fname) || match_arbitrary(line, lineno, fname)
84
+ save = match(line, lineno, fname)
85
85
  if save
86
86
  #file = fname
87
- text = save['note']
87
+ text = save.text
88
88
  #save = {'label'=>label,'file'=>file,'line'=>line_no,'note'=>text}
89
89
  records << save
90
- counts[save['label']] += 1
91
90
  else
92
91
  if text
93
92
  if line =~ /^\s*[#]{0,1}\s*$/ or line !~ /^\s*#/ or line =~ /^\s*#[+][+]/
@@ -105,98 +104,160 @@ module DNote
105
104
  end
106
105
  end
107
106
  end
108
- # organize the notes
109
- notes = organize(records)
110
- #
111
- @notes, @counts = notes, counts
107
+
108
+ @notes = records.sort
112
109
  end
113
110
 
114
111
  #
115
- def files
116
- @files ||= (
117
- [self.paths].flatten.map do |path|
118
- if File.directory?(path)
119
- Dir.glob(File.join(path, '**/*'))
120
- else
121
- Dir.glob(path)
122
- end
123
- end.flatten.uniq
124
- )
112
+ def match(line, lineno, file)
113
+ if labels.empty?
114
+ match_general(line, lineno, file)
115
+ else
116
+ match_special(line, lineno, file)
117
+ end
125
118
  end
126
119
 
127
- # TODO: ruby-1.9.1-p378 reports: notes.rb:131:in `match': invalid byte sequence in UTF-8
128
- def match_common(line, lineno, file)
120
+ # Match special notes.
121
+ def match_special(line, lineno, file)
129
122
  rec = nil
130
123
  labels.each do |label|
131
- if md = /\#\s*#{Regexp.escape(label)}[:]?\s*(.*?)$/.match(line)
124
+ if md = match_special_regex(label).match(line)
132
125
  text = md[1]
133
- rec = {'label'=>label,'file'=>file,'line'=>lineno,'note'=>text}
126
+ #rec = {'label'=>label,'file'=>file,'line'=>lineno,'note'=>text}
127
+ rec = Note.new(file, label, lineno, text)
134
128
  end
135
129
  end
136
- return rec
130
+ rec
137
131
  end
138
132
 
139
- #
140
- def match_arbitrary(line, lineno, file)
133
+ #--
134
+ # TODO: ruby-1.9.1-p378 reports: `match': invalid byte sequence in UTF-8
135
+ #++
136
+ def match_special_regex(label)
137
+ if colon
138
+ /\#\s*#{Regexp.escape(label)}[:]\s*(.*?)$/
139
+ else
140
+ /\#\s*#{Regexp.escape(label)}[:]?\s*(.*?)$/
141
+ end
142
+ end
143
+
144
+ # Match notes that are labeled with a colon.
145
+ def match_general(line, lineno, file)
141
146
  rec = nil
142
- labels.each do |label|
143
- if md = /\#\s*([A-Z]+)[:]\s*(.*?)$/.match(line)
144
- label, text = md[1], md[2]
145
- rec = {'label'=>label,'file'=>file,'line'=>lineno,'note'=>text}
146
- end
147
+ if md = match_general_regex.match(line)
148
+ label, text = md[1], md[2]
149
+ #rec = {'label'=>label,'file'=>file,'line'=>lineno,'note'=>text}
150
+ rec = Note.new(file, label, lineno, text)
147
151
  end
148
152
  return rec
149
153
  end
150
154
 
151
- # Organize records in heirarchical form.
152
155
  #
153
- def organize(records)
154
- orecs = {}
155
- records.each do |record|
156
- label = record['label']
157
- file = record['file']
158
- line = record['line']
159
- note = record['note'].rstrip
160
- orecs[label] ||= {}
161
- orecs[label][file] ||= []
162
- orecs[label][file] << [line, note]
156
+ def match_general_regex
157
+ if colon
158
+ /\#\s*([A-Z]+)[:]\s+(.*?)$/
159
+ else
160
+ /\#\s*([A-Z]+)[:]?\s+(.*?)$/
163
161
  end
164
- orecs
165
162
  end
166
163
 
167
- #
168
- def to(format)
169
- __send__("to_#{format}")
164
+ # Organize notes into a hash with labels for keys.
165
+ def by_label
166
+ @by_label ||= (
167
+ list = {}
168
+ notes.each do |note|
169
+ list[note.label] ||= []
170
+ list[note.label] << note
171
+ list[note.label].sort #!{ |a,b| a.line <=> b.line }
172
+ end
173
+ list
174
+ )
170
175
  end
171
176
 
172
- #
173
- def to_yaml
174
- require 'yaml'
175
- notes.to_yaml
177
+ # Organize notes into a hash with filename for keys.
178
+ def by_file
179
+ @by_file ||= (
180
+ list = {}
181
+ notes.each do |note|
182
+ list[note.file] ||= []
183
+ list[note.file] << note
184
+ list[note.file].sort! #!{ |a,b| a.line <=> b.line }
185
+ end
186
+ list
187
+ )
176
188
  end
177
189
 
178
- #
179
- def to_json
180
- begin
181
- require 'json'
182
- rescue LoadError
183
- require 'json_pure'
184
- end
185
- notes.to_json
190
+ # Organize notes into a hash with labels for keys, followed
191
+ # by a hash with filename for keys.
192
+ def by_label_file
193
+ @by_label ||= (
194
+ list = {}
195
+ notes.each do |note|
196
+ list[note.label] ||= {}
197
+ list[note.label][note.file] ||= []
198
+ list[note.label][note.file] << note
199
+ list[note.label][note.file].sort! #{ |a,b| a.line <=> b.line }
200
+ end
201
+ list
202
+ )
203
+ end
204
+
205
+ # Organize notes into a hash with filenames for keys, followed
206
+ # by a hash with labels for keys.
207
+ def by_file_label
208
+ @by_file ||= (
209
+ list = {}
210
+ notes.each do |note|
211
+ list[note.file] ||= {}
212
+ list[note.file][note.label] ||= []
213
+ list[note.file][note.label] << note
214
+ list[note.file][note.label].sort! #{ |a,b| a.line <=> b.line }
215
+ end
216
+ list
217
+ )
186
218
  end
187
219
 
188
- # Soap envelope XML.
189
- def to_soap
190
- require 'soap/marshal'
191
- SOAP::Marshal.marshal(notes)
220
+ # Convert to an array of hashes.
221
+ def to_a
222
+ notes.map{ |n| n.to_h }
192
223
  end
193
224
 
194
- # XOXO microformat.
195
- def to_xoxo
196
- require 'xoxo'
197
- notes.to_xoxo
225
+ # Same as #by_label.
226
+ def to_h
227
+ by_label
198
228
  end
199
229
 
230
+ # Convert to array of hashes then to YAML.
231
+ #def to_yaml
232
+ # require 'yaml'
233
+ # to_a.to_yaml
234
+ #end
235
+
236
+ # Convert to array of hashes then to JSON.
237
+ #def to_json
238
+ # begin
239
+ # require 'json'
240
+ # rescue LoadError
241
+ # require 'json_pure'
242
+ # end
243
+ # to_a.to_json
244
+ #end
245
+
246
+ # Convert to array of hashes then to a SOAP XML envelope.
247
+ #def to_soap
248
+ # require 'soap/marshal'
249
+ # SOAP::Marshal.marshal(to_a)
250
+ #end
251
+
252
+ # XOXO microformat.
253
+ #--
254
+ # TODO: Would to_xoxo be better organized by label and or file?
255
+ #++
256
+ #def to_xoxo
257
+ # require 'xoxo'
258
+ # to_a.to_xoxo
259
+ #end
260
+
200
261
  end
201
262
 
202
263
  end