rapuncel 0.0.1.alpha → 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +33 -36
- data/{Rakefile → Rakefile.rb} +1 -1
- data/lib/rapuncel.rb +1 -2
- data/lib/rapuncel/adapters/net_http_adapter.rb +6 -6
- data/lib/rapuncel/adapters/typhoeus_adapter.rb +33 -0
- data/lib/rapuncel/base.rb +2 -2
- data/lib/rapuncel/client.rb +13 -21
- data/lib/rapuncel/connection.rb +2 -2
- data/lib/rapuncel/core_ext/array.rb +16 -9
- data/lib/rapuncel/core_ext/big_decimal.rb +0 -7
- data/lib/rapuncel/core_ext/boolean.rb +13 -10
- data/lib/rapuncel/core_ext/float.rb +7 -4
- data/lib/rapuncel/core_ext/hash.rb +27 -17
- data/lib/rapuncel/core_ext/integer.rb +10 -2
- data/lib/rapuncel/core_ext/object.rb +6 -6
- data/lib/rapuncel/core_ext/string.rb +7 -5
- data/lib/rapuncel/core_ext/symbol.rb +3 -2
- data/lib/rapuncel/core_ext/time.rb +8 -5
- data/lib/rapuncel/fault.rb +10 -0
- data/lib/rapuncel/proxy.rb +14 -39
- data/lib/rapuncel/request.rb +6 -7
- data/lib/rapuncel/response.rb +31 -69
- data/rapuncel.gemspec +4 -3
- data/test/coverage/-Users-mariantheisen-Projects-Kayoom-rapuncel-lib-rapuncel-adapters-typhoeus_adapter_rb.html +231 -0
- data/test/coverage/-Users-mariantheisen-Projects-Kayoom-rapuncel-lib-rapuncel-base_rb.html +105 -0
- data/test/coverage/-Users-mariantheisen-Projects-Kayoom-rapuncel-lib-rapuncel-client_rb.html +321 -0
- data/test/coverage/-Users-mariantheisen-Projects-Kayoom-rapuncel-lib-rapuncel-connection_rb.html +513 -0
- data/test/coverage/-Users-mariantheisen-Projects-Kayoom-rapuncel-lib-rapuncel-core_ext-array_rb.html +303 -0
- data/test/coverage/-Users-mariantheisen-Projects-Kayoom-rapuncel-lib-rapuncel-core_ext-boolean_rb.html +255 -0
- data/test/coverage/-Users-mariantheisen-Projects-Kayoom-rapuncel-lib-rapuncel-core_ext-float_rb.html +177 -0
- data/test/coverage/-Users-mariantheisen-Projects-Kayoom-rapuncel-lib-rapuncel-core_ext-hash_rb.html +297 -0
- data/test/coverage/-Users-mariantheisen-Projects-Kayoom-rapuncel-lib-rapuncel-core_ext-integer_rb.html +177 -0
- data/test/coverage/-Users-mariantheisen-Projects-Kayoom-rapuncel-lib-rapuncel-core_ext-object_rb.html +297 -0
- data/test/coverage/-Users-mariantheisen-Projects-Kayoom-rapuncel-lib-rapuncel-core_ext-string_rb.html +159 -0
- data/test/coverage/-Users-mariantheisen-Projects-Kayoom-rapuncel-lib-rapuncel-core_ext-time_rb.html +165 -0
- data/test/coverage/-Users-mariantheisen-Projects-Kayoom-rapuncel-lib-rapuncel-fault_rb.html +93 -0
- data/test/coverage/-Users-mariantheisen-Projects-Kayoom-rapuncel-lib-rapuncel-proxy_rb.html +393 -0
- data/test/coverage/-Users-mariantheisen-Projects-Kayoom-rapuncel-lib-rapuncel-request_rb.html +351 -0
- data/test/coverage/-Users-mariantheisen-Projects-Kayoom-rapuncel-lib-rapuncel-response_rb.html +399 -0
- data/test/coverage/-Users-mariantheisen-Projects-Kayoom-rapuncel-lib-rapuncel_rb.html +201 -0
- data/test/coverage/functional_test_helper_rb.html +141 -0
- data/test/coverage/index.html +410 -0
- data/test/coverage/jquery-1.3.2.min.js +19 -0
- data/test/coverage/jquery.tablesorter.min.js +15 -0
- data/test/coverage/print.css +12 -0
- data/test/coverage/rcov.js +42 -0
- data/test/coverage/screen.css +270 -0
- data/test/coverage/test_helper_rb.html +291 -0
- data/test/coverage/test_server_rb.html +231 -0
- data/test/functional/client_test.rb +7 -38
- data/test/functional_test_helper.rb +2 -2
- data/test/test_server.rb +29 -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/object_test.rb +29 -29
- data/test/unit/proxy_test.rb +9 -9
- data/test/unit/response_test.rb +5 -69
- data/test/unit/string_test.rb +7 -15
- metadata +56 -20
- data/lib/rapuncel/core_ext/nil.rb +0 -7
- data/rapuncel-0.0.1.preview.gem +0 -0
- data/test/unit/nil_test.rb +0 -16
@@ -1,32 +1,42 @@
|
|
1
|
+
require 'builder'
|
2
|
+
|
3
|
+
class Rapuncel::Hash
|
4
|
+
|
5
|
+
end
|
6
|
+
|
1
7
|
class Hash
|
2
|
-
#
|
8
|
+
#Hash will be translated into an XML-RPC "struct" object
|
3
9
|
|
4
10
|
def to_xml_rpc b = Rapuncel.get_builder
|
11
|
+
|
5
12
|
b.struct do |b|
|
6
13
|
self.each_pair do |key, value|
|
7
|
-
b.member do |b|
|
8
|
-
b.name key.to_s
|
9
14
|
|
10
|
-
|
15
|
+
#warn "The key #{key.to_s} is a #{key.class.to_s}, which is neither a symbol nor a string. It will be converted using to_s" unless key.is_a?(String) || key.is_a?(Symbol)
|
16
|
+
|
17
|
+
b.member do
|
18
|
+
|
19
|
+
b.name key.to_s
|
20
|
+
b.value do
|
11
21
|
value.to_xml_rpc b
|
12
22
|
end
|
13
23
|
end
|
14
24
|
end
|
15
25
|
end
|
16
|
-
|
17
|
-
b.to_xml
|
18
26
|
end
|
19
|
-
|
27
|
+
|
20
28
|
def self.from_xml_rpc xml_node
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
29
|
+
#warn "The given xml_node is a #{xml_node.name}, not a 'struct'. Continuing at your risk" unless ['struct'].include? xml_node.name
|
30
|
+
|
31
|
+
keys_and_values = xml_node.element_children #xpath('./member')
|
32
|
+
|
33
|
+
hash = new
|
34
|
+
keys_and_values.each do |kv|
|
35
|
+
key = kv.first_element_child.text.to_sym
|
36
|
+
|
37
|
+
value = Object.from_xml_rpc kv.last_element_child.first_element_child
|
38
|
+
hash[key] = value
|
30
39
|
end
|
31
|
-
|
40
|
+
hash
|
41
|
+
end
|
32
42
|
end
|
@@ -1,11 +1,19 @@
|
|
1
|
+
require 'builder'
|
2
|
+
require 'nokogiri'
|
3
|
+
require 'ruby-debug'
|
4
|
+
|
1
5
|
class Integer
|
6
|
+
|
2
7
|
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
|
+
|
3
10
|
b.int self.to_s
|
4
11
|
|
5
|
-
b.to_xml
|
6
12
|
end
|
7
13
|
|
8
14
|
def self.from_xml_rpc xml_node
|
9
|
-
xml_node.
|
15
|
+
#warn "xml node given (name of #{xml_node.name}) is not of integer type, node name should be 'i4' or 'int'" unless ['i4','int'].include? xml_node.name.downcase
|
16
|
+
|
17
|
+
xml_node.text.to_i #calling to_i on the text between the i4 or int tags
|
10
18
|
end
|
11
19
|
end
|
@@ -1,21 +1,21 @@
|
|
1
|
+
require 'builder'
|
2
|
+
|
1
3
|
class Object
|
2
4
|
def to_xml_rpc b = Rapuncel.get_builder
|
3
5
|
if respond_to?(:acts_like?) && acts_like?(:time)
|
4
6
|
to_time.to_xml_rpc b
|
5
|
-
else
|
7
|
+
else
|
6
8
|
_collect_ivars_in_hash.to_xml_rpc b
|
7
9
|
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}"
|
38
38
|
end
|
39
39
|
end
|
40
40
|
|
@@ -1,12 +1,14 @@
|
|
1
|
+
require 'builder'
|
2
|
+
require 'nokogiri'
|
3
|
+
|
1
4
|
class String
|
2
5
|
def to_xml_rpc b = Rapuncel.get_builder
|
3
6
|
b.string self
|
4
|
-
|
5
|
-
b.to_xml
|
6
7
|
end
|
7
|
-
|
8
|
+
|
8
9
|
def self.from_xml_rpc xml_node
|
9
|
-
xml_node
|
10
|
-
|
10
|
+
#warn "I, String.from_xml_rpc have been given an xml_node with the wrong tag (name of #{xml_node.name}). My tag should be 'string'. Will still parse at your risk" unless ['string'].include? xml_node.name.downcase
|
11
|
+
|
12
|
+
xml_node.text #just give back the string between the 'string' tags
|
11
13
|
end
|
12
14
|
end
|
@@ -1,14 +1,17 @@
|
|
1
|
+
require 'builder'
|
1
2
|
require 'time'
|
3
|
+
require 'nokogiri'
|
2
4
|
|
3
5
|
class Time
|
4
6
|
|
5
7
|
def to_xml_rpc b=Rapuncel.get_builder
|
6
|
-
b.
|
7
|
-
|
8
|
-
b.to_xml
|
8
|
+
b.tag! "dateTime.iso8601", self.iso8601
|
9
9
|
end
|
10
|
-
|
10
|
+
|
11
11
|
def self.from_xml_rpc xml_node
|
12
|
-
|
12
|
+
#warn "Need node to be named 'dateTime.iso8601', but it is #{xml_node.name}. Will still parse, at your risk" unless ['dateTime.iso8601'].include? xml_node.name
|
13
|
+
|
14
|
+
Time.parse xml_node.text #make a Time object of this string which is hopefully in the right format
|
13
15
|
end
|
16
|
+
|
14
17
|
end
|
data/lib/rapuncel/proxy.rb
CHANGED
@@ -2,38 +2,23 @@ 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)
|
6
|
+
LOCKED_METHODS = %w(method_missing)
|
7
|
+
LOCKED_PATTERN = /(\A__|\?\Z|!\Z)/
|
8
8
|
|
9
9
|
class << self
|
10
|
-
|
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
|
10
|
+
def new client_or_configuration, interface = nil
|
24
11
|
client_or_configuration = Client.new client_or_configuration if client_or_configuration.is_a?(Hash)
|
25
|
-
|
12
|
+
|
26
13
|
allocate.__tap__ do |new_proxy|
|
27
14
|
new_proxy.__initialize__ client_or_configuration, interface
|
28
15
|
end
|
29
16
|
end
|
30
17
|
|
31
18
|
def define_proxy_method name
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
end
|
36
|
-
RUBY
|
19
|
+
define_method name do |*args|
|
20
|
+
call! name, *args
|
21
|
+
end
|
37
22
|
end
|
38
23
|
end
|
39
24
|
|
@@ -48,34 +33,24 @@ module Rapuncel
|
|
48
33
|
end
|
49
34
|
|
50
35
|
def call! name, *args
|
51
|
-
name =
|
52
|
-
|
53
|
-
@client.call_to_ruby(name, *args).tap do |response|
|
54
|
-
|
55
|
-
if block_given?
|
56
|
-
yield response
|
57
|
-
end
|
58
|
-
end
|
36
|
+
name = [@interface, name] * '.' if @interface
|
37
|
+
@client.execute_to_ruby Request.new(name, *args)
|
59
38
|
end
|
60
39
|
|
61
|
-
def __initialize__ client, interface
|
40
|
+
def __initialize__ client, interface
|
62
41
|
@interface = interface
|
63
42
|
@client = client
|
64
43
|
end
|
65
44
|
|
66
|
-
def respond_to? name #:nodoc:
|
67
|
-
LOCKED_PATTERN.match(name.to_s) ? super : true
|
68
|
-
end
|
69
|
-
|
70
45
|
protected
|
71
|
-
def method_missing name, *args
|
46
|
+
def method_missing name, *args
|
72
47
|
name = name.to_s
|
73
48
|
|
74
49
|
if LOCKED_PATTERN.match name
|
75
|
-
super
|
50
|
+
super
|
76
51
|
else
|
77
52
|
self.__class__.define_proxy_method name
|
78
|
-
call! name, *args
|
53
|
+
call! name, *args
|
79
54
|
end
|
80
55
|
end
|
81
56
|
end
|
data/lib/rapuncel/request.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
|
1
|
+
require 'builder'
|
2
2
|
|
3
3
|
|
4
4
|
module Rapuncel
|
@@ -13,14 +13,13 @@ 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'
|
18
16
|
end
|
19
17
|
|
20
18
|
protected
|
21
19
|
def method_call! builder
|
20
|
+
builder.instruct!
|
22
21
|
|
23
|
-
builder.methodCall do
|
22
|
+
builder.methodCall do
|
24
23
|
method_name! builder
|
25
24
|
params! builder
|
26
25
|
end
|
@@ -31,7 +30,7 @@ module Rapuncel
|
|
31
30
|
end
|
32
31
|
|
33
32
|
def params! builder
|
34
|
-
builder.params do
|
33
|
+
builder.params do
|
35
34
|
arguments.each do |value|
|
36
35
|
param! builder, value
|
37
36
|
end
|
@@ -39,8 +38,8 @@ module Rapuncel
|
|
39
38
|
end
|
40
39
|
|
41
40
|
def param! builder, value
|
42
|
-
builder.param do
|
43
|
-
builder.value do
|
41
|
+
builder.param do
|
42
|
+
builder.value do
|
44
43
|
value.to_xml_rpc builder
|
45
44
|
end
|
46
45
|
end
|
data/lib/rapuncel/response.rb
CHANGED
@@ -1,22 +1,9 @@
|
|
1
1
|
require 'active_support/core_ext/module/delegation'
|
2
|
+
require 'rapuncel/fault'
|
2
3
|
|
3
4
|
module Rapuncel
|
4
5
|
class Response
|
5
|
-
|
6
|
-
attr_accessor :code, :string
|
7
|
-
|
8
|
-
def initialize code, string
|
9
|
-
@code, @string = code, string
|
10
|
-
end
|
11
|
-
|
12
|
-
def exception
|
13
|
-
self
|
14
|
-
end
|
15
|
-
end
|
16
|
-
class Fault < Exception ; end
|
17
|
-
class Error < Exception ; end
|
18
|
-
|
19
|
-
attr_accessor :http_response, :status, :status_code
|
6
|
+
attr_accessor :http_response, :status
|
20
7
|
|
21
8
|
delegate :body,
|
22
9
|
:to => :http_response
|
@@ -24,16 +11,11 @@ module Rapuncel
|
|
24
11
|
def initialize http_response
|
25
12
|
@http_response = http_response
|
26
13
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
@status = case
|
34
|
-
when !http_response.success? then 'error'
|
35
|
-
when parsed_body && method_response_success? then 'success'
|
36
|
-
else 'fault'
|
14
|
+
if http_response.success?
|
15
|
+
parse_response
|
16
|
+
else
|
17
|
+
@status = http_response.code
|
18
|
+
raise("HTTP Error: #{@status}\n#{body}")
|
37
19
|
end
|
38
20
|
end
|
39
21
|
|
@@ -41,52 +23,32 @@ module Rapuncel
|
|
41
23
|
status == 'success'
|
42
24
|
end
|
43
25
|
|
44
|
-
def fault?
|
45
|
-
status == 'fault'
|
46
|
-
end
|
47
|
-
|
48
|
-
def error?
|
49
|
-
status == 'error'
|
50
|
-
end
|
51
|
-
|
52
|
-
def fault
|
53
|
-
if fault?
|
54
|
-
@fault ||= begin
|
55
|
-
fault_node = parsed_body.xpath('/methodResponse/fault/value/struct').first
|
56
|
-
fault_hash = Hash.from_xml_rpc(fault_node)
|
57
|
-
|
58
|
-
Fault.new fault_hash[:faultCode], fault_hash[:faultString]
|
59
|
-
end
|
60
|
-
end
|
61
|
-
end
|
62
|
-
|
63
|
-
def error
|
64
|
-
if error?
|
65
|
-
@error ||= Error.new @status_code, body
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
def result
|
70
|
-
if success?
|
71
|
-
@result ||= begin
|
72
|
-
return_values = parsed_body.xpath('/methodResponse/params/param/value/*')
|
73
|
-
|
74
|
-
Object.from_xml_rpc return_values.first
|
75
|
-
end
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
26
|
def to_ruby
|
80
|
-
|
81
|
-
end
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
27
|
+
@to_ruby
|
28
|
+
end
|
29
|
+
|
30
|
+
def parse_fault
|
31
|
+
fault = @xml_doc.xpath('/methodResponse/fault/value/struct')
|
32
|
+
|
33
|
+
@to_ruby = Fault.new Hash.from_xml_rpc(fault.first)
|
34
|
+
end
|
35
|
+
|
36
|
+
def parse_response
|
37
|
+
@xml_doc = Nokogiri::XML.parse body
|
38
|
+
|
39
|
+
if @xml_doc.xpath('/methodResponse/fault').empty?
|
40
|
+
@status = 'success'
|
41
|
+
parse_success
|
42
|
+
else
|
43
|
+
@status = 'fault'
|
44
|
+
parse_fault
|
45
|
+
end
|
86
46
|
end
|
87
|
-
|
88
|
-
def
|
89
|
-
|
47
|
+
|
48
|
+
def parse_success
|
49
|
+
values = @xml_doc.xpath('/methodResponse/params/param/value/*')
|
50
|
+
|
51
|
+
@to_ruby = Object.from_xml_rpc values.to_a.first
|
90
52
|
end
|
91
53
|
end
|
92
54
|
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.1
|
4
|
-
s.date = "
|
3
|
+
s.version = "0.0.1"
|
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 = "Simple XML-RPC Client"
|
10
10
|
|
11
11
|
s.files = Dir["**/*"] -
|
12
12
|
Dir["coverage/**/*"] -
|
@@ -16,6 +16,7 @@ Gem::Specification.new do |s|
|
|
16
16
|
Dir["rcov/**/*"]
|
17
17
|
|
18
18
|
s.add_dependency 'nokogiri'
|
19
|
+
s.add_dependency 'builder'
|
19
20
|
s.add_dependency 'activesupport', '>= 3.0.0'
|
20
21
|
|
21
22
|
s.add_development_dependency 'mocha'
|