fastri 0.2.1.1 → 0.3.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.
- data/CHANGES +13 -0
- data/Rakefile +8 -2
- data/bin/fastri-server +2 -0
- data/bin/fri +78 -54
- data/bin/qri +336 -0
- data/bin/ri-emacs +16 -7
- data/lib/fastri/ri_index.rb +1 -1
- data/lib/fastri/ri_service.rb +24 -1
- data/lib/fastri/util.rb +69 -0
- data/lib/fastri/version.rb +2 -2
- data/pre-install.rb +5 -2
- data/test/test_ri_index.rb +24 -0
- data/test/test_util.rb +53 -0
- metadata +4 -2
data/CHANGES
CHANGED
@@ -1,6 +1,19 @@
|
|
1
1
|
|
2
2
|
User-visible changes in FastRI
|
3
3
|
|
4
|
+
Since version 0.2.1 (2006-11-23)
|
5
|
+
================================
|
6
|
+
Features
|
7
|
+
--------
|
8
|
+
* get all the information about a class/module and its methods with --extended
|
9
|
+
* new search methods: complete namespace (-Om), partial completion on both
|
10
|
+
namespace and method name (-Of), and case-indep. variants.
|
11
|
+
* --local (-L) and --remote (-L) (default) options. --local makes fri operate
|
12
|
+
in standalone mode, without requiring fastri-server.
|
13
|
+
* new executable: qri, equivalent to fri -L (local, standalone mode)
|
14
|
+
* try to second-guess the correct method type if all search methods fail
|
15
|
+
and the type was explicitly given
|
16
|
+
|
4
17
|
Since version 0.2.0 (2006-11-15)
|
5
18
|
================================
|
6
19
|
Features
|
data/Rakefile
CHANGED
@@ -29,7 +29,7 @@ require 'fastri/version'
|
|
29
29
|
|
30
30
|
PKG_REVISION = ".1"
|
31
31
|
PKG_FILES = FileList[
|
32
|
-
"bin/fri", "bin/fastri-server", "bin/ri-emacs",
|
32
|
+
"bin/fri", "bin/qri", "bin/fastri-server", "bin/ri-emacs",
|
33
33
|
"lib/**/*.rb", "CHANGES",
|
34
34
|
"COPYING", "LEGAL", "LICENSE", "Rakefile", "README.*", "test/*.rb",
|
35
35
|
"setup.rb", "pre-install.rb",
|
@@ -54,7 +54,7 @@ EOF
|
|
54
54
|
s.email = "mfp@acm.org"
|
55
55
|
s.homepage = "http://eigenclass.org/hiki.rb?fastri"
|
56
56
|
s.bindir = "bin"
|
57
|
-
s.executables = %w[fri fastri-server ri-emacs]
|
57
|
+
s.executables = %w[fri qri fastri-server ri-emacs]
|
58
58
|
s.has_rdoc = true
|
59
59
|
#s.extra_rdoc_files = %w[]
|
60
60
|
s.rdoc_options << "--title" << 'FastRI: better, faster ri'
|
@@ -93,4 +93,10 @@ Rake::GemPackageTask.new(Spec) do |p|
|
|
93
93
|
p.need_tar = true
|
94
94
|
end
|
95
95
|
|
96
|
+
file "bin/qri" => %w[bin/fri] do
|
97
|
+
cp "bin/fri", "bin/qri"
|
98
|
+
end
|
99
|
+
|
100
|
+
task :gem => ["bin/qri"]
|
101
|
+
|
96
102
|
# vim: set sw=2 ft=ruby:
|
data/bin/fastri-server
CHANGED
@@ -107,6 +107,8 @@ options = {:allowed_hosts => ["127.0.0.1"], :addr => "127.0.0.1",
|
|
107
107
|
:full_text_dir => File.join(home, ".fastri-fulltext"),
|
108
108
|
}
|
109
109
|
OptionParser.new do |opts|
|
110
|
+
opts.version = FastRI::FASTRI_VERSION
|
111
|
+
opts.release = FastRI::FASTRI_RELEASE_DATE
|
110
112
|
opts.banner = "Usage: fastri-server.rb [options]"
|
111
113
|
|
112
114
|
opts.on("-a", "--allow HOST", "Allow connections from HOST.",
|
data/bin/fri
CHANGED
@@ -7,6 +7,8 @@ require 'optparse'
|
|
7
7
|
require 'fastri/util'
|
8
8
|
require 'fastri/full_text_index'
|
9
9
|
|
10
|
+
default_local_mode = File.basename($0)[/^qri/] ? true : false
|
11
|
+
|
10
12
|
# we bind to 127.0.0.1 by default, because otherwise Ruby will try with
|
11
13
|
# 0.0.0.0, which results in a DNS request, adding way too much latency
|
12
14
|
options = {
|
@@ -34,11 +36,30 @@ options = {
|
|
34
36
|
:pager => nil,
|
35
37
|
:list_classes => nil,
|
36
38
|
:list_methods => nil,
|
39
|
+
:extended => false,
|
40
|
+
:index_file => File.join(FastRI::Util.find_home, ".fastri-index"),
|
41
|
+
:local_mode => default_local_mode,
|
37
42
|
}
|
43
|
+
|
38
44
|
override_addr_env = false
|
45
|
+
|
39
46
|
optparser = OptionParser.new do |opts|
|
40
|
-
opts.
|
47
|
+
opts.version = FastRI::FASTRI_VERSION
|
48
|
+
opts.release = FastRI::FASTRI_RELEASE_DATE
|
49
|
+
opts.banner = "Usage: #{File.basename($0)} [options] <query>"
|
41
50
|
|
51
|
+
opts.on("-L", "--local", "Try to use local index instead of DRb service.",
|
52
|
+
*[("(default)" if default_local_mode)].compact) do
|
53
|
+
options[:local_mode] = true
|
54
|
+
end
|
55
|
+
opts.on("--index-file=FILE", "Use index file (forces --local mode).",
|
56
|
+
"(default: #{options[:index_file]})") do |file|
|
57
|
+
options[:index_file] = file
|
58
|
+
options[:local_mode] = true
|
59
|
+
end
|
60
|
+
opts.on("-R", "--remote", "Use DRb service. #{'(default)' unless default_local_mode}") do
|
61
|
+
options[:local_mode] = false
|
62
|
+
end
|
42
63
|
opts.on("-s", "--bind ADDR", "Bind to ADDR for incoming DRb connections.",
|
43
64
|
"(default: 127.0.0.1)") do |addr|
|
44
65
|
options[:addr] = addr
|
@@ -49,15 +70,24 @@ optparser = OptionParser.new do |opts|
|
|
49
70
|
'e' => :exact, 'E' => :exact_ci, 'n' => :nested, 'N' => :nested_ci,
|
50
71
|
'p' => :partial, 'P' => :partial_ci, 'x' => :nested_partial,
|
51
72
|
'X' => :nested_partial_ci, 'a' => :anywhere, 'A' => :anywhere_ci,
|
73
|
+
'm' => :namespace_partial, 'M' => :namespace_partial_ci,
|
74
|
+
'f' => :full_partial, 'F' => :full_partial_ci,
|
52
75
|
}
|
53
76
|
opts.on("-O", "--order ORDER", "Specify lookup order.",
|
54
77
|
"(default: eEnNpPxX)", "Uppercase: case-indep.",
|
55
78
|
"e:exact n:nested p:partial (completion)",
|
56
|
-
"x:nested and partial",
|
79
|
+
"x:nested and partial m:complete namespace",
|
80
|
+
"f:complete both class and method",
|
57
81
|
"a:match method name anywhere") do |order|
|
58
82
|
options[:lookup_order] = order.split(//).map{|x| order_mapping[x]}.compact
|
59
83
|
end
|
60
84
|
|
85
|
+
opts.on("-e", "--extended", "Show all methods for given namespace.") do
|
86
|
+
options[:extended] = true
|
87
|
+
options[:use_pager] = true
|
88
|
+
options[:format] = "plain"
|
89
|
+
end
|
90
|
+
|
61
91
|
opts.on("--show-matches", "Only show matching entries."){ options[:show_matches] = true }
|
62
92
|
|
63
93
|
opts.on("--classes", "List all known classes/modules.") do
|
@@ -124,39 +154,7 @@ if !options[:list_classes] && !options[:list_methods] && ARGV.empty?
|
|
124
154
|
end
|
125
155
|
|
126
156
|
# {{{ try to find where the method comes from exactly
|
127
|
-
|
128
|
-
unless m.inspect =~ %r[\A#<(?:Unbound)?Method: (.*?)>\Z]
|
129
|
-
raise "Cannot parse result of #{m.class}#inspect: #{m.inspect}"
|
130
|
-
end
|
131
|
-
$1.sub(/\A.*?\((.*?)\)(.*)\Z/){ "#{$1}#{$2}" }.sub(/\./, "::").sub(/#<Class:(.*?)>#/) { "#{$1}::" }
|
132
|
-
end
|
133
|
-
|
134
|
-
def magic_help(query)
|
135
|
-
if query =~ /\A(.*?)(#|::|\.)(.*)\Z/
|
136
|
-
c, k, m = $1, $2, $3
|
137
|
-
begin
|
138
|
-
c = Object.const_get(c)
|
139
|
-
m = case k
|
140
|
-
when "#"
|
141
|
-
c.instance_method(m)
|
142
|
-
when "::"
|
143
|
-
c.method(m)
|
144
|
-
when "."
|
145
|
-
begin
|
146
|
-
c.method(m)
|
147
|
-
rescue NameError
|
148
|
-
c.instance_method(m)
|
149
|
-
end
|
150
|
-
end
|
151
|
-
help_method_extract(m)
|
152
|
-
rescue Exception
|
153
|
-
query
|
154
|
-
end
|
155
|
-
else
|
156
|
-
query
|
157
|
-
end
|
158
|
-
end
|
159
|
-
|
157
|
+
include FastRI::Util::MagicHelp
|
160
158
|
|
161
159
|
MAX_CONTEXT_LINES = 20
|
162
160
|
def context_wrap(text, width)
|
@@ -255,26 +253,40 @@ end
|
|
255
253
|
perform_fulltext_search(options) if options[:do_full_text]
|
256
254
|
|
257
255
|
#{{{ normal query
|
258
|
-
|
256
|
+
if options[:local_mode]
|
257
|
+
require 'fastri/ri_service'
|
258
|
+
ri_reader = open(options[:index_file], "rb"){|io| Marshal.load io } rescue nil
|
259
|
+
unless ri_reader
|
260
|
+
puts <<EOF
|
261
|
+
Couldn't open the index:
|
262
|
+
#{options[:index_file]}
|
259
263
|
|
264
|
+
The index needs to be rebuilt with
|
265
|
+
fastri-server -b
|
266
|
+
EOF
|
267
|
+
exit(-1)
|
268
|
+
end
|
269
|
+
service = FastRI::RiService.new(ri_reader)
|
270
|
+
else # remote
|
271
|
+
require 'rinda/ring'
|
260
272
|
|
261
|
-
#{{{ determine the address to bind to
|
262
|
-
if override_addr_env
|
263
|
-
|
264
|
-
else
|
265
|
-
|
266
|
-
end
|
273
|
+
#{{{ determine the address to bind to
|
274
|
+
if override_addr_env
|
275
|
+
addr_spec = options[:addr]
|
276
|
+
else
|
277
|
+
addr_spec = ENV["FASTRI_ADDR"] || options[:addr]
|
278
|
+
end
|
267
279
|
|
268
|
-
ip = addr_spec[/^[^:]+/] || "127.0.0.1"
|
269
|
-
port = addr_spec[/:(\d+)/, 1] || 0
|
270
|
-
addr = "druby://#{ip}:#{port}"
|
280
|
+
ip = addr_spec[/^[^:]+/] || "127.0.0.1"
|
281
|
+
port = addr_spec[/:(\d+)/, 1] || 0
|
282
|
+
addr = "druby://#{ip}:#{port}"
|
271
283
|
|
272
|
-
#{{{ start DRb and perform request
|
273
|
-
begin
|
274
|
-
|
275
|
-
|
276
|
-
rescue Exception
|
277
|
-
|
284
|
+
#{{{ start DRb and perform request
|
285
|
+
begin
|
286
|
+
DRb.start_service(addr)
|
287
|
+
ring_server = Rinda::RingFinger.primary
|
288
|
+
rescue Exception
|
289
|
+
$stderr.puts <<EOF
|
278
290
|
Couldn't initialize DRb and locate the Ring server.
|
279
291
|
|
280
292
|
Please make sure that:
|
@@ -285,13 +297,17 @@ Please make sure that:
|
|
285
297
|
export FASTRI_ADDR="192.168.1.12"
|
286
298
|
fri Array
|
287
299
|
EOF
|
288
|
-
|
300
|
+
exit(-1)
|
301
|
+
end
|
302
|
+
service = ring_server.read([:name, :FastRI, nil, nil])[2]
|
289
303
|
end
|
290
|
-
|
304
|
+
|
305
|
+
|
291
306
|
info_options = {
|
292
307
|
:formatter => options[:format],
|
293
308
|
:width => options[:width],
|
294
309
|
:lookup_order => options[:lookup_order],
|
310
|
+
:extended => options[:extended],
|
295
311
|
}
|
296
312
|
|
297
313
|
# {{{ list classes or methods
|
@@ -306,7 +322,15 @@ ARGV.each do |term|
|
|
306
322
|
if options[:show_matches]
|
307
323
|
puts service.matches(help_query, info_options).sort
|
308
324
|
else
|
309
|
-
|
325
|
+
result = service.info(help_query, info_options)
|
326
|
+
# second-guess the correct method type only as the last resort.
|
327
|
+
if result
|
328
|
+
puts result
|
329
|
+
elsif (new_query = FastRI::Util.change_query_method_type(help_query)) != help_query
|
330
|
+
puts service.info(new_query)
|
331
|
+
else
|
332
|
+
puts nil
|
333
|
+
end
|
310
334
|
end
|
311
335
|
end
|
312
336
|
# vi: set sw=2 expandtab:
|
data/bin/qri
ADDED
@@ -0,0 +1,336 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# fri: access RI documentation through DRb
|
3
|
+
# Copyright (C) 2006 Mauricio Fernandez <mfp@acm.org>
|
4
|
+
#
|
5
|
+
|
6
|
+
require 'optparse'
|
7
|
+
require 'fastri/util'
|
8
|
+
require 'fastri/full_text_index'
|
9
|
+
|
10
|
+
default_local_mode = File.basename($0)[/^qri/] ? true : false
|
11
|
+
|
12
|
+
# we bind to 127.0.0.1 by default, because otherwise Ruby will try with
|
13
|
+
# 0.0.0.0, which results in a DNS request, adding way too much latency
|
14
|
+
options = {
|
15
|
+
:addr => "127.0.0.1",
|
16
|
+
:format =>
|
17
|
+
case RUBY_PLATFORM
|
18
|
+
when /win/
|
19
|
+
if /darwin|cygwin/ =~ RUBY_PLATFORM
|
20
|
+
"ansi"
|
21
|
+
else
|
22
|
+
"plain"
|
23
|
+
end
|
24
|
+
else
|
25
|
+
"ansi"
|
26
|
+
end,
|
27
|
+
:width => 72,
|
28
|
+
:lookup_order => [
|
29
|
+
:exact, :exact_ci, :nested, :nested_ci, :partial, :partial_ci,
|
30
|
+
:nested_partial, :nested_partial_ci,
|
31
|
+
],
|
32
|
+
:show_matches => false,
|
33
|
+
:do_full_text => false,
|
34
|
+
:full_text_dir => File.join(FastRI::Util.find_home, ".fastri-fulltext"),
|
35
|
+
:use_pager => nil,
|
36
|
+
:pager => nil,
|
37
|
+
:list_classes => nil,
|
38
|
+
:list_methods => nil,
|
39
|
+
:extended => false,
|
40
|
+
:index_file => File.join(FastRI::Util.find_home, ".fastri-index"),
|
41
|
+
:local_mode => default_local_mode,
|
42
|
+
}
|
43
|
+
|
44
|
+
override_addr_env = false
|
45
|
+
|
46
|
+
optparser = OptionParser.new do |opts|
|
47
|
+
opts.version = FastRI::FASTRI_VERSION
|
48
|
+
opts.release = FastRI::FASTRI_RELEASE_DATE
|
49
|
+
opts.banner = "Usage: #{File.basename($0)} [options] <query>"
|
50
|
+
|
51
|
+
opts.on("-L", "--local", "Try to use local index instead of DRb service.",
|
52
|
+
*[("(default)" if default_local_mode)].compact) do
|
53
|
+
options[:local_mode] = true
|
54
|
+
end
|
55
|
+
opts.on("--index-file=FILE", "Use index file (forces --local mode).",
|
56
|
+
"(default: #{options[:index_file]})") do |file|
|
57
|
+
options[:index_file] = file
|
58
|
+
options[:local_mode] = true
|
59
|
+
end
|
60
|
+
opts.on("-R", "--remote", "Use DRb service. #{'(default)' unless default_local_mode}") do
|
61
|
+
options[:local_mode] = false
|
62
|
+
end
|
63
|
+
opts.on("-s", "--bind ADDR", "Bind to ADDR for incoming DRb connections.",
|
64
|
+
"(default: 127.0.0.1)") do |addr|
|
65
|
+
options[:addr] = addr
|
66
|
+
override_addr_env = true
|
67
|
+
end
|
68
|
+
|
69
|
+
order_mapping = {
|
70
|
+
'e' => :exact, 'E' => :exact_ci, 'n' => :nested, 'N' => :nested_ci,
|
71
|
+
'p' => :partial, 'P' => :partial_ci, 'x' => :nested_partial,
|
72
|
+
'X' => :nested_partial_ci, 'a' => :anywhere, 'A' => :anywhere_ci,
|
73
|
+
'm' => :namespace_partial, 'M' => :namespace_partial_ci,
|
74
|
+
'f' => :full_partial, 'F' => :full_partial_ci,
|
75
|
+
}
|
76
|
+
opts.on("-O", "--order ORDER", "Specify lookup order.",
|
77
|
+
"(default: eEnNpPxX)", "Uppercase: case-indep.",
|
78
|
+
"e:exact n:nested p:partial (completion)",
|
79
|
+
"x:nested and partial m:complete namespace",
|
80
|
+
"f:complete both class and method",
|
81
|
+
"a:match method name anywhere") do |order|
|
82
|
+
options[:lookup_order] = order.split(//).map{|x| order_mapping[x]}.compact
|
83
|
+
end
|
84
|
+
|
85
|
+
opts.on("-e", "--extended", "Show all methods for given namespace.") do
|
86
|
+
options[:extended] = true
|
87
|
+
options[:use_pager] = true
|
88
|
+
options[:format] = "plain"
|
89
|
+
end
|
90
|
+
|
91
|
+
opts.on("--show-matches", "Only show matching entries."){ options[:show_matches] = true }
|
92
|
+
|
93
|
+
opts.on("--classes", "List all known classes/modules.") do
|
94
|
+
options[:use_pager] = true
|
95
|
+
options[:list_classes] = true
|
96
|
+
end
|
97
|
+
opts.on("--methods", "List all known methods.") do
|
98
|
+
options[:use_pager] = true
|
99
|
+
options[:list_methods] = true
|
100
|
+
end
|
101
|
+
opts.on("-l", "--list-names", "List all known namespaces/methods.") do
|
102
|
+
options[:use_pager] = true
|
103
|
+
options[:list_classes] = true
|
104
|
+
options[:list_methods] = true
|
105
|
+
end
|
106
|
+
|
107
|
+
opts.on("-S", "--full-text", "Perform full-text search.") do
|
108
|
+
options[:do_full_text] = true
|
109
|
+
options[:use_pager] = true if options[:use_pager].nil?
|
110
|
+
options[:format] = "plain"
|
111
|
+
end
|
112
|
+
|
113
|
+
opts.on("-F", "--full-text-dir DIR", "Use full-text index in DIR",
|
114
|
+
"(default: #{options[:full_text_dir]})") do |dir|
|
115
|
+
options[:full_text_dir] = dir if dir
|
116
|
+
options[:do_full_text] = true
|
117
|
+
options[:use_pager] = true
|
118
|
+
options[:format] = "plain"
|
119
|
+
end
|
120
|
+
|
121
|
+
opts.on("-f", "--format FMT", "Format to use when displaying output:",
|
122
|
+
" ansi, plain (default: #{options[:format]})") do |format|
|
123
|
+
options[:format] = format
|
124
|
+
end
|
125
|
+
|
126
|
+
opts.on("-P", "--[no-]pager", "Use pager.", "(default: don't)") do |usepager|
|
127
|
+
options[:use_pager] = usepager
|
128
|
+
options[:format] = "plain" if usepager
|
129
|
+
end
|
130
|
+
|
131
|
+
opts.on("-T", "Don't use a pager."){ options[:use_pager] = false }
|
132
|
+
|
133
|
+
opts.on("--pager-cmd PAGER", "Use pager PAGER.", "(default: don't)") do |pager|
|
134
|
+
options[:pager] = pager
|
135
|
+
options[:use_pager] = true
|
136
|
+
options[:format] = "plain"
|
137
|
+
end
|
138
|
+
|
139
|
+
opts.on("-w", "--width WIDTH", "Set the width of the output.") do |width|
|
140
|
+
w = width.to_i
|
141
|
+
options[:width] = w > 0 ? w : options[:width]
|
142
|
+
end
|
143
|
+
|
144
|
+
opts.on("-h", "--help", "Show this help message") do
|
145
|
+
puts opts
|
146
|
+
exit
|
147
|
+
end
|
148
|
+
end
|
149
|
+
optparser.parse!
|
150
|
+
|
151
|
+
if !options[:list_classes] && !options[:list_methods] && ARGV.empty?
|
152
|
+
puts optparser
|
153
|
+
exit
|
154
|
+
end
|
155
|
+
|
156
|
+
# {{{ try to find where the method comes from exactly
|
157
|
+
include FastRI::Util::MagicHelp
|
158
|
+
|
159
|
+
MAX_CONTEXT_LINES = 20
|
160
|
+
def context_wrap(text, width)
|
161
|
+
"... " +
|
162
|
+
text.gsub(/(.{1,#{width-4}})( +|$\n?)|(.{1,#{width-4}})/, "\\1\\3\n").chomp
|
163
|
+
end
|
164
|
+
|
165
|
+
def display_fulltext_search_results(results, gem_dir_info = FastRI::Util.gem_directories_unique,
|
166
|
+
width = 78)
|
167
|
+
return if results.empty?
|
168
|
+
path = File.expand_path(results[0].path)
|
169
|
+
gem_name, version, gem_path = FastRI::Util.gem_info_for_path(path, gem_dir_info)
|
170
|
+
if gem_name
|
171
|
+
rel_path = path[/#{Regexp.escape(gem_path)}\/(.*)/, 1]
|
172
|
+
if rel_path
|
173
|
+
entry_name = FastRI::Util.gem_relpath_to_full_name(rel_path)
|
174
|
+
end
|
175
|
+
puts "Found in #{gem_name} #{version} #{entry_name}"
|
176
|
+
else
|
177
|
+
rdoc_system_path = File.expand_path(RI::Paths::SYSDIR)
|
178
|
+
if path.index(rdoc_system_path)
|
179
|
+
rel_path = path[/#{Regexp.escape(rdoc_system_path)}\/(.*)/, 1]
|
180
|
+
puts "Found in system #{FastRI::Util.gem_relpath_to_full_name(rel_path)}"
|
181
|
+
else
|
182
|
+
puts "Found in #{path}:"
|
183
|
+
end
|
184
|
+
end
|
185
|
+
text = results.map do |result|
|
186
|
+
context = result.context(120)
|
187
|
+
from = (context.rindex("\n", context.index(result.query)) || -1) + 1
|
188
|
+
to = (context.index("\n", context.index(result.query)) || 0) - 1
|
189
|
+
context_wrap(context[from..to], width)
|
190
|
+
end
|
191
|
+
puts
|
192
|
+
puts text.uniq[0...MAX_CONTEXT_LINES]
|
193
|
+
puts
|
194
|
+
end
|
195
|
+
|
196
|
+
def perform_fulltext_search(options)
|
197
|
+
fulltext = File.join(options[:full_text_dir], "full_text.dat")
|
198
|
+
suffixes = File.join(options[:full_text_dir], "suffixes.dat")
|
199
|
+
begin
|
200
|
+
index = FastRI::FullTextIndex.new_from_filenames(fulltext, suffixes)
|
201
|
+
rescue Exception
|
202
|
+
puts <<EOF
|
203
|
+
Couldn't open the full-text index:
|
204
|
+
#{fulltext}
|
205
|
+
#{suffixes}
|
206
|
+
|
207
|
+
The index needs to be rebuilt with
|
208
|
+
fastri-server -B
|
209
|
+
EOF
|
210
|
+
exit(-1)
|
211
|
+
end
|
212
|
+
gem_dir_info = FastRI::Util.gem_directories_unique
|
213
|
+
match_sets = ARGV.map do |query|
|
214
|
+
result = index.lookup(query)
|
215
|
+
if result
|
216
|
+
index.next_matches(result) + [result]
|
217
|
+
else
|
218
|
+
[]
|
219
|
+
end
|
220
|
+
end
|
221
|
+
path_map = Hash.new{|h,k| h[k] = []}
|
222
|
+
match_sets.each{|matches| matches.each{|m| path_map[m.path] << m} }
|
223
|
+
paths = match_sets[1..-1].inject(match_sets[0].map{|x| x.path}.uniq) do |s,x|
|
224
|
+
s & x.map{|y| y.path}.uniq
|
225
|
+
end
|
226
|
+
if paths.empty?
|
227
|
+
puts "nil"
|
228
|
+
else
|
229
|
+
puts "#{paths.size} hits"
|
230
|
+
paths.sort_by{|path| 1.0 * -path_map[path].size / path_map[path].first.metadata[:size] ** 0.5}.map do |path|
|
231
|
+
puts "=" * options[:width]
|
232
|
+
puts 1.0 * path_map[path].size / path_map[path].first.metadata[:size] ** 0.5
|
233
|
+
display_fulltext_search_results(path_map[path], gem_dir_info, options[:width])
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
237
|
+
exit 0
|
238
|
+
end
|
239
|
+
|
240
|
+
#{{{ set up pager
|
241
|
+
if options[:use_pager]
|
242
|
+
[options[:pager], ENV["PAGER"], "less", "more", "pager"].compact.uniq.each do |pager|
|
243
|
+
begin
|
244
|
+
$stdout = IO.popen(pager, "w")
|
245
|
+
at_exit{ $stdout.close }
|
246
|
+
break
|
247
|
+
rescue Exception
|
248
|
+
end
|
249
|
+
end
|
250
|
+
end
|
251
|
+
|
252
|
+
#{{{ perform full text search if asked to
|
253
|
+
perform_fulltext_search(options) if options[:do_full_text]
|
254
|
+
|
255
|
+
#{{{ normal query
|
256
|
+
if options[:local_mode]
|
257
|
+
require 'fastri/ri_service'
|
258
|
+
ri_reader = open(options[:index_file], "rb"){|io| Marshal.load io } rescue nil
|
259
|
+
unless ri_reader
|
260
|
+
puts <<EOF
|
261
|
+
Couldn't open the index:
|
262
|
+
#{options[:index_file]}
|
263
|
+
|
264
|
+
The index needs to be rebuilt with
|
265
|
+
fastri-server -b
|
266
|
+
EOF
|
267
|
+
exit(-1)
|
268
|
+
end
|
269
|
+
service = FastRI::RiService.new(ri_reader)
|
270
|
+
else # remote
|
271
|
+
require 'rinda/ring'
|
272
|
+
|
273
|
+
#{{{ determine the address to bind to
|
274
|
+
if override_addr_env
|
275
|
+
addr_spec = options[:addr]
|
276
|
+
else
|
277
|
+
addr_spec = ENV["FASTRI_ADDR"] || options[:addr]
|
278
|
+
end
|
279
|
+
|
280
|
+
ip = addr_spec[/^[^:]+/] || "127.0.0.1"
|
281
|
+
port = addr_spec[/:(\d+)/, 1] || 0
|
282
|
+
addr = "druby://#{ip}:#{port}"
|
283
|
+
|
284
|
+
#{{{ start DRb and perform request
|
285
|
+
begin
|
286
|
+
DRb.start_service(addr)
|
287
|
+
ring_server = Rinda::RingFinger.primary
|
288
|
+
rescue Exception
|
289
|
+
$stderr.puts <<EOF
|
290
|
+
Couldn't initialize DRb and locate the Ring server.
|
291
|
+
|
292
|
+
Please make sure that:
|
293
|
+
* the fastri-server is running, the server is bound to the correct interface,
|
294
|
+
and the ACL setup allows connections from this host
|
295
|
+
* fri is using the correct interface for incoming DRb requests:
|
296
|
+
either set the FASTRI_ADDR environment variable, or use --bind ADDR, e.g
|
297
|
+
export FASTRI_ADDR="192.168.1.12"
|
298
|
+
fri Array
|
299
|
+
EOF
|
300
|
+
exit(-1)
|
301
|
+
end
|
302
|
+
service = ring_server.read([:name, :FastRI, nil, nil])[2]
|
303
|
+
end
|
304
|
+
|
305
|
+
|
306
|
+
info_options = {
|
307
|
+
:formatter => options[:format],
|
308
|
+
:width => options[:width],
|
309
|
+
:lookup_order => options[:lookup_order],
|
310
|
+
:extended => options[:extended],
|
311
|
+
}
|
312
|
+
|
313
|
+
# {{{ list classes or methods
|
314
|
+
puts service.all_classes if options[:list_classes]
|
315
|
+
puts service.all_methods if options[:list_methods]
|
316
|
+
exit if options[:list_classes] || options[:list_methods]
|
317
|
+
|
318
|
+
# {{{ normal query
|
319
|
+
|
320
|
+
ARGV.each do |term|
|
321
|
+
help_query = magic_help(term)
|
322
|
+
if options[:show_matches]
|
323
|
+
puts service.matches(help_query, info_options).sort
|
324
|
+
else
|
325
|
+
result = service.info(help_query, info_options)
|
326
|
+
# second-guess the correct method type only as the last resort.
|
327
|
+
if result
|
328
|
+
puts result
|
329
|
+
elsif (new_query = FastRI::Util.change_query_method_type(help_query)) != help_query
|
330
|
+
puts service.info(new_query)
|
331
|
+
else
|
332
|
+
puts nil
|
333
|
+
end
|
334
|
+
end
|
335
|
+
end
|
336
|
+
# vi: set sw=2 expandtab:
|
data/bin/ri-emacs
CHANGED
@@ -24,6 +24,7 @@
|
|
24
24
|
|
25
25
|
require 'rinda/ring'
|
26
26
|
require 'optparse'
|
27
|
+
require 'fastri/util'
|
27
28
|
|
28
29
|
# {{{ cmdline parsing and service discovery
|
29
30
|
# we bind to 127.0.0.1 by default, because otherwise Ruby will try with
|
@@ -67,11 +68,13 @@ Please make sure that:
|
|
67
68
|
export FASTRI_ADDR="192.168.1.12"
|
68
69
|
fri Array
|
69
70
|
EOF
|
70
|
-
exit(-1)
|
71
|
+
exit(-1) # '
|
71
72
|
end
|
72
73
|
service = ring_server.read([:name, :FastRI, nil, nil])[2]
|
73
74
|
|
74
75
|
class EventLoop
|
76
|
+
include FastRI::Util::MagicHelp
|
77
|
+
|
75
78
|
def initialize(ri)
|
76
79
|
@ri = ri
|
77
80
|
end
|
@@ -167,16 +170,22 @@ class EventLoop
|
|
167
170
|
end
|
168
171
|
end
|
169
172
|
|
170
|
-
def
|
171
|
-
data = @ri.
|
172
|
-
|
173
|
+
def display_(what, keyw)
|
174
|
+
data = @ri.__send__(what, magic_help(keyw))
|
175
|
+
if data
|
176
|
+
puts data
|
177
|
+
elsif (new_keyw = FastRI::Util.change_query_method_type(keyw)) != keyw
|
178
|
+
puts @ri.__send__(what, new_keyw)
|
179
|
+
end
|
173
180
|
puts "RI_EMACS_END_OF_INFO"
|
174
181
|
end
|
175
182
|
|
183
|
+
def display_args(keyw)
|
184
|
+
display_ :args, keyw
|
185
|
+
end
|
186
|
+
|
176
187
|
def display_info(keyw)
|
177
|
-
|
178
|
-
puts data if data
|
179
|
-
puts "RI_EMACS_END_OF_INFO"
|
188
|
+
display_ :info, keyw
|
180
189
|
end
|
181
190
|
end
|
182
191
|
|
data/lib/fastri/ri_index.rb
CHANGED
@@ -534,7 +534,7 @@ class RiIndex
|
|
534
534
|
if prefix.empty?
|
535
535
|
[//, /^[#.] /] # the second should never match
|
536
536
|
else
|
537
|
-
[/^#{Regexp.escape(prefix)}/, /^#{Regexp.escape(prefix)}([#.])\S+ / ]
|
537
|
+
[/^#{Regexp.escape(prefix)}([#.]|::)/, /^#{Regexp.escape(prefix)}([#.])\S+ / ]
|
538
538
|
end
|
539
539
|
end
|
540
540
|
|
data/lib/fastri/ri_service.rb
CHANGED
@@ -180,6 +180,7 @@ class RiService
|
|
180
180
|
DEFAULT_INFO_OPTIONS = {
|
181
181
|
:formatter => :ansi,
|
182
182
|
:width => 72,
|
183
|
+
:extended => false,
|
183
184
|
}
|
184
185
|
|
185
186
|
def matches(keyword, options = {})
|
@@ -205,6 +206,12 @@ class RiService
|
|
205
206
|
when :namespace
|
206
207
|
capture_stdout(display(options)) do |display|
|
207
208
|
display.display_class_info(@ri_reader.get_class(entries[0]), @ri_reader)
|
209
|
+
if options[:extended]
|
210
|
+
methods = @ri_reader.methods_under(entries[0], true)
|
211
|
+
methods.each do |meth_entry|
|
212
|
+
display.display_method_info(@ri_reader.get_method(meth_entry))
|
213
|
+
end
|
214
|
+
end
|
208
215
|
end
|
209
216
|
when :method
|
210
217
|
capture_stdout(display(options)) do |display|
|
@@ -269,6 +276,7 @@ class RiService
|
|
269
276
|
private
|
270
277
|
|
271
278
|
def obtain_unqualified_method_entries(name, separators, order)
|
279
|
+
name = Regexp.escape(name)
|
272
280
|
sep_re = "(" + separators.map{|x| Regexp.escape(x)}.join("|") + ")"
|
273
281
|
matcher = MatchFinder.new do |m|
|
274
282
|
m.add_matcher(:exact) do
|
@@ -294,6 +302,8 @@ class RiService
|
|
294
302
|
end
|
295
303
|
|
296
304
|
def obtain_qualified_method_entries(namespace, method, separators, order)
|
305
|
+
namespace, unescaped_namespace = Regexp.escape(namespace), namespace
|
306
|
+
method = Regexp.escape(method)
|
297
307
|
matcher = MatchFinder.new do |m|
|
298
308
|
m.add_matcher(:exact) do
|
299
309
|
separators.each do |sep|
|
@@ -311,7 +321,7 @@ class RiService
|
|
311
321
|
m.yield @ri_reader.methods_under_matching("", /::#{namespace}#{sep_re}#{method}$/i, true)
|
312
322
|
end
|
313
323
|
m.add_matcher(:partial) do
|
314
|
-
m.yield @ri_reader.methods_under_matching(
|
324
|
+
m.yield @ri_reader.methods_under_matching(unescaped_namespace, /#{sep_re}#{method}/, false)
|
315
325
|
end
|
316
326
|
m.add_matcher(:partial_ci) do
|
317
327
|
m.yield @ri_reader.methods_under_matching("", /^#{namespace}#{sep_re}#{method}/i, true)
|
@@ -322,11 +332,24 @@ class RiService
|
|
322
332
|
m.add_matcher(:nested_partial_ci) do
|
323
333
|
m.yield @ri_reader.methods_under_matching("", /::#{namespace}#{sep_re}#{method}/i, true)
|
324
334
|
end
|
335
|
+
m.add_matcher(:namespace_partial) do
|
336
|
+
m.yield @ri_reader.methods_under_matching("", /^#{namespace}[^:]*#{sep_re}#{method}$/, true)
|
337
|
+
end
|
338
|
+
m.add_matcher(:namespace_partial_ci) do
|
339
|
+
m.yield @ri_reader.methods_under_matching("", /^#{namespace}[^:]*#{sep_re}#{method}$/i, true)
|
340
|
+
end
|
341
|
+
m.add_matcher(:full_partial) do
|
342
|
+
m.yield @ri_reader.methods_under_matching("", /^#{namespace}[^:]*#{sep_re}#{method}/, true)
|
343
|
+
end
|
344
|
+
m.add_matcher(:full_partial_ci) do
|
345
|
+
m.yield @ri_reader.methods_under_matching("", /^#{namespace}[^:]*#{sep_re}#{method}/i, true)
|
346
|
+
end
|
325
347
|
end
|
326
348
|
matcher.get_matches(order)
|
327
349
|
end
|
328
350
|
|
329
351
|
def obtain_namespace_entries(name, order)
|
352
|
+
name = Regexp.escape(name)
|
330
353
|
matcher = MatchFinder.new do |m|
|
331
354
|
m.add_matcher(:exact){ m.yield @ri_reader.get_class_entry(name) }
|
332
355
|
m.add_matcher(:exact_ci) do
|
data/lib/fastri/util.rb
CHANGED
@@ -96,5 +96,74 @@ module Util
|
|
96
96
|
end
|
97
97
|
end
|
98
98
|
module_function :find_home
|
99
|
+
|
100
|
+
def change_query_method_type(query)
|
101
|
+
if md = /\A(.*)(#|\.|::)([^#.:]+)\z/.match(query)
|
102
|
+
namespace, sep, meth = md.captures
|
103
|
+
case sep
|
104
|
+
when /::/ then "#{namespace}##{meth}"
|
105
|
+
when /#/ then "#{namespace}::#{meth}"
|
106
|
+
else
|
107
|
+
query
|
108
|
+
end
|
109
|
+
else
|
110
|
+
query
|
111
|
+
end
|
112
|
+
end
|
113
|
+
module_function :change_query_method_type
|
114
|
+
|
115
|
+
|
116
|
+
module MagicHelp
|
117
|
+
def help_method_extract(m) # :nodoc:
|
118
|
+
unless m.inspect =~ %r[\A#<(?:Unbound)?Method: (.*?)>\Z]
|
119
|
+
raise "Cannot parse result of #{m.class}#inspect: #{m.inspect}"
|
120
|
+
end
|
121
|
+
$1.sub(/\A.*?\((.*?)\)(.*)\Z/){ "#{$1}#{$2}" }.sub(/\./, "::").sub(/#<Class:(.*?)>#/) { "#{$1}::" }
|
122
|
+
end
|
123
|
+
|
124
|
+
def magic_help(query)
|
125
|
+
if query =~ /\A(.*?)(#|::|\.)([^:#.]+)\Z/
|
126
|
+
c, k, m = $1, $2, $3
|
127
|
+
mid = m
|
128
|
+
begin
|
129
|
+
c = c.split(/::/).inject(Object){|s,x| s.const_get(x)}
|
130
|
+
m = case k
|
131
|
+
when "#"
|
132
|
+
c.instance_method(m)
|
133
|
+
when "::"
|
134
|
+
c.method(m)
|
135
|
+
when "."
|
136
|
+
begin
|
137
|
+
# if it's a private_instance_method, assume it was created
|
138
|
+
# with module_function
|
139
|
+
if c.private_instance_methods.include?(m)
|
140
|
+
c.instance_method(m)
|
141
|
+
else
|
142
|
+
c.method(m)
|
143
|
+
end
|
144
|
+
rescue NameError
|
145
|
+
c.instance_method(m)
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
ret = help_method_extract(m)
|
150
|
+
if ret == 'Class#new' and
|
151
|
+
c.private_method_defined?(:initialize)
|
152
|
+
return c.name + "::new"
|
153
|
+
elsif ret =~ /^Kernel#/ and
|
154
|
+
Kernel.instance_methods(false).include? mid
|
155
|
+
return "Object##{mid}"
|
156
|
+
end
|
157
|
+
ret
|
158
|
+
rescue Exception
|
159
|
+
query
|
160
|
+
end
|
161
|
+
else
|
162
|
+
query
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
|
99
168
|
end # module Util
|
100
169
|
end # module FastRI
|
data/lib/fastri/version.rb
CHANGED
data/pre-install.rb
CHANGED
@@ -1,8 +1,11 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
+
require 'fileutils'
|
3
|
+
|
4
|
+
FileUtils.cp "bin/fri", "bin/qri"
|
2
5
|
|
3
6
|
if /win/ =~ RUBY_PLATFORM and /darwin|cygwin/ !~ RUBY_PLATFORM
|
4
|
-
|
5
|
-
%w[fri fastri-server ri-emacs].each do |fname|
|
7
|
+
%w[fri qri fastri-server ri-emacs].each do |fname|
|
6
8
|
FileUtils.mv "bin/#{fname}", "bin/#{fname}.rb", :force => true
|
7
9
|
end
|
8
10
|
end
|
11
|
+
|
data/test/test_ri_index.rb
CHANGED
@@ -29,11 +29,30 @@ ABC::Zzz#foo 0
|
|
29
29
|
CDE.foo 1 2
|
30
30
|
FGH::Adfdsf#foo 2
|
31
31
|
================================================================================
|
32
|
+
EOF
|
33
|
+
INDEX_DATA2 =<<EOF
|
34
|
+
#{FastRI::RiIndex::MAGIC}
|
35
|
+
Sources:
|
36
|
+
system /usr/share/ri/system/
|
37
|
+
somegem-0.1.0 /long/path/somegem-0.1.0
|
38
|
+
stuff-1.1.0 /long/path/stuff-1.1.0
|
39
|
+
================================================================================
|
40
|
+
Namespaces:
|
41
|
+
ABC 0 1
|
42
|
+
ABCDEF 1 2
|
43
|
+
================================================================================
|
44
|
+
Methods:
|
45
|
+
ABC.bar 0
|
46
|
+
ABC#baz 1
|
47
|
+
ABCDEF#foo 1
|
48
|
+
ABCDEF.foo 1 2
|
49
|
+
================================================================================
|
32
50
|
EOF
|
33
51
|
|
34
52
|
require 'stringio'
|
35
53
|
def setup
|
36
54
|
@index = FastRI::RiIndex.new_from_IO(StringIO.new(INDEX_DATA))
|
55
|
+
@index2 = FastRI::RiIndex.new_from_IO(StringIO.new(INDEX_DATA2))
|
37
56
|
end
|
38
57
|
|
39
58
|
def test_dump
|
@@ -157,6 +176,11 @@ EOF
|
|
157
176
|
@index.source_paths_for(@index.get_method_entry("CDE.foo")))
|
158
177
|
end
|
159
178
|
|
179
|
+
def test_methods_under_same_prefix
|
180
|
+
results = @index2.methods_under("ABC", true, nil)
|
181
|
+
results.map{|x| x.full_name}
|
182
|
+
assert_equal(["ABC.bar", "ABC#baz"], results.map{|x| x.full_name})
|
183
|
+
end
|
160
184
|
|
161
185
|
def test_methods_under_scoped
|
162
186
|
results = @index.methods_under("ABC", true, 1)
|
data/test/test_util.rb
CHANGED
@@ -35,4 +35,57 @@ EOF
|
|
35
35
|
assert_equal("Foo::Bar#eql?", gem_relpath_to_full_name("Foo/Bar/eql%3f-i.yaml"))
|
36
36
|
assert_equal("Foo::Bar.eql?", gem_relpath_to_full_name("Foo/Bar/eql%3f-c.yaml"))
|
37
37
|
end
|
38
|
+
|
39
|
+
def test_change_query_method_type
|
40
|
+
assert_equal(".foo", change_query_method_type(".foo"))
|
41
|
+
assert_equal("::foo", change_query_method_type("#foo"))
|
42
|
+
assert_equal("#foo", change_query_method_type("::foo"))
|
43
|
+
assert_equal("A::B.foo", change_query_method_type("A::B.foo"))
|
44
|
+
assert_equal("A::B::foo", change_query_method_type("A::B#foo"))
|
45
|
+
assert_equal("A::B#foo", change_query_method_type("A::B::foo"))
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
class TestUtilMagicHelp < Test::Unit::TestCase
|
50
|
+
include FastRI::Util::MagicHelp
|
51
|
+
module TestModule
|
52
|
+
def foo; end
|
53
|
+
module_function :foo
|
54
|
+
|
55
|
+
def self.bar; end
|
56
|
+
def bar; end
|
57
|
+
end
|
58
|
+
|
59
|
+
def test_magic_help
|
60
|
+
assert_equal("IO::readlines", magic_help("IO::readlines"))
|
61
|
+
assert_equal("IO::readlines", magic_help("IO.readlines"))
|
62
|
+
|
63
|
+
assert_equal("Enumerable#inject", magic_help("File#inject"))
|
64
|
+
assert_equal("Enumerable#inject", magic_help("File.inject"))
|
65
|
+
|
66
|
+
assert_equal("IO::readlines", magic_help("File.readlines"))
|
67
|
+
assert_equal("IO::readlines", magic_help("File::readlines"))
|
68
|
+
end
|
69
|
+
|
70
|
+
def test_magic_help_nested_namespaces
|
71
|
+
assert_equal("TestUtilMagicHelp::TestModule#foo",
|
72
|
+
magic_help("TestUtilMagicHelp::TestModule.foo"))
|
73
|
+
assert_equal("TestUtilMagicHelp::TestModule::bar",
|
74
|
+
magic_help("TestUtilMagicHelp::TestModule.bar"))
|
75
|
+
end
|
76
|
+
|
77
|
+
def test_magic_help__new
|
78
|
+
assert_equal("Array::new", magic_help("Array::new"))
|
79
|
+
assert_equal("Array::new", magic_help("Array.new"))
|
80
|
+
assert_equal("Struct::new", magic_help("Struct.new"))
|
81
|
+
assert_equal("Struct::new", magic_help("Struct::new"))
|
82
|
+
end
|
83
|
+
|
84
|
+
def test_magic_help__Kernel_public_instance_methods
|
85
|
+
# It is mysterious.
|
86
|
+
# Object.instance_method(:object_id) # => #<UnboundMethod: Object(Kernel)#object_id>
|
87
|
+
assert_equal("Object#object_id", magic_help("Object.object_id"))
|
88
|
+
assert_equal("Object#object_id", magic_help("Object#object_id"))
|
89
|
+
end
|
90
|
+
|
38
91
|
end
|
metadata
CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.9.0
|
|
3
3
|
specification_version: 1
|
4
4
|
name: fastri
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 0.
|
7
|
-
date:
|
6
|
+
version: 0.3.0.1
|
7
|
+
date: 2007-01-29 00:00:00 +01:00
|
8
8
|
summary: RI docs across machines, faster and smarter than ri.
|
9
9
|
require_paths:
|
10
10
|
- lib
|
@@ -55,6 +55,7 @@ authors:
|
|
55
55
|
- Mauricio Fernandez
|
56
56
|
files:
|
57
57
|
- bin/fri
|
58
|
+
- bin/qri
|
58
59
|
- bin/fastri-server
|
59
60
|
- bin/ri-emacs
|
60
61
|
- lib/fastri/ri_index.rb
|
@@ -94,6 +95,7 @@ extra_rdoc_files: []
|
|
94
95
|
|
95
96
|
executables:
|
96
97
|
- fri
|
98
|
+
- qri
|
97
99
|
- fastri-server
|
98
100
|
- ri-emacs
|
99
101
|
extensions: []
|