RuBing 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (3) hide show
  1. data/lib/rubing.rb +179 -0
  2. data/test/test_search.rb +23 -0
  3. metadata +81 -0
data/lib/rubing.rb ADDED
@@ -0,0 +1,179 @@
1
+ require 'rubygems'
2
+
3
+ # Usage:
4
+ # RuBing::Search::app_id = 'xxxxxxxxxx'
5
+ # RuBing::Search::base_site = 'learnhub.com'
6
+ #
7
+ # response = RuBing::Search.get('Ruby')
8
+ # puts response.total_results
9
+ # response.results.each do |result|
10
+ # puts "#{result.title} #{result.url}"
11
+ # end
12
+ #
13
+ # Author:: Wesley Moxam (wesley.moxam@savvica.com)
14
+ # Copyright:: Copyright (c) 2009 Savvica Inc
15
+ # Licence:: Distributes under the same terms as Ruby
16
+ #
17
+ module RuBing
18
+ class Search
19
+ require 'net/http'
20
+ require 'uri'
21
+
22
+ DEFAULT_COUNT = 20
23
+
24
+ @@base_url = 'http://api.search.live.net/json.aspx?'
25
+ @@base_site = nil
26
+ @@app_id = nil
27
+
28
+ def self.base_site=(bs)
29
+ @@base_site = bs
30
+ end
31
+
32
+ def self.base_site
33
+ @@base_site
34
+ end
35
+
36
+ def self.app_id=(ai)
37
+ @@app_id = ai
38
+ end
39
+
40
+ def self.app_id
41
+ @@app_id
42
+ end
43
+
44
+ def self.get(query, options = {})
45
+ Response.new(get_json(query, options), options[:web_count] || DEFAULT_COUNT)
46
+ end
47
+
48
+ private
49
+ def self.get_json(query, options)
50
+ Net::HTTP.get(URI.parse(@@base_url + get_options(query, options)))
51
+ end
52
+
53
+ def self.get_options(query, options)
54
+ normalized_query = base_site.nil? ? query : "site:#{base_site} #{query}"
55
+ # TODO: will need seperate defaults when I fully support more than just web sources
56
+ config = { :app_id => app_id,
57
+ :disable_host_collapsing => true,
58
+ :sources => 'web',
59
+ :web_count => DEFAULT_COUNT,
60
+ :web_offset => 0,
61
+ :page => 1,
62
+ :query => normalized_query
63
+ }.update(options)
64
+ config[:page] = 1 if config[:page].to_i < 1
65
+ config[:web_offset] = config[:web_count] * (config[:page].to_i - 1)
66
+
67
+ raise 'You must set app_id in order to query live.com' if config[:app_id].nil?
68
+ dotted_params = %w{ ad image news mobile_web phonebook web video }
69
+ query_items = []
70
+ config.each_pair do |key, value|
71
+ if(/^(#{dotted_params.join('|')})/.match(key.to_s))
72
+ # most params are camelcase, except if they are Source specific. ex: Web.Count
73
+ first_key = $~[1]
74
+ second_key = key.to_s.sub("#{first_key}_", '')
75
+ query_items << "#{camelize(first_key)}.#{camelize(second_key)}=#{URI.encode(value.to_s)}"
76
+ else
77
+ query_items << "#{camelize(key.to_s)}=#{URI.encode(value.to_s)}"
78
+ end
79
+ end
80
+ query_items.join("&")
81
+ end
82
+
83
+ def self.camelize(str)
84
+ words = str.split(/_/)
85
+ words.inject("") {|camelized, word| camelized + word.capitalize }
86
+ end
87
+ end
88
+
89
+ class Response
90
+ require 'json'
91
+
92
+ def initialize(json, count)
93
+ @json = json
94
+ @count = count
95
+ end
96
+
97
+ def results
98
+ @results ||= get_results
99
+ end
100
+
101
+ def total_results
102
+ @total_results ||= get_total_results
103
+ end
104
+
105
+ def total_pages
106
+ total_results / @count
107
+ end
108
+
109
+ def current_page
110
+ (offset / @count) + 1
111
+ end
112
+
113
+ def previous_page
114
+ current_page > 1 ? (current_page - 1) : nil
115
+ end
116
+
117
+ def next_page
118
+ current_page < total_pages ? (current_page + 1) : nil
119
+ end
120
+
121
+ def offset
122
+ @offset ||= get_offset
123
+ end
124
+
125
+ private
126
+ def get_results
127
+ parsed_json["SearchResponse"]["Web"]["Results"].collect {|r| Result.new(r) } rescue []
128
+ end
129
+
130
+ def get_total_results
131
+ parsed_json["SearchResponse"]["Web"]["Total"] rescue 0
132
+ end
133
+
134
+ def get_offset
135
+ parsed_json["SearchResponse"]["Web"]["Offset"] rescue 0
136
+ end
137
+
138
+ def parsed_json
139
+ @parsed_json ||= JSON.parse(@json)
140
+ end
141
+ end
142
+
143
+ class Result
144
+ REQUIRED_ATTRIBUTES = %w{title description url}
145
+
146
+ def initialize(result_hash)
147
+ @data = result_hash
148
+ result_hash.each_pair do |key, value|
149
+ next if key == "SearchTags" || key == "DeepLinks" # not sure why this is returned. I don't want it :p
150
+ begin
151
+ instance_eval(<<-EOS, __FILE__, __LINE__)
152
+ def #{Result.rubyize(key)}
153
+ #{value.dump}
154
+ end
155
+ EOS
156
+ rescue Exception => e
157
+ puts "Bad Key: '#{key}' #{e.message}"
158
+ puts result_hash.inspect
159
+ end
160
+
161
+ # So in some unknown situations Bing does not return some attributes!
162
+ def method_missing(method_name, *args, &block)
163
+ return "" if REQUIRED_ATTRIBUTES.include?(method_name)
164
+ raise NoMethodError
165
+ end
166
+ end
167
+ end
168
+
169
+ def data
170
+ @data
171
+ end
172
+
173
+ private
174
+ def self.rubyize(str)
175
+ letters = str.split(/([A-Z])/).reject {|l| l == ""}
176
+ letters.inject("") {|rubyized, letter| (letter == letter.downcase) ? rubyized + letter + '_' : rubyized + letter.downcase }.chop
177
+ end
178
+ end
179
+ end
@@ -0,0 +1,23 @@
1
+ require 'test/unit'
2
+ require File.join(File.dirname(__FILE__), "..", "lib", "rubing")
3
+
4
+ class SearchTest < Test::Unit::TestCase
5
+ RuBing::Search::app_id = 'YOURAPPID'
6
+ RuBing::Search::base_site = 'learnhub.com'
7
+
8
+ def test_response
9
+ response = RuBing::Search.get('Ruby')
10
+ assert_not_nil response, "Should return a result"
11
+ assert response.total_results > 0, "Total results should be greater than zero"
12
+ end
13
+
14
+ def test_get_results
15
+ response = RuBing::Search.get('Ruby', {:web_count => 20})
16
+ assert_equal 20, response.results.length
17
+ end
18
+
19
+ def test_result_structure
20
+ response = RuBing::Search.get('Ruby')
21
+ assert response.results.first.methods.include?('url')
22
+ end
23
+ end
metadata ADDED
@@ -0,0 +1,81 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: RuBing
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 1
8
+ - 1
9
+ version: 0.1.1
10
+ platform: ruby
11
+ authors:
12
+ - Wesley Moxam
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-12-09 00:00:00 -05:00
18
+ default_executable:
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: json
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ none: false
25
+ requirements:
26
+ - - ">="
27
+ - !ruby/object:Gem::Version
28
+ segments:
29
+ - 1
30
+ - 1
31
+ - 0
32
+ version: 1.1.0
33
+ type: :runtime
34
+ version_requirements: *id001
35
+ description: A Ruby wrapper for Bing search API
36
+ email: wesley.moxam@savvica.com
37
+ executables: []
38
+
39
+ extensions: []
40
+
41
+ extra_rdoc_files: []
42
+
43
+ files:
44
+ - lib/rubing.rb
45
+ - test/test_search.rb
46
+ has_rdoc: true
47
+ homepage: http://github.com/wmoxam/RuBing
48
+ licenses: []
49
+
50
+ post_install_message:
51
+ rdoc_options: []
52
+
53
+ require_paths:
54
+ - lib
55
+ required_ruby_version: !ruby/object:Gem::Requirement
56
+ none: false
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ segments:
61
+ - 1
62
+ - 8
63
+ - 6
64
+ version: 1.8.6
65
+ required_rubygems_version: !ruby/object:Gem::Requirement
66
+ none: false
67
+ requirements:
68
+ - - ">="
69
+ - !ruby/object:Gem::Version
70
+ segments:
71
+ - 0
72
+ version: "0"
73
+ requirements: []
74
+
75
+ rubyforge_project:
76
+ rubygems_version: 1.3.7
77
+ signing_key:
78
+ specification_version: 3
79
+ summary: A Ruby wrapper for Bing search API
80
+ test_files: []
81
+