festivals_lab 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.rvmrc ADDED
@@ -0,0 +1,38 @@
1
+ #!/usr/bin/env bash
2
+
3
+ # This is an RVM Project .rvmrc file, used to automatically load the ruby
4
+ # development environment upon cd'ing into the directory
5
+
6
+ # First we specify our desired <ruby>[@<gemset>], the @gemset name is optional,
7
+ # Only full ruby name is supported here, for short names use:
8
+ # echo "rvm use 1.9.3" > .rvmrc
9
+ environment_id="ruby-1.9.3-p327@festivalslab"
10
+
11
+ # Uncomment the following lines if you want to verify rvm version per project
12
+ # rvmrc_rvm_version="1.17.0 (master)" # 1.10.1 seams as a safe start
13
+ # eval "$(echo ${rvm_version}.${rvmrc_rvm_version} | awk -F. '{print "[[ "$1*65536+$2*256+$3" -ge "$4*65536+$5*256+$6" ]]"}' )" || {
14
+ # echo "This .rvmrc file requires at least RVM ${rvmrc_rvm_version}, aborting loading."
15
+ # return 1
16
+ # }
17
+
18
+ # First we attempt to load the desired environment directly from the environment
19
+ # file. This is very fast and efficient compared to running through the entire
20
+ # CLI and selector. If you want feedback on which environment was used then
21
+ # insert the word 'use' after --create as this triggers verbose mode.
22
+ if [[ -d "${rvm_path:-$HOME/.rvm}/environments"
23
+ && -s "${rvm_path:-$HOME/.rvm}/environments/$environment_id" ]]
24
+ then
25
+ \. "${rvm_path:-$HOME/.rvm}/environments/$environment_id"
26
+ [[ -s "${rvm_path:-$HOME/.rvm}/hooks/after_use" ]] &&
27
+ \. "${rvm_path:-$HOME/.rvm}/hooks/after_use" || true
28
+ if [[ $- == *i* ]] # check for interactive shells
29
+ then echo "Using: $(tput setaf 2)$GEM_HOME$(tput sgr0)" # show the user the ruby and gemset they are using in green
30
+ else echo "Using: $GEM_HOME" # don't use colors in non-interactive shells
31
+ fi
32
+ else
33
+ # If the environment file has not yet been created, use the RVM CLI to select.
34
+ rvm --create use "$environment_id" || {
35
+ echo "Failed to create RVM environment '${environment_id}'."
36
+ return 1
37
+ }
38
+ fi
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'http://rubygems.org'
2
+
3
+ gemspec
@@ -0,0 +1,37 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ festivals_lab (0.0.1)
5
+
6
+ GEM
7
+ remote: http://rubygems.org/
8
+ specs:
9
+ addressable (2.3.5)
10
+ ansi (1.4.3)
11
+ builder (3.2.2)
12
+ crack (0.4.1)
13
+ safe_yaml (~> 0.9.0)
14
+ hashie (2.0.5)
15
+ minitest (4.7.5)
16
+ minitest-reporters (0.14.20)
17
+ ansi
18
+ builder
19
+ minitest (>= 2.12, < 5.0)
20
+ powerbar
21
+ powerbar (1.0.11)
22
+ ansi (~> 1.4.0)
23
+ hashie (>= 1.1.0)
24
+ rake (10.0.2)
25
+ safe_yaml (0.9.5)
26
+ webmock (1.13.0)
27
+ addressable (>= 2.2.7)
28
+ crack (>= 0.3.2)
29
+
30
+ PLATFORMS
31
+ ruby
32
+
33
+ DEPENDENCIES
34
+ festivals_lab!
35
+ minitest-reporters
36
+ rake
37
+ webmock
File without changes
@@ -0,0 +1,11 @@
1
+ require 'rake/testtask'
2
+
3
+ Bundler::GemHelper.install_tasks
4
+
5
+ Rake::TestTask.new do |t|
6
+ t.libs << "test"
7
+ t.test_files = FileList['test/**/test*.rb']
8
+ t.verbose = true
9
+ end
10
+
11
+ task :default => [:test]
@@ -0,0 +1,21 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/festivals_lab/version', __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.authors = ["Gareth Adams"]
6
+ gem.email = ["g@rethada.ms"]
7
+ gem.description = %q{Accesses festival data from the Edinburgh Festivals Innovation Lab API}
8
+ gem.summary = %q{The Edinburgh Festivals API is an ambitious project which aims to create open access to the event listings data of Edinburgh’s 12 major Festivals}
9
+ gem.homepage = "http://festivalslab.com/"
10
+
11
+ gem.files = `git ls-files`.split($\)
12
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
13
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
14
+ gem.name = "festivals_lab"
15
+ gem.require_paths = ["lib"]
16
+ gem.version = FestivalsLab::VERSION
17
+
18
+ gem.add_development_dependency 'rake'
19
+ gem.add_development_dependency 'webmock'
20
+ gem.add_development_dependency 'minitest-reporters'
21
+ end
@@ -0,0 +1,89 @@
1
+ require 'json'
2
+ require 'net/http'
3
+ require 'openssl' # Provides HMAC-SHA1
4
+
5
+ class FestivalsLab
6
+
7
+ attr_accessor :access_token, :access_key
8
+
9
+ SCHEME = "http"
10
+ HOST = "api.festivalslab.com"
11
+
12
+ def initialize access_token, access_key
13
+ @access_token = access_token
14
+ @access_key = access_key
15
+ end
16
+
17
+ def events params = {}
18
+ params = params.dup
19
+
20
+ # Exact field options
21
+ valid_options = [:festival, :genre, :country, :code, :year]
22
+ # Fulltext search options
23
+ valid_options += [:title, :description, :artist]
24
+ # Event date options
25
+ valid_options += [:date_from, :date_to]
26
+ # Venue options
27
+ valid_options += [:venue_name, :venue_code, :post_code, :distance, :lat, :lng]
28
+ # Price options
29
+ valid_options += [:price_from, :price_to]
30
+ # Update options
31
+ valid_options += [:modified_from]
32
+ # Pagination options
33
+ valid_options += [:size, :from]
34
+
35
+ invalid_keys = params.reject { |k,v| valid_options.include? k }.keys
36
+
37
+ raise ArgumentError, "Unexpected events parameter: #{invalid_keys.join ", "}" if invalid_keys.any?
38
+
39
+ request '/events', params
40
+ end
41
+
42
+ def request endpoint, params = {}
43
+ uri = signed_uri endpoint, params
44
+ Net::HTTP.start(uri.host, uri.port) do |http|
45
+ request = Net::HTTP::Get.new uri.request_uri
46
+ request['Accept'] = 'application/json'
47
+ response = http.request request
48
+ if Net::HTTPSuccess === response
49
+ JSON.parse(response.body)
50
+ else
51
+ raise ApiError.new(response)
52
+ end
53
+ end
54
+ end
55
+
56
+ def signed_uri endpoint, params = {}
57
+ params = params.dup
58
+ raise Error, "Missing API access key" unless access_key
59
+ raise Error, "Missing API access token" unless access_token
60
+ # Start with a generic URI representing just the path
61
+ # This is convenient because the URI represents the string which gets signed
62
+ uri = URI(endpoint)
63
+
64
+ params[:key] = access_token
65
+ uri.query = URI.encode_www_form(params)
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
75
+
76
+ def signature url
77
+ OpenSSL::HMAC.hexdigest 'sha1', access_key, url
78
+ end
79
+
80
+ Error = Class.new(StandardError)
81
+ ArgumentError = Class.new(::ArgumentError)
82
+ ApiError = Class.new(StandardError) do
83
+ attr_reader :response
84
+
85
+ def initialize response
86
+ @response = response
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,3 @@
1
+ class FestivalsLab
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,144 @@
1
+ require 'test_helper'
2
+
3
+ require 'minitest/spec'
4
+ require 'webmock/minitest'
5
+
6
+ require 'festivals_lab'
7
+
8
+ describe FestivalsLab do
9
+
10
+ before do
11
+ @api = FestivalsLab.new '123', '456'
12
+ @successful_response = { status: 200, body: "[{}]", headers: { 'Content-Type' => 'application/json' } }
13
+ @failed_response = { status: 403, body: "", headers: { 'Content-Type' => 'application/json' } }
14
+ end
15
+
16
+ it "has a VERSION" do
17
+ FestivalsLab.constants.must_include :VERSION
18
+ end
19
+
20
+ describe "#initialize" do
21
+ it "sets an access token" do
22
+ api = FestivalsLab.new "123", nil
23
+
24
+ api.access_token.must_equal "123"
25
+ end
26
+
27
+ it "sets an access key" do
28
+ api = FestivalsLab.new nil, "456"
29
+
30
+ api.access_key.must_equal "456"
31
+ end
32
+ end
33
+
34
+ describe "#events" do
35
+ [:festival, :genre, :country, :code, :year, :title, :description, :artist, :venue_name, :post_code, :distance].each do |param|
36
+ it "allows a string '#{param}' parameter" do
37
+ stub = stub_http_request(:get, %r{//api\.festivalslab\.com/events})
38
+ .with(query: hash_including(param => 'value'))
39
+ .to_return(@successful_response)
40
+
41
+ @api.events param => 'value'
42
+
43
+ assert_requested(stub)
44
+ end
45
+ end
46
+
47
+ [:venue_code, :price_from, :price_to, :size, :from, :lat, :lng].each do |param|
48
+ it "allows a numeric '#{param}' parameter" do
49
+ stub = stub_http_request(:get, %r{//api\.festivalslab\.com/events})
50
+ .with(query: hash_including(param => '42'))
51
+ .to_return(@successful_response)
52
+
53
+ @api.events param => 42
54
+
55
+ assert_requested(stub)
56
+ end
57
+ end
58
+
59
+ [:date_from, :date_to, :modified_from].each do |param|
60
+ it "allows a date '#{param}' parameter" do
61
+ stub = stub_http_request(:get, %r{//api\.festivalslab\.com/events})
62
+ .with(query: hash_including(param => '1970-01-01 01:00:00'))
63
+ .to_return(@successful_response)
64
+
65
+ @api.events param => Time.at(0).strftime("%F %T")
66
+
67
+ assert_requested(stub)
68
+ end
69
+ end
70
+
71
+ it "returns parsed events" do
72
+ stub = stub_http_request(:get, %r{//api\.festivalslab\.com/events})
73
+ .to_return(@successful_response)
74
+
75
+ response = @api.events
76
+
77
+ assert_equal [{}], response
78
+ end
79
+
80
+ it "rejects invalid parameters" do
81
+ lambda {
82
+ @api.events foobar: 42
83
+ }.must_raise(FestivalsLab::ArgumentError, "Unexpected events parameter: foobar")
84
+ end
85
+ end
86
+
87
+ describe "#request" do
88
+ before do
89
+ @uri = "http://api.festivalslab.com/events?key=123&signature=742969faae86a4ba4223c7d93d05ead4b1397c23"
90
+ end
91
+
92
+ it "makes a request to the signed endpoint URI" do
93
+ stub_request(:get, @uri).to_return(@successful_response)
94
+
95
+ @api.request '/events'
96
+
97
+ assert_requested(:get, @uri)
98
+ end
99
+
100
+ it "parses the response as JSON" do
101
+ stub = stub_http_request(:get, @uri)
102
+ .to_return(@successful_response)
103
+
104
+ response = @api.request '/events'
105
+
106
+ assert_equal [{}], response
107
+ end
108
+
109
+ it "raises FestivalsLab::ApiError on unsuccessful HTTP request" do
110
+ stub = stub_http_request(:get, @uri)
111
+ .to_return(@failed_response)
112
+
113
+ lambda { @api.request '/events' }.must_raise(FestivalsLab::ApiError)
114
+ end
115
+ end
116
+
117
+ describe "#signed_uri" do
118
+ it "requires an access key to be set" do
119
+ @api.access_key = nil
120
+ lambda { @api.signed_uri('/events') }.must_raise(FestivalsLab::Error, "Missing API access key")
121
+ end
122
+
123
+ it "requires an access token to be set" do
124
+ @api.access_token = nil
125
+ lambda { @api.signed_uri('/events') }.must_raise(FestivalsLab::Error, "Missing API access token")
126
+ end
127
+
128
+ it "appends the correct signature to the request URI" do
129
+ uri = @api.signed_uri('/events', {:key => 123})
130
+ uri.must_be_kind_of(URI)
131
+ uri.to_s.must_equal 'http://api.festivalslab.com/events?key=123&signature=742969faae86a4ba4223c7d93d05ead4b1397c23'
132
+ end
133
+ end
134
+
135
+ describe "#signature" do
136
+ it "calculates the HMAC-SHA1 signature based on the access key" do
137
+ ## Because `OpenSSL#HMAC.hexdigest('sha1', '456', '/events?key=123')` # => '742969faae86a4ba4223c7d93d05ead4b1397c23'
138
+ @api.signature('/events?key=123').must_equal '742969faae86a4ba4223c7d93d05ead4b1397c23'
139
+ end
140
+ end
141
+
142
+ end
143
+
144
+
@@ -0,0 +1,4 @@
1
+ require 'minitest/autorun'
2
+ require 'minitest/reporters'
3
+
4
+ MiniTest::Reporters.use!
metadata ADDED
@@ -0,0 +1,112 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: festivals_lab
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Gareth Adams
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-08-14 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rake
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: webmock
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ - !ruby/object:Gem::Dependency
47
+ name: minitest-reporters
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
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: '0'
62
+ description: Accesses festival data from the Edinburgh Festivals Innovation Lab API
63
+ email:
64
+ - g@rethada.ms
65
+ executables: []
66
+ extensions: []
67
+ extra_rdoc_files: []
68
+ files:
69
+ - .rvmrc
70
+ - Gemfile
71
+ - Gemfile.lock
72
+ - README.md
73
+ - Rakefile
74
+ - festivals_lab.gemspec
75
+ - lib/festivals_lab.rb
76
+ - lib/festivals_lab/version.rb
77
+ - test/lib/test_festivals_lab.rb
78
+ - test/test_helper.rb
79
+ homepage: http://festivalslab.com/
80
+ licenses: []
81
+ post_install_message:
82
+ rdoc_options: []
83
+ require_paths:
84
+ - lib
85
+ required_ruby_version: !ruby/object:Gem::Requirement
86
+ none: false
87
+ requirements:
88
+ - - ! '>='
89
+ - !ruby/object:Gem::Version
90
+ version: '0'
91
+ segments:
92
+ - 0
93
+ hash: -2264928236337400198
94
+ required_rubygems_version: !ruby/object:Gem::Requirement
95
+ none: false
96
+ requirements:
97
+ - - ! '>='
98
+ - !ruby/object:Gem::Version
99
+ version: '0'
100
+ segments:
101
+ - 0
102
+ hash: -2264928236337400198
103
+ requirements: []
104
+ rubyforge_project:
105
+ rubygems_version: 1.8.24
106
+ signing_key:
107
+ specification_version: 3
108
+ summary: The Edinburgh Festivals API is an ambitious project which aims to create
109
+ open access to the event listings data of Edinburgh’s 12 major Festivals
110
+ test_files:
111
+ - test/lib/test_festivals_lab.rb
112
+ - test/test_helper.rb