keshav-actionwebservice 1.0.0

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 (79) hide show
  1. data/CHANGELOG +3 -0
  2. data/MIT-LICENSE +21 -0
  3. data/README +381 -0
  4. data/Rakefile +180 -0
  5. data/TODO +32 -0
  6. data/examples/googlesearch/README +143 -0
  7. data/examples/googlesearch/autoloading/google_search_api.rb +50 -0
  8. data/examples/googlesearch/autoloading/google_search_controller.rb +57 -0
  9. data/examples/googlesearch/delegated/google_search_service.rb +108 -0
  10. data/examples/googlesearch/delegated/search_controller.rb +7 -0
  11. data/examples/googlesearch/direct/google_search_api.rb +50 -0
  12. data/examples/googlesearch/direct/search_controller.rb +58 -0
  13. data/examples/metaWeblog/README +17 -0
  14. data/examples/metaWeblog/apis/blogger_api.rb +60 -0
  15. data/examples/metaWeblog/apis/blogger_service.rb +34 -0
  16. data/examples/metaWeblog/apis/meta_weblog_api.rb +67 -0
  17. data/examples/metaWeblog/apis/meta_weblog_service.rb +48 -0
  18. data/examples/metaWeblog/controllers/xmlrpc_controller.rb +16 -0
  19. data/generators/web_service/USAGE +28 -0
  20. data/generators/web_service/templates/api_definition.rb +5 -0
  21. data/generators/web_service/templates/controller.rb +8 -0
  22. data/generators/web_service/templates/functional_test.rb +19 -0
  23. data/generators/web_service/web_service_generator.rb +29 -0
  24. data/lib/action_web_service.rb +66 -0
  25. data/lib/action_web_service/api.rb +297 -0
  26. data/lib/action_web_service/base.rb +38 -0
  27. data/lib/action_web_service/casting.rb +149 -0
  28. data/lib/action_web_service/client.rb +3 -0
  29. data/lib/action_web_service/client/base.rb +28 -0
  30. data/lib/action_web_service/client/soap_client.rb +113 -0
  31. data/lib/action_web_service/client/xmlrpc_client.rb +58 -0
  32. data/lib/action_web_service/container.rb +3 -0
  33. data/lib/action_web_service/container/action_controller_container.rb +94 -0
  34. data/lib/action_web_service/container/delegated_container.rb +86 -0
  35. data/lib/action_web_service/container/direct_container.rb +69 -0
  36. data/lib/action_web_service/dispatcher.rb +2 -0
  37. data/lib/action_web_service/dispatcher/abstract.rb +207 -0
  38. data/lib/action_web_service/dispatcher/action_controller_dispatcher.rb +379 -0
  39. data/lib/action_web_service/invocation.rb +202 -0
  40. data/lib/action_web_service/protocol.rb +4 -0
  41. data/lib/action_web_service/protocol/abstract.rb +112 -0
  42. data/lib/action_web_service/protocol/discovery.rb +37 -0
  43. data/lib/action_web_service/protocol/soap_protocol.rb +176 -0
  44. data/lib/action_web_service/protocol/soap_protocol/marshaler.rb +242 -0
  45. data/lib/action_web_service/protocol/xmlrpc_protocol.rb +122 -0
  46. data/lib/action_web_service/scaffolding.rb +281 -0
  47. data/lib/action_web_service/struct.rb +64 -0
  48. data/lib/action_web_service/support/class_inheritable_options.rb +26 -0
  49. data/lib/action_web_service/support/signature_types.rb +227 -0
  50. data/lib/action_web_service/templates/scaffolds/layout.html.erb +65 -0
  51. data/lib/action_web_service/templates/scaffolds/methods.html.erb +6 -0
  52. data/lib/action_web_service/templates/scaffolds/parameters.html.erb +29 -0
  53. data/lib/action_web_service/templates/scaffolds/result.html.erb +30 -0
  54. data/lib/action_web_service/test_invoke.rb +110 -0
  55. data/lib/action_web_service/version.rb +9 -0
  56. data/lib/actionwebservice.rb +1 -0
  57. data/setup.rb +1379 -0
  58. data/test/abstract_client.rb +183 -0
  59. data/test/abstract_dispatcher.rb +548 -0
  60. data/test/abstract_unit.rb +43 -0
  61. data/test/api_test.rb +102 -0
  62. data/test/apis/auto_load_api.rb +3 -0
  63. data/test/apis/broken_auto_load_api.rb +2 -0
  64. data/test/base_test.rb +42 -0
  65. data/test/casting_test.rb +95 -0
  66. data/test/client_soap_test.rb +155 -0
  67. data/test/client_xmlrpc_test.rb +153 -0
  68. data/test/container_test.rb +73 -0
  69. data/test/dispatcher_action_controller_soap_test.rb +139 -0
  70. data/test/dispatcher_action_controller_xmlrpc_test.rb +59 -0
  71. data/test/fixtures/db_definitions/mysql.sql +8 -0
  72. data/test/fixtures/users.yml +12 -0
  73. data/test/gencov +3 -0
  74. data/test/invocation_test.rb +185 -0
  75. data/test/run +6 -0
  76. data/test/scaffolded_controller_test.rb +146 -0
  77. data/test/struct_test.rb +52 -0
  78. data/test/test_invoke_test.rb +112 -0
  79. metadata +145 -0
@@ -0,0 +1,64 @@
1
+ module ActionWebService
2
+ # To send structured types across the wire, derive from ActionWebService::Struct,
3
+ # and use +member+ to declare structure members.
4
+ #
5
+ # ActionWebService::Struct should be used in method signatures when you want to accept or return
6
+ # structured types that have no Active Record model class representations, or you don't
7
+ # want to expose your entire Active Record model to remote callers.
8
+ #
9
+ # === Example
10
+ #
11
+ # class Person < ActionWebService::Struct
12
+ # member :id, :int
13
+ # member :firstnames, [:string]
14
+ # member :lastname, :string
15
+ # member :email, :string
16
+ # end
17
+ # person = Person.new(:id => 5, :firstname => 'john', :lastname => 'doe')
18
+ #
19
+ # Active Record model classes are already implicitly supported in method
20
+ # signatures.
21
+ class Struct
22
+ # If a Hash is given as argument to an ActionWebService::Struct constructor,
23
+ # it can contain initial values for the structure member.
24
+ def initialize(values={})
25
+ if values.is_a?(Hash)
26
+ values.map{|k,v| __send__('%s=' % k.to_s, v)}
27
+ end
28
+ end
29
+
30
+ # The member with the given name
31
+ def [](name)
32
+ send(name.to_s)
33
+ end
34
+
35
+ # Iterates through each member
36
+ def each_pair(&block)
37
+ self.class.members.each do |name, type|
38
+ yield name, self.__send__(name)
39
+ end
40
+ end
41
+
42
+ class << self
43
+ # Creates a structure member with the specified +name+ and +type+. Generates
44
+ # accessor methods for reading and writing the member value.
45
+ def member(name, type)
46
+ name = name.to_sym
47
+ type = ActionWebService::SignatureTypes.canonical_signature_entry({ name => type }, 0)
48
+ write_inheritable_hash("struct_members", name => type)
49
+ class_eval <<-END
50
+ def #{name}; @#{name}; end
51
+ def #{name}=(value); @#{name} = value; end
52
+ END
53
+ end
54
+
55
+ def members # :nodoc:
56
+ read_inheritable_attribute("struct_members") || {}
57
+ end
58
+
59
+ def member_type(name) # :nodoc:
60
+ members[name.to_sym]
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,26 @@
1
+ class Class # :nodoc:
2
+ def class_inheritable_option(sym, default_value=nil)
3
+ write_inheritable_attribute sym, default_value
4
+ class_eval <<-EOS
5
+ def self.#{sym}(value=nil)
6
+ if !value.nil?
7
+ write_inheritable_attribute(:#{sym}, value)
8
+ else
9
+ read_inheritable_attribute(:#{sym})
10
+ end
11
+ end
12
+
13
+ def self.#{sym}=(value)
14
+ write_inheritable_attribute(:#{sym}, value)
15
+ end
16
+
17
+ def #{sym}
18
+ self.class.#{sym}
19
+ end
20
+
21
+ def #{sym}=(value)
22
+ self.class.#{sym} = value
23
+ end
24
+ EOS
25
+ end
26
+ end
@@ -0,0 +1,227 @@
1
+ module ActionWebService # :nodoc:
2
+ # Action Web Service supports the following base types in a signature:
3
+ #
4
+ # [<tt>:int</tt>] Represents an integer value, will be cast to an integer using <tt>Integer(value)</tt>
5
+ # [<tt>:string</tt>] Represents a string value, will be cast to an string using the <tt>to_s</tt> method on an object
6
+ # [<tt>:base64</tt>] Represents a Base 64 value, will contain the binary bytes of a Base 64 value sent by the caller
7
+ # [<tt>:bool</tt>] Represents a boolean value, whatever is passed will be cast to boolean (<tt>true</tt>, '1', 'true', 'y', 'yes' are taken to represent true; <tt>false</tt>, '0', 'false', 'n', 'no' and <tt>nil</tt> represent false)
8
+ # [<tt>:float</tt>] Represents a floating point value, will be cast to a float using <tt>Float(value)</tt>
9
+ # [<tt>:time</tt>] Represents a timestamp, will be cast to a <tt>Time</tt> object
10
+ # [<tt>:datetime</tt>] Represents a timestamp, will be cast to a <tt>DateTime</tt> object
11
+ # [<tt>:date</tt>] Represents a date, will be cast to a <tt>Date</tt> object
12
+ #
13
+ # For structured types, you'll need to pass in the Class objects of
14
+ # ActionWebService::Struct and ActiveRecord::Base derivatives.
15
+ module SignatureTypes
16
+ def canonical_signature(signature) # :nodoc:
17
+ return nil if signature.nil?
18
+ unless signature.is_a?(Array)
19
+ raise(ActionWebServiceError, "Expected signature to be an Array")
20
+ end
21
+ i = -1
22
+ signature.map{ |spec| canonical_signature_entry(spec, i += 1) }
23
+ end
24
+
25
+ def canonical_signature_entry(spec, i) # :nodoc:
26
+ orig_spec = spec
27
+ name = "param#{i}"
28
+ if spec.is_a?(Hash)
29
+ name, spec = spec.keys.first, spec.values.first
30
+ end
31
+ type = spec
32
+ if spec.is_a?(Array)
33
+ ArrayType.new(orig_spec, canonical_signature_entry(spec[0], 0), name)
34
+ else
35
+ type = canonical_type(type)
36
+ if type.is_a?(Symbol)
37
+ BaseType.new(orig_spec, type, name)
38
+ else
39
+ StructuredType.new(orig_spec, type, name)
40
+ end
41
+ end
42
+ end
43
+
44
+ def canonical_type(type) # :nodoc:
45
+ type_name = symbol_name(type) || class_to_type_name(type)
46
+ type = type_name || type
47
+ return canonical_type_name(type) if type.is_a?(Symbol)
48
+ type
49
+ end
50
+
51
+ def canonical_type_name(name) # :nodoc:
52
+ name = name.to_sym
53
+ case name
54
+ when :int, :integer, :fixnum, :bignum
55
+ :int
56
+ when :string, :text
57
+ :string
58
+ when :base64, :binary
59
+ :base64
60
+ when :bool, :boolean
61
+ :bool
62
+ when :float, :double
63
+ :float
64
+ when :decimal
65
+ :decimal
66
+ when :time, :timestamp
67
+ :time
68
+ when :datetime
69
+ :datetime
70
+ when :date
71
+ :date
72
+ else
73
+ raise(TypeError, "#{name} is not a valid base type")
74
+ end
75
+ end
76
+
77
+ def canonical_type_class(type) # :nodoc:
78
+ type = canonical_type(type)
79
+ type.is_a?(Symbol) ? type_name_to_class(type) : type
80
+ end
81
+
82
+ def symbol_name(name) # :nodoc:
83
+ return name.to_sym if name.is_a?(Symbol) || name.is_a?(String)
84
+ nil
85
+ end
86
+
87
+ def class_to_type_name(klass) # :nodoc:
88
+ klass = klass.class unless klass.is_a?(Class)
89
+ if derived_from?(Integer, klass) || derived_from?(Fixnum, klass) || derived_from?(Bignum, klass)
90
+ :int
91
+ elsif klass == String
92
+ :string
93
+ elsif klass == Base64
94
+ :base64
95
+ elsif klass == TrueClass || klass == FalseClass
96
+ :bool
97
+ #elsif derived_from?(Float, klass) || derived_from?(Precision, klass) || derived_from?(Numeric, klass)
98
+ elsif derived_from?(Float, klass) || derived_from?(Numeric, klass)
99
+ :float
100
+ elsif klass == Time
101
+ :time
102
+ elsif klass == DateTime
103
+ :datetime
104
+ elsif klass == Date
105
+ :date
106
+ else
107
+ nil
108
+ end
109
+ end
110
+
111
+ def type_name_to_class(name) # :nodoc:
112
+ case canonical_type_name(name)
113
+ when :int
114
+ Integer
115
+ when :string
116
+ String
117
+ when :base64
118
+ Base64
119
+ when :bool
120
+ TrueClass
121
+ when :float
122
+ Float
123
+ when :decimal
124
+ BigDecimal
125
+ when :time
126
+ Time
127
+ when :date
128
+ Date
129
+ when :datetime
130
+ DateTime
131
+ else
132
+ nil
133
+ end
134
+ end
135
+
136
+ def derived_from?(ancestor, child) # :nodoc:
137
+ child.ancestors.include?(ancestor)
138
+ end
139
+
140
+ module_function :type_name_to_class
141
+ module_function :class_to_type_name
142
+ module_function :symbol_name
143
+ module_function :canonical_type_class
144
+ module_function :canonical_type_name
145
+ module_function :canonical_type
146
+ module_function :canonical_signature_entry
147
+ module_function :canonical_signature
148
+ module_function :derived_from?
149
+ end
150
+
151
+ class BaseType # :nodoc:
152
+ include SignatureTypes
153
+
154
+ attr :spec
155
+ attr :type
156
+ attr :type_class
157
+ attr :name
158
+
159
+ def initialize(spec, type, name)
160
+ @spec = spec
161
+ @type = canonical_type(type)
162
+ @type_class = canonical_type_class(@type)
163
+ @name = name
164
+ end
165
+
166
+ def custom?
167
+ false
168
+ end
169
+
170
+ def array?
171
+ false
172
+ end
173
+
174
+ def structured?
175
+ false
176
+ end
177
+
178
+ def human_name(show_name=true)
179
+ type_type = array? ? element_type.type.to_s : self.type.to_s
180
+ str = array? ? (type_type + '[]') : type_type
181
+ show_name ? (str + " " + name.to_s) : str
182
+ end
183
+ end
184
+
185
+ class ArrayType < BaseType # :nodoc:
186
+ attr :element_type
187
+
188
+ def initialize(spec, element_type, name)
189
+ super(spec, Array, name)
190
+ @element_type = element_type
191
+ end
192
+
193
+ def custom?
194
+ true
195
+ end
196
+
197
+ def array?
198
+ true
199
+ end
200
+ end
201
+
202
+ class StructuredType < BaseType # :nodoc:
203
+ def each_member
204
+ if @type_class.respond_to?(:members)
205
+ @type_class.members.each do |name, type|
206
+ yield name, type
207
+ end
208
+ elsif @type_class.respond_to?(:columns)
209
+ i = -1
210
+ @type_class.columns.each do |column|
211
+ yield column.name, canonical_signature_entry(column.type, i += 1)
212
+ end
213
+ end
214
+ end
215
+
216
+ def custom?
217
+ true
218
+ end
219
+
220
+ def structured?
221
+ true
222
+ end
223
+ end
224
+
225
+ class Base64 < String # :nodoc:
226
+ end
227
+ end
@@ -0,0 +1,65 @@
1
+ <html>
2
+ <head>
3
+ <title><%= @scaffold_class.wsdl_service_name %> Web Service</title>
4
+ <style>
5
+ body { background-color: #fff; color: #333; }
6
+
7
+ body, p, ol, ul, td {
8
+ font-family: verdana, arial, helvetica, sans-serif;
9
+ font-size: 13px;
10
+ line-height: 18px;
11
+ }
12
+
13
+ pre {
14
+ background-color: #eee;
15
+ padding: 10px;
16
+ font-size: 11px;
17
+ }
18
+
19
+ a { color: #000; }
20
+ a:visited { color: #666; }
21
+ a:hover { color: #fff; background-color:#000; }
22
+
23
+ .fieldWithErrors {
24
+ padding: 2px;
25
+ background-color: red;
26
+ display: table;
27
+ }
28
+
29
+ #errorExplanation {
30
+ width: 400px;
31
+ border: 2px solid red;
32
+ padding: 7px;
33
+ padding-bottom: 12px;
34
+ margin-bottom: 20px;
35
+ background-color: #f0f0f0;
36
+ }
37
+
38
+ #errorExplanation h2 {
39
+ text-align: left;
40
+ font-weight: bold;
41
+ padding: 5px 5px 5px 15px;
42
+ font-size: 12px;
43
+ margin: -7px;
44
+ background-color: #c00;
45
+ color: #fff;
46
+ }
47
+
48
+ #errorExplanation p {
49
+ color: #333;
50
+ margin-bottom: 0;
51
+ padding: 5px;
52
+ }
53
+
54
+ #errorExplanation ul li {
55
+ font-size: 12px;
56
+ list-style: square;
57
+ }
58
+ </style>
59
+ </head>
60
+ <body>
61
+
62
+ <%= @content_for_layout %>
63
+
64
+ </body>
65
+ </html>
@@ -0,0 +1,6 @@
1
+ <% @scaffold_container.services.each do |service| %>
2
+
3
+ <h4>API Methods for <%= service %></h4>
4
+ <%= service_method_list(service) %>
5
+
6
+ <% end %>
@@ -0,0 +1,29 @@
1
+ <h4>Method Invocation Details for <em><%= @scaffold_service %>#<%= @scaffold_method.public_name %></em></h4>
2
+
3
+ <% form_tag(:action => @scaffold_action_name + '_submit') do -%>
4
+ <%= hidden_field_tag "service", @scaffold_service.name %>
5
+ <%= hidden_field_tag "method", @scaffold_method.public_name %>
6
+
7
+ <p>
8
+ <label for="protocol">Protocol:</label><br />
9
+ <%= select_tag 'protocol', options_for_select([['SOAP', 'soap'], ['XML-RPC', 'xmlrpc']], params['protocol']) %>
10
+ </p>
11
+
12
+ <% if @scaffold_method.expects %>
13
+
14
+ <strong>Method Parameters:</strong><br />
15
+ <% @scaffold_method.expects.each_with_index do |type, i| %>
16
+ <p>
17
+ <label for="method_params[<%= i %>]"><%= method_parameter_label(type.name, type) %> </label><br />
18
+ <%= method_parameter_input_fields(@scaffold_method, type, "method_params", i) %>
19
+ </p>
20
+ <% end %>
21
+
22
+ <% end %>
23
+
24
+ <%= submit_tag "Invoke" %>
25
+ <% end -%>
26
+
27
+ <p>
28
+ <%= link_to "Back", :action => @scaffold_action_name %>
29
+ </p>
@@ -0,0 +1,30 @@
1
+ <h4>Method Invocation Result for <em><%= @scaffold_service %>#<%= @scaffold_method.public_name %></em></h4>
2
+
3
+ <p>
4
+ Invocation took <tt><%= '%f' % @method_elapsed %></tt> seconds
5
+ </p>
6
+
7
+ <p>
8
+ <strong>Return Value:</strong><br />
9
+ <pre>
10
+ <%= h @method_return_value.inspect %>
11
+ </pre>
12
+ </p>
13
+
14
+ <p>
15
+ <strong>Request XML:</strong><br />
16
+ <pre>
17
+ <%= h @method_request_xml %>
18
+ </pre>
19
+ </p>
20
+
21
+ <p>
22
+ <strong>Response XML:</strong><br />
23
+ <pre>
24
+ <%= h @method_response_xml %>
25
+ </pre>
26
+ </p>
27
+
28
+ <p>
29
+ <%= link_to "Back", :action => @scaffold_action_name + '_method_params', :method => @scaffold_method.public_name, :service => @scaffold_service.name %>
30
+ </p>