streamly_ffi 0.1.5
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +5 -0
- data/.rspec +1 -0
- data/CHANGELOG.md +18 -0
- data/MIT-LICENSE +20 -0
- data/README.rdoc +115 -0
- data/Rakefile +43 -0
- data/VERSION.yml +5 -0
- data/benchmark/basic_request.rb +34 -0
- data/benchmark/streaming_json_request.rb +43 -0
- data/examples/basic/delete.rb +9 -0
- data/examples/basic/get.rb +9 -0
- data/examples/basic/head.rb +9 -0
- data/examples/basic/post.rb +11 -0
- data/examples/basic/put.rb +11 -0
- data/examples/streaming/delete.rb +13 -0
- data/examples/streaming/get.rb +13 -0
- data/examples/streaming/head.rb +13 -0
- data/examples/streaming/post.rb +15 -0
- data/examples/streaming/put.rb +16 -0
- data/ext/extconf.rb +28 -0
- data/ext/streamly.c +427 -0
- data/ext/streamly.h +66 -0
- data/lib/streamly_ffi.rb +122 -0
- data/lib/streamly_ffi/request.rb +163 -0
- data/lib/streamly_ffi/version.rb +3 -0
- data/spec/server.rb +18 -0
- data/spec/spec_helper.rb +7 -0
- data/spec/streamly_ffi/request_spec.rb +293 -0
- data/streamly_ffi.gemspec +41 -0
- metadata +96 -0
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--colour
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
# Changelog
|
2
|
+
|
3
|
+
## 0.1.4 (September 2nd, 2010)
|
4
|
+
* Streamly now respects Encoding.default_internal on 1.9
|
5
|
+
* fixed a random segfault when applying a NULL auth field
|
6
|
+
* take advantage of rb_thread_blocking_region on 1.9 and emulate it's behavior on 1.8 for Ruby-aware thread-saftey
|
7
|
+
|
8
|
+
## 0.1.3 (August 19th, 2009)
|
9
|
+
* Fixed a bug where a username or password was specified, but not both
|
10
|
+
|
11
|
+
## 0.1.2 (July 28th, 2009)
|
12
|
+
* removing call to set CURLOPT_USERPWD to NULL as it would crash in linux
|
13
|
+
|
14
|
+
## 0.1.1 (July 27th, 2009)
|
15
|
+
* Version bump for Github's gem builder
|
16
|
+
|
17
|
+
## 0.1.0 (July 27th, 2009)
|
18
|
+
* Initial release
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2008-2009 Brian Lopez - http://github.com/brianmario
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,115 @@
|
|
1
|
+
= A streaming REST client for Ruby that uses libcurl
|
2
|
+
|
3
|
+
== Features
|
4
|
+
* rest-client like API
|
5
|
+
* Streaming API allows the caller to be handed chunks of the response while it's being received
|
6
|
+
* uses Encoding.default_internal (otherwise falls back to utf-8) for strings it hands back in 1.9
|
7
|
+
|
8
|
+
== How to install
|
9
|
+
|
10
|
+
Nothing special about it, just:
|
11
|
+
|
12
|
+
sudo gem install streamly
|
13
|
+
|
14
|
+
== Example of use
|
15
|
+
|
16
|
+
=== A basic HEAD request
|
17
|
+
|
18
|
+
Streamly.head 'www.somehost.com'
|
19
|
+
|
20
|
+
Or streaming
|
21
|
+
|
22
|
+
Streamly.head 'www.somehost.com' do |header_chunk|
|
23
|
+
# do something with header_chunk
|
24
|
+
end
|
25
|
+
|
26
|
+
You can also pass a Hash of headers
|
27
|
+
|
28
|
+
Streamly.head 'www.somehost.com', {"User-Agent" => "Your Mom"}
|
29
|
+
|
30
|
+
=== A basic GET request
|
31
|
+
|
32
|
+
Streamly.get 'www.somehost.com'
|
33
|
+
|
34
|
+
Or streaming
|
35
|
+
|
36
|
+
Streamly.get 'www.somehost.com' do |body_chunk|
|
37
|
+
# do something with body_chunk
|
38
|
+
end
|
39
|
+
|
40
|
+
You can also pass a Hash of headers
|
41
|
+
|
42
|
+
Streamly.get 'www.somehost.com', {"User-Agent" => "Your Mom"}
|
43
|
+
|
44
|
+
=== A basic POST request
|
45
|
+
|
46
|
+
Streamly.post 'www.somehost.com', 'blah=foo'
|
47
|
+
|
48
|
+
Or streaming
|
49
|
+
|
50
|
+
Streamly.post 'www.somehost.com', 'blah=foo' do |body_chunk|
|
51
|
+
# do something with body_chunk
|
52
|
+
end
|
53
|
+
|
54
|
+
You can also pass a Hash of headers
|
55
|
+
|
56
|
+
Streamly.post 'www.somehost.com', 'blah=foo', {"User-Agent" => "Your Mom"}
|
57
|
+
|
58
|
+
=== A basic PUT request
|
59
|
+
|
60
|
+
Streamly.put 'www.somehost.com', 'blah=foo'
|
61
|
+
|
62
|
+
Or streaming
|
63
|
+
|
64
|
+
Streamly.put 'www.somehost.com', 'blah=foo' do |body_chunk|
|
65
|
+
# do something with body_chunk
|
66
|
+
end
|
67
|
+
|
68
|
+
You can also pass a Hash of headers
|
69
|
+
|
70
|
+
Streamly.put 'www.somehost.com', 'blah=foo', {"User-Agent" => "Your Mom"}
|
71
|
+
|
72
|
+
=== A basic DELETE request
|
73
|
+
|
74
|
+
Streamly.delete 'www.somehost.com'
|
75
|
+
|
76
|
+
Or streaming
|
77
|
+
|
78
|
+
Streamly.delete 'www.somehost.com' do |body_chunk|
|
79
|
+
# do something with body_chunk
|
80
|
+
end
|
81
|
+
|
82
|
+
You can also pass a Hash of headers
|
83
|
+
|
84
|
+
Streamly.delete 'www.somehost.com', {"User-Agent" => "Your Mom"}
|
85
|
+
|
86
|
+
== Benchmarks
|
87
|
+
|
88
|
+
Fetching 2,405,005 bytes of JSON from a local lighttpd server
|
89
|
+
|
90
|
+
* Streamly: 0.011s
|
91
|
+
* Shell out to curl: 0.046s
|
92
|
+
* rest-client: 0.205s
|
93
|
+
|
94
|
+
Streaming, and parsing 2,405,005 bytes of JSON from a local lighttpd server
|
95
|
+
|
96
|
+
* Streamly: 0.231s
|
97
|
+
* Shell out to curl: 0.341s
|
98
|
+
* rest-client: 0.447s
|
99
|
+
|
100
|
+
== Other Notes
|
101
|
+
|
102
|
+
This library was basically an exercise in dealing with libcurl in C.
|
103
|
+
|
104
|
+
== Special Thanks
|
105
|
+
|
106
|
+
There are quite a few *extremely* nice REST client libraries out there for Ruby today. I especially owe thanks
|
107
|
+
to the following projects. Without them I probably would have never had the inspiration to even take the time
|
108
|
+
to write this library. In Streamly, you'll find snippets of code, API patterns and examples from all 3 of these projects.
|
109
|
+
I'll do my best to make sure I give credit where it's due *in* the source. Please let me know if I've missed something!
|
110
|
+
|
111
|
+
* rest-client - https://github.com/adamwiggins/rest-client
|
112
|
+
* curb - https://github.com/taf2/curb
|
113
|
+
* patron - https://github.com/toland/patron
|
114
|
+
|
115
|
+
And again, the Github crew for this amazing service!
|
data/Rakefile
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
require 'rake/gempackagetask'
|
4
|
+
|
5
|
+
gemspec = eval File.read('streamly_ffi.gemspec')
|
6
|
+
|
7
|
+
# Gem packaging tasks
|
8
|
+
Rake::GemPackageTask.new(gemspec) do |pkg|
|
9
|
+
pkg.need_zip = false
|
10
|
+
pkg.need_tar = false
|
11
|
+
end
|
12
|
+
|
13
|
+
task :gem => :gemspec
|
14
|
+
|
15
|
+
desc %{Build the gemspec file.}
|
16
|
+
task :gemspec do
|
17
|
+
gemspec.validate
|
18
|
+
end
|
19
|
+
|
20
|
+
desc %{Release the gem to RubyGems.org}
|
21
|
+
task :release => :gem do
|
22
|
+
system "gem push pkg/#{gemspec.name}-#{gemspec.version}.gem"
|
23
|
+
end
|
24
|
+
|
25
|
+
require 'rspec/core'
|
26
|
+
require 'rspec/core/rake_task'
|
27
|
+
|
28
|
+
desc "Run all examples with RCov"
|
29
|
+
Rspec::Core::RakeTask.new('spec:rcov') do |t|
|
30
|
+
#Spec::Rake::SpecTask.new('spec:rcov') do |t|
|
31
|
+
t.pattern = "spec/requests/**/*_spec.rb"
|
32
|
+
t.rcov = true
|
33
|
+
t.rcov_opts = lambda do
|
34
|
+
IO.readlines("spec/rcov.opts").map {|line|
|
35
|
+
line.chomp.split " "
|
36
|
+
}.flatten
|
37
|
+
end
|
38
|
+
end
|
39
|
+
Rspec::Core::RakeTask.new(:spec) do |t|
|
40
|
+
#Spec::Rake::SpecTask.new('spec') do |t|
|
41
|
+
t.pattern = "spec/streamly_ffi/**/*_spec.rb"
|
42
|
+
# t.opts << '--options' << 'spec/spec.opts'
|
43
|
+
end
|
data/VERSION.yml
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
$LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/..')
|
3
|
+
$LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/../lib')
|
4
|
+
|
5
|
+
require 'rubygems'
|
6
|
+
require 'net/http'
|
7
|
+
require 'rest_client'
|
8
|
+
require 'streamly'
|
9
|
+
require 'benchmark'
|
10
|
+
|
11
|
+
url = ARGV[0]
|
12
|
+
|
13
|
+
Benchmark.bmbm do |x|
|
14
|
+
x.report do
|
15
|
+
puts "Streamly"
|
16
|
+
(ARGV[1] || 1).to_i.times do
|
17
|
+
Streamly.get(url)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
x.report do
|
22
|
+
puts "Shell out to curl"
|
23
|
+
(ARGV[1] || 1).to_i.times do
|
24
|
+
`curl -s --compressed #{url}`
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
x.report do
|
29
|
+
puts "rest-client"
|
30
|
+
(ARGV[1] || 1).to_i.times do
|
31
|
+
RestClient.get(url, {"Accept-Encoding" => "identity, deflate, gzip"})
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
$LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/..')
|
3
|
+
$LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/../lib')
|
4
|
+
|
5
|
+
require 'rubygems'
|
6
|
+
require 'net/http'
|
7
|
+
require 'rest_client'
|
8
|
+
require 'streamly'
|
9
|
+
require 'yajl'
|
10
|
+
require 'benchmark'
|
11
|
+
|
12
|
+
url = ARGV[0]
|
13
|
+
|
14
|
+
Benchmark.bmbm do |x|
|
15
|
+
parser = Yajl::Parser.new
|
16
|
+
parser.on_parse_complete = lambda {|obj| }
|
17
|
+
x.report do
|
18
|
+
puts "Streamly"
|
19
|
+
(ARGV[1] || 1).to_i.times do
|
20
|
+
Streamly.get(url) do |chunk|
|
21
|
+
parser << chunk
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
parser = Yajl::Parser.new
|
27
|
+
parser.on_parse_complete = lambda {|obj| }
|
28
|
+
x.report do
|
29
|
+
puts "Shell out to curl"
|
30
|
+
(ARGV[1] || 1).to_i.times do
|
31
|
+
parser.parse `curl -s --compressed #{url}`
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
parser = Yajl::Parser.new
|
36
|
+
parser.on_parse_complete = lambda {|obj| }
|
37
|
+
x.report do
|
38
|
+
puts "rest-client"
|
39
|
+
(ARGV[1] || 1).to_i.times do
|
40
|
+
parser.parse RestClient.get(url, {"Accept-Encoding" => "identity, deflate, gzip"})
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
$LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/../../lib')
|
3
|
+
|
4
|
+
require 'streamly'
|
5
|
+
|
6
|
+
raise Exception, "You must pass a URL to request" if ARGV[0].nil?
|
7
|
+
raise Exception, "You must pass a payload to POST" if ARGV[1].nil?
|
8
|
+
|
9
|
+
url = ARGV[0]
|
10
|
+
payload = ARGV[1]
|
11
|
+
puts Streamly.post(url, payload)
|
@@ -0,0 +1,11 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
$LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/../../lib')
|
3
|
+
|
4
|
+
require 'streamly'
|
5
|
+
|
6
|
+
raise Exception, "You must pass a URL to request" if ARGV[0].nil?
|
7
|
+
raise Exception, "You must pass a payload to PUT" if ARGV[1].nil?
|
8
|
+
|
9
|
+
url = ARGV[0]
|
10
|
+
payload = ARGV[1]
|
11
|
+
puts Streamly.put(url, payload)
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
$LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/../../lib')
|
3
|
+
|
4
|
+
require 'streamly'
|
5
|
+
|
6
|
+
raise Exception, "You must pass a URL to request" if ARGV[0].nil?
|
7
|
+
|
8
|
+
url = ARGV[0]
|
9
|
+
Streamly.delete(url) do |chunk|
|
10
|
+
STDOUT.write chunk
|
11
|
+
STDOUT.flush
|
12
|
+
end
|
13
|
+
puts
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
$LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/../../lib')
|
3
|
+
|
4
|
+
require 'streamly'
|
5
|
+
|
6
|
+
raise Exception, "You must pass a URL to request" if ARGV[0].nil?
|
7
|
+
|
8
|
+
url = ARGV[0]
|
9
|
+
Streamly.get(url) do |chunk|
|
10
|
+
STDOUT.write chunk
|
11
|
+
STDOUT.flush
|
12
|
+
end
|
13
|
+
puts
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
$LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/../../lib')
|
3
|
+
|
4
|
+
require 'streamly'
|
5
|
+
|
6
|
+
raise Exception, "You must pass a URL to request" if ARGV[0].nil?
|
7
|
+
|
8
|
+
url = ARGV[0]
|
9
|
+
Streamly.head(url) do |chunk|
|
10
|
+
STDOUT.write chunk
|
11
|
+
STDOUT.flush
|
12
|
+
end
|
13
|
+
puts
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
$LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/../../lib')
|
3
|
+
|
4
|
+
require 'streamly'
|
5
|
+
|
6
|
+
raise Exception, "You must pass a URL to request" if ARGV[0].nil?
|
7
|
+
raise Exception, "You must pass a payload to POST" if ARGV[1].nil?
|
8
|
+
|
9
|
+
url = ARGV[0]
|
10
|
+
payload = ARGV[1]
|
11
|
+
Streamly.post(url, payload) do |chunk|
|
12
|
+
STDOUT.write chunk
|
13
|
+
STDOUT.flush
|
14
|
+
end
|
15
|
+
puts
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
$LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/../../lib')
|
3
|
+
|
4
|
+
require 'streamly'
|
5
|
+
|
6
|
+
raise Exception, "You must pass a URL to request" if ARGV[0].nil?
|
7
|
+
raise Exception, "You must pass a payload to PUT" if ARGV[1].nil?
|
8
|
+
|
9
|
+
url = ARGV[0]
|
10
|
+
payload = ARGV[1]
|
11
|
+
resp = ''
|
12
|
+
Streamly.put(url, payload) do |chunk|
|
13
|
+
STDOUT.write chunk
|
14
|
+
STDOUT.flush
|
15
|
+
end
|
16
|
+
puts
|
data/ext/extconf.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
require 'mkmf'
|
3
|
+
require 'rbconfig'
|
4
|
+
|
5
|
+
# 1.9-only
|
6
|
+
have_func('rb_thread_blocking_region')
|
7
|
+
|
8
|
+
$CFLAGS << ' -DHAVE_RBTRAP' if have_var('rb_trap_immediate', ['ruby.h', 'rubysig.h'])
|
9
|
+
# add_define 'HAVE_RBTRAP' if have_var('rb_trap_immediate', ['ruby.h', 'rubysig.h'])
|
10
|
+
|
11
|
+
# Borrowed from taf2-curb
|
12
|
+
dir_config('curl')
|
13
|
+
if find_executable('curl-config')
|
14
|
+
$CFLAGS << " #{`curl-config --cflags`.strip}"
|
15
|
+
$LIBS << " #{`curl-config --libs`.strip}"
|
16
|
+
elsif !have_library('curl') or !have_header('curl/curl.h')
|
17
|
+
fail <<-EOM
|
18
|
+
Can't find libcurl or curl/curl.h
|
19
|
+
|
20
|
+
Try passing --with-curl-dir or --with-curl-lib and --with-curl-include
|
21
|
+
options to extconf.
|
22
|
+
EOM
|
23
|
+
end
|
24
|
+
|
25
|
+
$CFLAGS << ' -Wall -Wextra -funroll-loops'
|
26
|
+
# $CFLAGS << ' -O0 -ggdb'
|
27
|
+
|
28
|
+
create_makefile("streamly_ext")
|