rest-more 0.7.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.
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