curl_ffi 0.0.2

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.
@@ -0,0 +1,86 @@
1
+ require "curl_ffi"
2
+
3
+ module CurlFFI
4
+ class Easy
5
+ attr_reader :pointer
6
+
7
+ def initialize
8
+ @pointer = FFI::AutoPointer.new(CurlFFI.easy_init, CurlFFI.method(:easy_cleanup))
9
+ end
10
+
11
+ def reset
12
+ CurlFFI.easy_reset(@pointer)
13
+ end
14
+
15
+ def initialize_copy(other)
16
+ @pointer = FFI::AutoPointer.new(CurlFFI.easy_duphandle(other.pointer), CurlFFI.method(:easy_cleanup))
17
+ end
18
+
19
+ def escape(string)
20
+ str_pointer = CurlFFI.easy_escape(@pointer, string, string.length)
21
+ result = str_pointer.null? ? nil : str_pointer.read_string
22
+ CurlFFI.free(str_pointer)
23
+ result
24
+ end
25
+
26
+ def unescape(string)
27
+ int_pointer = FFI::MemoryPointer.new(:int)
28
+ str_pointer = CurlFFI.easy_unescape(@pointer, string, string.length, int_pointer)
29
+ result = str_pointer.read_string(int_pointer.read_int)
30
+ CurlFFI.free(str_pointer)
31
+ result
32
+ end
33
+
34
+ def error_string(error_code)
35
+ CurlFFI.easy_strerror(error_code)
36
+ end
37
+
38
+ def perform
39
+ check_code(CurlFFI.easy_perform(@pointer))
40
+ end
41
+
42
+ def setopt(option, value)
43
+ check_code(CurlFFI.easy_setopt(@pointer, option, value))
44
+ end
45
+
46
+ def getinfo(info)
47
+ info = INFO[info] if info.is_a?(Symbol)
48
+
49
+ if info > CurlFFI::INFO_SLIST
50
+ raise "Not implemented yet"
51
+ elsif info > CurlFFI::INFO_DOUBLE
52
+ getinfo_double(info)
53
+ elsif info > CurlFFI::INFO_LONG
54
+ getinfo_long(info)
55
+ elsif info > CurlFFI::INFO_STRING
56
+ getinfo_string(info)
57
+ end
58
+ end
59
+
60
+ protected
61
+ def check_code(result)
62
+ if result != :OK
63
+ raise "Error - #{result}"
64
+ end
65
+ end
66
+
67
+ def getinfo_double(info)
68
+ double_ptr = FFI::MemoryPointer.new(:double)
69
+ check_code(CurlFFI.easy_getinfo(@pointer, info, double_ptr))
70
+ double_ptr.read_double
71
+ end
72
+
73
+ def getinfo_string(info)
74
+ pointer = FFI::MemoryPointer.new(:pointer)
75
+ check_code(CurlFFI.easy_getinfo(@pointer, info, pointer))
76
+ string_ptr = pointer.read_pointer
77
+ string_ptr.null? ? nil : string_ptr.read_string
78
+ end
79
+
80
+ def getinfo_long(info)
81
+ long_ptr = FFI::MemoryPointer.new(:long)
82
+ check_code(CurlFFI.easy_getinfo(@pointer, info, long_ptr))
83
+ long_ptr.read_long
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,66 @@
1
+ require "curl_ffi"
2
+
3
+ module CurlFFI
4
+ class Multi
5
+ attr_reader :pointer, :running
6
+
7
+ def initialize
8
+ @pointer = FFI::AutoPointer.new(CurlFFI.multi_init, CurlFFI.method(:multi_cleanup))
9
+ @running = -1
10
+ @handles = []
11
+ @messages_in_queue = 0
12
+ end
13
+
14
+ # @todo handle return code
15
+ def add_handle(easy)
16
+ CurlFFI.multi_add_handle(@pointer, easy.pointer)
17
+ @handles << easy # Save the handle so it won't be gc'ed
18
+ end
19
+
20
+ # @todo handle return code
21
+ def remove_handle(easy)
22
+ CurlFFI.multi_remove_handle(@pointer, easy.pointer)
23
+ @handles.delete(easy) # Save the handle so it won't be gc'ed
24
+ end
25
+
26
+ def setopt(option, param)
27
+ CurlFFI.multi_setopt(@pointer, option, param)
28
+ end
29
+
30
+ def info_read_all()
31
+ messages = []
32
+ while message = info_read_next
33
+ messages << message
34
+ end
35
+ messages
36
+ end
37
+
38
+ def info_read_next()
39
+ int_pointer = FFI::MemoryPointer.new(:int)
40
+ message_pointer = CurlFFI.multi_info_read(@pointer, int_pointer)
41
+ @messages_in_queue = int_pointer.read_int
42
+ message_pointer.null? ? nil : CurlFFI::Message.new(message_pointer)
43
+ end
44
+
45
+ # @todo handle return code
46
+ def socket_action(sockfd, ev_bitmask = 0)
47
+ int_pointer = FFI::MemoryPointer.new(:int)
48
+ result = CurlFFI.multi_socket_action(@pointer, sockfd, ev_bitmask, int_pointer)
49
+ @running = int_pointer.read_int
50
+ result
51
+ end
52
+
53
+ def perform()
54
+ int_pointer = FFI::MemoryPointer.new(:int)
55
+ result = CurlFFI.multi_perform(@pointer, int_pointer)
56
+ @running = int_pointer.read_int
57
+ result
58
+ end
59
+
60
+ def timeout
61
+ long_pointer = FFI::MemoryPointer.new(:long)
62
+ result = CurlFFI.multi_timeout(@pointer, long_pointer)
63
+ long_pointer.read_long
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,3 @@
1
+ module CurlFFI
2
+ VERSION = "0.0.2"
3
+ end
data/lib/curl_ffi.rb ADDED
@@ -0,0 +1,13 @@
1
+ $:.unshift(File.dirname(__FILE__)) unless
2
+ $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
3
+
4
+ require 'ffi'
5
+
6
+ require "curl_ffi/ffi_bindings"
7
+
8
+ module CurlFFI
9
+ extend CurlFFI::CurlBindings
10
+
11
+ autoload :Easy, "curl_ffi/easy"
12
+ autoload :Multi, "curl_ffi/multi"
13
+ end
@@ -0,0 +1,84 @@
1
+ require "spec_helper"
2
+
3
+ module Curl
4
+ describe Easy, ".new" do
5
+ it "should return a new Curl::Easy object" do
6
+ Easy.new.should be_a(Easy)
7
+ end
8
+ end
9
+
10
+ describe Easy do
11
+ before :each do
12
+ @easy = Easy.new
13
+ end
14
+
15
+ describe "#dup" do
16
+ it "should return a new Curl::Easy object" do
17
+ @easy.dup.should be_a(Easy)
18
+ end
19
+
20
+ it "should have a seperate libCurl handle" do
21
+ @easy.dup.pointer.should_not equal(@easy.pointer)
22
+ end
23
+ end
24
+
25
+ describe "#reset" do
26
+ it "should reset all set options" do
27
+ # TODO how would one test that?
28
+ @easy.should respond_to(:reset)
29
+ end
30
+ end
31
+
32
+ describe "#setopt" do
33
+ it "should correctly set string options" do
34
+ @easy.setopt(OPTION[:URL], "http://google.de")
35
+ end
36
+
37
+ it "should correctly set string options" do
38
+ @easy.setopt(OPTION[:PORT], 123)
39
+ end
40
+ end
41
+
42
+ describe "#getinfo" do
43
+ it "should return internal information" do
44
+ @easy.getinfo(INFO[:EFFECTIVE_URL]).should == ""
45
+
46
+ @easy.setopt(OPTION[:URL], "http://google.de")
47
+ @easy.getinfo(INFO[:EFFECTIVE_URL]).should == "http://google.de"
48
+ end
49
+ end
50
+
51
+ describe "#perform" do
52
+ # it "should perform the request" do
53
+ # @easy.setopt(OPTION[:URL], "http://google.de")
54
+ # @easy.perform
55
+ # end
56
+ end
57
+
58
+ describe "#escape" do
59
+ it "should escape the passed string" do
60
+ str = @easy.escape("Hello World!")
61
+ str.should == "Hello%20World%21"
62
+ end
63
+ end
64
+
65
+ describe "#unescape" do
66
+ it "should unescape the passed string" do
67
+ str = @easy.unescape("Hello%20World%21")
68
+ str.should == "Hello World!"
69
+ end
70
+
71
+ it "should correctly unescape strings containing '%00'" do
72
+ str = @easy.unescape("%00Test")
73
+ str.should == "\00Test"
74
+ end
75
+ end
76
+
77
+ describe "#error_string" do
78
+ it "should return a string describing the passed error code" do
79
+ @easy.error_string(:OK).should == "No error"
80
+ @easy.error_string(:UNSUPPORTED_PROTOCOL).should == "Unsupported protocol"
81
+ end
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,81 @@
1
+ require "spec_helper"
2
+
3
+ module Curl
4
+ describe Multi, ".new" do
5
+ it "should return a new Curl::Easy object" do
6
+ Multi.new.should be_a(Multi)
7
+ end
8
+ end
9
+
10
+ describe Multi do
11
+ before :each do
12
+ @multi = Multi.new
13
+ @easy = Easy.new
14
+ @easy.setopt(OPTION[:PROXY], "")
15
+ end
16
+
17
+ describe "#add_handle" do
18
+ it "should add the easy object to this multi objects handles" do
19
+ @multi.add_handle(@easy)
20
+ end
21
+ end
22
+
23
+ describe "#info_read_next" do
24
+ it "should return nil if there are no messages" do
25
+ @multi.info_read_next.should be_nil
26
+ end
27
+
28
+ it "should return Curl::Message objects when messages are available" do
29
+ @easy.setopt(OPTION[:URL], "http://google.de")
30
+ @multi.add_handle(@easy)
31
+
32
+ @multi.perform while @multi.running != 0
33
+ message = @multi.info_read_next
34
+ message.should be_a(Curl::Message)
35
+ message[:msg].should == :DONE
36
+ end
37
+ end
38
+
39
+ describe "#info_read_all" do
40
+ it "should return an empty array if there are no messages" do
41
+ @multi.info_read_all.should == []
42
+ end
43
+
44
+ it "should return an array of Curl::Message objects when messages are available" do
45
+ @easy.setopt(OPTION[:URL], "http://google.de")
46
+ @multi.add_handle(@easy)
47
+
48
+ @multi.perform while @multi.running != 0
49
+ messages = @multi.info_read_all
50
+ messages.size.should == 1
51
+
52
+ messages.first.should be_a(Curl::Message)
53
+ messages.first[:msg].should == :DONE
54
+ end
55
+ end
56
+
57
+ describe "#timeout" do
58
+ it "should return -1 if there is no timer set yet" do
59
+ @multi.timeout.should == -1
60
+ end
61
+
62
+ it "should return the timeout till the next call to #perform" do
63
+ @easy.setopt(OPTION[:URL], "http://google.de")
64
+ @multi.add_handle(@easy)
65
+
66
+ @multi.timeout.should == 1
67
+ @multi.perform
68
+ @multi.timeout.should == 1
69
+ end
70
+ end
71
+
72
+ describe "#perform" do
73
+ before :each do
74
+ @easy.setopt(OPTION[:URL], "http://google.de")
75
+ @multi.add_handle(@easy)
76
+ end
77
+
78
+ it "should perform the request"
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,3 @@
1
+ require "rubygems"
2
+
3
+ require "lib/curl"
metadata ADDED
@@ -0,0 +1,108 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: curl_ffi
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 0
8
+ - 2
9
+ version: 0.0.2
10
+ platform: ruby
11
+ authors:
12
+ - Arthur Schreiber
13
+ - Scott Gonyea
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2010-11-05 00:00:00 -07:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: ffi
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ segments:
30
+ - 0
31
+ version: "0"
32
+ type: :runtime
33
+ version_requirements: *id001
34
+ - !ruby/object:Gem::Dependency
35
+ name: rspec
36
+ prerelease: false
37
+ requirement: &id002 !ruby/object:Gem::Requirement
38
+ none: false
39
+ requirements:
40
+ - - ">="
41
+ - !ruby/object:Gem::Version
42
+ segments:
43
+ - 0
44
+ version: "0"
45
+ type: :development
46
+ version_requirements: *id002
47
+ description: An FFI based libCurl interface, intended to serve as a common backend for existing interfaces to libcurl
48
+ email:
49
+ - schreiber.arthur@gmail.com
50
+ executables: []
51
+
52
+ extensions: []
53
+
54
+ extra_rdoc_files: []
55
+
56
+ files:
57
+ - .gitignore
58
+ - Gemfile
59
+ - curl_ffi.gemspec
60
+ - examples/evented_multi.rb
61
+ - examples/perform_multi.rb
62
+ - examples/select_multi.rb
63
+ - lib/curl_ffi.rb
64
+ - lib/curl_ffi/curl_bindings.rb
65
+ - lib/curl_ffi/easy.rb
66
+ - lib/curl_ffi/multi.rb
67
+ - lib/curl_ffi/version.rb
68
+ - spec/curl/easy_spec.rb
69
+ - spec/curl/multi_spec.rb
70
+ - spec/spec_helper.rb
71
+ has_rdoc: true
72
+ homepage: http://github.com/nokarma/curl-ffi
73
+ licenses: []
74
+
75
+ post_install_message:
76
+ rdoc_options: []
77
+
78
+ require_paths:
79
+ - lib
80
+ required_ruby_version: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ">="
84
+ - !ruby/object:Gem::Version
85
+ segments:
86
+ - 0
87
+ version: "0"
88
+ required_rubygems_version: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ">="
92
+ - !ruby/object:Gem::Version
93
+ segments:
94
+ - 1
95
+ - 3
96
+ - 6
97
+ version: 1.3.6
98
+ requirements: []
99
+
100
+ rubyforge_project: curl-ffi
101
+ rubygems_version: 1.3.7
102
+ signing_key:
103
+ specification_version: 3
104
+ summary: An FFI based libCurl interface
105
+ test_files:
106
+ - spec/curl/easy_spec.rb
107
+ - spec/curl/multi_spec.rb
108
+ - spec/spec_helper.rb