rest-core 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (65) hide show
  1. data/.gitignore +6 -0
  2. data/.gitmodules +3 -0
  3. data/.travis.yml +9 -0
  4. data/CONTRIBUTORS +11 -0
  5. data/Gemfile +8 -0
  6. data/LICENSE +201 -0
  7. data/NOTE.md +48 -0
  8. data/README +83 -0
  9. data/README.md +83 -0
  10. data/Rakefile +26 -0
  11. data/TODO.md +17 -0
  12. data/example/facebook.rb +145 -0
  13. data/example/github.rb +21 -0
  14. data/lib/rest-core.rb +48 -0
  15. data/lib/rest-core/app/ask.rb +11 -0
  16. data/lib/rest-core/app/rest-client.rb +24 -0
  17. data/lib/rest-core/builder.rb +24 -0
  18. data/lib/rest-core/client.rb +278 -0
  19. data/lib/rest-core/client/github.rb +19 -0
  20. data/lib/rest-core/client/linkedin.rb +57 -0
  21. data/lib/rest-core/client/rest-graph.rb +262 -0
  22. data/lib/rest-core/client/twitter.rb +59 -0
  23. data/lib/rest-core/client_oauth1.rb +25 -0
  24. data/lib/rest-core/event.rb +17 -0
  25. data/lib/rest-core/middleware.rb +53 -0
  26. data/lib/rest-core/middleware/cache.rb +80 -0
  27. data/lib/rest-core/middleware/common_logger.rb +27 -0
  28. data/lib/rest-core/middleware/default_headers.rb +11 -0
  29. data/lib/rest-core/middleware/default_query.rb +11 -0
  30. data/lib/rest-core/middleware/default_site.rb +15 -0
  31. data/lib/rest-core/middleware/defaults.rb +44 -0
  32. data/lib/rest-core/middleware/error_detector.rb +16 -0
  33. data/lib/rest-core/middleware/error_detector_http.rb +11 -0
  34. data/lib/rest-core/middleware/error_handler.rb +19 -0
  35. data/lib/rest-core/middleware/json_decode.rb +83 -0
  36. data/lib/rest-core/middleware/oauth1_header.rb +81 -0
  37. data/lib/rest-core/middleware/oauth2_query.rb +19 -0
  38. data/lib/rest-core/middleware/timeout.rb +13 -0
  39. data/lib/rest-core/util/hmac.rb +22 -0
  40. data/lib/rest-core/version.rb +4 -0
  41. data/lib/rest-core/wrapper.rb +55 -0
  42. data/lib/rest-graph/config_util.rb +43 -0
  43. data/rest-core.gemspec +162 -0
  44. data/task/.gitignore +1 -0
  45. data/task/gemgem.rb +184 -0
  46. data/test/common.rb +29 -0
  47. data/test/config/rest-graph.yaml +7 -0
  48. data/test/pending/test_load_config.rb +42 -0
  49. data/test/pending/test_multi.rb +123 -0
  50. data/test/pending/test_test_util.rb +86 -0
  51. data/test/test_api.rb +98 -0
  52. data/test/test_cache.rb +62 -0
  53. data/test/test_default.rb +27 -0
  54. data/test/test_error.rb +66 -0
  55. data/test/test_handler.rb +87 -0
  56. data/test/test_misc.rb +75 -0
  57. data/test/test_oauth.rb +42 -0
  58. data/test/test_oauth1_header.rb +46 -0
  59. data/test/test_old.rb +116 -0
  60. data/test/test_page.rb +110 -0
  61. data/test/test_parse.rb +131 -0
  62. data/test/test_rest-graph.rb +10 -0
  63. data/test/test_serialize.rb +44 -0
  64. data/test/test_timeout.rb +25 -0
  65. metadata +267 -0
@@ -0,0 +1,22 @@
1
+
2
+ require 'openssl'
3
+
4
+ module RestCore; end
5
+ module RestCore::Hmac
6
+ module_function
7
+ # Fallback to ruby-hmac gem in case system openssl
8
+ # lib doesn't support SHA256 (OSX 10.5)
9
+ def sha256 key, data
10
+ OpenSSL::HMAC.digest('sha256', key, data)
11
+ rescue RuntimeError
12
+ require 'hmac-sha2'
13
+ HMAC::SHA256.digest(key, data)
14
+ end
15
+
16
+ def sha1 key, data
17
+ OpenSSL::HMAC.digest('sha1', key, data)
18
+ rescue RuntimeError
19
+ require 'hmac-sha1'
20
+ HMAC::SHA1.digest(key, data)
21
+ end
22
+ end
@@ -0,0 +1,4 @@
1
+
2
+ module RestCore
3
+ VERSION = '0.0.1'
4
+ end
@@ -0,0 +1,55 @@
1
+
2
+ require 'rest-core'
3
+
4
+ module RestCore::Wrapper
5
+ include RestCore
6
+ def self.included mod
7
+ mod.send(:attr_reader, :init, :middles, :wrapped)
8
+ end
9
+
10
+ def initialize &block
11
+ @middles ||= []
12
+ instance_eval(&block) if block_given?
13
+ @wrapped ||= to_app(@init || Ask)
14
+ end
15
+
16
+ def use middle, *args, &block
17
+ middles << [middle, args, block]
18
+ end
19
+
20
+ def run app
21
+ @init = app
22
+ end
23
+
24
+ def members
25
+ middles.map{ |(middle, args, block)|
26
+ if middle.public_method_defined?(:wrapped)
27
+ # TODO: this is hacky... try to avoid calling new!
28
+ middle.members + middle.new(Ask.new, *args, &block).members
29
+ else
30
+ middle.members
31
+ end
32
+ }.flatten
33
+ end
34
+
35
+ def to_app init=@init
36
+ # === foldr m.new app middles
37
+ middles.reverse.inject(init.new){ |app_, (middle, args, block)|
38
+ begin
39
+ middle.new(app_, *partial_deep_copy(args), &block)
40
+ rescue ArgumentError => e
41
+ raise ArgumentError.new("#{middle}: #{e}")
42
+ end
43
+ }
44
+ end
45
+
46
+ module_function
47
+ def partial_deep_copy obj
48
+ case obj
49
+ when Array; obj.map{ |o| partial_deep_copy(o) }
50
+ when Hash ; obj.inject({}){ |r, (k, v)| r[k] = partial_deep_copy(v); r }
51
+ when Numeric, Symbol, TrueClass, FalseClass, NilClass; obj
52
+ else begin obj.dup; rescue TypeError; obj; end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,43 @@
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)
@@ -0,0 +1,162 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = %q{rest-core}
5
+ s.version = "0.0.1"
6
+
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
+ s.authors = [
9
+ %q{Cardinal Blue},
10
+ %q{Lin Jen-Shin (godfat)}]
11
+ s.date = %q{2011-08-16}
12
+ s.description = %q{A modular Ruby REST client collection/infrastructure.
13
+
14
+ In this era of web services and mashups, we have seen a blooming of REST
15
+ APIs. One might wonder, how do we use these APIs easily and elegantly?
16
+ Since REST is very simple compared to SOAP, it is not hard to build a
17
+ dedicated client ourselves.
18
+
19
+ We have developed [rest-core][] with composable middlewares to build a
20
+ REST client, based on the effort from [rest-graph][]. In the cases of
21
+ common APIs such as Facebook, Github, and Twitter, developers can simply
22
+ use the built-in dedicated clients provided by rest-core, or do it yourself
23
+ for any other REST APIs.
24
+
25
+ [rest-core]: http://github.com/cardinalblue/rest-core
26
+ [rest-graph]: http://github.com/cardinalblue/rest-graph}
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
+ s.files = [
34
+ %q{.gitignore},
35
+ %q{.gitmodules},
36
+ %q{.travis.yml},
37
+ %q{CONTRIBUTORS},
38
+ %q{Gemfile},
39
+ %q{LICENSE},
40
+ %q{NOTE.md},
41
+ %q{README},
42
+ %q{README.md},
43
+ %q{Rakefile},
44
+ %q{TODO.md},
45
+ %q{example/facebook.rb},
46
+ %q{example/github.rb},
47
+ %q{lib/rest-core.rb},
48
+ %q{lib/rest-core/app/ask.rb},
49
+ %q{lib/rest-core/app/rest-client.rb},
50
+ %q{lib/rest-core/builder.rb},
51
+ %q{lib/rest-core/client.rb},
52
+ %q{lib/rest-core/client/github.rb},
53
+ %q{lib/rest-core/client/linkedin.rb},
54
+ %q{lib/rest-core/client/rest-graph.rb},
55
+ %q{lib/rest-core/client/twitter.rb},
56
+ %q{lib/rest-core/client_oauth1.rb},
57
+ %q{lib/rest-core/event.rb},
58
+ %q{lib/rest-core/middleware.rb},
59
+ %q{lib/rest-core/middleware/cache.rb},
60
+ %q{lib/rest-core/middleware/common_logger.rb},
61
+ %q{lib/rest-core/middleware/default_headers.rb},
62
+ %q{lib/rest-core/middleware/default_query.rb},
63
+ %q{lib/rest-core/middleware/default_site.rb},
64
+ %q{lib/rest-core/middleware/defaults.rb},
65
+ %q{lib/rest-core/middleware/error_detector.rb},
66
+ %q{lib/rest-core/middleware/error_detector_http.rb},
67
+ %q{lib/rest-core/middleware/error_handler.rb},
68
+ %q{lib/rest-core/middleware/json_decode.rb},
69
+ %q{lib/rest-core/middleware/oauth1_header.rb},
70
+ %q{lib/rest-core/middleware/oauth2_query.rb},
71
+ %q{lib/rest-core/middleware/timeout.rb},
72
+ %q{lib/rest-core/util/hmac.rb},
73
+ %q{lib/rest-core/version.rb},
74
+ %q{lib/rest-core/wrapper.rb},
75
+ %q{lib/rest-graph/config_util.rb},
76
+ %q{rest-core.gemspec},
77
+ %q{task/.gitignore},
78
+ %q{task/gemgem.rb},
79
+ %q{test/common.rb},
80
+ %q{test/config/rest-graph.yaml},
81
+ %q{test/pending/test_load_config.rb},
82
+ %q{test/pending/test_multi.rb},
83
+ %q{test/pending/test_test_util.rb},
84
+ %q{test/test_api.rb},
85
+ %q{test/test_cache.rb},
86
+ %q{test/test_default.rb},
87
+ %q{test/test_error.rb},
88
+ %q{test/test_handler.rb},
89
+ %q{test/test_misc.rb},
90
+ %q{test/test_oauth.rb},
91
+ %q{test/test_oauth1_header.rb},
92
+ %q{test/test_old.rb},
93
+ %q{test/test_page.rb},
94
+ %q{test/test_parse.rb},
95
+ %q{test/test_rest-graph.rb},
96
+ %q{test/test_serialize.rb},
97
+ %q{test/test_timeout.rb}]
98
+ s.homepage = %q{https://github.com/cardinalblue/rest-core}
99
+ s.rdoc_options = [
100
+ %q{--main},
101
+ %q{README}]
102
+ s.require_paths = [%q{lib}]
103
+ s.rubygems_version = %q{1.8.7}
104
+ s.summary = %q{A modular Ruby REST client collection/infrastructure.}
105
+ 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
+ %q{test/test_api.rb},
110
+ %q{test/test_cache.rb},
111
+ %q{test/test_default.rb},
112
+ %q{test/test_error.rb},
113
+ %q{test/test_handler.rb},
114
+ %q{test/test_misc.rb},
115
+ %q{test/test_oauth.rb},
116
+ %q{test/test_oauth1_header.rb},
117
+ %q{test/test_old.rb},
118
+ %q{test/test_page.rb},
119
+ %q{test/test_parse.rb},
120
+ %q{test/test_rest-graph.rb},
121
+ %q{test/test_serialize.rb},
122
+ %q{test/test_timeout.rb}]
123
+
124
+ if s.respond_to? :specification_version then
125
+ s.specification_version = 3
126
+
127
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
128
+ s.add_development_dependency(%q<rest-client>, [">= 0"])
129
+ s.add_development_dependency(%q<rack>, [">= 0"])
130
+ s.add_development_dependency(%q<yajl-ruby>, [">= 0"])
131
+ s.add_development_dependency(%q<json>, [">= 0"])
132
+ s.add_development_dependency(%q<json_pure>, [">= 0"])
133
+ s.add_development_dependency(%q<ruby-hmac>, [">= 0"])
134
+ s.add_development_dependency(%q<webmock>, [">= 0"])
135
+ s.add_development_dependency(%q<bacon>, [">= 0"])
136
+ s.add_development_dependency(%q<rr>, [">= 0"])
137
+ s.add_development_dependency(%q<rake>, [">= 0"])
138
+ else
139
+ s.add_dependency(%q<rest-client>, [">= 0"])
140
+ s.add_dependency(%q<rack>, [">= 0"])
141
+ s.add_dependency(%q<yajl-ruby>, [">= 0"])
142
+ s.add_dependency(%q<json>, [">= 0"])
143
+ s.add_dependency(%q<json_pure>, [">= 0"])
144
+ s.add_dependency(%q<ruby-hmac>, [">= 0"])
145
+ s.add_dependency(%q<webmock>, [">= 0"])
146
+ s.add_dependency(%q<bacon>, [">= 0"])
147
+ s.add_dependency(%q<rr>, [">= 0"])
148
+ s.add_dependency(%q<rake>, [">= 0"])
149
+ end
150
+ else
151
+ s.add_dependency(%q<rest-client>, [">= 0"])
152
+ s.add_dependency(%q<rack>, [">= 0"])
153
+ s.add_dependency(%q<yajl-ruby>, [">= 0"])
154
+ s.add_dependency(%q<json>, [">= 0"])
155
+ s.add_dependency(%q<json_pure>, [">= 0"])
156
+ s.add_dependency(%q<ruby-hmac>, [">= 0"])
157
+ s.add_dependency(%q<webmock>, [">= 0"])
158
+ s.add_dependency(%q<bacon>, [">= 0"])
159
+ s.add_dependency(%q<rr>, [">= 0"])
160
+ s.add_dependency(%q<rake>, [">= 0"])
161
+ end
162
+ end
@@ -0,0 +1 @@
1
+ *.rbc
@@ -0,0 +1,184 @@
1
+
2
+ require 'pathname'
3
+
4
+ module Gemgem
5
+ class << self
6
+ attr_accessor :dir, :spec
7
+ end
8
+
9
+ module_function
10
+ def create
11
+ yield(spec = Gem::Specification.new{ |s|
12
+ s.authors = ['Lin Jen-Shin (godfat)']
13
+ s.email = ['godfat (XD) godfat.org']
14
+
15
+ description = File.read("#{Gemgem.dir}/README").
16
+ match(/DESCRIPTION:\n\n(.+?)(?=\n\n[^\n]+:\n)/m)[1].
17
+ lines.to_a
18
+
19
+ s.description = description.join
20
+ s.summary = description.first
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
+ s.rubygems_version = Gem::VERSION
27
+ s.date = Time.now.strftime('%Y-%m-%d')
28
+ s.files = gem_files
29
+ s.test_files = gem_files.grep(%r{^test/(.+?/)*test_.+?\.rb$})
30
+ s.executables = Dir['bin/*'].map{ |f| File.basename(f) }
31
+ s.require_paths = %w[lib]
32
+ })
33
+ spec.homepage ||= "https://github.com/godfat/#{spec.name}"
34
+ spec
35
+ end
36
+
37
+ def gem_tag
38
+ "#{spec.name}-#{spec.version}"
39
+ end
40
+
41
+ def write
42
+ File.open("#{dir}/#{spec.name}.gemspec", 'w'){ |f|
43
+ f << split_lines(spec.to_ruby) }
44
+ end
45
+
46
+ def split_lines ruby
47
+ ruby.gsub(/(.+?)\[(.+?)\]/){ |s|
48
+ if $2.index(',')
49
+ "#{$1}[\n #{$2.split(',').map(&:strip).join(",\n ")}]"
50
+ else
51
+ s
52
+ end
53
+ }
54
+ end
55
+
56
+ def all_files
57
+ @all_files ||= find_files(Pathname.new(dir)).map{ |file|
58
+ if file.to_s =~ %r{\.git/}
59
+ nil
60
+ else
61
+ file.to_s
62
+ end
63
+ }.compact.sort
64
+ end
65
+
66
+ def gem_files
67
+ @gem_files ||= all_files - ignored_files
68
+ end
69
+
70
+ def ignored_files
71
+ @ignored_file ||= all_files.select{ |path| ignore_patterns.find{ |ignore|
72
+ path =~ ignore && !git_files.include?(path)}}
73
+ end
74
+
75
+ def git_files
76
+ @git_files ||= if File.exist?("#{dir}/.git")
77
+ `git ls-files`.split("\n")
78
+ else
79
+ []
80
+ end
81
+ end
82
+
83
+ # protected
84
+ def find_files path
85
+ path.children.select(&:file?).map{|file| file.to_s[(dir.size+1)..-1]} +
86
+ path.children.select(&:directory?).map{|dir| find_files(dir)}.flatten
87
+ end
88
+
89
+ def ignore_patterns
90
+ @ignore_files ||= expand_patterns(
91
+ File.read("#{dir}/.gitignore").split("\n").reject{ |pattern|
92
+ pattern.strip == ''
93
+ }).map{ |pattern| %r{^([^/]+/)*?#{Regexp.escape(pattern)}(/[^/]+)*?$} }
94
+ end
95
+
96
+ def expand_patterns pathes
97
+ pathes.map{ |path|
98
+ if path !~ /\*/
99
+ path
100
+ else
101
+ expand_patterns(
102
+ Dir[path] +
103
+ Pathname.new(File.dirname(path)).children.select(&:directory?).
104
+ map{ |prefix| "#{prefix}/#{File.basename(path)}" })
105
+ end
106
+ }.flatten
107
+ end
108
+ end
109
+
110
+ namespace :gem do
111
+
112
+ desc 'Install gem'
113
+ task :install => [:build] do
114
+ sh("#{Gem.ruby} -S gem install pkg/#{Gemgem.gem_tag}")
115
+ end
116
+
117
+ desc 'Build gem'
118
+ task :build => [:spec] do
119
+ sh("#{Gem.ruby} -S gem build #{Gemgem.spec.name}.gemspec")
120
+ sh("mkdir -p pkg")
121
+ sh("mv #{Gemgem.gem_tag}.gem pkg/")
122
+ end
123
+
124
+ desc 'Release gem'
125
+ task :release => [:spec, :check, :build] do
126
+ sh("git tag #{Gemgem.gem_tag}")
127
+ sh("git push")
128
+ sh("git push --tags")
129
+ sh("#{Gem.ruby} -S gem push pkg/#{Gemgem.gem_tag}.gem")
130
+ end
131
+
132
+ task :check do
133
+ ver = Gemgem.spec.version.to_s
134
+
135
+ if ENV['VERSION'].nil?
136
+ puts("\x1b[35mExpected " \
137
+ "\x1b[33mVERSION\x1b[35m=\x1b[33m#{ver}\x1b[m")
138
+ exit(1)
139
+
140
+ elsif ENV['VERSION'] != ver
141
+ puts("\x1b[35mExpected \x1b[33mVERSION\x1b[35m=\x1b[33m#{ver} " \
142
+ "\x1b[35mbut got\n " \
143
+ "\x1b[33mVERSION\x1b[35m=\x1b[33m#{ENV['VERSION']}\x1b[m")
144
+ exit(2)
145
+ end
146
+ end
147
+
148
+ end # of gem namespace
149
+
150
+ desc 'Run tests in memory'
151
+ task :test do
152
+ require 'bacon'
153
+ Bacon.extend(Bacon::TestUnitOutput)
154
+ Bacon.summary_on_exit
155
+ $LOAD_PATH.unshift('lib')
156
+ Dir['test/**/test_*.rb'].each{ |file| load file }
157
+ end
158
+
159
+ desc 'Run tests with shell'
160
+ task 'test:shell', :RUBY_OPTS do |t, args|
161
+ files = Dir['test/**/test_*.rb'].join(' ')
162
+
163
+ cmd = [Gem.ruby, args[:RUBY_OPTS],
164
+ '-I', 'lib', '-S', 'bacon', '--quiet', files]
165
+
166
+ sh(cmd.compact.join(' '))
167
+ end
168
+
169
+ desc 'Generate rdoc'
170
+ task :doc => ['gem:spec'] do
171
+ sh("yardoc -o rdoc --main README.md" \
172
+ " --files #{Gemgem.spec.extra_rdoc_files.join(',')}")
173
+ end
174
+
175
+ desc 'Removed ignored files'
176
+ task :clean => ['gem:spec'] do
177
+ trash = "~/.Trash/#{Gemgem.spec.name}/"
178
+ sh "mkdir -p #{trash}" unless File.exist?(File.expand_path(trash))
179
+ Gemgem.ignored_files.each{ |file| sh "mv #{file} #{trash}" }
180
+ end
181
+
182
+ task :default do
183
+ puts `#{Gem.ruby} -S #{$PROGRAM_NAME} -T`
184
+ end