lazydoc 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,19 @@
1
+ module Lazydoc
2
+
3
+ # A special type of self-resolving Comment that whose to_s returns the
4
+ # trailer, or an empty string if trailer is nil.
5
+ #
6
+ # t = Trailer.new
7
+ # t.subject = "def method # trailer string"
8
+ # t.to_s # => "trailer string"
9
+ #
10
+ class Trailer < Comment
11
+
12
+ # Self-resolves and returns trailer, or an empty
13
+ # string if trailer is nil.
14
+ def to_s
15
+ resolve
16
+ trailer.to_s
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,232 @@
1
+ require 'strscan'
2
+
3
+ module Lazydoc
4
+
5
+ # A number of utility methods used by Comment, factored out for
6
+ # testing and re-use.
7
+ module Utils
8
+ module_function
9
+
10
+ def split_lines(str)
11
+ (str.empty? ? [""] : str.split(/\r?\n/))
12
+ end
13
+
14
+ # Converts str to a StringScanner (or returns str if it already is
15
+ # a StringScanner). Raises a TypeError if str is not a String
16
+ # or a StringScanner.
17
+ def convert_to_scanner(str)
18
+ case str
19
+ when String then StringScanner.new(str)
20
+ when StringScanner then str
21
+ else raise TypeError, "can't convert #{str.class} into StringScanner"
22
+ end
23
+ end
24
+
25
+ # Scan determines if and how to add a line fragment to a comment and
26
+ # yields the appropriate fragments to the block. Returns true if
27
+ # fragments are yielded and false otherwise.
28
+ #
29
+ # Content may be built from an array of lines using scan like so:
30
+ #
31
+ # lines = [
32
+ # "# comments spanning multiple",
33
+ # "# lines are collected",
34
+ # "#",
35
+ # "# while indented lines",
36
+ # "# are preserved individually",
37
+ # "# ",
38
+ # "not a comment line",
39
+ # "# skipped since the loop breaks",
40
+ # "# at the first non-comment line"]
41
+ #
42
+ # c = Comment.new
43
+ # lines.each do |line|
44
+ # break unless Utils.scan(line) do |fragment|
45
+ # c.push(fragment)
46
+ # end
47
+ # end
48
+ #
49
+ # c.content
50
+ # # => [
51
+ # # ['comments spanning multiple', 'lines are collected'],
52
+ # # [''],
53
+ # # [' while indented lines'],
54
+ # # [' are preserved individually'],
55
+ # # [''],
56
+ # # []]
57
+ #
58
+ def scan(line) # :yields: fragment
59
+ return false unless line =~ /^[ \t]*#[ \t]?(([ \t]*).*?)\r?$/
60
+ categorize($1, $2) do |fragment|
61
+ yield(fragment)
62
+ end
63
+ true
64
+ end
65
+
66
+ # Parses an argument string (anything following the method name in a
67
+ # standard method definition, including parenthesis, comments, default
68
+ # values, etc) into an array of strings.
69
+ #
70
+ # Utils.parse_args("(a, b='default', *c, &block)")
71
+ # # => ["a", "b='default'", "*c", "&block"]
72
+ #
73
+ # Note the %-syntax for strings and arrays is not fully supported,
74
+ # ie %w, %Q, %q, etc. may not parse correctly. The same is true
75
+ # for multiline argument strings.
76
+ #
77
+ # Accepts a String or a StringScanner.
78
+ def scan_args(str)
79
+ scanner = convert_to_scanner(str)
80
+ str = scanner.string
81
+
82
+ # skip whitespace and leading LPAREN
83
+ scanner.skip(/\s*\(?\s*/)
84
+
85
+ args = []
86
+ brakets = braces = parens = 0
87
+ start = scanner.pos
88
+ broke = while scanner.skip(/.*?['"#,\(\)\{\}\[\]]/)
89
+ pos = scanner.pos - 1
90
+
91
+ case str[pos]
92
+ when ?,,nil
93
+ # skip if in brakets, braces, or parenthesis
94
+ next if parens > 0 || brakets > 0 || braces > 0
95
+
96
+ # ok, found an arg
97
+ args << str[start, pos-start].strip
98
+ start = pos + 1
99
+
100
+ when ?# then break(true) # break on a comment
101
+ when ?' then skip_quote(scanner, /'/) # parse over quoted strings
102
+ when ?" then skip_quote(scanner, /"/) # parse over double-quoted string
103
+
104
+ when ?( then parens += 1 # for brakets, braces, and parenthesis
105
+ when ?) # simply track the nesting EXCEPT for
106
+ break(true) if parens == 0 # RPAREN. If the closing parenthesis
107
+ parens -= 1 # is found, break.
108
+ when ?[ then braces += 1
109
+ when ?] then braces -= 1
110
+ when ?{ then brakets += 1
111
+ when ?} then brakets -= 1
112
+ end
113
+ end
114
+
115
+ # parse out the final arg. if the loop broke (ie
116
+ # a comment or the closing parenthesis was found)
117
+ # then the end position is determined by the
118
+ # scanner, otherwise take all that remains
119
+ pos = broke ? scanner.pos-1 : str.length
120
+ args << str[start, pos-start].strip unless pos == start
121
+
122
+ args
123
+ end
124
+
125
+ # Scans a stripped trailing comment off the input. Returns nil for
126
+ # strings without a trailing comment.
127
+ #
128
+ # Utils.scan_trailer "str with # trailer" # => "trailer"
129
+ # Utils.scan_trailer "'# in str' # trailer" # => "trailer"
130
+ # Utils.scan_trailer "str with without trailer" # => nil
131
+ #
132
+ # Note the %Q and %q syntax for defining strings is not supported
133
+ # within the leader and may not parse correctly:
134
+ #
135
+ # Utils.scan_trailer "%Q{# in str} # trailer" # => "in str} # trailer"
136
+ #
137
+ # Accepts a String or a StringScanner.
138
+ def scan_trailer(str)
139
+ scanner = convert_to_scanner(str)
140
+
141
+ args = []
142
+ brakets = braces = parens = 0
143
+ start = scanner.pos
144
+ while scanner.skip(/.*?['"#]/)
145
+ pos = scanner.pos - 1
146
+
147
+ case str[pos]
148
+ when ?# then return scanner.rest.strip # return the trailer
149
+ when ?' then skip_quote(scanner, /'/) # parse over quoted strings
150
+ when ?" then skip_quote(scanner, /"/) # parse over double-quoted string
151
+ end
152
+ end
153
+
154
+ return nil
155
+ end
156
+
157
+ # Splits a line of text along whitespace breaks into fragments of cols
158
+ # width. Tabs in the line will be expanded into tabsize spaces;
159
+ # fragments are rstripped of whitespace.
160
+ #
161
+ # Utils.wrap("some line that will wrap", 10) # => ["some line", "that will", "wrap"]
162
+ # Utils.wrap(" line that will wrap ", 10) # => [" line", "that will", "wrap"]
163
+ # Utils.wrap(" ", 10) # => []
164
+ #
165
+ # The wrapping algorithm is slightly modified from:
166
+ # http://blog.macromates.com/2006/wrapping-text-with-regular-expressions/
167
+ def wrap(line, cols=80, tabsize=2)
168
+ line = line.gsub(/\t/, " " * tabsize) unless tabsize == nil
169
+ line.gsub(/(.{1,#{cols}})( +|$\r?\n?)|(.{1,#{cols}})/, "\\1\\3\n").split(/\s*?\n/)
170
+ end
171
+
172
+ # Returns the line at which scanner currently resides. The position
173
+ # of scanner is not modified.
174
+ def determine_line_number(scanner)
175
+ scanner.string[0, scanner.pos].count("\n")
176
+ end
177
+
178
+ # Returns the index of the line where scanner ends up after the first
179
+ # match to regexp (starting at position 0). The existing position of
180
+ # scanner is not modified by this method. Returns nil if the scanner
181
+ # cannot match regexp.
182
+ #
183
+ # scanner = StringScanner.new %Q{zero\none\ntwo\nthree}
184
+ # Utils.scan_index(scanner, /two/) # => 2
185
+ # Utils.scan_index(scanner, /no match/) # => nil
186
+ #
187
+ def scan_index(scanner, regexp)
188
+ pos = scanner.pos
189
+ scanner.pos = 0
190
+ n = scanner.skip_until(regexp) ? determine_line_number(scanner) : nil
191
+ scanner.pos = pos
192
+ n
193
+ end
194
+
195
+ # Returns the index of the line in lines matching regexp,
196
+ # or nil if no line matches regexp.
197
+ def match_index(lines, regexp)
198
+ index = 0
199
+ lines.each do |line|
200
+ return index if line =~ regexp
201
+ index += 1
202
+ end
203
+ nil
204
+ end
205
+
206
+ # helper method to skip to the next non-escaped instance
207
+ # matching the quote regexp (/'/ or /"/).
208
+ def skip_quote(scanner, regexp) # :nodoc:
209
+ scanner.skip_until(regexp)
210
+ scanner.skip_until(regexp) while scanner.string[scanner.pos-2] == ?\\
211
+ end
212
+
213
+ # utility method used by scan to categorize and yield
214
+ # the appropriate objects to add the fragment to a
215
+ # comment
216
+ def categorize(fragment, indent) # :nodoc:
217
+ case
218
+ when fragment == indent
219
+ # empty comment line
220
+ yield [""]
221
+ yield []
222
+ when indent.empty?
223
+ # continuation line
224
+ yield fragment.rstrip
225
+ else
226
+ # indented line
227
+ yield [fragment.rstrip]
228
+ yield []
229
+ end
230
+ end
231
+ end
232
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lazydoc
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Simon Chiang
@@ -9,19 +9,10 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2008-12-07 00:00:00 -07:00
12
+ date: 2008-12-31 00:00:00 -07:00
13
13
  default_executable:
14
- dependencies:
15
- - !ruby/object:Gem::Dependency
16
- name: tap
17
- type: :development
18
- version_requirement:
19
- version_requirements: !ruby/object:Gem::Requirement
20
- requirements:
21
- - - ">="
22
- - !ruby/object:Gem::Version
23
- version: 0.11.1
24
- version:
14
+ dependencies: []
15
+
25
16
  description:
26
17
  email: simon.a.chiang@gmail.com
27
18
  executables: []
@@ -33,17 +24,26 @@ extra_rdoc_files:
33
24
  - MIT-LICENSE
34
25
  files:
35
26
  - lib/lazydoc.rb
27
+ - lib/lazydoc/arguments.rb
36
28
  - lib/lazydoc/attributes.rb
37
29
  - lib/lazydoc/comment.rb
38
30
  - lib/lazydoc/document.rb
39
31
  - lib/lazydoc/method.rb
32
+ - lib/lazydoc/subject.rb
33
+ - lib/lazydoc/trailer.rb
34
+ - lib/lazydoc/utils.rb
40
35
  - README
41
36
  - MIT-LICENSE
42
37
  has_rdoc: true
43
38
  homepage: http://tap.rubyforge.org/lazydoc
44
39
  post_install_message:
45
- rdoc_options: []
46
-
40
+ rdoc_options:
41
+ - --title
42
+ - Lazydoc
43
+ - --main
44
+ - README
45
+ - --line-numbers
46
+ - --inline-source
47
47
  require_paths:
48
48
  - lib
49
49
  required_ruby_version: !ruby/object:Gem::Requirement