rdoc-f95 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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
+