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
data/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  # Rapuncel - Simple XML-RPC Client
2
2
 
3
- Rapuncel ([wikipedia](http://en.wikipedia.org/wiki/Rapunzel)) is a simple and lightweight, but fast XML-RPC client library for ruby.
4
- It's based on Nokogiri for XML parsing and thus provides a major performance improvement for large XML responses.
3
+ Rapuncel ([wikipedia](http://en.wikipedia.org/wiki/Rapunzel)) is a simple and lightweight, but fast XML-RPC client library for ruby.
4
+ It's based on Nokogiri for XML parsing and thus provides a major performance improvement for large XML responses.
5
5
 
6
6
  ## Installation
7
7
 
@@ -9,18 +9,18 @@ It's based on Nokogiri for XML parsing and thus provides a major performance imp
9
9
  Add this to your Gemfile:
10
10
 
11
11
  gem 'rapuncel'
12
-
13
- Run
12
+
13
+ Run
14
14
 
15
15
  bundle install
16
-
17
- and you're good to go.
18
-
16
+
17
+ and you're good to go.
18
+
19
19
  ### Other Ruby / IRB
20
20
  Install it as gem:
21
21
 
22
22
  gem install rapuncel
23
-
23
+
24
24
  Require **rubygems** and **rapuncel**
25
25
 
26
26
  require 'rubygems'
@@ -34,50 +34,47 @@ object.
34
34
  First you have to create a client with the connection details, e.g.
35
35
 
36
36
  client = Rapuncel::Client.new :host => 'localhost', :port => 8080, :path => '/xmlrpc'
37
-
37
+
38
38
  Available options are:
39
39
 
40
40
  * **host**
41
- hostname or ip-address,
41
+ hostname or ip-address,
42
42
  _default_: localhost
43
43
  * **port**
44
- port where your XMLRPC service is listening,
44
+ port where your XMLRPC service is listening,
45
45
  _default_: 8080
46
46
  * **path**
47
- path to the service,
47
+ path to the service,
48
48
  _default_: /
49
49
  * **user**
50
- Username for HTTP Authentication
50
+ Username for HTTP Authentication
51
51
  _default_: _empty_
52
52
  * **password**
53
- Username for HTTP Authentication
53
+ Username for HTTP Authentication
54
54
  _default_: _empty_
55
55
  * **auth\_method**
56
- HTTP Auth method
56
+ HTTP Auth method
57
57
  _default_: basic **IF** user or password is set
58
58
  * **api\_key**
59
59
  If set, sends all request with a X-ApiKey: _api\_key_ header
60
60
  * **api\_key\_header**
61
- Allows you to modify the header key for API-Key auth
61
+ Allows you to modify the header key for API-Key auth
62
62
  _default_: X-ApiKey
63
- * **raise_on**
64
- Lets you define the behavior on errors or faults, if set to _:fault_, _:error_ or _:both_,
65
- an Exception will be raised if something goes wrong
66
63
 
67
- ### Get a proxy object and ...
64
+ ### Get a proxy object and ...
68
65
  A proxy object receives ruby method calls, redirects them to your XMLRPC service and returns the response as ruby objects!
69
-
66
+
70
67
  proxy = client.proxy
71
-
68
+
72
69
  # suppose your XMLRPC service has a method exposed 'concat_string(string1, string2)'
73
70
  proxy.concat_string "foo", "bar"
74
71
  -> "foobar"
75
-
72
+
76
73
  # if you need to access specific interfaces on your service, e.g. 'string.concat(string1, string2)'
77
74
  proxy = client.proxy_for 'string'
78
75
  proxy.concat 'foo', 'bar'
79
76
  -> 'foobar'
80
-
77
+
81
78
  ## Supported objects
82
79
  Rapuncel supports natively following object-types (and all their subclasses):
83
80
 
@@ -87,7 +84,6 @@ Rapuncel supports natively following object-types (and all their subclasses):
87
84
  * Hash
88
85
  * TrueClass, FalseClass
89
86
  * Float
90
- * BigDecimal (treated like Float)
91
87
  * Time, Time-like objects
92
88
 
93
89
  * Symbols are converted to Strings
@@ -111,33 +107,34 @@ Of course you don't have to delegate to #to\_s, you just can use the Builder obj
111
107
  You can use most methods via
112
108
 
113
109
  proxy.methodname *args
114
-
110
+
115
111
  However methods starting with \_\_, or ending with a bang \! or a question mark ? are not supported. To call those methods you can always
116
112
  use
117
113
 
118
114
  proxy.call! 'methodname', *args
119
-
115
+
120
116
  or via
121
117
 
122
118
  client.call_to_ruby 'methodname', *args
119
+
120
+ note
123
121
 
124
- note
125
-
126
- client.call 'methodname', *args
127
-
122
+ client.call 'methodname', *args
123
+
128
124
  will return a Rapuncel::Response object, use _call\_to\_ruby_ to get standard ruby objects
129
125
 
130
126
  ## Todo ?
131
127
 
132
- * RDoc
133
- * Extensive functional tests
134
- * Async requests
135
128
  * Base64 support (or rather a consistent concept for Base64)
136
129
  * XMLRPC Extensions (pluggable support)
130
+ * RDoc
131
+ * Extensive functional tests
137
132
 
138
133
  ## What happens if something goes wrong?
139
- ### HTTP Errors / XMLRPC Faults
140
- See Usage -> configuration -> raise\_on switch
134
+ ### HTTP Errors
135
+ Any HTTP response but 200 OK will raise an error, containing the returned status code and response body.
136
+ ### XMLRPC Faults
137
+ If the XMLRPC response is 'fault', a Rapuncel::Fault object will be returned, having a _code_ and a _string_ attribute
141
138
  ### Malformed XML/XMLRPC
142
139
  Rapuncel will most likely fail hard.
143
140
 
@@ -19,6 +19,6 @@ Rake::RDocTask.new(:rdoc) do |rdoc|
19
19
  rdoc.rdoc_dir = 'rdoc'
20
20
  rdoc.title = 'Rapuncel'
21
21
  rdoc.options << '--line-numbers' << '--inline-source'
22
- rdoc.rdoc_files.include('README.md')
22
+ rdoc.rdoc_files.include('README')
23
23
  rdoc.rdoc_files.include('lib/**/*.rb')
24
24
  end
data/lib/rapuncel.rb CHANGED
@@ -1,4 +1,4 @@
1
-
1
+ require 'builder'
2
2
 
3
3
  require 'active_support/core_ext/hash/keys'
4
4
 
@@ -20,6 +20,5 @@ require 'rapuncel/core_ext/float'
20
20
  require 'rapuncel/core_ext/hash'
21
21
  require 'rapuncel/core_ext/array'
22
22
  require 'rapuncel/core_ext/boolean'
23
- require 'rapuncel/core_ext/nil'
24
23
 
25
24
  require 'rapuncel/core_ext/time'
@@ -5,28 +5,28 @@ module Rapuncel
5
5
  module Adapters
6
6
  module NetHttpAdapter
7
7
  extend ActiveSupport::Memoizable
8
-
8
+
9
9
  class HttpResponse
10
10
  def initialize response
11
11
  @response = response
12
12
  end
13
-
13
+
14
14
  def success?
15
15
  @response.is_a? Net::HTTPOK
16
16
  end
17
-
17
+
18
18
  def body
19
19
  @response.body
20
20
  end
21
-
21
+
22
22
  def code
23
23
  @response.code
24
24
  end
25
25
  end
26
-
26
+
27
27
  def send_method_call str
28
28
  req = Net::HTTP.new connection.host, connection.port
29
-
29
+
30
30
  HttpResponse.new req.post(connection.path, str, connection.headers.stringify_keys)
31
31
  end
32
32
  end
@@ -0,0 +1,33 @@
1
+ require 'typhoeus'
2
+ require 'active_support/memoizable'
3
+
4
+ module Rapuncel
5
+ module Adapters
6
+ module TyphoeusAdapter
7
+ extend ActiveSupport::Memoizable
8
+
9
+
10
+ def send_method_call str
11
+ Typhoeus::Request.post connection.url, typhoeus_params.merge(:body => str)
12
+ end
13
+
14
+ protected
15
+ def typhoeus_params
16
+ {
17
+ :headers => connection.headers
18
+ }.merge auth_params
19
+ end
20
+ memoize :typhoeus_params
21
+
22
+ def auth_params
23
+ return {} unless connection.http_auth?
24
+
25
+ {
26
+ :user => connection.user,
27
+ :password => connection.password,
28
+ :auth_method => connection.auth_method
29
+ }
30
+ end
31
+ end
32
+ end
33
+ end
data/lib/rapuncel/base.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  module Rapuncel
2
- BUILDER_OPTIONS = {:encoding => 'UTF-8'}
2
+ BUILDER_OPTIONS = {}
3
3
 
4
4
  def self.get_builder options = {}
5
- Nokogiri::XML::Builder.new options
5
+ Builder::XmlMarkup.new BUILDER_OPTIONS.merge(options)
6
6
  end
7
7
  end
@@ -1,34 +1,28 @@
1
+ # require 'rapuncel/adapters/typhoeus_adapter'
1
2
  require 'rapuncel/adapters/net_http_adapter'
2
3
  require 'rapuncel/connection'
3
- require 'active_support/core_ext/hash/except'
4
+
4
5
 
5
6
  module Rapuncel
6
7
  class Client
7
- attr_accessor :connection, :raise_on_fault, :raise_on_error
8
+ attr_accessor :connection
8
9
 
9
10
  include Adapters::NetHttpAdapter
10
11
 
11
12
  def proxy_for interface
12
13
  Proxy.new self, interface
13
14
  end
14
-
15
+
15
16
  def proxy
16
17
  proxy_for nil
17
18
  end
18
19
 
19
20
  def initialize configuration = {}
20
- @connection = Connection.build configuration.except(:raise_on)
21
+ @connection = init_connection(configuration)
22
+ end
21
23
 
22
- @raise_on_fault, @raise_on_error = case configuration[:raise_on]
23
- when :fault
24
- [true, false]
25
- when :error
26
- [false, true]
27
- when :both
28
- [true, true]
29
- else
30
- [false, false]
31
- end
24
+ def init_connection configuration = {}
25
+ Connection.build configuration
32
26
  end
33
27
 
34
28
  def call name, *args
@@ -36,18 +30,16 @@ module Rapuncel
36
30
  end
37
31
 
38
32
  def call_to_ruby name, *args
39
- response = call name, *args
40
-
41
- raise_on_fault && response.fault? && raise(response.fault)
42
- raise_on_error && response.error? && raise(response.error)
33
+ call(name, *args).to_ruby
34
+ end
43
35
 
44
- response.to_ruby
36
+ def execute_to_ruby request
37
+ execute(request).to_ruby
45
38
  end
46
39
 
47
- protected
48
40
  def execute request
49
41
  xml = request.to_xml_rpc
50
-
42
+
51
43
  Response.new send_method_call(xml)
52
44
  end
53
45
  end
@@ -17,7 +17,7 @@ module Rapuncel
17
17
  alias_method :ssl?, :ssl
18
18
 
19
19
  def initialize configuration = {}
20
-
20
+
21
21
  @host = configuration[:host] || 'localhost'
22
22
  @port = configuration[:port] || '8080'
23
23
  @path = configuration[:path] || '/'
@@ -33,7 +33,7 @@ module Rapuncel
33
33
  def url
34
34
  "http://#{host}:#{port}#{path}"
35
35
  end
36
-
36
+
37
37
  def headers
38
38
  @headers.merge :Accept => 'text/xml', :'content-type' => 'text/xml'
39
39
  end
@@ -1,23 +1,30 @@
1
+ require 'builder'
2
+ require 'nokogiri'
3
+
1
4
  class Array
5
+
2
6
  def to_xml_rpc b = Rapuncel.get_builder
3
- b.array do |b|
4
- b.data do |b|
7
+
8
+ b.array do
9
+ b.data do
5
10
  each do |array_entry|
6
- b.value do |b|
11
+ b.value do
7
12
  array_entry.to_xml_rpc b
8
13
  end
9
14
  end
10
15
  end
11
16
  end
12
-
13
- b.to_xml
14
17
  end
15
-
18
+
19
+
16
20
  def self.from_xml_rpc xml_node
17
- values = xml_node.first_element_child.element_children
18
-
21
+ #warn "Warning: This is not an array-node (It is a(n) #{xml_node.name}.). Parsing may go wrong. Continuing at your risk" unless ['array'].include? xml_node.name.downcase
22
+
23
+
24
+ values = xml_node.first_element_child.element_children #xpath('./data/value/*')
25
+
19
26
  values.map do |value|
20
27
  Object.from_xml_rpc value.first_element_child
21
- end
28
+ end
22
29
  end
23
30
  end
@@ -1,7 +0,0 @@
1
- class BigDecimal
2
- def to_xml_rpc b = Rapuncel.get_builder
3
- b.double self.to_s
4
-
5
- b.to_xml
6
- end
7
- end
@@ -1,29 +1,32 @@
1
+ require 'builder'
2
+ require 'nokogiri'
3
+
1
4
  class TrueClass
5
+
2
6
  def to_xml_rpc b = Rapuncel.get_builder
3
7
  b.boolean "1"
4
-
5
- b.to_xml
6
8
  end
7
9
  end
8
10
 
11
+
9
12
  class FalseClass
13
+
10
14
  def to_xml_rpc b = Rapuncel.get_builder
11
15
  b.boolean "0"
12
-
13
- b.to_xml
14
16
  end
15
17
  end
16
18
 
17
- # this is to catch the from_xml_rpc call from Object
18
- class Rapuncel::Boolean
19
- def self.from_xml_rpc xml_node
20
19
 
21
- # DISCUSS: need convention here:
20
+ class Rapuncel::Boolean #this is to catch the from_xml_rpc call from Object
21
+ def self.from_xml_rpc xml_node
22
+ #warn "This node is not boolean (it is #{xml_node.name}), but will be treated as one at your request. keep in mind that 1 means true and all the rest will be false" unless ['boolean'].include? xml_node.name.downcase
23
+
24
+ #need convention here:
22
25
  case xml_node.text.downcase
23
26
  when '1'
24
27
  true
25
28
  else
26
29
  false
27
- end
28
- end
30
+ end
31
+ end
29
32
  end
@@ -1,11 +1,14 @@
1
+ require 'builder'
2
+ require 'nokogiri'
3
+
1
4
  class Float
2
5
  def self.from_xml_rpc xml_node
3
- xml_node.text.strip.to_f #calling to_float on the text between the (hopefully correct) tags
6
+ #warn "Node given (name of #{xml_node.name}) is not a 'double' node, name should be 'double'. Will still parse, at your risk." unless ['double'].include? xml_node.name.downcase
7
+
8
+ xml_node.text.to_f #calling to_float on the text between the (hopefully correct) tags
4
9
  end
5
-
10
+
6
11
  def to_xml_rpc b = Rapuncel.get_builder
7
12
  b.double to_s
8
-
9
- b.to_xml
10
13
  end
11
14
  end