rdoc 2.0.0 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of rdoc might be problematic. Click here for more details.

Files changed (52) hide show
  1. data.tar.gz.sig +1 -0
  2. data/History.txt +30 -0
  3. data/Manifest.txt +18 -6
  4. data/Rakefile +52 -0
  5. data/lib/rdoc.rb +69 -69
  6. data/lib/rdoc/code_objects.rb +331 -112
  7. data/lib/rdoc/generator.rb +172 -144
  8. data/lib/rdoc/generator/html.rb +45 -18
  9. data/lib/rdoc/generator/html/frameless.rb +795 -0
  10. data/lib/rdoc/generator/html/hefss.rb +11 -11
  11. data/lib/rdoc/generator/html/html.rb +81 -87
  12. data/lib/rdoc/generator/html/kilmer.rb +10 -10
  13. data/lib/rdoc/generator/html/one_page_html.rb +9 -9
  14. data/lib/rdoc/generator/ri.rb +5 -8
  15. data/lib/rdoc/generator/texinfo.rb +84 -0
  16. data/lib/rdoc/generator/texinfo/class.texinfo.erb +44 -0
  17. data/lib/rdoc/generator/texinfo/file.texinfo.erb +6 -0
  18. data/lib/rdoc/generator/texinfo/method.texinfo.erb +6 -0
  19. data/lib/rdoc/generator/texinfo/texinfo.erb +28 -0
  20. data/lib/rdoc/known_classes.rb +69 -0
  21. data/lib/rdoc/markup.rb +3 -3
  22. data/lib/rdoc/markup/attribute_manager.rb +0 -9
  23. data/lib/rdoc/markup/fragments.rb +1 -1
  24. data/lib/rdoc/markup/preprocess.rb +10 -6
  25. data/lib/rdoc/markup/to_html.rb +55 -8
  26. data/lib/rdoc/markup/to_html_crossref.rb +21 -5
  27. data/lib/rdoc/markup/to_texinfo.rb +69 -0
  28. data/lib/rdoc/options.rb +37 -14
  29. data/lib/rdoc/parser.rb +109 -0
  30. data/lib/rdoc/parser/c.rb +656 -0
  31. data/lib/rdoc/parser/f95.rb +1835 -0
  32. data/lib/rdoc/{parsers/parse_rb.rb → parser/ruby.rb} +1436 -1191
  33. data/lib/rdoc/parser/simple.rb +38 -0
  34. data/lib/rdoc/rdoc.rb +48 -32
  35. data/lib/rdoc/ri.rb +5 -1
  36. data/lib/rdoc/ri/descriptions.rb +8 -5
  37. data/lib/rdoc/ri/driver.rb +148 -49
  38. data/lib/rdoc/stats.rb +94 -4
  39. data/test/test_rdoc_info_formatting.rb +175 -0
  40. data/test/test_rdoc_info_sections.rb +136 -0
  41. data/test/test_rdoc_markup_to_html.rb +30 -0
  42. data/test/test_rdoc_markup_to_html_crossref.rb +18 -0
  43. data/test/{test_rdoc_c_parser.rb → test_rdoc_parser_c.rb} +8 -11
  44. data/test/test_rdoc_parser_ruby.rb +539 -0
  45. data/test/test_rdoc_ri_default_display.rb +17 -16
  46. data/test/test_rdoc_ri_driver.rb +92 -0
  47. metadata +54 -12
  48. metadata.gz.sig +0 -0
  49. data/lib/rdoc/parsers/parse_c.rb +0 -775
  50. data/lib/rdoc/parsers/parse_f95.rb +0 -1841
  51. data/lib/rdoc/parsers/parse_simple.rb +0 -40
  52. data/lib/rdoc/parsers/parserfactory.rb +0 -99
@@ -4,7 +4,7 @@ require 'rdoc/ri/formatter'
4
4
  require 'rdoc/ri/display'
5
5
  require 'rdoc/ri/driver'
6
6
 
7
- class TestRDocRIDefaultDisplay < Test::Unit::TestCase
7
+ class TestRdocRiDefaultDisplay < Test::Unit::TestCase
8
8
 
9
9
  def setup
10
10
  @output = StringIO.new
@@ -14,7 +14,7 @@ class TestRDocRIDefaultDisplay < Test::Unit::TestCase
14
14
  @dd = RDoc::RI::DefaultDisplay.new RDoc::RI::Formatter, @width, true,
15
15
  @output
16
16
 
17
- @some_method = {
17
+ @some_method = h \
18
18
  'aliases' => [{'name' => 'some_method_alias'}],
19
19
  'block_params' => 'block_param',
20
20
  'comment' => [RDoc::Markup::Flow::P.new('some comment')],
@@ -23,13 +23,12 @@ class TestRDocRIDefaultDisplay < Test::Unit::TestCase
23
23
  'name' => 'some_method',
24
24
  'params' => '(arg1, arg2) {|block_param| ...}',
25
25
  'source_path' => '/nonexistent',
26
- 'visibility' => 'public',
27
- }
26
+ 'visibility' => 'public'
28
27
  end
29
28
 
30
29
  def test_display_class_info
31
30
  ri_reader = nil
32
- klass = {
31
+ klass = h \
33
32
  'attributes' => [
34
33
  { 'name' => 'attribute', 'rw' => 'RW',
35
34
  'comment' => [RDoc::Markup::Flow::P.new('attribute comment')] },
@@ -58,8 +57,7 @@ class TestRDocRIDefaultDisplay < Test::Unit::TestCase
58
57
  'instance_method_extensions' => [
59
58
  { 'name' => 'instance_method_extension' },
60
59
  ],
61
- 'superclass_string' => 'Object',
62
- }
60
+ 'superclass_string' => 'Object'
63
61
 
64
62
  @dd.display_class_info klass, ri_reader
65
63
 
@@ -154,7 +152,7 @@ Attributes:
154
152
  end
155
153
 
156
154
  def test_display_method_info_singleton
157
- method = {
155
+ method = RDoc::RI::Driver::Hash.new.update \
158
156
  'aliases' => [],
159
157
  'block_params' => nil,
160
158
  'comment' => nil,
@@ -162,8 +160,7 @@ Attributes:
162
160
  'is_singleton' => true,
163
161
  'name' => 'some_method',
164
162
  'params' => '(arg1, arg2)',
165
- 'visibility' => 'public',
166
- }
163
+ 'visibility' => 'public'
167
164
 
168
165
  @dd.display_method_info method
169
166
 
@@ -179,7 +176,7 @@ Attributes:
179
176
 
180
177
  def test_display_method_list
181
178
  methods = [
182
- {
179
+ RDoc::RI::Driver::Hash.new.update(
183
180
  "aliases" => [],
184
181
  "block_params" => nil,
185
182
  "comment" => nil,
@@ -187,9 +184,9 @@ Attributes:
187
184
  "is_singleton" => false,
188
185
  "name" => "some_method",
189
186
  "params" => "()",
190
- "visibility" => "public",
191
- },
192
- {
187
+ "visibility" => "public"
188
+ ),
189
+ RDoc::RI::Driver::Hash.new.update(
193
190
  "aliases" => [],
194
191
  "block_params" => nil,
195
192
  "comment" => nil,
@@ -197,8 +194,8 @@ Attributes:
197
194
  "is_singleton" => false,
198
195
  "name" => "some_other_method",
199
196
  "params" => "()",
200
- "visibility" => "public",
201
- },
197
+ "visibility" => "public"
198
+ ),
202
199
  ]
203
200
 
204
201
  @dd.display_method_list methods
@@ -291,5 +288,9 @@ install an additional package, or ask the packager to enable ri generation.
291
288
  assert_equal expected, @output.string
292
289
  end
293
290
 
291
+ def h(hash)
292
+ RDoc::RI::Driver::Hash.convert hash
293
+ end
294
+
294
295
  end
295
296
 
@@ -0,0 +1,92 @@
1
+ require 'test/unit'
2
+ require 'tmpdir'
3
+ require 'rdoc/ri/driver'
4
+
5
+ class TestRDocRIDriver < Test::Unit::TestCase
6
+
7
+ def setup
8
+ @tmpdir = File.join Dir.tmpdir, "test_rdoc_ri_driver_#{$$}"
9
+ @home_ri = File.join @tmpdir, 'dot_ri'
10
+ @cache_dir = File.join @home_ri, 'cache'
11
+ @class_cache = File.join @cache_dir, 'classes'
12
+
13
+ FileUtils.mkdir_p @tmpdir
14
+ FileUtils.mkdir_p @home_ri
15
+ FileUtils.mkdir_p @cache_dir
16
+
17
+ @driver = RDoc::RI::Driver.new
18
+ @driver.homepath = @home_ri
19
+ end
20
+
21
+ def teardown
22
+ FileUtils.rm_rf @tmpdir
23
+ end
24
+
25
+ def test_lookup_method
26
+ def @driver.load_cache_for(klassname)
27
+ { 'Foo#bar' => :found }
28
+ end
29
+
30
+ assert @driver.lookup_method('Foo#bar', 'Foo')
31
+ end
32
+
33
+ def test_lookup_method_class_method
34
+ def @driver.load_cache_for(klassname)
35
+ { 'Foo::Bar' => :found }
36
+ end
37
+
38
+ assert @driver.lookup_method('Foo::Bar', 'Foo::Bar')
39
+ end
40
+
41
+ def test_lookup_method_class_missing
42
+ def @driver.load_cache_for(klassname) end
43
+
44
+ assert_nil @driver.lookup_method('Foo#bar', 'Foo')
45
+ end
46
+
47
+ def test_lookup_method_dot_instance
48
+ def @driver.load_cache_for(klassname)
49
+ { 'Foo#bar' => :instance, 'Foo::bar' => :klass }
50
+ end
51
+
52
+ assert_equal :instance, @driver.lookup_method('Foo.bar', 'Foo')
53
+ end
54
+
55
+ def test_lookup_method_dot_class
56
+ def @driver.load_cache_for(klassname)
57
+ { 'Foo::bar' => :found }
58
+ end
59
+
60
+ assert @driver.lookup_method('Foo.bar', 'Foo')
61
+ end
62
+
63
+ def test_lookup_method_method_missing
64
+ def @driver.load_cache_for(klassname) {} end
65
+
66
+ assert_nil @driver.lookup_method('Foo#bar', 'Foo')
67
+ end
68
+
69
+ def test_parse_name
70
+ klass, meth = @driver.parse_name 'Foo::Bar'
71
+
72
+ assert_equal 'Foo::Bar', klass, 'Foo::Bar class'
73
+ assert_equal nil, meth, 'Foo::Bar method'
74
+
75
+ klass, meth = @driver.parse_name 'Foo#Bar'
76
+
77
+ assert_equal 'Foo', klass, 'Foo#Bar class'
78
+ assert_equal 'Bar', meth, 'Foo#Bar method'
79
+
80
+ klass, meth = @driver.parse_name 'Foo.Bar'
81
+
82
+ assert_equal 'Foo', klass, 'Foo#Bar class'
83
+ assert_equal 'Bar', meth, 'Foo#Bar method'
84
+
85
+ klass, meth = @driver.parse_name 'Foo::bar'
86
+
87
+ assert_equal 'Foo', klass, 'Foo::bar class'
88
+ assert_equal 'bar', meth, 'Foo::bar method'
89
+ end
90
+
91
+ end
92
+
metadata CHANGED
@@ -1,31 +1,55 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rdoc
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.0
4
+ version: 2.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Eric Hodel
8
8
  - Dave Thomas
9
+ - Phil Hagelberg
9
10
  autorequire:
10
11
  bindir: bin
11
- cert_chain: []
12
+ cert_chain:
13
+ - |
14
+ -----BEGIN CERTIFICATE-----
15
+ MIIDNjCCAh6gAwIBAgIBADANBgkqhkiG9w0BAQUFADBBMRAwDgYDVQQDDAdkcmJy
16
+ YWluMRgwFgYKCZImiZPyLGQBGRYIc2VnbWVudDcxEzARBgoJkiaJk/IsZAEZFgNu
17
+ ZXQwHhcNMDcxMjIxMDIwNDE0WhcNMDgxMjIwMDIwNDE0WjBBMRAwDgYDVQQDDAdk
18
+ cmJyYWluMRgwFgYKCZImiZPyLGQBGRYIc2VnbWVudDcxEzARBgoJkiaJk/IsZAEZ
19
+ FgNuZXQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCbbgLrGLGIDE76
20
+ LV/cvxdEzCuYuS3oG9PrSZnuDweySUfdp/so0cDq+j8bqy6OzZSw07gdjwFMSd6J
21
+ U5ddZCVywn5nnAQ+Ui7jMW54CYt5/H6f2US6U0hQOjJR6cpfiymgxGdfyTiVcvTm
22
+ Gj/okWrQl0NjYOYBpDi+9PPmaH2RmLJu0dB/NylsDnW5j6yN1BEI8MfJRR+HRKZY
23
+ mUtgzBwF1V4KIZQ8EuL6I/nHVu07i6IkrpAgxpXUfdJQJi0oZAqXurAV3yTxkFwd
24
+ g62YrrW26mDe+pZBzR6bpLE+PmXCzz7UxUq3AE0gPHbiMXie3EFE0oxnsU3lIduh
25
+ sCANiQ8BAgMBAAGjOTA3MAkGA1UdEwQCMAAwCwYDVR0PBAQDAgSwMB0GA1UdDgQW
26
+ BBS5k4Z75VSpdM0AclG2UvzFA/VW5DANBgkqhkiG9w0BAQUFAAOCAQEAHagT4lfX
27
+ kP/hDaiwGct7XPuVGbrOsKRVD59FF5kETBxEc9UQ1clKWngf8JoVuEoKD774dW19
28
+ bU0GOVWO+J6FMmT/Cp7nuFJ79egMf/gy4gfUfQMuvfcr6DvZUPIs9P/TlK59iMYF
29
+ DIOQ3DxdF3rMzztNUCizN4taVscEsjCcgW6WkUJnGdqlu3OHWpQxZBJkBTjPCoc6
30
+ UW6on70SFPmAy/5Cq0OJNGEWBfgD9q7rrs/X8GGwUWqXb85RXnUVi/P8Up75E0ag
31
+ 14jEc90kN+C7oI/AGCBN0j6JnEtYIEJZibjjDJTSMWlUKKkj30kq7hlUC2CepJ4v
32
+ x52qPcexcYZR7w==
33
+ -----END CERTIFICATE-----
12
34
 
13
- date: 2008-04-10 00:00:00 -07:00
35
+ date: 2008-07-20 00:00:00 -07:00
14
36
  default_executable:
15
37
  dependencies:
16
38
  - !ruby/object:Gem::Dependency
17
39
  name: hoe
40
+ type: :development
18
41
  version_requirement:
19
42
  version_requirements: !ruby/object:Gem::Requirement
20
43
  requirements:
21
44
  - - ">="
22
45
  - !ruby/object:Gem::Version
23
- version: 1.5.1
46
+ version: 1.7.0
24
47
  version:
25
48
  description: RDoc is an application that produces documentation for one or more Ruby source files. RDoc includes the `rdoc` and `ri` tools for generating and displaying online documentation. At this point in time, RDoc 2.x is a work in progress and may incur further API changes beyond what has been made to the RDoc 1.0.1. Command-line tools are largely unaffected, but internal APIs may shift rapidly.
26
49
  email:
27
50
  - drbrain@segment7.net
28
51
  - ""
52
+ - technomancy@gmail.com
29
53
  executables:
30
54
  - rdoc
31
55
  - ri
@@ -50,14 +74,21 @@ files:
50
74
  - lib/rdoc/generator/chm.rb
51
75
  - lib/rdoc/generator/chm/chm.rb
52
76
  - lib/rdoc/generator/html.rb
77
+ - lib/rdoc/generator/html/frameless.rb
53
78
  - lib/rdoc/generator/html/hefss.rb
54
79
  - lib/rdoc/generator/html/html.rb
55
80
  - lib/rdoc/generator/html/kilmer.rb
56
81
  - lib/rdoc/generator/html/one_page_html.rb
57
82
  - lib/rdoc/generator/ri.rb
83
+ - lib/rdoc/generator/texinfo.rb
84
+ - lib/rdoc/generator/texinfo/class.texinfo.erb
85
+ - lib/rdoc/generator/texinfo/file.texinfo.erb
86
+ - lib/rdoc/generator/texinfo/method.texinfo.erb
87
+ - lib/rdoc/generator/texinfo/texinfo.erb
58
88
  - lib/rdoc/generator/xml.rb
59
89
  - lib/rdoc/generator/xml/rdf.rb
60
90
  - lib/rdoc/generator/xml/xml.rb
91
+ - lib/rdoc/known_classes.rb
61
92
  - lib/rdoc/markup.rb
62
93
  - lib/rdoc/markup/attribute_manager.rb
63
94
  - lib/rdoc/markup/formatter.rb
@@ -70,12 +101,13 @@ files:
70
101
  - lib/rdoc/markup/to_html_crossref.rb
71
102
  - lib/rdoc/markup/to_latex.rb
72
103
  - lib/rdoc/markup/to_test.rb
104
+ - lib/rdoc/markup/to_texinfo.rb
73
105
  - lib/rdoc/options.rb
74
- - lib/rdoc/parsers/parse_c.rb
75
- - lib/rdoc/parsers/parse_f95.rb
76
- - lib/rdoc/parsers/parse_rb.rb
77
- - lib/rdoc/parsers/parse_simple.rb
78
- - lib/rdoc/parsers/parserfactory.rb
106
+ - lib/rdoc/parser.rb
107
+ - lib/rdoc/parser/c.rb
108
+ - lib/rdoc/parser/f95.rb
109
+ - lib/rdoc/parser/ruby.rb
110
+ - lib/rdoc/parser/simple.rb
79
111
  - lib/rdoc/rdoc.rb
80
112
  - lib/rdoc/ri.rb
81
113
  - lib/rdoc/ri/cache.rb
@@ -90,11 +122,15 @@ files:
90
122
  - lib/rdoc/stats.rb
91
123
  - lib/rdoc/template.rb
92
124
  - lib/rdoc/tokenstream.rb
93
- - test/test_rdoc_c_parser.rb
125
+ - test/test_rdoc_info_formatting.rb
126
+ - test/test_rdoc_info_sections.rb
94
127
  - test/test_rdoc_markup.rb
95
128
  - test/test_rdoc_markup_attribute_manager.rb
129
+ - test/test_rdoc_parser_c.rb
130
+ - test/test_rdoc_parser_ruby.rb
96
131
  - test/test_rdoc_ri_attribute_formatter.rb
97
132
  - test/test_rdoc_ri_default_display.rb
133
+ - test/test_rdoc_ri_driver.rb
98
134
  - test/test_rdoc_ri_formatter.rb
99
135
  - test/test_rdoc_ri_overstrike_formatter.rb
100
136
  has_rdoc: true
@@ -120,15 +156,21 @@ required_rubygems_version: !ruby/object:Gem::Requirement
120
156
  requirements: []
121
157
 
122
158
  rubyforge_project: rdoc
123
- rubygems_version: 1.1.0
159
+ rubygems_version: 1.2.0
124
160
  signing_key:
125
161
  specification_version: 2
126
162
  summary: RDoc is an application that produces documentation for one or more Ruby source files
127
163
  test_files:
128
- - test/test_rdoc_c_parser.rb
164
+ - test/test_rdoc_info_formatting.rb
165
+ - test/test_rdoc_info_sections.rb
129
166
  - test/test_rdoc_markup.rb
130
167
  - test/test_rdoc_markup_attribute_manager.rb
168
+ - test/test_rdoc_markup_to_html.rb
169
+ - test/test_rdoc_markup_to_html_crossref.rb
170
+ - test/test_rdoc_parser_c.rb
171
+ - test/test_rdoc_parser_ruby.rb
131
172
  - test/test_rdoc_ri_attribute_formatter.rb
132
173
  - test/test_rdoc_ri_default_display.rb
174
+ - test/test_rdoc_ri_driver.rb
133
175
  - test/test_rdoc_ri_formatter.rb
134
176
  - test/test_rdoc_ri_overstrike_formatter.rb
Binary file
@@ -1,775 +0,0 @@
1
- # Classes and modules built in to the interpreter. We need
2
- # these to define superclasses of user objects
3
-
4
- require "rdoc/code_objects"
5
- require "rdoc/parsers/parserfactory"
6
- require "rdoc/rdoc"
7
-
8
- module RDoc
9
-
10
- ##
11
- # Ruby's built-in classes.
12
-
13
- KNOWN_CLASSES = {
14
- "rb_cObject" => "Object",
15
- "rb_cArray" => "Array",
16
- "rb_cBignum" => "Bignum",
17
- "rb_cClass" => "Class",
18
- "rb_cDir" => "Dir",
19
- "rb_cData" => "Data",
20
- "rb_cFalseClass" => "FalseClass",
21
- "rb_cFile" => "File",
22
- "rb_cFixnum" => "Fixnum",
23
- "rb_cFloat" => "Float",
24
- "rb_cHash" => "Hash",
25
- "rb_cInteger" => "Integer",
26
- "rb_cIO" => "IO",
27
- "rb_cModule" => "Module",
28
- "rb_cNilClass" => "NilClass",
29
- "rb_cNumeric" => "Numeric",
30
- "rb_cProc" => "Proc",
31
- "rb_cRange" => "Range",
32
- "rb_cRegexp" => "Regexp",
33
- "rb_cString" => "String",
34
- "rb_cSymbol" => "Symbol",
35
- "rb_cThread" => "Thread",
36
- "rb_cTime" => "Time",
37
- "rb_cTrueClass" => "TrueClass",
38
- "rb_cStruct" => "Struct",
39
- "rb_cVM" => "VM",
40
- "rb_eException" => "Exception",
41
- "rb_eStandardError" => "StandardError",
42
- "rb_eSystemExit" => "SystemExit",
43
- "rb_eInterrupt" => "Interrupt",
44
- "rb_eSignal" => "Signal",
45
- "rb_eFatal" => "Fatal",
46
- "rb_eArgError" => "ArgError",
47
- "rb_eEOFError" => "EOFError",
48
- "rb_eIndexError" => "IndexError",
49
- "rb_eRangeError" => "RangeError",
50
- "rb_eIOError" => "IOError",
51
- "rb_eRuntimeError" => "RuntimeError",
52
- "rb_eSecurityError" => "SecurityError",
53
- "rb_eSystemCallError" => "SystemCallError",
54
- "rb_eTypeError" => "TypeError",
55
- "rb_eZeroDivError" => "ZeroDivError",
56
- "rb_eNotImpError" => "NotImpError",
57
- "rb_eNoMemError" => "NoMemError",
58
- "rb_eFloatDomainError" => "FloatDomainError",
59
- "rb_eScriptError" => "ScriptError",
60
- "rb_eNameError" => "NameError",
61
- "rb_eSyntaxError" => "SyntaxError",
62
- "rb_eLoadError" => "LoadError",
63
-
64
- "rb_mKernel" => "Kernel",
65
- "rb_mComparable" => "Comparable",
66
- "rb_mEnumerable" => "Enumerable",
67
- "rb_mPrecision" => "Precision",
68
- "rb_mErrno" => "Errno",
69
- "rb_mFileTest" => "FileTest",
70
- "rb_mGC" => "GC",
71
- "rb_mMath" => "Math",
72
- "rb_mProcess" => "Process"
73
- }
74
-
75
- ##
76
- # We attempt to parse C extension files. Basically we look for
77
- # the standard patterns that you find in extensions: <tt>rb_define_class,
78
- # rb_define_method</tt> and so on. We also try to find the corresponding
79
- # C source for the methods and extract comments, but if we fail
80
- # we don't worry too much.
81
- #
82
- # The comments associated with a Ruby method are extracted from the C
83
- # comment block associated with the routine that _implements_ that
84
- # method, that is to say the method whose name is given in the
85
- # <tt>rb_define_method</tt> call. For example, you might write:
86
- #
87
- # /*
88
- # * Returns a new array that is a one-dimensional flattening of this
89
- # * array (recursively). That is, for every element that is an array,
90
- # * extract its elements into the new array.
91
- # *
92
- # * s = [ 1, 2, 3 ] #=> [1, 2, 3]
93
- # * t = [ 4, 5, 6, [7, 8] ] #=> [4, 5, 6, [7, 8]]
94
- # * a = [ s, t, 9, 10 ] #=> [[1, 2, 3], [4, 5, 6, [7, 8]], 9, 10]
95
- # * a.flatten #=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
96
- # */
97
- # static VALUE
98
- # rb_ary_flatten(ary)
99
- # VALUE ary;
100
- # {
101
- # ary = rb_obj_dup(ary);
102
- # rb_ary_flatten_bang(ary);
103
- # return ary;
104
- # }
105
- #
106
- # ...
107
- #
108
- # void
109
- # Init_Array()
110
- # {
111
- # ...
112
- # rb_define_method(rb_cArray, "flatten", rb_ary_flatten, 0);
113
- #
114
- # Here RDoc will determine from the rb_define_method line that there's a
115
- # method called "flatten" in class Array, and will look for the implementation
116
- # in the method rb_ary_flatten. It will then use the comment from that
117
- # method in the HTML output. This method must be in the same source file
118
- # as the rb_define_method.
119
- #
120
- # C classes can be diagramed (see /tc/dl/ruby/ruby/error.c), and RDoc
121
- # integrates C and Ruby source into one tree
122
- #
123
- # The comment blocks may include special direcives:
124
- #
125
- # [Document-class: <i>name</i>]
126
- # This comment block is documentation for the given class. Use this
127
- # when the <tt>Init_xxx</tt> method is not named after the class.
128
- #
129
- # [Document-method: <i>name</i>]
130
- # This comment documents the named method. Use when RDoc cannot
131
- # automatically find the method from it's declaration
132
- #
133
- # [call-seq: <i>text up to an empty line</i>]
134
- # Because C source doesn't give descripive names to Ruby-level parameters,
135
- # you need to document the calling sequence explicitly
136
- #
137
- # In additon, RDoc assumes by default that the C method implementing a
138
- # Ruby function is in the same source file as the rb_define_method call.
139
- # If this isn't the case, add the comment
140
- #
141
- # rb_define_method(....); // in: filename
142
- #
143
- # As an example, we might have an extension that defines multiple classes
144
- # in its Init_xxx method. We could document them using
145
- #
146
- #
147
- # /*
148
- # * Document-class: MyClass
149
- # *
150
- # * Encapsulate the writing and reading of the configuration
151
- # * file. ...
152
- # */
153
- #
154
- # /*
155
- # * Document-method: read_value
156
- # *
157
- # * call-seq:
158
- # * cfg.read_value(key) -> value
159
- # * cfg.read_value(key} { |key| } -> value
160
- # *
161
- # * Return the value corresponding to +key+ from the configuration.
162
- # * In the second form, if the key isn't found, invoke the
163
- # * block and return its value.
164
- # */
165
- #
166
-
167
- class C_Parser
168
-
169
- attr_writer :progress
170
-
171
- extend ParserFactory
172
- parse_files_matching(/\.(?:([CcHh])\1?|c([+xp])\2|y)\z/)
173
-
174
- @@enclosure_classes = {}
175
- @@known_bodies = {}
176
-
177
- # prepare to parse a C file
178
- def initialize(top_level, file_name, body, options, stats)
179
- @known_classes = KNOWN_CLASSES.dup
180
- @options = options
181
- @body = handle_tab_width(handle_ifdefs_in(body))
182
- @stats = stats
183
- @top_level = top_level
184
- @classes = Hash.new
185
- @file_dir = File.dirname(file_name)
186
- @progress = $stderr unless @options.quiet
187
- end
188
-
189
- # Extract the classes/modules and methods from a C file
190
- # and return the corresponding top-level object
191
- def scan
192
- remove_commented_out_lines
193
- do_classes
194
- do_constants
195
- do_methods
196
- do_includes
197
- do_aliases
198
- @top_level
199
- end
200
-
201
- #######
202
- private
203
- #######
204
-
205
- def progress(char)
206
- unless @options.quiet
207
- @progress.print(char)
208
- @progress.flush
209
- end
210
- end
211
-
212
- def warn(msg)
213
- $stderr.puts
214
- $stderr.puts msg
215
- $stderr.flush
216
- end
217
-
218
- def remove_private_comments(comment)
219
- comment.gsub!(/\/?\*--(.*?)\/?\*\+\+/m, '')
220
- comment.sub!(/\/?\*--.*/m, '')
221
- end
222
-
223
- ##
224
- # removes lines that are commented out that might otherwise get picked up
225
- # when scanning for classes and methods
226
-
227
- def remove_commented_out_lines
228
- @body.gsub!(%r{//.*rb_define_}, '//')
229
- end
230
-
231
- def handle_class_module(var_name, class_mod, class_name, parent, in_module)
232
- progress(class_mod[0, 1])
233
-
234
- parent_name = @known_classes[parent] || parent
235
-
236
- if in_module
237
- enclosure = @classes[in_module] || @@enclosure_classes[in_module]
238
- unless enclosure
239
- if enclosure = @known_classes[in_module]
240
- handle_class_module(in_module, (/^rb_m/ =~ in_module ? "module" : "class"),
241
- enclosure, nil, nil)
242
- enclosure = @classes[in_module]
243
- end
244
- end
245
- unless enclosure
246
- warn("Enclosing class/module '#{in_module}' for " +
247
- "#{class_mod} #{class_name} not known")
248
- return
249
- end
250
- else
251
- enclosure = @top_level
252
- end
253
-
254
- if class_mod == "class"
255
- cm = enclosure.add_class(NormalClass, class_name, parent_name)
256
- @stats.num_classes += 1
257
- else
258
- cm = enclosure.add_module(NormalModule, class_name)
259
- @stats.num_modules += 1
260
- end
261
- cm.record_location(enclosure.toplevel)
262
-
263
- find_class_comment(cm.full_name, cm)
264
- @classes[var_name] = cm
265
- @@enclosure_classes[var_name] = cm
266
- @known_classes[var_name] = cm.full_name
267
- end
268
-
269
- ##
270
- # Look for class or module documentation above Init_+class_name+(void),
271
- # in a Document-class +class_name+ (or module) comment or above an
272
- # rb_define_class (or module). If a comment is supplied above a matching
273
- # Init_ and a rb_define_class the Init_ comment is used.
274
- #
275
- # /*
276
- # * This is a comment for Foo
277
- # */
278
- # Init_Foo(void) {
279
- # VALUE cFoo = rb_define_class("Foo", rb_cObject);
280
- # }
281
- #
282
- # /*
283
- # * Document-class: Foo
284
- # * This is a comment for Foo
285
- # */
286
- # Init_foo(void) {
287
- # VALUE cFoo = rb_define_class("Foo", rb_cObject);
288
- # }
289
- #
290
- # /*
291
- # * This is a comment for Foo
292
- # */
293
- # VALUE cFoo = rb_define_class("Foo", rb_cObject);
294
-
295
- def find_class_comment(class_name, class_meth)
296
- comment = nil
297
- if @body =~ %r{((?>/\*.*?\*/\s+))
298
- (static\s+)?void\s+Init_#{class_name}\s*(?:_\(\s*)?\(\s*(?:void\s*)\)}xmi
299
- comment = $1
300
- elsif @body =~ %r{Document-(class|module):\s#{class_name}\s*?\n((?>.*?\*/))}m
301
- comment = $2
302
- else
303
- if @body =~ /rb_define_(class|module)/m then
304
- class_name = class_name.split("::").last
305
- comments = []
306
- @body.split(/(\/\*.*?\*\/)\s*?\n/m).each_with_index do |chunk, index|
307
- comments[index] = chunk
308
- if chunk =~ /rb_define_(class|module).*?"(#{class_name})"/m then
309
- comment = comments[index-1]
310
- break
311
- end
312
- end
313
- end
314
- end
315
- class_meth.comment = mangle_comment(comment) if comment
316
- end
317
-
318
- ############################################################
319
-
320
- def do_classes
321
- @body.scan(/(\w+)\s* = \s*rb_define_module\s*\(\s*"(\w+)"\s*\)/mx) do
322
- |var_name, class_name|
323
- handle_class_module(var_name, "module", class_name, nil, nil)
324
- end
325
-
326
- # The '.' lets us handle SWIG-generated files
327
- @body.scan(/([\w\.]+)\s* = \s*rb_define_class\s*
328
- \(
329
- \s*"(\w+)",
330
- \s*(\w+)\s*
331
- \)/mx) do
332
-
333
- |var_name, class_name, parent|
334
- handle_class_module(var_name, "class", class_name, parent, nil)
335
- end
336
-
337
- @body.scan(/(\w+)\s*=\s*boot_defclass\s*\(\s*"(\w+?)",\s*(\w+?)\s*\)/) do
338
- |var_name, class_name, parent|
339
- parent = nil if parent == "0"
340
- handle_class_module(var_name, "class", class_name, parent, nil)
341
- end
342
-
343
- @body.scan(/(\w+)\s* = \s*rb_define_module_under\s*
344
- \(
345
- \s*(\w+),
346
- \s*"(\w+)"
347
- \s*\)/mx) do
348
-
349
- |var_name, in_module, class_name|
350
- handle_class_module(var_name, "module", class_name, nil, in_module)
351
- end
352
-
353
- @body.scan(/([\w\.]+)\s* = \s*rb_define_class_under\s*
354
- \(
355
- \s*(\w+),
356
- \s*"(\w+)",
357
- \s*(\w+)\s*
358
- \s*\)/mx) do
359
-
360
- |var_name, in_module, class_name, parent|
361
- handle_class_module(var_name, "class", class_name, parent, in_module)
362
- end
363
-
364
- end
365
-
366
- ###########################################################
367
-
368
- def do_constants
369
- @body.scan(%r{\Wrb_define_
370
- (
371
- variable |
372
- readonly_variable |
373
- const |
374
- global_const |
375
- )
376
- \s*\(
377
- (?:\s*(\w+),)?
378
- \s*"(\w+)",
379
- \s*(.*?)\s*\)\s*;
380
- }xm) do
381
-
382
- |type, var_name, const_name, definition|
383
- var_name = "rb_cObject" if !var_name or var_name == "rb_mKernel"
384
- handle_constants(type, var_name, const_name, definition)
385
- end
386
- end
387
-
388
- ############################################################
389
-
390
- def do_methods
391
-
392
- @body.scan(%r{rb_define_
393
- (
394
- singleton_method |
395
- method |
396
- module_function |
397
- private_method
398
- )
399
- \s*\(\s*([\w\.]+),
400
- \s*"([^"]+)",
401
- \s*(?:RUBY_METHOD_FUNC\(|VALUEFUNC\()?(\w+)\)?,
402
- \s*(-?\w+)\s*\)
403
- (?:;\s*/[*/]\s+in\s+(\w+?\.[cy]))?
404
- }xm) do
405
- |type, var_name, meth_name, meth_body, param_count, source_file|
406
- #"
407
-
408
- # Ignore top-object and weird struct.c dynamic stuff
409
- next if var_name == "ruby_top_self"
410
- next if var_name == "nstr"
411
- next if var_name == "envtbl"
412
- next if var_name == "argf" # it'd be nice to handle this one
413
-
414
- var_name = "rb_cObject" if var_name == "rb_mKernel"
415
- handle_method(type, var_name, meth_name,
416
- meth_body, param_count, source_file)
417
- end
418
-
419
- @body.scan(%r{rb_define_attr\(
420
- \s*([\w\.]+),
421
- \s*"([^"]+)",
422
- \s*(\d+),
423
- \s*(\d+)\s*\);
424
- }xm) do #"
425
- |var_name, attr_name, attr_reader, attr_writer|
426
-
427
- #var_name = "rb_cObject" if var_name == "rb_mKernel"
428
- handle_attr(var_name, attr_name,
429
- attr_reader.to_i != 0,
430
- attr_writer.to_i != 0)
431
- end
432
-
433
- @body.scan(%r{rb_define_global_function\s*\(
434
- \s*"([^"]+)",
435
- \s*(?:RUBY_METHOD_FUNC\(|VALUEFUNC\()?(\w+)\)?,
436
- \s*(-?\w+)\s*\)
437
- (?:;\s*/[*/]\s+in\s+(\w+?\.[cy]))?
438
- }xm) do #"
439
- |meth_name, meth_body, param_count, source_file|
440
- handle_method("method", "rb_mKernel", meth_name,
441
- meth_body, param_count, source_file)
442
- end
443
-
444
- @body.scan(/define_filetest_function\s*\(
445
- \s*"([^"]+)",
446
- \s*(?:RUBY_METHOD_FUNC\(|VALUEFUNC\()?(\w+)\)?,
447
- \s*(-?\w+)\s*\)/xm) do #"
448
- |meth_name, meth_body, param_count|
449
-
450
- handle_method("method", "rb_mFileTest", meth_name, meth_body, param_count)
451
- handle_method("singleton_method", "rb_cFile", meth_name, meth_body, param_count)
452
- end
453
- end
454
-
455
- ############################################################
456
-
457
- def do_aliases
458
- @body.scan(%r{rb_define_alias\s*\(\s*(\w+),\s*"([^"]+)",\s*"([^"]+)"\s*\)}m) do
459
- |var_name, new_name, old_name|
460
- @stats.num_methods += 1
461
- class_name = @known_classes[var_name] || var_name
462
- class_obj = find_class(var_name, class_name)
463
-
464
- class_obj.add_alias(Alias.new("", old_name, new_name, ""))
465
- end
466
- end
467
-
468
- ##
469
- # Adds constant comments. By providing some_value: at the start ofthe
470
- # comment you can override the C value of the comment to give a friendly
471
- # definition.
472
- #
473
- # /* 300: The perfect score in bowling */
474
- # rb_define_const(cFoo, "PERFECT", INT2FIX(300);
475
- #
476
- # Will override +INT2FIX(300)+ with the value +300+ in the output RDoc.
477
- # Values may include quotes and escaped colons (\:).
478
-
479
- def handle_constants(type, var_name, const_name, definition)
480
- #@stats.num_constants += 1
481
- class_name = @known_classes[var_name]
482
-
483
- return unless class_name
484
-
485
- class_obj = find_class(var_name, class_name)
486
-
487
- unless class_obj
488
- warn("Enclosing class/module '#{const_name}' for not known")
489
- return
490
- end
491
-
492
- comment = find_const_comment(type, const_name)
493
-
494
- # In the case of rb_define_const, the definition and comment are in
495
- # "/* definition: comment */" form. The literal ':' and '\' characters
496
- # can be escaped with a backslash.
497
- if type.downcase == 'const' then
498
- elements = mangle_comment(comment).split(':')
499
- if elements.nil? or elements.empty? then
500
- con = Constant.new(const_name, definition, mangle_comment(comment))
501
- else
502
- new_definition = elements[0..-2].join(':')
503
- if new_definition.empty? then # Default to literal C definition
504
- new_definition = definition
505
- else
506
- new_definition.gsub!("\:", ":")
507
- new_definition.gsub!("\\", '\\')
508
- end
509
- new_definition.sub!(/\A(\s+)/, '')
510
- new_comment = $1.nil? ? elements.last : "#{$1}#{elements.last.lstrip}"
511
- con = Constant.new(const_name, new_definition,
512
- mangle_comment(new_comment))
513
- end
514
- else
515
- con = Constant.new(const_name, definition, mangle_comment(comment))
516
- end
517
-
518
- class_obj.add_constant(con)
519
- end
520
-
521
- ##
522
- # Finds a comment matching +type+ and +const_name+ either above the
523
- # comment or in the matching Document- section.
524
-
525
- def find_const_comment(type, const_name)
526
- if @body =~ %r{((?>^\s*/\*.*?\*/\s+))
527
- rb_define_#{type}\((?:\s*(\w+),)?\s*"#{const_name}"\s*,.*?\)\s*;}xmi
528
- $1
529
- elsif @body =~ %r{Document-(?:const|global|variable):\s#{const_name}\s*?\n((?>.*?\*/))}m
530
- $1
531
- else
532
- ''
533
- end
534
- end
535
-
536
- ###########################################################
537
-
538
- def handle_attr(var_name, attr_name, reader, writer)
539
- rw = ''
540
- if reader
541
- #@stats.num_methods += 1
542
- rw << 'R'
543
- end
544
- if writer
545
- #@stats.num_methods += 1
546
- rw << 'W'
547
- end
548
-
549
- class_name = @known_classes[var_name]
550
-
551
- return unless class_name
552
-
553
- class_obj = find_class(var_name, class_name)
554
-
555
- if class_obj
556
- comment = find_attr_comment(attr_name)
557
- unless comment.empty?
558
- comment = mangle_comment(comment)
559
- end
560
- att = Attr.new('', attr_name, rw, comment)
561
- class_obj.add_attribute(att)
562
- end
563
-
564
- end
565
-
566
- ###########################################################
567
-
568
- def find_attr_comment(attr_name)
569
- if @body =~ %r{((?>/\*.*?\*/\s+))
570
- rb_define_attr\((?:\s*(\w+),)?\s*"#{attr_name}"\s*,.*?\)\s*;}xmi
571
- $1
572
- elsif @body =~ %r{Document-attr:\s#{attr_name}\s*?\n((?>.*?\*/))}m
573
- $1
574
- else
575
- ''
576
- end
577
- end
578
-
579
- ###########################################################
580
-
581
- def handle_method(type, var_name, meth_name,
582
- meth_body, param_count, source_file = nil)
583
- progress(".")
584
-
585
- @stats.num_methods += 1
586
- class_name = @known_classes[var_name]
587
-
588
- return unless class_name
589
-
590
- class_obj = find_class(var_name, class_name)
591
-
592
- if class_obj
593
- if meth_name == "initialize"
594
- meth_name = "new"
595
- type = "singleton_method"
596
- end
597
- meth_obj = AnyMethod.new("", meth_name)
598
- meth_obj.singleton =
599
- %w{singleton_method module_function}.include?(type)
600
-
601
- p_count = (Integer(param_count) rescue -1)
602
-
603
- if p_count < 0
604
- meth_obj.params = "(...)"
605
- elsif p_count == 0
606
- meth_obj.params = "()"
607
- else
608
- meth_obj.params = "(" +
609
- (1..p_count).map{|i| "p#{i}"}.join(", ") +
610
- ")"
611
- end
612
-
613
- if source_file
614
- file_name = File.join(@file_dir, source_file)
615
- body = (@@known_bodies[source_file] ||= File.read(file_name))
616
- else
617
- body = @body
618
- end
619
- if find_body(meth_body, meth_obj, body) and meth_obj.document_self
620
- class_obj.add_method(meth_obj)
621
- end
622
- end
623
- end
624
-
625
- ############################################################
626
-
627
- # Find the C code corresponding to a Ruby method
628
- def find_body(meth_name, meth_obj, body, quiet = false)
629
- case body
630
- when %r"((?>/\*.*?\*/\s*))(?:static\s+)?VALUE\s+#{meth_name}
631
- \s*(\([^)]*\))\s*\{.*?^\}"xm
632
- comment, params = $1, $2
633
- body_text = $&
634
-
635
- remove_private_comments(comment) if comment
636
-
637
- # see if we can find the whole body
638
-
639
- re = Regexp.escape(body_text) + '[^(]*^\{.*?^\}'
640
- if Regexp.new(re, Regexp::MULTILINE).match(body)
641
- body_text = $&
642
- end
643
-
644
- # The comment block may have been overridden with a
645
- # 'Document-method' block. This happens in the interpreter
646
- # when multiple methods are vectored through to the same
647
- # C method but those methods are logically distinct (for
648
- # example Kernel.hash and Kernel.object_id share the same
649
- # implementation
650
-
651
- override_comment = find_override_comment(meth_obj.name)
652
- comment = override_comment if override_comment
653
-
654
- find_modifiers(comment, meth_obj) if comment
655
-
656
- # meth_obj.params = params
657
- meth_obj.start_collecting_tokens
658
- meth_obj.add_token(RubyToken::Token.new(1,1).set_text(body_text))
659
- meth_obj.comment = mangle_comment(comment)
660
- when %r{((?>/\*.*?\*/\s*))^\s*\#\s*define\s+#{meth_name}\s+(\w+)}m
661
- comment = $1
662
- find_body($2, meth_obj, body, true)
663
- find_modifiers(comment, meth_obj)
664
- meth_obj.comment = mangle_comment(comment) + meth_obj.comment
665
- when %r{^\s*\#\s*define\s+#{meth_name}\s+(\w+)}m
666
- unless find_body($1, meth_obj, body, true)
667
- warn "No definition for #{meth_name}" unless quiet
668
- return false
669
- end
670
- else
671
-
672
- # No body, but might still have an override comment
673
- comment = find_override_comment(meth_obj.name)
674
-
675
- if comment
676
- find_modifiers(comment, meth_obj)
677
- meth_obj.comment = mangle_comment(comment)
678
- else
679
- warn "No definition for #{meth_name}" unless quiet
680
- return false
681
- end
682
- end
683
- true
684
- end
685
-
686
-
687
- ##
688
- # If the comment block contains a section that looks like:
689
- #
690
- # call-seq:
691
- # Array.new
692
- # Array.new(10)
693
- #
694
- # use it for the parameters.
695
-
696
- def find_modifiers(comment, meth_obj)
697
- if comment.sub!(/:nodoc:\s*^\s*\*?\s*$/m, '') or
698
- comment.sub!(/\A\/\*\s*:nodoc:\s*\*\/\Z/, '')
699
- meth_obj.document_self = false
700
- end
701
- if comment.sub!(/call-seq:(.*?)^\s*\*?\s*$/m, '') or
702
- comment.sub!(/\A\/\*\s*call-seq:(.*?)\*\/\Z/, '')
703
- seq = $1
704
- seq.gsub!(/^\s*\*\s*/, '')
705
- meth_obj.call_seq = seq
706
- end
707
- end
708
-
709
- ############################################################
710
-
711
- def find_override_comment(meth_name)
712
- name = Regexp.escape(meth_name)
713
- if @body =~ %r{Document-method:\s#{name}\s*?\n((?>.*?\*/))}m
714
- $1
715
- end
716
- end
717
-
718
- ##
719
- # Look for includes of the form:
720
- #
721
- # rb_include_module(rb_cArray, rb_mEnumerable);
722
-
723
- def do_includes
724
- @body.scan(/rb_include_module\s*\(\s*(\w+?),\s*(\w+?)\s*\)/) do |c,m|
725
- if cls = @classes[c]
726
- m = @known_classes[m] || m
727
- cls.add_include(Include.new(m, ""))
728
- end
729
- end
730
- end
731
-
732
- ##
733
- # Remove the /*'s and leading asterisks from C comments
734
-
735
- def mangle_comment(comment)
736
- comment.sub!(%r{/\*+}) { " " * $&.length }
737
- comment.sub!(%r{\*+/}) { " " * $&.length }
738
- comment.gsub!(/^[ \t]*\*/m) { " " * $&.length }
739
- comment
740
- end
741
-
742
- def find_class(raw_name, name)
743
- unless @classes[raw_name]
744
- if raw_name =~ /^rb_m/
745
- @classes[raw_name] = @top_level.add_module(NormalModule, name)
746
- else
747
- @classes[raw_name] = @top_level.add_class(NormalClass, name, nil)
748
- end
749
- end
750
- @classes[raw_name]
751
- end
752
-
753
- def handle_tab_width(body)
754
- if /\t/ =~ body
755
- tab_width = @options.tab_width
756
- body.split(/\n/).map do |line|
757
- 1 while line.gsub!(/\t+/) { ' ' * (tab_width*$&.length - $`.length % tab_width)} && $~ #`
758
- line
759
- end .join("\n")
760
- else
761
- body
762
- end
763
- end
764
-
765
- ##
766
- # Removes #ifdefs that would otherwise confuse us
767
-
768
- def handle_ifdefs_in(body)
769
- body.gsub(/^#ifdef HAVE_PROTOTYPES.*?#else.*?\n(.*?)#endif.*?\n/m, '\1')
770
- end
771
-
772
- end
773
-
774
- end
775
-