radar-lookup 0.1.0 → 0.2.0
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/LICENSE +2 -0
- data/README.md +1 -0
- data/bin/lookup +78 -2
- data/lib/lookup.rb +51 -145
- data/lib/models.rb +70 -0
- metadata +3 -2
data/LICENSE
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
Copyright (c) 2009 Ryan Bigg
|
|
2
2
|
|
|
3
|
+
Contributions by: Josh Goebel / Dreamer3
|
|
4
|
+
|
|
3
5
|
Permission is hereby granted, free of charge, to any person obtaining
|
|
4
6
|
a copy of this software and associated documentation files (the
|
|
5
7
|
"Software"), to deal in the Software without restriction, including
|
data/README.md
CHANGED
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
It also takes options:
|
|
15
15
|
|
|
16
16
|
* `-c or --clear` will delete the database and update the api again. This can take a minute or two.
|
|
17
|
+
* `-t or --text` is useful for when you don't want lookup to spam tabs into your browser willy-nilly.
|
|
17
18
|
|
|
18
19
|
## How it finds them
|
|
19
20
|
|
data/bin/lookup
CHANGED
|
@@ -1,3 +1,79 @@
|
|
|
1
1
|
#!/usr/bin/ruby
|
|
2
|
-
require '
|
|
3
|
-
|
|
2
|
+
require 'optparse'
|
|
3
|
+
|
|
4
|
+
# How many methods / constants to return.
|
|
5
|
+
THRESHOLD = 5
|
|
6
|
+
MAC = !!/darwin/.match(PLATFORM)
|
|
7
|
+
WINDOWS = !!/win/.match(PLATFORM) if not MAC
|
|
8
|
+
|
|
9
|
+
def clear_database
|
|
10
|
+
file = File.join(File.dirname(__FILE__), "lookup.sqlite3")
|
|
11
|
+
FileUtils.rm(file) if File.exists?(file)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def display_url(result, options={})
|
|
15
|
+
# if we're not on mac or windows we default to text output
|
|
16
|
+
if OPTIONS[:text] or not (MAC || WINDOWS)
|
|
17
|
+
s = options[:number] ? options[:number].to_s + ". " : ""
|
|
18
|
+
# if we're a method then show the constant in parans
|
|
19
|
+
s += "(#{result.constant.name}) " if result.respond_to?(:constant)
|
|
20
|
+
s += "#{result.name} #{result.url}"
|
|
21
|
+
puts s
|
|
22
|
+
elsif MAC
|
|
23
|
+
`open #{result.url}`
|
|
24
|
+
elsif WINDOWS
|
|
25
|
+
`start #{result.url}`
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def display_results(results, search_string)
|
|
30
|
+
if results.empty?
|
|
31
|
+
puts "There were no results matching #{search_string}."
|
|
32
|
+
# if entry
|
|
33
|
+
# puts "There are no constants that match #{name} and contain #{entry}."
|
|
34
|
+
# else
|
|
35
|
+
# puts "There are no constants that match #{name}"
|
|
36
|
+
# end
|
|
37
|
+
elsif results.size == 1
|
|
38
|
+
display_url(results.first)
|
|
39
|
+
elsif results.size <= THRESHOLD
|
|
40
|
+
results.each_with_index do |result, i|
|
|
41
|
+
display_url(result, :number => i+1)
|
|
42
|
+
end
|
|
43
|
+
else
|
|
44
|
+
puts "Please refine your query, we found #{results.size} results (threshold is #{THRESHOLD})."
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
OPTIONS = {}
|
|
49
|
+
op=OptionParser.new do |opts|
|
|
50
|
+
opts.banner = "Usage: lookup <constant|method> [method] [OPTIONS]"
|
|
51
|
+
|
|
52
|
+
opts.on("-c", "--clear", "Clear database") do
|
|
53
|
+
OPTIONS[:clear] = true
|
|
54
|
+
end
|
|
55
|
+
opts.on("-t", "--text", "Text only") do
|
|
56
|
+
OPTIONS[:text] = true
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
op.parse!
|
|
60
|
+
|
|
61
|
+
clear_database if OPTIONS[:clear]
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
local_lib=File.join(File.dirname(__FILE__), "../lib/lookup")
|
|
65
|
+
if File.exists?(local_lib + ".rb")
|
|
66
|
+
require local_lib
|
|
67
|
+
else
|
|
68
|
+
require 'rubygems'
|
|
69
|
+
require 'lookup'
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
search_string=ARGV[0..-1].join(" ")
|
|
73
|
+
if search_string.strip.empty?
|
|
74
|
+
puts op.help
|
|
75
|
+
puts
|
|
76
|
+
else
|
|
77
|
+
results=APILookup.search(ARGV[0..-1])
|
|
78
|
+
display_results(results, search_string)
|
|
79
|
+
end
|
data/lib/lookup.rb
CHANGED
|
@@ -1,16 +1,7 @@
|
|
|
1
1
|
require 'rubygems'
|
|
2
2
|
require 'activerecord'
|
|
3
|
-
require 'optparse'
|
|
4
3
|
|
|
5
|
-
|
|
6
|
-
WINDOWS = !!/win/.match(PLATFORM)
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
# How many methods / constants to return.
|
|
10
|
-
THRESHOLD = 5
|
|
11
|
-
|
|
12
|
-
ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :database => File.join(File.dirname(__FILE__), "lookup.sqlite3"))
|
|
13
|
-
class Lookup
|
|
4
|
+
class APILookup
|
|
14
5
|
|
|
15
6
|
class << self
|
|
16
7
|
def update
|
|
@@ -29,11 +20,11 @@ class Lookup
|
|
|
29
20
|
end
|
|
30
21
|
|
|
31
22
|
def update_api(name, url)
|
|
32
|
-
puts "Updating API for #{name}"
|
|
23
|
+
puts "Updating API for #{name}..."
|
|
33
24
|
Api.find_or_create_by_name_and_url(name, url)
|
|
34
25
|
update_methods(Hpricot(Net::HTTP.get(URI.parse("#{url}/fr_method_index.html"))), url)
|
|
35
26
|
update_classes(Hpricot(Net::HTTP.get(URI.parse("#{url}/fr_class_index.html"))), url)
|
|
36
|
-
puts "
|
|
27
|
+
puts "DONE (with #{name})!"
|
|
37
28
|
end
|
|
38
29
|
|
|
39
30
|
def update_methods(doc, prefix)
|
|
@@ -63,49 +54,52 @@ class Lookup
|
|
|
63
54
|
def find_constant(name, entry=nil)
|
|
64
55
|
# Find by specific name.
|
|
65
56
|
constants = Constant.find_all_by_name(name, :include => "entries")
|
|
57
|
+
# search for class methods, which is prolly what we want if we can find it
|
|
58
|
+
constants = Constant.find_all_by_name("#{name}::ClassMethods", :include => "entries") if constants.empty?
|
|
66
59
|
# Find by name beginning with <blah>.
|
|
67
60
|
constants = Constant.all(:conditions => ["name LIKE ?", name + "%"], :include => "entries") if constants.empty?
|
|
68
61
|
# Find by fuzzy.
|
|
69
|
-
|
|
70
|
-
if constants.
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
puts "There are no constants that match #{name} and contain #{entry}."
|
|
87
|
-
else
|
|
88
|
-
puts "There are no constants that match #{name}"
|
|
89
|
-
end
|
|
90
|
-
else
|
|
91
|
-
return [constants, constants.size]
|
|
92
|
-
end
|
|
93
|
-
else
|
|
94
|
-
if entry.nil?
|
|
95
|
-
display_constants(constants)
|
|
96
|
-
else
|
|
97
|
-
return [[constants.first], 1]
|
|
98
|
-
end
|
|
62
|
+
match="%#{name.split("").join("%")}%"
|
|
63
|
+
constants = Constant.find_by_sql("select * from constants where name LIKE '#{match}'") if constants.empty?
|
|
64
|
+
regex=build_regex_from_constant(name)
|
|
65
|
+
constants = constants.select { |x| x.name =~ regex }
|
|
66
|
+
# Narrow it down to the constants that only contain the entry we are looking for.
|
|
67
|
+
if entry
|
|
68
|
+
constants = constants.select { |constant| !constant.entries.find_by_name(entry).nil? }
|
|
69
|
+
end
|
|
70
|
+
constants
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# this uses a regex to lock down our SQL finds even more
|
|
74
|
+
# so that things like AR::Base will not match
|
|
75
|
+
# ActiveRecord::ConnectionAdapters::DatabaseStatements
|
|
76
|
+
def build_regex_from_constant(name)
|
|
77
|
+
parts=name.split("::").map do |c|
|
|
78
|
+
c.split("").join("[^:]*")+"[^:]*"
|
|
99
79
|
end
|
|
100
|
-
|
|
80
|
+
/#{parts.join("::")}/i
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def smart_rails_constant_substitutions(name)
|
|
84
|
+
parts=name.split("::").map { |x| x.split(":")}.flatten
|
|
85
|
+
rep = case parts.first.downcase
|
|
86
|
+
# so it falls back on fuzzy and matches AR as well as ActiveResource
|
|
87
|
+
when "ar": "ActiveRecord"
|
|
88
|
+
when "ares": "ActiveResource"
|
|
89
|
+
when "am": "ActionMailer"
|
|
90
|
+
when "as": "ActiveSupport"
|
|
91
|
+
when "ac": "ActionController"
|
|
92
|
+
when "av": "ActionView"
|
|
93
|
+
else
|
|
94
|
+
parts.first
|
|
95
|
+
end
|
|
96
|
+
([rep] + parts[1..-1]).join("::")
|
|
97
|
+
end
|
|
101
98
|
|
|
102
99
|
# Find an entry.
|
|
103
100
|
# If the constant argument is passed, look it up within the scope of the constant.
|
|
104
101
|
def find_method(name, constant=nil)
|
|
105
|
-
|
|
106
|
-
constants, number = find_constant(constant, name)
|
|
107
|
-
end
|
|
108
|
-
methods = []
|
|
102
|
+
methods = []
|
|
109
103
|
methods = Entry.find_all_by_name(name.to_s)
|
|
110
104
|
methods = Entry.all(:conditions => ["name LIKE ?", name.to_s + "%"]) if methods.empty?
|
|
111
105
|
methods = Entry.find_by_sql("select * from entries where name LIKE '%#{name.split("").join("%")}%'") if methods.empty?
|
|
@@ -114,120 +108,32 @@ class Lookup
|
|
|
114
108
|
methods = methods.sort_by(&:weighting)
|
|
115
109
|
|
|
116
110
|
if constant
|
|
111
|
+
constants = find_constant(constant, name)
|
|
117
112
|
methods = methods.select { |m| constants.include?(m.constant) }
|
|
118
113
|
end
|
|
119
|
-
|
|
120
|
-
if methods.size == 1
|
|
121
|
-
method = methods.first
|
|
122
|
-
if OPTIONS[:text]
|
|
123
|
-
puts display_method(method)
|
|
124
|
-
elsif MAC
|
|
125
|
-
`open #{method.url}`
|
|
126
|
-
elsif WINDOWS
|
|
127
|
-
`start #{method.url}`
|
|
128
|
-
else
|
|
129
|
-
puts display_method(method)
|
|
130
|
-
end
|
|
131
|
-
elsif methods.size <= THRESHOLD
|
|
132
|
-
for method in methods
|
|
133
|
-
if OPTIONS[:text]
|
|
134
|
-
puts "#{count += 1}. #{display_method(method)}"
|
|
135
|
-
elsif MAC
|
|
136
|
-
`open #{method.url}`
|
|
137
|
-
elsif WINDOWS
|
|
138
|
-
`start #{method.url}`
|
|
139
|
-
else
|
|
140
|
-
puts "#{count += 1}. #{display_method(method)}"
|
|
141
|
-
end
|
|
142
|
-
end
|
|
143
|
-
methods
|
|
144
|
-
else
|
|
145
|
-
puts "Please refine your query, we found #{methods.size} methods. Threshold is #{THRESHOLD}."
|
|
146
|
-
end
|
|
147
|
-
return nil
|
|
148
|
-
end
|
|
149
|
-
|
|
150
|
-
def display_method(method)
|
|
151
|
-
"(#{method.constant.name}) #{method.name} #{method.url}"
|
|
152
|
-
end
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
def display_constants(constants)
|
|
156
|
-
count = 0
|
|
157
|
-
if constants.size == 1
|
|
158
|
-
constant = constants.first
|
|
159
|
-
if OPTIONS[:text]
|
|
160
|
-
puts "#{constant.name} #{constant.url}"
|
|
161
|
-
elsif MAC && !OPTIONS[:text]
|
|
162
|
-
`open #{constant.url}`
|
|
163
|
-
elsif WINDOWS && !OPTIONS[:text]
|
|
164
|
-
`start #{constant.url}`
|
|
165
|
-
else
|
|
166
|
-
puts "#{constant.name} #{constant.url}"
|
|
167
|
-
end
|
|
168
|
-
|
|
169
|
-
elsif constants.size <= THRESHOLD
|
|
170
|
-
for constant in constants
|
|
171
|
-
if OPTIONS[:text]
|
|
172
|
-
puts "#{count+=1}. #{constant.name} #{constant.url}"
|
|
173
|
-
elsif MAC
|
|
174
|
-
`open #{constant.url}`
|
|
175
|
-
elsif WINDOWS
|
|
176
|
-
`open #{constant.url}`
|
|
177
|
-
else
|
|
178
|
-
puts "#{count+=1}. #{constant.name} #{constant.url}"
|
|
179
|
-
end
|
|
180
|
-
end
|
|
181
|
-
else
|
|
182
|
-
puts "Please refine your query, we found #{constants.size} constants (threshold is #{THRESHOLD})."
|
|
183
|
-
end
|
|
184
|
-
return nil
|
|
114
|
+
methods
|
|
185
115
|
end
|
|
186
|
-
|
|
187
|
-
def
|
|
116
|
+
|
|
117
|
+
def search(msg)
|
|
188
118
|
msg = msg.split(" ")[0..-1].flatten.map { |a| a.split("#") }.flatten!
|
|
189
119
|
|
|
190
120
|
# It's a constant! Oh... and there's nothing else in the string!
|
|
191
|
-
|
|
192
|
-
|
|
121
|
+
first=smart_rails_constant_substitutions(msg.first)
|
|
122
|
+
if /^[A-Z]/.match(first) && msg.size == 1
|
|
123
|
+
find_constant(first)
|
|
193
124
|
# It's a method!
|
|
194
125
|
else
|
|
195
126
|
# Right, so they only specified one argument. Therefore, we look everywhere.
|
|
196
|
-
if msg.
|
|
197
|
-
|
|
127
|
+
if msg.size == 1
|
|
128
|
+
find_method(msg)
|
|
198
129
|
# Left, so they specified two arguments. First is probably a constant, so let's find that!
|
|
199
130
|
else
|
|
200
|
-
|
|
131
|
+
find_method(msg.last, first)
|
|
201
132
|
end
|
|
202
133
|
end
|
|
203
134
|
end
|
|
204
135
|
|
|
205
|
-
def setup
|
|
206
|
-
file = File.join(File.dirname(__FILE__), "lookup.sqlite3")
|
|
207
|
-
FileUtils.rm(file) if File.exists?(file) && OPTIONS[:clear]
|
|
208
|
-
end
|
|
209
136
|
end
|
|
210
137
|
end
|
|
211
138
|
|
|
212
|
-
OPTIONS = {}
|
|
213
|
-
unless $TESTING
|
|
214
|
-
OptionParser.new do |opts|
|
|
215
|
-
opts.banner = "Usage: lookup <constant|method> [method] [OPTIONS]"
|
|
216
|
-
|
|
217
|
-
opts.on("-c", "--clear", "Clear database") do
|
|
218
|
-
OPTIONS[:clear] = true
|
|
219
|
-
end
|
|
220
|
-
opts.on("-t", "--text", "Text only") do
|
|
221
|
-
OPTIONS[:text] = true
|
|
222
|
-
end
|
|
223
|
-
end.parse!
|
|
224
|
-
end
|
|
225
|
-
# Ready!
|
|
226
|
-
Lookup.setup
|
|
227
|
-
|
|
228
|
-
# Set!
|
|
229
139
|
require File.join(File.dirname(__FILE__), 'models')
|
|
230
|
-
|
|
231
|
-
# Go!
|
|
232
|
-
Lookup.do(ARGV[0..-1])
|
|
233
|
-
|
data/lib/models.rb
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
require 'fileutils'
|
|
2
|
+
|
|
3
|
+
class APILookup
|
|
4
|
+
|
|
5
|
+
class MissingHome < StandardError
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
class LookupBase < ActiveRecord::Base
|
|
9
|
+
end
|
|
10
|
+
if ENV["HOME"].nil?
|
|
11
|
+
puts "The HOME environment variable should be set so lookup knows where"
|
|
12
|
+
puts "to store it's lookup database."
|
|
13
|
+
raise MissingHome, "HOME must be set to know where to store our local db."
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
LookupBase.establish_connection(:adapter => "sqlite3",
|
|
17
|
+
:database => File.join(ENV["HOME"],".lookup", "lookup.sqlite3"))
|
|
18
|
+
|
|
19
|
+
class Api < LookupBase
|
|
20
|
+
set_table_name "apis"
|
|
21
|
+
has_many :constants
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
class Constant < LookupBase
|
|
25
|
+
set_table_name "constants"
|
|
26
|
+
belongs_to :api
|
|
27
|
+
has_many :entries
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
class Entry < LookupBase
|
|
31
|
+
set_table_name "entries"
|
|
32
|
+
belongs_to :constant
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
class SetupTables < ActiveRecord::Migration
|
|
38
|
+
def self.connection
|
|
39
|
+
APILookup::Api.connection
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def self.up
|
|
43
|
+
create_table :apis do |t|
|
|
44
|
+
t.string :name, :url
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
create_table :entries do |t|
|
|
48
|
+
t.string :name, :url
|
|
49
|
+
t.references :constant
|
|
50
|
+
t.integer :weighting, :default => 0
|
|
51
|
+
t.integer :count, :default => 0
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
create_table :constants do |t|
|
|
55
|
+
t.string :name, :url
|
|
56
|
+
t.references :api
|
|
57
|
+
t.integer :weighting, :default => 0
|
|
58
|
+
t.integer :count, :default => 0
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
FileUtils.mkdir_p(File.join(ENV["HOME"],".lookup"))
|
|
64
|
+
|
|
65
|
+
if !APILookup::Api.table_exists? &&
|
|
66
|
+
!APILookup::Constant.table_exists? &&
|
|
67
|
+
!APILookup::Entry.table_exists?
|
|
68
|
+
SetupTables.up
|
|
69
|
+
APILookup.update
|
|
70
|
+
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: radar-lookup
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ryan Bigg
|
|
@@ -9,7 +9,7 @@ autorequire: lookup
|
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
11
|
|
|
12
|
-
date: 2009-
|
|
12
|
+
date: 2009-03-30 00:00:00 -07:00
|
|
13
13
|
default_executable: lookup
|
|
14
14
|
dependencies: []
|
|
15
15
|
|
|
@@ -30,6 +30,7 @@ files:
|
|
|
30
30
|
- TODO
|
|
31
31
|
- lib/config.rb
|
|
32
32
|
- lib/lookup.rb
|
|
33
|
+
- lib/models.rb
|
|
33
34
|
- spec/lookup_spec.rb
|
|
34
35
|
- spec/spec_helper.rb
|
|
35
36
|
- bin/lookup
|