evri 0.03
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/History.txt +6 -0
- data/Manifest.txt +15 -0
- data/README.txt +48 -0
- data/Rakefile +22 -0
- data/TODO +13 -0
- data/evri-api.gemspec +39 -0
- data/lib/evri/entity.rb +240 -0
- data/lib/evri/media.rb +47 -0
- data/lib/evri/relation.rb +22 -0
- data/lib/evri/zeitgeist.rb +31 -0
- data/lib/evri.rb +144 -0
- data/test/test_entity.rb +144 -0
- data/test/test_evri.rb +35 -0
- data/test/test_media.rb +10 -0
- data/test/test_zeitgeist.rb +19 -0
- metadata +103 -0
data/History.txt
ADDED
data/Manifest.txt
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
History.txt
|
2
|
+
Manifest.txt
|
3
|
+
README.txt
|
4
|
+
Rakefile
|
5
|
+
TODO
|
6
|
+
evri-api.gemspec
|
7
|
+
lib/evri.rb
|
8
|
+
lib/evri/entity.rb
|
9
|
+
lib/evri/media.rb
|
10
|
+
lib/evri/relation.rb
|
11
|
+
lib/evri/zeitgeist.rb
|
12
|
+
test/test_entity.rb
|
13
|
+
test/test_evri.rb
|
14
|
+
test/test_media.rb
|
15
|
+
test/test_zeitgeist.rb
|
data/README.txt
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
= evri-api
|
2
|
+
|
3
|
+
* http://github.com/joevandyk/evri-api
|
4
|
+
|
5
|
+
== DESCRIPTION:
|
6
|
+
|
7
|
+
A beautiful API that wraps the RESTful services provided by evri.com.
|
8
|
+
|
9
|
+
== FEATURES/PROBLEMS:
|
10
|
+
|
11
|
+
None yet.
|
12
|
+
|
13
|
+
== SYNOPSIS:
|
14
|
+
|
15
|
+
None yet.
|
16
|
+
|
17
|
+
== REQUIREMENTS:
|
18
|
+
|
19
|
+
none yet.
|
20
|
+
|
21
|
+
== INSTALL:
|
22
|
+
|
23
|
+
gem install evri-api
|
24
|
+
|
25
|
+
== LICENSE:
|
26
|
+
|
27
|
+
(The MIT License)
|
28
|
+
|
29
|
+
Copyright (c) 2008 Joe Van Dyk
|
30
|
+
|
31
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
32
|
+
a copy of this software and associated documentation files (the
|
33
|
+
'Software'), to deal in the Software without restriction, including
|
34
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
35
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
36
|
+
permit persons to whom the Software is furnished to do so, subject to
|
37
|
+
the following conditions:
|
38
|
+
|
39
|
+
The above copyright notice and this permission notice shall be
|
40
|
+
included in all copies or substantial portions of the Software.
|
41
|
+
|
42
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
43
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
44
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
45
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
46
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
47
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
48
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
# -*- ruby -*-
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'hoe'
|
5
|
+
require './lib/evri.rb'
|
6
|
+
|
7
|
+
Hoe.new('evri', Evri::VERSION) do |p|
|
8
|
+
p.rubyforge_name = 'evri-api'
|
9
|
+
p.developer('Joe Van Dyk', 'joe@@fixieconsulting.com')
|
10
|
+
p.extra_deps = [:json]
|
11
|
+
p.extra_dev_deps = [:mocha]
|
12
|
+
end
|
13
|
+
|
14
|
+
task :github do
|
15
|
+
data = `rake check_manifest | sed 1d`
|
16
|
+
IO.popen("patch -p0 Manifest.txt", "w") do |p|
|
17
|
+
p << data
|
18
|
+
end
|
19
|
+
`rake debug_gem | sed 1d > evri-api.gemspec`
|
20
|
+
end
|
21
|
+
|
22
|
+
# vim: syntax=Ruby
|
data/TODO
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
STUFF LEFT TO DO
|
2
|
+
|
3
|
+
* Handle Query Tokens
|
4
|
+
- QTs are initially generated here:
|
5
|
+
- query token for whole medias/entity document
|
6
|
+
- query token for each entity in the returned results of ^
|
7
|
+
- query token for each pair of entities in above ^
|
8
|
+
- Then pass them into the calls that can take them (and handle the returned QTs)
|
9
|
+
|
10
|
+
* Refactor code to make Resource and JSON handling flexible (after API is done)
|
11
|
+
|
12
|
+
* Ability to batch requests (via threading)
|
13
|
+
- see how facebooker does it
|
data/evri-api.gemspec
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = %q{evri}
|
3
|
+
s.version = "0.03"
|
4
|
+
|
5
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
6
|
+
s.authors = ["Joe Van Dyk"]
|
7
|
+
s.date = %q{2008-10-27}
|
8
|
+
s.description = %q{A beautiful API that wraps the RESTful services provided by evri.com.}
|
9
|
+
s.email = ["joe@@fixieconsulting.com"]
|
10
|
+
s.extra_rdoc_files = ["History.txt", "Manifest.txt", "README.txt"]
|
11
|
+
s.files = ["History.txt", "Manifest.txt", "README.txt", "Rakefile", "TODO", "evri-api.gemspec", "lib/evri.rb", "lib/evri/entity.rb", "lib/evri/media.rb", "lib/evri/relation.rb", "lib/evri/zeitgeist.rb", "test/test_entity.rb", "test/test_evri.rb", "test/test_media.rb", "test/test_zeitgeist.rb"]
|
12
|
+
s.has_rdoc = true
|
13
|
+
s.homepage = %q{http://github.com/joevandyk/evri-api}
|
14
|
+
s.rdoc_options = ["--main", "README.txt"]
|
15
|
+
s.require_paths = ["lib"]
|
16
|
+
s.rubyforge_project = %q{evri}
|
17
|
+
s.rubygems_version = %q{1.2.0}
|
18
|
+
s.summary = %q{A beautiful API that wraps the RESTful services provided by evri.com.}
|
19
|
+
s.test_files = ["test/test_media.rb", "test/test_zeitgeist.rb", "test/test_entity.rb", "test/test_evri.rb"]
|
20
|
+
|
21
|
+
if s.respond_to? :specification_version then
|
22
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
23
|
+
s.specification_version = 2
|
24
|
+
|
25
|
+
if current_version >= 3 then
|
26
|
+
s.add_runtime_dependency(%q<json>, [">= 0"])
|
27
|
+
s.add_development_dependency(%q<mocha>, [">= 0"])
|
28
|
+
s.add_development_dependency(%q<hoe>, [">= 1.7.0"])
|
29
|
+
else
|
30
|
+
s.add_dependency(%q<json>, [">= 0"])
|
31
|
+
s.add_dependency(%q<mocha>, [">= 0"])
|
32
|
+
s.add_dependency(%q<hoe>, [">= 1.7.0"])
|
33
|
+
end
|
34
|
+
else
|
35
|
+
s.add_dependency(%q<json>, [">= 0"])
|
36
|
+
s.add_dependency(%q<mocha>, [">= 0"])
|
37
|
+
s.add_dependency(%q<hoe>, [">= 1.7.0"])
|
38
|
+
end
|
39
|
+
end
|
data/lib/evri/entity.rb
ADDED
@@ -0,0 +1,240 @@
|
|
1
|
+
module Evri
|
2
|
+
# Represents an Evri Entity.
|
3
|
+
class Entity
|
4
|
+
attr_reader :properties
|
5
|
+
|
6
|
+
# Finds a specific entity, given an ID.
|
7
|
+
def self.find id
|
8
|
+
@entended_properties = true
|
9
|
+
@results ||= {}
|
10
|
+
id = "/" + id unless id =~ /\A\//
|
11
|
+
return @results[id] if @results[id]
|
12
|
+
@results[id] = create_from_json do
|
13
|
+
Evri.query(:type => :uri, :query => id)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
# Searches for an exact match.
|
18
|
+
def self.search name
|
19
|
+
create_from_jsons do
|
20
|
+
Evri.query(:type => :search, :query => name)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# Searches for a partial match. i.e. 'ob' will return 'Obama'.
|
25
|
+
def self.search_by_prefix prefix
|
26
|
+
create_from_jsons do
|
27
|
+
Evri.query(:type => :prefix, :query => prefix)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
# Given a :uri and :text options, return the related entities.
|
32
|
+
def self.from_media options={}
|
33
|
+
uri, text = options[:uri], options[:text]
|
34
|
+
raise ArgumentError, "Must specify URI via the :uri option" unless uri
|
35
|
+
raise ArgumentError, "Must specify some text via the :text option" unless text
|
36
|
+
|
37
|
+
json = Evri.parse_json(Evri.query(:type => :from_media, :uri => uri, :text => text))
|
38
|
+
json["graph"]["entities"].map do |e, entity_json|
|
39
|
+
Entity.new entity_json
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
# Returns where the information for this entity came from.
|
44
|
+
def source_url
|
45
|
+
@source_url
|
46
|
+
end
|
47
|
+
|
48
|
+
# Returns information about an entity.
|
49
|
+
# i.e obama.info(:birth_date)
|
50
|
+
def info option=nil
|
51
|
+
@properties ||= {}
|
52
|
+
if defined?(@extended_properties)
|
53
|
+
if option
|
54
|
+
@properties[option]
|
55
|
+
else
|
56
|
+
@properties
|
57
|
+
end
|
58
|
+
else
|
59
|
+
@properties = Entity.find(uri).properties
|
60
|
+
@extended_properties = true
|
61
|
+
info(option)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def to_s
|
66
|
+
"#{name} (#{ id })"
|
67
|
+
end
|
68
|
+
|
69
|
+
def inspect
|
70
|
+
"#<Evri::Entity:#{to_s}>"
|
71
|
+
end
|
72
|
+
|
73
|
+
# Returns the name of the entity
|
74
|
+
def name
|
75
|
+
@parsed_json["name"]["$"] || @parsed_json["name"]
|
76
|
+
end
|
77
|
+
|
78
|
+
def initialize json
|
79
|
+
@parsed_json = json
|
80
|
+
@relations = []
|
81
|
+
@source_url = Evri.source_url
|
82
|
+
if json["properties"]
|
83
|
+
set_properties json["properties"]
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def == b
|
88
|
+
self.id == b.id
|
89
|
+
end
|
90
|
+
|
91
|
+
# Returns the Evri URI of the entity
|
92
|
+
def href
|
93
|
+
@parsed_json["@href"]
|
94
|
+
end
|
95
|
+
|
96
|
+
alias id href
|
97
|
+
alias uri href
|
98
|
+
|
99
|
+
# TODO
|
100
|
+
def target_href
|
101
|
+
@parsed_json["@targetHref"]
|
102
|
+
end
|
103
|
+
|
104
|
+
# Returns relationships for the entity
|
105
|
+
def relations options={}
|
106
|
+
from_domains = nil
|
107
|
+
if options[:from]
|
108
|
+
if options[:from].class == String
|
109
|
+
from_domains = options[:from]
|
110
|
+
else
|
111
|
+
from_domains = options[:from].join(',')
|
112
|
+
end
|
113
|
+
end
|
114
|
+
json = Evri.query(:type => :relations, :query => id, :from_domains => from_domains)
|
115
|
+
Evri.parse_json(json)["relations"].each do |type, relation_json|
|
116
|
+
next if type != 'relation'
|
117
|
+
relation_json.each do |r|
|
118
|
+
@relations << Relation.new(r)
|
119
|
+
end
|
120
|
+
end
|
121
|
+
@relations
|
122
|
+
end
|
123
|
+
|
124
|
+
# Returns which entities are related to the current entity
|
125
|
+
def related_by options={}
|
126
|
+
media, verb, verb_value, entity, uri = nil, nil, nil, nil, nil
|
127
|
+
options.each do |key, value|
|
128
|
+
if key == :entity
|
129
|
+
entity = value
|
130
|
+
elsif key == :uri
|
131
|
+
uri = value
|
132
|
+
elsif key == :type
|
133
|
+
media = value
|
134
|
+
else
|
135
|
+
verb = key
|
136
|
+
verb_value = value
|
137
|
+
end
|
138
|
+
end
|
139
|
+
@entities = []
|
140
|
+
json = Evri.query(:type => :related_by, :media => media, :query => id, :uri => uri, :entity => entity, :verb => verb, :value => verb_value)
|
141
|
+
Evri.parse_json(json)["relations"].each do |type, relation_json|
|
142
|
+
next if type != 'relation'
|
143
|
+
relation_json["targets"].each do |type, r|
|
144
|
+
r.each do |entity|
|
145
|
+
if entity.class == Hash
|
146
|
+
if entity["@href"]
|
147
|
+
@entities << Entity.new(entity)
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
@entities
|
154
|
+
end
|
155
|
+
|
156
|
+
# Returns images relating to the current entity
|
157
|
+
def images options={}
|
158
|
+
medias = []
|
159
|
+
if options[:entities]
|
160
|
+
entity_uris = options[:entities].map do |e|
|
161
|
+
if e.class == Evri::Entity
|
162
|
+
e.uri
|
163
|
+
else
|
164
|
+
e
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
json = Evri.parse_json(Evri.query(:type => :related_medias, :query => href, :entities => entity_uris, :media => 'image'))
|
170
|
+
# TODO handle images here
|
171
|
+
if json["mediaResult"]["imageList"]
|
172
|
+
json["mediaResult"]["imageList"]["image"].each do |media_json|
|
173
|
+
medias << Image.new(media_json)
|
174
|
+
end
|
175
|
+
end
|
176
|
+
medias
|
177
|
+
end
|
178
|
+
|
179
|
+
# Returns articles relating to the current entity
|
180
|
+
def articles options={}
|
181
|
+
medias = []
|
182
|
+
if options[:entities]
|
183
|
+
entity_uris = options[:entities].map do |e|
|
184
|
+
if e.class == Evri::Entity
|
185
|
+
e.uri
|
186
|
+
else
|
187
|
+
e
|
188
|
+
end
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
type = options[:type] ? options[:type] : nil
|
193
|
+
json = Evri.parse_json(Evri.query(:type => :related_medias, :query => href, :entities => entity_uris, :media => type))
|
194
|
+
if json["mediaResult"]["articleList"]
|
195
|
+
json["mediaResult"]["articleList"]["article"].each do |media_json|
|
196
|
+
medias << Article.new(media_json)
|
197
|
+
end
|
198
|
+
end
|
199
|
+
medias
|
200
|
+
end
|
201
|
+
|
202
|
+
|
203
|
+
private
|
204
|
+
|
205
|
+
def self.create_from_json json=nil, &block
|
206
|
+
begin
|
207
|
+
json = block.call if block
|
208
|
+
Entity.new Evri.parse_json(json)["entity"]
|
209
|
+
rescue Evri::Error => e
|
210
|
+
raise Evri::EntityNotFound.new(e.message)
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
def self.create_from_jsons jsons=nil, &block
|
215
|
+
jsons = block.call if block
|
216
|
+
result = []
|
217
|
+
Evri.parse_json(jsons)["entities"].each do |type, entity|
|
218
|
+
if entity.class == Array
|
219
|
+
entity.each do |e|
|
220
|
+
result << Entity.new(e)
|
221
|
+
end
|
222
|
+
else
|
223
|
+
result << Entity.new(entity)
|
224
|
+
end
|
225
|
+
end
|
226
|
+
result
|
227
|
+
end
|
228
|
+
|
229
|
+
def set_properties json
|
230
|
+
@properties = {}
|
231
|
+
json["property"].each do |prop|
|
232
|
+
if prop.class == Array
|
233
|
+
@properties[prop.first.to_sym] = prop.last["$"]
|
234
|
+
else
|
235
|
+
@properties[prop["name"]["$"].to_sym] = prop["value"]["$"]
|
236
|
+
end
|
237
|
+
end
|
238
|
+
end
|
239
|
+
end
|
240
|
+
end
|
data/lib/evri/media.rb
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
module Evri
|
2
|
+
class Media
|
3
|
+
end
|
4
|
+
|
5
|
+
# Represents an Article.
|
6
|
+
class Article < Media
|
7
|
+
attr_accessor :title, :href, :uri, :author, :published_at, :content
|
8
|
+
def initialize json
|
9
|
+
@title = json["title"]["$"]
|
10
|
+
@author = json["author"]["$"]
|
11
|
+
@content = json["content"] ? json["content"]["$"] : "No content provided"
|
12
|
+
@published_at = json["published"]["$"]
|
13
|
+
@href = Evri.api_host + json["link"]["@href"]
|
14
|
+
@uri = json["link"]["@hostName"] + json["link"]["@path"]
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
# Represents an Image.
|
19
|
+
class Image < Media
|
20
|
+
attr_accessor :size, :title, :article_href, :mime_type, :thumbnail, :date, :content, :width, :url, :click_url, :height
|
21
|
+
def initialize json
|
22
|
+
@title = json["title"]
|
23
|
+
@width = json["@width"]
|
24
|
+
@height = json["@height"]
|
25
|
+
@url = json["@url"]
|
26
|
+
@size = json["size"]
|
27
|
+
@title = json["title"]
|
28
|
+
@article_href = json["articleHref"]["$"]
|
29
|
+
@mime_type = json["mimeType"]
|
30
|
+
@date = Date.parse(json["date"]["$"])
|
31
|
+
@content = json["content"]["$"]
|
32
|
+
@click_url = json["clickUrl"]["$"]
|
33
|
+
@thumbnail = Thumbnail.new(json["thumbnail"])
|
34
|
+
end
|
35
|
+
|
36
|
+
# Represents an Thumbnail for an Image.
|
37
|
+
class Thumbnail
|
38
|
+
attr_accessor :size, :width, :height, :url
|
39
|
+
def initialize json
|
40
|
+
@size = json["size"]
|
41
|
+
@width = json["@width"]
|
42
|
+
@height = json["@height"]
|
43
|
+
@url = json["@url"]
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Evri
|
2
|
+
# Represents a relation.
|
3
|
+
class Relation
|
4
|
+
attr_accessor :name, :href, :type
|
5
|
+
def initialize json
|
6
|
+
@name = json["name"]["$"]
|
7
|
+
@href = json["@href"]
|
8
|
+
@type = json["type"]["$"]
|
9
|
+
@entities = []
|
10
|
+
end
|
11
|
+
|
12
|
+
# Returns the entities in this relation.
|
13
|
+
def entities
|
14
|
+
return @entities unless @entities.empty?
|
15
|
+
json = JSON.parse(Evri.query(:type => :uri, :query => @href))
|
16
|
+
json["relations"]["relation"]["targets"]["entity"].each do |entity_json|
|
17
|
+
@entities << Entity.new(entity_json)
|
18
|
+
end
|
19
|
+
@entities
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Evri
|
2
|
+
# Returns information about a specific trend.
|
3
|
+
#
|
4
|
+
# To access the information, combine a TREND with a TYPE to form a class method.
|
5
|
+
#
|
6
|
+
# i.e.
|
7
|
+
#
|
8
|
+
# * Zeitgeist.all_chemical
|
9
|
+
# * Zeitgeist.falling_person
|
10
|
+
# * Zeitgeist.popular_organization
|
11
|
+
#
|
12
|
+
# etc
|
13
|
+
class Zeitgeist
|
14
|
+
|
15
|
+
TYPES = %w( animal backterium chemical concept disorder event location organization person plant product virus )
|
16
|
+
TRENDS = %w( all popular rising falling )
|
17
|
+
|
18
|
+
TRENDS.each do |t|
|
19
|
+
TYPES.each do |et|
|
20
|
+
eval %(
|
21
|
+
def self.#{t}_#{et}
|
22
|
+
json = Evri.parse_json(Evri.query :type => :zeitgeist, :query => "#{et}/#{t}")
|
23
|
+
json["zeitgeist"]["#{t}"]["entities"]["entity"].map do |entity_json|
|
24
|
+
Entity.new(entity_json)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
data/lib/evri.rb
ADDED
@@ -0,0 +1,144 @@
|
|
1
|
+
$: << File.dirname(__FILE__)
|
2
|
+
|
3
|
+
require 'uri'
|
4
|
+
require 'net/http'
|
5
|
+
require 'cgi'
|
6
|
+
|
7
|
+
begin
|
8
|
+
require 'rubygems'
|
9
|
+
rescue LoadError
|
10
|
+
nil
|
11
|
+
end
|
12
|
+
|
13
|
+
require 'json'
|
14
|
+
|
15
|
+
for file in Dir[File.join(File.dirname(__FILE__), 'evri', '*')]
|
16
|
+
require file
|
17
|
+
end
|
18
|
+
|
19
|
+
module Evri
|
20
|
+
|
21
|
+
# A general error.
|
22
|
+
class Error < Exception; end
|
23
|
+
|
24
|
+
# Raised whenever the entity you are searching for cannot be found.
|
25
|
+
class EntityNotFound < Error; end
|
26
|
+
|
27
|
+
VERSION = "0.03"
|
28
|
+
@@api_host = "api.evri.com"
|
29
|
+
@@source_host = @@api_host
|
30
|
+
@@source_url = nil
|
31
|
+
|
32
|
+
# Sets the hostname for the Evri API.
|
33
|
+
def self.api_host= host
|
34
|
+
@@api_host = validate_host(host)
|
35
|
+
end
|
36
|
+
|
37
|
+
# Returns the hostname for the Evri API.
|
38
|
+
def self.api_host
|
39
|
+
@@api_host
|
40
|
+
end
|
41
|
+
|
42
|
+
# Returns the source host for the Evri API
|
43
|
+
def self.source_host
|
44
|
+
@@source_host
|
45
|
+
end
|
46
|
+
|
47
|
+
# Returns the source host for the Evri API
|
48
|
+
def self.source_host= host
|
49
|
+
@@source_host = validate_host(host)
|
50
|
+
end
|
51
|
+
|
52
|
+
# Returns the source url for the Evri API
|
53
|
+
def self.source_url
|
54
|
+
@@source_url
|
55
|
+
end
|
56
|
+
|
57
|
+
# Parses JSON data
|
58
|
+
def self.parse_json json
|
59
|
+
begin
|
60
|
+
JSON.parse(json)
|
61
|
+
rescue JSON::ParserError => e
|
62
|
+
# puts "Error!"
|
63
|
+
# puts e.message
|
64
|
+
# puts json
|
65
|
+
raise Error.new(e)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
# TODO Rewrite
|
70
|
+
def self.query options={}
|
71
|
+
query = ""
|
72
|
+
case options[:type]
|
73
|
+
when :uri
|
74
|
+
path = options[:query]
|
75
|
+
when :relations
|
76
|
+
path = options[:query] + "/relations"
|
77
|
+
if options[:from_domains]
|
78
|
+
query = "includeDomain=#{options[:from_domains]}"
|
79
|
+
end
|
80
|
+
when :related_by
|
81
|
+
if options[:uri]
|
82
|
+
path = options[:query] + "/related/entities"
|
83
|
+
query = "uri=#{escape(options[:uri])}"
|
84
|
+
else
|
85
|
+
path = options[:query] + "/relations"
|
86
|
+
if options[:verb]
|
87
|
+
path += "/#{options[:verb]}/#{escape(options[:value])}"
|
88
|
+
if options[:entity]
|
89
|
+
path += options[:entity].href
|
90
|
+
end
|
91
|
+
end
|
92
|
+
if options[:media]
|
93
|
+
query += "media=#{options[:media]}"
|
94
|
+
end
|
95
|
+
end
|
96
|
+
when :zeitgeist
|
97
|
+
path = "/zeitgeist/entities/" + options[:query]
|
98
|
+
when :related_medias
|
99
|
+
path = options[:query] + "/media/related"
|
100
|
+
if options[:entities]
|
101
|
+
query = options[:entities].map do |e|
|
102
|
+
"entityURI=#{e}&"
|
103
|
+
end
|
104
|
+
query = query.join
|
105
|
+
end
|
106
|
+
query += "type=#{options[:media]}" if options[:media]
|
107
|
+
when :from_media
|
108
|
+
path = "/media/entities"
|
109
|
+
query = "uri=#{escape(options[:uri])}&text=#{escape(options[:text])}"
|
110
|
+
when :search
|
111
|
+
path = "/entities/find"
|
112
|
+
query = "name=#{escape(options[:query])}"
|
113
|
+
when :prefix
|
114
|
+
path = "/entities/find"
|
115
|
+
query = "prefix=#{escape(options[:query])}"
|
116
|
+
else
|
117
|
+
raise ArgumentError, "unexpected type #{ options[:type] }"
|
118
|
+
end
|
119
|
+
query = nil if query.empty?
|
120
|
+
uri = URI::HTTP.build :host => self.api_host, :path => path + '.json', :query => query
|
121
|
+
# puts "getting #{ uri }"
|
122
|
+
response = Net::HTTP.get_response(uri)
|
123
|
+
raise Error.new("unexpected http response: #{ response.code }") unless response.code == "200"
|
124
|
+
@@source_url = @@source_host + uri.request_uri
|
125
|
+
response.body
|
126
|
+
end
|
127
|
+
|
128
|
+
# Escapes CGI text
|
129
|
+
def self.escape text
|
130
|
+
text ? CGI.escape(text.to_s) : ''
|
131
|
+
end
|
132
|
+
|
133
|
+
private
|
134
|
+
|
135
|
+
def self.validate_host host
|
136
|
+
host = host.to_s
|
137
|
+
begin
|
138
|
+
URI::HTTP.build(:host => host)
|
139
|
+
host
|
140
|
+
rescue URI::InvalidComponentError
|
141
|
+
raise ArgumentError.new("Invalid host name specified (#{host}). Use something like 'api.evri.com'")
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
data/test/test_entity.rb
ADDED
@@ -0,0 +1,144 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'lib/evri'
|
3
|
+
require 'mocha'
|
4
|
+
|
5
|
+
class TestEntity < Test::Unit::TestCase
|
6
|
+
BARACK_ID = "/person/barack-obama-0x16f69"
|
7
|
+
MICHELLE_ID = "person/michelle-obama-0x4c6e8" # Works without leading slash
|
8
|
+
MCCAIN_ID = "/person/john-mccain-0x2a2a7"
|
9
|
+
|
10
|
+
def setup
|
11
|
+
@obama = Evri::Entity.find BARACK_ID
|
12
|
+
@michelle = Evri::Entity.find MICHELLE_ID
|
13
|
+
@mccain = Evri::Entity.find MCCAIN_ID
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_failed_http_get_raises_good_error
|
17
|
+
bad_response = stub(:code => "500")
|
18
|
+
Net::HTTP.expects(:get_response).returns(bad_response)
|
19
|
+
assert_raises(Evri::Error) { @obama.relations }
|
20
|
+
end
|
21
|
+
|
22
|
+
# Ensure that when we search for Barack, we get the @obama and @michelle objects returned
|
23
|
+
def test_class_find
|
24
|
+
results = Evri::Entity.search "obama"
|
25
|
+
[@obama, @michelle].each do |person|
|
26
|
+
assert results.include?(person), "Expected search to contain #{ person }"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_find_raises_for_missing_ids
|
31
|
+
assert_raises(Evri::EntityNotFound) { Evri::Entity.find "crap" }
|
32
|
+
end
|
33
|
+
|
34
|
+
def test_failed_search_returns_empty_array
|
35
|
+
assert Evri::Entity.search("asdfasdfasdfasdfjlskdjflkasdjfkljasdklfjkladsjfklajsdl;kfjlaksdjfadklsjfkladsjlfkjasdfkljas#").empty?
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_class_find_with_prefix
|
39
|
+
results = Evri::Entity.search_by_prefix "ob"
|
40
|
+
assert results.include?(@obama), "Expected search to contain #{ @obama }"
|
41
|
+
end
|
42
|
+
|
43
|
+
def test_name
|
44
|
+
assert_equal @obama.name, "Barack Obama"
|
45
|
+
end
|
46
|
+
|
47
|
+
def test_id
|
48
|
+
assert_equal @obama.id, BARACK_ID
|
49
|
+
end
|
50
|
+
|
51
|
+
def test_properties
|
52
|
+
vandyk_parks = Evri::Entity.find "/person/van-dyke-parks-0x16b10"
|
53
|
+
assert vandyk_parks.info(:occupation).include?("Composer")
|
54
|
+
end
|
55
|
+
|
56
|
+
def test_properties_from_search
|
57
|
+
vandyk_parks = Evri::Entity.search_by_prefix("van dyke parks").first
|
58
|
+
assert vandyk_parks.info(:occupation).include?("Composer")
|
59
|
+
end
|
60
|
+
|
61
|
+
def test_properties_from_related_by
|
62
|
+
loaded_entity = @obama.related_by(:verb => :kill).first
|
63
|
+
assert loaded_entity.info(:name)
|
64
|
+
end
|
65
|
+
|
66
|
+
def test_relations
|
67
|
+
assert @obama.relations.find { |r| r.name == "US Politician" }
|
68
|
+
assert @obama.relations.find { |r| r.href == "#{@obama.href}/relations/facet/politician" }
|
69
|
+
end
|
70
|
+
|
71
|
+
def test_related_by_from_uri
|
72
|
+
# Sends right data, but bug in API prevents it from knowing about the URI
|
73
|
+
# assert !@obama.related_by(:uri => "www.boston.com/news/nation/articles/2008/10/23/obama_takes_campaign_break_to_visit_ill_grandmother/?rss_id=Boston.com+--+Latest+news")
|
74
|
+
end
|
75
|
+
|
76
|
+
def test_relations_from_domains
|
77
|
+
assert !@obama.relations(:from => "time.com").empty?
|
78
|
+
assert !@obama.relations(:from => ["time.com", "nytimes.com"]).empty?
|
79
|
+
end
|
80
|
+
|
81
|
+
def test_relations_with_type
|
82
|
+
# TODO tests
|
83
|
+
@obama.related_by(:verb => :kill, :type => :image)
|
84
|
+
end
|
85
|
+
|
86
|
+
def test_relations_related_to
|
87
|
+
# TODO tests
|
88
|
+
@obama.related_by(:facet => :musical_artist)
|
89
|
+
@obama.related_by(:qt => "joined-by-0x78")
|
90
|
+
@mccain.related_by(:verb => :kill, :entity => @obama)
|
91
|
+
@obama.related_by(:facet => :politician, :entity => @mccain)
|
92
|
+
end
|
93
|
+
|
94
|
+
def test_source_url
|
95
|
+
dude = @obama.related_by(:facet => :politician).first
|
96
|
+
assert_equal "#{Evri.source_host}#{@obama.uri}/relations/facet/politician.json", dude.source_url
|
97
|
+
end
|
98
|
+
|
99
|
+
def test_media_related_to_entities_about_an_entity
|
100
|
+
# articles takes either entities or entity URIs
|
101
|
+
# NOTE: the plural of 'media' is 'media'
|
102
|
+
medias = @obama.articles(:entities => [@mccain, "/person/bill-ayers-0x27a65"])
|
103
|
+
assert medias.size > 1
|
104
|
+
end
|
105
|
+
|
106
|
+
def test_medias_with_type_of_image
|
107
|
+
image = @obama.images.first
|
108
|
+
%w( size title article_href mime_type thumbnail date content width url click_url height).each do |field|
|
109
|
+
assert image.send(field), "Expected #{ image.inspect }'s #{ field } field to be larger than zero"
|
110
|
+
end
|
111
|
+
%w( size width height url).each do |field|
|
112
|
+
assert image.thumbnail.send(field), "Expected #{ image.thumbnail.inspect }'s #{ field } field to be larger than zero"
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
def test_relations_loading
|
117
|
+
politician_relation = @obama.relations.find { |r| r.name == "US Politician" }
|
118
|
+
assert politician_relation.entities.include?(@mccain)
|
119
|
+
end
|
120
|
+
|
121
|
+
def test_relations_with_verb
|
122
|
+
entities = @obama.related_by(:verb => :attack)
|
123
|
+
assert entities.first.target_href.include?("attack")
|
124
|
+
|
125
|
+
assert @obama.related_by(:qt => "joined-by-0x78").find { |e| e.name == "Joe Biden" }
|
126
|
+
|
127
|
+
assert @obama.related_by(:facet => :politician).include?(@mccain)
|
128
|
+
end
|
129
|
+
|
130
|
+
def test_media
|
131
|
+
media = @obama.articles.first
|
132
|
+
# check for media.title, media.uri, etc
|
133
|
+
%w( title author published_at content href uri).each do |field|
|
134
|
+
assert media.send(field).size > 0, "Expected #{ media.inspect }'s #{ field } field to be larger than zero"
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
def test_find_by_media
|
139
|
+
uri = "http://www.reuters.com/article/industryNews/idUSTRE4981RO20081009"
|
140
|
+
dreamworks = Evri::Entity.find "/organization/dreamworks-0x3c510"
|
141
|
+
entities = Evri::Entity.from_media(:uri => uri, :text => "Dreamworks")
|
142
|
+
assert entities.include?(dreamworks)
|
143
|
+
end
|
144
|
+
end
|
data/test/test_evri.rb
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'lib/evri'
|
3
|
+
require 'mocha'
|
4
|
+
|
5
|
+
class TestModuleEvri < Test::Unit::TestCase
|
6
|
+
def test_setting_invalid_new_api_host
|
7
|
+
remember_original_settings(:api_host) do
|
8
|
+
assert_raise(ArgumentError) { Evri.api_host = "http://slashdot.org" }
|
9
|
+
assert_raise(ArgumentError) { Evri.api_host = "Joe's Cat" }
|
10
|
+
assert_raise(ArgumentError) { Evri.api_host = 3 }
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_setting_new_api_host
|
15
|
+
remember_original_settings(:api_host) do
|
16
|
+
Evri.api_host = "new.api.evri.com"
|
17
|
+
assert_equal Evri.api_host, "new.api.evri.com"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_source_host
|
22
|
+
remember_original_settings(:source_host) do
|
23
|
+
Evri.source_host = "new.api.evri.com"
|
24
|
+
assert_equal Evri.source_host, "new.api.evri.com"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def remember_original_settings method
|
31
|
+
original = Evri.send method
|
32
|
+
yield ensure Evri.send"#{method}=", original
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
data/test/test_media.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'lib/evri'
|
3
|
+
|
4
|
+
class TestZeitgeist < Test::Unit::TestCase
|
5
|
+
BARACK_ID = "person/barack-obama-0x16f69"
|
6
|
+
|
7
|
+
def setup
|
8
|
+
@obama = Evri::Entity.find BARACK_ID
|
9
|
+
end
|
10
|
+
|
11
|
+
def test_popular_person
|
12
|
+
assert Evri::Zeitgeist.popular_person.include?(@obama)
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_falling_product
|
16
|
+
# just check to see that the first falling product's name is not blank.
|
17
|
+
assert Evri::Zeitgeist.falling_product.first.name.size > 0
|
18
|
+
end
|
19
|
+
end
|
metadata
ADDED
@@ -0,0 +1,103 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: evri
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: "0.03"
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Joe Van Dyk
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2008-10-31 00:00:00 -07:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: :json
|
17
|
+
type: :runtime
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: "0"
|
24
|
+
version:
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: :mocha
|
27
|
+
type: :development
|
28
|
+
version_requirement:
|
29
|
+
version_requirements: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: "0"
|
34
|
+
version:
|
35
|
+
- !ruby/object:Gem::Dependency
|
36
|
+
name: hoe
|
37
|
+
type: :development
|
38
|
+
version_requirement:
|
39
|
+
version_requirements: !ruby/object:Gem::Requirement
|
40
|
+
requirements:
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: 1.8.2
|
44
|
+
version:
|
45
|
+
description: A beautiful API that wraps the RESTful services provided by evri.com.
|
46
|
+
email:
|
47
|
+
- joe@@fixieconsulting.com
|
48
|
+
executables: []
|
49
|
+
|
50
|
+
extensions: []
|
51
|
+
|
52
|
+
extra_rdoc_files:
|
53
|
+
- History.txt
|
54
|
+
- Manifest.txt
|
55
|
+
- README.txt
|
56
|
+
files:
|
57
|
+
- History.txt
|
58
|
+
- Manifest.txt
|
59
|
+
- README.txt
|
60
|
+
- Rakefile
|
61
|
+
- TODO
|
62
|
+
- evri-api.gemspec
|
63
|
+
- lib/evri.rb
|
64
|
+
- lib/evri/entity.rb
|
65
|
+
- lib/evri/media.rb
|
66
|
+
- lib/evri/relation.rb
|
67
|
+
- lib/evri/zeitgeist.rb
|
68
|
+
- test/test_entity.rb
|
69
|
+
- test/test_evri.rb
|
70
|
+
- test/test_media.rb
|
71
|
+
- test/test_zeitgeist.rb
|
72
|
+
has_rdoc: true
|
73
|
+
homepage: http://github.com/joevandyk/evri-api
|
74
|
+
post_install_message:
|
75
|
+
rdoc_options:
|
76
|
+
- --main
|
77
|
+
- README.txt
|
78
|
+
require_paths:
|
79
|
+
- lib
|
80
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
81
|
+
requirements:
|
82
|
+
- - ">="
|
83
|
+
- !ruby/object:Gem::Version
|
84
|
+
version: "0"
|
85
|
+
version:
|
86
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
87
|
+
requirements:
|
88
|
+
- - ">="
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
version: "0"
|
91
|
+
version:
|
92
|
+
requirements: []
|
93
|
+
|
94
|
+
rubyforge_project: evri-api
|
95
|
+
rubygems_version: 1.2.0
|
96
|
+
signing_key:
|
97
|
+
specification_version: 2
|
98
|
+
summary: A beautiful API that wraps the RESTful services provided by evri.com.
|
99
|
+
test_files:
|
100
|
+
- test/test_entity.rb
|
101
|
+
- test/test_evri.rb
|
102
|
+
- test/test_zeitgeist.rb
|
103
|
+
- test/test_media.rb
|