lazydoc 0.1.0 → 0.2.0
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/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
|
|