rapuncel 0.0.1.alpha → 0.0.1
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 +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'
|