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.
Files changed (64) hide show
  1. data/README.md +33 -36
  2. data/{Rakefile → Rakefile.rb} +1 -1
  3. data/lib/rapuncel.rb +1 -2
  4. data/lib/rapuncel/adapters/net_http_adapter.rb +6 -6
  5. data/lib/rapuncel/adapters/typhoeus_adapter.rb +33 -0
  6. data/lib/rapuncel/base.rb +2 -2
  7. data/lib/rapuncel/client.rb +13 -21
  8. data/lib/rapuncel/connection.rb +2 -2
  9. data/lib/rapuncel/core_ext/array.rb +16 -9
  10. data/lib/rapuncel/core_ext/big_decimal.rb +0 -7
  11. data/lib/rapuncel/core_ext/boolean.rb +13 -10
  12. data/lib/rapuncel/core_ext/float.rb +7 -4
  13. data/lib/rapuncel/core_ext/hash.rb +27 -17
  14. data/lib/rapuncel/core_ext/integer.rb +10 -2
  15. data/lib/rapuncel/core_ext/object.rb +6 -6
  16. data/lib/rapuncel/core_ext/string.rb +7 -5
  17. data/lib/rapuncel/core_ext/symbol.rb +3 -2
  18. data/lib/rapuncel/core_ext/time.rb +8 -5
  19. data/lib/rapuncel/fault.rb +10 -0
  20. data/lib/rapuncel/proxy.rb +14 -39
  21. data/lib/rapuncel/request.rb +6 -7
  22. data/lib/rapuncel/response.rb +31 -69
  23. data/rapuncel.gemspec +4 -3
  24. data/test/coverage/-Users-mariantheisen-Projects-Kayoom-rapuncel-lib-rapuncel-adapters-typhoeus_adapter_rb.html +231 -0
  25. data/test/coverage/-Users-mariantheisen-Projects-Kayoom-rapuncel-lib-rapuncel-base_rb.html +105 -0
  26. data/test/coverage/-Users-mariantheisen-Projects-Kayoom-rapuncel-lib-rapuncel-client_rb.html +321 -0
  27. data/test/coverage/-Users-mariantheisen-Projects-Kayoom-rapuncel-lib-rapuncel-connection_rb.html +513 -0
  28. data/test/coverage/-Users-mariantheisen-Projects-Kayoom-rapuncel-lib-rapuncel-core_ext-array_rb.html +303 -0
  29. data/test/coverage/-Users-mariantheisen-Projects-Kayoom-rapuncel-lib-rapuncel-core_ext-boolean_rb.html +255 -0
  30. data/test/coverage/-Users-mariantheisen-Projects-Kayoom-rapuncel-lib-rapuncel-core_ext-float_rb.html +177 -0
  31. data/test/coverage/-Users-mariantheisen-Projects-Kayoom-rapuncel-lib-rapuncel-core_ext-hash_rb.html +297 -0
  32. data/test/coverage/-Users-mariantheisen-Projects-Kayoom-rapuncel-lib-rapuncel-core_ext-integer_rb.html +177 -0
  33. data/test/coverage/-Users-mariantheisen-Projects-Kayoom-rapuncel-lib-rapuncel-core_ext-object_rb.html +297 -0
  34. data/test/coverage/-Users-mariantheisen-Projects-Kayoom-rapuncel-lib-rapuncel-core_ext-string_rb.html +159 -0
  35. data/test/coverage/-Users-mariantheisen-Projects-Kayoom-rapuncel-lib-rapuncel-core_ext-time_rb.html +165 -0
  36. data/test/coverage/-Users-mariantheisen-Projects-Kayoom-rapuncel-lib-rapuncel-fault_rb.html +93 -0
  37. data/test/coverage/-Users-mariantheisen-Projects-Kayoom-rapuncel-lib-rapuncel-proxy_rb.html +393 -0
  38. data/test/coverage/-Users-mariantheisen-Projects-Kayoom-rapuncel-lib-rapuncel-request_rb.html +351 -0
  39. data/test/coverage/-Users-mariantheisen-Projects-Kayoom-rapuncel-lib-rapuncel-response_rb.html +399 -0
  40. data/test/coverage/-Users-mariantheisen-Projects-Kayoom-rapuncel-lib-rapuncel_rb.html +201 -0
  41. data/test/coverage/functional_test_helper_rb.html +141 -0
  42. data/test/coverage/index.html +410 -0
  43. data/test/coverage/jquery-1.3.2.min.js +19 -0
  44. data/test/coverage/jquery.tablesorter.min.js +15 -0
  45. data/test/coverage/print.css +12 -0
  46. data/test/coverage/rcov.js +42 -0
  47. data/test/coverage/screen.css +270 -0
  48. data/test/coverage/test_helper_rb.html +291 -0
  49. data/test/coverage/test_server_rb.html +231 -0
  50. data/test/functional/client_test.rb +7 -38
  51. data/test/functional_test_helper.rb +2 -2
  52. data/test/test_server.rb +29 -3
  53. data/test/unit/array_test.rb +14 -14
  54. data/test/unit/boolean_test.rb +6 -6
  55. data/test/unit/float_test.rb +7 -7
  56. data/test/unit/hash_test.rb +16 -16
  57. data/test/unit/object_test.rb +29 -29
  58. data/test/unit/proxy_test.rb +9 -9
  59. data/test/unit/response_test.rb +5 -69
  60. data/test/unit/string_test.rb +7 -15
  61. metadata +56 -20
  62. data/lib/rapuncel/core_ext/nil.rb +0 -7
  63. data/rapuncel-0.0.1.preview.gem +0 -0
  64. 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
- # Hash will be translated into an XML-RPC "struct" object
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
- b.value do |b|
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
- keys_and_values = xml_node.element_children
22
-
23
- new.tap do |hash|
24
- keys_and_values.each do |kv|
25
- key = kv.first_element_child.text.strip.to_sym
26
- value = Object.from_xml_rpc kv.last_element_child.first_element_child
27
-
28
- hash[key] = value
29
- end
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
- end
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.text.strip.to_i #calling to_i on the text between the i4 or int tags
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.strip}"
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.text.gsub(/(\r\n|\r)/, "\n") #just give back the string between the 'string' tags
10
- # DISCUSS: to strip or not to strip
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,7 +1,8 @@
1
+ require 'builder'
2
+ require 'nokogiri'
3
+
1
4
  class Symbol
2
5
  def to_xml_rpc b = Rapuncel.get_builder
3
6
  b.string to_s
4
-
5
- b.to_xml
6
7
  end
7
8
  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.send "dateTime.iso8601", self.iso8601
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
- Time.parse xml_node.text.strip #make a Time object of this string which is hopefully in the right format
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
@@ -0,0 +1,10 @@
1
+ module Rapuncel
2
+ class Fault
3
+ attr_accessor :code, :string
4
+
5
+ def initialize hsh
6
+ @code = hsh[:faultCode]
7
+ @string = hsh[:faultString]
8
+ end
9
+ end
10
+ end
@@ -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).freeze
6
- LOCKED_METHODS = %w(method_missing).freeze
7
- LOCKED_PATTERN = /(\A__|\?\Z|!\Z)/.freeze
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
- # 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
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
- class_eval <<-RUBY, __FILE__, __LINE__ + 1
33
- def #{name} *args, &block
34
- call! '#{name}', *args, &block
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 = "#{@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
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 #:nodoc:
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, &block #:nodoc:
46
+ def method_missing name, *args
72
47
  name = name.to_s
73
48
 
74
49
  if LOCKED_PATTERN.match name
75
- super name.to_sym, *args, &block
50
+ super
76
51
  else
77
52
  self.__class__.define_proxy_method name
78
- call! name, *args, &block
53
+ call! name, *args
79
54
  end
80
55
  end
81
56
  end
@@ -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 |builder|
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 |builder|
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 |builder|
43
- builder.value do |builder|
41
+ builder.param do
42
+ builder.value do
44
43
  value.to_xml_rpc builder
45
44
  end
46
45
  end
@@ -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
- class Exception < ::Exception
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
- evaluate_status
28
- end
29
-
30
- def evaluate_status
31
- @status_code = http_response.code.to_i
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
- result || fault || error
81
- end
82
-
83
- protected
84
- def parsed_body
85
- @xml_doc ||= Nokogiri::XML.parse body
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 method_response_success?
89
- parsed_body.xpath('/methodResponse/fault').empty?
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.alpha"
4
- s.date = "2010-12-02"
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 = "Rapuncel is a simple XML-RPC Client based on Nokogiri, thus provides a fast and easy way to interact with XML-RPC services."
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'