dambalah-dcgov 0.0.1 → 0.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.
@@ -0,0 +1,19 @@
1
+ require 'uri'
2
+ require 'cgi'
3
+ require 'net/http'
4
+ require 'rubygems'
5
+ require 'json'
6
+
7
+ $:.unshift(File.dirname(__FILE__))
8
+ require 'dcgov/easy_class_maker'
9
+ require 'dcgov/geocoder'
10
+ require 'dcgov/open311'
11
+ require 'dcgov/service_request_field'
12
+ require 'dcgov/service_type'
13
+ require 'dcgov/address'
14
+ require 'dcgov/util'
15
+
16
+ module DCGOV
17
+ #Not too much in here...
18
+
19
+ end
@@ -0,0 +1,48 @@
1
+ module DCGOV
2
+ class Address
3
+ include EasyClassMaker
4
+
5
+ # just a sample of what dc returns, for reference purposes.
6
+ # [{"aid"=>"285552"}, {"status"=>"ACTIVE"}, {"fulladdress"=>"441 4TH STREET NW"}, {"addrnum"=>"441"}, {"stname"=>"4TH"}, {"street_type"=>"STREET"},
7
+ # {"quadrant"=>"NW"}, {"city"=>"WASHINGTON"}, {"state"=>"DC"}, {"xcoord"=>"398642.18"}, {"ycoord"=>"136399.84"},
8
+ # {"ssl"=>"0532 0020"}, {"anc"=>"ANC 6C"}, {"psa"=>"Police Service Area 101"}, {"ward"=>"Ward 6"}, {"nbhd_action"=>" "},
9
+ # {"cluster"=>"Cluster 8"}, {"poldist"=>"Police District - First District"}, {"roc"=>"-"}, {"census_tract"=>"59"},
10
+ # {"vote_prcnct"=>"Precinct 143"}, {"smd"=>"SMD02 6C09"}, {"zipcode"=>"20001"}, {"latitude"=>"38.89544591"},
11
+ # {"longitude"=>"-77.01565221"}, {"distance"=>"0"}]
12
+
13
+ attributes :aid,:status,:fulladdress,:addrnum,:stname,:street_type,:quadrant,:city,:state,:xoord,:ycoord,:ssl,:anc,:psa,:ward,:nbhd,:clust,:poldist,:roc,:census_tract,
14
+ :vote_prcnct,:smd,:zipcode,:latitude,:longitude,:distance
15
+
16
+ # Creates a new user from a piece of xml
17
+ def self.new_from_hash(hsh)
18
+ u = new
19
+ u.aid = hsh['aid']
20
+ u.status = hsh['status']
21
+ u.fulladdress = hsh['fulladdress']
22
+ u.addrnum = hsh['addrnum']
23
+ u.stname = hsh['stname']
24
+ u.street_type = hsh['street_type']
25
+ u.quadrant = hsh['quadrant']
26
+ u.city = hsh['city']
27
+ u.state = hsh['state']
28
+ u.xoord = hsh['xoord']
29
+ u.ycoord = hsh['ycoord']
30
+ u.ssl = hsh['ssl']
31
+ u.anc = hsh['anc']
32
+ u.psa = hsh['psa']
33
+ u.ward = hsh['ward']
34
+ u.nbhd = hsh['nbhd']
35
+ u.clust = hsh['clust']
36
+ u.poldist = hsh['poldist']
37
+ u.roc = hsh['roc']
38
+ u.census_tract = hsh['census_tract']
39
+ u.vote_prcnct = hsh['vote_prcnct']
40
+ u.smd = hsh['smd']
41
+ u.zipcode = hsh['zipcode']
42
+ u.latitude = hsh['latitude']
43
+ u.longitude = hsh['longitude']
44
+ u.distance = hsh['distance']
45
+ u
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,45 @@
1
+ # This is pretty much just a macro for creating a class that allows
2
+ # using a block to initialize stuff and to define getters and setters
3
+ # really quickly.
4
+ #
5
+ # I stole this from the Twitter gem. Who knows who they stole it from.
6
+ module DCGOV
7
+ module EasyClassMaker
8
+
9
+ def self.included(base)
10
+ base.extend(ClassMethods)
11
+ end
12
+
13
+ module ClassMethods
14
+ # creates the attributes class variable and creates each attribute's accessor methods
15
+ def attributes(*attrs)
16
+ @@attributes = attrs
17
+ @@attributes.each { |a| attr_accessor a }
18
+ end
19
+
20
+ # read method for attributes class variable
21
+ def self.attributes; @@attributes end
22
+ end
23
+
24
+ # allows for any class that includes this to use a block to initialize
25
+ # variables instead of assigning each one seperately
26
+ #
27
+ # Example:
28
+ #
29
+ # instead of...
30
+ #
31
+ # s = Status.new
32
+ # s.foo = 'thing'
33
+ # s.bar = 'another thing'
34
+ #
35
+ # you can ...
36
+ #
37
+ # Status.new do |s|
38
+ # s.foo = 'thing'
39
+ # s.bar = 'another thing'
40
+ # end
41
+ def initialize
42
+ yield self if block_given?
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,60 @@
1
+ module DCGOV
2
+ class GeoCoder
3
+ #master dispatcher
4
+ def self.get(options)
5
+ if options[:address]
6
+ find_by_address(options[:address])
7
+ elsif options[:lat] && options[:lon]
8
+ find_by_lat_lon(options[:lat],options[:lon])
9
+ elsif options[:mar_id]
10
+ find_by_id(options[:mar_id])
11
+ else
12
+ nil #dumbass.
13
+ end
14
+ end
15
+
16
+
17
+ #do a search via latitude and longitude.
18
+ def self.find_by_lat_lon(lat,lon)
19
+ begin
20
+ request_url = "/geocoding/v1/getFromLatLong.json?lat=#{CGI::escape(lat)}&long=#{CGI::escape(lon)}"
21
+ result_json = DCGOV::Util.pull_from_json(request_url)
22
+ return result_json["addresses"].collect { |address| DCGOV::Address.new_from_hash(address["address"][0]) }
23
+ rescue
24
+ #crap, something went wrong
25
+ return nil
26
+ end
27
+ end
28
+
29
+
30
+ #find via a normal street address... "1600 pennsylvania"
31
+ def self.find_by_address(address)
32
+ begin
33
+ request_url = "/geocoding/v1/search.json?address=#{CGI::escape(address)}"
34
+ result_json = DCGOV::Util.pull_from_json(request_url)
35
+ return result_json["addresses"].collect { |address| DCGOV::Address.new_from_hash(address["address"][0]) }
36
+ rescue
37
+ #crap, something went wrong
38
+ return nil
39
+ end
40
+ end
41
+
42
+ #find by a mar ID
43
+ def self.find_by_id(mar_id)
44
+ begin
45
+ request_url = "/geocoding/v1/get.json?aid=#{mar_id}"
46
+ result_json = DCGOV::Util.pull_from_json(request_url)
47
+ return DCGOV::Address.new_from_hash(result_json["address"][0])
48
+ rescue
49
+ #crap, something went wrong
50
+ return nil
51
+ end
52
+ end
53
+
54
+ # just so I could make sure rspec was working.
55
+ def self.foo
56
+ "bar"
57
+ end
58
+
59
+ end
60
+ end
@@ -0,0 +1,36 @@
1
+ module DCGOV
2
+ class Open311
3
+ def self.get_service_types()
4
+ request_url = "/open311/v1/meta_getTypesList.json"
5
+ result_json = DCGOV::Util.pull_from_json(request_url)
6
+ return result_json["servicetypeslist"].collect { |st| DCGOV::ServiceType.new_from_hash(st["servicetype"]) }
7
+ end
8
+
9
+ def self.get_request_fields(sr_id)
10
+ request_url = "/open311/v1/meta_getTypeDefinition.json?servicecode=#{CGI::escape(sr_id)}"
11
+ result_json = DCGOV::Util.pull_from_json(request_url)
12
+ #print result_json.inspect
13
+ return result_json["servicetypedefinition"].collect { |st| DCGOV::ServiceRequestField.new_from_hash(st["servicetype"]) }
14
+ end
15
+
16
+ def self.get(request_id)
17
+ request_url = "/open311/v1/get.json?servicerequestid=#{CGI::escape(request_id)}"
18
+ result_json = DCGOV::Util.pull_from_json(request_url)
19
+ results_fixed = DCGOV::Util::fix_hash(result_json["servicerequest"])
20
+ return results_fixed
21
+ end
22
+
23
+ def self.resolve_token(token_id)
24
+ request_url = "/open311/v1/getFromToken.json?token=#{token_id}"
25
+ result_json = DCGOV::Util.pull_from_json(request_url)
26
+ result_json["servicerequestid"]
27
+ end
28
+
29
+ def self.submit(values)
30
+ request_url = "/open311/v1/submit.json"
31
+ result_json = DCGOV::Util.post_to_json(values,request_url)
32
+ result_json["token"]
33
+ end
34
+
35
+ end
36
+ end
@@ -0,0 +1,40 @@
1
+ module DCGOV
2
+ class ServiceRequest
3
+
4
+ include EasyClassMaker
5
+
6
+ attributes :anc,:lattitude,:serviceorderdate,:resolution,:servicerequestid,:siteaddress,:serviceorderstatus,:district,:zipcode,:servicenotes,:servicetypecodedescription,:servicecodedescription,:servicecode,:neighborhoodcluster,:servicepriority,:aid,:serviceduedate,:resolutiondate,:psa,:longitude,:smd,:ward,:agencyabbreviation,:servicetypeocde
7
+
8
+ # Creates a new user from a piece of xml
9
+ def self.new_from_hash(hsh)
10
+ u = new
11
+ u.anc = hsh['anc']
12
+ u.lattitude = hsh['lattitude']
13
+ u.serviceorderdate = hsh['serviceorderdate']
14
+ u.resolution = hsh['resolution']
15
+ u.servicerequestid = hsh['servicerequestid']
16
+ u.siteaddress = hsh['siteaddress']
17
+ u.serviceorderstatus = hsh['serviceorderstatus']
18
+ u.district = hsh['district']
19
+ u.zipcode = hsh['zipcode']
20
+ u.servicenotes = hsh['servicenotes']
21
+ u.servicetypecodedescription = hsh['servicetypecodedescription']
22
+ u.servicecodedescription = hsh['servicecodedescription']
23
+ u.servicecode = hsh['servicecode']
24
+ u.neighborhoodcluster = hsh['neighborhoodcluster']
25
+ u.servicepriority = hsh['servicepriority']
26
+ u.aid = hsh['aid']
27
+ u.serviceduedate = hsh['serviceduedate']
28
+ u.resolutiondate = hsh['resolutiondate']
29
+ u.psa = hsh['psa']
30
+ u.longitude = hsh['longitude']
31
+ u.smd = hsh['smd']
32
+ u.ward = hsh['ward']
33
+ u.agencyabbreviation = hsh['agencyabbreviation']
34
+ u.servicetypeocde = hsh['servicetypeocde']
35
+
36
+
37
+ u
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,25 @@
1
+ module DCGOV
2
+ class ServiceRequestField
3
+ include EasyClassMaker
4
+ #{"servicetype"=>[{"servicetype"=>"Abandoned Bicycles"}, {"servicecode"=>"S0021"},
5
+ #{"name"=>"ABDBIC-HOWLONG"}, {"prompt"=>"How long has the bicycle been abandoned?"},
6
+ # {"required"=>"Y"}, {"type"=>"TextBox "}, {"width"=>"200"}, {"itemlist"=>"\r"}]}
7
+
8
+ attributes :service_type,:service_code,:field_name,:field_label,:field_required,:field_type,:field_width,:item_list
9
+
10
+ # Creates a new user from a piece of xml
11
+ def self.new_from_hash(hsh)
12
+ u = new
13
+ u.service_type = hsh[0]['servicetype']
14
+ u.service_code = hsh[1]['servicecode']
15
+ u.field_name = hsh[2]['name']
16
+ u.field_label = hsh[3]['prompt']
17
+ u.field_required = hsh[4]['required']
18
+ u.field_type = hsh[5]['type']
19
+ u.field_width = hsh[6]['width']
20
+ u.item_list = hsh[7]['itemlist']
21
+ u
22
+ end
23
+
24
+ end
25
+ end
@@ -0,0 +1,16 @@
1
+ module DCGOV
2
+ class ServiceType
3
+ include EasyClassMaker
4
+ attributes :service_type,:service_code
5
+
6
+ # Creates a new user from a piece of xml
7
+ def self.new_from_hash(hsh)
8
+ hash_to_proc = hsh.to_a
9
+ u = new
10
+ u.service_type = hash_to_proc[0]['servicetype']
11
+ u.service_code = hash_to_proc[1]['servicecode']
12
+ u
13
+ end
14
+
15
+ end
16
+ end
@@ -0,0 +1,42 @@
1
+ module DCGOV
2
+ class Util
3
+
4
+ # just about all there is.
5
+ def self.pull_from_json(params)
6
+
7
+ #why am I wrapping the entire deal in a rescue block? Well, the API has no error handling at all
8
+ # so if you enter in something bad, it just craps on you.
9
+ begin
10
+ @resp
11
+ Net::HTTP.start('api.dc.gov') {|http|
12
+ req = Net::HTTP::Get.new(params)
13
+ response = http.request(req)
14
+ @resp = response.body
15
+ }
16
+ JSON.parse @resp
17
+ rescue
18
+ #so the caller can catch a "better" error than some JSON parsing or HTTP bs.
19
+ raise "An error occurred while attempting to grab and parse the results"
20
+ end
21
+ end
22
+
23
+ def self.post_to_json(params,url)
24
+ @resp
25
+ Net::HTTP.start('api.dc.gov') {|http|
26
+ req = Net::HTTP::Post.new(url)
27
+ req.set_form_data(params)
28
+ response = http.request(req)
29
+ @resp = response.body
30
+ }
31
+ JSON.parse @resp
32
+ end
33
+
34
+ def self.fix_hash(hsh)
35
+ results = Hash.new
36
+ hsh.each { |i|
37
+ results.merge!(i)
38
+ }
39
+ return results
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,42 @@
1
+ require File.dirname(__FILE__) + '/spec_helper.rb'
2
+
3
+ describe "DCGOV::GeoCoder" do
4
+
5
+ it "should be able to look up an address that exists" do
6
+ results = DCGOV::GeoCoder.get({:address=>"441 4th str, nw"})
7
+ results.length.should == 1
8
+ end
9
+
10
+ it "should be able to look up an address that doesn't exist" do
11
+ results = DCGOV::GeoCoder.get({:address=>"1dsggdsdgssdgdsgdsgdsgdgsW"})
12
+ results.length.should == 0
13
+ end
14
+
15
+ it "should be able to look up an address that has multiple results" do
16
+ results = DCGOV::GeoCoder.get({:address=>"441 4th str"})
17
+ results.length.should == 2
18
+ end
19
+
20
+ it "should be able to look up a latitude and a longitude" do
21
+ results = DCGOV::GeoCoder.get({:lat=>"38.89544591",:lon=>"-77.01565221"})
22
+ results[0].aid.should=="285552"
23
+ results.length.should > 0
24
+ end
25
+
26
+ it "should be able to look up via a mar ID" do
27
+ aid = 285552
28
+ result = DCGOV::GeoCoder.get({:mar_id=>aid})
29
+ result.aid.to_i.should == aid
30
+ end
31
+
32
+ it "should return nil when a nonsensical mar is thrown" do
33
+ results = DCGOV::GeoCoder.get({:mar_id=>'adslkfhjdgsalkjgdlksdgjlgkds'})
34
+ results.should == nil
35
+ end
36
+
37
+ #stupid test. for fun.
38
+ it "should work" do
39
+ DCGOV::GeoCoder.foo.should == "bar"
40
+ end
41
+
42
+ end
@@ -0,0 +1,41 @@
1
+ require File.dirname(__FILE__) + '/spec_helper.rb'
2
+
3
+ describe "DCGOV::Open311" do
4
+
5
+ it "should return a list of service types" do
6
+ service_types = DCGOV::Open311.get_service_types()
7
+ service_types.length.should > 0
8
+ service_types[0].class.to_s.should == "DCGOV::ServiceType"
9
+ service_types[0].service_type.should =="Abandoned Bicycles"
10
+ service_types[0].service_code.should =="S0021"
11
+ end
12
+
13
+ it "should return a list of fields for a service type" do
14
+ service_code="S0021"
15
+ request_fields = DCGOV::Open311.get_request_fields(service_code)
16
+ request_fields.length.should > 0
17
+ request_fields[0].service_type.should == "Abandoned Bicycles"
18
+ request_fields[0].field_name.should == "ABDBIC-HOWLONG"
19
+ request_fields[0].field_label.should == "How long has the bicycle been abandoned?"
20
+
21
+ end
22
+
23
+ it "should return a request based on a service ID" do
24
+ request_id="123456"
25
+ request = DCGOV::Open311.get(request_id)
26
+ request.class.to_s.should == "Hash"
27
+ end
28
+
29
+ it "should convert a token into a service request id" do
30
+ token_id = "123456"
31
+ service_request_id = DCGOV::Open311.resolve_token(token_id)
32
+ service_request_id.should_not == nil
33
+ end
34
+
35
+ it "should post a service request" do
36
+ values = Hash.new
37
+ token_id = DCGOV::Open311.submit(values)
38
+ token_id.should_not == nil
39
+ end
40
+
41
+ end
@@ -0,0 +1,23 @@
1
+ begin
2
+ require 'spec'
3
+ rescue LoadError
4
+ require 'rubygems'
5
+ gem 'rspec'
6
+ require 'spec'
7
+ end
8
+
9
+ dir = File.dirname(__FILE__)
10
+
11
+ $:.unshift(File.join(dir, '/../lib/'))
12
+ require dir + '/../lib/dcgov'
13
+
14
+
15
+ def stdout_for(&block)
16
+ # Inspired by http://www.ruby-forum.com/topic/58647
17
+ old_stdout = $stdout
18
+ $stdout = StringIO.new
19
+ yield
20
+ output = $stdout.string
21
+ $stdout = old_stdout
22
+ output
23
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dambalah-dcgov
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Zvi Band
@@ -35,6 +35,19 @@ files:
35
35
  - LICENSE
36
36
  - README
37
37
  - Rakefile
38
+ - lib/dcgov
39
+ - lib/dcgov/service_type.rb
40
+ - lib/dcgov/util.rb
41
+ - lib/dcgov/open311.rb
42
+ - lib/dcgov/address.rb
43
+ - lib/dcgov/easy_class_maker.rb
44
+ - lib/dcgov/service_request_field.rb
45
+ - lib/dcgov/geocoder.rb
46
+ - lib/dcgov/service_request.rb
47
+ - lib/dcgov.rb
48
+ - spec/geocoder_spec.rb
49
+ - spec/spec_helper.rb
50
+ - spec/open_311_spec.rb
38
51
  has_rdoc: true
39
52
  homepage: http://skeevisarts.com
40
53
  post_install_message: