twfy 1.0.1 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +17 -0
- data/.travis.yml +4 -0
- data/Gemfile +3 -0
- data/History.txt +6 -0
- data/LICENSE.txt +35 -0
- data/README.md +99 -0
- data/Rakefile +7 -19
- data/lib/twfy/api.rb +47 -0
- data/lib/twfy/client.rb +84 -0
- data/lib/twfy/commands.rb +73 -0
- data/lib/twfy/constituency.rb +15 -0
- data/lib/twfy/data_element.rb +62 -0
- data/lib/twfy/geometry.rb +17 -0
- data/lib/twfy/mp.rb +39 -0
- data/lib/twfy/validation.rb +88 -0
- data/lib/twfy/version.rb +3 -0
- data/lib/twfy.rb +12 -175
- data/test/fixtures/vcr_cassettes/client_test.yml +2723 -0
- data/test/fixtures/vcr_cassettes/data_element_test.yml +240 -0
- data/test/{test_twfy.rb → lib/twfy/client_test.rb} +13 -15
- data/test/{test_twfy_chain.rb → lib/twfy/data_element_test.rb} +12 -16
- data/test/test_helper.rb +38 -0
- data/twfy.gemspec +29 -0
- metadata +156 -76
- data/Manifest.txt +0 -9
- data/README.txt +0 -108
- data/lib/data_element.rb +0 -101
- data/test/api_key +0 -1
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 2e4a7122b6b66c6ef20ed5fd0291dfa1f76599fc
|
4
|
+
data.tar.gz: c199d960584b65f80b353e9ba5da4b60a8895abc
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: c81d7d14a1ce73b2c4f86f501a69afa9299513b1e3d62cd5e82263ed003c0d1c2fff7bfdd1c6313a283a4a0242d6cc37b6ee48fc9a3d5ba18b597d41c4994435
|
7
|
+
data.tar.gz: 1d1b0d34b3be41dfaccefd13e3b856d11fb5f34a6eeaee30797f26ebe332dffdcb529a7c540f40dbe8e7f3c557787cc30a600036ba3366cafdd749860548bfcc
|
data/.gitignore
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/History.txt
CHANGED
@@ -1,3 +1,9 @@
|
|
1
|
+
== 1.1.0 / 2013-11-12
|
2
|
+
|
3
|
+
* Modernize source
|
4
|
+
* Support Ruby 1.9, 2.0
|
5
|
+
* Requires >= Ruby 1.9
|
6
|
+
|
1
7
|
== 1.0.1 / 2008-08-02
|
2
8
|
|
3
9
|
* In the near future the TWFY API will require an API Key for all calls. In preparation for this, this binding now requires an API Key. They are available at http://www.theyworkforyou.com/api/key
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
Copyright (c) 2006 - 2013 Bruce Williams, Martin Owen & Tom Hipkin
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
23
|
+
|
24
|
+
Data is licensed separately:
|
25
|
+
|
26
|
+
The TheyWorkForYou license statement, from their website
|
27
|
+
(http://www.theyworkforyou.com/api/), is:
|
28
|
+
|
29
|
+
To use parliamentary material yourself (that's data returned from getDebates,
|
30
|
+
getWrans, and getWMS), you will need to get a Parliamentary Licence from
|
31
|
+
the Office of Public Sector Information. Our own data - lists of MPs, Lords,
|
32
|
+
constituencies and so on - is available under the Creative Commons
|
33
|
+
Attribution-ShareAlike license version 2.5.
|
34
|
+
|
35
|
+
Non-commercial use is free, please contact us for commercial use.
|
data/README.md
ADDED
@@ -0,0 +1,99 @@
|
|
1
|
+
# They Work For You
|
2
|
+
|
3
|
+
A Ruby library to interface with the
|
4
|
+
[TheyWorkForYou](http://www.theyworkforyou.com) API.
|
5
|
+
|
6
|
+
[![Build Status](https://travis-ci.org/bruce/twfy.png?branch=master)](https://travis-ci.org/bruce/twfy)
|
7
|
+
[![Code Climate](https://codeclimate.com/github/bruce/twfy.png)](https://codeclimate.com/github/bruce/twfy)
|
8
|
+
|
9
|
+
## Features
|
10
|
+
|
11
|
+
The Ruby API closely mirrors that of TWFY, with the exception that the client
|
12
|
+
methods are in lowercase and don't include the `get` prefix.
|
13
|
+
|
14
|
+
Some examples:
|
15
|
+
|
16
|
+
* `getComments` -> `comments`
|
17
|
+
* `getMPs` -> `mps`
|
18
|
+
* `getMPInfo` -> `mp_info`
|
19
|
+
|
20
|
+
## Requirements
|
21
|
+
|
22
|
+
Ruby 1.9+
|
23
|
+
|
24
|
+
* multi_json
|
25
|
+
* paginator
|
26
|
+
|
27
|
+
## Examples
|
28
|
+
|
29
|
+
### Get a Client
|
30
|
+
|
31
|
+
```ruby
|
32
|
+
require 'twfy'
|
33
|
+
client = Twfy::Client.new("YOUR-API-KEY")
|
34
|
+
```
|
35
|
+
|
36
|
+
You can get an API key from http://www.theyworkforyou.com/api/key
|
37
|
+
|
38
|
+
### Call API methods directly on client
|
39
|
+
|
40
|
+
```ruby
|
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(&: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
|
+
|
59
|
+
### Daisy Chaining
|
60
|
+
|
61
|
+
A few methods on the client return non-OpenStruct instances that
|
62
|
+
support daisy chaining. Using these to access related data more
|
63
|
+
naturally (with caching).
|
64
|
+
|
65
|
+
Here are some examples
|
66
|
+
|
67
|
+
```ruby
|
68
|
+
# Get the MP for the last constituency (if you sort them alphabetically)
|
69
|
+
mp = client.constituencies.sort_by(&:name).last.mp
|
70
|
+
# get the geometry information for that constituency (coming from the MP)
|
71
|
+
geometry = mp.constituency.geometry
|
72
|
+
|
73
|
+
# An overkill example showing caching (no services are called here, since
|
74
|
+
# the results have already been cached from above)
|
75
|
+
mp = mp.constituency.mp.constituency.geometry.constituency.mp
|
76
|
+
|
77
|
+
# These return equivalent results (Note how much easier the first is)
|
78
|
+
info1 = mp.info # this is cached for subsequent calls
|
79
|
+
info2 = client.mp_info(id: mp.person_id)
|
80
|
+
|
81
|
+
# Get pages of debates mentioning 'medicine'
|
82
|
+
debates1 = mp.debates(search: 'medicine')
|
83
|
+
debates2 = mp.debates(search: 'medicine', page: 2)
|
84
|
+
```
|
85
|
+
|
86
|
+
See http://www.theyworkforyou.com/api/docs for API documentation.
|
87
|
+
|
88
|
+
## Support
|
89
|
+
|
90
|
+
Please submit issues to https://github.com/bruce/twfy/issues
|
91
|
+
|
92
|
+
Pull requests gratefully accepted.
|
93
|
+
|
94
|
+
## License
|
95
|
+
|
96
|
+
See LICENSE.txt.
|
97
|
+
|
98
|
+
Please note that data pulled from the API is licensed separately from
|
99
|
+
this library.
|
data/Rakefile
CHANGED
@@ -1,22 +1,10 @@
|
|
1
|
-
|
1
|
+
require "bundler/gem_tasks"
|
2
2
|
|
3
|
-
require '
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
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 Owen"]
|
3
|
+
require 'rake/testtask'
|
4
|
+
Rake::TestTask.new do |t|
|
5
|
+
t.libs << "test"
|
6
|
+
t.test_files = FileList['test/**/*_test.rb']
|
7
|
+
t.verbose = true
|
20
8
|
end
|
21
9
|
|
22
|
-
|
10
|
+
task default: :test
|
data/lib/twfy/api.rb
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
module Twfy
|
2
|
+
|
3
|
+
module API
|
4
|
+
|
5
|
+
VERSION = '1.0.0'
|
6
|
+
|
7
|
+
VALIDATIONS = {
|
8
|
+
convertURL: {require: :url},
|
9
|
+
getConstituency: {require: :postcode},
|
10
|
+
getConstituencies: {allow: [:date, :search, :longitude, :latitude, :distance]},
|
11
|
+
getMP: {allow: [:postcode, :constituency, :id, :always_return]},
|
12
|
+
getMPInfo: {require: :id},
|
13
|
+
getMPs: {allow: [:date, :party, :search]},
|
14
|
+
getLord: {require: :id},
|
15
|
+
getLords: {allow: [:date, :party, :search]},
|
16
|
+
getMLAs: {allow: [:date, :party, :search]},
|
17
|
+
getMSPs: {allow: [:date, :party, :search]},
|
18
|
+
getGeometry: {allow: :name},
|
19
|
+
getCommittee: {require: :name, allow: :date},
|
20
|
+
getDebates: {
|
21
|
+
require: :type,
|
22
|
+
require_one_of: [:date, :person, :search, :gid],
|
23
|
+
allow_dependencies: {
|
24
|
+
search: [:order, :page, :num],
|
25
|
+
person: [:order, :page, :num]
|
26
|
+
}
|
27
|
+
},
|
28
|
+
getWrans: {
|
29
|
+
require_one_of: [:date, :person, :search, :gid],
|
30
|
+
allow_dependencies: {
|
31
|
+
search: [:order, :page, :num],
|
32
|
+
person: [:order, :page, :num]
|
33
|
+
}
|
34
|
+
},
|
35
|
+
getWMS: {
|
36
|
+
require_one_of: [:date, :person, :search, :gid],
|
37
|
+
allow_dependencies: {
|
38
|
+
search: [:order, :page, :num],
|
39
|
+
person: [:order, :page, :num]
|
40
|
+
}
|
41
|
+
},
|
42
|
+
getComments: {allow: [:date, :search, :user_id, :pid, :page, :num]}
|
43
|
+
}
|
44
|
+
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
data/lib/twfy/client.rb
ADDED
@@ -0,0 +1,84 @@
|
|
1
|
+
require 'cgi'
|
2
|
+
require 'logger'
|
3
|
+
require 'multi_json'
|
4
|
+
require 'open-uri'
|
5
|
+
require 'ostruct'
|
6
|
+
|
7
|
+
module Twfy
|
8
|
+
|
9
|
+
class Client
|
10
|
+
include API
|
11
|
+
include Commands
|
12
|
+
|
13
|
+
class Error < ::StandardError; end
|
14
|
+
class APIError < ::StandardError; end
|
15
|
+
|
16
|
+
def initialize(api_key, log_to=$stderr)
|
17
|
+
@api_key = api_key
|
18
|
+
@logger = Logger.new(log_to)
|
19
|
+
end
|
20
|
+
|
21
|
+
def log(message, level=:info)
|
22
|
+
@logger.send(level, message) if $DEBUG
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def service(name, params = {}, target = OpenStruct, &block)
|
28
|
+
log "Calling service #{name}"
|
29
|
+
url = service_url(name, params)
|
30
|
+
result = MultiJson.load(url.read)
|
31
|
+
log result.inspect
|
32
|
+
unless result.kind_of?(Enumerable)
|
33
|
+
raise Error, "Could not handle result: #{result.inspect}"
|
34
|
+
end
|
35
|
+
if result.kind_of?(Hash) && result['error']
|
36
|
+
raise APIError, result['error'].to_s
|
37
|
+
else
|
38
|
+
structure result, block || target
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def service_url(name, params = {})
|
43
|
+
url = BASE + name.to_s
|
44
|
+
url.query = build_query(validate(params, API::VALIDATIONS[name]))
|
45
|
+
url
|
46
|
+
end
|
47
|
+
|
48
|
+
def validate(params, against)
|
49
|
+
Validation.run(params, against)
|
50
|
+
params
|
51
|
+
end
|
52
|
+
|
53
|
+
def structure(value, target)
|
54
|
+
case value
|
55
|
+
when Array
|
56
|
+
value.map{|r| structure(r, target) }
|
57
|
+
when Hash
|
58
|
+
if target.kind_of?(Proc)
|
59
|
+
target.call(value)
|
60
|
+
elsif target == Hash
|
61
|
+
value
|
62
|
+
else
|
63
|
+
target.ancestors.include?(DataElement) ? target.new(self,value) : target.new(value)
|
64
|
+
end
|
65
|
+
else
|
66
|
+
result
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def build_query(params)
|
71
|
+
params.merge(api_params).map { |set|
|
72
|
+
set.map { |i|
|
73
|
+
CGI.escape(i.to_s)
|
74
|
+
}.join('=')
|
75
|
+
}.join('&')
|
76
|
+
end
|
77
|
+
|
78
|
+
def api_params
|
79
|
+
@api_params ||= {key: @api_key, version: API::VERSION}
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
module Twfy
|
2
|
+
module Commands
|
3
|
+
|
4
|
+
def convert_url(params = {})
|
5
|
+
service :convertURL, params do |value|
|
6
|
+
URI.parse(value['url'])
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
def constituency(params = {})
|
11
|
+
service :getConstituency, params, Constituency
|
12
|
+
end
|
13
|
+
|
14
|
+
def constituencies(params = {})
|
15
|
+
service :getConstituencies, params, Constituency
|
16
|
+
end
|
17
|
+
|
18
|
+
def mp(params = {})
|
19
|
+
service :getMP, params, MP
|
20
|
+
end
|
21
|
+
|
22
|
+
def mp_info(params = {})
|
23
|
+
service :getMPInfo, params
|
24
|
+
end
|
25
|
+
|
26
|
+
def mps(params = {})
|
27
|
+
service :getMPs, params, MP
|
28
|
+
end
|
29
|
+
|
30
|
+
def lord(params = {})
|
31
|
+
service :getLord, params
|
32
|
+
end
|
33
|
+
|
34
|
+
def lords(params = {})
|
35
|
+
service :getLords, params
|
36
|
+
end
|
37
|
+
|
38
|
+
# Members of Legislative Assembly
|
39
|
+
def mlas(params = {})
|
40
|
+
service :getMLAs, params
|
41
|
+
end
|
42
|
+
|
43
|
+
# Member of Scottish parliament
|
44
|
+
def msps(params = {})
|
45
|
+
service :getMSPs, params
|
46
|
+
end
|
47
|
+
|
48
|
+
def geometry(params = {})
|
49
|
+
service :getGeometry, params, Geometry
|
50
|
+
end
|
51
|
+
|
52
|
+
def committee(params = {})
|
53
|
+
service :getCommittee, params
|
54
|
+
end
|
55
|
+
|
56
|
+
def debates(params = {})
|
57
|
+
service :getDebates, params
|
58
|
+
end
|
59
|
+
|
60
|
+
def wrans(params = {})
|
61
|
+
service :getWrans, params
|
62
|
+
end
|
63
|
+
|
64
|
+
def wms(params = {})
|
65
|
+
service :getWMS, params
|
66
|
+
end
|
67
|
+
|
68
|
+
def comments(params = {})
|
69
|
+
service :getComments, params
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'uri'
|
2
|
+
require 'date'
|
3
|
+
|
4
|
+
module Twfy
|
5
|
+
|
6
|
+
class DataElement
|
7
|
+
|
8
|
+
@@conversions = {}
|
9
|
+
|
10
|
+
class << self
|
11
|
+
|
12
|
+
def convert(*fields,&block)
|
13
|
+
fields.each do |field|
|
14
|
+
@@conversions[field] = block
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def convert_to_date(*fields)
|
19
|
+
fields.each do |field|
|
20
|
+
convert field do |d|
|
21
|
+
Date.parse(d)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
attr_reader :client
|
29
|
+
def initialize(client, data={})
|
30
|
+
@client = client
|
31
|
+
update_attributes(data)
|
32
|
+
end
|
33
|
+
|
34
|
+
def update_attributes(data = {})
|
35
|
+
data.each do |field,value|
|
36
|
+
instance_variable_set("@#{field}", convert(field, value))
|
37
|
+
unless self.respond_to?(field)
|
38
|
+
self.class.send(:define_method, field) do
|
39
|
+
instance_variable_get("@#{field}")
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def with(data = {})
|
46
|
+
update_attributes(data)
|
47
|
+
self
|
48
|
+
end
|
49
|
+
|
50
|
+
def convert(field, value)
|
51
|
+
if conversion = @@conversions[field.to_sym]
|
52
|
+
args = [value]
|
53
|
+
args.unshift self if conversion.arity == 2
|
54
|
+
conversion.call(*args)
|
55
|
+
else
|
56
|
+
value
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
data/lib/twfy/mp.rb
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
module Twfy
|
2
|
+
|
3
|
+
class MP < DataElement
|
4
|
+
|
5
|
+
convert_to_date :entered_house, :left_house
|
6
|
+
|
7
|
+
convert :image do |value|
|
8
|
+
URI.parse("http://theyworkforyou.com#{value}")
|
9
|
+
end
|
10
|
+
|
11
|
+
convert :constituency do |source, value|
|
12
|
+
if value.is_a?(Constituency)
|
13
|
+
value
|
14
|
+
else
|
15
|
+
Constituency.new(source.client, name: value, mp: source)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def in_office?
|
20
|
+
@left_reason == 'still_in_office'
|
21
|
+
end
|
22
|
+
|
23
|
+
def info
|
24
|
+
@info ||= @client.mp_info(id: @person_id)
|
25
|
+
end
|
26
|
+
|
27
|
+
def debates(params={})
|
28
|
+
@debates ||= {}
|
29
|
+
@debates[params] ||= @client.debates(params.merge(person: @person_id, type: 'commons'))
|
30
|
+
end
|
31
|
+
|
32
|
+
def comments(params={})
|
33
|
+
@comments ||= {}
|
34
|
+
@comments[params] ||= @client.comments(params.merge(pid: @person_id))
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
module Twfy
|
2
|
+
|
3
|
+
class Validation
|
4
|
+
|
5
|
+
class ServiceArgumentError < ::ArgumentError; end
|
6
|
+
|
7
|
+
def self.run(params = {}, against = {})
|
8
|
+
new(params, against).check!
|
9
|
+
end
|
10
|
+
|
11
|
+
def initialize(params = {}, against = {})
|
12
|
+
@params = params
|
13
|
+
@against = against
|
14
|
+
end
|
15
|
+
|
16
|
+
def check!
|
17
|
+
unless missing.empty?
|
18
|
+
raise ServiceArgumentError, "Missing required params #{missing.inspect}"
|
19
|
+
end
|
20
|
+
unless extra.empty?
|
21
|
+
raise ServiceArgumentError, "Unknown params #{extra.inspect}"
|
22
|
+
end
|
23
|
+
check_one_required!
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def required
|
29
|
+
@required ||= list(@against[:require])
|
30
|
+
end
|
31
|
+
|
32
|
+
def allowed
|
33
|
+
@allowed ||= allowed_with_dependencies
|
34
|
+
end
|
35
|
+
|
36
|
+
def one_required
|
37
|
+
@one_required ||= list(@against[:require_one_of])
|
38
|
+
end
|
39
|
+
|
40
|
+
def dependencies_allowed
|
41
|
+
@dependencies_allowed ||= @against[:allow_dependencies] || {}
|
42
|
+
end
|
43
|
+
|
44
|
+
def allowed_with_dependencies
|
45
|
+
base = list(@against[:allow])
|
46
|
+
dependencies_allowed.each_with_object(base) do |(key, dependent_keys), memo|
|
47
|
+
if provided.include?(key)
|
48
|
+
memo.push(*list(dependent_keys))
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def provided
|
54
|
+
@provided ||= @params.keys.map(&:to_sym)
|
55
|
+
end
|
56
|
+
|
57
|
+
def list(candidate)
|
58
|
+
Array(candidate).dup.compact
|
59
|
+
end
|
60
|
+
|
61
|
+
def missing
|
62
|
+
@missing ||= required - provided
|
63
|
+
end
|
64
|
+
|
65
|
+
def extra
|
66
|
+
@extra ||= provided - (required + allowed + one_required)
|
67
|
+
end
|
68
|
+
|
69
|
+
def check_one_required!
|
70
|
+
count = one_required_count
|
71
|
+
if count
|
72
|
+
if count < 1
|
73
|
+
raise ServiceArgumentError, "Need exactly one of #{one_required.inspect}"
|
74
|
+
elsif count > 1
|
75
|
+
raise ServiceArgumentError, "Only one of #{one_required.inspect} allowed"
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def one_required_count
|
81
|
+
if one_required.any?
|
82
|
+
provided.select { |item| one_required.include?(item) }.size
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
87
|
+
|
88
|
+
end
|
data/lib/twfy/version.rb
ADDED