lookup 0.4.1 → 1.0.0.beta1

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.
@@ -0,0 +1,208 @@
1
+
2
+ body {
3
+ font-family: Verdana,Arial,Helvetica,sans-serif;
4
+ font-size: 90%;
5
+ margin: 0;
6
+ margin-left: 40px;
7
+ padding: 0;
8
+ background: white;
9
+ }
10
+
11
+ h1,h2,h3,h4 { margin: 0; color: #efefef; background: transparent; }
12
+ h1 { font-size: 150%; }
13
+ h2,h3,h4 { margin-top: 1em; }
14
+
15
+ a { background: #eef; color: #039; text-decoration: none; }
16
+ a:hover { background: #039; color: #eef; }
17
+
18
+ /* Override the base stylesheet's Anchor inside a table cell */
19
+ td > a {
20
+ background: transparent;
21
+ color: #039;
22
+ text-decoration: none;
23
+ }
24
+
25
+ /* and inside a section title */
26
+ .section-title > a {
27
+ background: transparent;
28
+ color: #eee;
29
+ text-decoration: none;
30
+ }
31
+
32
+ /* === Structural elements =================================== */
33
+
34
+ div#index {
35
+ margin: 0;
36
+ margin-left: -40px;
37
+ padding: 0;
38
+ font-size: 90%;
39
+ }
40
+
41
+
42
+ div#index a {
43
+ margin-left: 0.7em;
44
+ }
45
+
46
+ div#index .section-bar {
47
+ margin-left: 0px;
48
+ padding-left: 0.7em;
49
+ background: #ccc;
50
+ font-size: small;
51
+ }
52
+
53
+
54
+ div#classHeader, div#fileHeader {
55
+ width: auto;
56
+ color: white;
57
+ padding: 0.5em 1.5em 0.5em 1.5em;
58
+ margin: 0;
59
+ margin-left: -40px;
60
+ border-bottom: 3px solid #006;
61
+ }
62
+
63
+ div#classHeader a, div#fileHeader a {
64
+ background: inherit;
65
+ color: white;
66
+ }
67
+
68
+ div#classHeader td, div#fileHeader td {
69
+ background: inherit;
70
+ color: white;
71
+ }
72
+
73
+
74
+ div#fileHeader {
75
+ background: #057;
76
+ }
77
+
78
+ div#classHeader {
79
+ background: #048;
80
+ }
81
+
82
+
83
+ .class-name-in-header {
84
+ font-size: 180%;
85
+ font-weight: bold;
86
+ }
87
+
88
+
89
+ div#bodyContent {
90
+ padding: 0 1.5em 0 1.5em;
91
+ }
92
+
93
+ div#description {
94
+ padding: 0.5em 1.5em;
95
+ background: #efefef;
96
+ border: 1px dotted #999;
97
+ }
98
+
99
+ div#description h1,h2,h3,h4,h5,h6 {
100
+ color: #125;;
101
+ background: transparent;
102
+ }
103
+
104
+ div#validator-badges {
105
+ text-align: center;
106
+ }
107
+ div#validator-badges img { border: 0; }
108
+
109
+ div#copyright {
110
+ color: #333;
111
+ background: #efefef;
112
+ font: 0.75em sans-serif;
113
+ margin-top: 5em;
114
+ margin-bottom: 0;
115
+ padding: 0.5em 2em;
116
+ }
117
+
118
+
119
+ /* === Classes =================================== */
120
+
121
+ table.header-table {
122
+ color: white;
123
+ font-size: small;
124
+ }
125
+
126
+ .type-note {
127
+ font-size: small;
128
+ color: #DEDEDE;
129
+ }
130
+
131
+ .xxsection-bar {
132
+ background: #eee;
133
+ color: #333;
134
+ padding: 3px;
135
+ }
136
+
137
+ .section-bar {
138
+ color: #333;
139
+ border-bottom: 1px solid #999;
140
+ margin-left: -20px;
141
+ }
142
+
143
+
144
+ .section-title {
145
+ background: #79a;
146
+ color: #eee;
147
+ padding: 3px;
148
+ margin-top: 2em;
149
+ margin-left: -30px;
150
+ border: 1px solid #999;
151
+ }
152
+
153
+ .top-aligned-row { vertical-align: top }
154
+ .bottom-aligned-row { vertical-align: bottom }
155
+
156
+ /* --- Context section classes ----------------------- */
157
+
158
+ .context-row { }
159
+ .context-item-name { font-family: monospace; font-weight: bold; color: black; }
160
+ .context-item-value { font-size: small; color: #448; }
161
+ .context-item-desc { color: #333; padding-left: 2em; }
162
+
163
+ /* --- Method classes -------------------------- */
164
+ .method-detail {
165
+ background: #efefef;
166
+ padding: 0;
167
+ margin-top: 0.5em;
168
+ margin-bottom: 1em;
169
+ border: 1px dotted #ccc;
170
+ }
171
+ .method-heading {
172
+ color: black;
173
+ background: #ccc;
174
+ border-bottom: 1px solid #666;
175
+ padding: 0.2em 0.5em 0 0.5em;
176
+ }
177
+ .method-signature { color: black; background: inherit; }
178
+ .method-name { font-weight: bold; }
179
+ .method-args { font-style: italic; }
180
+ .method-description { padding: 0 0.5em 0 0.5em; }
181
+
182
+ /* --- Source code sections -------------------- */
183
+
184
+ a.source-toggle { font-size: 90%; }
185
+ div.method-source-code {
186
+ background: #262626;
187
+ color: #ffdead;
188
+ margin: 1em;
189
+ padding: 0.5em;
190
+ border: 1px dashed #999;
191
+ overflow: hidden;
192
+ }
193
+
194
+ div.method-source-code pre { color: #ffdead; overflow: hidden; }
195
+
196
+ /* --- Ruby keyword styles --------------------- */
197
+
198
+ .standalone-code { background: #221111; color: #ffdead; overflow: hidden; }
199
+
200
+ .ruby-constant { color: #7fffd4; background: transparent; }
201
+ .ruby-keyword { color: #00ffff; background: transparent; }
202
+ .ruby-ivar { color: #eedd82; background: transparent; }
203
+ .ruby-operator { color: #00ffee; background: transparent; }
204
+ .ruby-identifier { color: #ffdead; background: transparent; }
205
+ .ruby-node { color: #ffa07a; background: transparent; }
206
+ .ruby-comment { color: #b22222; font-weight: bold; background: transparent; }
207
+ .ruby-regexp { color: #ffa07a; background: transparent; }
208
+ .ruby-value { color: #7fffd4; background: transparent; }
data/lib/lookup.rb CHANGED
@@ -1,9 +1,10 @@
1
1
  require 'rubygems'
2
+ require 'bundler'
2
3
  require 'net/http'
3
4
 
5
+ Bundler.setup
6
+ Bundler.require(:default)
4
7
  require 'active_record'
5
- require 'nokogiri'
6
- require 'find_by_hash'
7
8
 
8
9
  module APILookup
9
10
 
@@ -12,7 +13,8 @@ module APILookup
12
13
  puts "Updating API, this may take a minute or two. Please be patient!"
13
14
  [Constant, Entry, Api].map { |klass| klass.delete_all }
14
15
 
15
- update_api!("Rails", "http://api.rubyonrails.org")
16
+ update_api!("Rails v3.0.0", "http://api.rubyonrails.org")
17
+ update_api!("Rails v2.3.8", "http://api.rubyonrails.org/v2.3.8")
16
18
  update_api!("Ruby 1.8.7", "http://www.ruby-doc.org/core")
17
19
  update_api!("Ruby 1.9", "http://ruby-doc.org/ruby-1.9")
18
20
 
@@ -26,16 +28,17 @@ module APILookup
26
28
  puts "DONE (with #{name})!"
27
29
  end
28
30
 
29
- def find_constant(name, entry=nil)
31
+ def find_constant(name, entry=nil, options={})
32
+ scope = options[:api].constants || Constant
30
33
  # Find by specific name.
31
- constants = Constant.find_all_by_name(name, :include => "entries")
34
+ constants = scope.find_all_by_name(name, :include => "entries")
32
35
  # search for class methods, which is prolly what we want if we can find it
33
- constants = Constant.find_all_by_name("#{name}::ClassMethods", :include => "entries") if constants.empty?
36
+ constants = scope.find_all_by_name("#{name}::ClassMethods", :include => "entries") if constants.empty?
34
37
  # Find by name beginning with <blah>.
35
- constants = Constant.all(:conditions => ["name LIKE ?", name + "%"], :include => "entries") if constants.empty?
38
+ constants = scope.all(:conditions => ["constants.name LIKE ?", name + "%"], :include => "entries") if constants.empty?
36
39
  # Find by fuzzy.
37
40
  match="%#{name.split("").join("%")}%"
38
- constants = Constant.find_by_sql("select * from constants where name LIKE '#{match}'") if constants.empty?
41
+ constants = scope.find_by_sql("select * from constants where name LIKE '#{match}'") if constants.empty?
39
42
  regex=build_regex_from_constant(name)
40
43
  constants = constants.select { |x| x.name =~ regex }
41
44
  # Narrow it down to the constants that only contain the entry we are looking for.
@@ -76,22 +79,23 @@ module APILookup
76
79
 
77
80
  # Find an entry.
78
81
  # If the constant argument is passed, look it up within the scope of the constant.
79
- def find_method(name, constant=nil)
82
+ def find_method(name, constant=nil, options = {})
83
+ scope = options[:api].entries || Entry
80
84
  methods = []
81
85
  # Full match
82
- methods = Entry.find_all_by_name(name.to_s)
86
+ methods = scope.find_all_by_name(name.to_s)
83
87
  # Start match
84
- methods = Entry.all(:conditions => ["name LIKE ?", name.to_s + "%"]) if methods.empty?
88
+ methods = scope.all(:conditions => ["entries.name LIKE ?", name.to_s + "%"]) if methods.empty?
85
89
  # Wildcard substitution
86
- methods = Entry.find_by_sql("select * from entries where name LIKE '#{name.to_s.gsub("*", "%")}'") if methods.empty?
90
+ methods = scope.find_by_sql("select * from entries where name LIKE '#{name.to_s.gsub("*", "%")}'") if methods.empty?
87
91
  # Fuzzy match
88
- methods = Entry.find_by_sql("select * from entries where name LIKE '%#{name.to_s.split("").join("%")}%'") if methods.empty?
92
+ methods = scope.find_by_sql("select * from entries where name LIKE '%#{name.to_s.split("").join("%")}%'") if methods.empty?
89
93
 
90
94
  # Weight the results, last result is the first one we want shown first
91
95
  methods = methods.sort_by(&:weighting)
92
96
 
93
97
  if constant
94
- constants = find_constant(constant)
98
+ constants = find_constant(constant, nil, options)
95
99
  methods = methods.select { |m| constants.include?(m.constant) }
96
100
  end
97
101
  methods
@@ -101,36 +105,39 @@ module APILookup
101
105
  options[:api] ||= if /^1\.9/.match(msg)
102
106
  "Ruby 1.9"
103
107
  elsif /^1\.8/.match(msg)
104
- "Ruby 1.8"
105
- elsif /^Rails/i.match(msg)
106
- "Rails"
108
+ "Ruby 1.8.7"
109
+ elsif /^v([\d\.]{5})/i.match(msg)
110
+ "Rails v#{$1}"
107
111
  end
108
112
 
113
+ options[:api] = Api.find_by_name!(options[:api]) unless options[:api].is_a?(Api)
114
+
109
115
  msg = msg.gsub(/^(.*?)\s/, "") if options[:api]
110
116
 
111
117
  splitter = options[:splitter] || "#"
112
118
  parts = msg.split(" ")[0..-1].flatten.map { |a| a.split(splitter) }.flatten!
113
119
  # It's a constant! Oh... and there's nothing else in the string!
114
120
  first = smart_rails_constant_substitutions(parts.first)
121
+
115
122
  output = if /^[A-Z]/.match(first) && parts.size == 1
116
- find_constant(first)
123
+ find_constant(first, nil, options)
117
124
  # It's a method!
118
125
  else
119
126
  # Right, so they only specified one argument. Therefore, we look everywhere.
120
127
  if parts.size == 1
121
- o = find_method(parts.last)
128
+ o = find_method(parts.last, nil, options)
122
129
  # Left, so they specified two arguments. First is probably a constant, so let's find that!
123
130
  else
124
- o = find_method(parts.last, first)
131
+ o = find_method(parts.last, first, options)
125
132
  end
126
133
  o
127
134
  end
128
135
 
129
-
130
136
  output = search(msg, options.merge(:splitter => ".")) if output.empty? && splitter != "."
131
-
132
- output = output.select { |m| m.api.name == options[:api] } if options[:api]
133
- return output
137
+ selected_output = output.select { |m| options[:api].name == m.api.name }
138
+ selected_output = output if selected_output.empty?
139
+
140
+ return selected_output
134
141
  end
135
142
 
136
143
  end
data/lib/models.rb CHANGED
@@ -21,6 +21,7 @@ module APILookup
21
21
  class Api < LookupBase
22
22
  set_table_name "apis"
23
23
  has_many :constants, :class_name => "APILookup::Constant"
24
+ has_many :entries, :through => :constants
24
25
 
25
26
  def update_methods!
26
27
  entries = []
@@ -29,7 +30,8 @@ module APILookup
29
30
 
30
31
  # Actual HTML on Ruby doc site is invalid.
31
32
  # This makes it valid.
32
- doc = Nokogiri::HTML(doc.gsub(/<a(.*?)>(.*?)<\/a>/) { "<a#{$1}>#{$2.gsub("<", "&lt;").gsub("&gt;", ">")}" })
33
+ doc = Nokogiri::HTML(doc.gsub(/<a(.*?)>(.*?)<\/a>/m) { "<a#{$1}>#{$2.gsub("<", "&lt;").gsub(">", "&gt;")}" })
34
+
33
35
  doc.css("a").each do |a|
34
36
  names = a.text.split(" ")
35
37
  next if names.empty?
@@ -37,10 +39,10 @@ module APILookup
37
39
  constant = names[1].gsub(/[\(|\)]/, "")
38
40
  # The same constant can be defined twice in different APIs, be wary!
39
41
  url = self.url + "/classes/" + constant.gsub("::", "/") + ".html"
40
- constant = self.constants.find_or_create_by_hash(:name => constant, :url => url)
42
+ constant = self.constants.find_or_create_by_name_and_url(constant, url)
41
43
 
42
44
  url = self.url + "/" + a["href"]
43
- constant.entries.find_or_create_by_hash(:name => method, :url => url)
45
+ constant.entries.find_or_create_by_name_and_url(method, url)
44
46
  end
45
47
 
46
48
  # entries.each_slice(100) do |methods|
File without changes
File without changes