lib/lookup.rb in lookup-0.3.3 vs lib/lookup.rb in lookup-0.4.0

- old
+ new

@@ -1,58 +1,33 @@ require 'rubygems' +require 'net/http' + require 'active_record' +require 'nokogiri' +require 'find_by_hash' module APILookup class << self - def update - require 'hpricot' - require 'net/http' + def update! puts "Updating API, this may take a minute or two. Please be patient!" - Constant.delete_all - Entry.delete_all - # Ruby on Rails Classes & Methods - update_api("Rails", "http://api.rubyonrails.org") - # Ruby Classes & Methods - update_api("Ruby", "http://www.ruby-doc.org/core") + [Constant, Entry, Api].map { |klass| klass.delete_all } - weight_results - puts "Updated API index! Use the lookup <method> or lookup <class> <method> to find what you're after" + update_api!("Rails", "http://api.rubyonrails.org") + update_api!("Ruby 1.8.7", "http://www.ruby-doc.org/core") + update_api!("Ruby 1.9", "http://ruby-doc.org/ruby-1.9") + end - - def update_api(name, url) + + def update_api!(name, url) puts "Updating API for #{name}..." - Api.find_or_create_by_name_and_url(name, url) - update_methods(Hpricot(Net::HTTP.get(URI.parse("#{url}/fr_method_index.html"))), url) - update_classes(Hpricot(Net::HTTP.get(URI.parse("#{url}/fr_class_index.html"))), url) + api = Api.find_or_create_by_name_and_url(name, url) + api.update_methods! + api.update_classes! puts "DONE (with #{name})!" end - - def update_methods(doc, prefix) - doc.search("a").each do |a| - names = a.inner_html.split(" ") - method = names[0] - name = names[1].gsub(/[\(|\)]/, "") - # The same constant can be defined twice in different APIs, be wary! - url = prefix + "/classes/" + name.gsub("::", "/") + ".html" - constant = Constant.find_or_create_by_name_and_url(name, url) - constant.entries.create!(:name => method, :url => prefix + "/" + a["href"]) - end - end - - def update_classes(doc, prefix) - doc.search("a").each do |a| - constant = Constant.find_or_create_by_name_and_url(a.inner_html, prefix + "/" + a["href"]) - end - end - - # Weights the results so the ones more likely to be used by people come up first. - def weight_results - e = Constant.find_by_name("ActiveRecord::Associations::ClassMethods").entries.find_by_name("belongs_to") - e.increment!(:weighting) - end - + def find_constant(name, entry=nil) # Find by specific name. constants = Constant.find_all_by_name(name, :include => "entries") # search for class methods, which is prolly what we want if we can find it constants = Constant.find_all_by_name("#{name}::ClassMethods", :include => "entries") if constants.empty? @@ -67,11 +42,11 @@ if entry constants = constants.select { |constant| !constant.entries.find_by_name(entry).nil? } end constants end - + # this uses a regex to lock down our SQL finds even more # so that things like AR::Base will not match # ActiveRecord::ConnectionAdapters::DatabaseStatements def build_regex_from_constant(name) parts=name.split("::").map do |c| @@ -96,11 +71,11 @@ end return ([rep] + parts[1..-1]).join("::") end name end - + # Find an entry. # If the constant argument is passed, look it up within the scope of the constant. def find_method(name, constant=nil) methods = [] # Full match @@ -120,28 +95,45 @@ methods = methods.select { |m| constants.include?(m.constant) } end methods end - def search(msg) - msg = msg.split(" ")[0..-1].flatten.map { |a| a.split("#") }.flatten! - + def search(msg, options={}) + options[:api] ||= if /^1\.9/.match(msg) + "Ruby 1.9" + elsif /^1\.8/.match(msg) + "Ruby 1.8" + elsif /^Rails/i.match(msg) + "Rails" + end + + msg = msg.gsub(/^(.*?)\s/, "") if options[:api] + + splitter = options[:splitter] || "#" + parts = msg.split(" ")[0..-1].flatten.map { |a| a.split(splitter) }.flatten! # It's a constant! Oh... and there's nothing else in the string! - first = smart_rails_constant_substitutions(msg.first) - if /^[A-Z]/.match(first) && msg.size == 1 - find_constant(first) + first = smart_rails_constant_substitutions(parts.first) + output = if /^[A-Z]/.match(first) && parts.size == 1 + find_constant(first) # It's a method! else # Right, so they only specified one argument. Therefore, we look everywhere. - if msg.size == 1 - find_method(msg.last) + if parts.size == 1 + o = find_method(parts.last) # Left, so they specified two arguments. First is probably a constant, so let's find that! else - find_method(msg.last, first) - end + o = find_method(parts.last, first) + end + o end + + + output = search(msg, options.merge(:splitter => ".")) if output.empty? && splitter != "." + + output = output.select { |m| m.api.name == options[:api] } if options[:api] + return output end - + end end require File.join(File.dirname(__FILE__), 'models') \ No newline at end of file