lazydoc 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README +36 -1
- data/lib/lazydoc/attributes.rb +20 -9
- data/lib/lazydoc/comment.rb +55 -6
- data/lib/lazydoc/document.rb +30 -5
- data/lib/lazydoc/method.rb +128 -0
- data/lib/lazydoc.rb +22 -0
- metadata +5 -4
data/README
CHANGED
@@ -63,7 +63,7 @@ Lazydoc::Comment.
|
|
63
63
|
# constant attribute, or an end
|
64
64
|
# key
|
65
65
|
# ..............................
|
66
|
-
#}
|
66
|
+
# }
|
67
67
|
|
68
68
|
In addition, individual lines of code may be registered and resolved by Lazydoc:
|
69
69
|
|
@@ -73,11 +73,46 @@ In addition, individual lines of code may be registered and resolved by Lazydoc:
|
|
73
73
|
doc.resolve
|
74
74
|
comment.subject # => " def method_one"
|
75
75
|
comment.content # => [["comment content for a code comment", "may similarly span multiple lines"]]
|
76
|
+
|
77
|
+
A variety of helper methods exist to register methods, in particular:
|
78
|
+
|
79
|
+
class Helpers
|
80
|
+
extend Lazydoc::Attributes
|
81
|
+
|
82
|
+
register_method___
|
83
|
+
# method_one was registered by the
|
84
|
+
# helper
|
85
|
+
def method_one(a, b='str', &c)
|
86
|
+
end
|
87
|
+
|
88
|
+
# method_two illustrates registration
|
89
|
+
# of the line that *calls* method_two
|
90
|
+
def method_two
|
91
|
+
Lazydoc.register_caller
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
# *THIS* is the line that gets registered
|
96
|
+
# by method_two
|
97
|
+
Helpers.new.method_two
|
98
|
+
|
99
|
+
doc = Helpers.lazydoc
|
100
|
+
doc.resolve
|
101
|
+
|
102
|
+
m1 = doc.comments[0]
|
103
|
+
m1.method_name # => "method_one"
|
104
|
+
m1.arguments # => ["a", "b='str'", "&c"]
|
105
|
+
m1.to_s # => "method_one was registered by the helper"
|
106
|
+
|
107
|
+
comment = doc.comments[1]
|
108
|
+
comment.subject # => "Helpers.new.method_two"
|
109
|
+
comment.to_s # => "*THIS* is the line that gets registered by method_two"
|
76
110
|
|
77
111
|
Check out these links for development, and bug tracking.
|
78
112
|
|
79
113
|
* Website[http://tap.rubyforge.org/lazydoc]
|
80
114
|
* Github[http://github.com/bahuvrihi/lazydoc/tree/master]
|
115
|
+
* Lighthouse[http://bahuvrihi.lighthouseapp.com/projects/19948-lazydoc/tickets?q=all]
|
81
116
|
* {Google Group}[http://groups.google.com/group/ruby-on-tap]
|
82
117
|
|
83
118
|
== Usage
|
data/lib/lazydoc/attributes.rb
CHANGED
@@ -1,24 +1,30 @@
|
|
1
|
+
require 'lazydoc'
|
2
|
+
|
1
3
|
module Lazydoc
|
2
|
-
# Attributes adds methods to declare class-level accessors
|
3
|
-
#
|
4
|
-
# be set manually.
|
4
|
+
# Attributes adds methods to declare class-level accessors for Lazydoc
|
5
|
+
# attributes.
|
5
6
|
#
|
6
7
|
# # ConstName::key value
|
7
8
|
# class ConstName
|
8
|
-
#
|
9
|
-
# include Lazydoc::Attributes
|
10
|
-
# end
|
9
|
+
# extend Lazydoc::Attributes
|
11
10
|
#
|
12
|
-
# self.source_file = __FILE__
|
13
11
|
# lazy_attr :key
|
14
12
|
# end
|
15
13
|
#
|
14
|
+
# ConstName.source_file # => __FILE__
|
16
15
|
# ConstName::key.subject # => 'value'
|
17
16
|
#
|
18
17
|
module Attributes
|
19
18
|
|
20
|
-
# The source_file for self.
|
19
|
+
# The source_file for self. By default set to the file where
|
20
|
+
# Attributes extends a class (if you include Attributes, you
|
21
|
+
# must set source_file manually).
|
21
22
|
attr_accessor :source_file
|
23
|
+
|
24
|
+
def self.extended(base) # :nodoc:
|
25
|
+
caller[1] =~ CALLER_REGEXP
|
26
|
+
base.source_file ||= $1
|
27
|
+
end
|
22
28
|
|
23
29
|
# Returns the lazydoc for source_file
|
24
30
|
def lazydoc(resolve=true)
|
@@ -37,6 +43,11 @@ end
|
|
37
43
|
def #{key}=(comment)
|
38
44
|
Lazydoc[source_file][to_s]['#{attribute}'] = comment
|
39
45
|
end}
|
40
|
-
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# Registers the next method.
|
49
|
+
def register_method___(comment_class=Method)
|
50
|
+
lazydoc(false).register___(comment_class, 1)
|
51
|
+
end
|
41
52
|
end
|
42
53
|
end
|
data/lib/lazydoc/comment.rb
CHANGED
@@ -105,7 +105,7 @@ module Lazydoc
|
|
105
105
|
else raise TypeError, "can't convert #{str.class} into StringScanner or String"
|
106
106
|
end
|
107
107
|
|
108
|
-
comment =
|
108
|
+
comment = self.new
|
109
109
|
while scanner.scan(/\r?\n?[ \t]*#[ \t]?(([ \t]*).*?)\r?$/)
|
110
110
|
fragment = scanner[1]
|
111
111
|
indent = scanner[2]
|
@@ -124,8 +124,10 @@ module Lazydoc
|
|
124
124
|
if parse_subject
|
125
125
|
scanner.skip(/\s+/)
|
126
126
|
unless scanner.peek(1) == '#'
|
127
|
-
|
128
|
-
|
127
|
+
if subject = scanner.scan(/.+?$/)
|
128
|
+
subject.strip!
|
129
|
+
end
|
130
|
+
comment.subject = subject
|
129
131
|
end
|
130
132
|
end
|
131
133
|
|
@@ -172,7 +174,40 @@ module Lazydoc
|
|
172
174
|
end
|
173
175
|
true
|
174
176
|
end
|
175
|
-
|
177
|
+
|
178
|
+
# Scans a stripped trailing comment off of str, tolerant to a leader
|
179
|
+
# that uses '#' within a string. Returns nil for strings without a
|
180
|
+
# trailing comment.
|
181
|
+
#
|
182
|
+
# Comment.scan_trailer "str with # trailer" # => "trailer"
|
183
|
+
# Comment.scan_trailer "'# in str' # trailer" # => "trailer"
|
184
|
+
# Comment.scan_trailer "str with without trailer" # => nil
|
185
|
+
#
|
186
|
+
# Note the %-syntax for strings is not fully supported, ie %Q, %q,
|
187
|
+
# etc. may not parse correctly. Accepts Strings or a StringScanner.
|
188
|
+
def scan_trailer(str)
|
189
|
+
scanner = case str
|
190
|
+
when StringScanner then str
|
191
|
+
when String then StringScanner.new(str)
|
192
|
+
else raise TypeError, "can't convert #{str.class} into StringScanner or String"
|
193
|
+
end
|
194
|
+
|
195
|
+
args = []
|
196
|
+
brakets = braces = parens = 0
|
197
|
+
start = scanner.pos
|
198
|
+
while scanner.skip(/.*?['"#]/)
|
199
|
+
pos = scanner.pos - 1
|
200
|
+
|
201
|
+
case str[pos]
|
202
|
+
when ?# then return scanner.rest.strip # return the trailer
|
203
|
+
when ?' then skip_quote(scanner, /'/) # parse over quoted strings
|
204
|
+
when ?" then skip_quote(scanner, /"/) # parse over double-quoted string
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
return nil
|
209
|
+
end
|
210
|
+
|
176
211
|
# Splits a line of text along whitespace breaks into fragments of cols
|
177
212
|
# width. Tabs in the line will be expanded into tabsize spaces;
|
178
213
|
# fragments are rstripped of whitespace.
|
@@ -208,6 +243,13 @@ module Lazydoc
|
|
208
243
|
yield []
|
209
244
|
end
|
210
245
|
end
|
246
|
+
|
247
|
+
# helper method to skip to the next non-escaped instance
|
248
|
+
# matching the quote regexp (/'/ or /"/).
|
249
|
+
def skip_quote(scanner, regexp) # :nodoc:
|
250
|
+
scanner.skip_until(regexp)
|
251
|
+
scanner.skip_until(regexp) while scanner.string[scanner.pos-2] == ?\\
|
252
|
+
end
|
211
253
|
end
|
212
254
|
|
213
255
|
# An array of comment fragments organized into lines
|
@@ -421,10 +463,12 @@ module Lazydoc
|
|
421
463
|
# quietly exit if a line number was not found
|
422
464
|
return self unless n.kind_of?(Integer)
|
423
465
|
|
466
|
+
# update negative line numbers
|
467
|
+
n += lines.length if n < 0
|
424
468
|
unless n < lines.length
|
425
|
-
raise RangeError, "line_number outside of lines: #{
|
469
|
+
raise RangeError, "line_number outside of lines: #{n} (#{lines.length})"
|
426
470
|
end
|
427
|
-
|
471
|
+
|
428
472
|
self.line_number = n
|
429
473
|
self.subject = lines[n]
|
430
474
|
self.content.clear
|
@@ -455,6 +499,11 @@ module Lazydoc
|
|
455
499
|
!content.find {|line| !line.empty?}
|
456
500
|
end
|
457
501
|
|
502
|
+
# Returns a comment trailing the subject.
|
503
|
+
def trailer
|
504
|
+
subject ? Comment.scan_trailer(subject) : nil
|
505
|
+
end
|
506
|
+
|
458
507
|
# Returns content as a string where line fragments are joined by
|
459
508
|
# fragment_sep and lines are joined by line_sep.
|
460
509
|
def to_s(fragment_sep=" ", line_sep="\n", strip=true)
|
data/lib/lazydoc/document.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'lazydoc/comment'
|
2
|
+
require 'lazydoc/method'
|
2
3
|
|
3
4
|
module Lazydoc
|
4
5
|
|
@@ -100,12 +101,36 @@ module Lazydoc
|
|
100
101
|
comment
|
101
102
|
end
|
102
103
|
|
103
|
-
# Registers a regexp matching
|
104
|
-
|
105
|
-
|
106
|
-
register(/^\s*def\s+#{method}(\W|$)/, comment_class)
|
104
|
+
# Registers a regexp matching the first method by the specified name.
|
105
|
+
def register_method(method_name, comment_class=Method)
|
106
|
+
register(Method.method_regexp(method_name), comment_class)
|
107
107
|
end
|
108
|
-
|
108
|
+
|
109
|
+
# Registers the next comment.
|
110
|
+
#
|
111
|
+
# lazydoc = Document.new(__FILE__)
|
112
|
+
#
|
113
|
+
# lazydoc.register___
|
114
|
+
# # this is the comment
|
115
|
+
# # that is registered
|
116
|
+
# def method(a,b,c)
|
117
|
+
# end
|
118
|
+
#
|
119
|
+
# lazydoc.resolve
|
120
|
+
# m = lazydoc.comments[0]
|
121
|
+
# m.subject # => "def method(a,b,c)"
|
122
|
+
# m.to_s # => "this is the comment that is registered"
|
123
|
+
#
|
124
|
+
def register___(comment_class=Comment, caller_index=0)
|
125
|
+
caller[caller_index] =~ CALLER_REGEXP
|
126
|
+
block = lambda do |lines|
|
127
|
+
n = $3.to_i
|
128
|
+
n += 1 while lines[n] =~ /^\s*(#.*)?$/
|
129
|
+
n
|
130
|
+
end
|
131
|
+
register(block, comment_class)
|
132
|
+
end
|
133
|
+
|
109
134
|
# Scans str for constant attributes and adds them to to self. Code
|
110
135
|
# comments are also resolved against str. If no str is specified,
|
111
136
|
# the contents of source_file are used instead.
|
@@ -0,0 +1,128 @@
|
|
1
|
+
module Lazydoc
|
2
|
+
|
3
|
+
# Method represents a code comment for a standard method definition.
|
4
|
+
# Methods give access to the method name, the arguments, and the
|
5
|
+
# trailing comment, if present.
|
6
|
+
#
|
7
|
+
# sample_method = %Q{
|
8
|
+
# # This is the comment body
|
9
|
+
# def method_name(a, b='default', &c) # trailing comment
|
10
|
+
# end
|
11
|
+
# }
|
12
|
+
#
|
13
|
+
# m = Method.parse(sample_method)
|
14
|
+
# m.method_name # => "method_name"
|
15
|
+
# m.arguments # => ["a", "b='default'", "&c"]
|
16
|
+
# m.trailer # => "trailing comment"
|
17
|
+
# m.to_s # => "This is the comment body"
|
18
|
+
#
|
19
|
+
class Method < Comment
|
20
|
+
class << self
|
21
|
+
|
22
|
+
# Generates a regexp matching a standard definition of the
|
23
|
+
# specified method.
|
24
|
+
#
|
25
|
+
# m = Method.method_regexp("method")
|
26
|
+
# m =~ "def method" # => true
|
27
|
+
# m =~ "def method(with, args, &block)" # => true
|
28
|
+
# m !~ "def some_other_method" # => true
|
29
|
+
#
|
30
|
+
def method_regexp(method_name)
|
31
|
+
/^\s*def\s+#{method_name}(\W|$)/
|
32
|
+
end
|
33
|
+
|
34
|
+
# Parses an argument string (anything following the method name in a
|
35
|
+
# standard method definition, including parenthesis/comments/default
|
36
|
+
# values etc) into an array of strings.
|
37
|
+
#
|
38
|
+
# Method.parse_args("(a, b='default', &block)")
|
39
|
+
# # => ["a", "b='default'", "&block"]
|
40
|
+
#
|
41
|
+
# Note the %-syntax for strings and arrays is not fully supported,
|
42
|
+
# ie %w, %Q, %q, etc. may not parse correctly. The same is true
|
43
|
+
# for multiline argument strings.
|
44
|
+
def parse_args(str)
|
45
|
+
scanner = case str
|
46
|
+
when StringScanner then str
|
47
|
+
when String then StringScanner.new(str)
|
48
|
+
else raise TypeError, "can't convert #{str.class} into StringScanner or String"
|
49
|
+
end
|
50
|
+
str = scanner.string
|
51
|
+
|
52
|
+
# skip whitespace and leading LPAREN
|
53
|
+
scanner.skip(/\s*\(?\s*/)
|
54
|
+
|
55
|
+
args = []
|
56
|
+
brakets = braces = parens = 0
|
57
|
+
start = scanner.pos
|
58
|
+
broke = while scanner.skip(/.*?['"#,\(\)\{\}\[\]]/)
|
59
|
+
pos = scanner.pos - 1
|
60
|
+
|
61
|
+
case str[pos]
|
62
|
+
when ?,,nil
|
63
|
+
# skip if in brakets, braces, or parenthesis
|
64
|
+
next if parens > 0 || brakets > 0 || braces > 0
|
65
|
+
|
66
|
+
# ok, found an arg
|
67
|
+
args << str[start, pos-start].strip
|
68
|
+
start = pos + 1
|
69
|
+
|
70
|
+
when ?# then break(true) # break on a comment
|
71
|
+
when ?' then skip_quote(scanner, /'/) # parse over quoted strings
|
72
|
+
when ?" then skip_quote(scanner, /"/) # parse over double-quoted string
|
73
|
+
|
74
|
+
when ?( then parens += 1 # for brakets, braces, and parenthesis
|
75
|
+
when ?) # simply track the nesting EXCEPT for
|
76
|
+
break(true) if parens == 0 # RPAREN. If the closing parenthesis
|
77
|
+
parens -= 1 # is found, break.
|
78
|
+
when ?[ then braces += 1
|
79
|
+
when ?] then braces -= 1
|
80
|
+
when ?{ then brakets += 1
|
81
|
+
when ?} then brakets -= 1
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
# parse out the final arg. if the loop broke (ie
|
86
|
+
# a comment or the closing parenthesis was found)
|
87
|
+
# then the end position is determined by the
|
88
|
+
# scanner, otherwise take all that remains
|
89
|
+
pos = broke ? scanner.pos-1 : str.length
|
90
|
+
args << str[start, pos-start].strip
|
91
|
+
|
92
|
+
args
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
# Matches a standard method definition. After the match:
|
97
|
+
#
|
98
|
+
# $1:: the method name
|
99
|
+
# $2:: the argument string, which may be parsed by parse_args
|
100
|
+
#
|
101
|
+
METHOD_DEF = /^\s*def (\w+)(.*)$/
|
102
|
+
|
103
|
+
# The resolved method name
|
104
|
+
attr_reader :method_name
|
105
|
+
|
106
|
+
# An array of the resolved arguments for the method
|
107
|
+
attr_reader :arguments
|
108
|
+
|
109
|
+
def initialize(*args)
|
110
|
+
super
|
111
|
+
@method_name = nil
|
112
|
+
@arguments = []
|
113
|
+
end
|
114
|
+
|
115
|
+
# Overridden to parse and set the method_name, arguments, and
|
116
|
+
# trailer in addition to setting the subject.
|
117
|
+
def subject=(value)
|
118
|
+
unless value =~ METHOD_DEF
|
119
|
+
raise ArgumentError, "not a method definition: #{value}"
|
120
|
+
end
|
121
|
+
|
122
|
+
@method_name = $1
|
123
|
+
@arguments = Method.parse_args($2)
|
124
|
+
|
125
|
+
super
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
data/lib/lazydoc.rb
CHANGED
@@ -49,6 +49,26 @@ module Lazydoc
|
|
49
49
|
Lazydoc[source_file].register(line_number, comment_class)
|
50
50
|
end
|
51
51
|
|
52
|
+
# Registers the method at the specified index in the call stack, to
|
53
|
+
# the file where the method was called. Using the default index of
|
54
|
+
# 1, register_caller registers the caller of the method where
|
55
|
+
# register_caller is called. For instance:
|
56
|
+
#
|
57
|
+
# module Sample
|
58
|
+
# module_function
|
59
|
+
# def method
|
60
|
+
# Lazydoc.register_caller
|
61
|
+
# end
|
62
|
+
# end
|
63
|
+
#
|
64
|
+
# # this is the line that gets registered
|
65
|
+
# Sample.method
|
66
|
+
#
|
67
|
+
def register_caller(comment_class=Comment, caller_index=1)
|
68
|
+
caller[caller_index] =~ CALLER_REGEXP
|
69
|
+
Lazydoc[$1].register($3.to_i - 1, comment_class)
|
70
|
+
end
|
71
|
+
|
52
72
|
# Resolves all lazydocs which include the specified code comments.
|
53
73
|
def resolve_comments(comments)
|
54
74
|
registry.each do |doc|
|
@@ -172,6 +192,8 @@ module Lazydoc
|
|
172
192
|
end
|
173
193
|
end
|
174
194
|
|
195
|
+
# Parses the usage for a file, ie the first comment in the file
|
196
|
+
# following an optional bang line.
|
175
197
|
def usage(path, cols=80)
|
176
198
|
scanner = StringScanner.new(File.read(path))
|
177
199
|
scanner.scan(/^#!.*?$/)
|
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.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Simon Chiang
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2008-
|
12
|
+
date: 2008-12-07 00:00:00 -07:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -36,6 +36,7 @@ files:
|
|
36
36
|
- lib/lazydoc/attributes.rb
|
37
37
|
- lib/lazydoc/comment.rb
|
38
38
|
- lib/lazydoc/document.rb
|
39
|
+
- lib/lazydoc/method.rb
|
39
40
|
- README
|
40
41
|
- MIT-LICENSE
|
41
42
|
has_rdoc: true
|
@@ -60,9 +61,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
60
61
|
requirements: []
|
61
62
|
|
62
63
|
rubyforge_project: tap
|
63
|
-
rubygems_version: 1.
|
64
|
+
rubygems_version: 1.3.1
|
64
65
|
signing_key:
|
65
66
|
specification_version: 2
|
66
|
-
summary:
|
67
|
+
summary: Lazily pull documentation out of source files.
|
67
68
|
test_files: []
|
68
69
|
|