aboutsummaryrefslogtreecommitdiffstats
path: root/actionwebservice/lib/action_web_service/container/action_controller_container.rb
blob: 06b47e9d79de3ee80e0cec8f3468176a70c5da6e (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
module ActionWebService # :nodoc:
  module Container # :nodoc:
    module ActionController # :nodoc:
      def self.append_features(base) # :nodoc:
        base.class_eval do 
          class << self
            alias_method :inherited_without_api, :inherited
            alias_method :web_service_api_without_require, :web_service_api
          end
        end
        base.extend(ClassMethods)
      end

      module ClassMethods
        # Creates a client for accessing remote web services, using the
        # given +protocol+ to communicate with the +endpoint_uri+.
        #
        # ==== Example
        #
        #   class MyController < ActionController::Base
        #     web_client_api :blogger, :xmlrpc, "http://blogger.com/myblog/api/RPC2", :handler_name => 'blogger'
        #   end
        #
        # In this example, a protected method named <tt>blogger</tt> will
        # now exist on the controller, and calling it will return the
        # XML-RPC client object for working with that remote service.
        #
        # +options+ is the set of protocol client specific options,
        # see a protocol client class for details.
        #
        # If your API definition does not exist on the load path with the
        # correct rules for it to be found using +name+, you can pass through
        # the API definition class in +options+, using a key of <tt>:api</tt>
        def web_client_api(name, protocol, endpoint_uri, options={})
          unless method_defined?(name)
            api_klass = options.delete(:api) || require_web_service_api(name)
            class_eval do
              define_method(name) do
                create_web_service_client(api_klass, protocol, endpoint_uri, options)
              end
              protected name
            end
          end
        end

        def web_service_api(definition=nil) # :nodoc:
          return web_service_api_without_require if definition.nil?
          case definition
          when String, Symbol
            klass = require_web_service_api(definition)
          else
            klass = definition
          end
          web_service_api_without_require(klass)
        end

        def require_web_service_api(name) # :nodoc:
          case name
          when String, Symbol
            file_name = name.to_s.underscore + "_api"
            class_name = file_name.camelize
            class_names = [class_name, class_name.sub(/Api$/, 'API')]
            begin
              require_dependency(file_name)
            rescue LoadError => load_error
              requiree = / -- (.*?)(\.rb)?$/.match(load_error).to_a[1]
              msg = requiree == file_name ? "Missing API definition file in apis/#{file_name}.rb" : "Can't load file: #{requiree}"
              raise LoadError.new(msg).copy_blame!(load_error)
            end
            klass = nil
            class_names.each do |name|
              klass = name.constantize rescue nil
              break unless klass.nil?
            end
            unless klass
              raise(NameError, "neither #{class_names[0]} or #{class_names[1]} found")
            end
            klass
          else
            raise(ArgumentError, "expected String or Symbol argument")
          end
        end

        private
          def inherited(child)
            inherited_without_api(child)
            begin child.web_service_api(child.controller_path)
            rescue MissingSourceFile => e
              raise unless e.is_missing?("apis/#{child.controller_path}_api")
            end
          end
      end
    end
  end
end