twfy 1.0.0
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 +10 -0
- data/Manifest.txt +8 -0
- data/README.txt +105 -0
- data/Rakefile +22 -0
- data/lib/data_element.rb +101 -0
- data/lib/twfy.rb +173 -0
- data/test/test_twfy.rb +44 -0
- data/test/test_twfy_chain.rb +49 -0
- metadata +71 -0
data/History.txt
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
== 1.0.0 / 2006-11-08
|
2
|
+
|
3
|
+
* Initial release supporting all services from TWFY API 1.0.0
|
4
|
+
* Basic support for 'daisy-chained' service calls via DataElement subclasses, caching results
|
5
|
+
* MP (info, debates, comments)
|
6
|
+
* Constituency (mp, geometry)
|
7
|
+
* Coming up:
|
8
|
+
* Easy pagination of debates, comments, etc
|
9
|
+
* Data mining MPInfo information (ie expenses, accessible directly from MP instance)
|
10
|
+
* Other stuff :-)
|
data/Manifest.txt
ADDED
data/README.txt
ADDED
@@ -0,0 +1,105 @@
|
|
1
|
+
twfy
|
2
|
+
by Bruce Williams (http://codefluency.com)
|
3
|
+
and Martin Owens
|
4
|
+
|
5
|
+
== DESCRIPTION:
|
6
|
+
|
7
|
+
Ruby library to interface with the TheyWorkForYou API.
|
8
|
+
|
9
|
+
From their website:
|
10
|
+
|
11
|
+
"TheyWorkForYou.com is a non-partisan, volunteer-run website which aims to make it easy
|
12
|
+
for people to keep tabs on their elected and unelected representatives in Parliament."
|
13
|
+
|
14
|
+
== FEATURES/PROBLEMS:
|
15
|
+
|
16
|
+
All services [currently] provided by the API are supported.
|
17
|
+
|
18
|
+
The Ruby API closely mirrors that of TWFY, with the exception that the client
|
19
|
+
methods are in lowercase and don't include the 'get' prefix.
|
20
|
+
|
21
|
+
Some examples:
|
22
|
+
|
23
|
+
getComments:: comments
|
24
|
+
getMPs:: mps
|
25
|
+
getMPInfo:: mp_info
|
26
|
+
|
27
|
+
Please submit bug reports to the RubyForge tracker via the project's homepage at
|
28
|
+
http://rubyforge.org/projects/twfy
|
29
|
+
|
30
|
+
== SYNOPSIS:
|
31
|
+
|
32
|
+
Use is very easy.
|
33
|
+
|
34
|
+
=== Get a Client
|
35
|
+
|
36
|
+
require 'twfy'
|
37
|
+
client = Twfy::Client.new
|
38
|
+
|
39
|
+
=== Call API methods directly on client
|
40
|
+
|
41
|
+
puts client.constituency(:postcode=>'IP6 9PN').name
|
42
|
+
# => Central Suffolk & North Ipswich
|
43
|
+
|
44
|
+
mp = client.mp(:postcode=>'IP6 9PN')
|
45
|
+
puts mp.full_name
|
46
|
+
# => Michael Lord
|
47
|
+
|
48
|
+
# Get a *lot* of info about this MP
|
49
|
+
info = client.mp_info(:id=>mp.person_id)
|
50
|
+
|
51
|
+
# Get a sorted list of all the parties in the House of Lords
|
52
|
+
client.lords.map{|l| l.party}.uniq.sort
|
53
|
+
#=> ["Bishop", "Conservative", "Crossbench", "DUP", "Green", "Labour", "Liberal Democrat", "Other"]
|
54
|
+
|
55
|
+
# Get number of debates in the House of Commons mentioning 'Iraq'
|
56
|
+
number = client.debates(:type=>'commons',:search=>'Iraq').info['total_results']
|
57
|
+
|
58
|
+
=== Daisy chaining
|
59
|
+
|
60
|
+
A few methods on the client return non-OpenStruct instances that support daisy chaining. Using these to access related data more naturally (with caching).
|
61
|
+
|
62
|
+
Here are some examples
|
63
|
+
|
64
|
+
# Get the MP for the last constituency (if you sort them alphabetically)
|
65
|
+
mp = client.constituencies.sort_by{|c| c.name }.last.mp
|
66
|
+
# get the geometry information for that constituency (coming from the MP)
|
67
|
+
geometry = mp.constituency.geometry
|
68
|
+
|
69
|
+
# An overkill example showing caching (no services are called here, since
|
70
|
+
# the results have already been cached from above)
|
71
|
+
mp = mp.constituency.mp.constituency.geometry.constituency.mp
|
72
|
+
|
73
|
+
# These return equivalent results (Note how much easier the first is)
|
74
|
+
info1 = mp.info # this is cached for subsequent calls
|
75
|
+
info2 = client.mp_info(:id=>mp.person_id)
|
76
|
+
|
77
|
+
# Get pages of debates mentioning 'medicine'
|
78
|
+
debates1 = mp.debates(:search=>'medicine')
|
79
|
+
debates2 = mp.debates(:search=>'medicine', :page=>2)
|
80
|
+
|
81
|
+
See http://www.theyworkforyou.com/api/docs for API documentation.
|
82
|
+
|
83
|
+
Please note that data pulled from the API is licensed separately;
|
84
|
+
see the LICENSE portion of this README for further details.
|
85
|
+
|
86
|
+
== REQUIREMENTS:
|
87
|
+
|
88
|
+
+ json library (available as a gem)
|
89
|
+
|
90
|
+
== INSTALL:
|
91
|
+
|
92
|
+
No special instructions.
|
93
|
+
|
94
|
+
== LICENSE:
|
95
|
+
|
96
|
+
This library uses the MIT License
|
97
|
+
Copyright (c) 2006 Bruce Williams
|
98
|
+
|
99
|
+
Data is licensed separately:
|
100
|
+
|
101
|
+
The TheyWorkForYou license statement, from their website (http://www.theyworkforyou.com/api/), is:
|
102
|
+
|
103
|
+
To use parliamentary material yourself (that's data returned from getDebates, getWrans, and getWMS), you will need to get a Parliamentary Licence from the Office of Public Sector Information. Our own data - lists of MPs, Lords, constituencies and so on - is available under the Creative Commons Attribution-ShareAlike license version 2.5.
|
104
|
+
|
105
|
+
Non-commercial use is free, please contact us for commercial use.
|
data/Rakefile
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
# -*- ruby -*-
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'hoe'
|
5
|
+
require 'lib/twfy.rb'
|
6
|
+
|
7
|
+
Hoe.new('twfy', Twfy::VERSION) do |p|
|
8
|
+
p.rubyforge_name = 'twfy'
|
9
|
+
p.summary = 'Ruby library to interface with the TheyWorkForYou(.com) API; an information source on Parliament'
|
10
|
+
p.description =<<EOD
|
11
|
+
Ruby library to interface with the TheyWorkForYou API. TheyWorkForYou.com is
|
12
|
+
"a non-partisan, volunteer-run website which aims to make it easy for people to keep
|
13
|
+
tabs on their elected and unelected representatives in Parliament."
|
14
|
+
EOD
|
15
|
+
p.url = "http://twfy.rubyforge.org"
|
16
|
+
p.changes = p.paragraphs_of('History.txt', 0..1).join("\n\n")
|
17
|
+
p.extra_deps = ['json', 'paginator']
|
18
|
+
p.email = %q{bruce@codefluency.com}
|
19
|
+
p.author = ["Bruce Williams", "Martin Owens"]
|
20
|
+
end
|
21
|
+
|
22
|
+
# vim: syntax=Ruby
|
data/lib/data_element.rb
ADDED
@@ -0,0 +1,101 @@
|
|
1
|
+
require 'uri'
|
2
|
+
require 'date'
|
3
|
+
|
4
|
+
module Twfy
|
5
|
+
|
6
|
+
class DataElement
|
7
|
+
@@conversions = {}
|
8
|
+
class << self
|
9
|
+
def convert(*fields,&block)
|
10
|
+
fields.each do |field|
|
11
|
+
@@conversions[field] = block
|
12
|
+
end
|
13
|
+
end
|
14
|
+
def convert_to_date(*fields)
|
15
|
+
fields.each do |field|
|
16
|
+
convert field do |d|
|
17
|
+
Date.parse(d)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
attr_reader :client
|
24
|
+
def initialize(client, data={})
|
25
|
+
@client = client
|
26
|
+
data.each do |field,value|
|
27
|
+
instance_variable_set("@#{field}", convert(field, value))
|
28
|
+
unless self.respond_to?(field)
|
29
|
+
self.class.send(:define_method, field) do
|
30
|
+
instance_variable_get("@#{field}")
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def convert(field, value)
|
37
|
+
if conversion = @@conversions[field.to_sym]
|
38
|
+
args = [value]
|
39
|
+
args.unshift self if conversion.arity == 2
|
40
|
+
conversion.call(*args)
|
41
|
+
else
|
42
|
+
value
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
|
48
|
+
class MP < DataElement
|
49
|
+
|
50
|
+
convert_to_date :entered_house, :left_house
|
51
|
+
convert :image do |value|
|
52
|
+
URI.parse("http://theyworkforyou.com#{value}")
|
53
|
+
end
|
54
|
+
convert :constituency do |source,value|
|
55
|
+
Constituency.new(source.client, :name => value, :mp => source)
|
56
|
+
end
|
57
|
+
|
58
|
+
def in_office?
|
59
|
+
@left_reason == 'still_in_office'
|
60
|
+
end
|
61
|
+
|
62
|
+
def info
|
63
|
+
@info ||= @client.mp_info(:id => @person_id)
|
64
|
+
end
|
65
|
+
|
66
|
+
def debates(params={})
|
67
|
+
@debates ||= {}
|
68
|
+
@debates[params] ||= @client.debates(params.merge(:person=>@person_id, :type=>'commons'))
|
69
|
+
end
|
70
|
+
|
71
|
+
def comments(params={})
|
72
|
+
@comments ||= {}
|
73
|
+
@comments[params] ||= @client.comments(params.merge(:pid=>@person_id))
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
77
|
+
|
78
|
+
class Constituency < DataElement
|
79
|
+
|
80
|
+
def initialize(*args)
|
81
|
+
super
|
82
|
+
end
|
83
|
+
def geometry
|
84
|
+
@geometry ||= @client.geometry(:name=>@name)
|
85
|
+
end
|
86
|
+
|
87
|
+
def mp
|
88
|
+
@mp ||= @client.mp(:constituency=>@name)
|
89
|
+
end
|
90
|
+
|
91
|
+
end
|
92
|
+
|
93
|
+
class Geometry < DataElement
|
94
|
+
|
95
|
+
convert :constituency do |source,value|
|
96
|
+
Constituency.new(source.client, :name => value, :geometry => source)
|
97
|
+
end
|
98
|
+
|
99
|
+
end
|
100
|
+
|
101
|
+
end
|
data/lib/twfy.rb
ADDED
@@ -0,0 +1,173 @@
|
|
1
|
+
require 'open-uri'
|
2
|
+
require 'json'
|
3
|
+
require 'cgi'
|
4
|
+
require 'ostruct'
|
5
|
+
require 'logger'
|
6
|
+
|
7
|
+
require File.join(File.dirname(__FILE__), 'data_element')
|
8
|
+
|
9
|
+
module Twfy
|
10
|
+
|
11
|
+
VERSION = '1.0.0'
|
12
|
+
BASE = URI.parse('http://www.theyworkforyou.com/api/')
|
13
|
+
|
14
|
+
API_VERSION = '1.0.0'
|
15
|
+
|
16
|
+
class Client
|
17
|
+
|
18
|
+
class Error < ::StandardError; end
|
19
|
+
class ServiceArgumentError < ::ArgumentError; end
|
20
|
+
class APIError < ::StandardError; end
|
21
|
+
|
22
|
+
def initialize(log_to=$stderr)
|
23
|
+
@logger = Logger.new(log_to)
|
24
|
+
end
|
25
|
+
|
26
|
+
def log(message, level=:info)
|
27
|
+
@logger.send(level, message) if $DEBUG
|
28
|
+
end
|
29
|
+
|
30
|
+
def convert_url(params={})
|
31
|
+
service :convertURL, validate(params, :require => :url) do |value|
|
32
|
+
URI.parse(value['url'])
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def constituency(params={})
|
37
|
+
service :getConstituency, validate(params, :require => :postcode), Constituency
|
38
|
+
end
|
39
|
+
|
40
|
+
def constituencies(params={})
|
41
|
+
service :getConstituencies, validate(params, :allow => [:date, :search, :longitude, :latitude, :distance]), Constituency
|
42
|
+
end
|
43
|
+
|
44
|
+
def mp(params={})
|
45
|
+
service :getMP, validate(params, :allow => [:postcode, :constituency, :id, :always_return]), MP
|
46
|
+
end
|
47
|
+
|
48
|
+
def mp_info(params={})
|
49
|
+
service :getMPInfo, validate(params, :require => :id)
|
50
|
+
end
|
51
|
+
|
52
|
+
def mps(params={})
|
53
|
+
service :getMPs, validate(params, :allow => [:date, :search]), MP
|
54
|
+
end
|
55
|
+
|
56
|
+
def lord(params={})
|
57
|
+
service :getLord, validate(params, :require => :id)
|
58
|
+
end
|
59
|
+
|
60
|
+
def lords(params={})
|
61
|
+
service :getLords, validate(params, :allow => [:date, :search])
|
62
|
+
end
|
63
|
+
|
64
|
+
def geometry(params={})
|
65
|
+
service :getGeometry, validate(params, :allow => :name), Geometry
|
66
|
+
end
|
67
|
+
|
68
|
+
def committee(params={})
|
69
|
+
service :getCommittee, validate(params, :require => :name, :allow => :date)
|
70
|
+
end
|
71
|
+
|
72
|
+
def debates(params={})
|
73
|
+
service :getDebates, validate(params, :require => :type, :require_one_of => [:date, :person, :search, :gid], :allow_dependencies => {
|
74
|
+
:search => [:order, :page, :num],
|
75
|
+
:person => [:order, :page, :num]
|
76
|
+
})
|
77
|
+
end
|
78
|
+
|
79
|
+
def wrans(params={})
|
80
|
+
service :getWrans, validate(params, :require_one_of => [:date, :person, :search, :gid], :allow_dependencies => {
|
81
|
+
:search => [:order, :page, :num],
|
82
|
+
:person => [:order, :page, :num]
|
83
|
+
} )
|
84
|
+
end
|
85
|
+
|
86
|
+
def wms(params={})
|
87
|
+
service :getWMS, validate(params, :require_one_of => [:date, :person, :search, :gid], :allow_dependencies => {
|
88
|
+
:search => [:order, :page, :num],
|
89
|
+
:person => [:order, :page, :num]
|
90
|
+
} )
|
91
|
+
end
|
92
|
+
|
93
|
+
def comments(params={})
|
94
|
+
service :getComments, validate(params, :allow => [:date, :search, :user_id, :pid, :page, :num])
|
95
|
+
end
|
96
|
+
|
97
|
+
def service(name, params={}, target=OpenStruct, &block)
|
98
|
+
log "Calling service #{name}"
|
99
|
+
url = BASE + name.to_s
|
100
|
+
url.query = build_query(params)
|
101
|
+
result = JSON.parse(url.read)
|
102
|
+
log result.inspect
|
103
|
+
unless result.kind_of?(Enumerable)
|
104
|
+
raise Error, "Could not handle result: #{result.inspect}"
|
105
|
+
end
|
106
|
+
if result.kind_of?(Hash) && result['error']
|
107
|
+
raise APIError, result['error'].to_s
|
108
|
+
else
|
109
|
+
structure result, block || target
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
#######
|
114
|
+
private
|
115
|
+
#######
|
116
|
+
|
117
|
+
def validate(params, against)
|
118
|
+
requirements = against[:require].kind_of?(Array) ? against[:require] : [against[:require]].compact
|
119
|
+
allowed = against[:allow].kind_of?(Array) ? against[:allow] : [against[:allow]].compact
|
120
|
+
require_one = against[:require_one_of].kind_of?(Array) ? against[:require_one_of] : [against[:require_one_of]].compact
|
121
|
+
allow_dependencies = against[:allow_dependencies] || {}
|
122
|
+
provided_keys = params.keys.map{|k| k.to_sym }
|
123
|
+
|
124
|
+
# Add allowed dependencies
|
125
|
+
allow_dependencies.each do |key,dependent_keys|
|
126
|
+
dependent_keys = dependent_keys.kind_of?(Array) ? dependent_keys : [dependent_keys].compact
|
127
|
+
allowed += dependent_keys if provided_keys.include?(key)
|
128
|
+
end
|
129
|
+
|
130
|
+
if (missing = requirements.select{|r| !provided_keys.include? r }).any?
|
131
|
+
raise ServiceArgumentError, "Missing required params #{missing.inspect}"
|
132
|
+
end
|
133
|
+
|
134
|
+
if require_one.any?
|
135
|
+
if (count = provided_keys.inject(0){|count,item| count + (require_one.include?(item) ? 1 : 0) }) < 1
|
136
|
+
raise ServiceArgumentError, "Need exactly one of #{require_one.inspect}"
|
137
|
+
elsif count > 1
|
138
|
+
raise ServiceArgumentError, "Only one of #{require_one.inspect} allowed"
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
unless (extra = provided_keys - (requirements + allowed + require_one)).empty?
|
143
|
+
raise ServiceArgumentError, "Unknown params #{extra.inspect}"
|
144
|
+
end
|
145
|
+
|
146
|
+
params
|
147
|
+
end
|
148
|
+
|
149
|
+
def structure(value, target)
|
150
|
+
case value
|
151
|
+
when Array
|
152
|
+
value.map{|r| structure(r, target) }
|
153
|
+
when Hash
|
154
|
+
if target.kind_of?(Proc)
|
155
|
+
target.call(value)
|
156
|
+
elsif target == Hash
|
157
|
+
value
|
158
|
+
else
|
159
|
+
target.ancestors.include?(DataElement) ? target.new(self,value) : target.new(value)
|
160
|
+
end
|
161
|
+
else
|
162
|
+
result
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
def build_query(params)
|
167
|
+
params.update(:version=>API_VERSION)
|
168
|
+
params.map{|set| set.map{|i| CGI.escape(i.to_s)}.join('=') }.join('&')
|
169
|
+
end
|
170
|
+
|
171
|
+
end
|
172
|
+
|
173
|
+
end
|
data/test/test_twfy.rb
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require File.join(File.dirname(__FILE__), '../lib/twfy')
|
3
|
+
|
4
|
+
class BasicReturnedDataTest < Test::Unit::TestCase
|
5
|
+
|
6
|
+
def setup
|
7
|
+
@client = Twfy::Client.new
|
8
|
+
end
|
9
|
+
|
10
|
+
def test_convert_url
|
11
|
+
uri = @client.convert_url(:url=>'http://www.publications.parliament.uk/pa/cm200506/cmhansrd/cm061018/debtext/61018-0002.htm#06101834000471')
|
12
|
+
assert_kind_of URI::HTTP, uri
|
13
|
+
assert_equal "www.theyworkforyou.com", uri.host
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_mp_and_mp_info
|
17
|
+
mp = @client.mp(:postcode=>'IP6 9PN')
|
18
|
+
assert_kind_of Twfy::MP, mp
|
19
|
+
assert_kind_of OpenStruct, @client.mp_info(:id=>mp.person_id)
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_mps
|
23
|
+
mps = @client.mps
|
24
|
+
assert_kind_of Array, mps
|
25
|
+
mps.each do |mp|
|
26
|
+
assert_kind_of Twfy::MP, mp
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_constituency_and_geometry
|
31
|
+
c = @client.constituency(:postcode => 'IP6 9PN')
|
32
|
+
assert_kind_of Twfy::Constituency, c
|
33
|
+
assert_kind_of Twfy::Geometry, @client.geometry(:name=>c.name)
|
34
|
+
end
|
35
|
+
|
36
|
+
def test_constituencies
|
37
|
+
cs = @client.constituencies
|
38
|
+
assert_kind_of Array, cs
|
39
|
+
cs.each do |c|
|
40
|
+
assert_kind_of Twfy::Constituency, c
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require File.join(File.dirname(__FILE__), '../lib/twfy')
|
3
|
+
|
4
|
+
class ChainDataTest < Test::Unit::TestCase
|
5
|
+
|
6
|
+
def setup
|
7
|
+
@client = Twfy::Client.new
|
8
|
+
@mp = @client.mp(:postcode=>'IP6 9PN')
|
9
|
+
end
|
10
|
+
|
11
|
+
def test_single_chain_class
|
12
|
+
assert_kind_of Twfy::Constituency, @mp.constituency
|
13
|
+
c = @mp.instance_eval{ @constituency }
|
14
|
+
assert c
|
15
|
+
assert_kind_of Twfy::Constituency, c
|
16
|
+
end
|
17
|
+
|
18
|
+
def test_reflexive_chain_class
|
19
|
+
c = @mp.constituency
|
20
|
+
assert_kind_of Twfy::Constituency, c
|
21
|
+
mp = @mp.constituency.mp
|
22
|
+
assert_kind_of Twfy::MP, mp
|
23
|
+
assert c.instance_eval{ @mp }
|
24
|
+
assert_equal mp, c.instance_eval{ @mp }
|
25
|
+
end
|
26
|
+
|
27
|
+
def test_round_trip_chain_class
|
28
|
+
c = @mp.constituency
|
29
|
+
assert_kind_of Twfy::Constituency, c
|
30
|
+
c2 = @mp.constituency.mp.constituency
|
31
|
+
assert_kind_of Twfy::Constituency, @mp.instance_eval{ @constituency }
|
32
|
+
assert_kind_of Twfy::MP, @mp.constituency.instance_eval{ @mp }
|
33
|
+
assert_kind_of Twfy::Constituency, @mp.constituency.mp.instance_eval{ @constituency }
|
34
|
+
assert_kind_of Twfy::Constituency, c2
|
35
|
+
assert_equal c.name, c2.name
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_overkill_chain_class
|
39
|
+
mp = @mp.constituency.mp.constituency.geometry.constituency.mp
|
40
|
+
assert_kind_of Twfy::MP, mp
|
41
|
+
assert_equal @mp.full_name, mp.full_name
|
42
|
+
end
|
43
|
+
|
44
|
+
def test_simple_chain_and_direct_call_are_equivalent
|
45
|
+
assert_equal @client.mp_info(:id=>@mp.person_id), @mp.info
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
|
metadata
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
rubygems_version: 0.8.11
|
3
|
+
specification_version: 1
|
4
|
+
name: twfy
|
5
|
+
version: !ruby/object:Gem::Version
|
6
|
+
version: 1.0.0
|
7
|
+
date: 2006-11-20 00:00:00 -07:00
|
8
|
+
summary: Ruby library to interface with the TheyWorkForYou(.com) API; an information source on Parliament
|
9
|
+
require_paths:
|
10
|
+
- lib
|
11
|
+
- test
|
12
|
+
email: bruce@codefluency.com
|
13
|
+
homepage: http://twfy.rubyforge.org
|
14
|
+
rubyforge_project: twfy
|
15
|
+
description: Ruby library to interface with the TheyWorkForYou API. TheyWorkForYou.com is "a non-partisan, volunteer-run website which aims to make it easy for people to keep tabs on their elected and unelected representatives in Parliament."
|
16
|
+
autorequire:
|
17
|
+
default_executable:
|
18
|
+
bindir: bin
|
19
|
+
has_rdoc: true
|
20
|
+
required_ruby_version: !ruby/object:Gem::Version::Requirement
|
21
|
+
requirements:
|
22
|
+
- - ">"
|
23
|
+
- !ruby/object:Gem::Version
|
24
|
+
version: 0.0.0
|
25
|
+
version:
|
26
|
+
platform: ruby
|
27
|
+
signing_key:
|
28
|
+
cert_chain:
|
29
|
+
authors:
|
30
|
+
- Bruce Williams
|
31
|
+
- Martin Owens
|
32
|
+
files:
|
33
|
+
- History.txt
|
34
|
+
- Manifest.txt
|
35
|
+
- README.txt
|
36
|
+
- Rakefile
|
37
|
+
- lib/data_element.rb
|
38
|
+
- lib/twfy.rb
|
39
|
+
- test/test_twfy.rb
|
40
|
+
- test/test_twfy_chain.rb
|
41
|
+
test_files: []
|
42
|
+
|
43
|
+
rdoc_options: []
|
44
|
+
|
45
|
+
extra_rdoc_files: []
|
46
|
+
|
47
|
+
executables: []
|
48
|
+
|
49
|
+
extensions: []
|
50
|
+
|
51
|
+
requirements: []
|
52
|
+
|
53
|
+
dependencies:
|
54
|
+
- !ruby/object:Gem::Dependency
|
55
|
+
name: json
|
56
|
+
version_requirement:
|
57
|
+
version_requirements: !ruby/object:Gem::Version::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 0.0.0
|
62
|
+
version:
|
63
|
+
- !ruby/object:Gem::Dependency
|
64
|
+
name: paginator
|
65
|
+
version_requirement:
|
66
|
+
version_requirements: !ruby/object:Gem::Version::Requirement
|
67
|
+
requirements:
|
68
|
+
- - ">"
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
version: 0.0.0
|
71
|
+
version:
|