axtro-actionwebservice 2.3.5.1.20101118142125

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 (85) hide show
  1. data/CHANGELOG +335 -0
  2. data/MIT-LICENSE +21 -0
  3. data/README +381 -0
  4. data/Rakefile +184 -0
  5. data/TODO +32 -0
  6. data/examples/googlesearch/README +143 -0
  7. data/examples/googlesearch/autoloading/google_search_api.rb +51 -0
  8. data/examples/googlesearch/autoloading/google_search_controller.rb +58 -0
  9. data/examples/googlesearch/delegated/google_search_service.rb +109 -0
  10. data/examples/googlesearch/delegated/search_controller.rb +8 -0
  11. data/examples/googlesearch/direct/google_search_api.rb +51 -0
  12. data/examples/googlesearch/direct/search_controller.rb +59 -0
  13. data/examples/metaWeblog/README +17 -0
  14. data/examples/metaWeblog/apis/blogger_api.rb +61 -0
  15. data/examples/metaWeblog/apis/blogger_service.rb +35 -0
  16. data/examples/metaWeblog/apis/meta_weblog_api.rb +68 -0
  17. data/examples/metaWeblog/apis/meta_weblog_service.rb +49 -0
  18. data/examples/metaWeblog/controllers/xmlrpc_controller.rb +17 -0
  19. data/generators/web_service/USAGE +28 -0
  20. data/generators/web_service/templates/api_definition.rb +6 -0
  21. data/generators/web_service/templates/controller.rb +9 -0
  22. data/generators/web_service/templates/functional_test.rb +20 -0
  23. data/generators/web_service/web_service_generator.rb +30 -0
  24. data/lib/action_web_service.rb +61 -0
  25. data/lib/action_web_service/acts_as_web_service.rb +26 -0
  26. data/lib/action_web_service/api.rb +298 -0
  27. data/lib/action_web_service/base.rb +39 -0
  28. data/lib/action_web_service/casting.rb +160 -0
  29. data/lib/action_web_service/client.rb +4 -0
  30. data/lib/action_web_service/client/base.rb +29 -0
  31. data/lib/action_web_service/client/soap_client.rb +114 -0
  32. data/lib/action_web_service/client/xmlrpc_client.rb +59 -0
  33. data/lib/action_web_service/container.rb +4 -0
  34. data/lib/action_web_service/container/action_controller_container.rb +94 -0
  35. data/lib/action_web_service/container/delegated_container.rb +87 -0
  36. data/lib/action_web_service/container/direct_container.rb +70 -0
  37. data/lib/action_web_service/dispatcher.rb +3 -0
  38. data/lib/action_web_service/dispatcher/abstract.rb +209 -0
  39. data/lib/action_web_service/dispatcher/action_controller_dispatcher.rb +397 -0
  40. data/lib/action_web_service/invocation.rb +203 -0
  41. data/lib/action_web_service/protocol.rb +5 -0
  42. data/lib/action_web_service/protocol/abstract.rb +113 -0
  43. data/lib/action_web_service/protocol/discovery.rb +38 -0
  44. data/lib/action_web_service/protocol/soap_protocol.rb +177 -0
  45. data/lib/action_web_service/protocol/soap_protocol/marshaler.rb +243 -0
  46. data/lib/action_web_service/protocol/soap_protocol/marshaler.rb~ +243 -0
  47. data/lib/action_web_service/protocol/xmlrpc_protocol.rb +124 -0
  48. data/lib/action_web_service/scaffolding.rb +282 -0
  49. data/lib/action_web_service/simple.rb +54 -0
  50. data/lib/action_web_service/string_to_datetime_for_soap.rb +17 -0
  51. data/lib/action_web_service/struct.rb +69 -0
  52. data/lib/action_web_service/support/class_inheritable_options.rb +27 -0
  53. data/lib/action_web_service/support/signature_types.rb +262 -0
  54. data/lib/action_web_service/templates/scaffolds/layout.html.erb +65 -0
  55. data/lib/action_web_service/templates/scaffolds/methods.html.erb +6 -0
  56. data/lib/action_web_service/templates/scaffolds/parameters.html.erb +29 -0
  57. data/lib/action_web_service/templates/scaffolds/result.html.erb +30 -0
  58. data/lib/action_web_service/test_invoke.rb +111 -0
  59. data/lib/action_web_service/version.rb +11 -0
  60. data/lib/action_web_service/version.rb~ +10 -0
  61. data/lib/actionwebservice.rb +2 -0
  62. data/setup.rb +1380 -0
  63. data/test/abstract_client.rb +185 -0
  64. data/test/abstract_dispatcher.rb +550 -0
  65. data/test/abstract_unit.rb +44 -0
  66. data/test/api_test.rb +103 -0
  67. data/test/apis/auto_load_api.rb +4 -0
  68. data/test/apis/broken_auto_load_api.rb +3 -0
  69. data/test/base_test.rb +43 -0
  70. data/test/casting_test.rb +96 -0
  71. data/test/client_soap_test.rb +157 -0
  72. data/test/client_xmlrpc_test.rb +155 -0
  73. data/test/container_test.rb +76 -0
  74. data/test/dispatcher_action_controller_soap_test.rb +147 -0
  75. data/test/dispatcher_action_controller_xmlrpc_test.rb +60 -0
  76. data/test/fixtures/db_definitions/mysql.sql +8 -0
  77. data/test/fixtures/db_definitions/sqlite3.sql +8 -0
  78. data/test/fixtures/users.yml +12 -0
  79. data/test/gencov +3 -0
  80. data/test/invocation_test.rb +187 -0
  81. data/test/run +6 -0
  82. data/test/scaffolded_controller_test.rb +148 -0
  83. data/test/struct_test.rb +85 -0
  84. data/test/test_invoke_test.rb +114 -0
  85. metadata +167 -0
@@ -0,0 +1,39 @@
1
+ # encoding: UTF-8
2
+ module ActionWebService # :nodoc:
3
+ class ActionWebServiceError < StandardError # :nodoc:
4
+ end
5
+
6
+ # An Action Web Service object implements a specified API.
7
+ #
8
+ # Used by controllers operating in _Delegated_ dispatching mode.
9
+ #
10
+ # ==== Example
11
+ #
12
+ # class PersonService < ActionWebService::Base
13
+ # web_service_api PersonAPI
14
+ #
15
+ # def find_person(criteria)
16
+ # Person.find(:all) [...]
17
+ # end
18
+ #
19
+ # def delete_person(id)
20
+ # Person.find_by_id(id).destroy
21
+ # end
22
+ # end
23
+ #
24
+ # class PersonAPI < ActionWebService::API::Base
25
+ # api_method :find_person, :expects => [SearchCriteria], :returns => [[Person]]
26
+ # api_method :delete_person, :expects => [:int]
27
+ # end
28
+ #
29
+ # class SearchCriteria < ActionWebService::Struct
30
+ # member :firstname, :string
31
+ # member :lastname, :string
32
+ # member :email, :string
33
+ # end
34
+ class Base
35
+ # Whether to report exceptions back to the caller in the protocol's exception
36
+ # format
37
+ class_inheritable_option :web_service_exception_reporting, true
38
+ end
39
+ end
@@ -0,0 +1,160 @@
1
+ # encoding: UTF-8
2
+ require 'time'
3
+ require 'date'
4
+ require 'xmlrpc/datetime'
5
+
6
+ module ActionWebService # :nodoc:
7
+ module Casting # :nodoc:
8
+ class CastingError < ActionWebServiceError # :nodoc:
9
+ end
10
+
11
+ # Performs casting of arbitrary values into the correct types for the signature
12
+ class BaseCaster # :nodoc:
13
+ def initialize(api_method)
14
+ @api_method = api_method
15
+ end
16
+
17
+ # Coerces the parameters in +params+ (an Enumerable) into the types
18
+ # this method expects
19
+ def cast_expects(params)
20
+ self.class.cast_expects(@api_method, params)
21
+ end
22
+
23
+ # Coerces the given +return_value+ into the type returned by this
24
+ # method
25
+ def cast_returns(return_value)
26
+ self.class.cast_returns(@api_method, return_value)
27
+ end
28
+
29
+ class << self
30
+ include ActionWebService::SignatureTypes
31
+
32
+ def cast_expects(api_method, params) # :nodoc:
33
+ return [] if api_method.expects.nil?
34
+ api_method.expects.zip(params).map{ |type, param| cast(param, type) }
35
+ end
36
+
37
+ def cast_returns(api_method, return_value) # :nodoc:
38
+ return nil if api_method.returns.nil?
39
+ cast(return_value, api_method.returns[0])
40
+ end
41
+
42
+ def cast(value, signature_type) # :nodoc:
43
+ return value if signature_type.nil? # signature.length != params.length
44
+ return nil if value.nil?
45
+ # XMLRPC protocol doesn't support nil values. It uses false instead.
46
+ # It should never happen for SOAP.
47
+ if signature_type.structured? && value.equal?(false)
48
+ return nil
49
+ end
50
+ unless signature_type.array? || signature_type.structured?
51
+ return value if canonical_type(value.class) == signature_type.type
52
+ end
53
+ if signature_type.array?
54
+ unless value.respond_to?(:entries) && !value.is_a?(String)
55
+ raise CastingError, "Don't know how to cast #{value.class} into #{signature_type.type.inspect}"
56
+ end
57
+ value.entries.map do |entry|
58
+ cast(entry, signature_type.element_type)
59
+ end
60
+ elsif signature_type.simple?
61
+ return value
62
+ elsif signature_type.structured?
63
+ cast_to_structured_type(value, signature_type)
64
+ elsif !signature_type.custom?
65
+ cast_base_type(value, signature_type)
66
+ end
67
+ end
68
+
69
+ def cast_base_type(value, signature_type) # :nodoc:
70
+ # This is a work-around for the fact that XML-RPC special-cases DateTime values into its own DateTime type
71
+ # in order to support iso8601 dates. This doesn't work too well for us, so we'll convert it into a Time,
72
+ # with the caveat that we won't be able to handle pre-1970 dates that are sent to us.
73
+ #
74
+ # See http://dev.rubyonrails.com/ticket/2516
75
+ value = value.to_time if value.is_a?(XMLRPC::DateTime)
76
+
77
+ case signature_type.type
78
+ when :int
79
+ Integer(value)
80
+ when :string
81
+ value.to_s
82
+ when :base64
83
+ if value.is_a?(ActionWebService::Base64)
84
+ value
85
+ else
86
+ ActionWebService::Base64.new(value.to_s)
87
+ end
88
+ when :bool
89
+ return false if value.nil?
90
+ return value if value == true || value == false
91
+ case value.to_s.downcase
92
+ when '1', 'true', 'y', 'yes'
93
+ true
94
+ when '0', 'false', 'n', 'no'
95
+ false
96
+ else
97
+ raise CastingError, "Don't know how to cast #{value.class} into Boolean"
98
+ end
99
+ when :float
100
+ Float(value)
101
+ when :decimal
102
+ BigDecimal(value.to_s)
103
+ when :time
104
+ if value.kind_of?(Hash)
105
+ value = "%s/%s/%s %s:%s:%s" % value.values_at(*%w[2 3 1 4 5 6])
106
+ Time.respond_to?(:strptime) ? Time.strptime(value.to_s, "%m/%d/%Y %H:%M:%S") : Time.parse(value.to_s)
107
+ elsif value.kind_of?(Time)
108
+ value
109
+ elsif value.kind_of?(DateTime)
110
+ value.to_time
111
+ else
112
+ Time.parse(value.to_s)
113
+ end
114
+ when :date
115
+ if value.kind_of?(Hash)
116
+ value = "%s/%s/%s" % value.values_at(*%w[2 3 1])
117
+ return Date.strptime(value.to_s,"%m/%d/%Y")
118
+ end
119
+ value.kind_of?(Date) ? value : Date.parse(value.to_s)
120
+ when :datetime
121
+ if value.kind_of?(Hash)
122
+ value = "%s/%s/%s %s:%s:%s" % value.values_at(*%w[2 3 1 4 5 6])
123
+ return DateTime.strptime(value.to_s,"%m/%d/%Y %H:%M:%S")
124
+ end
125
+ value.kind_of?(DateTime) ? value : DateTime.parse(value.to_s)
126
+ end
127
+ end
128
+
129
+ def cast_to_structured_type(value, signature_type) # :nodoc:
130
+ obj = nil
131
+ # if the canonical classes are the same or if the given value is of
132
+ # a type that is derived from the signature_type do not attempt to
133
+ # "cast" the value into the signature_type as it's already good to go
134
+ obj = (
135
+ canonical_type(value.class) == canonical_type(signature_type.type) or
136
+ derived_from?(signature_type.type, value.class)
137
+ ) ? value : signature_type.type_class.new
138
+ if value.respond_to?(:each_pair)
139
+ klass = signature_type.type_class
140
+ value.each_pair do |name, val|
141
+ type = klass.respond_to?(:member_type) ? klass.member_type(name) : nil
142
+ val = cast(val, type) if type
143
+ # See http://dev.rubyonrails.com/ticket/3567
144
+ val = val.to_time if val.is_a?(XMLRPC::DateTime)
145
+ obj.__send__("#{name}=", val) if obj.respond_to?(name)
146
+ end
147
+ elsif value.respond_to?(:attributes)
148
+ signature_type.each_member do |name, type|
149
+ val = value.__send__(name)
150
+ obj.__send__("#{name}=", cast(val, type)) if obj.respond_to?(name)
151
+ end
152
+ else
153
+ raise CastingError, "Don't know how to cast #{value.class} to #{signature_type.type_class}"
154
+ end
155
+ obj
156
+ end
157
+ end
158
+ end
159
+ end
160
+ end
@@ -0,0 +1,4 @@
1
+ # encoding: UTF-8
2
+ require 'action_web_service/client/base'
3
+ require 'action_web_service/client/soap_client'
4
+ require 'action_web_service/client/xmlrpc_client'
@@ -0,0 +1,29 @@
1
+ # encoding: UTF-8
2
+ module ActionWebService # :nodoc:
3
+ module Client # :nodoc:
4
+ class ClientError < StandardError # :nodoc:
5
+ end
6
+
7
+ class Base # :nodoc:
8
+ def initialize(api, endpoint_uri)
9
+ @api = api
10
+ @endpoint_uri = endpoint_uri
11
+ end
12
+
13
+ def method_missing(name, *args) # :nodoc:
14
+ call_name = method_name(name)
15
+ return super(name, *args) if call_name.nil?
16
+ self.perform_invocation(call_name, args)
17
+ end
18
+
19
+ private
20
+ def method_name(name)
21
+ if @api.has_api_method?(name.to_sym)
22
+ name.to_s
23
+ elsif @api.has_public_api_method?(name.to_s)
24
+ @api.api_method_name(name.to_s).to_s
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,114 @@
1
+ # encoding: UTF-8
2
+ require 'soap/rpc/driver'
3
+ require 'uri'
4
+
5
+ module ActionWebService # :nodoc:
6
+ module Client # :nodoc:
7
+
8
+ # Implements SOAP client support (using RPC encoding for the messages).
9
+ #
10
+ # ==== Example Usage
11
+ #
12
+ # class PersonAPI < ActionWebService::API::Base
13
+ # api_method :find_all, :returns => [[Person]]
14
+ # end
15
+ #
16
+ # soap_client = ActionWebService::Client::Soap.new(PersonAPI, "http://...")
17
+ # persons = soap_client.find_all
18
+ #
19
+ class Soap < Base
20
+ # provides access to the underlying soap driver
21
+ attr_reader :driver
22
+
23
+ # Creates a new web service client using the SOAP RPC protocol.
24
+ #
25
+ # +api+ must be an ActionWebService::API::Base derivative, and
26
+ # +endpoint_uri+ must point at the relevant URL to which protocol requests
27
+ # will be sent with HTTP POST.
28
+ #
29
+ # Valid options:
30
+ # [<tt>:namespace</tt>] If the remote server has used a custom namespace to
31
+ # declare its custom types, you can specify it here. This would
32
+ # be the namespace declared with a [WebService(Namespace = "http://namespace")] attribute
33
+ # in .NET, for example.
34
+ # [<tt>:driver_options</tt>] If you want to supply any custom SOAP RPC driver
35
+ # options, you can provide them as a Hash here
36
+ #
37
+ # The <tt>:driver_options</tt> option can be used to configure the backend SOAP
38
+ # RPC driver. An example of configuring the SOAP backend to do
39
+ # client-certificate authenticated SSL connections to the server:
40
+ #
41
+ # opts = {}
42
+ # opts['protocol.http.ssl_config.verify_mode'] = 'OpenSSL::SSL::VERIFY_PEER'
43
+ # opts['protocol.http.ssl_config.client_cert'] = client_cert_file_path
44
+ # opts['protocol.http.ssl_config.client_key'] = client_key_file_path
45
+ # opts['protocol.http.ssl_config.ca_file'] = ca_cert_file_path
46
+ # client = ActionWebService::Client::Soap.new(api, 'https://some/service', :driver_options => opts)
47
+ def initialize(api, endpoint_uri, options={})
48
+ super(api, endpoint_uri)
49
+ @namespace = options[:namespace] || 'urn:ActionWebService'
50
+ @driver_options = options[:driver_options] || {}
51
+ @protocol = ActionWebService::Protocol::Soap::SoapProtocol.new @namespace
52
+ @soap_action_base = options[:soap_action_base]
53
+ @soap_action_base ||= URI.parse(endpoint_uri).path
54
+ @driver = create_soap_rpc_driver(api, endpoint_uri)
55
+ @driver_options.each do |name, value|
56
+ @driver.options[name.to_s] = value
57
+ end
58
+ end
59
+
60
+ protected
61
+ def perform_invocation(method_name, args)
62
+ method = @api.api_methods[method_name.to_sym]
63
+ args = method.cast_expects(args.dup) rescue args
64
+ return_value = @driver.send(method_name, *args)
65
+ method.cast_returns(return_value.dup) rescue return_value
66
+ end
67
+
68
+ def soap_action(method_name)
69
+ "#{@soap_action_base}/#{method_name}"
70
+ end
71
+
72
+ private
73
+ def create_soap_rpc_driver(api, endpoint_uri)
74
+ @protocol.register_api(api)
75
+ driver = SoapDriver.new(endpoint_uri, nil)
76
+ driver.mapping_registry = @protocol.marshaler.registry
77
+ api.api_methods.each do |name, method|
78
+ qname = XSD::QName.new(@namespace, method.public_name)
79
+ action = soap_action(method.public_name)
80
+ expects = method.expects
81
+ returns = method.returns
82
+ param_def = []
83
+ if expects
84
+ expects.each do |type|
85
+ type_binding = @protocol.marshaler.lookup_type(type)
86
+ if SOAP::Version >= "1.5.5"
87
+ param_def << ['in', type.name.to_s, [type_binding.type.type_class.to_s]]
88
+ else
89
+ param_def << ['in', type.name, type_binding.mapping]
90
+ end
91
+ end
92
+ end
93
+ if returns
94
+ type_binding = @protocol.marshaler.lookup_type(returns[0])
95
+ if SOAP::Version >= "1.5.5"
96
+ param_def << ['retval', 'return', [type_binding.type.type_class.to_s]]
97
+ else
98
+ param_def << ['retval', 'return', type_binding.mapping]
99
+ end
100
+ end
101
+ driver.add_method(qname, action, method.name.to_s, param_def)
102
+ end
103
+ driver
104
+ end
105
+
106
+ class SoapDriver < SOAP::RPC::Driver # :nodoc:
107
+ def add_method(qname, soapaction, name, param_def)
108
+ @proxy.add_rpc_method(qname, soapaction, name, param_def)
109
+ add_rpc_method_interface(name, param_def)
110
+ end
111
+ end
112
+ end
113
+ end
114
+ end
@@ -0,0 +1,59 @@
1
+ # encoding: UTF-8
2
+ require 'uri'
3
+ require 'xmlrpc/client'
4
+
5
+ module ActionWebService # :nodoc:
6
+ module Client # :nodoc:
7
+
8
+ # Implements XML-RPC client support
9
+ #
10
+ # ==== Example Usage
11
+ #
12
+ # class BloggerAPI < ActionWebService::API::Base
13
+ # inflect_names false
14
+ # api_method :getRecentPosts, :returns => [[Blog::Post]]
15
+ # end
16
+ #
17
+ # blog = ActionWebService::Client::XmlRpc.new(BloggerAPI, "http://.../RPC", :handler_name => "blogger")
18
+ # posts = blog.getRecentPosts
19
+ class XmlRpc < Base
20
+
21
+ # Creates a new web service client using the XML-RPC protocol.
22
+ #
23
+ # +api+ must be an ActionWebService::API::Base derivative, and
24
+ # +endpoint_uri+ must point at the relevant URL to which protocol requests
25
+ # will be sent with HTTP POST.
26
+ #
27
+ # Valid options:
28
+ # [<tt>:handler_name</tt>] If the remote server defines its services inside special
29
+ # handler (the Blogger API uses a <tt>"blogger"</tt> handler name for example),
30
+ # provide it here, or your method calls will fail
31
+ def initialize(api, endpoint_uri, options={})
32
+ @api = api
33
+ @handler_name = options[:handler_name]
34
+ @protocol = ActionWebService::Protocol::XmlRpc::XmlRpcProtocol.new
35
+ @client = XMLRPC::Client.new2(endpoint_uri, options[:proxy], options[:timeout])
36
+ end
37
+
38
+ protected
39
+ def perform_invocation(method_name, args)
40
+ method = @api.api_methods[method_name.to_sym]
41
+ if method.expects && method.expects.length != args.length
42
+ raise(ArgumentError, "#{method.public_name}: wrong number of arguments (#{args.length} for #{method.expects.length})")
43
+ end
44
+ args = method.cast_expects(args.dup) rescue args
45
+ if method.expects
46
+ method.expects.each_with_index{ |type, i| args[i] = @protocol.value_to_xmlrpc_wire_format(args[i], type) }
47
+ end
48
+ ok, return_value = @client.call2(public_name(method_name), *args)
49
+ return (method.cast_returns(return_value.dup) rescue return_value) if ok
50
+ raise(ClientError, "#{return_value.faultCode}: #{return_value.faultString}")
51
+ end
52
+
53
+ def public_name(method_name)
54
+ public_name = @api.public_api_method_name(method_name)
55
+ @handler_name ? "#{@handler_name}.#{public_name}" : public_name
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,4 @@
1
+ # encoding: UTF-8
2
+ require 'action_web_service/container/direct_container'
3
+ require 'action_web_service/container/delegated_container'
4
+ require 'action_web_service/container/action_controller_container'
@@ -0,0 +1,94 @@
1
+ # encoding: UTF-8
2
+ module ActionWebService # :nodoc:
3
+ module Container # :nodoc:
4
+ module ActionController # :nodoc:
5
+ def self.included(base) # :nodoc:
6
+ class << base
7
+ include ClassMethods
8
+ alias_method_chain :inherited, :api
9
+ alias_method_chain :web_service_api, :require
10
+ end
11
+ end
12
+
13
+ module ClassMethods
14
+ # Creates a client for accessing remote web services, using the
15
+ # given +protocol+ to communicate with the +endpoint_uri+.
16
+ #
17
+ # ==== Example
18
+ #
19
+ # class MyController < ActionController::Base
20
+ # web_client_api :blogger, :xmlrpc, "http://blogger.com/myblog/api/RPC2", :handler_name => 'blogger'
21
+ # end
22
+ #
23
+ # In this example, a protected method named <tt>blogger</tt> will
24
+ # now exist on the controller, and calling it will return the
25
+ # XML-RPC client object for working with that remote service.
26
+ #
27
+ # +options+ is the set of protocol client specific options (see
28
+ # a protocol client class for details).
29
+ #
30
+ # If your API definition does not exist on the load path with the
31
+ # correct rules for it to be found using +name+, you can pass in
32
+ # the API definition class via +options+, using a key of <tt>:api</tt>
33
+ def web_client_api(name, protocol, endpoint_uri, options={})
34
+ unless method_defined?(name)
35
+ api_klass = options.delete(:api) || require_web_service_api(name)
36
+ class_eval do
37
+ define_method(name) do
38
+ create_web_service_client(api_klass, protocol, endpoint_uri, options)
39
+ end
40
+ protected name
41
+ end
42
+ end
43
+ end
44
+
45
+ def web_service_api_with_require(definition=nil) # :nodoc:
46
+ return web_service_api_without_require if definition.nil?
47
+ case definition
48
+ when String, Symbol
49
+ klass = require_web_service_api(definition)
50
+ else
51
+ klass = definition
52
+ end
53
+ web_service_api_without_require(klass)
54
+ end
55
+
56
+ def require_web_service_api(name) # :nodoc:
57
+ case name
58
+ when String, Symbol
59
+ file_name = name.to_s.underscore + "_api"
60
+ class_name = file_name.camelize
61
+ class_names = [class_name, class_name.sub(/Api$/, 'API')]
62
+ begin
63
+ require_dependency(file_name)
64
+ rescue LoadError => load_error
65
+ requiree = / -- (.*?)(\.rb)?$/.match(load_error.message).to_a[1]
66
+ msg = requiree == file_name ? "Missing API definition file in apis/#{file_name}.rb" : "Can't load file: #{requiree}"
67
+ raise LoadError.new(msg).copy_blame!(load_error)
68
+ end
69
+ klass = nil
70
+ class_names.each do |name|
71
+ klass = name.constantize rescue nil
72
+ break unless klass.nil?
73
+ end
74
+ unless klass
75
+ raise(NameError, "neither #{class_names[0]} or #{class_names[1]} found")
76
+ end
77
+ klass
78
+ else
79
+ raise(ArgumentError, "expected String or Symbol argument")
80
+ end
81
+ end
82
+
83
+ private
84
+ def inherited_with_api(child)
85
+ inherited_without_api(child)
86
+ begin child.web_service_api(child.controller_path)
87
+ rescue MissingSourceFile => e
88
+ raise unless e.is_missing?("apis/#{child.controller_path}_api")
89
+ end
90
+ end
91
+ end
92
+ end
93
+ end
94
+ end