factual-api 0.1 → 0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.md +3 -0
- data/README.md +6 -2
- data/lib/factual_api.rb +112 -102
- metadata +1 -1
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -51,16 +51,20 @@ This is the Factual supported Ruby driver for [Factual's public API](http://deve
|
|
51
51
|
|
52
52
|
# Concordance information of a place
|
53
53
|
FACTUAL_ID = "110ace9f-80a7-47d3-9170-e9317624ebd9"
|
54
|
-
factual.crosswalk(FACTUAL_ID)
|
54
|
+
query = factual.crosswalk(FACTUAL_ID)
|
55
|
+
query.rows
|
55
56
|
|
56
57
|
## Resolve
|
57
58
|
|
58
59
|
# Returns resolved entities as Factual::Row objects
|
59
|
-
factual.resolve("name" => "McDonalds",
|
60
|
+
query = factual.resolve("name" => "McDonalds",
|
60
61
|
"address" => "10451 Santa Monica Blvd",
|
61
62
|
"region" => "CA",
|
62
63
|
"postcode" => "90025")
|
63
64
|
|
65
|
+
query.first.resolved # true or false
|
66
|
+
query.rows # resolved rows
|
67
|
+
|
64
68
|
## Schema
|
65
69
|
|
66
70
|
# Returns a Factual::Table object whose fields are an array of Factual::Field objects
|
data/lib/factual_api.rb
CHANGED
@@ -5,11 +5,65 @@ require 'ostruct'
|
|
5
5
|
|
6
6
|
module Factual
|
7
7
|
class Api
|
8
|
-
API_V3_HOST
|
8
|
+
API_V3_HOST = "http://api.v3.factual.com"
|
9
9
|
DRIVER_VERSION_TAG = "factual-ruby-driver-1.0"
|
10
|
+
PARAM_ALIASES = { :search => :q }
|
10
11
|
|
12
|
+
# initializers
|
13
|
+
# ----------------
|
14
|
+
def initialize(key, secret)
|
15
|
+
@access_token = OAuth::AccessToken.new(
|
16
|
+
OAuth::Consumer.new(key, secret))
|
17
|
+
end
|
18
|
+
|
19
|
+
# actions
|
20
|
+
# ----------------
|
21
|
+
def crosswalk(factual_id, format = :object)
|
22
|
+
query = Query.new(self, :crosswalk, "places/crosswalk", { :factual_id => factual_id }, format)
|
23
|
+
|
24
|
+
return query
|
25
|
+
end
|
26
|
+
|
27
|
+
def resolve(values, format = :object)
|
28
|
+
query = Query.new(self, :resolve, "places/resolve", { :values => values }, format)
|
29
|
+
|
30
|
+
return query
|
31
|
+
end
|
32
|
+
|
33
|
+
def table(table_id_or_alias, format = :object)
|
34
|
+
query = Query.new(self, :read, "t/#{table_id_or_alias}", Hash.new, format)
|
35
|
+
|
36
|
+
return query
|
37
|
+
end
|
38
|
+
|
39
|
+
# requesting
|
40
|
+
# ----------------
|
41
|
+
def request(path, params)
|
42
|
+
url = "#{API_V3_HOST}/#{path}?#{query_string(params)}"
|
43
|
+
headers = {"X-Factual-Lib" => DRIVER_VERSION_TAG}
|
44
|
+
|
45
|
+
return @access_token.get(url, headers)
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
def query_string(params)
|
51
|
+
arr = []
|
52
|
+
params.each do |param, v|
|
53
|
+
param_alias = PARAM_ALIASES[param.to_sym] || param.to_sym
|
54
|
+
|
55
|
+
v = v.to_json if v.class == Hash
|
56
|
+
arr << "#{param_alias}=#{URI.escape(v.to_s)}"
|
57
|
+
end
|
58
|
+
return arr.join("&")
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
62
|
+
|
63
|
+
class Query
|
64
|
+
|
65
|
+
# helper functions
|
11
66
|
DEFAULT_LIMIT = 20
|
12
|
-
PARAM_ALIASES = { :search => :q }
|
13
67
|
|
14
68
|
VALID_PARAMS = {
|
15
69
|
:read => [ :filters, :search, :geo, :sort, :select, :limit, :offset ],
|
@@ -20,30 +74,24 @@ module Factual
|
|
20
74
|
:any => [ :include_count ]
|
21
75
|
}
|
22
76
|
|
23
|
-
attr_accessor :
|
77
|
+
attr_accessor :params
|
24
78
|
|
25
79
|
# initializers
|
26
80
|
# ----------------
|
27
|
-
def initialize(
|
28
|
-
@
|
29
|
-
|
30
|
-
|
81
|
+
def initialize(api, action, path, params = nil, format = :object)
|
82
|
+
@api = api
|
83
|
+
@action = action
|
84
|
+
@path = path
|
85
|
+
@params = params || Hash.new
|
31
86
|
@format = format
|
32
|
-
@params = Hash.new
|
33
87
|
end
|
34
88
|
|
35
89
|
# helper functions
|
36
90
|
# ----------------
|
37
|
-
def
|
38
|
-
|
39
|
-
|
40
|
-
new_api.access_token = api.access_token
|
41
|
-
new_api.path = api.path
|
42
|
-
new_api.action = api.action
|
43
|
-
new_api.format = api.format
|
44
|
-
new_api.params = api.params.clone
|
91
|
+
def clone
|
92
|
+
new_query = self.class.new(@api, @action, @path, @params.clone, @format)
|
45
93
|
|
46
|
-
return
|
94
|
+
return new_query
|
47
95
|
end
|
48
96
|
|
49
97
|
def set_param(key, value)
|
@@ -53,20 +101,35 @@ module Factual
|
|
53
101
|
# attributes, after 'get'
|
54
102
|
# ----------------
|
55
103
|
def first
|
56
|
-
row_data =
|
104
|
+
row_data = read_response["data"].first
|
57
105
|
|
58
|
-
if (@format == :json) # or :
|
106
|
+
if (@format == :json) # or :object
|
59
107
|
return row_data
|
60
108
|
else
|
61
109
|
return Row.new(row_data)
|
62
110
|
end
|
63
111
|
end
|
64
112
|
|
113
|
+
def rows
|
114
|
+
return read_response["data"] if (@format == :json)
|
115
|
+
|
116
|
+
return read_response["data"].collect do |row_data|
|
117
|
+
Row.new(row_data)
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
def total_count
|
122
|
+
read_response["total_row_count"]
|
123
|
+
end
|
124
|
+
|
125
|
+
|
65
126
|
def schema
|
66
|
-
@
|
67
|
-
|
127
|
+
unless @schema_response
|
128
|
+
@path += "/schema"
|
129
|
+
@schema_response = response(:schema)
|
130
|
+
end
|
68
131
|
|
69
|
-
view =
|
132
|
+
view = @schema_response["view"]
|
70
133
|
fields = view["fields"]
|
71
134
|
|
72
135
|
schema = Table.new(view)
|
@@ -80,30 +143,20 @@ module Factual
|
|
80
143
|
end
|
81
144
|
|
82
145
|
def facets
|
83
|
-
@
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
return Facet.new(columns)
|
88
|
-
end
|
89
|
-
|
90
|
-
def total_count
|
91
|
-
response["total_row_count"]
|
92
|
-
end
|
93
|
-
|
94
|
-
def rows
|
95
|
-
return response["data"] if (@format == :json)
|
96
|
-
|
97
|
-
return response["data"].collect do |row_data|
|
98
|
-
Row.new(row_data)
|
146
|
+
unless @facets_response
|
147
|
+
@path += "/facets"
|
148
|
+
@facets_response = response(:facets)
|
99
149
|
end
|
150
|
+
columns = @facets_response["data"]
|
151
|
+
|
152
|
+
return Facet.new(columns)
|
100
153
|
end
|
101
154
|
|
102
155
|
# query builder, returns immutable ojbects
|
103
156
|
# ----------------
|
104
157
|
VALID_PARAMS.values.flatten.uniq.each do |param|
|
105
158
|
define_method(param) do |*args|
|
106
|
-
api = self.
|
159
|
+
api = self.clone()
|
107
160
|
val = (args.length == 1) ? args.first : args.join(',')
|
108
161
|
|
109
162
|
api.set_param(param, val)
|
@@ -115,7 +168,7 @@ module Factual
|
|
115
168
|
# sugers
|
116
169
|
# ----------------
|
117
170
|
def sort_desc(*args)
|
118
|
-
api = self.
|
171
|
+
api = self.clone
|
119
172
|
columns = args.collect{ |col|"#{col}:desc" }
|
120
173
|
api.set_param(:sort, columns.join(','))
|
121
174
|
|
@@ -130,92 +183,49 @@ module Factual
|
|
130
183
|
page_num = 1 if page_num < 1
|
131
184
|
offset = (page_num - 1) * limit
|
132
185
|
|
133
|
-
api = self.
|
186
|
+
api = self.clone
|
134
187
|
api.set_param(:limit, limit)
|
135
188
|
api.set_param(:offset, offset)
|
136
189
|
|
137
190
|
return api
|
138
191
|
end
|
139
192
|
|
140
|
-
#
|
193
|
+
# requesting
|
141
194
|
# ----------------
|
142
|
-
|
143
|
-
api = self
|
195
|
+
private
|
144
196
|
|
145
|
-
|
146
|
-
|
147
|
-
|
197
|
+
def read_response
|
198
|
+
unless @read_response
|
199
|
+
# always include count for reads
|
200
|
+
@params[:include_count] = true
|
201
|
+
@read_response = response(@action || :read)
|
202
|
+
end
|
148
203
|
|
149
|
-
return
|
204
|
+
return @read_response
|
150
205
|
end
|
151
206
|
|
152
|
-
def
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
api.params = { :values => values }
|
158
|
-
|
159
|
-
return api
|
160
|
-
end
|
161
|
-
|
162
|
-
def table(table_id_or_alias)
|
163
|
-
api = self
|
164
|
-
if @response
|
165
|
-
api = self.class.clone(self)
|
207
|
+
def check_params!(action)
|
208
|
+
@params.each do |param, val|
|
209
|
+
unless (VALID_PARAMS[action] + VALID_PARAMS[:any]).include?(param)
|
210
|
+
raise StandardError.new("InvalidArgument #{param} for #{action}")
|
211
|
+
end
|
166
212
|
end
|
167
|
-
|
168
|
-
api.path = "t/#{table_id_or_alias}"
|
169
|
-
api.action = :read
|
170
|
-
|
171
|
-
return api
|
172
213
|
end
|
173
214
|
|
174
|
-
|
175
|
-
|
176
|
-
# real requesting
|
177
|
-
# ----------------
|
178
|
-
def response
|
179
|
-
@response ||= {}
|
180
|
-
return @response[@action] if @response[@action]
|
181
|
-
|
182
|
-
# always include count for reads
|
183
|
-
@params[:include_count] = true unless @action == :schema
|
215
|
+
def response(action)
|
216
|
+
check_params!(action)
|
184
217
|
|
185
|
-
res = request()
|
218
|
+
res = @api.request(@path, @params)
|
186
219
|
|
187
220
|
code = res.code
|
188
221
|
json = res.body
|
189
222
|
payload = JSON.parse(json)
|
190
223
|
|
191
224
|
if payload["status"] == "ok"
|
192
|
-
|
225
|
+
return payload["response"]
|
193
226
|
else
|
194
227
|
raise StandardError.new(payload["message"])
|
195
228
|
end
|
196
|
-
|
197
|
-
return @response[@action]
|
198
|
-
end
|
199
|
-
|
200
|
-
def request
|
201
|
-
url = "#{API_V3_HOST}/#{@path}?#{query_string}"
|
202
|
-
headers = {"X-Factual-Lib" => DRIVER_VERSION_TAG}
|
203
|
-
|
204
|
-
return @access_token.get(url, headers)
|
205
|
-
end
|
206
|
-
|
207
|
-
def query_string()
|
208
|
-
arr = []
|
209
|
-
@params.each do |param, v|
|
210
|
-
unless (VALID_PARAMS[@action] + VALID_PARAMS[:any]).include?(param)
|
211
|
-
raise StandardError.new("InvalidArgument #{param} for #{@action}")
|
212
|
-
end
|
213
|
-
param_alias = PARAM_ALIASES[param.to_sym] || param.to_sym
|
214
|
-
|
215
|
-
v = v.to_json if v.class == Hash
|
216
|
-
arr << "#{param_alias}=#{URI.escape(v.to_s)}"
|
217
|
-
end
|
218
|
-
return arr.join("&")
|
219
229
|
end
|
220
230
|
|
221
231
|
end
|