rdoc-f95 0.0.1

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.
Files changed (71) hide show
  1. data/History.txt +4 -0
  2. data/Manifest.txt +79 -0
  3. data/PostInstall.txt +7 -0
  4. data/README.rdoc +147 -0
  5. data/Rakefile +28 -0
  6. data/bin/rdoc-f95 +70 -0
  7. data/lib/rdoc-f95.rb +306 -0
  8. data/lib/rdoc-f95/code_objects.rb +776 -0
  9. data/lib/rdoc-f95/diagram.rb +342 -0
  10. data/lib/rdoc-f95/dot.rb +249 -0
  11. data/lib/rdoc-f95/generator.rb +1088 -0
  12. data/lib/rdoc-f95/generator/chm.rb +113 -0
  13. data/lib/rdoc-f95/generator/chm/chm.rb +98 -0
  14. data/lib/rdoc-f95/generator/html.rb +370 -0
  15. data/lib/rdoc-f95/generator/html/hefss.rb +414 -0
  16. data/lib/rdoc-f95/generator/html/html.rb +708 -0
  17. data/lib/rdoc-f95/generator/html/kilmer.rb +418 -0
  18. data/lib/rdoc-f95/generator/html/one_page_html.rb +121 -0
  19. data/lib/rdoc-f95/generator/ri.rb +229 -0
  20. data/lib/rdoc-f95/generator/xhtml.rb +106 -0
  21. data/lib/rdoc-f95/generator/xhtml/ctop.xsl +1318 -0
  22. data/lib/rdoc-f95/generator/xhtml/mathml.xsl +42 -0
  23. data/lib/rdoc-f95/generator/xhtml/pmathml.xsl +612 -0
  24. data/lib/rdoc-f95/generator/xhtml/pmathmlcss.xsl +872 -0
  25. data/lib/rdoc-f95/generator/xhtml/xhtml.rb +732 -0
  26. data/lib/rdoc-f95/generator/xml.rb +120 -0
  27. data/lib/rdoc-f95/generator/xml/rdf.rb +113 -0
  28. data/lib/rdoc-f95/generator/xml/xml.rb +111 -0
  29. data/lib/rdoc-f95/install.rb +166 -0
  30. data/lib/rdoc-f95/markup.rb +506 -0
  31. data/lib/rdoc-f95/markup/formatter.rb +14 -0
  32. data/lib/rdoc-f95/markup/fragments.rb +337 -0
  33. data/lib/rdoc-f95/markup/inline.rb +361 -0
  34. data/lib/rdoc-f95/markup/install.rb +57 -0
  35. data/lib/rdoc-f95/markup/lines.rb +152 -0
  36. data/lib/rdoc-f95/markup/mathml_wrapper.rb +91 -0
  37. data/lib/rdoc-f95/markup/preprocess.rb +71 -0
  38. data/lib/rdoc-f95/markup/sample/rdoc2latex.rb +16 -0
  39. data/lib/rdoc-f95/markup/sample/sample.rb +42 -0
  40. data/lib/rdoc-f95/markup/to_flow.rb +185 -0
  41. data/lib/rdoc-f95/markup/to_html.rb +357 -0
  42. data/lib/rdoc-f95/markup/to_html_crossref.rb +123 -0
  43. data/lib/rdoc-f95/markup/to_latex.rb +328 -0
  44. data/lib/rdoc-f95/markup/to_test.rb +50 -0
  45. data/lib/rdoc-f95/markup/to_xhtml_texparser.rb +234 -0
  46. data/lib/rdoc-f95/options.rb +745 -0
  47. data/lib/rdoc-f95/parsers/parse_c.rb +775 -0
  48. data/lib/rdoc-f95/parsers/parse_f95.rb +2499 -0
  49. data/lib/rdoc-f95/parsers/parse_rb.rb +2587 -0
  50. data/lib/rdoc-f95/parsers/parse_simple.rb +39 -0
  51. data/lib/rdoc-f95/parsers/parserfactory.rb +99 -0
  52. data/lib/rdoc-f95/ri.rb +2 -0
  53. data/lib/rdoc-f95/ri/cache.rb +188 -0
  54. data/lib/rdoc-f95/ri/descriptions.rb +147 -0
  55. data/lib/rdoc-f95/ri/display.rb +244 -0
  56. data/lib/rdoc-f95/ri/driver.rb +435 -0
  57. data/lib/rdoc-f95/ri/formatter.rb +603 -0
  58. data/lib/rdoc-f95/ri/paths.rb +105 -0
  59. data/lib/rdoc-f95/ri/reader.rb +106 -0
  60. data/lib/rdoc-f95/ri/util.rb +81 -0
  61. data/lib/rdoc-f95/ri/writer.rb +64 -0
  62. data/lib/rdoc-f95/stats.rb +23 -0
  63. data/lib/rdoc-f95/template.rb +64 -0
  64. data/lib/rdoc-f95/tokenstream.rb +33 -0
  65. data/lib/rdoc-f95/usage.rb +210 -0
  66. data/script/console +10 -0
  67. data/script/destroy +14 -0
  68. data/script/generate +14 -0
  69. data/test/test_helper.rb +3 -0
  70. data/test/test_rdoc-f95.rb +11 -0
  71. metadata +156 -0
@@ -0,0 +1,244 @@
1
+ require 'rdoc-f95/ri'
2
+
3
+ ##
4
+ # This is a kind of 'flag' module. If you want to write your own 'ri' display
5
+ # module (perhaps because you'r writing an IDE or somesuch beast), you simply
6
+ # write a class which implements the various 'display' methods in
7
+ # 'DefaultDisplay', and include the 'RiDisplay' module in that class.
8
+ #
9
+ # To access your class from the command line, you can do
10
+ #
11
+ # ruby -r <your source file> ../ri ....
12
+
13
+ module RDocF95::RI::Display
14
+
15
+ @@display_class = nil
16
+
17
+ def self.append_features(display_class)
18
+ @@display_class = display_class
19
+ end
20
+
21
+ def self.new(*args)
22
+ @@display_class.new(*args)
23
+ end
24
+
25
+ end
26
+
27
+ ##
28
+ # A paging display module. Uses the RDocF95::RI::Formatter class to do the actual
29
+ # presentation.
30
+
31
+ class RDocF95::RI::DefaultDisplay
32
+
33
+ include RDocF95::RI::Display
34
+
35
+ def initialize(formatter, width, use_stdout)
36
+ @use_stdout = use_stdout
37
+ @formatter = formatter.new $stdout, width, " "
38
+ end
39
+
40
+ def display_method_info(method)
41
+ page do
42
+ @formatter.draw_line(method.full_name)
43
+ display_params(method)
44
+ @formatter.draw_line
45
+ display_flow(method.comment)
46
+ if method.aliases && !method.aliases.empty?
47
+ @formatter.blankline
48
+ aka = "(also known as "
49
+ aka << method.aliases.map {|a| a.name }.join(", ")
50
+ aka << ")"
51
+ @formatter.wrap(aka)
52
+ end
53
+ end
54
+ end
55
+
56
+ def display_class_info(klass, ri_reader)
57
+ page do
58
+ superclass = klass.superclass_string
59
+
60
+ if superclass
61
+ superclass = " < " + superclass
62
+ else
63
+ superclass = ""
64
+ end
65
+
66
+ @formatter.draw_line(klass.display_name + ": " +
67
+ klass.full_name + superclass)
68
+
69
+ display_flow(klass.comment)
70
+ @formatter.draw_line
71
+
72
+ unless klass.includes.empty?
73
+ @formatter.blankline
74
+ @formatter.display_heading("Includes:", 2, "")
75
+ incs = []
76
+ klass.includes.each do |inc|
77
+ inc_desc = ri_reader.find_class_by_name(inc.name)
78
+ if inc_desc
79
+ str = inc.name + "("
80
+ str << inc_desc.instance_methods.map{|m| m.name}.join(", ")
81
+ str << ")"
82
+ incs << str
83
+ else
84
+ incs << inc.name
85
+ end
86
+ end
87
+ @formatter.wrap(incs.sort.join(', '))
88
+ end
89
+
90
+ unless klass.constants.empty?
91
+ @formatter.blankline
92
+ @formatter.display_heading("Constants:", 2, "")
93
+ len = 0
94
+ klass.constants.each { |c| len = c.name.length if c.name.length > len }
95
+ len += 2
96
+ klass.constants.each do |c|
97
+ @formatter.wrap(c.value,
98
+ @formatter.indent+((c.name+":").ljust(len)))
99
+ end
100
+ end
101
+
102
+ unless klass.class_methods.empty?
103
+ @formatter.blankline
104
+ @formatter.display_heading("Class methods:", 2, "")
105
+ @formatter.wrap(klass.class_methods.map{|m| m.name}.sort.join(', '))
106
+ end
107
+
108
+ unless klass.class_method_extensions.empty?
109
+ @formatter.blankline
110
+ @formatter.display_heading("Class Method Extensions:", 2, "")
111
+ @formatter.wrap(klass.class_method_extensions.map{|m| m.name}.sort.join(', '))
112
+ end
113
+
114
+ unless klass.instance_methods.empty?
115
+ @formatter.blankline
116
+ @formatter.display_heading("Instance methods:", 2, "")
117
+ @formatter.wrap(klass.instance_methods.map{|m| m.name}.sort.join(', '))
118
+ end
119
+
120
+ unless klass.instance_method_extensions.empty?
121
+ @formatter.blankline
122
+ @formatter.display_heading("Instance Method Extensions:", 2, "")
123
+ @formatter.wrap(klass.instance_method_extensions.map{|m| m.name}.sort.join(', '))
124
+ end
125
+
126
+ unless klass.attributes.empty?
127
+ @formatter.blankline
128
+ @formatter.wrap("Attributes:", "")
129
+ @formatter.wrap(klass.attributes.map{|a| a.name}.sort.join(', '))
130
+ end
131
+ end
132
+ end
133
+
134
+ ##
135
+ # Display a list of method names
136
+
137
+ def display_method_list(methods)
138
+ page do
139
+ @formatter.raw_print_line("More than one method matched your request. You can refine")
140
+ @formatter.raw_print_line("your search by asking for information on one of:\n\n")
141
+ @formatter.wrap(methods.map {|m| m.full_name} .join(", "))
142
+ end
143
+ end
144
+
145
+ def display_class_list(namespaces)
146
+ page do
147
+ @formatter.raw_print_line("More than one class or module matched your request. You can refine")
148
+ @formatter.raw_print_line("your search by asking for information on one of:\n\n")
149
+ @formatter.wrap(namespaces.map {|m| m.full_name}.join(", "))
150
+ end
151
+ end
152
+
153
+ def list_known_classes(classes)
154
+ if classes.empty?
155
+ warn_no_database
156
+ else
157
+ page do
158
+ @formatter.draw_line("Known classes and modules")
159
+ @formatter.blankline
160
+ @formatter.wrap(classes.sort.join(", "))
161
+ end
162
+ end
163
+ end
164
+
165
+ def list_known_names(names)
166
+ if names.empty?
167
+ warn_no_database
168
+ else
169
+ page do
170
+ names.each {|n| @formatter.raw_print_line(n)}
171
+ end
172
+ end
173
+ end
174
+
175
+ private
176
+
177
+ def page
178
+ if pager = setup_pager then
179
+ begin
180
+ orig_output = @formatter.output
181
+ @formatter.output = pager
182
+ yield
183
+ ensure
184
+ @formatter.output = orig_output
185
+ pager.close
186
+ end
187
+ else
188
+ yield
189
+ end
190
+ rescue Errno::EPIPE
191
+ end
192
+
193
+ def setup_pager
194
+ unless @use_stdout then
195
+ for pager in [ ENV['PAGER'], "less", "more", 'pager' ].compact.uniq
196
+ return IO.popen(pager, "w") rescue nil
197
+ end
198
+ @use_stdout = true
199
+ nil
200
+ end
201
+ end
202
+
203
+ def display_params(method)
204
+ params = method.params
205
+
206
+ if params[0,1] == "("
207
+ if method.is_singleton
208
+ params = method.full_name + params
209
+ else
210
+ params = method.name + params
211
+ end
212
+ end
213
+ params.split(/\n/).each do |p|
214
+ @formatter.wrap(p)
215
+ @formatter.break_to_newline
216
+ end
217
+ if method.source_path then
218
+ @formatter.blankline
219
+ @formatter.wrap("Extension from #{method.source_path}")
220
+ end
221
+ end
222
+
223
+ def display_flow(flow)
224
+ if !flow || flow.empty?
225
+ @formatter.wrap("(no description...)")
226
+ else
227
+ @formatter.display_flow(flow)
228
+ end
229
+ end
230
+
231
+ def warn_no_database
232
+ puts "No ri data found"
233
+ puts
234
+ puts "If you've installed Ruby yourself, you need to generate documentation using:"
235
+ puts
236
+ puts " make install-doc"
237
+ puts
238
+ puts "from the same place you ran `make` to build ruby."
239
+ puts
240
+ puts "If you installed Ruby from a packaging system, then you may need to"
241
+ puts "install an additional package, or ask the packager to enable ri generation."
242
+ end
243
+ end
244
+
@@ -0,0 +1,435 @@
1
+ require 'optparse'
2
+ require 'yaml'
3
+
4
+ require 'rdoc-f95/ri'
5
+ require 'rdoc-f95/ri/paths'
6
+ require 'rdoc-f95/ri/formatter'
7
+ require 'rdoc-f95/ri/display'
8
+ require 'fileutils'
9
+ require 'rdoc-f95/markup'
10
+ require 'rdoc-f95/markup/to_flow'
11
+
12
+ class RDocF95::RI::Driver
13
+
14
+ def self.process_args(argv)
15
+ options = {}
16
+ options[:use_stdout] = !$stdout.tty?
17
+ options[:width] = 72
18
+ options[:formatter] = RDocF95::RI::Formatter.for 'plain'
19
+ options[:list_classes] = false
20
+ options[:list_names] = false
21
+
22
+ # By default all paths are used. If any of these are true, only those
23
+ # directories are used.
24
+ use_system = false
25
+ use_site = false
26
+ use_home = false
27
+ use_gems = false
28
+ doc_dirs = []
29
+
30
+ opts = OptionParser.new do |opt|
31
+ opt.program_name = File.basename $0
32
+ opt.version = RDocF95::VERSION
33
+ opt.summary_indent = ' ' * 4
34
+
35
+ directories = [
36
+ RDocF95::RI::Paths::SYSDIR,
37
+ RDocF95::RI::Paths::SITEDIR,
38
+ RDocF95::RI::Paths::HOMEDIR
39
+ ]
40
+
41
+ if RDocF95::RI::Paths::GEMDIRS then
42
+ Gem.path.each do |dir|
43
+ directories << "#{dir}/doc/*/ri"
44
+ end
45
+ end
46
+
47
+ opt.banner = <<-EOT
48
+ Usage: #{opt.program_name} [options] [names...]
49
+
50
+ Where name can be:
51
+
52
+ Class | Class::method | Class#method | Class.method | method
53
+
54
+ All class names may be abbreviated to their minimum unambiguous form. If a name
55
+ is ambiguous, all valid options will be listed.
56
+
57
+ The form '.' method matches either class or instance methods, while #method
58
+ matches only instance and ::method matches only class methods.
59
+
60
+ For example:
61
+
62
+ #{opt.program_name} Fil
63
+ #{opt.program_name} File
64
+ #{opt.program_name} File.new
65
+ #{opt.program_name} zip
66
+
67
+ Note that shell quoting may be required for method names containing
68
+ punctuation:
69
+
70
+ #{opt.program_name} 'Array.[]'
71
+ #{opt.program_name} compact\\!
72
+
73
+ By default ri searches for documentation in the following directories:
74
+
75
+ #{directories.join "\n "}
76
+
77
+ Specifying the --system, --site, --home, --gems or --doc-dir options will
78
+ limit ri to searching only the specified directories.
79
+
80
+ Options may also be set in the 'RI' environment variable.
81
+ EOT
82
+
83
+ opt.separator nil
84
+ opt.separator "Options:"
85
+ opt.separator nil
86
+
87
+ opt.on("--classes", "-c",
88
+ "Display the names of classes and modules we",
89
+ "know about.") do |value|
90
+ options[:list_classes] = value
91
+ end
92
+
93
+ opt.separator nil
94
+
95
+ opt.on("--doc-dir=DIRNAME", "-d", Array,
96
+ "List of directories to search for",
97
+ "documentation. If not specified, we search",
98
+ "the standard rdoc/ri directories. May be",
99
+ "repeated.") do |value|
100
+ value.each do |dir|
101
+ unless File.directory? dir then
102
+ raise OptionParser::InvalidArgument, "#{dir} is not a directory"
103
+ end
104
+ end
105
+
106
+ doc_dirs.concat value
107
+ end
108
+
109
+ opt.separator nil
110
+
111
+ opt.on("--fmt=FORMAT", "--format=FORMAT", "-f",
112
+ RDocF95::RI::Formatter::FORMATTERS.keys,
113
+ "Format to use when displaying output:",
114
+ " #{RDocF95::RI::Formatter.list}",
115
+ "Use 'bs' (backspace) with most pager",
116
+ "programs. To use ANSI, either disable the",
117
+ "pager or tell the pager to allow control",
118
+ "characters.") do |value|
119
+ options[:formatter] = RDocF95::RI::Formatter.for value
120
+ end
121
+
122
+ opt.separator nil
123
+
124
+ unless RDocF95::RI::Paths::GEMDIRS.empty? then
125
+ opt.on("--[no-]gems",
126
+ "Include documentation from RubyGems.") do |value|
127
+ use_gems = value
128
+ end
129
+ end
130
+
131
+ opt.separator nil
132
+
133
+ opt.on("--[no-]home",
134
+ "Include documentation stored in ~/.rdoc.") do |value|
135
+ use_home = value
136
+ end
137
+
138
+ opt.separator nil
139
+
140
+ opt.on("--[no-]list-names", "-l",
141
+ "List all the names known to RDoc, one per",
142
+ "line.") do |value|
143
+ options[:list_names] = value
144
+ end
145
+
146
+ opt.separator nil
147
+
148
+ opt.on("--no-pager", "-T",
149
+ "Send output directly to stdout.") do |value|
150
+ options[:use_stdout] = !value
151
+ end
152
+
153
+ opt.separator nil
154
+
155
+ opt.on("--[no-]site",
156
+ "Include documentation from libraries",
157
+ "installed in site_lib.") do |value|
158
+ use_site = value
159
+ end
160
+
161
+ opt.separator nil
162
+
163
+ opt.on("--[no-]system",
164
+ "Include documentation from Ruby's standard",
165
+ "library.") do |value|
166
+ use_system = value
167
+ end
168
+
169
+ opt.separator nil
170
+
171
+ opt.on("--width=WIDTH", "-w", OptionParser::DecimalInteger,
172
+ "Set the width of the output.") do |value|
173
+ options[:width] = value
174
+ end
175
+ end
176
+
177
+ argv = ENV['RI'].to_s.split.concat argv
178
+
179
+ opts.parse! argv
180
+
181
+ options[:names] = argv
182
+
183
+ options[:path] = RDocF95::RI::Paths.path(use_system, use_site, use_home,
184
+ use_gems, *doc_dirs)
185
+ options[:raw_path] = RDocF95::RI::Paths.raw_path(use_system, use_site,
186
+ use_home, use_gems, *doc_dirs)
187
+
188
+ options
189
+
190
+ rescue OptionParser::InvalidArgument, OptionParser::InvalidOption => e
191
+ puts opts
192
+ puts
193
+ puts e
194
+ exit 1
195
+ end
196
+
197
+ def self.run(argv = ARGV)
198
+ options = process_args argv
199
+ ri = new options
200
+ ri.run
201
+ end
202
+
203
+ def initialize(options)
204
+ @names = options[:names]
205
+
206
+ @class_cache_name = 'classes'
207
+ @all_dirs = RDocF95::RI::Paths.path(true, true, true, true)
208
+ @homepath = RDocF95::RI::Paths.raw_path(false, false, true, false).first
209
+ @homepath = @homepath.sub(/\.rdoc/, '.ri')
210
+ @sys_dirs = RDocF95::RI::Paths.raw_path(true, false, false, false)
211
+
212
+ FileUtils.mkdir_p cache_file_path unless File.directory? cache_file_path
213
+
214
+ @class_cache = nil
215
+
216
+ @display = RDocF95::RI::DefaultDisplay.new(options[:formatter],
217
+ options[:width],
218
+ options[:use_stdout])
219
+ end
220
+
221
+ def class_cache
222
+ return @class_cache if @class_cache
223
+
224
+ newest = map_dirs('created.rid', :all) do |f|
225
+ File.mtime f if test ?f, f
226
+ end.max
227
+
228
+ up_to_date = (File.exist?(class_cache_file_path) and
229
+ newest < File.mtime(class_cache_file_path))
230
+
231
+ @class_cache = if up_to_date then
232
+ load_cache_for @class_cache_name
233
+ else
234
+ class_cache = {}
235
+
236
+ classes = map_dirs('**/cdesc*.yaml', :sys) { |f| Dir[f] }
237
+ populate_class_cache class_cache, classes
238
+
239
+ classes = map_dirs('**/cdesc*.yaml') { |f| Dir[f] }
240
+ warn "Updating class cache with #{classes.size} classes..."
241
+
242
+ populate_class_cache class_cache, classes, true
243
+ write_cache class_cache, class_cache_file_path
244
+ end
245
+ end
246
+
247
+ def class_cache_file_path
248
+ File.join cache_file_path, @class_cache_name
249
+ end
250
+
251
+ def cache_file_for(klassname)
252
+ File.join cache_file_path, klassname.gsub(/:+/, "-")
253
+ end
254
+
255
+ def cache_file_path
256
+ File.join @homepath, 'cache'
257
+ end
258
+
259
+ def display_class(name)
260
+ klass = class_cache[name]
261
+ @display.display_class_info klass, class_cache
262
+ end
263
+
264
+ def load_cache_for(klassname)
265
+ path = cache_file_for klassname
266
+
267
+ if File.exist? path and
268
+ File.mtime(path) >= File.mtime(class_cache_file_path) then
269
+ File.open path, 'rb' do |fp|
270
+ Marshal.load fp.read
271
+ end
272
+ else
273
+ class_cache = nil
274
+
275
+ File.open class_cache_file_path, 'rb' do |fp|
276
+ class_cache = Marshal.load fp.read
277
+ end
278
+
279
+ klass = class_cache[klassname]
280
+ return nil unless klass
281
+
282
+ method_files = klass["sources"]
283
+ cache = {}
284
+
285
+ sys_dir = @sys_dirs.first
286
+ method_files.each do |f|
287
+ system_file = f.index(sys_dir) == 0
288
+ Dir[File.join(File.dirname(f), "*")].each do |yaml|
289
+ next unless yaml =~ /yaml$/
290
+ next if yaml =~ /cdesc-[^\/]+yaml$/
291
+ method = read_yaml yaml
292
+ name = method["full_name"]
293
+ ext_path = f
294
+ ext_path = "gem #{$1}" if f =~ %r%gems/[\d.]+/doc/([^/]+)%
295
+ method["source_path"] = ext_path unless system_file
296
+ cache[name] = method
297
+ end
298
+ end
299
+
300
+ write_cache cache, path
301
+ end
302
+ end
303
+
304
+ def map_dirs(file_name, system=false)
305
+ dirs = if system == :all then
306
+ @all_dirs
307
+ else
308
+ if system then
309
+ @sys_dirs
310
+ else
311
+ @all_dirs - @sys_dirs
312
+ end
313
+ end
314
+
315
+ dirs.map { |dir| yield File.join(dir, file_name) }.flatten.compact
316
+ end
317
+
318
+ def populate_class_cache(class_cache, classes, extension = false)
319
+ classes.each do |cdesc|
320
+ desc = read_yaml cdesc
321
+ klassname = desc["full_name"]
322
+
323
+ unless class_cache.has_key? klassname then
324
+ desc["display_name"] = "Class"
325
+ desc["sources"] = [cdesc]
326
+ desc["instance_method_extensions"] = []
327
+ desc["class_method_extensions"] = []
328
+ class_cache[klassname] = desc
329
+ else
330
+ klass = class_cache[klassname]
331
+
332
+ if extension then
333
+ desc["instance_method_extensions"] = desc.delete "instance_methods"
334
+ desc["class_method_extensions"] = desc.delete "class_methods"
335
+ end
336
+
337
+ klass.merge_enums desc
338
+ klass["sources"] << cdesc
339
+ end
340
+ end
341
+ end
342
+
343
+ def read_yaml(path)
344
+ YAML.load File.read(path).gsub(/ \!ruby\/(object|struct):(RDocF95::RI|RI|SM).*/, '')
345
+ end
346
+
347
+ def run
348
+ if @names.empty? then
349
+ @display.list_known_classes class_cache.keys.sort
350
+ else
351
+ @names.each do |name|
352
+ case name
353
+ when /::|\#|\./ then
354
+ if class_cache.key? name then
355
+ display_class name
356
+ else
357
+ meth = nil
358
+
359
+ parts = name.split(/::|\#|\./)
360
+ meth = parts.pop unless parts.last =~ /^[A-Z]/
361
+ klass = parts.join '::'
362
+
363
+ cache = load_cache_for klass
364
+ # HACK Does not support F.n
365
+ abort "Nothing known about #{name}" unless cache
366
+ method = cache[name.gsub(/\./, '#')]
367
+ abort "Nothing known about #{name}" unless method
368
+ @display.display_method_info method
369
+ end
370
+ else
371
+ if class_cache.key? name then
372
+ display_class name
373
+ else
374
+ methods = select_methods(/^#{name}/)
375
+ if methods.size == 0
376
+ abort "Nothing known about #{name}"
377
+ elsif methods.size == 1
378
+ @display.display_method_info methods.first
379
+ else
380
+ @display.display_method_list methods
381
+ end
382
+ end
383
+ end
384
+ end
385
+ end
386
+ end
387
+
388
+ def select_methods(pattern)
389
+ methods = []
390
+ class_cache.keys.sort.each do |klass|
391
+ class_cache[klass]["instance_methods"].map{|h|h["name"]}.grep(pattern) do |name|
392
+ method = load_cache_for(klass)[klass+'#'+name]
393
+ methods << method if method
394
+ end
395
+ class_cache[klass]["class_methods"].map{|h|h["name"]}.grep(pattern) do |name|
396
+ method = load_cache_for(klass)[klass+'::'+name]
397
+ methods << method if method
398
+ end
399
+ end
400
+ methods
401
+ end
402
+
403
+ def write_cache(cache, path)
404
+ File.open path, "wb" do |cache_file|
405
+ Marshal.dump cache, cache_file
406
+ end
407
+
408
+ cache
409
+ end
410
+
411
+ end
412
+
413
+ class Hash
414
+ def method_missing method, *args
415
+ self[method.to_s]
416
+ end
417
+
418
+ def merge_enums(other)
419
+ other.each do |k,v|
420
+ if self[k] then
421
+ case v
422
+ when Array then
423
+ self[k] += v
424
+ when Hash then
425
+ self[k].merge! v
426
+ else
427
+ # do nothing
428
+ end
429
+ else
430
+ self[k] = v
431
+ end
432
+ end
433
+ end
434
+ end
435
+