dillo 0.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/README.md +22 -0
  2. data/lib/dillo.rb +324 -0
  3. metadata +128 -0
@@ -0,0 +1,22 @@
1
+ #Dillo
2
+
3
+ Ruby library for working with the City of Austin [Data Portal](http://data.austintexas.gov). This library is derived from [Windy](https://github.com/Chicago/windy) which is a library for interacting with Chicago's [Socrata](http://www.socrata.com) powered data portal.
4
+
5
+ ##Installing
6
+
7
+ $ gem install dillo
8
+
9
+ ##Future Plans
10
+
11
+ + Full RDoc documentation
12
+ + Rake tasks for running tests and misc.
13
+ + More tests
14
+ + Example applications
15
+
16
+ ##Issues
17
+
18
+ Please use the issue tracker here on github.
19
+
20
+ ##Contributions
21
+
22
+ Any contributions are welcome, there is not an specific requirements or standards being used at the moment.
@@ -0,0 +1,324 @@
1
+ require 'faraday_middleware'
2
+ require 'multi_json'
3
+
4
+ module Dillo
5
+ VERSION = '0.1'
6
+
7
+ class << self
8
+ attr_accessor :app_token, :debug
9
+ end
10
+
11
+ module Response
12
+ class RaiseClientError < Faraday::Response::Middleware
13
+ def on_complete(env)
14
+ case env[:status].to_i
15
+ when 403
16
+ raise env[:response_headers][:x_error_message]
17
+ end
18
+ end
19
+ end
20
+ end
21
+
22
+ class SocrataAppTokenMiddleware < Faraday::Middleware
23
+ def call(env)
24
+ raise "You must specify an app token" if !Dillo.app_token
25
+ env[:request_headers]["X-App-Token"] = Dillo.app_token
26
+ @app.call env
27
+ end
28
+ end
29
+
30
+ class Base
31
+ def self.root
32
+ "http://data.austintexas.gov"
33
+ end
34
+
35
+ attr_reader :connection
36
+
37
+ def initialize
38
+ @connection = Faraday.new(:url => self.class.root) do |builder|
39
+ builder.use SocrataAppTokenMiddleware
40
+ builder.use Dillo::Response::RaiseClientError
41
+ builder.use FaradayMiddleware::ParseJson, :content_type => /\bjson$/
42
+
43
+ # Enable logger output with Dillojamie.phillips@austintexas.gov.debug = true
44
+ if Dillo.debug
45
+ builder.response :logger
46
+ end
47
+
48
+ builder.adapter :net_http
49
+ end
50
+ end
51
+
52
+ def body
53
+ @body ||= connection.get(path) do |request|
54
+ prepare_request(request)
55
+ # warn "Fetching #{request.to_env(@connection)[:url]}"
56
+ end.body
57
+ end
58
+
59
+ def prepare_request(request)
60
+ end
61
+
62
+ def json
63
+ # For some reason ruby 1.9.x seems to be trying to parse the
64
+ # API JSON output as ASCII instead of UTF-8
65
+ body.force_encoding("UTF-8") unless body.nil? || !body.respond_to?(:force_encoding)
66
+ @json ||= MultiJson.decode(body)
67
+ end
68
+
69
+ def inspect
70
+ "#<#{self.class.name} #{self.class.root}#{path}>"
71
+ end
72
+ end
73
+
74
+ module Finders
75
+ def [](index)
76
+ to_a[index]
77
+ end
78
+
79
+ def respond_to?(method)
80
+ method.to_s[/^find(_all)?_by_./] || super
81
+ end
82
+
83
+ def method_missing(method, *args, &block)
84
+ if attribute = method.to_s[/^(find(_all)?)_by_(.+)$/, 3]
85
+ value = args.first
86
+ send($1) { |record| record.send(attribute) == value }
87
+ else
88
+ super
89
+ end
90
+ end
91
+ end
92
+
93
+ class PaginatedCollection < Base
94
+ include Enumerable, Finders
95
+
96
+ def initialize
97
+ @pages ||= {}
98
+ end
99
+
100
+ def page(number)
101
+ @pages[number] ||= Page.new(self, number)
102
+ end
103
+
104
+ def each_page
105
+ number = 1
106
+ loop do
107
+ page = self.page(number)
108
+ break if page.count.zero?
109
+ yield page
110
+ number += 1
111
+ end
112
+ end
113
+
114
+ def each(&block)
115
+ each_page do |page|
116
+ page.each(&block)
117
+ end
118
+ end
119
+ end
120
+
121
+ class Collection < Base
122
+ include Enumerable, Finders
123
+
124
+ def each(&block)
125
+ records.each(&block)
126
+ end
127
+
128
+ def record_attributes
129
+ json
130
+ end
131
+
132
+ def records
133
+ @records ||= record_attributes.map do |attributes|
134
+ create_record(attributes)
135
+ end
136
+ end
137
+
138
+ def create_record(attributes)
139
+ record_class.new(attributes)
140
+ end
141
+ end
142
+
143
+ class Page < Collection
144
+ attr_accessor :collection, :number
145
+
146
+ def initialize(collection, number)
147
+ @collection = collection
148
+ @number = number
149
+ super()
150
+ end
151
+
152
+ def path
153
+ collection.path
154
+ end
155
+
156
+ def record_class
157
+ collection.record_class
158
+ end
159
+
160
+ def prepare_request(request)
161
+ request.params['limit'] = 200
162
+ request.params['page'] = @number
163
+ end
164
+ end
165
+
166
+ class Record
167
+ undef_method(:id) if method_defined?(:id)
168
+
169
+ attr_reader :attributes
170
+
171
+ def initialize(attributes)
172
+ self.attributes = attributes
173
+ end
174
+
175
+ def attributes=(attributes)
176
+ @attributes = Dillo.underscore(attributes)
177
+ end
178
+
179
+ def respond_to?(method)
180
+ @attributes.has_key?(method.to_s) || super
181
+ end
182
+
183
+ def method_missing(method, *args, &block)
184
+ if respond_to?(method)
185
+ @attributes[method.to_s]
186
+ else
187
+ super
188
+ end
189
+ end
190
+
191
+ def inspect
192
+ "#<#{self.class.name}:#{id}>"
193
+ end
194
+ end
195
+
196
+ class Views < PaginatedCollection
197
+ def path
198
+ "/api/views"
199
+ end
200
+
201
+ def record_class
202
+ View
203
+ end
204
+ end
205
+
206
+ class View < Record
207
+ def columns
208
+ @columns ||= Columns.new(id)
209
+ end
210
+
211
+ def rows
212
+ @rows ||= Rows.new(id)
213
+ end
214
+
215
+ def inspect
216
+ super[0..-2] + " #{name.inspect}>"
217
+ end
218
+ end
219
+
220
+ class Columns < Collection
221
+ def initialize(id)
222
+ @id = id
223
+ super()
224
+ end
225
+
226
+ def path
227
+ "/api/views/#{@id}/columns.json"
228
+ end
229
+
230
+ def record_class
231
+ Column
232
+ end
233
+ end
234
+
235
+ class Column < Record
236
+ def inspect
237
+ "#<#{self.class.name}:#{id} #{name.inspect}>"
238
+ end
239
+ end
240
+
241
+ class Rows < Collection
242
+ def initialize(id)
243
+ @id = id
244
+ super()
245
+ end
246
+
247
+ def path
248
+ "/api/views/#{@id}/rows.json"
249
+ end
250
+
251
+ def record_class
252
+ Row
253
+ end
254
+
255
+ def record_attributes
256
+ json['data']
257
+ end
258
+
259
+ def columns
260
+ @columns ||= json['meta']['view']['columns'].map { |column| column['name'].downcase }
261
+ end
262
+
263
+ def column_index(name)
264
+ columns.index(name.to_s.downcase)
265
+ end
266
+
267
+ def create_record(attributes)
268
+ record_class.new(self, attributes)
269
+ end
270
+ end
271
+
272
+ class Row
273
+ undef_method(:id) if method_defined?(:id)
274
+
275
+ attr_reader :collection, :values
276
+
277
+ def initialize(collection, values)
278
+ @collection = collection
279
+ @values = values
280
+ end
281
+
282
+ def [](index_or_name)
283
+ if index_or_name.is_a?(Integer)
284
+ values[index_or_name]
285
+ elsif index = collection.column_index(index_or_name)
286
+ values[index]
287
+ end
288
+ end
289
+
290
+ def method_missing(method, *args, &block)
291
+ name = method.to_s.gsub('_', ' ')
292
+ if collection.column_index(name)
293
+ self[name]
294
+ else
295
+ super
296
+ end
297
+ end
298
+
299
+ def length
300
+ values.length
301
+ end
302
+
303
+ def to_a
304
+ values
305
+ end
306
+
307
+ def inspect
308
+ "#<#{self.class.name} #{values.inspect}>"
309
+ end
310
+ end
311
+
312
+ def self.views
313
+ @views ||= Views.new
314
+ end
315
+
316
+ def self.underscore(hash)
317
+ Hash.new.tap do |result|
318
+ hash.each do |original_key, value|
319
+ new_key = original_key.gsub(/([a-z])([A-Z])/) { "#{$1}_#{$2.downcase}" }
320
+ result[new_key] = value.is_a?(Hash) ? underscore(value) : value
321
+ end
322
+ end
323
+ end
324
+ end
metadata ADDED
@@ -0,0 +1,128 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: dillo
3
+ version: !ruby/object:Gem::Version
4
+ version: '0.1'
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Jamie Phillips
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-05-19 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: faraday_middleware
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: '0.8'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: '0.8'
30
+ - !ruby/object:Gem::Dependency
31
+ name: multi_json
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ~>
36
+ - !ruby/object:Gem::Version
37
+ version: '1.0'
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ version: '1.0'
46
+ - !ruby/object:Gem::Dependency
47
+ name: rspec
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ~>
52
+ - !ruby/object:Gem::Version
53
+ version: '2.6'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: '2.6'
62
+ - !ruby/object:Gem::Dependency
63
+ name: simplecov
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ~>
68
+ - !ruby/object:Gem::Version
69
+ version: '0.4'
70
+ type: :development
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ~>
76
+ - !ruby/object:Gem::Version
77
+ version: '0.4'
78
+ - !ruby/object:Gem::Dependency
79
+ name: webmock
80
+ requirement: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ~>
84
+ - !ruby/object:Gem::Version
85
+ version: '1.7'
86
+ type: :development
87
+ prerelease: false
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ~>
92
+ - !ruby/object:Gem::Version
93
+ version: '1.7'
94
+ description: Dillo is a Ruby module that allows you to easily interact with the City
95
+ of Austin's Data Portal.
96
+ email:
97
+ - jamie.phillips@austintexas.gov
98
+ executables: []
99
+ extensions: []
100
+ extra_rdoc_files: []
101
+ files:
102
+ - README.md
103
+ - lib/dillo.rb
104
+ homepage: http://github.com/phillipsj/dillo
105
+ licenses: []
106
+ post_install_message:
107
+ rdoc_options: []
108
+ require_paths:
109
+ - lib
110
+ required_ruby_version: !ruby/object:Gem::Requirement
111
+ none: false
112
+ requirements:
113
+ - - ! '>='
114
+ - !ruby/object:Gem::Version
115
+ version: '0'
116
+ required_rubygems_version: !ruby/object:Gem::Requirement
117
+ none: false
118
+ requirements:
119
+ - - ! '>='
120
+ - !ruby/object:Gem::Version
121
+ version: '0'
122
+ requirements: []
123
+ rubyforge_project:
124
+ rubygems_version: 1.8.24
125
+ signing_key:
126
+ specification_version: 3
127
+ summary: Ruby interface to the City of Austin's Data Portal API
128
+ test_files: []