festivals_lab 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -0
- data/CONTRIBUTING.md +16 -0
- data/Gemfile.lock +1 -1
- data/LICENSE +22 -0
- data/README.md +63 -0
- data/lib/festivals_lab/version.rb +1 -1
- data/lib/festivals_lab.rb +43 -36
- data/test/lib/test_festivals_lab.rb +34 -14
- metadata +6 -3
data/.gitignore
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
/pkg/
|
data/CONTRIBUTING.md
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
# Contributing #
|
2
|
+
|
3
|
+
Thanks for reading this! Contributions are very welcome via Github pull request, but first bear in mind a couple of general guidelines that I'm starting out with:
|
4
|
+
|
5
|
+
* The gem is designed to lightly wrap the Festivals Lab API, and not be too smart about processing the input or output. The API is currently in beta and behaviour is subject to change
|
6
|
+
|
7
|
+
* Create separate pull requests for each feature, and try not to include changes that aren't relevant to the request (for example, `.gitignore`)
|
8
|
+
|
9
|
+
## Getting started ##
|
10
|
+
|
11
|
+
To start hacking at the code, it should be as simple as checking out the code and running the tests
|
12
|
+
|
13
|
+
> git clone https://github.com/gareth/festivals_lab.git
|
14
|
+
> cd festivals_lab
|
15
|
+
> bundle
|
16
|
+
> bundle exec rake
|
data/Gemfile.lock
CHANGED
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
(The MIT License)
|
2
|
+
|
3
|
+
Copyright (c) 2013 Gareth Adams
|
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 NONINFRINGEMENT.
|
19
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
20
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
21
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
22
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
CHANGED
@@ -0,0 +1,63 @@
|
|
1
|
+
# Festivals Lab API #
|
2
|
+
|
3
|
+
An unofficial library to access festival data from the Edinburgh Festivals Innovation Lab API
|
4
|
+
|
5
|
+
## Description ##
|
6
|
+
|
7
|
+
Festivals Lab is an open data initiative which provides free access to the events of the 12 annual Edinburgh festivals.
|
8
|
+
|
9
|
+
The `festivals_lab` gem wraps the API and ties it with a Ruby bow
|
10
|
+
|
11
|
+
## Compatibility ##
|
12
|
+
|
13
|
+
* As an alpha, `festivals_lab` is only developed and tested against Ruby 1.9.3 (other rubies should work, but run the tests first).
|
14
|
+
* There are no external dependencies for use other than the Ruby standard library.
|
15
|
+
|
16
|
+
## Installation ##
|
17
|
+
|
18
|
+
Install festivals_lab like any other ruby gem:
|
19
|
+
|
20
|
+
> gem install festivals_lab
|
21
|
+
|
22
|
+
Or, to use it in a project with Bundler, add this to your Gemfile:
|
23
|
+
|
24
|
+
gem 'festivals_lab'
|
25
|
+
|
26
|
+
…and then run the bundle install command from your shell:
|
27
|
+
|
28
|
+
> bundle
|
29
|
+
|
30
|
+
## Usage ##
|
31
|
+
|
32
|
+
To use the FestivalsLab API you will need an API key, which can be obtained from the [Festivals Lab website][gettingstarted].
|
33
|
+
|
34
|
+
The parameters for library method calls match the [official documentation][querying], with the following considerations:
|
35
|
+
|
36
|
+
* The `key` and `signature` parameters are automatically added for you based on your authentication details, so there is no need to supply those to each API call.
|
37
|
+
* All parameters should be passed as `String` or `Numeric` (e.g. `Integer` or `Float`), specifically `Date`s aren't converted into the API's expected format yet
|
38
|
+
* The library exclusively requests JSON responses from the API, and the `pretty` parameter is invalid.
|
39
|
+
|
40
|
+
[gettingstarted]: http://api.festivalslab.com/documentation#gettingstarted
|
41
|
+
[querying]: http://api.festivalslab.com/documentation#Querying the API
|
42
|
+
|
43
|
+
### Sample usage ###
|
44
|
+
|
45
|
+
api = FestivalsLab.new("xxAPIAccessKeyxx", "xxAPISecretKeyxxxxAPISecretKeyxx")
|
46
|
+
|
47
|
+
api.events # The first page of events (using the API's default of 25 per page)
|
48
|
+
|
49
|
+
api.events(festival: 'book', size: 50, from: 100)
|
50
|
+
|
51
|
+
api.events(festival: 'fringe', post_code: 'EH1', price_to: 5)
|
52
|
+
|
53
|
+
The library returns the data as returned from the API, run through a JSON parser
|
54
|
+
|
55
|
+
### License ###
|
56
|
+
|
57
|
+
This software is open source and is licensed under the MIT license.
|
58
|
+
|
59
|
+
See the LICENSE file for more details
|
60
|
+
|
61
|
+
### Contributing ###
|
62
|
+
|
63
|
+
See the CONTRIBUTING file
|
data/lib/festivals_lab.rb
CHANGED
@@ -4,14 +4,14 @@ require 'openssl' # Provides HMAC-SHA1
|
|
4
4
|
|
5
5
|
class FestivalsLab
|
6
6
|
|
7
|
-
attr_accessor :
|
7
|
+
attr_accessor :access_key, :secret_token
|
8
8
|
|
9
9
|
SCHEME = "http"
|
10
10
|
HOST = "api.festivalslab.com"
|
11
11
|
|
12
|
-
def initialize
|
13
|
-
@access_token = access_token
|
12
|
+
def initialize access_key, secret_token
|
14
13
|
@access_key = access_key
|
14
|
+
@secret_token = secret_token
|
15
15
|
end
|
16
16
|
|
17
17
|
def events params = {}
|
@@ -36,47 +36,54 @@ class FestivalsLab
|
|
36
36
|
|
37
37
|
raise ArgumentError, "Unexpected events parameter: #{invalid_keys.join ", "}" if invalid_keys.any?
|
38
38
|
|
39
|
-
request '/events', params
|
39
|
+
FestivalsLab.request access_key, secret_token, '/events', params
|
40
40
|
end
|
41
41
|
|
42
|
-
def
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
42
|
+
def event uuid
|
43
|
+
FestivalsLab.request access_key, secret_token, "/event/#{uuid}"
|
44
|
+
end
|
45
|
+
|
46
|
+
class << self
|
47
|
+
def request access_key, secret_token, endpoint, params = {}
|
48
|
+
uri = FestivalsLab.signed_uri access_key, secret_token, endpoint, params
|
49
|
+
Net::HTTP.start(uri.host, uri.port) do |http|
|
50
|
+
request = Net::HTTP::Get.new uri.request_uri
|
51
|
+
request['Accept'] = 'application/json'
|
52
|
+
response = http.request request
|
53
|
+
if Net::HTTPSuccess === response
|
54
|
+
JSON.parse(response.body)
|
55
|
+
else
|
56
|
+
raise ApiError.new(response)
|
57
|
+
end
|
52
58
|
end
|
53
59
|
end
|
54
|
-
end
|
55
60
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
params[:signature] = self.signature uri.to_s
|
68
|
-
uri.query = URI.encode_www_form(params)
|
69
|
-
|
70
|
-
uri.scheme = SCHEME
|
71
|
-
uri.host = HOST
|
72
|
-
# Now the URI has a scheme we can convert it to an actual URI::HTTP
|
73
|
-
URI.parse(uri.to_s)
|
74
|
-
end
|
61
|
+
def signed_uri access_key, secret_token, endpoint, params = {}
|
62
|
+
params = params.dup
|
63
|
+
raise Error, "Missing API access key" unless access_key
|
64
|
+
raise Error, "Missing API secret token" unless secret_token
|
65
|
+
# Start with a generic URI representing just the path
|
66
|
+
# This is convenient because the URI represents the string which gets signed
|
67
|
+
uri = URI(endpoint)
|
68
|
+
|
69
|
+
params[:key] = access_key
|
70
|
+
uri.query = URI.encode_www_form(params)
|
75
71
|
|
76
|
-
|
77
|
-
|
72
|
+
params[:signature] = FestivalsLab.signature secret_token, uri.to_s
|
73
|
+
uri.query = URI.encode_www_form(params)
|
74
|
+
|
75
|
+
uri.scheme = SCHEME
|
76
|
+
uri.host = HOST
|
77
|
+
# Now the URI has a scheme we can convert it to an actual URI::HTTP
|
78
|
+
URI.parse(uri.to_s)
|
79
|
+
end
|
80
|
+
|
81
|
+
def signature secret_token, url
|
82
|
+
OpenSSL::HMAC.hexdigest 'sha1', secret_token, url
|
83
|
+
end
|
78
84
|
end
|
79
85
|
|
86
|
+
|
80
87
|
Error = Class.new(StandardError)
|
81
88
|
ArgumentError = Class.new(::ArgumentError)
|
82
89
|
ApiError = Class.new(StandardError) do
|
@@ -21,13 +21,13 @@ describe FestivalsLab do
|
|
21
21
|
it "sets an access token" do
|
22
22
|
api = FestivalsLab.new "123", nil
|
23
23
|
|
24
|
-
api.
|
24
|
+
api.access_key.must_equal "123"
|
25
25
|
end
|
26
26
|
|
27
27
|
it "sets an access key" do
|
28
28
|
api = FestivalsLab.new nil, "456"
|
29
29
|
|
30
|
-
api.
|
30
|
+
api.secret_token.must_equal "456"
|
31
31
|
end
|
32
32
|
end
|
33
33
|
|
@@ -84,7 +84,27 @@ describe FestivalsLab do
|
|
84
84
|
end
|
85
85
|
end
|
86
86
|
|
87
|
-
describe "#
|
87
|
+
describe "#event" do
|
88
|
+
it "requests the event from the API" do
|
89
|
+
stub = stub_http_request(:get, %r{//api\.festivalslab\.com/event/00000000000000000000000000000000deadbeef})
|
90
|
+
.to_return(@successful_response)
|
91
|
+
|
92
|
+
response = @api.event '00000000000000000000000000000000deadbeef'
|
93
|
+
|
94
|
+
assert_requested(stub)
|
95
|
+
end
|
96
|
+
|
97
|
+
it "returns the parsed event" do
|
98
|
+
stub = stub_http_request(:get, %r{//api\.festivalslab\.com/event/00000000000000000000000000000000deadbeef})
|
99
|
+
.to_return(@successful_response)
|
100
|
+
|
101
|
+
response = @api.event '00000000000000000000000000000000deadbeef'
|
102
|
+
|
103
|
+
assert_equal [{}], response
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
describe "request" do
|
88
108
|
before do
|
89
109
|
@uri = "http://api.festivalslab.com/events?key=123&signature=742969faae86a4ba4223c7d93d05ead4b1397c23"
|
90
110
|
end
|
@@ -92,7 +112,7 @@ describe FestivalsLab do
|
|
92
112
|
it "makes a request to the signed endpoint URI" do
|
93
113
|
stub_request(:get, @uri).to_return(@successful_response)
|
94
114
|
|
95
|
-
@api.
|
115
|
+
FestivalsLab.request @api.access_key, @api.secret_token, '/events'
|
96
116
|
|
97
117
|
assert_requested(:get, @uri)
|
98
118
|
end
|
@@ -101,7 +121,7 @@ describe FestivalsLab do
|
|
101
121
|
stub = stub_http_request(:get, @uri)
|
102
122
|
.to_return(@successful_response)
|
103
123
|
|
104
|
-
response = @api.
|
124
|
+
response = FestivalsLab.request @api.access_key, @api.secret_token, '/events'
|
105
125
|
|
106
126
|
assert_equal [{}], response
|
107
127
|
end
|
@@ -110,32 +130,32 @@ describe FestivalsLab do
|
|
110
130
|
stub = stub_http_request(:get, @uri)
|
111
131
|
.to_return(@failed_response)
|
112
132
|
|
113
|
-
lambda { @api.
|
133
|
+
lambda { FestivalsLab.request @api.access_key, @api.secret_token, '/events' }.must_raise(FestivalsLab::ApiError)
|
114
134
|
end
|
115
135
|
end
|
116
136
|
|
117
|
-
describe "
|
137
|
+
describe "signed_uri" do
|
118
138
|
it "requires an access key to be set" do
|
119
|
-
@api.
|
120
|
-
lambda { @api.
|
139
|
+
@api.secret_token = nil
|
140
|
+
lambda { FestivalsLab.signed_uri(@api.access_key, @api.secret_token, '/events') }.must_raise(FestivalsLab::Error, "Missing API access key")
|
121
141
|
end
|
122
142
|
|
123
143
|
it "requires an access token to be set" do
|
124
|
-
@api.
|
125
|
-
lambda { @api.
|
144
|
+
@api.access_key = nil
|
145
|
+
lambda { FestivalsLab.signed_uri(@api.access_key, @api.secret_token, '/events') }.must_raise(FestivalsLab::Error, "Missing API access token")
|
126
146
|
end
|
127
147
|
|
128
148
|
it "appends the correct signature to the request URI" do
|
129
|
-
uri = @api.
|
149
|
+
uri = FestivalsLab.signed_uri(@api.access_key, @api.secret_token, '/events', {:key => 123})
|
130
150
|
uri.must_be_kind_of(URI)
|
131
151
|
uri.to_s.must_equal 'http://api.festivalslab.com/events?key=123&signature=742969faae86a4ba4223c7d93d05ead4b1397c23'
|
132
152
|
end
|
133
153
|
end
|
134
154
|
|
135
|
-
describe "
|
155
|
+
describe "signature" do
|
136
156
|
it "calculates the HMAC-SHA1 signature based on the access key" do
|
137
157
|
## Because `OpenSSL#HMAC.hexdigest('sha1', '456', '/events?key=123')` # => '742969faae86a4ba4223c7d93d05ead4b1397c23'
|
138
|
-
@api.
|
158
|
+
FestivalsLab.signature(@api.secret_token, '/events?key=123').must_equal '742969faae86a4ba4223c7d93d05ead4b1397c23'
|
139
159
|
end
|
140
160
|
end
|
141
161
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: festivals_lab
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -66,9 +66,12 @@ executables: []
|
|
66
66
|
extensions: []
|
67
67
|
extra_rdoc_files: []
|
68
68
|
files:
|
69
|
+
- .gitignore
|
69
70
|
- .rvmrc
|
71
|
+
- CONTRIBUTING.md
|
70
72
|
- Gemfile
|
71
73
|
- Gemfile.lock
|
74
|
+
- LICENSE
|
72
75
|
- README.md
|
73
76
|
- Rakefile
|
74
77
|
- festivals_lab.gemspec
|
@@ -90,7 +93,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
90
93
|
version: '0'
|
91
94
|
segments:
|
92
95
|
- 0
|
93
|
-
hash:
|
96
|
+
hash: 4234472854470534461
|
94
97
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
95
98
|
none: false
|
96
99
|
requirements:
|
@@ -99,7 +102,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
99
102
|
version: '0'
|
100
103
|
segments:
|
101
104
|
- 0
|
102
|
-
hash:
|
105
|
+
hash: 4234472854470534461
|
103
106
|
requirements: []
|
104
107
|
rubyforge_project:
|
105
108
|
rubygems_version: 1.8.24
|