lazydoc 0.9.0 → 1.0

Sign up to get free protection for your applications and to get access to all the features.
data/History CHANGED
@@ -1,3 +1,20 @@
1
+ == 1.0.0 / 2009-12-05
2
+
3
+ * optimized regexps
4
+ * updated Lazydoc::Attributes to automatically set source_file
5
+ when inherited
6
+ * added document method to Lazydoc to look up document for
7
+ source_file without automatically creating the document (as
8
+ is the case with Lazydoc[])
9
+ * register_file now guesses a default constant name based on
10
+ the path relative to a matching LOAD_PATH
11
+ * updated Lazydoc::Attributes to allow manually registered
12
+ comments across multiple source files
13
+ * added inheritance for lazy attributes
14
+ * changed registered_methods to return an array of the methods
15
+ whose documentation will be registered (no longer a hash by
16
+ default)
17
+
1
18
  == 0.9.0 / 2009-05-25
2
19
 
3
20
  * lazy attributes can now be accessed without auto-resolve
@@ -1,19 +1,20 @@
1
1
  Copyright (c) 2008-2009, Regents of the University of Colorado.
2
+ Copyright (c) 2009, Simon Chiang.
2
3
 
3
- Permission is hereby granted, free of charge, to any person obtaining a copy of this
4
- software and associated documentation files (the "Software"), to deal in the Software
5
- without restriction, including without limitation the rights to use, copy, modify, merge,
6
- publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
7
- to whom the Software is furnished to do so, subject to the following conditions:
4
+ Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ of this software and associated documentation files (the "Software"), to deal
6
+ in the Software without restriction, including without limitation the rights
7
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ copies of the Software, and to permit persons to whom the Software is
9
+ furnished to do so, subject to the following conditions:
8
10
 
9
- The above copyright notice and this permission notice shall be included in all copies or
10
- substantial portions of the Software.
11
+ The above copyright notice and this permission notice shall be included in all
12
+ copies or substantial portions of the Software.
11
13
 
12
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
13
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
14
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
15
- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
16
- HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
17
- WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18
- FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
19
- OTHER DEALINGS IN THE SOFTWARE.
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20
+ SOFTWARE.
data/README CHANGED
@@ -6,9 +6,8 @@ Tap[http://tap.rubyforge.org] framework.
6
6
 
7
7
  == Description
8
8
 
9
- Lazydoc allows you to define lazy attributes that act as markers for
10
- documentation in a source file. When you call the lazy attribute,
11
- Lazydoc pulls out the documentation:
9
+ Lazydoc allows you to define lazy attributes that access documentation in a
10
+ source file.
12
11
 
13
12
  # Sample::key <value>
14
13
  # This is the comment content. A content
@@ -35,8 +34,7 @@ Comments support wrapping, allowing for easy presentation:
35
34
  # ..............................
36
35
  # }
37
36
 
38
- In addition, Lazydoc provides helpers to register individual lines of code,
39
- particularly method definitions:
37
+ Lazydoc also provides helpers to register method documentation:
40
38
 
41
39
  class Helpers
42
40
  extend Lazydoc::Attributes
@@ -49,7 +47,7 @@ particularly method definitions:
49
47
  end
50
48
 
51
49
  # register_caller will register the line
52
- # that *calls* method_two
50
+ # that *calls* method_two (see below)
53
51
  def method_two
54
52
  Lazydoc.register_caller
55
53
  end
@@ -59,19 +57,18 @@ particularly method definitions:
59
57
  # registered by method_two
60
58
  Helpers.const_attrs[:method_two] = Helpers.new.method_two
61
59
 
62
- doc = Helpers.lazydoc
63
- doc.resolve
64
-
65
60
  one = Helpers.const_attrs[:method_one]
61
+ one.resolve
66
62
  one.method_name # => "method_one"
67
63
  one.arguments # => ["a", "b='str'", "&c"]
68
64
  one.to_s # => "method_one is registered whenever it gets defined"
69
65
 
70
66
  two = Helpers.const_attrs[:method_two]
67
+ two.resolve
71
68
  two.subject # => "Helpers.const_attrs[:method_two] = Helpers.new.method_two"
72
69
  two.to_s # => "*THIS* is the line that gets registered by method_two"
73
70
 
74
- Lazy accessors may be defined to map the registered lines as well:
71
+ Lazy accessors may be defined to access the registered lines more easily:
75
72
 
76
73
  class Helpers
77
74
  lazy_attr(:one, :method_one)
@@ -81,11 +78,10 @@ Lazy accessors may be defined to map the registered lines as well:
81
78
  Helpers.one.method_name # => "method_one"
82
79
  Helpers.two.subject # => "Helpers.const_attrs[:method_two] = Helpers.new.method_two"
83
80
 
84
- Check out these links for development, and bug tracking.
81
+ Check out these links for developments and bug tracking.
85
82
 
86
83
  * Website[http://tap.rubyforge.org/lazydoc]
87
84
  * Github[http://github.com/bahuvrihi/lazydoc/tree/master]
88
- * Lighthouse[http://bahuvrihi.lighthouseapp.com/projects/19948-lazydoc/tickets?q=all]
89
85
  * {Google Group}[http://groups.google.com/group/ruby-on-tap]
90
86
 
91
87
  == Usage
@@ -96,9 +92,9 @@ are represented by Comment objects.
96
92
 
97
93
  === Constant Attributes
98
94
 
99
- Constant attributes are like constants in Ruby, but with an extra 'key'
100
- that must consist of only lowercase letters and/or underscores. For
101
- example, these are constant attributes:
95
+ Constant attributes are defined in the documentation to look like constants,
96
+ but with an extra 'key' that must consist of only lowercase letters and/or
97
+ underscores. For example, these are constant attributes:
102
98
 
103
99
  # Const::Name::key
104
100
  # Const::Name::key_with_underscores
@@ -111,7 +107,7 @@ While these are not:
111
107
  # Const::Name::k@y
112
108
 
113
109
  Lazydoc parses a Lazydoc::Comment for each constant attribute by using the
114
- remainder of the line as a value (ie subject) and parsing down for content.
110
+ remainder of the line as a value (ie subject) and trailing lines as content.
115
111
  Parsing continues until a non-comment line, an end key, or a new attribute
116
112
  is reached; the comment is then stored by constant name and key.
117
113
 
@@ -139,8 +135,8 @@ is reached; the comment is then stored by constant name and key.
139
135
  # 'another' => ['value for another', 'comment for another parsed to an end key']}
140
136
  # }
141
137
 
142
- Constant attributes are only parsed from commented lines. To turn off
143
- attribute parsing for a section of documentation, use start/stop keys:
138
+ Constant attributes are only parsed from comment lines. To turn off attribute
139
+ parsing for a section of documentation, use start/stop keys:
144
140
 
145
141
  str = %Q{
146
142
  Const::Name::not_parsed
@@ -155,9 +151,9 @@ attribute parsing for a section of documentation, use start/stop keys:
155
151
  doc.resolve(str)
156
152
  doc.summarize {|comment| comment.value } # => {'Const::Name' => {'parsed' => 'value'}}
157
153
 
158
- To hide attributes from RDoc, make use of the RDoc <tt>:startdoc:</tt>
159
- document modifier like this (note that spaces are added to prevent RDoc
160
- from hiding the example):
154
+ To hide attributes from RDoc, make use of the RDoc <tt>:startdoc:</tt>
155
+ document modifier like this (note the modifiers have an extra space in them to
156
+ prevent RDoc from hiding the example):
161
157
 
162
158
  # :start doc::Const::Name::one hidden in RDoc
163
159
  # * This line is visible in RDoc.
@@ -171,16 +167,17 @@ from hiding the example):
171
167
  #
172
168
  # * This line is also visible in RDoc.
173
169
 
174
- As a side note, 'Const::Name::key' is not a reference to the 'key'
175
- constant (that would be invalid). In *very* idiomatic ruby
176
- 'Const::Name::key' is equivalent to the method call 'Const::Name.key'.
170
+ As a side note, the constant attribute syntax is designed to echo how the
171
+ Lazydoc::Attributes module makes comments accessible in code. In *very*
172
+ idiomatic Ruby 'Const::Name::key' is equivalent to the method call
173
+ 'Const::Name.key'.
177
174
 
178
175
  === Code Comments
179
176
 
180
- Code comments are lines registered for parsing if and when a Lazydoc gets
177
+ Code comments are lines registered for parsing if and when a Lazydoc gets
181
178
  resolved. Unlike constant attributes, the registered line is the comment
182
- subject (ie value) and contents are parsed up from it (basically mimicking
183
- the behavior of RDoc).
179
+ subject (ie value) and the content consists of the preceding documentation
180
+ (basically mimicking the behavior of RDoc).
184
181
 
185
182
  str = %Q{
186
183
  # comment lines for
@@ -211,6 +208,31 @@ of a Regexp, the first matching line is used; Procs receive an array of
211
208
  lines and should return the line number that should be used. See
212
209
  {Comment#parse_up}[link://classes/Lazydoc/Comment.html] for more details.
213
210
 
211
+ Manually registering lines for documentation can be quite cumbersome. The
212
+ Lazydoc::Attributes module provides helpers to register method documentation
213
+ on classes with method-like inheritance.
214
+
215
+ class A
216
+ extend Lazydoc::Attributes
217
+ lazy_attr(:one, :method_one)
218
+ lazy_register(:method_one)
219
+
220
+ # documentation for method one
221
+ def method_one; end
222
+ end
223
+
224
+ class B < A
225
+ end
226
+
227
+ class C < B
228
+ # overriding documentation for method one
229
+ def method_one; end
230
+ end
231
+
232
+ A::one.comment # => "documentation for method one"
233
+ B::one.comment # => "documentation for method one"
234
+ C::one.comment # => "overriding documentation for method one"
235
+
214
236
  == Installation
215
237
 
216
238
  Lazydoc is available as a gem on RubyForge[http://rubyforge.org/projects/tap]. Use:
@@ -219,7 +241,6 @@ Lazydoc is available as a gem on RubyForge[http://rubyforge.org/projects/tap].
219
241
 
220
242
  == Info
221
243
 
222
- Copyright (c) 2008-2009, Regents of the University of Colorado.
223
- Developer:: {Simon Chiang}[http://bahuvrihi.wordpress.com], {Biomolecular Structure Program}[http://biomol.uchsc.edu/], {Hansen Lab}[http://hsc-proteomics.uchsc.edu/hansenlab/]
224
- Support:: CU Denver School of Medicine Deans Academic Enrichment Fund
244
+ Copyright (c) 2009, Simon Chiang.
245
+ Developer:: {Simon Chiang}[http://bahuvrihi.wordpress.com]
225
246
  License:: {MIT-Style}[link:files/MIT-LICENSE.html]
@@ -1,3 +1,4 @@
1
+ require 'lazydoc/version'
1
2
  require 'lazydoc/document'
2
3
 
3
4
  module Lazydoc
@@ -8,22 +9,54 @@ module Lazydoc
8
9
  @registry ||= []
9
10
  end
10
11
 
11
- # Returns the Document in registry for the specified source file.
12
- # If no such Document exists, one will be created for it.
12
+ # Returns the document registered to the source file, or nil if no such
13
+ # document exists.
14
+ def document(source_file)
15
+ source_file = File.expand_path(source_file.to_s)
16
+ registry.find {|doc| doc.source_file == source_file }
17
+ end
18
+
19
+ # Returns the document registered to the source file. If no such document
20
+ # exists, one will be created for it.
13
21
  def [](source_file)
22
+ document(source_file) || register_file(source_file)
23
+ end
24
+
25
+ # Guesses the default constant name for the source file by camelizing the
26
+ # shortest relative path from a matching $LOAD_PATH to the source file.
27
+ # Returns nil if the source file is not relative to any load path.
28
+ #
29
+ # ==== Code Credit
30
+ #
31
+ # The camelize algorithm is taken from the ActiveSupport {Inflections}[http://api.rubyonrails.org/classes/ActiveSupport/CoreExtensions/String/Inflections.html]
32
+ # module. See the {Tap::Env::StringExt}[http://tap.rubyforge.org/rdoc/classes/Tap/Env/StringExt.html]
33
+ # module (which uses the same) for a proper credit and license.
34
+ #
35
+ def guess_const_name(source_file)
14
36
  source_file = File.expand_path(source_file.to_s)
15
- registry.find {|doc| doc.source_file == source_file } || register_file(source_file)
37
+
38
+ load_paths = []
39
+ $LOAD_PATH.each do |load_path|
40
+ load_path = File.expand_path(load_path)
41
+ if source_file.rindex(load_path, 0) == 0
42
+ load_paths << load_path
43
+ end
44
+ end
45
+
46
+ return nil if load_paths.empty?
47
+
48
+ load_path = load_paths.sort_by {|load_path| load_path.length}.pop
49
+ extname = File.extname(source_file)
50
+ relative_path = source_file[(load_path.length + 1)..(-1 - extname.length)]
51
+ relative_path.gsub(/\/(.?)/) { "::" + $1.upcase }.gsub(/(^|_)(.)/) { $2.upcase }
16
52
  end
17
53
 
18
- # Generates a Document the source_file and default_const_name and adds it to
19
- # registry, or returns the document already registered to source_file. An
54
+ # Generates a document for the source_file and default_const_name and adds it to
55
+ # registry, or returns the document already registered to the source file. An
20
56
  # error is raised if you try to re-register a source_file with an inconsistent
21
57
  # default_const_name.
22
- def register_file(source_file, default_const_name=nil)
23
- source_file = File.expand_path(source_file.to_s)
24
- lazydoc = registry.find {|doc| doc.source_file == source_file }
25
-
26
- unless lazydoc
58
+ def register_file(source_file, default_const_name=guess_const_name(source_file))
59
+ unless lazydoc = document(source_file)
27
60
  lazydoc = Document.new(source_file)
28
61
  registry << lazydoc
29
62
  end
@@ -32,16 +65,15 @@ module Lazydoc
32
65
  lazydoc
33
66
  end
34
67
 
35
- # Registers the line number to the document for source_file and
36
- # returns the corresponding comment.
68
+ # Registers the line number to the document for source_file and returns the
69
+ # new comment.
37
70
  def register(source_file, line_number, comment_class=Comment)
38
71
  Lazydoc[source_file].register(line_number, comment_class)
39
72
  end
40
73
 
41
- # Registers the method at the specified index in the call stack to
42
- # the file where the method was called. Using the default index of
43
- # 1, register_caller registers the caller of the method where
44
- # register_caller is called (whew!). For instance:
74
+ # Registers the method to the line where it was called. To do so,
75
+ # register_caller examines the specified index in the call stack
76
+ # and extracts a file and line number. For instance:
45
77
  #
46
78
  # module Sample
47
79
  # module_function
@@ -59,7 +91,7 @@ module Lazydoc
59
91
  #
60
92
  def register_caller(comment_class=Comment, caller_index=1)
61
93
  caller[caller_index] =~ CALLER_REGEXP
62
- Lazydoc[$1].register($3.to_i - 1, comment_class)
94
+ Lazydoc[$1].register($2.to_i - 1, comment_class)
63
95
  end
64
96
 
65
97
  # Parses the usage for a file (ie the first comment in the file
@@ -1,7 +1,7 @@
1
1
  module Lazydoc
2
2
 
3
3
  # Attributes adds methods to declare class-level accessors for constant
4
- # attributes.
4
+ # attributes associated with the class.
5
5
  #
6
6
  # # ConstName::key value
7
7
  # class ConstName
@@ -9,132 +9,287 @@ module Lazydoc
9
9
  # lazy_attr :key
10
10
  # end
11
11
  #
12
- # ConstName.source_file # => __FILE__
13
- # ConstName::key.subject # => 'value'
12
+ # ConstName::key.subject # => 'value'
13
+ #
14
+ # Lazy attributes are inherited, but can be overridden.
15
+ #
16
+ # class SubclassA < ConstName; end
17
+ # SubclassA::key.subject # => 'value'
18
+ #
19
+ # # SubclassB::key overridden value
20
+ # class SubclassB < ConstName; end
21
+ # SubclassB::key.subject # => 'overridden value'
22
+ #
23
+ # You can use Attributes to register methods on modules, but currently the
24
+ # inheritance is a bit wonky; the accessors are methods on the extended
25
+ # class/module and so standard module inclusion will not pass them on.
26
+ # To work around you need to extend and redefine the accessors. Note,
27
+ # however, that methods do not need to be re-registered.
28
+ #
29
+ # module A
30
+ # extend Lazydoc::Attributes
31
+ # lazy_attr(:one, :method_one)
32
+ # lazy_register(:method_one)
33
+ #
34
+ # # documentation for method one
35
+ # def method_one; end
36
+ # end
14
37
  #
38
+ # class B
39
+ # include A
40
+ # extend Lazydoc::Attributes
41
+ # lazy_attr(:one, :method_one)
42
+ # end
43
+ #
44
+ # class C < B
45
+ # # overriding documentation for method one
46
+ # def method_one; end
47
+ # end
48
+ #
49
+ # A::one.comment # => "documentation for method one"
50
+ # B::one.comment # => "documentation for method one"
51
+ # C::one.comment # => "overriding documentation for method one"
52
+ #
15
53
  # ==== Keys and Register
16
54
  #
17
- # Note that constant attributes parsed from a source file are stored in
18
- # const_attrs, and will ALWAYS be keyed using a string (since the
19
- # 'ConstName::key' syntax specifies a string key).
55
+ # Constant attributes parsed from a source file will ALWAYS be stored in
56
+ # const_attrs using a string (since the 'ConstName::key' syntax always
57
+ # results in a string key). A lazy_attr is basically shorthand for either
58
+ # of these statements:
59
+ #
60
+ # ConstName.const_attrs['key'].subject # => 'value'
61
+ # Lazydoc::Document['ConstName']['key'].subject # => 'value'
62
+ #
63
+ # By default a lazy_attr maps to the constant attribute with the same name
64
+ # as the accessor, but this can be overridden by specifying the string key
65
+ # for another attribute.
66
+ #
67
+ # class ConstName
68
+ # lazy_attr :alt, 'key'
69
+ # end
20
70
  #
21
- # ConstName.const_attrs['key'] # => ConstName::key
71
+ # ConstName::alt.subject # => 'value'
72
+ # ConstName.const_attrs['alt'] # => nil
22
73
  #
23
- # 'Constant Attributes' specified by non-string keys are sometimes used to
24
- # tie comments to a constant that will NOT be resolved from the constant
25
- # attribute syntax. For instance you could register a method like this:
74
+ # Comments specified by non-string keys may also be stored in const_attrs;
75
+ # these will not conflict with constant attributes parsed from a source
76
+ # file. For instance you could manually register a comment to a symbol key
77
+ # using lazy_register:
26
78
  #
27
79
  # class Sample
28
80
  # extend Lazydoc::Attributes
29
81
  #
30
- # const_attrs[:method_one] = register___
82
+ # lazy_register(:method_one)
83
+ #
31
84
  # # this is the method one comment
32
85
  # def method_one
33
86
  # end
34
87
  # end
35
88
  #
36
- # Sample.lazydoc.resolve
37
- # Sample.const_attrs[:method_one].comment # => "this is the method one comment"
89
+ # Sample.const_attrs[:method_one].comment # => "this is the method one comment"
38
90
  #
39
- # For easier access, you could define a lazy_attr to access the registered
40
- # comment. And in the simplest case, you pair a lazy_register with a
41
- # lazy_attr.
91
+ # Manually-registered comments may then be paired with a lazy_attr. As
92
+ # before the key for the comment is provided in the definition.
42
93
  #
43
94
  # class Paired
44
95
  # extend Lazydoc::Attributes
45
96
  #
46
97
  # lazy_attr(:one, :method_one)
47
- # lazy_attr(:two, :method_two)
48
- # lazy_register(:method_two)
98
+ # lazy_register(:method_one)
49
99
  #
50
- # const_attrs[:method_one] = register___
51
- # # this is the manually-registered method one comment
100
+ # # this is the method one comment
52
101
  # def method_one
53
102
  # end
54
- #
55
- # # this is the lazyily-registered method two comment
56
- # def method_two
57
- # end
58
103
  # end
59
104
  #
60
- # Paired.lazydoc.resolve
61
- # Paired.one.comment # => "this is the manually-registered method one comment"
62
- # Paired.two.comment # => "this is the lazyily-registered method two comment"
105
+ # Paired::one.comment # => "this is the method one comment"
106
+ #
107
+ # ==== Troubleshooting
63
108
  #
109
+ # Under most circumstances Attributes will register all the necessary files
110
+ # to make constant attributes available. These include:
111
+ #
112
+ # * the file where the class is extended
113
+ # * the file where a subclass inherits from an extended class
114
+ # * files that declare a lazy_attr
115
+ #
116
+ # Be sure to call register_lazydoc in files that are not covered by one of
117
+ # these cases but nonetheless contain constant attributes that should be
118
+ # available to a lazy_attr.
64
119
  module Attributes
65
-
66
- # The source file for the extended class. By default source_file
67
- # is set to the file where Attributes extends the class (if you
68
- # include Attributes, you must set source_file manually).
69
- attr_accessor :source_file
70
120
 
71
- def self.extended(base) # :nodoc:
121
+ # Sets source_file as the file where Attributes first extends the class.
122
+ def self.extended(base)
72
123
  caller[1] =~ CALLER_REGEXP
73
- base.source_file ||= $1
74
- end
75
-
76
- # Inherits registered_methods from parent to child.
77
- def inherited(child)
78
- child.registered_methods.merge!(registered_methods)
124
+ unless base.instance_variable_defined?(:@lazydocs)
125
+ base.instance_variable_set(:@lazydocs, [Lazydoc[$1]])
126
+ end
127
+
128
+ unless base.instance_variable_defined?(:@lazy_registry)
129
+ base.instance_variable_set(:@lazy_registry, {})
130
+ end
131
+
79
132
  super
80
133
  end
81
134
 
82
- # Lazily registers the added method if marked for lazy registration.
83
- def method_added(sym)
84
- if args = registered_methods[sym]
85
- const_attrs[sym] ||= Lazydoc.register_caller(*args)
135
+ # Returns the documents registered to the extending class.
136
+ #
137
+ # By default lazydocs contains a Document for the file where Attributes
138
+ # extends the class, or where a subclass first inherits from an extended
139
+ # class (if you include Attributes, you must set lazydocs manually).
140
+ #
141
+ # Additional documents may be added by calling register_lazydoc.
142
+ attr_reader :lazydocs
143
+
144
+ # Returns an array of the methods whose documentation will be automatically
145
+ # registered by Attributes. Set as_registry to true to return a hash of
146
+ # of (method_name, [comment_class, caller_index]) pairs where the
147
+ # registration arguments are the hash values.
148
+ def registered_methods(as_registry=false)
149
+ methods = {}
150
+ ancestors.reverse.each do |ancestor|
151
+ if ancestor.kind_of?(Attributes)
152
+ methods.merge!(ancestor.lazy_registry)
153
+ end
86
154
  end
87
155
 
88
- super
156
+ as_registry ? methods : methods.keys
89
157
  end
90
158
 
91
159
  # Returns the constant attributes resolved for the extended class.
92
160
  def const_attrs
93
161
  Document[to_s]
94
162
  end
95
-
96
- # Returns the Document for source_file
97
- def lazydoc
98
- Lazydoc[source_file]
99
- end
163
+
164
+ protected
100
165
 
101
166
  # A hash of (method_name, [comment_class, caller_index]) pairs indicating
102
- # methods to lazily register, and the inputs to Lazydoc.register_caller
103
- # used to register the method.
104
- def registered_methods
105
- @registered_methods ||= {}
167
+ # methods to lazily register, and the inputs used to register the method.
168
+ #
169
+ # The lazy_registry only contains methods lazily registered within the
170
+ # current class or module. To return methods registered throughout the
171
+ # inheritance hierarchy, use registered_methods(true)
172
+ attr_reader :lazy_registry
173
+
174
+ # Registers the calling file into lazydocs. Registration occurs by
175
+ # examining the call stack at the specified index.
176
+ def register_lazydoc(caller_index=0)
177
+ caller[caller_index] =~ CALLER_REGEXP
178
+ lazydocs << Lazydoc[File.expand_path($1)]
179
+ lazydocs.uniq!
180
+ self
106
181
  end
107
182
 
108
183
  # Creates a method that reads and resolves the constant attribute specified
109
- # by key, which should normally be a string (see above for more details).
110
- # If writable is true, a corresponding writer is also created.
184
+ # by key. The method has a signature like:
185
+ #
186
+ # def method(resolve=true)
187
+ # end
188
+ #
189
+ # To return the constant attribute without resolving, call the method with
190
+ # resolve == false. If writable is true, a corresponding writer is also
191
+ # created.
111
192
  def lazy_attr(symbol, key=symbol.to_s, writable=true)
112
- key = case key
113
- when String, Symbol, Numeric, true, false, nil then key.inspect
114
- else "YAML.load(\'#{YAML.dump(key)}\')"
193
+ unless key.kind_of?(String) || key.kind_of?(Symbol)
194
+ raise "invalid lazy_attr key: #{key.inspect} (#{key.class})"
115
195
  end
116
196
 
117
- instance_eval %Q{
118
- def #{symbol}(resolve=true)
119
- comment = const_attrs[#{key}] ||= Subject.new(nil, lazydoc)
120
- resolve && comment.kind_of?(Comment) ? comment.resolve : comment
121
- end}
122
-
123
- instance_eval(%Q{
124
- def #{symbol}=(comment)
125
- const_attrs[#{key}] = comment
126
- end}) if writable
197
+ key = key.inspect
198
+ instance_eval %Q{def #{symbol}(resolve=true); get_const_attr(#{key}, resolve); end}
199
+ instance_eval(%Q{def #{symbol}=(comment); const_attrs[#{key}] = comment; end}) if writable
200
+
201
+ register_lazydoc(1)
127
202
  end
128
203
 
129
204
  # Marks the method for lazy registration. When the method is registered,
130
205
  # it will be stored in const_attrs by method_name.
131
206
  def lazy_register(method_name, comment_class=Method, caller_index=1)
132
- registered_methods[method_name.to_sym] = [comment_class, caller_index]
207
+ lazy_registry[method_name.to_sym] = [comment_class, caller_index]
133
208
  end
134
209
 
135
- # Registers the next comment (by default as a Method).
136
- def register___(comment_class=Method)
137
- lazydoc.register___(comment_class, 1)
210
+ # Manually registers the next comment into const_attrs. Note a lazy_attr
211
+ # will still need to be defined to access this comment as an attribute.
212
+ def register___(key, comment_class=Method)
213
+ caller[0] =~ CALLER_REGEXP
214
+ source_file = File.expand_path($1)
215
+ const_attrs[key] = Lazydoc[source_file].register___(comment_class, 1)
216
+ end
217
+
218
+ private
219
+
220
+ # Inherits lazy_registry from parent to child. Also registers the
221
+ # source_file for the child as the file where the inheritance first
222
+ # occurs.
223
+ def inherited(child)
224
+ unless child.instance_variable_defined?(:@lazydocs)
225
+ caller.each do |call|
226
+ next if call =~ /in `inherited'$/
227
+
228
+ call =~ CALLER_REGEXP
229
+ child.instance_variable_set(:@lazydocs, [Lazydoc[$1]])
230
+ break
231
+ end
232
+ end
233
+
234
+ unless child.instance_variable_defined?(:@lazy_registry)
235
+ child.instance_variable_set(:@lazy_registry, {})
236
+ end
237
+
238
+ super
239
+ end
240
+
241
+ # Helper to traverse the inheritance hierarchy. The logic of this method
242
+ # is described in the dsl pattern: http://gist.github.com/181961
243
+ def each_ancestor # :nodoc:
244
+ yield(self)
245
+
246
+ blank, *ancestors = self.ancestors
247
+ ancestors.each do |ancestor|
248
+ yield(ancestor) if ancestor.kind_of?(Attributes)
249
+ end
250
+
251
+ nil
252
+ end
253
+
254
+ # Lazily registers the added method if marked for lazy registration.
255
+ def method_added(sym)
256
+ current = nil
257
+ each_ancestor do |ancestor|
258
+ if ancestor.lazy_registry.has_key?(sym)
259
+ current = ancestor
260
+ break
261
+ end
262
+ end
263
+
264
+ if current
265
+ args = current.lazy_registry[sym]
266
+ const_attrs[sym] ||= Lazydoc.register_caller(*args)
267
+ end
268
+
269
+ super
270
+ end
271
+
272
+ # helper to traverse up the inheritance hierarchy looking for the first
273
+ # const_attr assigned to key. the lazydocs for each class will be
274
+ # resolved along the way, if specified.
275
+ def get_const_attr(key, resolve) # :nodoc:
276
+ each_ancestor do |ancestor|
277
+ const_attrs = ancestor.const_attrs
278
+
279
+ unless const_attrs.has_key?(key)
280
+ next unless resolve
281
+
282
+ ancestor.lazydocs.each {|doc| doc.resolve }
283
+ next unless const_attrs.has_key?(key)
284
+ end
285
+
286
+ const_attr = const_attrs[key]
287
+ if resolve && const_attr.kind_of?(Comment)
288
+ const_attr.resolve
289
+ end
290
+
291
+ return const_attr
292
+ end
138
293
  end
139
294
  end
140
295
  end
@@ -10,22 +10,22 @@ module Lazydoc
10
10
  # A regexp matching an attribute start or end. After a match:
11
11
  #
12
12
  # $1:: const_name
13
- # $3:: key
14
- # $4:: end flag
13
+ # $2:: key
14
+ # $3:: end flag
15
15
  #
16
- ATTRIBUTE_REGEXP = /([A-Z][A-z]*(::[A-Z][A-z]*)*)?::([a-z_]+)(-?)/
16
+ ATTRIBUTE_REGEXP = /([A-Z][A-z]*(?:::[A-Z][A-z]*)*)?::([a-z_]+)(-?)/
17
17
 
18
18
  # A regexp matching constants from the ATTRIBUTE_REGEXP leader
19
- CONSTANT_REGEXP = /#.*?([A-Z][A-z]*(::[A-Z][A-z]*)*)?$/
19
+ CONSTANT_REGEXP = /#.*?([A-Z][A-z]*(?:::[A-Z][A-z]*)*)?$/
20
20
 
21
21
  # A regexp matching a caller line, to extract the calling file
22
22
  # and line number. After a match:
23
23
  #
24
24
  # $1:: file
25
- # $3:: line number (as a string, obviously)
25
+ # $2:: line number (as a string, obviously)
26
26
  #
27
27
  # Note that line numbers in caller start at 1, not 0.
28
- CALLER_REGEXP = /^(([A-z]:)?[^:]+):(\d+)/
28
+ CALLER_REGEXP = /^((?:[A-z]:)?[^:]+):(\d+)/
29
29
 
30
30
  # A Document resolves constant attributes and code comments for a particular
31
31
  # source file. Documents may be assigned a default_const_name to be used
@@ -40,9 +40,8 @@ module Lazydoc
40
40
  # Document['Const::Name']['key'].value # => 'value a'
41
41
  # Document['Default']['key'].value # => 'value b'
42
42
  #
43
- # As shown in the example, constant attibutes for all documents are cached in
44
- # the class-level const_attrs hash and are normally consumed through Document
45
- # itself.
43
+ # As in the example, constant attibutes for all documents may be accessed
44
+ # from Document[].
46
45
  class Document
47
46
  class << self
48
47
 
@@ -136,6 +135,9 @@ module Lazydoc
136
135
  # Returns the attributes for the specified const_name. If an empty
137
136
  # const_name ('') is specified, and a default_const_name is set,
138
137
  # the default_const_name will be used instead.
138
+ #
139
+ # Note this method will return ALL attributes associated with const_name,
140
+ # not just attributes associated with self.
139
141
  def [](const_name)
140
142
  const_name = default_const_name if default_const_name && const_name == ''
141
143
  Document[const_name]
@@ -184,7 +186,7 @@ module Lazydoc
184
186
  def register___(comment_class=Comment, caller_index=0)
185
187
  caller[caller_index] =~ CALLER_REGEXP
186
188
  block = lambda do |scanner, lines|
187
- n = $3.to_i
189
+ n = $2.to_i
188
190
  n += 1 while lines[n] =~ /^\s*(#.*)?$/
189
191
  n
190
192
  end
@@ -216,7 +218,7 @@ module Lazydoc
216
218
  comment.parse_down(scanner, lines) do |line|
217
219
  if line =~ ATTRIBUTE_REGEXP
218
220
  # rewind to capture the next attribute unless an end is specified.
219
- scanner.unscan unless $4 == '-' && $3 == key && $1.to_s == const_name
221
+ scanner.unscan unless $3 == '-' && $2 == key && $1.to_s == const_name
220
222
  true
221
223
  else false
222
224
  end
@@ -0,0 +1,7 @@
1
+ module Lazydoc
2
+ MAJOR = 1
3
+ MINOR = 0
4
+ TINY = 0
5
+
6
+ VERSION="#{MAJOR}.#{MINOR}.#{TINY}"
7
+ 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.9.0
4
+ version: "1.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: 2009-05-25 00:00:00 -06:00
12
+ date: 2009-12-05 00:00:00 -07:00
13
13
  default_executable:
14
14
  dependencies: []
15
15
 
@@ -33,11 +33,14 @@ files:
33
33
  - lib/lazydoc/subject.rb
34
34
  - lib/lazydoc/trailer.rb
35
35
  - lib/lazydoc/utils.rb
36
+ - lib/lazydoc/version.rb
36
37
  - README
37
38
  - MIT-LICENSE
38
39
  - History
39
40
  has_rdoc: true
40
41
  homepage: http://tap.rubyforge.org/lazydoc
42
+ licenses: []
43
+
41
44
  post_install_message:
42
45
  rdoc_options:
43
46
  - --title
@@ -63,9 +66,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
63
66
  requirements: []
64
67
 
65
68
  rubyforge_project: tap
66
- rubygems_version: 1.3.1
69
+ rubygems_version: 1.3.5
67
70
  signing_key:
68
- specification_version: 2
71
+ specification_version: 3
69
72
  summary: Lazily pull documentation out of source files.
70
73
  test_files: []
71
74