rest-core 0.0.1 → 0.2.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/README.md +36 -14
- data/TODO.md +0 -2
- data/example/facebook.rb +6 -142
- data/example/github.rb +1 -18
- data/example/linkedin.rb +8 -0
- data/example/twitter.rb +12 -0
- data/lib/rest-core.rb +5 -0
- data/lib/rest-core/builder.rb +3 -4
- data/lib/rest-core/client.rb +6 -4
- data/lib/rest-core/client/github.rb +4 -2
- data/lib/rest-core/client/linkedin.rb +11 -7
- data/lib/rest-core/client/rest-graph.rb +2 -2
- data/lib/rest-core/client/twitter.rb +17 -10
- data/lib/rest-core/middleware/oauth1_header.rb +14 -1
- data/lib/rest-core/util/config.rb +49 -0
- data/lib/rest-core/version.rb +1 -1
- data/{test/pending → pending}/test_multi.rb +0 -0
- data/{test/pending → pending}/test_test_util.rb +0 -0
- data/rest-core.gemspec +10 -21
- data/task/gemgem.rb +13 -6
- data/test/config/{rest-graph.yaml → rest-core.yaml} +0 -0
- data/test/test_load_config.rb +42 -0
- data/test/test_oauth1_header.rb +13 -0
- metadata +32 -40
- data/README +0 -83
- data/lib/rest-graph/config_util.rb +0 -43
- data/test/pending/test_load_config.rb +0 -42
- data/test/test_rest-graph.rb +0 -10
data/README.md
CHANGED
|
@@ -29,8 +29,8 @@ for any other REST APIs.
|
|
|
29
29
|
## REQUIREMENTS:
|
|
30
30
|
|
|
31
31
|
* Tested with MRI (official ruby) 1.9.2, 1.8.7, and trunk
|
|
32
|
-
* Tested with Rubinius (rbx) 1.2
|
|
33
|
-
* Tested with JRuby 1.6
|
|
32
|
+
* Tested with Rubinius (rbx) 1.2
|
|
33
|
+
* Tested with JRuby 1.6
|
|
34
34
|
|
|
35
35
|
## INSTALLATION:
|
|
36
36
|
|
|
@@ -38,31 +38,53 @@ for any other REST APIs.
|
|
|
38
38
|
|
|
39
39
|
Or if you want development version, put this in Gemfile:
|
|
40
40
|
|
|
41
|
-
gem 'rest-core', :git => 'git://github.com/cardinalblue/rest-core.git'
|
|
41
|
+
gem 'rest-core', :git => 'git://github.com/cardinalblue/rest-core.git',
|
|
42
|
+
:submodules => true
|
|
42
43
|
|
|
43
|
-
##
|
|
44
|
+
## Built-in Clients Example:
|
|
44
45
|
|
|
45
|
-
|
|
46
|
+
require 'rest-core'
|
|
47
|
+
|
|
48
|
+
RestCore::Twitter.new.statuses('godfat') # get user tweets
|
|
49
|
+
RestCore::Github.new.get('users/godfat') # get user info
|
|
50
|
+
|
|
51
|
+
linkedin = RestCore::Linkedin.new(:consumer_key => '...',
|
|
52
|
+
:consumer_secret => '...')
|
|
53
|
+
linkedin.authorize_url! # copy and paste the URL in browser to authorize
|
|
54
|
+
linkedin.authorize!('..') # paste your code from browser
|
|
55
|
+
linkedin.me # get current user info
|
|
56
|
+
|
|
57
|
+
# below is exactly the same as [rest-graph][]
|
|
58
|
+
require 'rest-core/client/rest-graph'
|
|
59
|
+
RestGraph.new.get('4') # get user info
|
|
60
|
+
|
|
61
|
+
See [example][] for more complex examples.
|
|
62
|
+
|
|
63
|
+
[example]: https://github.com/cardinalblue/rest-core/tree/master/example
|
|
64
|
+
|
|
65
|
+
## Build Your Own Clients Example:
|
|
66
|
+
|
|
67
|
+
require 'rest-core'
|
|
68
|
+
|
|
69
|
+
YourClient = RestCore::Builder.client do
|
|
46
70
|
use DefaultSite , 'https://api.github.com/users/'
|
|
47
71
|
use JsonDecode , true
|
|
48
72
|
use CommonLogger, method(:puts)
|
|
49
|
-
use Cache , {},
|
|
73
|
+
use Cache , {}, 3600
|
|
50
74
|
run RestClient
|
|
51
75
|
end
|
|
52
76
|
|
|
53
77
|
client = YourClient.new
|
|
54
|
-
client.get('godfat')
|
|
55
|
-
client.get('godfat')
|
|
78
|
+
client.get('godfat') # cache miss
|
|
79
|
+
client.get('godfat') # cache hit
|
|
56
80
|
|
|
57
81
|
client.site = 'http://github.com/api/v2/json/user/show/'
|
|
58
|
-
client.get('godfat')
|
|
59
|
-
client.get('godfat')
|
|
82
|
+
client.get('godfat') # cache miss
|
|
83
|
+
client.get('godfat') # cache hit
|
|
60
84
|
|
|
61
|
-
See [
|
|
62
|
-
more complex examples.
|
|
85
|
+
See [built-in clients][] for more complex examples.
|
|
63
86
|
|
|
64
|
-
[
|
|
65
|
-
[build-in clients]: https://github.com/cardinalblue/rest-core/tree/master/lib/rest-core/client
|
|
87
|
+
[built-in clients]: https://github.com/cardinalblue/rest-core/tree/master/lib/rest-core/client
|
|
66
88
|
|
|
67
89
|
## LICENSE:
|
|
68
90
|
|
data/TODO.md
CHANGED
data/example/facebook.rb
CHANGED
|
@@ -1,145 +1,9 @@
|
|
|
1
1
|
|
|
2
|
-
|
|
2
|
+
require 'rest-core/client/rest-graph'
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
p RestGraph.new.get('4') # get user info
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
use s::DefaultSite , 'https://graph.facebook.com/'
|
|
11
|
-
use s::DefaultHeaders, {'Accept' => 'application/json',
|
|
12
|
-
'Accept-Language' => 'en-us'}
|
|
13
|
-
use s::Oauth2Query , 'access_token', nil
|
|
14
|
-
|
|
15
|
-
use s::CommonLogger , method(:puts)
|
|
16
|
-
use s::Cache , {}, nil
|
|
17
|
-
use s::ErrorHandler , lambda{ |env| raise ::Facebook::Error.call(env) }
|
|
18
|
-
use s::ErrorDetector , lambda{ |env| env[s::RESPONSE_BODY]['error'] ||
|
|
19
|
-
env[s::RESPONSE_BODY]['error_code'] }
|
|
20
|
-
use s::JsonDecode , true
|
|
21
|
-
|
|
22
|
-
use s::Defaults , :data => lambda{{}},
|
|
23
|
-
:old_site => 'https://api.facebook.com/'
|
|
24
|
-
|
|
25
|
-
run s::RestClient
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
class Facebook::Error < RuntimeError
|
|
29
|
-
include RestCore
|
|
30
|
-
|
|
31
|
-
attr_reader :error, :url
|
|
32
|
-
def initialize error, url=''
|
|
33
|
-
@error, @url = error, url
|
|
34
|
-
super("#{error.inspect} from #{url}")
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
def self.call env
|
|
38
|
-
error, url = env[RESPONSE_BODY], Middleware.request_uri(env)
|
|
39
|
-
new(error, url)
|
|
40
|
-
end
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
module Facebook::Client
|
|
44
|
-
include RestCore
|
|
45
|
-
|
|
46
|
-
def oauth_token
|
|
47
|
-
data['access_token'] || data['oauth_token'] if data.kind_of?(Hash)
|
|
48
|
-
end
|
|
49
|
-
def oauth_token= token
|
|
50
|
-
data['access_token'] = token if data.kind_of?(Hash)
|
|
51
|
-
end
|
|
52
|
-
alias_method :access_token , :oauth_token
|
|
53
|
-
alias_method :access_token=, :oauth_token=
|
|
54
|
-
|
|
55
|
-
def secret_oauth_token ; "#{app_id}|#{secret}" ; end
|
|
56
|
-
alias_method :secret_access_token, :secret_oauth_token
|
|
57
|
-
|
|
58
|
-
def accept ; headers['Accept'] ; end
|
|
59
|
-
def accept= val; headers['Accept'] = val; end
|
|
60
|
-
def lang ; headers['Accept-Language'] ; end
|
|
61
|
-
def lang= val; headers['Accept-Language'] = val; end
|
|
62
|
-
|
|
63
|
-
def authorized? ; !!oauth_token ; end
|
|
64
|
-
|
|
65
|
-
# cookies, app_id, secrect related below
|
|
66
|
-
|
|
67
|
-
def parse_fbs! fbs
|
|
68
|
-
self.data = check_sig_and_return_data(
|
|
69
|
-
# take out facebook sometimes there but sometimes not quotes in cookies
|
|
70
|
-
Rack::Utils.parse_query(fbs.to_s.sub(/^"/, '').sub(/"$/, '')))
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
def fbs
|
|
74
|
-
"#{fbs_without_sig(data).join('&')}&sig=#{calculate_sig(data)}"
|
|
75
|
-
end
|
|
76
|
-
|
|
77
|
-
# facebook's new signed_request...
|
|
78
|
-
|
|
79
|
-
def parse_signed_request! request
|
|
80
|
-
sig_encoded, json_encoded = request.split('.')
|
|
81
|
-
sig, json = [sig_encoded, json_encoded].map{ |str|
|
|
82
|
-
"#{str.tr('-_', '+/')}==".unpack('m').first
|
|
83
|
-
}
|
|
84
|
-
self.data = check_sig_and_return_data(
|
|
85
|
-
JsonDecode.json_decode(json).merge('sig' => sig)){
|
|
86
|
-
Hmac.sha256(secret, json_encoded)
|
|
87
|
-
}
|
|
88
|
-
rescue JsonDecode::ParseError
|
|
89
|
-
self.data = nil
|
|
90
|
-
end
|
|
91
|
-
|
|
92
|
-
# oauth related
|
|
93
|
-
|
|
94
|
-
def authorize_url opts={}
|
|
95
|
-
url('oauth/authorize',
|
|
96
|
-
{:client_id => app_id, :access_token => nil}.merge(opts))
|
|
97
|
-
end
|
|
98
|
-
|
|
99
|
-
def authorize! opts={}
|
|
100
|
-
query = {:client_id => app_id, :client_secret => secret}.merge(opts)
|
|
101
|
-
self.data = Rack::Utils.parse_query(
|
|
102
|
-
request({:auto_decode => false}.merge(opts),
|
|
103
|
-
[:get, url('oauth/access_token', query)]))
|
|
104
|
-
end
|
|
105
|
-
|
|
106
|
-
# old rest facebook api, i will definitely love to remove them someday
|
|
107
|
-
|
|
108
|
-
def old_rest path, query={}, opts={}, &cb
|
|
109
|
-
uri = url("method/#{path}", {:format => 'json'}.merge(query),
|
|
110
|
-
{:site => old_site}.merge(opts))
|
|
111
|
-
request(opts, [:get, uri], &cb)
|
|
112
|
-
end
|
|
113
|
-
|
|
114
|
-
def secret_old_rest path, query={}, opts={}, &cb
|
|
115
|
-
old_rest(path, query, {:secret => true}.merge(opts), &cb)
|
|
116
|
-
end
|
|
117
|
-
|
|
118
|
-
def fql code, query={}, opts={}, &cb
|
|
119
|
-
old_rest('fql.query', {:query => code}.merge(query), opts, &cb)
|
|
120
|
-
end
|
|
121
|
-
|
|
122
|
-
def fql_multi codes, query={}, opts={}, &cb
|
|
123
|
-
old_rest('fql.multiquery',
|
|
124
|
-
{:queries => JsonDecode.json_encode(codes)}.merge(query), opts, &cb)
|
|
125
|
-
end
|
|
126
|
-
|
|
127
|
-
protected
|
|
128
|
-
def check_sig_and_return_data cookies
|
|
129
|
-
cookies if secret && if block_given?
|
|
130
|
-
yield
|
|
131
|
-
else
|
|
132
|
-
calculate_sig(cookies)
|
|
133
|
-
end == cookies['sig']
|
|
134
|
-
end
|
|
135
|
-
|
|
136
|
-
def calculate_sig cookies
|
|
137
|
-
Digest::MD5.hexdigest(fbs_without_sig(cookies).join + secret)
|
|
138
|
-
end
|
|
139
|
-
|
|
140
|
-
def fbs_without_sig cookies
|
|
141
|
-
cookies.reject{ |(k, v)| k == 'sig' }.sort.map{ |a| a.join('=') }
|
|
142
|
-
end
|
|
143
|
-
end
|
|
144
|
-
|
|
145
|
-
Facebook.send(:include, Facebook::Client)
|
|
6
|
+
facebook = RestGraph.new(:app_id => '...', :secret => '...')
|
|
7
|
+
facebook.authorize_url # copy and paste the URL in browser to authorize
|
|
8
|
+
facebook.authorize!(:redirect_uri => '...', :code => '...')
|
|
9
|
+
p facebook.get('me')
|
data/example/github.rb
CHANGED
|
@@ -1,21 +1,4 @@
|
|
|
1
1
|
|
|
2
|
-
# simple client
|
|
3
|
-
|
|
4
2
|
require 'rest-core'
|
|
5
3
|
|
|
6
|
-
RestCore::
|
|
7
|
-
s = self.class # this is only for ruby 1.8!
|
|
8
|
-
use s::Timeout , 10
|
|
9
|
-
|
|
10
|
-
use s::DefaultSite , 'https://api.github.com/'
|
|
11
|
-
use s::Oauth2Query , 'access_token', nil
|
|
12
|
-
|
|
13
|
-
use s::CommonLogger , method(:puts)
|
|
14
|
-
use s::Cache , {}, nil
|
|
15
|
-
use s::ErrorHandler , lambda{|env| raise env[s::RESPONSE_BODY]['message']}
|
|
16
|
-
use s::ErrorDetector, lambda{|env| env[s::RESPONSE_HEADERS]['status'].
|
|
17
|
-
first !~ /^2/}
|
|
18
|
-
use s::JsonDecode , true
|
|
19
|
-
|
|
20
|
-
run s::RestClient
|
|
21
|
-
end
|
|
4
|
+
p RestCore::Github.new.get('users/godfat') # get user info
|
data/example/linkedin.rb
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
|
|
2
|
+
require 'rest-core'
|
|
3
|
+
|
|
4
|
+
linkedin = RestCore::Linkedin.new(:consumer_key => '...',
|
|
5
|
+
:consumer_secret => '...')
|
|
6
|
+
linkedin.authorize_url! # copy and paste the URL in browser to authorize
|
|
7
|
+
linkedin.authorize!('..') # paste your code from browser
|
|
8
|
+
p linkedin.me # get current user info
|
data/example/twitter.rb
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
|
|
2
|
+
require 'rest-core'
|
|
3
|
+
RestCore::Twitter.new.statuses('godfat') # get user tweets
|
|
4
|
+
|
|
5
|
+
twitter = RestCore::Twitter.new(:consumer_key => '...',
|
|
6
|
+
:consumer_secret => '...')
|
|
7
|
+
twitter.authorize_url! # copy and paste the URL in browser to authorize
|
|
8
|
+
twitter.authorize!('..') # paste your code from browser
|
|
9
|
+
p twitter.tweet('hi!') # tweet for the current user
|
|
10
|
+
|
|
11
|
+
p twitter.post('statuses/update_with_media.json',
|
|
12
|
+
:status => 'hi!', 'media[]' => File.open('...'))
|
data/lib/rest-core.rb
CHANGED
|
@@ -45,4 +45,9 @@ module RestCore
|
|
|
45
45
|
# apps
|
|
46
46
|
autoload :Ask , 'rest-core/app/ask'
|
|
47
47
|
autoload :RestClient , 'rest-core/app/rest-client'
|
|
48
|
+
|
|
49
|
+
# clients
|
|
50
|
+
autoload :Github , 'rest-core/client/github'
|
|
51
|
+
autoload :Twitter , 'rest-core/client/twitter'
|
|
52
|
+
autoload :Linkedin , 'rest-core/client/linkedin'
|
|
48
53
|
end
|
data/lib/rest-core/builder.rb
CHANGED
|
@@ -6,16 +6,15 @@ class RestCore::Builder
|
|
|
6
6
|
include RestCore
|
|
7
7
|
include Wrapper
|
|
8
8
|
|
|
9
|
-
def self.client
|
|
10
|
-
new(&block).to_client(
|
|
9
|
+
def self.client *attrs, &block
|
|
10
|
+
new(&block).to_client(*attrs)
|
|
11
11
|
end
|
|
12
12
|
|
|
13
|
-
def to_client
|
|
13
|
+
def to_client *attrs
|
|
14
14
|
# struct = Struct.new(*members, *attrs) if RUBY_VERSION >= 1.9.2
|
|
15
15
|
struct = Struct.new(*(members + attrs))
|
|
16
16
|
client = Class.new(struct)
|
|
17
17
|
client.send(:include, Client)
|
|
18
|
-
Object.const_set( prefix , client)
|
|
19
18
|
client.const_set('Struct', struct)
|
|
20
19
|
class << client; attr_reader :builder; end
|
|
21
20
|
client.instance_variable_set(:@builder, self)
|
data/lib/rest-core/client.rb
CHANGED
|
@@ -19,13 +19,15 @@ module RestCore::Client
|
|
|
19
19
|
end
|
|
20
20
|
|
|
21
21
|
def default_#{name} app=app
|
|
22
|
-
if app.respond_to?(:#{name})
|
|
22
|
+
if app.respond_to?(:#{name}) # instance value
|
|
23
23
|
app.#{name}({})
|
|
24
|
-
elsif app.respond_to?(:wrapped)
|
|
25
|
-
default_#{name}(app.wrapped) ||
|
|
24
|
+
elsif app.respond_to?(:wrapped) # wrapper value
|
|
25
|
+
default_#{name}(app.wrapped) || # walk into it
|
|
26
26
|
default_#{name}(app.app)
|
|
27
|
-
elsif app.respond_to?(:app)
|
|
27
|
+
elsif app.respond_to?(:app) # walk into next app
|
|
28
28
|
default_#{name}(app.app)
|
|
29
|
+
elsif self.class.respond_to?("default_#{name}")
|
|
30
|
+
self.class.default_#{name} # old class default style
|
|
29
31
|
else
|
|
30
32
|
nil
|
|
31
33
|
end
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
|
|
2
|
-
|
|
2
|
+
require 'rest-core'
|
|
3
|
+
|
|
4
|
+
RestCore::Github = RestCore::Builder.client do
|
|
3
5
|
s = self.class # this is only for ruby 1.8!
|
|
4
6
|
use s::Timeout , 10
|
|
5
7
|
|
|
@@ -8,7 +10,7 @@ RestCore::Builder.client('Github') do
|
|
|
8
10
|
use s::Oauth2Query , 'access_token', nil
|
|
9
11
|
|
|
10
12
|
use s::CommonLogger , lambda{|obj|obj}
|
|
11
|
-
use s::Cache , {},
|
|
13
|
+
use s::Cache , {}, 3600 do
|
|
12
14
|
use s::ErrorHandler , lambda{|env| raise env[s::RESPONSE_BODY]['message']}
|
|
13
15
|
use s::ErrorDetectorHttp
|
|
14
16
|
use s::JsonDecode , true
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
|
|
2
|
-
RestCore::Builder.client(
|
|
2
|
+
RestCore::Linkedin = RestCore::Builder.client(:data) do
|
|
3
3
|
s = self.class # this is only for ruby 1.8!
|
|
4
4
|
use s::Timeout , 10
|
|
5
5
|
|
|
@@ -13,7 +13,7 @@ RestCore::Builder.client('Linkedin', :data) do
|
|
|
13
13
|
|
|
14
14
|
use s::CommonLogger , method(:puts)
|
|
15
15
|
|
|
16
|
-
use s::Cache , {},
|
|
16
|
+
use s::Cache , {}, 3600 do
|
|
17
17
|
use s::ErrorHandler , lambda{|env|
|
|
18
18
|
if (body = env[s::RESPONSE_BODY]).kind_of?(Hash)
|
|
19
19
|
raise body['message']
|
|
@@ -31,27 +31,31 @@ RestCore::Builder.client('Linkedin', :data) do
|
|
|
31
31
|
run s::RestClient
|
|
32
32
|
end
|
|
33
33
|
|
|
34
|
-
module Linkedin::Client
|
|
34
|
+
module RestCore::Linkedin::Client
|
|
35
35
|
include RestCore
|
|
36
36
|
|
|
37
37
|
def oauth_token
|
|
38
38
|
data['oauth_token'] if data.kind_of?(Hash)
|
|
39
39
|
end
|
|
40
|
-
def oauth_token=
|
|
40
|
+
def oauth_token= token
|
|
41
41
|
data['oauth_token'] = token if data.kind_of?(Hash)
|
|
42
42
|
end
|
|
43
43
|
def oauth_token_secret
|
|
44
44
|
data['oauth_token_secret'] if data.kind_of?(Hash)
|
|
45
45
|
end
|
|
46
|
-
def oauth_token_secret=
|
|
46
|
+
def oauth_token_secret= secret
|
|
47
47
|
data['oauth_token_secret'] = secret if data.kind_of?(Hash)
|
|
48
48
|
end
|
|
49
49
|
|
|
50
|
+
def me queries={}, opts={}
|
|
51
|
+
get('v1/people/~', queries, opts)
|
|
52
|
+
end
|
|
53
|
+
|
|
50
54
|
private
|
|
51
55
|
def set_token query
|
|
52
56
|
self.data = query
|
|
53
57
|
end
|
|
54
58
|
end
|
|
55
59
|
|
|
56
|
-
Linkedin.send(:include, RestCore::ClientOauth1)
|
|
57
|
-
Linkedin.send(:include, Linkedin::Client)
|
|
60
|
+
RestCore::Linkedin.send(:include, RestCore::ClientOauth1)
|
|
61
|
+
RestCore::Linkedin.send(:include, RestCore::Linkedin::Client)
|
|
@@ -5,7 +5,7 @@ require 'rest-core/util/hmac'
|
|
|
5
5
|
# optional gem
|
|
6
6
|
begin; require 'rack'; rescue LoadError; end
|
|
7
7
|
|
|
8
|
-
RestCore::Builder.client(
|
|
8
|
+
RestGraph = RestCore::Builder.client(:data, :app_id, :secret, :old_site) do
|
|
9
9
|
s = self.class # this is only for ruby 1.8!
|
|
10
10
|
use s::Timeout , 10
|
|
11
11
|
|
|
@@ -16,7 +16,7 @@ RestCore::Builder.client('RestGraph', :data, :app_id, :secret, :old_site) do
|
|
|
16
16
|
|
|
17
17
|
use s::CommonLogger , lambda{|obj|obj}
|
|
18
18
|
|
|
19
|
-
use s::Cache , {},
|
|
19
|
+
use s::Cache , {}, 3600 do
|
|
20
20
|
use s::ErrorHandler , lambda{ |env| raise ::RestGraph::Error.call(env) }
|
|
21
21
|
use s::ErrorDetector , lambda{ |env|
|
|
22
22
|
if env[s::RESPONSE_BODY].kind_of?(Hash)
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
|
|
2
|
-
|
|
2
|
+
require 'rest-core'
|
|
3
|
+
|
|
4
|
+
RestCore::Twitter = RestCore::Builder.client(:data) do
|
|
3
5
|
s = self.class # this is only for ruby 1.8!
|
|
4
6
|
use s::Timeout , 10
|
|
5
7
|
|
|
6
|
-
use s::DefaultSite , 'https://api.twitter.com/'
|
|
8
|
+
use s::DefaultSite , 'https://api.twitter.com/1/'
|
|
7
9
|
use s::DefaultHeaders, {'Accept' => 'application/json'}
|
|
8
10
|
|
|
9
11
|
use s::Oauth1Header ,
|
|
@@ -11,7 +13,7 @@ RestCore::Builder.client('Twitter', :data) do
|
|
|
11
13
|
|
|
12
14
|
use s::CommonLogger , method(:puts)
|
|
13
15
|
|
|
14
|
-
use s::Cache , {},
|
|
16
|
+
use s::Cache , {}, 3600 do
|
|
15
17
|
use s::ErrorHandler , lambda{ |env|
|
|
16
18
|
if (body = env[s::RESPONSE_BODY]).kind_of?(Hash)
|
|
17
19
|
raise body['error']
|
|
@@ -29,24 +31,29 @@ RestCore::Builder.client('Twitter', :data) do
|
|
|
29
31
|
run s::RestClient
|
|
30
32
|
end
|
|
31
33
|
|
|
32
|
-
module Twitter::Client
|
|
34
|
+
module RestCore::Twitter::Client
|
|
33
35
|
include RestCore
|
|
34
36
|
|
|
35
37
|
def oauth_token
|
|
36
38
|
data['oauth_token'] if data.kind_of?(Hash)
|
|
37
39
|
end
|
|
38
|
-
def oauth_token=
|
|
40
|
+
def oauth_token= token
|
|
39
41
|
data['oauth_token'] = token if data.kind_of?(Hash)
|
|
40
42
|
end
|
|
41
43
|
def oauth_token_secret
|
|
42
44
|
data['oauth_token_secret'] if data.kind_of?(Hash)
|
|
43
45
|
end
|
|
44
|
-
def oauth_token_secret=
|
|
46
|
+
def oauth_token_secret= secret
|
|
45
47
|
data['oauth_token_secret'] = secret if data.kind_of?(Hash)
|
|
46
48
|
end
|
|
47
49
|
|
|
48
|
-
def tweet status,
|
|
49
|
-
post('
|
|
50
|
+
def tweet status, queries={}, opts={}
|
|
51
|
+
post('statuses/update.json',
|
|
52
|
+
{:status => status}.merge(queries), opts)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def statuses user, queries={}, opts={}
|
|
56
|
+
get('statuses/user_timeline.json', {:id => user}.merge(queries), opts)
|
|
50
57
|
end
|
|
51
58
|
|
|
52
59
|
private
|
|
@@ -55,5 +62,5 @@ module Twitter::Client
|
|
|
55
62
|
end
|
|
56
63
|
end
|
|
57
64
|
|
|
58
|
-
Twitter.send(:include, RestCore::ClientOauth1)
|
|
59
|
-
Twitter.send(:include,
|
|
65
|
+
RestCore::Twitter.send(:include, RestCore::ClientOauth1)
|
|
66
|
+
RestCore::Twitter.send(:include, RestCore::Twitter::Client)
|
|
@@ -55,8 +55,16 @@ class RestCore::Oauth1Header
|
|
|
55
55
|
def base_string env, oauth_params
|
|
56
56
|
method = env[REQUEST_METHOD].to_s.upcase
|
|
57
57
|
base_uri = env[REQUEST_PATH]
|
|
58
|
+
# TODO: the detection should be checking if it's
|
|
59
|
+
# application/x-www-form-urlencoded or not, instead of multipart or not.
|
|
60
|
+
# but since the Content-Type is generated in app (http client),
|
|
61
|
+
# we have no idea what it would be here. so simply guessing it...
|
|
62
|
+
payload = if multipart?(env)
|
|
63
|
+
{}
|
|
64
|
+
else
|
|
65
|
+
reject_blank(env[REQUEST_PAYLOAD] || {})
|
|
66
|
+
end
|
|
58
67
|
query = reject_blank(env[REQUEST_QUERY] || {})
|
|
59
|
-
payload = reject_blank(env[REQUEST_PAYLOAD] || {})
|
|
60
68
|
params = reject_blank(oauth_params.merge(query.merge(payload))).
|
|
61
69
|
to_a.sort.map{ |(k, v)|
|
|
62
70
|
"#{encode(k.to_s)}=#{encode(v.to_s)}"}.join('&')
|
|
@@ -68,6 +76,11 @@ class RestCore::Oauth1Header
|
|
|
68
76
|
[OpenSSL::Random.random_bytes(32)].pack('m').tr("+/=\n", '')
|
|
69
77
|
end
|
|
70
78
|
|
|
79
|
+
def multipart? env
|
|
80
|
+
!!(env[REQUEST_PAYLOAD] &&
|
|
81
|
+
env[REQUEST_PAYLOAD].find{ |k, v| v.kind_of?(IO) })
|
|
82
|
+
end
|
|
83
|
+
|
|
71
84
|
def reject_blank params
|
|
72
85
|
params.reject{ |k, v| v.nil? || v == false ||
|
|
73
86
|
(v.respond_to?(:strip) &&
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
|
|
2
|
+
require 'erb'
|
|
3
|
+
require 'yaml'
|
|
4
|
+
|
|
5
|
+
require 'rest-core'
|
|
6
|
+
|
|
7
|
+
module RestCore::Config
|
|
8
|
+
extend self
|
|
9
|
+
|
|
10
|
+
DefaultModuleName = 'DefaultAttributes'
|
|
11
|
+
|
|
12
|
+
def load_for_rails klass, app=Rails
|
|
13
|
+
root = File.expand_path(app.root)
|
|
14
|
+
path = ["#{root}/config/rest-core.yaml", # YAML should use .yaml
|
|
15
|
+
"#{root}/config/rest-core.yml" ].find{|p| File.exist?(p)}
|
|
16
|
+
RestCore::Config.load(klass, path, app.env)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def load klass, path, env
|
|
20
|
+
return false if klass.const_defined?(DefaultModuleName)
|
|
21
|
+
RestCore::Config.load!(klass, path, env)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def load! klass, path, env
|
|
25
|
+
config = YAML.load(ERB.new(File.read(path)).result(binding))
|
|
26
|
+
defaults = config[env]
|
|
27
|
+
return false unless defaults
|
|
28
|
+
raise ArgumentError.new("#{defaults} is not a hash") unless
|
|
29
|
+
defaults.kind_of?(Hash)
|
|
30
|
+
|
|
31
|
+
mod = if klass.const_defined?(DefaultModuleName)
|
|
32
|
+
klass.const_get(DefaultModuleName)
|
|
33
|
+
else
|
|
34
|
+
m = Module.new
|
|
35
|
+
klass.send(:extend, m)
|
|
36
|
+
klass.send(:const_set, DefaultModuleName, m)
|
|
37
|
+
m
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
mod.module_eval(defaults.inject([]){ |r, (k, v)|
|
|
41
|
+
# quote strings, leave others free (e.g. false, numbers, etc)
|
|
42
|
+
r << <<-RUBY
|
|
43
|
+
def default_#{k}
|
|
44
|
+
#{v.kind_of?(String) ? "'#{v}'" : v}
|
|
45
|
+
end
|
|
46
|
+
RUBY
|
|
47
|
+
}.join, __FILE__, __LINE__)
|
|
48
|
+
end
|
|
49
|
+
end
|
data/lib/rest-core/version.rb
CHANGED
|
File without changes
|
|
File without changes
|
data/rest-core.gemspec
CHANGED
|
@@ -2,13 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
Gem::Specification.new do |s|
|
|
4
4
|
s.name = %q{rest-core}
|
|
5
|
-
s.version = "0.0
|
|
5
|
+
s.version = "0.2.0"
|
|
6
6
|
|
|
7
7
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
|
8
8
|
s.authors = [
|
|
9
9
|
%q{Cardinal Blue},
|
|
10
10
|
%q{Lin Jen-Shin (godfat)}]
|
|
11
|
-
s.date = %q{2011-08-
|
|
11
|
+
s.date = %q{2011-08-24}
|
|
12
12
|
s.description = %q{A modular Ruby REST client collection/infrastructure.
|
|
13
13
|
|
|
14
14
|
In this era of web services and mashups, we have seen a blooming of REST
|
|
@@ -25,11 +25,6 @@ for any other REST APIs.
|
|
|
25
25
|
[rest-core]: http://github.com/cardinalblue/rest-core
|
|
26
26
|
[rest-graph]: http://github.com/cardinalblue/rest-graph}
|
|
27
27
|
s.email = [%q{dev (XD) cardinalblue.com}]
|
|
28
|
-
s.extra_rdoc_files = [
|
|
29
|
-
%q{CONTRIBUTORS},
|
|
30
|
-
%q{LICENSE},
|
|
31
|
-
%q{TODO.md},
|
|
32
|
-
%q{CONTRIBUTORS}]
|
|
33
28
|
s.files = [
|
|
34
29
|
%q{.gitignore},
|
|
35
30
|
%q{.gitmodules},
|
|
@@ -38,12 +33,13 @@ for any other REST APIs.
|
|
|
38
33
|
%q{Gemfile},
|
|
39
34
|
%q{LICENSE},
|
|
40
35
|
%q{NOTE.md},
|
|
41
|
-
%q{README},
|
|
42
36
|
%q{README.md},
|
|
43
37
|
%q{Rakefile},
|
|
44
38
|
%q{TODO.md},
|
|
45
39
|
%q{example/facebook.rb},
|
|
46
40
|
%q{example/github.rb},
|
|
41
|
+
%q{example/linkedin.rb},
|
|
42
|
+
%q{example/twitter.rb},
|
|
47
43
|
%q{lib/rest-core.rb},
|
|
48
44
|
%q{lib/rest-core/app/ask.rb},
|
|
49
45
|
%q{lib/rest-core/app/rest-client.rb},
|
|
@@ -69,55 +65,48 @@ for any other REST APIs.
|
|
|
69
65
|
%q{lib/rest-core/middleware/oauth1_header.rb},
|
|
70
66
|
%q{lib/rest-core/middleware/oauth2_query.rb},
|
|
71
67
|
%q{lib/rest-core/middleware/timeout.rb},
|
|
68
|
+
%q{lib/rest-core/util/config.rb},
|
|
72
69
|
%q{lib/rest-core/util/hmac.rb},
|
|
73
70
|
%q{lib/rest-core/version.rb},
|
|
74
71
|
%q{lib/rest-core/wrapper.rb},
|
|
75
|
-
%q{
|
|
72
|
+
%q{pending/test_multi.rb},
|
|
73
|
+
%q{pending/test_test_util.rb},
|
|
76
74
|
%q{rest-core.gemspec},
|
|
77
75
|
%q{task/.gitignore},
|
|
78
76
|
%q{task/gemgem.rb},
|
|
79
77
|
%q{test/common.rb},
|
|
80
|
-
%q{test/config/rest-
|
|
81
|
-
%q{test/pending/test_load_config.rb},
|
|
82
|
-
%q{test/pending/test_multi.rb},
|
|
83
|
-
%q{test/pending/test_test_util.rb},
|
|
78
|
+
%q{test/config/rest-core.yaml},
|
|
84
79
|
%q{test/test_api.rb},
|
|
85
80
|
%q{test/test_cache.rb},
|
|
86
81
|
%q{test/test_default.rb},
|
|
87
82
|
%q{test/test_error.rb},
|
|
88
83
|
%q{test/test_handler.rb},
|
|
84
|
+
%q{test/test_load_config.rb},
|
|
89
85
|
%q{test/test_misc.rb},
|
|
90
86
|
%q{test/test_oauth.rb},
|
|
91
87
|
%q{test/test_oauth1_header.rb},
|
|
92
88
|
%q{test/test_old.rb},
|
|
93
89
|
%q{test/test_page.rb},
|
|
94
90
|
%q{test/test_parse.rb},
|
|
95
|
-
%q{test/test_rest-graph.rb},
|
|
96
91
|
%q{test/test_serialize.rb},
|
|
97
92
|
%q{test/test_timeout.rb}]
|
|
98
93
|
s.homepage = %q{https://github.com/cardinalblue/rest-core}
|
|
99
|
-
s.rdoc_options = [
|
|
100
|
-
%q{--main},
|
|
101
|
-
%q{README}]
|
|
102
94
|
s.require_paths = [%q{lib}]
|
|
103
95
|
s.rubygems_version = %q{1.8.7}
|
|
104
96
|
s.summary = %q{A modular Ruby REST client collection/infrastructure.}
|
|
105
97
|
s.test_files = [
|
|
106
|
-
%q{test/pending/test_load_config.rb},
|
|
107
|
-
%q{test/pending/test_multi.rb},
|
|
108
|
-
%q{test/pending/test_test_util.rb},
|
|
109
98
|
%q{test/test_api.rb},
|
|
110
99
|
%q{test/test_cache.rb},
|
|
111
100
|
%q{test/test_default.rb},
|
|
112
101
|
%q{test/test_error.rb},
|
|
113
102
|
%q{test/test_handler.rb},
|
|
103
|
+
%q{test/test_load_config.rb},
|
|
114
104
|
%q{test/test_misc.rb},
|
|
115
105
|
%q{test/test_oauth.rb},
|
|
116
106
|
%q{test/test_oauth1_header.rb},
|
|
117
107
|
%q{test/test_old.rb},
|
|
118
108
|
%q{test/test_page.rb},
|
|
119
109
|
%q{test/test_parse.rb},
|
|
120
|
-
%q{test/test_rest-graph.rb},
|
|
121
110
|
%q{test/test_serialize.rb},
|
|
122
111
|
%q{test/test_timeout.rb}]
|
|
123
112
|
|
data/task/gemgem.rb
CHANGED
|
@@ -12,17 +12,13 @@ module Gemgem
|
|
|
12
12
|
s.authors = ['Lin Jen-Shin (godfat)']
|
|
13
13
|
s.email = ['godfat (XD) godfat.org']
|
|
14
14
|
|
|
15
|
-
description =
|
|
15
|
+
description = readme.
|
|
16
16
|
match(/DESCRIPTION:\n\n(.+?)(?=\n\n[^\n]+:\n)/m)[1].
|
|
17
17
|
lines.to_a
|
|
18
18
|
|
|
19
19
|
s.description = description.join
|
|
20
20
|
s.summary = description.first
|
|
21
21
|
|
|
22
|
-
s.extra_rdoc_files = %w[CHANGES TODO CONTRIBUTORS LICENSE
|
|
23
|
-
CHANGES.md TODO.md CONTRIBUTORS].select{ |f|
|
|
24
|
-
File.exist?(f) }
|
|
25
|
-
s.rdoc_options = %w[--main README]
|
|
26
22
|
s.rubygems_version = Gem::VERSION
|
|
27
23
|
s.date = Time.now.strftime('%Y-%m-%d')
|
|
28
24
|
s.files = gem_files
|
|
@@ -34,6 +30,17 @@ module Gemgem
|
|
|
34
30
|
spec
|
|
35
31
|
end
|
|
36
32
|
|
|
33
|
+
def readme
|
|
34
|
+
path = %w[README.md README].find{ |name|
|
|
35
|
+
File.exist?("#{Gemgem.dir}/#{name}")
|
|
36
|
+
}
|
|
37
|
+
if path
|
|
38
|
+
File.read(path)
|
|
39
|
+
else
|
|
40
|
+
"DESCRIPTION:\n\n \n\nEND:\n"
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
37
44
|
def gem_tag
|
|
38
45
|
"#{spec.name}-#{spec.version}"
|
|
39
46
|
end
|
|
@@ -153,7 +160,7 @@ task :test do
|
|
|
153
160
|
Bacon.extend(Bacon::TestUnitOutput)
|
|
154
161
|
Bacon.summary_on_exit
|
|
155
162
|
$LOAD_PATH.unshift('lib')
|
|
156
|
-
Dir['test/**/test_*.rb'].each{ |file|
|
|
163
|
+
Dir['./test/**/test_*.rb'].each{ |file| require file[0..-4] }
|
|
157
164
|
end
|
|
158
165
|
|
|
159
166
|
desc 'Run tests with shell'
|
|
File without changes
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
|
|
2
|
+
if respond_to?(:require_relative, true)
|
|
3
|
+
require_relative 'common'
|
|
4
|
+
else
|
|
5
|
+
require File.dirname(__FILE__) + '/common'
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
require 'rest-core/util/config'
|
|
9
|
+
::Rails = Object.new
|
|
10
|
+
|
|
11
|
+
describe RestCore::Config do
|
|
12
|
+
|
|
13
|
+
before do
|
|
14
|
+
@klass = RestGraph.dup
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
after do
|
|
18
|
+
RR.verify
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def check
|
|
22
|
+
@klass.default_app_id .should == 41829
|
|
23
|
+
@klass.default_secret .should == 'r41829'.reverse
|
|
24
|
+
@klass.default_auto_decode.should == false
|
|
25
|
+
@klass.default_lang .should == 'zh-tw'
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
should 'honor rails config' do
|
|
29
|
+
mock(Rails).env { 'test' }
|
|
30
|
+
mock(Rails).root{ File.dirname(__FILE__) }
|
|
31
|
+
RestCore::Config.load_for_rails(@klass)
|
|
32
|
+
check
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
should 'honor config' do
|
|
36
|
+
RestCore::Config.load(
|
|
37
|
+
@klass,
|
|
38
|
+
"#{File.dirname(__FILE__)}/config/rest-core.yaml",
|
|
39
|
+
'test')
|
|
40
|
+
check
|
|
41
|
+
end
|
|
42
|
+
end
|
data/test/test_oauth1_header.rb
CHANGED
|
@@ -39,6 +39,19 @@ describe RestCore::Oauth1Header do
|
|
|
39
39
|
'oauth_version%3D1.0')
|
|
40
40
|
end
|
|
41
41
|
|
|
42
|
+
should 'not use payload in multipart request for base_string' do
|
|
43
|
+
@env = @env.merge(RestCore::REQUEST_PAYLOAD =>
|
|
44
|
+
{'file' => File.open(__FILE__)})
|
|
45
|
+
@auth.base_string(@env, @oauth_params).should.equal(
|
|
46
|
+
'POST&https%3A%2F%2Fapi.twitter.com%2Foauth%2Frequest_token&' \
|
|
47
|
+
'oauth_callback%3Dhttp%253A%252F%252Flocalhost%253A3005%252F' \
|
|
48
|
+
'the_dance%252Fprocess_callback%253Fservice_provider_id%253D' \
|
|
49
|
+
'11%26oauth_consumer_key%3DGDdmIQH6jhtmLUypg82g%26oauth_nonc' \
|
|
50
|
+
'e%3DQP70eNmVz8jvdPevU3oJD2AfF7R7odC2XJcn4XlZJqk%26oauth_sig' \
|
|
51
|
+
'nature_method%3DHMAC-SHA1%26oauth_timestamp%3D1272323042%26' \
|
|
52
|
+
'oauth_version%3D1.0')
|
|
53
|
+
end
|
|
54
|
+
|
|
42
55
|
should 'have correct signature' do
|
|
43
56
|
@auth.signature(@env, @oauth_params).should.equal(
|
|
44
57
|
'8wUi7m5HFQy76nowoCThusfgB+Q=')
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: rest-core
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.0
|
|
4
|
+
version: 0.2.0
|
|
5
5
|
prerelease:
|
|
6
6
|
platform: ruby
|
|
7
7
|
authors:
|
|
@@ -10,11 +10,11 @@ authors:
|
|
|
10
10
|
autorequire:
|
|
11
11
|
bindir: bin
|
|
12
12
|
cert_chain: []
|
|
13
|
-
date: 2011-08-
|
|
13
|
+
date: 2011-08-24 00:00:00.000000000Z
|
|
14
14
|
dependencies:
|
|
15
15
|
- !ruby/object:Gem::Dependency
|
|
16
16
|
name: rest-client
|
|
17
|
-
requirement: &
|
|
17
|
+
requirement: &2168876060 !ruby/object:Gem::Requirement
|
|
18
18
|
none: false
|
|
19
19
|
requirements:
|
|
20
20
|
- - ! '>='
|
|
@@ -22,10 +22,10 @@ dependencies:
|
|
|
22
22
|
version: '0'
|
|
23
23
|
type: :development
|
|
24
24
|
prerelease: false
|
|
25
|
-
version_requirements: *
|
|
25
|
+
version_requirements: *2168876060
|
|
26
26
|
- !ruby/object:Gem::Dependency
|
|
27
27
|
name: rack
|
|
28
|
-
requirement: &
|
|
28
|
+
requirement: &2168875580 !ruby/object:Gem::Requirement
|
|
29
29
|
none: false
|
|
30
30
|
requirements:
|
|
31
31
|
- - ! '>='
|
|
@@ -33,10 +33,10 @@ dependencies:
|
|
|
33
33
|
version: '0'
|
|
34
34
|
type: :development
|
|
35
35
|
prerelease: false
|
|
36
|
-
version_requirements: *
|
|
36
|
+
version_requirements: *2168875580
|
|
37
37
|
- !ruby/object:Gem::Dependency
|
|
38
38
|
name: yajl-ruby
|
|
39
|
-
requirement: &
|
|
39
|
+
requirement: &2168875100 !ruby/object:Gem::Requirement
|
|
40
40
|
none: false
|
|
41
41
|
requirements:
|
|
42
42
|
- - ! '>='
|
|
@@ -44,10 +44,10 @@ dependencies:
|
|
|
44
44
|
version: '0'
|
|
45
45
|
type: :development
|
|
46
46
|
prerelease: false
|
|
47
|
-
version_requirements: *
|
|
47
|
+
version_requirements: *2168875100
|
|
48
48
|
- !ruby/object:Gem::Dependency
|
|
49
49
|
name: json
|
|
50
|
-
requirement: &
|
|
50
|
+
requirement: &2168874620 !ruby/object:Gem::Requirement
|
|
51
51
|
none: false
|
|
52
52
|
requirements:
|
|
53
53
|
- - ! '>='
|
|
@@ -55,10 +55,10 @@ dependencies:
|
|
|
55
55
|
version: '0'
|
|
56
56
|
type: :development
|
|
57
57
|
prerelease: false
|
|
58
|
-
version_requirements: *
|
|
58
|
+
version_requirements: *2168874620
|
|
59
59
|
- !ruby/object:Gem::Dependency
|
|
60
60
|
name: json_pure
|
|
61
|
-
requirement: &
|
|
61
|
+
requirement: &2168874140 !ruby/object:Gem::Requirement
|
|
62
62
|
none: false
|
|
63
63
|
requirements:
|
|
64
64
|
- - ! '>='
|
|
@@ -66,10 +66,10 @@ dependencies:
|
|
|
66
66
|
version: '0'
|
|
67
67
|
type: :development
|
|
68
68
|
prerelease: false
|
|
69
|
-
version_requirements: *
|
|
69
|
+
version_requirements: *2168874140
|
|
70
70
|
- !ruby/object:Gem::Dependency
|
|
71
71
|
name: ruby-hmac
|
|
72
|
-
requirement: &
|
|
72
|
+
requirement: &2168873660 !ruby/object:Gem::Requirement
|
|
73
73
|
none: false
|
|
74
74
|
requirements:
|
|
75
75
|
- - ! '>='
|
|
@@ -77,10 +77,10 @@ dependencies:
|
|
|
77
77
|
version: '0'
|
|
78
78
|
type: :development
|
|
79
79
|
prerelease: false
|
|
80
|
-
version_requirements: *
|
|
80
|
+
version_requirements: *2168873660
|
|
81
81
|
- !ruby/object:Gem::Dependency
|
|
82
82
|
name: webmock
|
|
83
|
-
requirement: &
|
|
83
|
+
requirement: &2168873180 !ruby/object:Gem::Requirement
|
|
84
84
|
none: false
|
|
85
85
|
requirements:
|
|
86
86
|
- - ! '>='
|
|
@@ -88,10 +88,10 @@ dependencies:
|
|
|
88
88
|
version: '0'
|
|
89
89
|
type: :development
|
|
90
90
|
prerelease: false
|
|
91
|
-
version_requirements: *
|
|
91
|
+
version_requirements: *2168873180
|
|
92
92
|
- !ruby/object:Gem::Dependency
|
|
93
93
|
name: bacon
|
|
94
|
-
requirement: &
|
|
94
|
+
requirement: &2168906220 !ruby/object:Gem::Requirement
|
|
95
95
|
none: false
|
|
96
96
|
requirements:
|
|
97
97
|
- - ! '>='
|
|
@@ -99,10 +99,10 @@ dependencies:
|
|
|
99
99
|
version: '0'
|
|
100
100
|
type: :development
|
|
101
101
|
prerelease: false
|
|
102
|
-
version_requirements: *
|
|
102
|
+
version_requirements: *2168906220
|
|
103
103
|
- !ruby/object:Gem::Dependency
|
|
104
104
|
name: rr
|
|
105
|
-
requirement: &
|
|
105
|
+
requirement: &2168905740 !ruby/object:Gem::Requirement
|
|
106
106
|
none: false
|
|
107
107
|
requirements:
|
|
108
108
|
- - ! '>='
|
|
@@ -110,10 +110,10 @@ dependencies:
|
|
|
110
110
|
version: '0'
|
|
111
111
|
type: :development
|
|
112
112
|
prerelease: false
|
|
113
|
-
version_requirements: *
|
|
113
|
+
version_requirements: *2168905740
|
|
114
114
|
- !ruby/object:Gem::Dependency
|
|
115
115
|
name: rake
|
|
116
|
-
requirement: &
|
|
116
|
+
requirement: &2168905260 !ruby/object:Gem::Requirement
|
|
117
117
|
none: false
|
|
118
118
|
requirements:
|
|
119
119
|
- - ! '>='
|
|
@@ -121,7 +121,7 @@ dependencies:
|
|
|
121
121
|
version: '0'
|
|
122
122
|
type: :development
|
|
123
123
|
prerelease: false
|
|
124
|
-
version_requirements: *
|
|
124
|
+
version_requirements: *2168905260
|
|
125
125
|
description: ! 'A modular Ruby REST client collection/infrastructure.
|
|
126
126
|
|
|
127
127
|
|
|
@@ -152,10 +152,7 @@ email:
|
|
|
152
152
|
- dev (XD) cardinalblue.com
|
|
153
153
|
executables: []
|
|
154
154
|
extensions: []
|
|
155
|
-
extra_rdoc_files:
|
|
156
|
-
- CONTRIBUTORS
|
|
157
|
-
- LICENSE
|
|
158
|
-
- TODO.md
|
|
155
|
+
extra_rdoc_files: []
|
|
159
156
|
files:
|
|
160
157
|
- .gitignore
|
|
161
158
|
- .gitmodules
|
|
@@ -164,12 +161,13 @@ files:
|
|
|
164
161
|
- Gemfile
|
|
165
162
|
- LICENSE
|
|
166
163
|
- NOTE.md
|
|
167
|
-
- README
|
|
168
164
|
- README.md
|
|
169
165
|
- Rakefile
|
|
170
166
|
- TODO.md
|
|
171
167
|
- example/facebook.rb
|
|
172
168
|
- example/github.rb
|
|
169
|
+
- example/linkedin.rb
|
|
170
|
+
- example/twitter.rb
|
|
173
171
|
- lib/rest-core.rb
|
|
174
172
|
- lib/rest-core/app/ask.rb
|
|
175
173
|
- lib/rest-core/app/rest-client.rb
|
|
@@ -195,38 +193,35 @@ files:
|
|
|
195
193
|
- lib/rest-core/middleware/oauth1_header.rb
|
|
196
194
|
- lib/rest-core/middleware/oauth2_query.rb
|
|
197
195
|
- lib/rest-core/middleware/timeout.rb
|
|
196
|
+
- lib/rest-core/util/config.rb
|
|
198
197
|
- lib/rest-core/util/hmac.rb
|
|
199
198
|
- lib/rest-core/version.rb
|
|
200
199
|
- lib/rest-core/wrapper.rb
|
|
201
|
-
-
|
|
200
|
+
- pending/test_multi.rb
|
|
201
|
+
- pending/test_test_util.rb
|
|
202
202
|
- rest-core.gemspec
|
|
203
203
|
- task/.gitignore
|
|
204
204
|
- task/gemgem.rb
|
|
205
205
|
- test/common.rb
|
|
206
|
-
- test/config/rest-
|
|
207
|
-
- test/pending/test_load_config.rb
|
|
208
|
-
- test/pending/test_multi.rb
|
|
209
|
-
- test/pending/test_test_util.rb
|
|
206
|
+
- test/config/rest-core.yaml
|
|
210
207
|
- test/test_api.rb
|
|
211
208
|
- test/test_cache.rb
|
|
212
209
|
- test/test_default.rb
|
|
213
210
|
- test/test_error.rb
|
|
214
211
|
- test/test_handler.rb
|
|
212
|
+
- test/test_load_config.rb
|
|
215
213
|
- test/test_misc.rb
|
|
216
214
|
- test/test_oauth.rb
|
|
217
215
|
- test/test_oauth1_header.rb
|
|
218
216
|
- test/test_old.rb
|
|
219
217
|
- test/test_page.rb
|
|
220
218
|
- test/test_parse.rb
|
|
221
|
-
- test/test_rest-graph.rb
|
|
222
219
|
- test/test_serialize.rb
|
|
223
220
|
- test/test_timeout.rb
|
|
224
221
|
homepage: https://github.com/cardinalblue/rest-core
|
|
225
222
|
licenses: []
|
|
226
223
|
post_install_message:
|
|
227
|
-
rdoc_options:
|
|
228
|
-
- --main
|
|
229
|
-
- README
|
|
224
|
+
rdoc_options: []
|
|
230
225
|
require_paths:
|
|
231
226
|
- lib
|
|
232
227
|
required_ruby_version: !ruby/object:Gem::Requirement
|
|
@@ -248,20 +243,17 @@ signing_key:
|
|
|
248
243
|
specification_version: 3
|
|
249
244
|
summary: A modular Ruby REST client collection/infrastructure.
|
|
250
245
|
test_files:
|
|
251
|
-
- test/pending/test_load_config.rb
|
|
252
|
-
- test/pending/test_multi.rb
|
|
253
|
-
- test/pending/test_test_util.rb
|
|
254
246
|
- test/test_api.rb
|
|
255
247
|
- test/test_cache.rb
|
|
256
248
|
- test/test_default.rb
|
|
257
249
|
- test/test_error.rb
|
|
258
250
|
- test/test_handler.rb
|
|
251
|
+
- test/test_load_config.rb
|
|
259
252
|
- test/test_misc.rb
|
|
260
253
|
- test/test_oauth.rb
|
|
261
254
|
- test/test_oauth1_header.rb
|
|
262
255
|
- test/test_old.rb
|
|
263
256
|
- test/test_page.rb
|
|
264
257
|
- test/test_parse.rb
|
|
265
|
-
- test/test_rest-graph.rb
|
|
266
258
|
- test/test_serialize.rb
|
|
267
259
|
- test/test_timeout.rb
|
data/README
DELETED
|
@@ -1,83 +0,0 @@
|
|
|
1
|
-
# rest-core [](http://travis-ci.org/godfat/rest-core)
|
|
2
|
-
by Cardinal Blue <http://cardinalblue.com>
|
|
3
|
-
|
|
4
|
-
## LINKS:
|
|
5
|
-
|
|
6
|
-
* [github](https://github.com/cardinalblue/rest-core)
|
|
7
|
-
* [rubygems](http://rubygems.org/gems/rest-core)
|
|
8
|
-
* [rdoc](http://rdoc.info/projects/cardinalblue/rest-core)
|
|
9
|
-
* [mailing list](http://groups.google.com/group/rest-core/topics)
|
|
10
|
-
|
|
11
|
-
## DESCRIPTION:
|
|
12
|
-
|
|
13
|
-
A modular Ruby REST client collection/infrastructure.
|
|
14
|
-
|
|
15
|
-
In this era of web services and mashups, we have seen a blooming of REST
|
|
16
|
-
APIs. One might wonder, how do we use these APIs easily and elegantly?
|
|
17
|
-
Since REST is very simple compared to SOAP, it is not hard to build a
|
|
18
|
-
dedicated client ourselves.
|
|
19
|
-
|
|
20
|
-
We have developed [rest-core][] with composable middlewares to build a
|
|
21
|
-
REST client, based on the effort from [rest-graph][]. In the cases of
|
|
22
|
-
common APIs such as Facebook, Github, and Twitter, developers can simply
|
|
23
|
-
use the built-in dedicated clients provided by rest-core, or do it yourself
|
|
24
|
-
for any other REST APIs.
|
|
25
|
-
|
|
26
|
-
[rest-core]: http://github.com/cardinalblue/rest-core
|
|
27
|
-
[rest-graph]: http://github.com/cardinalblue/rest-graph
|
|
28
|
-
|
|
29
|
-
## REQUIREMENTS:
|
|
30
|
-
|
|
31
|
-
* Tested with MRI (official ruby) 1.9.2, 1.8.7, and trunk
|
|
32
|
-
* Tested with Rubinius (rbx) 1.2.3
|
|
33
|
-
* Tested with JRuby 1.6.2
|
|
34
|
-
|
|
35
|
-
## INSTALLATION:
|
|
36
|
-
|
|
37
|
-
gem install rest-core
|
|
38
|
-
|
|
39
|
-
Or if you want development version, put this in Gemfile:
|
|
40
|
-
|
|
41
|
-
gem 'rest-core', :git => 'git://github.com/cardinalblue/rest-core.git'
|
|
42
|
-
|
|
43
|
-
## EXAMPLE:
|
|
44
|
-
|
|
45
|
-
RestCore::Builder.client('YourClient') do
|
|
46
|
-
use DefaultSite , 'https://api.github.com/users/'
|
|
47
|
-
use JsonDecode , true
|
|
48
|
-
use CommonLogger, method(:puts)
|
|
49
|
-
use Cache , {}, nil
|
|
50
|
-
run RestClient
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
client = YourClient.new
|
|
54
|
-
client.get('godfat')
|
|
55
|
-
client.get('godfat')
|
|
56
|
-
|
|
57
|
-
client.site = 'http://github.com/api/v2/json/user/show/'
|
|
58
|
-
client.get('godfat')
|
|
59
|
-
client.get('godfat')
|
|
60
|
-
|
|
61
|
-
See [example][] for more complex examples, and [build-in clients][] for even
|
|
62
|
-
more complex examples.
|
|
63
|
-
|
|
64
|
-
[example]: https://github.com/cardinalblue/rest-core/tree/master/example
|
|
65
|
-
[build-in clients]: https://github.com/cardinalblue/rest-core/tree/master/lib/rest-core/client
|
|
66
|
-
|
|
67
|
-
## LICENSE:
|
|
68
|
-
|
|
69
|
-
Apache License 2.0
|
|
70
|
-
|
|
71
|
-
Copyright (c) 2011, Cardinal Blue
|
|
72
|
-
|
|
73
|
-
Licensed under the Apache License, Version 2.0 (the "License");
|
|
74
|
-
you may not use this file except in compliance with the License.
|
|
75
|
-
You may obtain a copy of the License at
|
|
76
|
-
|
|
77
|
-
<http://www.apache.org/licenses/LICENSE-2.0>
|
|
78
|
-
|
|
79
|
-
Unless required by applicable law or agreed to in writing, software
|
|
80
|
-
distributed under the License is distributed on an "AS IS" BASIS,
|
|
81
|
-
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
82
|
-
See the License for the specific language governing permissions and
|
|
83
|
-
limitations under the License.
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
require 'erb'
|
|
3
|
-
require 'yaml'
|
|
4
|
-
|
|
5
|
-
require 'rest-graph/core'
|
|
6
|
-
|
|
7
|
-
module RestGraph::ConfigUtil
|
|
8
|
-
extend self
|
|
9
|
-
|
|
10
|
-
def load_config_for_all
|
|
11
|
-
RestGraph::ConfigUtil.load_config_for_rails if
|
|
12
|
-
Object.const_defined?(:Rails)
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
def load_config_for_rails app=Rails
|
|
16
|
-
root = app.root
|
|
17
|
-
file = ["#{root}/config/rest-graph.yaml", # YAML should use .yaml
|
|
18
|
-
"#{root}/config/rest-graph.yml"].find{|path| File.exist?(path)}
|
|
19
|
-
return unless file
|
|
20
|
-
|
|
21
|
-
RestGraph::ConfigUtil.load_config(file, Rails.env)
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
def load_config file, env
|
|
25
|
-
config = YAML.load(ERB.new(File.read(file)).result(binding))
|
|
26
|
-
defaults = config[env]
|
|
27
|
-
return unless defaults
|
|
28
|
-
|
|
29
|
-
mod = Module.new
|
|
30
|
-
mod.module_eval(defaults.inject([]){ |r, (k, v)|
|
|
31
|
-
# quote strings, leave others free (e.g. false, numbers, etc)
|
|
32
|
-
r << <<-RUBY
|
|
33
|
-
def default_#{k}
|
|
34
|
-
#{v.kind_of?(String) ? "'#{v}'" : v}
|
|
35
|
-
end
|
|
36
|
-
RUBY
|
|
37
|
-
}.join, __FILE__, __LINE__)
|
|
38
|
-
|
|
39
|
-
RestGraph.send(:extend, mod)
|
|
40
|
-
end
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
RestGraph.send(:extend, RestGraph::ConfigUtil)
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
if respond_to?(:require_relative, true)
|
|
3
|
-
require_relative 'common'
|
|
4
|
-
else
|
|
5
|
-
require File.dirname(__FILE__) + '/common'
|
|
6
|
-
end
|
|
7
|
-
|
|
8
|
-
require 'rest-graph/config_util'
|
|
9
|
-
|
|
10
|
-
describe RestGraph::ConfigUtil do
|
|
11
|
-
|
|
12
|
-
after do
|
|
13
|
-
RR.verify
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
should 'honor rails config' do
|
|
17
|
-
::Rails = Object.new
|
|
18
|
-
mock(Rails).env { 'test' }.times(2)
|
|
19
|
-
mock(Rails).root{ File.dirname(__FILE__) }.times(2)
|
|
20
|
-
|
|
21
|
-
check = lambda{
|
|
22
|
-
RestGraph.default_app_id.should == 41829
|
|
23
|
-
RestGraph.default_secret.should == 'r41829'.reverse
|
|
24
|
-
RestGraph.default_auto_decode.should == false
|
|
25
|
-
RestGraph.default_lang.should == 'zh-tw'
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
[RestGraph::ConfigUtil, RestGraph].each{ |const|
|
|
29
|
-
TestHelper.ensure_rollback{
|
|
30
|
-
const.load_config_for_rails
|
|
31
|
-
check.call
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
TestHelper.ensure_rollback{
|
|
35
|
-
const.load_config(
|
|
36
|
-
"#{File.dirname(__FILE__)}/config/rest-graph.yaml",
|
|
37
|
-
'test')
|
|
38
|
-
check.call
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
end
|
|
42
|
-
end
|
data/test/test_rest-graph.rb
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
$LOAD_PATH << File.dirname(__FILE__)
|
|
3
|
-
$LOAD_PATH.uniq!
|
|
4
|
-
|
|
5
|
-
Dir["#{File.dirname(__FILE__)}/*.rb"].each{ |file|
|
|
6
|
-
next if file == __FILE__
|
|
7
|
-
next if ARGV.map{ |path| File.expand_path(path)
|
|
8
|
-
}.include?(File.expand_path(file))
|
|
9
|
-
require File.basename(file).sub(/\..+$/, '')
|
|
10
|
-
}
|