brewery_db 0.0.1 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (65) hide show
  1. checksums.yaml +15 -0
  2. data/.gitignore +2 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +5 -0
  5. data/CHANGELOG.md +15 -0
  6. data/README.md +81 -29
  7. data/Rakefile +5 -0
  8. data/brewery_db.gemspec +6 -5
  9. data/lib/brewery_db.rb +15 -19
  10. data/lib/brewery_db/client.rb +19 -7
  11. data/lib/brewery_db/collection.rb +42 -0
  12. data/lib/brewery_db/config.rb +7 -6
  13. data/lib/brewery_db/mash.rb +18 -0
  14. data/lib/brewery_db/middleware/error_handler.rb +28 -0
  15. data/lib/brewery_db/request.rb +27 -0
  16. data/lib/brewery_db/resource.rb +16 -22
  17. data/lib/brewery_db/resources/beers.rb +2 -2
  18. data/lib/brewery_db/resources/breweries.rb +2 -2
  19. data/lib/brewery_db/resources/brewery.rb +16 -0
  20. data/lib/brewery_db/resources/categories.rb +2 -2
  21. data/lib/brewery_db/resources/glassware.rb +2 -2
  22. data/lib/brewery_db/resources/search.rb +1 -1
  23. data/lib/brewery_db/resources/styles.rb +2 -2
  24. data/lib/brewery_db/response.rb +26 -12
  25. data/lib/brewery_db/version.rb +1 -1
  26. data/lib/brewery_db/web_hook.rb +32 -0
  27. data/spec/brewery_db/client_spec.rb +41 -30
  28. data/spec/brewery_db/config_spec.rb +25 -28
  29. data/spec/brewery_db/{response_spec.rb → mash_spec.rb} +1 -1
  30. data/spec/brewery_db/middleware/error_handler_spec.rb +49 -0
  31. data/spec/brewery_db/resource_spec.rb +35 -22
  32. data/spec/brewery_db/resources/beers_spec.rb +10 -82
  33. data/spec/brewery_db/resources/breweries_spec.rb +10 -54
  34. data/spec/brewery_db/resources/brewery_spec.rb +27 -0
  35. data/spec/brewery_db/resources/categories_spec.rb +10 -38
  36. data/spec/brewery_db/resources/glassware_spec.rb +10 -36
  37. data/spec/brewery_db/resources/search_spec.rb +19 -61
  38. data/spec/brewery_db/resources/styles_spec.rb +10 -72
  39. data/spec/brewery_db/web_hook_spec.rb +79 -0
  40. data/spec/fixtures/BreweryDB_Resource/_get/a_list_of_resources/can_be_enumerated.yml +515 -0
  41. data/spec/fixtures/BreweryDB_Resource/_get/a_not_found_request/raises_an_exception.yml +38 -0
  42. data/spec/fixtures/BreweryDB_Resource/_get/a_not_found_request/sets_the_exception_message_to_the_error_message_in_the_response.yml +38 -0
  43. data/spec/fixtures/BreweryDB_Resource/_get/an_OK_request/name/.yml +54 -0
  44. data/spec/fixtures/BreweryDB_Resources_Beers/_all/fetches_all_of_the_beers_at_once.yml +889 -0
  45. data/spec/fixtures/BreweryDB_Resources_Beers/_find/fetches_only_the_beer_asked_for.yml +61 -0
  46. data/spec/fixtures/BreweryDB_Resources_Breweries/_all/fetches_all_of_the_breweries_at_once.yml +430 -0
  47. data/spec/fixtures/BreweryDB_Resources_Breweries/_find/fetches_only_the_brewery_asked_for.yml +57 -0
  48. data/spec/fixtures/BreweryDB_Resources_Categories/_all/fetches_all_of_the_cagtegories_at_once.yml +49 -0
  49. data/spec/fixtures/BreweryDB_Resources_Categories/_find/fetches_only_the_category_asked_for.yml +39 -0
  50. data/spec/fixtures/BreweryDB_Resources_Glassware/_all/fetches_all_of_the_glassware_at_once.yml +45 -0
  51. data/spec/fixtures/BreweryDB_Resources_Glassware/_find/fetches_only_the_glassware_asked_for.yml +39 -0
  52. data/spec/fixtures/BreweryDB_Resources_Search/_all/fetches_all_of_the_search_results_at_once.yml +1132 -0
  53. data/spec/fixtures/BreweryDB_Resources_Styles/_all/fetches_all_of_the_styles_at_once.yml +1866 -0
  54. data/spec/fixtures/BreweryDB_Resources_Styles/_find/fetches_only_the_style_asked_for.yml +50 -0
  55. data/spec/spec_helper.rb +4 -4
  56. data/spec/support/shared/a_resource.rb +3 -9
  57. data/spec/support/vcr.rb +6 -1
  58. metadata +82 -42
  59. data/spec/brewery_db_spec.rb +0 -18
  60. data/spec/fixtures/beers.yml +0 -445
  61. data/spec/fixtures/breweries.yml +0 -409
  62. data/spec/fixtures/categories.yml +0 -102
  63. data/spec/fixtures/glassware.yml +0 -65
  64. data/spec/fixtures/search.yml +0 -314
  65. data/spec/fixtures/styles.yml +0 -317
@@ -0,0 +1,28 @@
1
+ module BreweryDB
2
+ module Middleware
3
+ class ErrorHandler < Faraday::Response::Middleware
4
+ def on_complete(env)
5
+ case env[:status]
6
+ when 200
7
+ when 400 then fail with(BadRequest, env)
8
+ when 401 then fail with(rate_limit_exceeded_or_unauthorized(env[:response_headers]), env)
9
+ when 404 then fail with(NotFound, env)
10
+ else fail with(Error, env)
11
+ end
12
+ end
13
+
14
+ def rate_limit_exceeded_or_unauthorized(headers)
15
+ rate_limit = headers.fetch('x-ratelimit-remaining') { :rate_limit_unknown }
16
+
17
+ rate_limit == '0' ? RateLimitExceeded : Unauthorized
18
+ end
19
+ private :rate_limit_exceeded_or_unauthorized
20
+
21
+ def with(error_class, env)
22
+ message = "Status => #{env[:status]}. Error message => #{env[:body].error_message}"
23
+ error_class.new(message)
24
+ end
25
+ private :with
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,27 @@
1
+ module BreweryDB
2
+ class Request
3
+ def initialize(connection, path, params={})
4
+ @connection = connection
5
+ @path = path
6
+ @params = params
7
+ end
8
+
9
+ def response
10
+ Response.new(response_body, self)
11
+ end
12
+
13
+ def next_page
14
+ self.class.new(@connection, @path, @params.merge(p: page_number + 1))
15
+ end
16
+
17
+ def response_body
18
+ @connection.get(@path, @params).body
19
+ end
20
+ private :response_body
21
+
22
+ def page_number
23
+ @params[:p] || 1
24
+ end
25
+ private :page_number
26
+ end
27
+ end
@@ -3,34 +3,28 @@ require 'faraday_middleware'
3
3
 
4
4
  module BreweryDB
5
5
  class Resource
6
- def initialize(client)
7
- @client = client
8
- end
9
-
10
- # TODO: Make this private once the appropriate test coverage is in place.
11
- def connection
12
- # TODO: Use an instance-level option once faraday_middleware is updated.
13
- FaradayMiddleware::Mashify.mash_class = Response
14
-
15
- Faraday.new(
16
- url: @client.config.endpoint,
17
- headers: { user_agent: @client.config.user_agent }
18
- ) do |connection|
19
- connection.response(:mashify)
20
- connection.response(:json, content_type: /\bjson$/)
21
-
22
- connection.adapter(@client.config.adapter)
23
- end
6
+ def initialize(config)
7
+ @config = config
24
8
  end
25
9
 
26
10
  def get(path, params={})
27
- connection.get(path, default_params.merge(params)).body
11
+ Request.new(connection, path, params).response
28
12
  end
29
13
  private :get
30
14
 
31
- def default_params
32
- { key: @client.config.api_key }
15
+ def connection
16
+ Faraday.new(request: { timeout: @config.timeout }) do |builder|
17
+ builder.url_prefix = @config.base_uri
18
+ builder.headers[:user_agent] = @config.user_agent
19
+ builder.params[:key] = @config.api_key
20
+
21
+ builder.use(Middleware::ErrorHandler)
22
+ builder.response(:mashify, mash_class: Mash)
23
+ builder.response(:json, content_type: /\bjson$/)
24
+
25
+ builder.adapter(@config.adapter)
26
+ end
33
27
  end
34
- private :default_params
28
+ private :connection
35
29
  end
36
30
  end
@@ -2,11 +2,11 @@ module BreweryDB
2
2
  module Resources
3
3
  class Beers < Resource
4
4
  def all(params={})
5
- get('beers', params)
5
+ get('beers', params).collection
6
6
  end
7
7
 
8
8
  def find(id, params={})
9
- get('beer/%s' % id, params)
9
+ get('beer/%s' % id, params).data
10
10
  end
11
11
  end
12
12
  end
@@ -2,11 +2,11 @@ module BreweryDB
2
2
  module Resources
3
3
  class Breweries < Resource
4
4
  def all(params={})
5
- get('breweries', params)
5
+ get('breweries', params).collection
6
6
  end
7
7
 
8
8
  def find(id, params={})
9
- get('brewery/%s' % id, params)
9
+ get('brewery/%s' % id, params).data
10
10
  end
11
11
  end
12
12
  end
@@ -0,0 +1,16 @@
1
+ module BreweryDB
2
+ module Resources
3
+ class Brewery < Resource
4
+ attr_reader :id
5
+
6
+ def initialize(config, options={})
7
+ @id = options[:id]
8
+ super(config)
9
+ end
10
+
11
+ def beers(params={})
12
+ get("brewery/#{id}/beers", params).data
13
+ end
14
+ end
15
+ end
16
+ end
@@ -2,11 +2,11 @@ module BreweryDB
2
2
  module Resources
3
3
  class Categories < Resource
4
4
  def all(params={})
5
- get('categories', params)
5
+ get('categories', params).data
6
6
  end
7
7
 
8
8
  def find(id, params={})
9
- get('category/%s' % id, params)
9
+ get('category/%s' % id, params).data
10
10
  end
11
11
  end
12
12
  end
@@ -2,11 +2,11 @@ module BreweryDB
2
2
  module Resources
3
3
  class Glassware < Resource
4
4
  def all(params={})
5
- get('glassware', params)
5
+ get('glassware', params).data
6
6
  end
7
7
 
8
8
  def find(id, params={})
9
- get('glass/%s' % id, params)
9
+ get('glass/%s' % id, params).data
10
10
  end
11
11
  end
12
12
  end
@@ -2,7 +2,7 @@ module BreweryDB
2
2
  module Resources
3
3
  class Search < Resource
4
4
  def all(params={})
5
- get('search', params)
5
+ get('search', params).collection
6
6
  end
7
7
 
8
8
  def beers(params={})
@@ -2,11 +2,11 @@ module BreweryDB
2
2
  module Resources
3
3
  class Styles < Resource
4
4
  def all(params={})
5
- get('styles', params)
5
+ get('styles', params).data
6
6
  end
7
7
 
8
8
  def find(id, params={})
9
- get('style/%s' % id, params)
9
+ get('style/%s' % id, params).data
10
10
  end
11
11
  end
12
12
  end
@@ -1,18 +1,32 @@
1
- require 'hashie'
2
-
3
1
  module BreweryDB
4
- class Response < Hashie::Mash
5
- def convert_key(key)
6
- key = key.to_s.dup
7
- key.gsub!(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
8
- key.gsub!(/([a-z\d])([A-Z])/, '\1_\2')
9
- key.tr('-', '_').downcase
2
+ class Response
3
+ def initialize(body, request)
4
+ @body = body
5
+ @request = request
6
+ end
7
+
8
+ def data
9
+ @body.data
10
+ end
11
+
12
+ def collection
13
+ Collection.new(self)
14
+ end
15
+
16
+ def next_page
17
+ @request.next_page.response
18
+ end
19
+
20
+ def page_number
21
+ @body.current_page
22
+ end
23
+
24
+ def page_count
25
+ @body.number_of_pages
10
26
  end
11
- protected :convert_key
12
27
 
13
- def convert_value(value, duping=false)
14
- value.is_a?(String) ? super.gsub("\r\n", "\n") : super
28
+ def count
29
+ @body.total_results
15
30
  end
16
- protected :convert_value
17
31
  end
18
32
  end
@@ -1,3 +1,3 @@
1
1
  module BreweryDB
2
- VERSION = '0.0.1'
2
+ VERSION = '0.1.0'
3
3
  end
@@ -0,0 +1,32 @@
1
+ require 'digest/sha1'
2
+
3
+ module BreweryDB
4
+ class WebHook
5
+ attr_reader :action
6
+ attr_reader :attribute
7
+ attr_reader :attribute_id
8
+ attr_reader :key
9
+ attr_reader :nonce
10
+ attr_reader :sub_action
11
+ attr_reader :timestamp
12
+
13
+ def initialize(args)
14
+ @action = args[:action]
15
+ @attribute = args[:attribute]
16
+ @attribute_id = args[:attributeId]
17
+ @key = args[:key]
18
+ @nonce = args[:nonce]
19
+ @sub_action = args[:subAction]
20
+ @timestamp = args[:timestamp]
21
+ end
22
+
23
+ def valid?(api_key)
24
+ hash(api_key) == key
25
+ end
26
+
27
+ def hash(api_key)
28
+ Digest::SHA1.hexdigest("#{api_key}#{nonce}")
29
+ end
30
+ private :hash
31
+ end
32
+ end
@@ -2,43 +2,54 @@ require 'spec_helper'
2
2
 
3
3
  describe BreweryDB::Client do
4
4
  context '#config' do
5
- subject { described_class.new.config }
6
-
7
- it { should be_a(BreweryDB::Config) }
5
+ it 'returns a configuration instance' do
6
+ subject.config.should be_a(BreweryDB::Config)
7
+ end
8
8
 
9
- its(:adapter) { should == BreweryDB::Config::ADAPTER }
10
- its(:api_key) { should == nil }
11
- its(:endpoint) { should == BreweryDB::Config::ENDPOINT }
9
+ it 'memoizes the return value' do
10
+ BreweryDB::Config.should_receive(:new).once.and_return(stub)
11
+ 2.times { subject.config }
12
+ end
12
13
  end
13
14
 
14
15
  context '#configure' do
15
- subject do
16
- described_class.new.configure do |config|
17
- config.adapter = :typhoeus
18
- config.api_key = 'A1029384756B'
19
- config.endpoint = 'http://api.playground.brewerydb.com'
20
- end
16
+ it 'can set the adapter' do
17
+ expect {
18
+ subject.configure { |config| config.adapter = :typhoeus }
19
+ }.to change(subject.config, :adapter).to(:typhoeus)
21
20
  end
22
21
 
23
- its(:adapter) { should == :typhoeus }
24
- its(:api_key) { should == 'A1029384756B' }
25
- its(:endpoint) { should == 'http://api.playground.brewerydb.com' }
26
- end
22
+ it 'can set the API key' do
23
+ expect {
24
+ subject.configure { |config| config.api_key = 'secret' }
25
+ }.to change(subject.config, :api_key).to('secret')
26
+ end
27
27
 
28
- {
29
- beers: BreweryDB::Resources::Beers,
30
- breweries: BreweryDB::Resources::Breweries,
31
- categories: BreweryDB::Resources::Categories,
32
- glassware: BreweryDB::Resources::Glassware,
33
- search: BreweryDB::Resources::Search,
34
- styles: BreweryDB::Resources::Styles
35
- }.each do |method, resource|
36
- context "##{method}" do
37
- specify do
38
- endpoint = resource.new(subject)
39
- resource.should_receive(:new).and_return(endpoint)
40
- subject.send(method).should == endpoint
41
- end
28
+ it 'can set the base URI' do
29
+ expect {
30
+ subject.configure { |config| config.base_uri = 'http://example.com' }
31
+ }.to change(subject.config, :base_uri).to('http://example.com')
32
+ end
33
+
34
+ it 'can set the timeout' do
35
+ expect {
36
+ subject.configure { |config| config.timeout = 42 }
37
+ }.to change(subject.config, :timeout).to(42)
38
+ end
39
+
40
+ it 'can set the user agent' do
41
+ expect {
42
+ subject.configure { |config| config.user_agent = 'Brewdega' }
43
+ }.to change(subject.config, :user_agent).to('Brewdega')
42
44
  end
43
45
  end
46
+
47
+ its(:beers) { should be_a(BreweryDB::Resources::Beers) }
48
+ its(:breweries) { should be_a(BreweryDB::Resources::Breweries) }
49
+ its(:categories) { should be_a(BreweryDB::Resources::Categories) }
50
+ its(:glassware) { should be_a(BreweryDB::Resources::Glassware) }
51
+ its(:search) { should be_a(BreweryDB::Resources::Search) }
52
+ its(:styles) { should be_a(BreweryDB::Resources::Styles) }
53
+
54
+ it { subject.brewery('KlSsWY').should be_a(BreweryDB::Resources::Brewery) }
44
55
  end
@@ -1,27 +1,16 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe BreweryDB::Config do
4
- {
5
- ADAPTER: Faraday.default_adapter,
6
- ENDPOINT: 'http://api.brewerydb.com/v2',
7
- USER_AGENT: "BreweryDB Ruby Gem #{BreweryDB::VERSION}"
8
- }.each do |constant, value|
9
- context constant do
10
- subject { described_class.const_get(constant) }
11
-
12
- it { should == value }
13
- end
14
- end
15
-
16
4
  context 'defaults' do
17
- its(:adapter) { should == described_class::ADAPTER }
18
- its(:api_key) { should == nil }
19
- its(:endpoint) { should == described_class::ENDPOINT }
20
- its(:user_agent) { should == described_class::USER_AGENT }
5
+ its(:adapter) { should eq Faraday.default_adapter }
6
+ its(:api_key) { should be_nil }
7
+ its(:base_uri) { should eq described_class::BASE_URI }
8
+ its(:timeout) { should eq described_class::TIMEOUT }
9
+ its(:user_agent) { should eq described_class::USER_AGENT }
21
10
  end
22
11
 
23
12
  context '#adapter=' do
24
- specify do
13
+ it do
25
14
  expect {
26
15
  subject.adapter = :typhoeus
27
16
  }.to change(subject, :adapter).to(:typhoeus)
@@ -29,26 +18,34 @@ describe BreweryDB::Config do
29
18
  end
30
19
 
31
20
  context '#api_key=' do
32
- specify do
21
+ it do
22
+ expect {
23
+ subject.api_key = 'secret'
24
+ }.to change(subject, :api_key).to('secret')
25
+ end
26
+ end
27
+
28
+ context '#base_uri=' do
29
+ it do
33
30
  expect {
34
- subject.api_key = 'A1029384756B'
35
- }.to change(subject, :api_key).to('A1029384756B')
31
+ subject.base_uri = 'http://example.com'
32
+ }.to change(subject, :base_uri).to('http://example.com')
36
33
  end
37
34
  end
38
35
 
39
- context '#endpoint=' do
40
- specify do
36
+ context 'timeout=' do
37
+ it do
41
38
  expect {
42
- subject.endpoint = 'http://api.playground.brewerydb.com'
43
- }.to change(subject, :endpoint).to('http://api.playground.brewerydb.com')
39
+ subject.timeout = 42
40
+ }.to change(subject, :timeout).to(42)
44
41
  end
45
42
  end
46
43
 
47
- context '#user_agent=' do
48
- specify do
44
+ context 'user_agent=' do
45
+ it do
49
46
  expect {
50
- subject.user_agent = 'A BreweryDB Application'
51
- }.to change(subject, :user_agent).to('A BreweryDB Application')
47
+ subject.user_agent = 'Brewdega'
48
+ }.to change(subject, :user_agent).to('Brewdega')
52
49
  end
53
50
  end
54
51
  end