aboutsummaryrefslogtreecommitdiffstats
path: root/actionwebservice/lib/action_web_service/container.rb
blob: f02717579e791b470179b3927be1584dca010d94 (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
module ActionWebService # :nodoc:
  module Container # :nodoc:
    class ContainerError < ActionWebService::ActionWebServiceError # :nodoc:
    end

    def self.append_features(base) # :nodoc:
      super
      base.extend(ClassMethods)
      base.send(:include, ActionWebService::Container::InstanceMethods)
    end

    module ClassMethods
      # Declares a web service that will provides access to the API of the given
      # +object+. +object+ must be an ActionWebService::Base derivative.
      #
      # Web service object creation can either be _immediate_, where the object
      # instance is given at class definition time, or _deferred_, where
      # object instantiation is delayed until request time.
      #
      # ==== Immediate web service object example
      #
      #   class ApiController < ApplicationController
      #     web_service_dispatching_mode :delegated
      #
      #     web_service :person, PersonService.new
      #   end
      #
      # For deferred instantiation, a block should be given instead of an
      # object instance. This block will be executed in controller instance
      # context, so it can rely on controller instance variables being present.
      #
      # ==== Deferred web service object example
      #
      #   class ApiController < ApplicationController
      #     web_service_dispatching_mode :delegated
      #
      #     web_service(:person) { PersonService.new(@request.env) }
      #   end
      def web_service(name, object=nil, &block)
        if (object && block_given?) || (object.nil? && block.nil?)
          raise(ContainerError, "either service, or a block must be given")
        end
        name = name.to_sym
        if block_given?
          info = { name => { :block => block } }
        else
          info = { name => { :object => object } }
        end
        write_inheritable_hash("web_services", info)
        call_web_service_definition_callbacks(self, name, info)
      end

      # Whether this service contains a service with the given +name+
      def has_web_service?(name)
        web_services.has_key?(name.to_sym)
      end

      def web_services # :nodoc:
        read_inheritable_attribute("web_services") || {}
      end

      def add_web_service_definition_callback(&block) # :nodoc:
        write_inheritable_array("web_service_definition_callbacks", [block])
      end

      private
        def call_web_service_definition_callbacks(container_class, web_service_name, service_info)
          (read_inheritable_attribute("web_service_definition_callbacks") || []).each do |block|
            block.call(container_class, web_service_name, service_info)
          end
        end
    end

    module InstanceMethods # :nodoc:
      def web_service_object(web_service_name)
        info = self.class.web_services[web_service_name.to_sym]
        unless info
          raise(ContainerError, "no such web service '#{web_service_name}'")
        end
        service = info[:block]
        service ? instance_eval(&service) : info[:object]
      end
    end
  end
end