drink-socially 0.0.4

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.
@@ -0,0 +1,69 @@
1
+ require 'cgi'
2
+
3
+ module NRB
4
+ module Untappd
5
+ class API
6
+
7
+ private
8
+
9
+ class Credential
10
+
11
+ class IncompleteCredentialError < ArgumentError; end
12
+
13
+ def self.valid_attrs
14
+ [ :access_token, :client_id, :client_secret ]
15
+ end
16
+
17
+
18
+ def initialize(opts={})
19
+ opts.slice!(*self.class.valid_attrs)
20
+ @creds = {}
21
+ !! opts[:access_token] && @creds[:access_token] = CGI::escape(opts[:access_token])
22
+ !! opts[:client_id] && @creds[:client_id] = CGI::escape(opts[:client_id])
23
+ !! opts[:client_secret] && @creds[:client_secret] = CGI::escape(opts[:client_secret])
24
+ raise IncompleteCredentialError.new('Provide either API access token or API client id & secret') unless valid?
25
+ end
26
+
27
+ valid_attrs.each do |m|
28
+ define_method m do
29
+ @creds[m]
30
+ end
31
+ end
32
+
33
+
34
+ def is_client?
35
+ !! @creds[:client_id] && !! @creds[:client_secret]
36
+ end
37
+ alias_method :is_app?, :is_client?
38
+
39
+
40
+ def is_user?
41
+ !! @creds[:access_token]
42
+ end
43
+
44
+
45
+ def merge(hash)
46
+ @creds.merge(hash)
47
+ end
48
+
49
+
50
+ def to_h
51
+ @creds
52
+ end
53
+
54
+
55
+ def to_param
56
+ @creds.map { |k,v| "#{k}=#{v}" }.join("&")
57
+ end
58
+
59
+ private
60
+
61
+ def valid?
62
+ (is_client? || is_user?) && ! (is_client? && is_user?)
63
+ end
64
+
65
+ end
66
+
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,13 @@
1
+ module NRB
2
+ module Untappd
3
+ class API
4
+ class Notification
5
+
6
+ def initialize(response)
7
+
8
+ end
9
+
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,83 @@
1
+ module NRB
2
+ module Untappd
3
+ class API
4
+ class Object < HTTPService::Response
5
+
6
+ attr_reader :attributes, :error_message, :pagination, :results
7
+
8
+ def initialize(args)
9
+ super
10
+ parse_error_response
11
+ setup_pagination(args)
12
+ extract_results args[:results_path]
13
+ end
14
+
15
+ private
16
+
17
+ def define_attributes_from(hash)
18
+ return unless hash.respond_to?(:keys)
19
+ @attributes ||= []
20
+ perform_unless_respond_to(hash.keys) do |attr|
21
+ @attributes.push(attr.to_sym)
22
+ end
23
+ end
24
+
25
+
26
+ def define_methods_from(hash)
27
+ return unless hash.respond_to?(:keys)
28
+ perform_unless_respond_to(hash.keys) do |meth|
29
+ define_singleton_method meth, lambda { hash[meth] }
30
+ end
31
+ end
32
+
33
+
34
+ def extract_from_body(path)
35
+ return unless !! body
36
+ path.inject(body) do |node,method_name|
37
+ break unless node.respond_to? method_name
38
+ node.send method_name
39
+ end
40
+ end
41
+
42
+
43
+ def extract_results(path)
44
+ @results = extract_from_body path if !! path
45
+ define_attributes_from @results
46
+ define_methods_from @results
47
+ end
48
+
49
+
50
+ def parse_error_response
51
+ return unless errored?
52
+ @error_message = if body[:meta]
53
+ "[#{body[:meta][:error_type]}] #{body[:meta][:error_detail]}"
54
+
55
+ elsif body[:error]
56
+ body[:error]
57
+
58
+ else
59
+ "Could not parse error message from response body"
60
+ end
61
+ end
62
+
63
+
64
+ def perform_unless_respond_to(arr)
65
+ return unless arr.respond_to?(:each)
66
+ arr.each do |key|
67
+ unless respond_to?(key)
68
+ yield key
69
+ end
70
+ end
71
+ end
72
+
73
+
74
+ def setup_pagination(args)
75
+ @paginator = args[:paginator_class] || NRB::Untappd::API::Pagination
76
+ @pagination = @paginator.from_response self
77
+ end
78
+
79
+ end
80
+ end
81
+ end
82
+ end
83
+
@@ -0,0 +1,73 @@
1
+ require 'uri'
2
+ module NRB
3
+ module Untappd
4
+ class API
5
+ class Pagination
6
+
7
+ def self.from_response(response)
8
+ # It's duck types (almost) all the way down
9
+ return unless response.respond_to?(:body) &&
10
+ response.body.respond_to?(:response) &&
11
+ response.body.response.respond_to?(:pagination) &&
12
+ !! response.body.response.pagination
13
+ new response.body.response.pagination
14
+ end
15
+
16
+
17
+ def initialize(pagination)
18
+ @api_max_id = pagination[:max_id].to_i
19
+ @uris = { api_next: URI.parse(pagination[:next_url]),
20
+ api_prev: URI.parse(pagination[:since_url]),
21
+ api_since: URI.parse(pagination[:since_url])
22
+ }
23
+ end
24
+
25
+
26
+ def next_id
27
+ @api_max_id + 1
28
+ end
29
+
30
+
31
+ # Warning: The API will return the most recent results if next_id is
32
+ # greater than the most recent result
33
+ def next_uri
34
+ uri_for query: "since=#{next_id}", uri: :next
35
+ end
36
+
37
+
38
+ def next_url
39
+ next_uri.to_s
40
+ end
41
+
42
+
43
+ def prev_id
44
+ @api_max_id - 1
45
+ end
46
+ alias_method :previous_id, :prev_id
47
+
48
+
49
+ def prev_uri
50
+ uri_for query: "max_id=#{prev_id}", uri: :prev
51
+ end
52
+ alias_method :previous_uri, :prev_uri
53
+
54
+
55
+ def prev_url
56
+ prev_uri.to_s
57
+ end
58
+ alias_method :previous_url, :prev_url
59
+
60
+ private
61
+
62
+ def uri_for(opts)
63
+ return nil unless !! opts[:uri]
64
+ return @uris[otps[:uri]] if @uris[opts[:uri]]
65
+ @uris[otps[:uri]] = @uris["api_#{opts[:uri]}".to_sym]
66
+ @uris[otps[:uri]].query = opts[:query] if opts[:query]
67
+ @uris[otps[:uri]]
68
+ end
69
+
70
+ end
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,17 @@
1
+ module NRB
2
+ module Untappd
3
+ class API
4
+ class RateLimit
5
+
6
+ attr_reader :limit, :remaining
7
+
8
+ def initialize(headers)
9
+ return unless headers.respond_to?(:[])
10
+ @limit = headers["x-ratelimit-limit"]
11
+ @remaining = headers["x-ratelimit-remaining"]
12
+ end
13
+
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,47 @@
1
+ require 'strscan'
2
+ module NRB
3
+ module Untappd
4
+ class API
5
+ class URLTokenizer
6
+ attr_reader :map, :string
7
+
8
+ def initialize(args)
9
+ @map = args[:map]
10
+ @string = args[:string]
11
+ raise ArgumentError unless @map && @string
12
+ end
13
+
14
+
15
+ def tr
16
+ return @string unless @string =~ /:[#{word_chars}]+:/
17
+ result = ""
18
+ s = StringScanner.new(@string)
19
+ until s.eos? do
20
+ word = s.scan(/:[#{word_chars}]+:|[#{url_chars}]+/)
21
+ raise RuntimeError.new("String Scanner failed. File a bug.") if word.nil?
22
+ result += tr_word(word)
23
+ end
24
+ result
25
+ end
26
+
27
+ private
28
+
29
+ def tr_word(word)
30
+ return word unless word =~ /:([#{word_chars}]+):/
31
+ return map[$1.to_sym].to_s
32
+ end
33
+
34
+
35
+ def url_chars
36
+ word_chars + Regexp.quote('/')
37
+ end
38
+
39
+
40
+ def word_chars
41
+ "0-9a-zA-Z" + Regexp.quote("$-_.+!*'(),")
42
+ end
43
+
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,48 @@
1
+ require 'yaml'
2
+
3
+ module NRB
4
+ module Untappd
5
+ class Config
6
+
7
+ class NoConfig < ArgumentError; end
8
+
9
+ extend Forwardable
10
+
11
+ attr_reader :data
12
+
13
+ def_delegators :@data, :[], :each, :keys
14
+
15
+ def initialize(args)
16
+ load_data(args)
17
+ define_accessors
18
+ end
19
+
20
+ private
21
+
22
+ def define_accessors
23
+ return unless @data
24
+ @data.keys.each do |name|
25
+ unless respond_to?(name)
26
+ define_singleton_method name, lambda { data[name] }
27
+ end
28
+ end
29
+ end
30
+
31
+
32
+ def find_stream(args)
33
+ if args[:filename]
34
+ File.open args[:filename]
35
+ end
36
+ end
37
+
38
+
39
+ def load_data(args)
40
+ args[:stream] ||= find_stream(args)
41
+ raise NoConfig.new("Please supply :filename or :stream to Config.new") unless !! args[:stream]
42
+ loader = args[:stream_loader] || YAML
43
+ @data = loader.load_stream(args[:stream])[0]
44
+ end
45
+
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,17 @@
1
+ class Hash
2
+
3
+ def slice(*keys)
4
+ hash = self.class.new
5
+ keys.each { |k| hash[k] = self[k] if has_key?(k) }
6
+ hash
7
+ end
8
+
9
+
10
+ def slice!(*keys)
11
+ omit = slice(*self.keys - keys)
12
+ hash = slice(*keys)
13
+ replace(hash)
14
+ omit
15
+ end
16
+
17
+ end
@@ -0,0 +1,61 @@
1
+ require 'faraday'
2
+ require 'faraday_middleware/parse_oj'
3
+
4
+ module NRB
5
+ class HTTPService
6
+
7
+ autoload :Response, 'drink-socially/http_service/response'
8
+
9
+ DEFAULT_MIDDLEWARE = Proc.new do |faraday|
10
+ faraday.adapter Faraday.default_adapter
11
+ faraday.request :url_encoded
12
+ faraday.response :oj
13
+ end
14
+
15
+ class << self
16
+ attr_accessor :faraday_middleware
17
+
18
+ def default_middleware; DEFAULT_MIDDLEWARE; end
19
+ def default_http_class; Faraday; end
20
+ def default_response_class; Response; end
21
+
22
+
23
+ def make_request(args={}, connection_opts={})
24
+ new(args,connection_opts).make_request
25
+ end
26
+
27
+ end
28
+
29
+ self.faraday_middleware = self.default_middleware
30
+
31
+
32
+ def initialize(args={}, connection_opts={})
33
+ @connection_opts = connection_opts
34
+ @response_class = args.delete(:response_class) || self.class.default_response_class
35
+ @verb = args.delete(:verb)
36
+ @url = args.delete(:url)
37
+ @params = process_args(args)
38
+ @args = args
39
+ end
40
+
41
+
42
+ def make_request
43
+ connection = self.class.default_http_class.new @url, @connection_opts, &self.class.faraday_middleware
44
+ response = connection.send @verb, @url, @params
45
+ args = @args.merge( { body: response.body, headers: response.headers, status: response.status.to_i } )
46
+ @response_class.new args
47
+ rescue Faraday::Error::ParsingError => e
48
+ self.class.default_response_class.new body: {error: e.message}, status: 500
49
+ end
50
+
51
+ private
52
+
53
+ attr_reader :params, :verb, :url
54
+
55
+ def process_args(args)
56
+ return args unless @verb == :post
57
+ args.inject("") { |str,pair| str += "#{pair.first}=#{pair.last}&" }.chop
58
+ end
59
+
60
+ end
61
+ end
@@ -0,0 +1,27 @@
1
+ require 'hashie'
2
+
3
+ module NRB
4
+ class HTTPService
5
+ class Response
6
+
7
+ attr_reader :status, :body, :headers
8
+
9
+ def errored?
10
+ ! success?
11
+ end
12
+
13
+
14
+ def initialize(args)
15
+ @status = args[:status]
16
+ @body = Hashie::Mash.new args[:body]
17
+ @headers = Hashie::Mash.new args[:headers]
18
+ end
19
+
20
+
21
+ def success?
22
+ @status >= 200 && @status < 300
23
+ end
24
+
25
+ end
26
+ end
27
+ end