rapuncel 0.0.1 → 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.
- data/README.md +39 -33
- data/{Rakefile.rb → Rakefile} +1 -1
- data/lib/rapuncel.rb +2 -1
- data/lib/rapuncel/adapters/net_http_adapter.rb +6 -6
- data/lib/rapuncel/base.rb +2 -2
- data/lib/rapuncel/client.rb +21 -13
- data/lib/rapuncel/connection.rb +2 -2
- data/lib/rapuncel/core_ext/array.rb +9 -16
- data/lib/rapuncel/core_ext/big_decimal.rb +7 -0
- data/lib/rapuncel/core_ext/boolean.rb +10 -13
- data/lib/rapuncel/core_ext/float.rb +4 -7
- data/lib/rapuncel/core_ext/hash.rb +17 -27
- data/lib/rapuncel/core_ext/integer.rb +2 -10
- data/lib/rapuncel/core_ext/nil.rb +7 -0
- data/lib/rapuncel/core_ext/object.rb +6 -6
- data/lib/rapuncel/core_ext/string.rb +5 -7
- data/lib/rapuncel/core_ext/symbol.rb +2 -3
- data/lib/rapuncel/core_ext/time.rb +5 -8
- data/lib/rapuncel/proxy.rb +39 -14
- data/lib/rapuncel/request.rb +7 -6
- data/lib/rapuncel/response.rb +60 -31
- data/rapuncel.gemspec +2 -3
- data/test/functional/client_test.rb +38 -7
- data/test/functional_test_helper.rb +2 -2
- data/test/test_server.rb +3 -3
- data/test/unit/array_test.rb +14 -14
- data/test/unit/boolean_test.rb +6 -6
- data/test/unit/float_test.rb +7 -7
- data/test/unit/hash_test.rb +16 -16
- data/test/unit/nil_test.rb +16 -0
- data/test/unit/object_test.rb +29 -29
- data/test/unit/proxy_test.rb +9 -9
- data/test/unit/response_test.rb +69 -5
- data/test/unit/string_test.rb +15 -7
- metadata +13 -53
- data/lib/rapuncel/adapters/typhoeus_adapter.rb +0 -33
- data/lib/rapuncel/fault.rb +0 -10
- data/test/coverage/-Users-mariantheisen-Projects-Kayoom-rapuncel-lib-rapuncel-adapters-typhoeus_adapter_rb.html +0 -231
- data/test/coverage/-Users-mariantheisen-Projects-Kayoom-rapuncel-lib-rapuncel-base_rb.html +0 -105
- data/test/coverage/-Users-mariantheisen-Projects-Kayoom-rapuncel-lib-rapuncel-client_rb.html +0 -321
- data/test/coverage/-Users-mariantheisen-Projects-Kayoom-rapuncel-lib-rapuncel-connection_rb.html +0 -513
- data/test/coverage/-Users-mariantheisen-Projects-Kayoom-rapuncel-lib-rapuncel-core_ext-array_rb.html +0 -303
- data/test/coverage/-Users-mariantheisen-Projects-Kayoom-rapuncel-lib-rapuncel-core_ext-boolean_rb.html +0 -255
- data/test/coverage/-Users-mariantheisen-Projects-Kayoom-rapuncel-lib-rapuncel-core_ext-float_rb.html +0 -177
- data/test/coverage/-Users-mariantheisen-Projects-Kayoom-rapuncel-lib-rapuncel-core_ext-hash_rb.html +0 -297
- data/test/coverage/-Users-mariantheisen-Projects-Kayoom-rapuncel-lib-rapuncel-core_ext-integer_rb.html +0 -177
- data/test/coverage/-Users-mariantheisen-Projects-Kayoom-rapuncel-lib-rapuncel-core_ext-object_rb.html +0 -297
- data/test/coverage/-Users-mariantheisen-Projects-Kayoom-rapuncel-lib-rapuncel-core_ext-string_rb.html +0 -159
- data/test/coverage/-Users-mariantheisen-Projects-Kayoom-rapuncel-lib-rapuncel-core_ext-time_rb.html +0 -165
- data/test/coverage/-Users-mariantheisen-Projects-Kayoom-rapuncel-lib-rapuncel-fault_rb.html +0 -93
- data/test/coverage/-Users-mariantheisen-Projects-Kayoom-rapuncel-lib-rapuncel-proxy_rb.html +0 -393
- data/test/coverage/-Users-mariantheisen-Projects-Kayoom-rapuncel-lib-rapuncel-request_rb.html +0 -351
- data/test/coverage/-Users-mariantheisen-Projects-Kayoom-rapuncel-lib-rapuncel-response_rb.html +0 -399
- data/test/coverage/-Users-mariantheisen-Projects-Kayoom-rapuncel-lib-rapuncel_rb.html +0 -201
- data/test/coverage/functional_test_helper_rb.html +0 -141
- data/test/coverage/index.html +0 -410
- data/test/coverage/jquery-1.3.2.min.js +0 -19
- data/test/coverage/jquery.tablesorter.min.js +0 -15
- data/test/coverage/print.css +0 -12
- data/test/coverage/rcov.js +0 -42
- data/test/coverage/screen.css +0 -270
- data/test/coverage/test_helper_rb.html +0 -291
- data/test/coverage/test_server_rb.html +0 -231
@@ -1,19 +1,11 @@
|
|
1
|
-
require 'builder'
|
2
|
-
require 'nokogiri'
|
3
|
-
require 'ruby-debug'
|
4
|
-
|
5
1
|
class Integer
|
6
|
-
|
7
2
|
def to_xml_rpc b = Rapuncel.get_builder
|
8
|
-
#warn "XML-RPC standard only supports 4 byte signed integers, i.e #{(-2**31).to_s} to #{2**31-1}" unless ((-2**31)...(2**31)) === self
|
9
|
-
|
10
3
|
b.int self.to_s
|
11
4
|
|
5
|
+
b.to_xml
|
12
6
|
end
|
13
7
|
|
14
8
|
def self.from_xml_rpc xml_node
|
15
|
-
|
16
|
-
|
17
|
-
xml_node.text.to_i #calling to_i on the text between the i4 or int tags
|
9
|
+
xml_node.text.strip.to_i #calling to_i on the text between the i4 or int tags
|
18
10
|
end
|
19
11
|
end
|
@@ -1,21 +1,21 @@
|
|
1
|
-
require 'builder'
|
2
|
-
|
3
1
|
class Object
|
4
2
|
def to_xml_rpc b = Rapuncel.get_builder
|
5
3
|
if respond_to?(:acts_like?) && acts_like?(:time)
|
6
4
|
to_time.to_xml_rpc b
|
7
|
-
else
|
5
|
+
else
|
8
6
|
_collect_ivars_in_hash.to_xml_rpc b
|
9
7
|
end
|
8
|
+
|
9
|
+
b.to_xml
|
10
10
|
end
|
11
11
|
|
12
12
|
def self.from_xml_rpc xml_node
|
13
13
|
if xml_node.is_a? String
|
14
14
|
xml_node = Nokogiri::XML.parse(xml_node).root
|
15
15
|
end
|
16
|
-
|
16
|
+
|
17
17
|
return nil if xml_node.nil?
|
18
|
-
|
18
|
+
|
19
19
|
case xml_node.name
|
20
20
|
when 'i4', 'int'
|
21
21
|
Integer.from_xml_rpc xml_node
|
@@ -34,7 +34,7 @@ class Object
|
|
34
34
|
when 'base64'
|
35
35
|
raise 'Now its time to implement Base64'
|
36
36
|
else
|
37
|
-
raise "What is this? I didn't know #{xml_node.name} was part of the XMLRPC specification? Anyway, the value was: #{xml_node.text}"
|
37
|
+
raise "What is this? I didn't know #{xml_node.name} was part of the XMLRPC specification? Anyway, the value was: #{xml_node.text.strip}"
|
38
38
|
end
|
39
39
|
end
|
40
40
|
|
@@ -1,14 +1,12 @@
|
|
1
|
-
require 'builder'
|
2
|
-
require 'nokogiri'
|
3
|
-
|
4
1
|
class String
|
5
2
|
def to_xml_rpc b = Rapuncel.get_builder
|
6
3
|
b.string self
|
4
|
+
|
5
|
+
b.to_xml
|
7
6
|
end
|
8
|
-
|
7
|
+
|
9
8
|
def self.from_xml_rpc xml_node
|
10
|
-
|
11
|
-
|
12
|
-
xml_node.text #just give back the string between the 'string' tags
|
9
|
+
xml_node.text.gsub(/(\r\n|\r)/, "\n") #just give back the string between the 'string' tags
|
10
|
+
# DISCUSS: to strip or not to strip
|
13
11
|
end
|
14
12
|
end
|
@@ -1,17 +1,14 @@
|
|
1
|
-
require 'builder'
|
2
1
|
require 'time'
|
3
|
-
require 'nokogiri'
|
4
2
|
|
5
3
|
class Time
|
6
4
|
|
7
5
|
def to_xml_rpc b=Rapuncel.get_builder
|
8
|
-
b.
|
6
|
+
b.send "dateTime.iso8601", self.iso8601
|
7
|
+
|
8
|
+
b.to_xml
|
9
9
|
end
|
10
|
-
|
10
|
+
|
11
11
|
def self.from_xml_rpc xml_node
|
12
|
-
#
|
13
|
-
|
14
|
-
Time.parse xml_node.text #make a Time object of this string which is hopefully in the right format
|
12
|
+
Time.parse xml_node.text.strip #make a Time object of this string which is hopefully in the right format
|
15
13
|
end
|
16
|
-
|
17
14
|
end
|
data/lib/rapuncel/proxy.rb
CHANGED
@@ -2,23 +2,38 @@ require 'rapuncel/request'
|
|
2
2
|
|
3
3
|
module Rapuncel
|
4
4
|
class Proxy
|
5
|
-
PROXY_METHODS = %w(tap inspect clone freeze dup class initialize)
|
6
|
-
LOCKED_METHODS = %w(method_missing)
|
7
|
-
LOCKED_PATTERN = /(\A__|\?\Z|!\Z)
|
5
|
+
PROXY_METHODS = %w(tap inspect clone freeze dup class initialize).freeze
|
6
|
+
LOCKED_METHODS = %w(method_missing).freeze
|
7
|
+
LOCKED_PATTERN = /(\A__|\?\Z|!\Z)/.freeze
|
8
8
|
|
9
9
|
class << self
|
10
|
-
|
10
|
+
# Initialize a new Proxy object for a specific Client. Alternatively
|
11
|
+
# you can pass a Hash containing configuration for a new Client, which
|
12
|
+
# will be created on-the-fly, but not accessible. The second parameter
|
13
|
+
# specifies a specific interface/namespace for the remote calls,
|
14
|
+
# i.e. if your RPC method is
|
15
|
+
#
|
16
|
+
# int numbers.add(int a, int b)
|
17
|
+
#
|
18
|
+
# You can create a specific proxy for +numbers+, and use +add+ directly
|
19
|
+
#
|
20
|
+
# proxy = Proxy.new client, 'numbers'
|
21
|
+
# proxy.add(40, 2) -> 42
|
22
|
+
#
|
23
|
+
def new client_or_configuration, interface = nil
|
11
24
|
client_or_configuration = Client.new client_or_configuration if client_or_configuration.is_a?(Hash)
|
12
|
-
|
25
|
+
|
13
26
|
allocate.__tap__ do |new_proxy|
|
14
27
|
new_proxy.__initialize__ client_or_configuration, interface
|
15
28
|
end
|
16
29
|
end
|
17
30
|
|
18
31
|
def define_proxy_method name
|
19
|
-
|
20
|
-
|
21
|
-
|
32
|
+
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
33
|
+
def #{name} *args, &block
|
34
|
+
call! '#{name}', *args, &block
|
35
|
+
end
|
36
|
+
RUBY
|
22
37
|
end
|
23
38
|
end
|
24
39
|
|
@@ -33,24 +48,34 @@ module Rapuncel
|
|
33
48
|
end
|
34
49
|
|
35
50
|
def call! name, *args
|
36
|
-
name =
|
37
|
-
|
51
|
+
name = "#{@interface}.#{name}" if @interface
|
52
|
+
|
53
|
+
@client.call_to_ruby(name, *args).tap do |response|
|
54
|
+
|
55
|
+
if block_given?
|
56
|
+
yield response
|
57
|
+
end
|
58
|
+
end
|
38
59
|
end
|
39
60
|
|
40
|
-
def __initialize__ client, interface
|
61
|
+
def __initialize__ client, interface #:nodoc:
|
41
62
|
@interface = interface
|
42
63
|
@client = client
|
43
64
|
end
|
44
65
|
|
66
|
+
def respond_to? name #:nodoc:
|
67
|
+
LOCKED_PATTERN.match(name.to_s) ? super : true
|
68
|
+
end
|
69
|
+
|
45
70
|
protected
|
46
|
-
def method_missing name, *args
|
71
|
+
def method_missing name, *args, &block #:nodoc:
|
47
72
|
name = name.to_s
|
48
73
|
|
49
74
|
if LOCKED_PATTERN.match name
|
50
|
-
super
|
75
|
+
super name.to_sym, *args, &block
|
51
76
|
else
|
52
77
|
self.__class__.define_proxy_method name
|
53
|
-
call! name, *args
|
78
|
+
call! name, *args, &block
|
54
79
|
end
|
55
80
|
end
|
56
81
|
end
|
data/lib/rapuncel/request.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
|
1
|
+
|
2
2
|
|
3
3
|
|
4
4
|
module Rapuncel
|
@@ -13,13 +13,14 @@ module Rapuncel
|
|
13
13
|
|
14
14
|
def to_xml_rpc builder = Rapuncel.get_builder
|
15
15
|
method_call! builder
|
16
|
+
|
17
|
+
builder.to_xml :encoding => 'UTF-8'
|
16
18
|
end
|
17
19
|
|
18
20
|
protected
|
19
21
|
def method_call! builder
|
20
|
-
builder.instruct!
|
21
22
|
|
22
|
-
builder.methodCall do
|
23
|
+
builder.methodCall do |builder|
|
23
24
|
method_name! builder
|
24
25
|
params! builder
|
25
26
|
end
|
@@ -30,7 +31,7 @@ module Rapuncel
|
|
30
31
|
end
|
31
32
|
|
32
33
|
def params! builder
|
33
|
-
builder.params do
|
34
|
+
builder.params do |builder|
|
34
35
|
arguments.each do |value|
|
35
36
|
param! builder, value
|
36
37
|
end
|
@@ -38,8 +39,8 @@ module Rapuncel
|
|
38
39
|
end
|
39
40
|
|
40
41
|
def param! builder, value
|
41
|
-
builder.param do
|
42
|
-
builder.value do
|
42
|
+
builder.param do |builder|
|
43
|
+
builder.value do |builder|
|
43
44
|
value.to_xml_rpc builder
|
44
45
|
end
|
45
46
|
end
|
data/lib/rapuncel/response.rb
CHANGED
@@ -1,9 +1,12 @@
|
|
1
1
|
require 'active_support/core_ext/module/delegation'
|
2
|
-
require 'rapuncel/fault'
|
3
2
|
|
4
3
|
module Rapuncel
|
5
4
|
class Response
|
6
|
-
|
5
|
+
class Exception < ::Exception ; end
|
6
|
+
class Fault < Exception ; end
|
7
|
+
class Error < Exception ; end
|
8
|
+
|
9
|
+
attr_accessor :http_response, :status, :status_code
|
7
10
|
|
8
11
|
delegate :body,
|
9
12
|
:to => :http_response
|
@@ -11,11 +14,16 @@ module Rapuncel
|
|
11
14
|
def initialize http_response
|
12
15
|
@http_response = http_response
|
13
16
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
17
|
+
evaluate_status
|
18
|
+
end
|
19
|
+
|
20
|
+
def evaluate_status
|
21
|
+
@status_code = http_response.code.to_i
|
22
|
+
|
23
|
+
@status = case
|
24
|
+
when !http_response.success? then 'error'
|
25
|
+
when parsed_body && method_response_success? then 'success'
|
26
|
+
else 'fault'
|
19
27
|
end
|
20
28
|
end
|
21
29
|
|
@@ -23,32 +31,53 @@ module Rapuncel
|
|
23
31
|
status == 'success'
|
24
32
|
end
|
25
33
|
|
26
|
-
def
|
27
|
-
|
28
|
-
end
|
29
|
-
|
30
|
-
def
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
34
|
+
def fault?
|
35
|
+
status == 'fault'
|
36
|
+
end
|
37
|
+
|
38
|
+
def error?
|
39
|
+
status == 'error'
|
40
|
+
end
|
41
|
+
|
42
|
+
def fault
|
43
|
+
if fault?
|
44
|
+
@fault ||= begin
|
45
|
+
fault_node = parsed_body.xpath('/methodResponse/fault/value/struct').first
|
46
|
+
|
47
|
+
Hash.from_xml_rpc(fault_node).tap do |h|
|
48
|
+
h[:faultString] = h[:faultString].strip
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def error
|
55
|
+
if error?
|
56
|
+
@error ||= { :http_code => @status_code, :http_body => body }
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def result
|
61
|
+
if success?
|
62
|
+
@result ||= begin
|
63
|
+
return_values = parsed_body.xpath('/methodResponse/params/param/value/*')
|
64
|
+
|
65
|
+
Object.from_xml_rpc return_values.first
|
66
|
+
end
|
45
67
|
end
|
46
68
|
end
|
47
|
-
|
48
|
-
def
|
49
|
-
|
50
|
-
|
51
|
-
|
69
|
+
|
70
|
+
def to_ruby
|
71
|
+
result || fault || error
|
72
|
+
end
|
73
|
+
|
74
|
+
protected
|
75
|
+
def parsed_body
|
76
|
+
@xml_doc ||= Nokogiri::XML.parse body
|
77
|
+
end
|
78
|
+
|
79
|
+
def method_response_success?
|
80
|
+
parsed_body.xpath('/methodResponse/fault').empty?
|
52
81
|
end
|
53
82
|
end
|
54
83
|
end
|
data/rapuncel.gemspec
CHANGED
@@ -1,12 +1,12 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
s.name = "rapuncel"
|
3
|
-
s.version = "0.0.
|
3
|
+
s.version = "0.0.2"
|
4
4
|
s.date = Time.now.strftime("%Y-%m-%d")
|
5
5
|
s.authors = ["Michael Eickenberg", "Marian Theisen"]
|
6
6
|
s.email = 'marian@cice-online.net'
|
7
7
|
s.summary = "Simple XML-RPC Client"
|
8
8
|
s.homepage = "http://github.com/cice/rapuncel"
|
9
|
-
s.description = "
|
9
|
+
s.description = "Rapuncel is a simple XML-RPC Client based on Nokogiri, thus provides a fast and easy way to interact with XML-RPC services."
|
10
10
|
|
11
11
|
s.files = Dir["**/*"] -
|
12
12
|
Dir["coverage/**/*"] -
|
@@ -16,7 +16,6 @@ Gem::Specification.new do |s|
|
|
16
16
|
Dir["rcov/**/*"]
|
17
17
|
|
18
18
|
s.add_dependency 'nokogiri'
|
19
|
-
s.add_dependency 'builder'
|
20
19
|
s.add_dependency 'activesupport', '>= 3.0.0'
|
21
20
|
|
22
21
|
s.add_development_dependency 'mocha'
|
@@ -2,22 +2,53 @@ require 'functional_test_helper'
|
|
2
2
|
|
3
3
|
class FunctionalClientTest < FunctionalTest
|
4
4
|
test "Simple XMLRPC call" do
|
5
|
-
client = Rapuncel::Client.new :port => 8080
|
5
|
+
client = Rapuncel::Client.new :port => 8080, :raise_on => :both
|
6
6
|
proxy = client.proxy_for 'num'
|
7
|
-
|
7
|
+
|
8
8
|
result = proxy.add 40, 2
|
9
|
-
|
9
|
+
|
10
10
|
assert_equal 42, result
|
11
11
|
end
|
12
12
|
|
13
|
-
test "Fault rpc call" do
|
13
|
+
test "Fault rpc call without raise" do
|
14
14
|
client = Rapuncel::Client.new :port => 8080
|
15
15
|
proxy = client.proxy_for 'num'
|
16
16
|
|
17
|
-
|
17
|
+
assert_nothing_raised Rapuncel::Response::Exception do
|
18
|
+
proxy.add 20, 20, 2
|
19
|
+
end
|
18
20
|
|
19
|
-
assert_kind_of
|
21
|
+
assert_kind_of Hash, proxy.add(20, 20, 2)
|
20
22
|
end
|
21
|
-
|
22
23
|
|
24
|
+
test "Fault rpc call" do
|
25
|
+
client = Rapuncel::Client.new :port => 8080, :raise_on => :both
|
26
|
+
proxy = client.proxy_for 'num'
|
27
|
+
|
28
|
+
assert_raise Rapuncel::Response::Fault do
|
29
|
+
proxy.add 20, 20, 2
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
test "Error rpc connection" do
|
34
|
+
client = Rapuncel::Client.new :host => 'www.cice-online.net', :port => 80, :path => '/hullahoobahubbahooo', :raise_on => :both
|
35
|
+
proxy = client.proxy
|
36
|
+
|
37
|
+
assert_raise Rapuncel::Response::Error do
|
38
|
+
proxy.foo :bar, :baz
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
test "Error rpc connection without raise" do
|
43
|
+
client = Rapuncel::Client.new :host => 'www.google.de', :port => 80, :path => '/hullahoobahubbahooo'
|
44
|
+
proxy = client.proxy
|
45
|
+
|
46
|
+
assert_nothing_raised Rapuncel::Response::Error do
|
47
|
+
proxy.foo :bar, :baz
|
48
|
+
end
|
49
|
+
|
50
|
+
err = proxy.foo(:bar, :baz)
|
51
|
+
assert_kind_of Hash, err
|
52
|
+
assert_equal 404, err[:http_code]
|
53
|
+
end
|
23
54
|
end
|