twoffein-client 0.1.0
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.
- data/.gitignore +7 -0
- data/.rspec +2 -0
- data/.rvmrc +1 -0
- data/Gemfile +4 -0
- data/LICENSE +22 -0
- data/README.md +207 -0
- data/README.md.erb +52 -0
- data/Rakefile +67 -0
- data/VERSION +1 -0
- data/bin/twoffein-client +84 -0
- data/features/step_definitions/twoffein-client_steps.rb +1 -0
- data/features/support/env.rb +16 -0
- data/features/twoffein-client.feature +13 -0
- data/fixtures/vcr_cassettes/cookie.yml +234 -0
- data/fixtures/vcr_cassettes/drink.yml +60 -0
- data/fixtures/vcr_cassettes/drinks.yml +461 -0
- data/fixtures/vcr_cassettes/profile.yml +69 -0
- data/fixtures/vcr_cassettes/tweet.yml +103 -0
- data/lib/twoffein-client.rb +12 -0
- data/lib/twoffein-client/constants.rb +9 -0
- data/lib/twoffein-client/cookie.rb +23 -0
- data/lib/twoffein-client/credentials.rb +5 -0
- data/lib/twoffein-client/drink.rb +43 -0
- data/lib/twoffein-client/drinks.rb +96 -0
- data/lib/twoffein-client/exceptions.rb +15 -0
- data/lib/twoffein-client/http.rb +96 -0
- data/lib/twoffein-client/profile.rb +61 -0
- data/lib/twoffein-client/tweet.rb +31 -0
- data/lib/twoffein-client/util.rb +7 -0
- data/lib/twoffein-client/version.rb +7 -0
- data/spec/constants_spec.rb +11 -0
- data/spec/cookie_spec.rb +25 -0
- data/spec/drink_spec.rb +49 -0
- data/spec/drinks_spec.rb +154 -0
- data/spec/exceptions_spec.rb +14 -0
- data/spec/http_spec.rb +94 -0
- data/spec/profile_spec.rb +58 -0
- data/spec/spec_helper.rb +25 -0
- data/spec/tweet_spec.rb +41 -0
- data/spec/util_spec.rb +20 -0
- data/twoffein-client.gemspec +28 -0
- metadata +245 -0
@@ -0,0 +1,69 @@
|
|
1
|
+
---
|
2
|
+
http_interactions:
|
3
|
+
- request:
|
4
|
+
method: get
|
5
|
+
uri: http://twoffein.com/api/get/profile/?api_key=1CBA7V9XFKHJ&screen_name=DSIW
|
6
|
+
body:
|
7
|
+
encoding: US-ASCII
|
8
|
+
string: ''
|
9
|
+
headers:
|
10
|
+
Accept:
|
11
|
+
- ! '*/*'
|
12
|
+
User-Agent:
|
13
|
+
- Ruby
|
14
|
+
response:
|
15
|
+
status:
|
16
|
+
code: 200
|
17
|
+
message: OK
|
18
|
+
headers:
|
19
|
+
Date:
|
20
|
+
- Wed, 22 Aug 2012 14:26:16 GMT
|
21
|
+
Server:
|
22
|
+
- Apache/2.2.15 (CentOS)
|
23
|
+
X-Powered-By:
|
24
|
+
- PHP/5.4.4
|
25
|
+
Connection:
|
26
|
+
- close
|
27
|
+
Transfer-Encoding:
|
28
|
+
- chunked
|
29
|
+
Content-Type:
|
30
|
+
- application/json; charset=utf-8
|
31
|
+
body:
|
32
|
+
encoding: US-ASCII
|
33
|
+
string: ! '{"quest":"Blitzlicht","drink":"Club-Mate","rank":74,"rank_title":"Kaffeek\u00e4nnchen","drunken":"15","bluttwoffeinkonzentration":"1%","first_login":"1341747375","screen_name":"DSIW"}'
|
34
|
+
http_version:
|
35
|
+
recorded_at: Wed, 22 Aug 2012 14:26:16 GMT
|
36
|
+
- request:
|
37
|
+
method: get
|
38
|
+
uri: http://twoffein.com/api/get/profile/?api_key=1CBA7V9XFKHJ&profile=BakeRolls&screen_name=DSIW
|
39
|
+
body:
|
40
|
+
encoding: US-ASCII
|
41
|
+
string: ''
|
42
|
+
headers:
|
43
|
+
Accept:
|
44
|
+
- ! '*/*'
|
45
|
+
User-Agent:
|
46
|
+
- Ruby
|
47
|
+
response:
|
48
|
+
status:
|
49
|
+
code: 200
|
50
|
+
message: OK
|
51
|
+
headers:
|
52
|
+
Date:
|
53
|
+
- Wed, 22 Aug 2012 14:27:12 GMT
|
54
|
+
Server:
|
55
|
+
- Apache/2.2.15 (CentOS)
|
56
|
+
X-Powered-By:
|
57
|
+
- PHP/5.4.4
|
58
|
+
Connection:
|
59
|
+
- close
|
60
|
+
Transfer-Encoding:
|
61
|
+
- chunked
|
62
|
+
Content-Type:
|
63
|
+
- application/json; charset=utf-8
|
64
|
+
body:
|
65
|
+
encoding: US-ASCII
|
66
|
+
string: ! '{"quest":"Blitzlicht","drink":"Club-Mate","rank":74,"rank_title":"Kaffeek\u00e4nnchen","drunken":"15","bluttwoffeinkonzentration":"1%","first_login":"1341747375","screen_name":"DSIW"}'
|
67
|
+
http_version:
|
68
|
+
recorded_at: Wed, 22 Aug 2012 14:27:12 GMT
|
69
|
+
recorded_with: VCR 2.2.4
|
@@ -0,0 +1,103 @@
|
|
1
|
+
---
|
2
|
+
http_interactions:
|
3
|
+
- request:
|
4
|
+
method: get
|
5
|
+
uri: http://twoffein.com/api/post/tweet/?api_key=1CBA7V9XFKHJ&drink=clubmate&screen_name=DSIW&target_screen_name=UserDoesNotExistTest
|
6
|
+
body:
|
7
|
+
encoding: US-ASCII
|
8
|
+
string: ''
|
9
|
+
headers:
|
10
|
+
Accept:
|
11
|
+
- ! '*/*'
|
12
|
+
User-Agent:
|
13
|
+
- Ruby
|
14
|
+
response:
|
15
|
+
status:
|
16
|
+
code: 200
|
17
|
+
message: OK
|
18
|
+
headers:
|
19
|
+
Date:
|
20
|
+
- Wed, 22 Aug 2012 13:46:08 GMT
|
21
|
+
Server:
|
22
|
+
- Apache/2.2.15 (CentOS)
|
23
|
+
X-Powered-By:
|
24
|
+
- PHP/5.4.4
|
25
|
+
Connection:
|
26
|
+
- close
|
27
|
+
Transfer-Encoding:
|
28
|
+
- chunked
|
29
|
+
Content-Type:
|
30
|
+
- application/json; charset=utf-8
|
31
|
+
body:
|
32
|
+
encoding: US-ASCII
|
33
|
+
string: ! '{"code":"luna","info":"Youre Tweet has been tweeted. Thanks.","tweets":1}'
|
34
|
+
http_version:
|
35
|
+
recorded_at: Wed, 22 Aug 2012 13:46:08 GMT
|
36
|
+
- request:
|
37
|
+
method: get
|
38
|
+
uri: http://twoffein.com/api/post/tweet/?api_key=1CBA7V9XFKHJ&drink=clubmate&screen_name=DSIW&target_screen_name=BakeRolls
|
39
|
+
body:
|
40
|
+
encoding: US-ASCII
|
41
|
+
string: ''
|
42
|
+
headers:
|
43
|
+
Accept:
|
44
|
+
- ! '*/*'
|
45
|
+
User-Agent:
|
46
|
+
- Ruby
|
47
|
+
response:
|
48
|
+
status:
|
49
|
+
code: 200
|
50
|
+
message: OK
|
51
|
+
headers:
|
52
|
+
Date:
|
53
|
+
- Wed, 22 Aug 2012 13:51:28 GMT
|
54
|
+
Server:
|
55
|
+
- Apache/2.2.15 (CentOS)
|
56
|
+
X-Powered-By:
|
57
|
+
- PHP/5.4.4
|
58
|
+
Connection:
|
59
|
+
- close
|
60
|
+
Transfer-Encoding:
|
61
|
+
- chunked
|
62
|
+
Content-Type:
|
63
|
+
- application/json; charset=utf-8
|
64
|
+
body:
|
65
|
+
encoding: US-ASCII
|
66
|
+
string: ! '{"code":"pinkiepie","error":"You cant drink more than one drink in
|
67
|
+
15 minutes.","sleep":9}'
|
68
|
+
http_version:
|
69
|
+
recorded_at: Wed, 22 Aug 2012 13:51:28 GMT
|
70
|
+
- request:
|
71
|
+
method: get
|
72
|
+
uri: http://twoffein.com/api/post/tweet/?api_key=1CBA7V9XFKHJ&drink=clubmate&screen_name=DSIW
|
73
|
+
body:
|
74
|
+
encoding: US-ASCII
|
75
|
+
string: ''
|
76
|
+
headers:
|
77
|
+
Accept:
|
78
|
+
- ! '*/*'
|
79
|
+
User-Agent:
|
80
|
+
- Ruby
|
81
|
+
response:
|
82
|
+
status:
|
83
|
+
code: 200
|
84
|
+
message: OK
|
85
|
+
headers:
|
86
|
+
Date:
|
87
|
+
- Wed, 22 Aug 2012 14:07:21 GMT
|
88
|
+
Server:
|
89
|
+
- Apache/2.2.15 (CentOS)
|
90
|
+
X-Powered-By:
|
91
|
+
- PHP/5.4.4
|
92
|
+
Connection:
|
93
|
+
- close
|
94
|
+
Transfer-Encoding:
|
95
|
+
- chunked
|
96
|
+
Content-Type:
|
97
|
+
- application/json; charset=utf-8
|
98
|
+
body:
|
99
|
+
encoding: US-ASCII
|
100
|
+
string: ! '{"code":"luna","info":"Youre Tweet has been tweeted. Thanks.","tweets":2}'
|
101
|
+
http_version:
|
102
|
+
recorded_at: Wed, 22 Aug 2012 14:07:22 GMT
|
103
|
+
recorded_with: VCR 2.2.4
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require "twoffein-client/version"
|
2
|
+
require "twoffein-client/credentials"
|
3
|
+
|
4
|
+
require "twoffein-client/http"
|
5
|
+
require "twoffein-client/util"
|
6
|
+
require "twoffein-client/exceptions"
|
7
|
+
|
8
|
+
require "twoffein-client/drink"
|
9
|
+
require "twoffein-client/drinks"
|
10
|
+
require "twoffein-client/profile"
|
11
|
+
require "twoffein-client/tweet"
|
12
|
+
require "twoffein-client/cookie"
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require_relative "exceptions"
|
2
|
+
require_relative "http"
|
3
|
+
|
4
|
+
module Twoffein
|
5
|
+
class Cookie
|
6
|
+
attr_accessor :target_screen_name
|
7
|
+
|
8
|
+
def initialize target_screen_name
|
9
|
+
@target_screen_name = target_screen_name
|
10
|
+
end
|
11
|
+
|
12
|
+
def post
|
13
|
+
info = HTTP.post("cookie", :target_screen_name => @target_screen_name)
|
14
|
+
raise Server::Error.new(info[:code], info[:error]) if info.has_key? :error
|
15
|
+
info
|
16
|
+
end
|
17
|
+
alias send post
|
18
|
+
|
19
|
+
def to_s
|
20
|
+
"Ich gebe #@target_screen_name einen Keks!"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Twoffein
|
4
|
+
class Drink
|
5
|
+
attr_reader :name, :key, :brand
|
6
|
+
|
7
|
+
def initialize(name, key=nil, brand=false)
|
8
|
+
@name = name.to_s
|
9
|
+
@key = (key ? key : key_of(name)).to_sym
|
10
|
+
@brand = !!brand
|
11
|
+
end
|
12
|
+
|
13
|
+
def to_s
|
14
|
+
"#@name (#@key)"
|
15
|
+
end
|
16
|
+
|
17
|
+
def ==(drink)
|
18
|
+
name == drink.name &&
|
19
|
+
key == drink.key &&
|
20
|
+
brand == drink.brand
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def key_of(name)
|
26
|
+
key = name.dup
|
27
|
+
changes = {
|
28
|
+
'ü' => 'ue',
|
29
|
+
'Ü' => 'Ue',
|
30
|
+
'ö' => 'oe',
|
31
|
+
'Ö' => 'Oe',
|
32
|
+
'ä' => 'ae',
|
33
|
+
'Ä' => 'Ae',
|
34
|
+
}
|
35
|
+
changes.each { |orig, trans| key.gsub!(orig, trans) }
|
36
|
+
|
37
|
+
removeables = [/\W/]
|
38
|
+
removeables.each { |r| key.gsub!(r, '') }
|
39
|
+
|
40
|
+
key.downcase.to_sym
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
require_relative "drink"
|
2
|
+
require_relative "http"
|
3
|
+
|
4
|
+
module Twoffein
|
5
|
+
class Drinks
|
6
|
+
attr_reader :all
|
7
|
+
|
8
|
+
def initialize(subset=nil)
|
9
|
+
unless subset
|
10
|
+
@all ||= Drinks.get
|
11
|
+
return @all.map! do |drink|
|
12
|
+
name = drink[:drink]
|
13
|
+
key = drink[:key].to_sym
|
14
|
+
brand = (drink[:brand] == "0" ? false : true)
|
15
|
+
Drink.new(name, key, brand)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
if subset.is_a? Array
|
20
|
+
@all = subset
|
21
|
+
else
|
22
|
+
@all = [subset]
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
class << self
|
27
|
+
def all; new.all; end
|
28
|
+
def names; all.map { |d| d.name }; end
|
29
|
+
def keys; all.map { |d| d.key }; end
|
30
|
+
def brands; all.map { |d| d.brand }; end
|
31
|
+
|
32
|
+
def get
|
33
|
+
HTTP.get("drinks", :drink => :all)
|
34
|
+
end
|
35
|
+
|
36
|
+
def find(key)
|
37
|
+
key = key.to_sym
|
38
|
+
all.each { |d| return d if d.key == key }
|
39
|
+
nil
|
40
|
+
end
|
41
|
+
alias :[] :find
|
42
|
+
|
43
|
+
def search search
|
44
|
+
search = /#{search}/i unless search.is_a? Regexp
|
45
|
+
selected = all.select { |drink| drink.to_s =~ search }
|
46
|
+
new(selected)
|
47
|
+
#all.grep(search) # TODO see :===
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def add(drink)
|
52
|
+
raise ArgumentError, "drink has to be of type Drink" unless drink.is_a? Drink
|
53
|
+
@all << drink
|
54
|
+
end
|
55
|
+
|
56
|
+
def to_s
|
57
|
+
name_max_length = @all.map { |d| d.name.length }.max
|
58
|
+
pre_key = " ("
|
59
|
+
post_key = ")"
|
60
|
+
|
61
|
+
# Calc max length of line
|
62
|
+
length = lambda do |drink|
|
63
|
+
key = drink.key
|
64
|
+
[pre_key, key, post_key].map { |cont|
|
65
|
+
cont.length
|
66
|
+
}.push(name_max_length).reduce(&:+)
|
67
|
+
end
|
68
|
+
max_line = @all.map { |d| length.call(d) }.max
|
69
|
+
|
70
|
+
# Header
|
71
|
+
header = ["Drink".ljust(name_max_length), pre_key, "key", post_key].join
|
72
|
+
line = "-"*max_line
|
73
|
+
|
74
|
+
# Drinks
|
75
|
+
drinks = @all.map { |d|
|
76
|
+
name = d.name
|
77
|
+
key = d.key
|
78
|
+
[name.ljust(name_max_length), pre_key, key, post_key].join
|
79
|
+
}.join("\n")
|
80
|
+
|
81
|
+
# All
|
82
|
+
[header, line, drinks].join("\n")
|
83
|
+
end
|
84
|
+
|
85
|
+
private
|
86
|
+
|
87
|
+
# Delegates method call to @all if it has defined this method
|
88
|
+
def method_missing(method, *args, &block)
|
89
|
+
if @all.respond_to? method
|
90
|
+
@all.send(method, *args, &block)
|
91
|
+
else
|
92
|
+
super(method, *args, &block)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'net/http'
|
3
|
+
require 'uri'
|
4
|
+
#require 'rexml/document'
|
5
|
+
|
6
|
+
require_relative "util"
|
7
|
+
require_relative "constants"
|
8
|
+
|
9
|
+
module Twoffein
|
10
|
+
class HTTP
|
11
|
+
def self.create_url(path, params={})
|
12
|
+
query = URI.encode_www_form(params)
|
13
|
+
# TODO: Change API-URI: Add controller in MVC –> rest_client (https://github.com/adamwiggins/rest-client)
|
14
|
+
URI.join(BASE_URL, path+'/').to_s + '?' + query
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.fetch(uri_str, limit = 10)
|
18
|
+
# You should choose a better exception.
|
19
|
+
raise ArgumentError, 'too many HTTP redirects' if limit == 0
|
20
|
+
|
21
|
+
response = Net::HTTP.get_response(URI(uri_str))
|
22
|
+
|
23
|
+
case response
|
24
|
+
when Net::HTTPSuccess then
|
25
|
+
response
|
26
|
+
when Net::HTTPRedirection then
|
27
|
+
location = response['location']
|
28
|
+
#warn "redirected to #{location}"
|
29
|
+
fetch(location, limit - 1)
|
30
|
+
else
|
31
|
+
response.value
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.request(verb, path, params={})
|
36
|
+
Util.compact! params
|
37
|
+
case verb
|
38
|
+
when :get
|
39
|
+
res = fetch(create_url([verb, path].join('/'), PARAMS.merge(params)))
|
40
|
+
case content_type(res)
|
41
|
+
when /xml/
|
42
|
+
puts "XML isn't supported."
|
43
|
+
exit 1
|
44
|
+
#xml = REXML::Document.new(res.body)
|
45
|
+
when /json/
|
46
|
+
return JSON.parse(res.body, :symbolize_names => true)
|
47
|
+
end
|
48
|
+
when :post # TODO
|
49
|
+
res = fetch(create_url([:post, path].join('/'), PARAMS.merge(params)))
|
50
|
+
end
|
51
|
+
JSON.parse(res.body, :symbolize_names => true)
|
52
|
+
end
|
53
|
+
|
54
|
+
def self.post_data(path, data, params={})
|
55
|
+
#self.request(:post, path, params)
|
56
|
+
uri = URI(path)
|
57
|
+
req = Net::HTTP::Post.new(uri.path)
|
58
|
+
req.set_form_data(data)
|
59
|
+
#req.body = multipart_data
|
60
|
+
#req.content_type = 'multipart/form-data'
|
61
|
+
|
62
|
+
res = Net::HTTP.start(uri.hostname, uri.port) do |http|
|
63
|
+
http.request(req)
|
64
|
+
end
|
65
|
+
|
66
|
+
case res
|
67
|
+
when Net::HTTPSuccess, Net::HTTPRedirection
|
68
|
+
# OK
|
69
|
+
else
|
70
|
+
raise res.value
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def self.get(path, params={})
|
75
|
+
request(:get, path, params)
|
76
|
+
end
|
77
|
+
|
78
|
+
def self.post(path, params={})
|
79
|
+
request(:post, path, params)
|
80
|
+
end
|
81
|
+
|
82
|
+
private
|
83
|
+
|
84
|
+
def self.content_type(res)
|
85
|
+
res["Content-Type"].split(';').first
|
86
|
+
end
|
87
|
+
|
88
|
+
def self.xml?(res)
|
89
|
+
content_type(res) == "application/xml"
|
90
|
+
end
|
91
|
+
|
92
|
+
def self.json?(res)
|
93
|
+
content_type(res) == "application/json"
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|