rest-more 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (81) hide show
  1. data/.gitignore +6 -0
  2. data/.gitmodules +3 -0
  3. data/.travis.yml +13 -0
  4. data/CHANGES.md +7 -0
  5. data/Gemfile +26 -0
  6. data/LICENSE +201 -0
  7. data/README.md +72 -0
  8. data/Rakefile +63 -0
  9. data/TODO.md +14 -0
  10. data/example/rails2/Gemfile +21 -0
  11. data/example/rails2/README +4 -0
  12. data/example/rails2/Rakefile +11 -0
  13. data/example/rails2/app/controllers/application_controller.rb +134 -0
  14. data/example/rails2/app/views/application/helper.html.erb +2 -0
  15. data/example/rails2/config/boot.rb +130 -0
  16. data/example/rails2/config/environment.rb +15 -0
  17. data/example/rails2/config/environments/development.rb +17 -0
  18. data/example/rails2/config/environments/production.rb +28 -0
  19. data/example/rails2/config/environments/test.rb +30 -0
  20. data/example/rails2/config/initializers/cookie_verification_secret.rb +7 -0
  21. data/example/rails2/config/initializers/new_rails_defaults.rb +21 -0
  22. data/example/rails2/config/initializers/session_store.rb +15 -0
  23. data/example/rails2/config/preinitializer.rb +23 -0
  24. data/example/rails2/config/rest-core.yaml +16 -0
  25. data/example/rails2/config/routes.rb +43 -0
  26. data/example/rails2/log +0 -0
  27. data/example/rails2/test/functional/application_controller_test.rb +219 -0
  28. data/example/rails2/test/test_helper.rb +18 -0
  29. data/example/rails2/test/unit/rails_util_test.rb +44 -0
  30. data/example/rails3/Gemfile +20 -0
  31. data/example/rails3/README +4 -0
  32. data/example/rails3/Rakefile +7 -0
  33. data/example/rails3/app/controllers/application_controller.rb +134 -0
  34. data/example/rails3/app/views/application/helper.html.erb +2 -0
  35. data/example/rails3/config.ru +4 -0
  36. data/example/rails3/config/application.rb +23 -0
  37. data/example/rails3/config/boot.rb +6 -0
  38. data/example/rails3/config/environment.rb +5 -0
  39. data/example/rails3/config/environments/development.rb +23 -0
  40. data/example/rails3/config/environments/production.rb +49 -0
  41. data/example/rails3/config/environments/test.rb +30 -0
  42. data/example/rails3/config/initializers/secret_token.rb +7 -0
  43. data/example/rails3/config/initializers/session_store.rb +8 -0
  44. data/example/rails3/config/rest-core.yaml +16 -0
  45. data/example/rails3/config/routes.rb +5 -0
  46. data/example/rails3/test/functional/application_controller_test.rb +219 -0
  47. data/example/rails3/test/test_helper.rb +18 -0
  48. data/example/rails3/test/unit/rails_util_test.rb +44 -0
  49. data/example/sinatra/config.ru +16 -0
  50. data/lib/rest-core/client/facebook.rb +265 -0
  51. data/lib/rest-core/client/facebook/rails_util.rb +334 -0
  52. data/lib/rest-core/client/flurry.rb +107 -0
  53. data/lib/rest-core/client/flurry/rails_util.rb +74 -0
  54. data/lib/rest-core/client/github.rb +18 -0
  55. data/lib/rest-core/client/linkedin.rb +59 -0
  56. data/lib/rest-core/client/mixi.rb +47 -0
  57. data/lib/rest-core/client/simple.rb +2 -0
  58. data/lib/rest-core/client/twitter.rb +101 -0
  59. data/lib/rest-core/client/universal.rb +18 -0
  60. data/lib/rest-more.rb +11 -0
  61. data/lib/rest-more/version.rb +4 -0
  62. data/rest-more.gemspec +127 -0
  63. data/task/.gitignore +1 -0
  64. data/task/gemgem.rb +265 -0
  65. data/test/client/facebook/config/rest-core.yaml +8 -0
  66. data/test/client/facebook/test_api.rb +97 -0
  67. data/test/client/facebook/test_cache.rb +58 -0
  68. data/test/client/facebook/test_default.rb +23 -0
  69. data/test/client/facebook/test_error.rb +65 -0
  70. data/test/client/facebook/test_handler.rb +84 -0
  71. data/test/client/facebook/test_load_config.rb +39 -0
  72. data/test/client/facebook/test_misc.rb +72 -0
  73. data/test/client/facebook/test_oauth.rb +38 -0
  74. data/test/client/facebook/test_old.rb +114 -0
  75. data/test/client/facebook/test_page.rb +106 -0
  76. data/test/client/facebook/test_parse.rb +166 -0
  77. data/test/client/facebook/test_serialize.rb +43 -0
  78. data/test/client/facebook/test_timeout.rb +22 -0
  79. data/test/client/flurry/test_metrics.rb +83 -0
  80. data/test/client/twitter/test_api.rb +37 -0
  81. metadata +155 -0
@@ -0,0 +1,107 @@
1
+
2
+ require 'rest-core'
3
+
4
+ require 'time' # for Time.parse
5
+
6
+ RestCore::Flurry = RestCore::Builder.client(:api_key, :access_code) do
7
+ s = self.class # this is only for ruby 1.8!
8
+ use s::Timeout , 10
9
+
10
+ use s::DefaultSite , 'http://api.flurry.com/'
11
+ use s::DefaultHeaders, {'Accept' => 'application/json'}
12
+ use s::DefaultQuery , {}
13
+
14
+ use s::CommonLogger , nil
15
+ use s::Cache , nil, 600 do
16
+ use s::ErrorHandler, lambda{|env| raise env[s::RESPONSE_BODY]['message']}
17
+ use s::ErrorDetectorHttp
18
+ use s::JsonDecode , true
19
+ end
20
+ end
21
+
22
+ module RestCore::Flurry::Client
23
+ # see: http://wiki.flurry.com/index.php?title=AppInfo
24
+ # >> f.app_info
25
+ # => {"@platform"=>"iPhone", "@name"=>"PicCollage",
26
+ # "@createdDate"=>"2011-07-24", "@category"=>"Photography",
27
+ # "@version"=>"1.0", "@generatedDate"=>"9/15/11 7:08 AM",
28
+ # "version"=>[{"@name"=>"2.1", ...
29
+ def app_info query={}
30
+ get('appInfo/getApplication', query)
31
+ end
32
+
33
+ # see: http://wiki.flurry.com/index.php?title=EventMetrics
34
+ # >> f.event_matrics({}, :days => 7)
35
+ # => {"Facebook share error"=>{"@usersLastWeek"=>"948",
36
+ # "@usersLastMonth"=>"2046",
37
+ # "@usersLastDay"=>"4",...}}
38
+ def event_metrics query={}, opts={}
39
+ get('eventMetrics/Summary', *calculate_query_and_opts(query, opts)
40
+ )['event'].inject({}){ |r, i|
41
+ r[i['@eventName']] = i.reject{ |k, _| k == '@eventName' }
42
+ r }
43
+ end
44
+
45
+ # see: http://wiki.flurry.com/index.php?title=AppMetrics
46
+ # >> f.metrics('ActiveUsers', {}, :weeks => 4)
47
+ # => [["2011-09-19", 6516], ["2011-09-18", 43920], ["2011-09-17", 45412],
48
+ # ["2011-09-16", 40972], ["2011-09-15", 37587], ["2011-09-14", 34918],
49
+ # ["2011-09-13", 35223], ["2011-09-12", 37750], ["2011-09-11", 45057],
50
+ # ["2011-09-10", 44077], ["2011-09-09", 36683], ["2011-09-08", 34871],
51
+ # ["2011-09-07", 35960], ["2011-09-06", 35829], ["2011-09-05", 37777],
52
+ # ["2011-09-04", 40233], ["2011-09-03", 39306], ["2011-09-02", 33467],
53
+ # ["2011-09-01", 31558], ["2011-08-31", 32096], ["2011-08-30", 34076],
54
+ # ["2011-08-29", 34950], ["2011-08-28", 40456], ["2011-08-27", 41332],
55
+ # ["2011-08-26", 37737], ["2011-08-25", 34392], ["2011-08-24", 33560],
56
+ # ["2011-08-23", 34722]]
57
+ def metrics path, query={}, opts={}
58
+ get("appMetrics/#{path}", *calculate_query_and_opts(query, opts)
59
+ )['day'].map{ |i| [i['@date'], i['@value'].to_i] }.reverse
60
+ end
61
+
62
+ # >> f.weekly(f.metrics('ActiveUsers', {}, :weeks => 4))
63
+ # => [244548, 270227, 248513, 257149]
64
+ def weekly array
65
+ start = Time.parse(array.first.first, nil).to_i
66
+ array.group_by{ |(date, value)|
67
+ current = Time.parse(date, nil).to_i
68
+ - (current - start) / (86400*7)
69
+ # calling .last to discard week numbers created by group_by
70
+ }.sort.map(&:last).map{ |week|
71
+ week.map{ |(date, num)| num }.inject(&:+) }
72
+ end
73
+
74
+ # >> f.sum(f.weekly(f.metrics('ActiveUsers', {}, :weeks => 4)))
75
+ # => [1020437, 775889, 505662, 257149]
76
+ def sum array
77
+ reverse = array.reverse
78
+ (0...reverse.size).map{ |index|
79
+ reverse[1, index].inject(reverse.first, &:+)
80
+ }.reverse
81
+ end
82
+
83
+ def query
84
+ {'apiKey' => api_key ,
85
+ 'apiAccessCode' => access_code}
86
+ end
87
+
88
+ private
89
+ def calculate_query_and_opts query, opts
90
+ days = opts[:days] || (opts[:weeks] && opts[:weeks] * 7) ||
91
+ (opts[:months] && opts[:months] * 30)
92
+
93
+ startDate = query[:startDate] || (Time.now + 86400 - 86400*days).
94
+ strftime('%Y-%m-%d')
95
+
96
+ endDate = query[:endDate] || Time.now.
97
+ strftime('%Y-%m-%d')
98
+
99
+ [query.merge(:startDate => startDate,
100
+ :endDate => endDate),
101
+ opts.reject{ |k| [:days, :weeks, :months].include?(k) }]
102
+ end
103
+ end
104
+
105
+ RestCore::Flurry.send(:include, RestCore::Flurry::Client)
106
+ require 'rest-core/client/flurry/rails_util' if
107
+ Object.const_defined?(:Rails)
@@ -0,0 +1,74 @@
1
+
2
+ require 'rest-core/util/rails_util_util'
3
+
4
+ module RestCore::Flurry::DefaultAttributes
5
+ def default_log_method ; Rails.logger.method(:debug); end
6
+ def default_cache ; Rails.cache ; end
7
+ def default_api_key ; nil ; end
8
+ def default_access_code; nil ; end
9
+ end
10
+
11
+ module RestCore::Flurry::RailsUtil
12
+ def self.init app=Rails
13
+ RestCore::Config.load_for_rails(RestCore::Flurry, 'flurry', app)
14
+ end
15
+
16
+ module Helper
17
+ def rc_flurry
18
+ controller.send(:rc_flurry)
19
+ end
20
+ end
21
+
22
+ def self.included controller
23
+ # skip if included already, any better way to detect this?
24
+ return if controller.respond_to?(:rc_flurry, true)
25
+
26
+ controller.helper(RestCore::Flurry::RailsUtil::Helper)
27
+ controller.instance_methods.select{ |method|
28
+ method.to_s =~ /^rc_flurry/
29
+ }.each{ |method| controller.send(:protected, method) }
30
+ end
31
+
32
+ def rc_flurry_setup options={}
33
+ rc_flurry_options_ctl.merge!(
34
+ RestCore::RailsUtilUtil.extract_options(
35
+ RestCore::Flurry.members, options, :reject))
36
+ rc_flurry_options_new.merge!(
37
+ RestCore::RailsUtilUtil.extract_options(
38
+ RestCore::Flurry.members, options, :select))
39
+
40
+ # we'll need to reinitialize rc_flurry with the new options,
41
+ # otherwise if you're calling rc_flurry before rc_flurry_setup,
42
+ # you'll end up with default options without the ones you've passed
43
+ # into rc_flurry_setup.
44
+ rc_flurry.send(:initialize, rc_flurry_options_new)
45
+
46
+ true # keep going
47
+ end
48
+
49
+ def rc_flurry
50
+ @rc_flurry ||= RestCore::Flurry.new(rc_flurry_options_new)
51
+ end
52
+
53
+ module_function
54
+
55
+ # ==================== begin options utility =======================
56
+ def rc_flurry_oget key
57
+ if rc_flurry_options_ctl.has_key?(key)
58
+ rc_flurry_options_ctl[key]
59
+ else
60
+ RestCore::Flurry.send("default_#{key}")
61
+ end
62
+ end
63
+
64
+ def rc_flurry_options_ctl
65
+ @rc_flurry_options_ctl ||= {}
66
+ end
67
+
68
+ def rc_flurry_options_new
69
+ @rc_flurry_options_new ||= {}
70
+ end
71
+ # ==================== end options utility =======================
72
+ end
73
+
74
+ RestCore::Flurry::RailsUtil.init(Rails)
@@ -0,0 +1,18 @@
1
+
2
+ require 'rest-core'
3
+
4
+ RestCore::Github = RestCore::Builder.client do
5
+ s = self.class # this is only for ruby 1.8!
6
+ use s::Timeout , 10
7
+
8
+ use s::DefaultSite , 'https://api.github.com/'
9
+ use s::DefaultHeaders, {'Accept' => 'application/json'}
10
+ use s::Oauth2Query , 'access_token', nil
11
+
12
+ use s::CommonLogger , nil
13
+ use s::Cache , nil, 600 do
14
+ use s::ErrorHandler, lambda{|env| raise env[s::RESPONSE_BODY]['message']}
15
+ use s::ErrorDetectorHttp
16
+ use s::JsonDecode , true
17
+ end
18
+ end
@@ -0,0 +1,59 @@
1
+
2
+ require 'rest-core'
3
+
4
+ RestCore::Linkedin = RestCore::Builder.client(:data) do
5
+ s = self.class # this is only for ruby 1.8!
6
+ use s::Timeout , 10
7
+
8
+ use s::DefaultSite , 'https://api.linkedin.com/'
9
+ use s::DefaultHeaders, {'Accept' => 'application/json'}
10
+ use s::DefaultQuery , {'format' => 'json'}
11
+
12
+ use s::Oauth1Header ,
13
+ 'uas/oauth/requestToken', 'uas/oauth/accessToken',
14
+ 'https://www.linkedin.com/uas/oauth/authorize'
15
+
16
+ use s::CommonLogger , nil
17
+ use s::Cache , nil, 600 do
18
+ use s::ErrorHandler, lambda{|env|
19
+ if (body = env[s::RESPONSE_BODY]).kind_of?(Hash)
20
+ raise body['message']
21
+ else
22
+ raise body
23
+ end
24
+ }
25
+ use s::ErrorDetectorHttp
26
+ use s::JsonDecode , true
27
+ end
28
+
29
+ use s::Defaults , :data => lambda{{}}
30
+ end
31
+
32
+ module RestCore::Linkedin::Client
33
+ include RestCore
34
+
35
+ def oauth_token
36
+ data['oauth_token'] if data.kind_of?(Hash)
37
+ end
38
+ def oauth_token= token
39
+ data['oauth_token'] = token if data.kind_of?(Hash)
40
+ end
41
+ def oauth_token_secret
42
+ data['oauth_token_secret'] if data.kind_of?(Hash)
43
+ end
44
+ def oauth_token_secret= secret
45
+ data['oauth_token_secret'] = secret if data.kind_of?(Hash)
46
+ end
47
+
48
+ def me queries={}, opts={}
49
+ get('v1/people/~', queries, opts)
50
+ end
51
+
52
+ private
53
+ def set_token query
54
+ self.data = query
55
+ end
56
+ end
57
+
58
+ RestCore::Linkedin.send(:include, RestCore::ClientOauth1)
59
+ RestCore::Linkedin.send(:include, RestCore::Linkedin::Client)
@@ -0,0 +1,47 @@
1
+
2
+ RestCore::Mixi = RestCore::Builder.client(
3
+ :data, :consumer_key, :consumer_secret, :redirect_uri) do
4
+ s = self.class # this is only for ruby 1.8!
5
+ use s::Timeout , 10
6
+
7
+ use s::DefaultSite , 'http://api.mixi-platform.com/'
8
+ use s::DefaultHeaders, {'Accept' => 'application/json'}
9
+
10
+ use s::Oauth2Header , nil
11
+
12
+ use s::CommonLogger , nil
13
+ use s::Cache , nil, 600 do
14
+ use s::ErrorHandler , lambda{ |env| p env }
15
+ use s::ErrorDetectorHttp
16
+ use s::JsonDecode , true
17
+ end
18
+
19
+ use s::Defaults , :data => lambda{{}}
20
+ end
21
+
22
+ module RestCore::Mixi::Client
23
+ include RestCore
24
+
25
+ def access_token
26
+ data['access_token'] if data.kind_of?(Hash)
27
+ end
28
+
29
+ def authorize_url queries={}
30
+ url('https://mixi.jp/connect_authorize.pl',
31
+ {:client_id => consumer_key,
32
+ :response_type => 'code',
33
+ :scope => 'r_profile'}.merge(queries))
34
+ end
35
+
36
+ def authorize! code, payload={}, opts={}
37
+ pl = {:client_id => consumer_key ,
38
+ :client_secret => consumer_secret,
39
+ :redirect_uri => redirect_uri ,
40
+ :grant_type => 'authorization_code',
41
+ :code => code}.merge(payload)
42
+
43
+ self.data = post('https://secure.mixi-platform.com/2/token', pl, {}, opts)
44
+ end
45
+ end
46
+
47
+ RestCore::Mixi.send(:include, RestCore::Mixi::Client)
@@ -0,0 +1,2 @@
1
+
2
+ RestCore::Simple = RestCore::Builder.client
@@ -0,0 +1,101 @@
1
+
2
+ require 'rest-core'
3
+
4
+ RestCore::Twitter = RestCore::Builder.client(:data) do
5
+ s = self.class # this is only for ruby 1.8!
6
+ use s::Timeout , 10
7
+
8
+ use s::DefaultSite , 'https://api.twitter.com/'
9
+ use s::DefaultHeaders, {'Accept' => 'application/json'}
10
+
11
+ use s::Oauth1Header ,
12
+ 'oauth/request_token', 'oauth/access_token', 'oauth/authorize'
13
+
14
+ use s::CommonLogger , nil
15
+ use s::Cache , nil, 600 do
16
+ use s::ErrorHandler, lambda{ |env|
17
+ raise ::RestCore::Twitter::Error.call(env) }
18
+ use s::ErrorDetectorHttp
19
+ use s::JsonDecode , true
20
+ end
21
+
22
+ use s::Defaults , :data => lambda{{}}
23
+ end
24
+
25
+ class RestCore::Twitter::Error < RestCore::Error
26
+ include RestCore
27
+ class ServerError < Twitter::Error; end
28
+
29
+ class BadRequest < Twitter::Error; end
30
+ class Unauthorized < Twitter::Error; end
31
+ class Forbidden < Twitter::Error; end
32
+ class NotFound < Twitter::Error; end
33
+ class NotAcceptable < Twitter::Error; end
34
+ class EnhanceYourCalm < Twitter::Error; end
35
+
36
+ class InternalServerError < Twitter::Error::ServerError; end
37
+ class BadGateway < Twitter::Error::ServerError; end
38
+ class ServiceUnavailable < Twitter::Error::ServerError; end
39
+
40
+ attr_reader :error, :url
41
+ def initialize error, url=''
42
+ @error, @url = error, url
43
+ super("#{error.inspect} from #{url}")
44
+ end
45
+
46
+ def self.call env
47
+ error, url = env[RESPONSE_BODY], Middleware.request_uri(env)
48
+ return new(env[FAIL], url) unless error.kind_of?(Hash)
49
+ case env[RESPONSE_STATUS]
50
+ when 400; BadRequest
51
+ when 401; Unauthorized
52
+ when 403; Forbidden
53
+ when 404; NotFound
54
+ when 406; NotAcceptable
55
+ when 420; EnhanceYourCalm
56
+ when 500; InternalServerError
57
+ when 502; BadGateway
58
+ when 503; ServiceUnavailable
59
+ else ; self
60
+ end.new(error, url)
61
+ end
62
+ end
63
+
64
+ module RestCore::Twitter::Client
65
+ include RestCore
66
+
67
+ def oauth_token
68
+ data['oauth_token'] if data.kind_of?(Hash)
69
+ end
70
+ def oauth_token= token
71
+ data['oauth_token'] = token if data.kind_of?(Hash)
72
+ end
73
+ def oauth_token_secret
74
+ data['oauth_token_secret'] if data.kind_of?(Hash)
75
+ end
76
+ def oauth_token_secret= secret
77
+ data['oauth_token_secret'] = secret if data.kind_of?(Hash)
78
+ end
79
+
80
+ def tweet status, media=nil, opts={}
81
+ if media
82
+ post('https://upload.twitter.com/1/statuses/update_with_media.json',
83
+ {:status => status, 'media[]' => media},
84
+ {}, opts)
85
+ else
86
+ post('1/statuses/update.json', {:status => status}, {}, opts)
87
+ end
88
+ end
89
+
90
+ def statuses user, queries={}, opts={}
91
+ get('1/statuses/user_timeline.json', {:id => user}.merge(queries), opts)
92
+ end
93
+
94
+ private
95
+ def set_token query
96
+ self.data = query
97
+ end
98
+ end
99
+
100
+ RestCore::Twitter.send(:include, RestCore::ClientOauth1)
101
+ RestCore::Twitter.send(:include, RestCore::Twitter::Client)
@@ -0,0 +1,18 @@
1
+
2
+ RestCore::Universal = RestCore::Builder.client(:data) do
3
+ s = self.class # this is only for ruby 1.8!
4
+ use s::Timeout , 0
5
+
6
+ use s::DefaultSite , nil
7
+ use s::DefaultHeaders, {}
8
+ use s::DefaultQuery , {}
9
+
10
+ use s::CommonLogger , method(:puts)
11
+ use s::Cache , {}, 600 do
12
+ use s::ErrorHandler, nil
13
+ use s::ErrorDetectorHttp
14
+ use s::JsonDecode , false
15
+ end
16
+
17
+ use s::Defaults , :data => lambda{{}}
18
+ end
data/lib/rest-more.rb ADDED
@@ -0,0 +1,11 @@
1
+
2
+ require 'rest-core'
3
+
4
+ module RestCore
5
+ autoload :Github , 'rest-core/client/github'
6
+ autoload :Twitter , 'rest-core/client/twitter'
7
+ autoload :Linkedin, 'rest-core/client/linkedin'
8
+ autoload :Facebook, 'rest-core/client/facebook'
9
+ autoload :Mixi , 'rest-core/client/mixi'
10
+ autoload :Flurry , 'rest-core/client/flurry'
11
+ end