rest-core 2.1.2 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (58) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -2
  3. data/.travis.yml +3 -5
  4. data/CHANGES.md +65 -5
  5. data/Gemfile +10 -5
  6. data/NOTE.md +1 -1
  7. data/README.md +194 -128
  8. data/Rakefile +8 -34
  9. data/TODO.md +3 -2
  10. data/example/simple.rb +6 -4
  11. data/example/use-cases.rb +39 -122
  12. data/lib/rest-core.rb +14 -5
  13. data/lib/rest-core/builder.rb +12 -2
  14. data/lib/rest-core/client.rb +31 -25
  15. data/lib/rest-core/engine.rb +39 -0
  16. data/lib/rest-core/engine/http-client.rb +41 -0
  17. data/lib/rest-core/engine/net-http-persistent.rb +21 -0
  18. data/lib/rest-core/engine/rest-client.rb +13 -42
  19. data/lib/rest-core/event_source.rb +91 -0
  20. data/lib/rest-core/middleware.rb +17 -11
  21. data/lib/rest-core/middleware/error_detector.rb +1 -6
  22. data/lib/rest-core/middleware/oauth1_header.rb +1 -0
  23. data/lib/rest-core/middleware/oauth2_header.rb +20 -8
  24. data/lib/rest-core/middleware/oauth2_query.rb +1 -0
  25. data/lib/rest-core/middleware/timeout.rb +5 -19
  26. data/lib/rest-core/promise.rb +137 -0
  27. data/lib/rest-core/test.rb +2 -43
  28. data/lib/rest-core/thread_pool.rb +122 -0
  29. data/lib/rest-core/timer.rb +30 -0
  30. data/lib/rest-core/util/hmac.rb +0 -8
  31. data/lib/rest-core/version.rb +1 -1
  32. data/lib/rest-core/wrapper.rb +1 -1
  33. data/rest-core.gemspec +36 -25
  34. data/task/README.md +54 -0
  35. data/task/gemgem.rb +150 -156
  36. data/test/test_builder.rb +2 -2
  37. data/test/test_cache.rb +8 -8
  38. data/test/test_client.rb +16 -6
  39. data/test/test_client_oauth1.rb +1 -1
  40. data/test/test_event_source.rb +77 -0
  41. data/test/test_follow_redirect.rb +1 -1
  42. data/test/test_future.rb +16 -0
  43. data/test/test_oauth2_header.rb +28 -0
  44. data/test/test_promise.rb +89 -0
  45. data/test/test_rest-client.rb +21 -0
  46. data/test/test_thread_pool.rb +10 -0
  47. data/test/test_timeout.rb +13 -8
  48. metadata +61 -37
  49. data/example/multi.rb +0 -44
  50. data/lib/rest-core/engine/auto.rb +0 -25
  51. data/lib/rest-core/engine/em-http-request.rb +0 -90
  52. data/lib/rest-core/engine/future/future.rb +0 -107
  53. data/lib/rest-core/engine/future/future_fiber.rb +0 -32
  54. data/lib/rest-core/engine/future/future_thread.rb +0 -29
  55. data/lib/rest-core/middleware/timeout/timer_em.rb +0 -26
  56. data/lib/rest-core/middleware/timeout/timer_thread.rb +0 -36
  57. data/task/.gitignore +0 -1
  58. data/test/test_em-http-request.rb +0 -186
@@ -1,14 +1,26 @@
1
1
 
2
- require 'pathname'
3
-
4
2
  module Gemgem
5
3
  class << self
6
- attr_accessor :dir, :spec
4
+ attr_accessor :dir, :spec, :spec_create
7
5
  end
8
6
 
9
7
  module_function
8
+ def gem_tag ; "#{spec.name}-#{spec.version}" ; end
9
+ def gem_path ; "#{pkg_dir}/#{gem_tag}.gem" ; end
10
+ def spec_path ; "#{dir}/#{spec.name}.gemspec" ; end
11
+ def pkg_dir ; "#{dir}/pkg" ; end
12
+ def escaped_dir; @escaped_dir ||= Regexp.escape(dir); end
13
+
14
+ def init dir, &block
15
+ self.dir = dir
16
+ $LOAD_PATH.unshift("#{dir}/lib")
17
+ ENV['RUBYLIB'] = "#{dir}/lib:#{ENV['RUBYLIB']}"
18
+ ENV['PATH'] = "#{dir}/bin:#{ENV['PATH']}"
19
+ self.spec_create = block
20
+ end
21
+
10
22
  def create
11
- yield(spec = Gem::Specification.new{ |s|
23
+ spec = Gem::Specification.new do |s|
12
24
  s.authors = ['Lin Jen-Shin (godfat)']
13
25
  s.email = ['godfat (XD) godfat.org']
14
26
 
@@ -16,163 +28,144 @@ module Gemgem
16
28
  s.summary = description.first
17
29
  s.license = readme['LICENSE'].sub(/.+\n\n/, '').lines.first.strip
18
30
 
19
- s.rubygems_version = Gem::VERSION
20
- s.date = Time.now.strftime('%Y-%m-%d')
21
- s.files = gem_files
22
- s.test_files = gem_files.grep(%r{^test/(.+?/)*test_.+?\.rb$})
23
- s.executables = Dir['bin/*'].map{ |f| File.basename(f) }
24
- s.require_paths = %w[lib]
25
- })
26
- spec.homepage ||= "https://github.com/godfat/#{spec.name}"
27
- spec
31
+ s.date = Time.now.strftime('%Y-%m-%d')
32
+ s.files = gem_files
33
+ s.test_files = test_files
34
+ s.executables = bin_files
35
+ end
36
+ spec_create.call(spec)
37
+ spec.homepage = "https://github.com/godfat/#{spec.name}"
38
+ self.spec = spec
28
39
  end
29
40
 
30
- def readme
31
- path = %w[README.md README].find{ |name|
32
- File.exist?("#{Gemgem.dir}/#{name}")
33
- }
34
- @readme ||=
35
- if path
36
- ps = "##{File.read(path)}".
37
- scan(/((#+)[^\n]+\n\n.+?(?=(\n\n\2[^#\n]+\n)|\Z))/m).map(&:first)
38
- ps.inject('HEADER' => ps.first){ |r, s, i|
39
- r[s[/\w+/]] = s
40
- r
41
- }
41
+ def write
42
+ File.open(spec_path, 'w'){ |f| f << split_lines(spec.to_ruby) }
43
+ end
44
+
45
+ def split_lines ruby
46
+ ruby.gsub(/(.+?)\s*=\s*\[(.+?)\]/){ |s|
47
+ if $2.index(',')
48
+ "#{$1} = [\n #{$2.split(',').map(&:strip).join(",\n ")}]"
42
49
  else
43
- {}
50
+ s
44
51
  end
52
+ }
45
53
  end
46
54
 
47
- def description
48
- @description ||= (readme['DESCRIPTION']||'').sub(/.+\n\n/, '').lines
55
+ def strip_path path
56
+ strip_home_path(strip_cwd_path(path))
49
57
  end
50
58
 
51
- def changes
52
- path = %w[CHANGES.md CHANGES].find{ |name|
53
- File.exist?("#{Gemgem.dir}/#{name}")
54
- }
55
- @changes ||=
56
- if path
57
- date = '\d+{4}\-\d+{2}\-\d{2}'
58
- File.read(path).match(
59
- /([^\n]+#{date}\n\n(.+?))(?=\n\n[^\n]+#{date}\n|\Z)/m)[1]
60
- else
61
- ''
62
- end
59
+ def strip_home_path path
60
+ path.sub(ENV['HOME'], '~')
63
61
  end
64
62
 
65
- def ann_md
66
- "#{readme['HEADER'].sub(/([\w\-]+)/, "[\\1](#{spec.homepage})")}\n\n" \
67
- "##{readme['DESCRIPTION'][/[^\n]+\n\n[^\n]+/]}\n\n" \
68
- "### CHANGES:\n\n" \
69
- "###{changes}\n\n" \
70
- "##{readme['INSTALLATION']}\n\n" +
71
- if readme['SYNOPSIS'] then "##{readme['SYNOPSIS'][/[^\n]+\n\n[^\n]+/]}"
72
- else '' end
63
+ def strip_cwd_path path
64
+ path.sub(Dir.pwd, '.')
73
65
  end
74
66
 
75
- def ann_html
76
- gem 'nokogiri'
77
- gem 'kramdown'
78
-
79
- IO.popen('kramdown', 'r+') do |md|
80
- md.puts Gemgem.ann_md
81
- md.close_write
82
- require 'nokogiri'
83
- html = Nokogiri::XML.parse("<gemgem>#{md.read}</gemgem>")
84
- html.css('*').each{ |n| n.delete('id') }
85
- html.root.children.to_html
86
- end
67
+ def git *args
68
+ `git --git-dir=#{dir}/.git #{args.join(' ')}`
87
69
  end
88
70
 
89
- def ann_email
90
- "#{readme['HEADER'].sub(/([\w\-]+)/, "\\1 <#{spec.homepage}>")}\n\n" \
91
- "#{readme['DESCRIPTION']}\n\n" \
92
- "#{readme['INSTALLATION']}\n\n" +
93
- if readme['SYNOPSIS'] then "##{readme['SYNOPSIS']}\n\n" else '' end +
94
- "## CHANGES:\n\n" \
95
- "##{changes}\n\n"
71
+ def sh_git *args
72
+ Rake.sh('git', "--git-dir=#{dir}/.git", *args)
96
73
  end
97
74
 
98
- def gem_tag
99
- "#{spec.name}-#{spec.version}"
75
+ def sh_gem *args
76
+ Rake.sh(Gem.ruby, '-S', 'gem', *args)
100
77
  end
101
78
 
102
- def write
103
- File.open("#{dir}/#{spec.name}.gemspec", 'w'){ |f|
104
- f << split_lines(spec.to_ruby) }
79
+ def glob path=dir
80
+ Dir.glob("#{path}/**/*", File::FNM_DOTMATCH)
105
81
  end
106
82
 
107
- def split_lines ruby
108
- ruby.gsub(/(.+?)\s*=\s*\[(.+?)\]/){ |s|
109
- if $2.index(',')
110
- "#{$1} = [\n #{$2.split(',').map(&:strip).join(",\n ")}]"
83
+ def readme
84
+ @readme ||=
85
+ if (path = "#{Gemgem.dir}/README.md") && File.exist?(path)
86
+ ps = "##{File.read(path)}".
87
+ scan(/((#+)[^\n]+\n\n.+?(?=(\n\n\2[^#\n]+\n)|\Z))/m).map(&:first)
88
+ ps.inject('HEADER' => ps.first){ |r, s, i|
89
+ r[s[/\w+/]] = s
90
+ r
91
+ }
111
92
  else
112
- s
93
+ {}
113
94
  end
114
- }
95
+ end
96
+
97
+ def description
98
+ # JRuby String#lines is returning an enumerator
99
+ @description ||= (readme['DESCRIPTION']||'').sub(/.+\n\n/, '').lines.to_a
115
100
  end
116
101
 
117
102
  def all_files
118
- @all_files ||= find_files(Pathname.new(dir)).map{ |file|
119
- if file.to_s =~ %r{\.git/|\.git$}
120
- nil
103
+ @all_files ||= fold_files(glob).sort
104
+ end
105
+
106
+ def fold_files files
107
+ files.inject([]){ |r, path|
108
+ if File.file?(path) && path !~ %r{/\.git(/|$)} &&
109
+ (rpath = path[%r{^#{escaped_dir}/(.*$)}, 1])
110
+ r << rpath
111
+ elsif File.symlink?(path) # walk into symlinks...
112
+ r.concat(fold_files(glob(File.expand_path(path,
113
+ File.readlink(path)))))
121
114
  else
122
- file.to_s
115
+ r
123
116
  end
124
- }.compact.sort
117
+ }
125
118
  end
126
119
 
127
120
  def gem_files
128
- @gem_files ||= all_files - ignored_files
121
+ @gem_files ||= all_files.reject{ |f|
122
+ f =~ ignored_pattern && !git_files.include?(f)
123
+ }
129
124
  end
130
125
 
131
- def ignored_files
132
- @ignored_file ||= all_files.select{ |path| ignore_patterns.find{ |ignore|
133
- path =~ ignore && !git_files.include?(path)}}
126
+ def test_files
127
+ @test_files ||= gem_files.grep(%r{^test/(.+?/)*test_.+?\.rb$})
128
+ end
129
+
130
+ def bin_files
131
+ @bin_files ||= gem_files.grep(%r{^bin/}).map{ |f| File.basename(f) }
134
132
  end
135
133
 
136
134
  def git_files
137
135
  @git_files ||= if File.exist?("#{dir}/.git")
138
- `git ls-files`.split("\n")
136
+ git('ls-files').split("\n")
139
137
  else
140
138
  []
141
139
  end
142
140
  end
143
141
 
144
- # protected
145
- def find_files path
146
- path.children.select(&:file?).map{|file| file.to_s[(dir.size+1)..-1]} +
147
- path.children.select(&:directory?).map{|dir| find_files(dir)}.flatten
142
+ def ignored_files
143
+ @ignored_files ||= all_files.grep(ignored_pattern)
148
144
  end
149
145
 
150
- def ignore_patterns
151
- @ignore_files ||= expand_patterns(
152
- gitignore.split("\n").reject{ |pattern|
153
- pattern.strip == ''
154
- }).map{ |pattern| %r{^([^/]+/)*?#{Regexp.escape(pattern)}(/[^/]+)*?$} }
146
+ def ignored_pattern
147
+ @ignored_pattern ||= if gitignore.empty?
148
+ /^$/
149
+ else
150
+ Regexp.new(expand_patterns(gitignore).join('|'))
151
+ end
155
152
  end
156
153
 
157
154
  def expand_patterns pathes
158
- pathes.map{ |path|
159
- if path !~ /\*/
160
- path
161
- else
162
- expand_patterns(
163
- Dir[path] +
164
- Pathname.new(File.dirname(path)).children.select(&:directory?).
165
- map{ |prefix| "#{prefix}/#{File.basename(path)}" })
166
- end
167
- }.flatten
155
+ # http://git-scm.com/docs/gitignore
156
+ pathes.flat_map{ |path|
157
+ # we didn't implement negative pattern for now
158
+ Regexp.escape(path).sub(%r{^/}, '^').gsub(/\\\*/, '[^/]*')
159
+ }
168
160
  end
169
161
 
170
162
  def gitignore
171
- if File.exist?(path = "#{dir}/.gitignore")
172
- File.read(path)
173
- else
174
- ''
175
- end
163
+ @gitignore ||= if File.exist?(path = "#{dir}/.gitignore")
164
+ File.read(path).lines.
165
+ reject{ |l| l == /^\s*(#|\s+$)/ }.map(&:strip)
166
+ else
167
+ []
168
+ end
176
169
  end
177
170
  end
178
171
 
@@ -180,22 +173,37 @@ namespace :gem do
180
173
 
181
174
  desc 'Install gem'
182
175
  task :install => [:build] do
183
- sh("#{Gem.ruby} -S gem install pkg/#{Gemgem.gem_tag}.gem")
176
+ Gemgem.sh_gem('install', Gemgem.gem_path)
184
177
  end
185
178
 
186
179
  desc 'Build gem'
187
180
  task :build => [:spec] do
188
- sh("#{Gem.ruby} -S gem build #{Gemgem.spec.name}.gemspec")
189
- sh("mkdir -p pkg")
190
- sh("mv #{Gemgem.gem_tag}.gem pkg/")
181
+ require 'fileutils'
182
+ require 'rubygems/package'
183
+ gem = nil
184
+ Dir.chdir(Gemgem.dir) do
185
+ gem = Gem::Package.build(Gem::Specification.load(Gemgem.spec_path))
186
+ FileUtils.mkdir_p(Gemgem.pkg_dir)
187
+ FileUtils.mv(gem, Gemgem.pkg_dir) # gem is relative path, but might be ok
188
+ end
189
+ puts "\e[35mGem built: \e[33m" \
190
+ "#{Gemgem.strip_path("#{Gemgem.pkg_dir}/#{gem}")}\e[0m"
191
+ end
192
+
193
+ desc 'Generate gemspec'
194
+ task :spec do
195
+ Gemgem.create
196
+ Gemgem.write
191
197
  end
192
198
 
193
199
  desc 'Release gem'
194
200
  task :release => [:spec, :check, :build] do
195
- sh("git tag #{Gemgem.gem_tag}")
196
- sh("git push")
197
- sh("git push --tags")
198
- sh("#{Gem.ruby} -S gem push pkg/#{Gemgem.gem_tag}.gem")
201
+ Gemgem.module_eval do
202
+ sh_git('tag', Gemgem.gem_tag)
203
+ sh_git('push')
204
+ sh_git('push', '--tags')
205
+ sh_gem('push', Gemgem.gem_path)
206
+ end
199
207
  end
200
208
 
201
209
  task :check do
@@ -216,53 +224,39 @@ end
216
224
 
217
225
  end # of gem namespace
218
226
 
219
- desc 'Run tests in memory'
227
+ desc 'Run tests'
220
228
  task :test do
229
+ next if Gemgem.test_files.empty?
230
+
221
231
  require 'bacon'
222
232
  Bacon.extend(Bacon::TestUnitOutput)
223
233
  Bacon.summary_on_exit
224
- $LOAD_PATH.unshift('lib')
225
- Dir['./test/**/test_*.rb'].each{ |file| require file[0..-4] }
234
+ Gemgem.test_files.each{ |file| require "#{Gemgem.dir}/#{file[0..-4]}" }
226
235
  end
227
236
 
228
- desc 'Run tests with shell'
229
- task 'test:shell', :RUBY_OPTS do |t, args|
230
- files = Dir['test/**/test_*.rb'].join(' ')
231
-
232
- cmd = [Gem.ruby, args[:RUBY_OPTS],
233
- '-I', 'lib', '-S', 'bacon', '--quiet', files]
234
-
235
- sh(cmd.compact.join(' '))
236
- end
237
+ desc 'Trash ignored files'
238
+ task :clean => ['gem:spec'] do
239
+ next if Gemgem.ignored_files.empty?
237
240
 
238
- desc 'Generate ann markdown'
239
- task 'ann:md' => ['gem:spec'] do
240
- puts Gemgem.ann_md
241
- end
241
+ require 'fileutils'
242
+ trash = File.expand_path("~/.Trash/#{Gemgem.spec.name}")
243
+ puts "Move the following files into:" \
244
+ " \e[35m#{Gemgem.strip_path(trash)}\e[33m"
242
245
 
243
- desc 'Generate ann html'
244
- task 'ann:html' => ['gem:spec'] do
245
- puts Gemgem.ann_html
246
- end
246
+ Gemgem.ignored_files.each do |file|
247
+ from = "#{Gemgem.dir}/#{file}"
248
+ to = "#{trash}/#{File.dirname(file)}"
249
+ puts Gemgem.strip_path(from)
247
250
 
248
- desc 'Generate ann email'
249
- task 'ann:email' => ['gem:spec'] do
250
- puts Gemgem.ann_email
251
- end
252
-
253
- desc 'Generate rdoc'
254
- task :doc => ['gem:spec'] do
255
- sh("yardoc -o rdoc --main README.md" \
256
- " --files #{Gemgem.spec.extra_rdoc_files.join(',')}")
257
- end
251
+ FileUtils.mkdir_p(to)
252
+ FileUtils.mv(from, to)
253
+ end
258
254
 
259
- desc 'Remove ignored files'
260
- task :clean => ['gem:spec'] do
261
- trash = "~/.Trash/#{Gemgem.spec.name}/"
262
- sh "mkdir -p #{trash}" unless File.exist?(File.expand_path(trash))
263
- Gemgem.ignored_files.each{ |file| sh "mv #{file} #{trash}" }
255
+ print "\e[0m"
264
256
  end
265
257
 
266
258
  task :default do
267
- puts `#{Gem.ruby} -S #{$PROGRAM_NAME} -T`
259
+ # Is there a reliable way to do this in the current process?
260
+ # It failed miserably before between Rake versions...
261
+ exec "#{Gem.ruby} -S #{$PROGRAM_NAME} -f #{Rake.application.rakefile} -T"
268
262
  end
@@ -2,8 +2,8 @@
2
2
  require 'rest-core/test'
3
3
 
4
4
  describe RC::Builder do
5
- should 'default app is RestCore::Auto' do
6
- RC::Builder.client.new.app.class.should.eq RC::Auto
5
+ should 'default app is a kind of RestCore::Dry' do
6
+ RC::Builder.client.new.app.should.kind_of RC::Engine
7
7
  end
8
8
 
9
9
  should 'switch default_engine to RestCore::Dry' do
@@ -4,7 +4,7 @@ require 'rest-core/test'
4
4
  describe RC::Cache do
5
5
  after do
6
6
  WebMock.reset!
7
- RR.verify
7
+ Muack.verify
8
8
  end
9
9
 
10
10
  should 'basic 0' do
@@ -102,8 +102,8 @@ describe RC::Cache do
102
102
  use RC::JsonResponse, true
103
103
  end
104
104
  end.new
105
- stub_request(:get, 'me').to_return(:body => body = '{"a":"b"}')
106
- c.get('me').should.eq 'a' => 'b'
105
+ stub_request(:get, 'http://me').to_return(:body => body = '{"a":"b"}')
106
+ c.get('http://me').should.eq 'a' => 'b'
107
107
  c.cache.values.first.should.eq "200\n\n\n#{body}"
108
108
  end
109
109
 
@@ -111,10 +111,10 @@ describe RC::Cache do
111
111
  c = RC::Builder.client do
112
112
  use RC::Cache, {}, 3600
113
113
  end.new
114
- stub_request(:get, 'html').to_return(:body => body = "a\n\nb")
115
- c.get('html').should.eq body
114
+ stub_request(:get, 'http://html').to_return(:body => body = "a\n\nb")
115
+ c.get('http://html').should.eq body
116
116
  c.cache.values.first.should.eq "200\n\n\n#{body}"
117
- c.get('html') .should.eq body
117
+ c.get('http://html').should.eq body
118
118
  end
119
119
 
120
120
  should "follow redirect with cache.update correctly" do
@@ -174,8 +174,8 @@ describe RC::Cache do
174
174
  @url, @body = "https://cache", 'ok'
175
175
  stub_request(:get, @url).to_return(:body => @body)
176
176
  @cache = {}
177
- mock(@cache).method(:store){ mock!.arity{ -3 } }
178
- mock(@cache).store(is_a(String), is_a(String), :expires_in => 3)
177
+ mock(@cache).method(:store){ mock.arity{ -3 }.object }
178
+ mock(@cache).store(is_a(String), is_a(String), :expires_in => 3){}
179
179
  @cache
180
180
  end
181
181