factual-api 0.1 → 0.2
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/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
|