rapuncel 0.0.4 → 0.0.5.RC1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (59) hide show
  1. data/Gemfile +3 -0
  2. data/README.md +35 -24
  3. data/Rakefile +11 -11
  4. data/lib/rapuncel.rb +9 -17
  5. data/lib/rapuncel/adapters/net_http_adapter.rb +7 -5
  6. data/lib/rapuncel/base_64_string.rb +31 -0
  7. data/lib/rapuncel/client.rb +2 -2
  8. data/lib/rapuncel/connection.rb +35 -58
  9. data/lib/rapuncel/request.rb +1 -38
  10. data/lib/rapuncel/response.rb +17 -30
  11. data/lib/rapuncel/xml_rpc_deserializer.rb +110 -0
  12. data/lib/rapuncel/xml_rpc_serializer.rb +148 -0
  13. data/rapuncel.gemspec +3 -2
  14. data/spec/functional/client_spec.rb +53 -0
  15. data/spec/spec_helper.rb +48 -0
  16. data/{test → spec}/test_server.rb +0 -1
  17. data/spec/unit/array_spec.rb +41 -0
  18. data/spec/unit/base64_spec.rb +30 -0
  19. data/spec/unit/boolean_spec.rb +39 -0
  20. data/spec/unit/connection_spec.rb +22 -0
  21. data/spec/unit/float_spec.rb +38 -0
  22. data/spec/unit/hash_spec.rb +54 -0
  23. data/spec/unit/int_spec.rb +23 -0
  24. data/spec/unit/nil_spec.rb +7 -0
  25. data/spec/unit/object_spec.rb +24 -0
  26. data/spec/unit/proxy_spec.rb +29 -0
  27. data/spec/unit/request_spec.rb +28 -0
  28. data/{test/unit/response_test.rb → spec/unit/response_spec.rb} +29 -44
  29. data/spec/unit/string_spec.rb +35 -0
  30. data/spec/unit/time_spec.rb +20 -0
  31. metadata +77 -104
  32. data/lib/rapuncel/base.rb +0 -7
  33. data/lib/rapuncel/core_ext/array.rb +0 -23
  34. data/lib/rapuncel/core_ext/big_decimal.rb +0 -7
  35. data/lib/rapuncel/core_ext/boolean.rb +0 -29
  36. data/lib/rapuncel/core_ext/float.rb +0 -11
  37. data/lib/rapuncel/core_ext/hash.rb +0 -32
  38. data/lib/rapuncel/core_ext/integer.rb +0 -11
  39. data/lib/rapuncel/core_ext/nil.rb +0 -7
  40. data/lib/rapuncel/core_ext/object.rb +0 -49
  41. data/lib/rapuncel/core_ext/string.rb +0 -12
  42. data/lib/rapuncel/core_ext/symbol.rb +0 -7
  43. data/lib/rapuncel/core_ext/time.rb +0 -14
  44. data/rapuncel-0.0.3.gem +0 -0
  45. data/test/functional/client_test.rb +0 -54
  46. data/test/functional_test_helper.rb +0 -13
  47. data/test/test_helper.rb +0 -38
  48. data/test/unit/array_test.rb +0 -97
  49. data/test/unit/boolean_test.rb +0 -34
  50. data/test/unit/connection_test.rb +0 -29
  51. data/test/unit/float_test.rb +0 -23
  52. data/test/unit/hash_test.rb +0 -54
  53. data/test/unit/int_test.rb +0 -27
  54. data/test/unit/nil_test.rb +0 -16
  55. data/test/unit/object_test.rb +0 -83
  56. data/test/unit/proxy_test.rb +0 -52
  57. data/test/unit/request_test.rb +0 -34
  58. data/test/unit/string_test.rb +0 -40
  59. data/test/unit/time_test.rb +0 -23
@@ -0,0 +1,110 @@
1
+ module Rapuncel
2
+ class XmlRpcDeserializer
3
+ XML_ENCODING = 'UTF-8'
4
+
5
+ def initialize xml
6
+ @xml_doc = Nokogiri::XML.parse xml
7
+ end
8
+
9
+ def deserialize xml_node = root_node
10
+ send "deserialize_#{xml_node.name}", xml_node
11
+ end
12
+
13
+ def deserialize_base64 xml_node
14
+ Base64String.decode_base64 xml_node.text.strip
15
+ end
16
+
17
+ def deserialize_string xml_node
18
+ xml_node.text.gsub(/(\r\n|\r)/, "\n")
19
+ end
20
+
21
+ def deserialize_array xml_node
22
+ values = xml_node.first_element_child.element_children
23
+
24
+ values.map do |value|
25
+ deserialize value.first_element_child
26
+ end
27
+ end
28
+
29
+ def deserialize_boolean xml_node
30
+ xml_node.text == "1"
31
+ end
32
+
33
+ def deserialize_double xml_node
34
+ text = xml_node.text.strip
35
+
36
+ if double_as_bigdecimal?
37
+ BigDecimal.new text
38
+ else
39
+ text.to_f
40
+ end
41
+ end
42
+
43
+ def deserialize_struct xml_node
44
+ keys_and_values = xml_node.element_children
45
+
46
+ {}.tap do |hash|
47
+ keys_and_values.each do |key_value|
48
+ key = key_value.first_element_child.text.strip
49
+ key = key.to_sym unless hash_keys_as_string?
50
+
51
+ value = deserialize key_value.last_element_child.first_element_child
52
+
53
+ hash[key] = value
54
+ end
55
+ end
56
+ end
57
+
58
+ def deserialize_int xml_node
59
+ xml_node.text.strip.to_i
60
+ end
61
+ alias_method :deserialize_i4, :deserialize_int
62
+
63
+ define_method "deserialize_dateTime.iso8601" do |xml_node|
64
+ Time.parse xml_node.text.strip
65
+ end
66
+
67
+ def deserialize_methodResponse xml_node
68
+ response = xml_node.first_element_child
69
+
70
+ if response.name == 'fault'
71
+ deserialize_methodResponse_fault response
72
+ else
73
+ deserialize_methodResponse_params response
74
+ end
75
+ end
76
+
77
+ def deserialize_methodResponse_params xml_node
78
+ deserialize xml_node.first_element_child.first_element_child.first_element_child
79
+ end
80
+
81
+ def deserialize_methodResponse_fault xml_node
82
+ deserialize xml_node.first_element_child.first_element_child
83
+ end
84
+
85
+ def to_ruby
86
+ deserialize
87
+ end
88
+
89
+ protected
90
+ def root_node
91
+ @xml_doc.root
92
+ end
93
+
94
+ def double_as_bigdecimal?
95
+ !!self.class.double_as_bigdecimal
96
+ end
97
+
98
+ def hash_keys_as_string?
99
+ !!self.class.hash_keys_as_string
100
+ end
101
+
102
+ class << self
103
+ attr_accessor :double_as_bigdecimal, :hash_keys_as_string
104
+
105
+ def [] xml
106
+ new(xml).to_ruby
107
+ end
108
+ end
109
+ end
110
+ end
@@ -0,0 +1,148 @@
1
+ require 'bigdecimal'
2
+ require 'time'
3
+
4
+ module Rapuncel
5
+ class XmlRpcSerializer
6
+ XML_ENCODING = 'UTF-8'
7
+
8
+ attr_reader :builder
9
+
10
+ def initialize object
11
+ @builder = Nokogiri::XML::Builder.new :encoding => XML_ENCODING
12
+
13
+ serialize object
14
+ end
15
+
16
+ def serialize object
17
+ case object
18
+ when Base64String
19
+ serialize_base64 object
20
+ when Array
21
+ serialize_array object
22
+ when String, Symbol
23
+ serialize_string object.to_s
24
+ when TrueClass
25
+ serialize_true
26
+ when FalseClass
27
+ serialize_false
28
+ when Float
29
+ serialize_float object
30
+ when BigDecimal
31
+ serialize_big_decimal object
32
+ when Hash
33
+ serialize_hash object
34
+ when Integer
35
+ serialize_integer object
36
+ when NilClass
37
+ serialize_nil
38
+ when Time
39
+ serialize_time object
40
+ when Request
41
+ serialize_request object
42
+ else
43
+ if object.respond_to?(:acts_like?) && object.acts_like?(:time)
44
+ serialize_time object
45
+ else
46
+ serialize_hash instance_variable_hash(object)
47
+ end
48
+ end
49
+
50
+ self
51
+ end
52
+
53
+ def serialize_base64 string
54
+ builder.base64 string.base64_encoded
55
+ end
56
+
57
+ def serialize_array array
58
+ builder.array do |builder|
59
+ builder.data do |builder|
60
+ array.each do |element|
61
+ builder.value do |_|
62
+ serialize element
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
68
+
69
+ def serialize_string string
70
+ builder.string string
71
+ end
72
+
73
+ def serialize_true
74
+ builder.boolean "1"
75
+ end
76
+
77
+ def serialize_false
78
+ builder.boolean "0"
79
+ end
80
+ alias_method :serialize_nil, :serialize_false
81
+
82
+ def serialize_float float
83
+ builder.double float.to_s
84
+ end
85
+
86
+ def serialize_big_decimal big_decimal
87
+ builder.double big_decimal.to_s("F")
88
+ end
89
+
90
+ def serialize_hash hash
91
+ builder.struct do |builder|
92
+ hash.each_pair do |key, value|
93
+ builder.member do |builder|
94
+ # Get a better string representation of BigDecimals
95
+ key = key.to_s("F") if BigDecimal === key
96
+ builder.name key.to_s
97
+
98
+ builder.value do |builder|
99
+ serialize value
100
+ end
101
+ end
102
+ end
103
+ end
104
+ end
105
+
106
+ def serialize_integer int
107
+ builder.int int.to_s
108
+ end
109
+
110
+ def serialize_time time
111
+ builder.send "dateTime.iso8601", time.iso8601
112
+ end
113
+
114
+ def serialize_request request
115
+ builder.methodCall do |builder|
116
+ builder.methodName request.method_name
117
+ builder.params do |builder|
118
+ request.arguments.each do |argument|
119
+ builder.param do |builder|
120
+ builder.value do |builder|
121
+ serialize argument
122
+ end
123
+ end
124
+ end
125
+ end
126
+ end
127
+ end
128
+
129
+ def to_xml
130
+ @builder.to_xml
131
+ end
132
+
133
+ protected
134
+ def instance_variable_hash object
135
+ {}.tap do |hash|
136
+ object.instance_variables.each do |ivar|
137
+ hash[ivar[1..-1]] = object.instance_variable_get ivar
138
+ end
139
+ end
140
+ end
141
+
142
+ class << self
143
+ def [] object
144
+ new(object).to_xml
145
+ end
146
+ end
147
+ end
148
+ end
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = "rapuncel"
3
- s.version = "0.0.4"
3
+ s.version = "0.0.5.RC1"
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'
@@ -18,5 +18,6 @@ Gem::Specification.new do |s|
18
18
  s.add_dependency 'nokogiri'
19
19
  s.add_dependency 'activesupport', '>= 3.0.0'
20
20
 
21
- s.add_development_dependency 'mocha'
21
+ s.add_development_dependency 'rspec', '>= 2.6.0'
22
+ s.add_development_dependency 'rake'
22
23
  end
@@ -0,0 +1,53 @@
1
+ require 'spec_helper'
2
+
3
+ describe Rapuncel::Client do
4
+ it 'simple XMLRPC' do
5
+ client = Rapuncel::Client.new :port => 9485
6
+ proxy = client.proxy_for 'num'
7
+
8
+ proxy.add(40, 2).should == 42
9
+ end
10
+
11
+ it 'fault XMLRPC without raising' do
12
+ client = Rapuncel::Client.new :port => 9485
13
+ proxy = client.proxy_for 'num'
14
+
15
+ lambda do
16
+ proxy.add 20, 20, 2
17
+ end.should_not raise_error Rapuncel::Response::Exception
18
+
19
+
20
+ proxy.add(20, 20, 2).should be_a Hash
21
+ end
22
+
23
+ it 'fault XMLRPC with raising' do
24
+ client = Rapuncel::Client.new :port => 9485, :raise_on => :both
25
+ proxy = client.proxy_for 'num'
26
+
27
+ lambda do
28
+ proxy.add 20, 20, 2
29
+ end.should raise_error Rapuncel::Response::Fault
30
+ end
31
+
32
+ it 'error in connection without raising' do
33
+ client = Rapuncel::Client.new :host => 'www.google.de', :port => 80, :path => '/somefoobarurl'
34
+ proxy = client.proxy
35
+
36
+ lambda do
37
+ proxy.foo :bar, :baz
38
+ end.should_not raise_error Rapuncel::Response::Error
39
+
40
+ err = proxy.foo(:bar, :baz)
41
+ err.should be_a Hash
42
+ err[:http_code].should == 404
43
+ end
44
+
45
+ it 'error in connection with raising' do
46
+ client = Rapuncel::Client.new :host => 'www.google.de', :port => 80, :path => '/somefoobarurl', :raise_on => :both
47
+ proxy = client.proxy
48
+
49
+ lambda do
50
+ proxy.foo :bar
51
+ end.should raise_error Rapuncel::Response::Error
52
+ end
53
+ end
@@ -0,0 +1,48 @@
1
+ require 'rubygems'
2
+ require 'bundler/setup'
3
+
4
+ require 'nokogiri'
5
+ require 'rapuncel'
6
+ require 'test_server'
7
+
8
+ module SpecHelper
9
+ def anythings count
10
+ [anything] * count
11
+ end
12
+ end
13
+
14
+ RSpec.configure do |config|
15
+ config.before :all do
16
+ @server = TestServer.new
17
+ @server.start
18
+ end
19
+
20
+ config.after :all do
21
+ @server.stop
22
+ end
23
+ end
24
+
25
+ String.class_eval do
26
+ def has_xpath? xpath, options = {}
27
+ eq = options[:content]
28
+ count = options[:count] || 1
29
+ doc = Nokogiri::XML.parse self, nil, nil, Nokogiri::XML::ParseOptions::STRICT
30
+ res = doc.xpath xpath
31
+
32
+ unless eq
33
+ res.size.should == count
34
+ else
35
+ eq = eq.strip
36
+
37
+ if count
38
+ res.to_a.select{ |node|
39
+ node.text.strip == eq
40
+ }.size.should == count
41
+ else
42
+ res.to_a.all?{ |node|
43
+ node.text.strip == eq
44
+ }.should == true
45
+ end
46
+ end
47
+ end
48
+ end
@@ -1,6 +1,5 @@
1
1
  require "xmlrpc/server"
2
2
  require 'rubygems'
3
- require 'faker'
4
3
 
5
4
  class Num
6
5
  INTERFACE = XMLRPC::interface("num") {
@@ -0,0 +1,41 @@
1
+ require 'spec_helper'
2
+
3
+ describe Array do
4
+ describe "Serialization" do
5
+ before do
6
+ @array = (1..10).to_a.map &:to_s
7
+
8
+ @xml = Rapuncel::XmlRpcSerializer[@array]
9
+ end
10
+
11
+ it "yields a value tag for each array element" do
12
+ @xml.should have_xpath('/array/data/value', :count => 10)
13
+ end
14
+
15
+ it "preserves the element order" do
16
+ @xml.should have_xpath('/array/data/value[4]/string', :content => "4")
17
+ @xml.should have_xpath('/array/data/value[5]/string', :content => "5")
18
+ end
19
+ end
20
+
21
+ describe "Deserialization" do
22
+ before do
23
+ @xml = <<-XML
24
+ <array><data>
25
+ <value><string>1</string></value>
26
+ <value><string>2</string></value>
27
+ <value><string>3</string></value>
28
+ </data></array>
29
+ XML
30
+ @array = Rapuncel::XmlRpcDeserializer[@xml]
31
+ end
32
+
33
+ it 'has correct number of elements' do
34
+ @array.count.should == 3
35
+ end
36
+
37
+ it 'preserves element order' do
38
+ @array.should == ["1", "2", "3"]
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,30 @@
1
+ require 'spec_helper'
2
+
3
+ describe "Base64" do
4
+ def to_base64 string
5
+ if RUBY_VERSION =~ /^1\.9/
6
+ [string].pack('m')
7
+ else
8
+ require 'base64'
9
+ Base64.encode64(string)
10
+ end
11
+ end
12
+
13
+ it 'should encode Base64 marked strings as Base64' do
14
+ string = "abcdefghABCDEFGH1234567890".as_base64
15
+ string.should be_a Rapuncel::Base64String
16
+
17
+ xml = Rapuncel::XmlRpcSerializer[string]
18
+ xml.should have_xpath('/base64', :content => to_base64(string))
19
+ end
20
+
21
+ it 'should decode base64 as Base64Strings' do
22
+ xml = <<-XML
23
+ <base64>YWJjZGVmZ2hBQkNERUZHSDEyMzQ1Njc4OTA=</base64>
24
+ XML
25
+
26
+ string = Rapuncel::XmlRpcDeserializer[xml]
27
+ string.should be_a Rapuncel::Base64String
28
+ string.should == "abcdefghABCDEFGH1234567890"
29
+ end
30
+ end