1#
2# Copyright (C) 2001, 2002, 2003 by Michael Neumann (mneumann@ntecs.de)
3#
4# $Id: utils.rb 36958 2012-09-13 02:22:10Z zzak $
5#
6module XMLRPC # :nodoc:
7
8
9  # This module enables a user-class to be marshalled
10  # by XML-RPC for Ruby into a Hash, with one additional
11  # key/value pair <code>___class___ => ClassName</code>
12  #
13  module Marshallable
14  end
15
16
17  # Defines ParserWriterChooseMixin, which makes it possible to choose a
18  # different XMLWriter and/or XMLParser then the default one.
19  #
20  # The Mixin is used in client.rb (class XMLRPC::Client)
21  # and server.rb (class XMLRPC::BasicServer)
22  module ParserWriterChooseMixin
23
24    # Sets the XMLWriter to use for generating XML output.
25    #
26    # Should be an instance of a class from module XMLRPC::XMLWriter.
27    #
28    # If this method is not called, then XMLRPC::Config::DEFAULT_WRITER is used.
29    def set_writer(writer)
30      @create = Create.new(writer)
31      self
32    end
33
34    # Sets the XMLParser to use for parsing XML documents.
35    #
36    # Should be an instance of a class from module XMLRPC::XMLParser.
37    #
38    # If this method is not called, then XMLRPC::Config::DEFAULT_PARSER is used.
39    def set_parser(parser)
40      @parser = parser
41      self
42    end
43
44    private
45
46    def create
47      # if set_writer was not already called then call it now
48      if @create.nil? then
49        set_writer(Config::DEFAULT_WRITER.new)
50      end
51      @create
52    end
53
54    def parser
55      # if set_parser was not already called then call it now
56      if @parser.nil? then
57        set_parser(Config::DEFAULT_PARSER.new)
58      end
59      @parser
60    end
61
62  end # module ParserWriterChooseMixin
63
64
65  module Service
66
67  # Base class for XMLRPC::Service::Interface definitions, used
68  # by XMLRPC::BasicServer#add_handler
69  class BasicInterface
70    attr_reader :prefix, :methods
71
72    def initialize(prefix)
73      @prefix = prefix
74      @methods = []
75    end
76
77    def add_method(sig, help=nil, meth_name=nil)
78      mname = nil
79      sig = [sig] if sig.kind_of? String
80
81      sig = sig.collect do |s|
82        name, si = parse_sig(s)
83        raise "Wrong signatures!" if mname != nil and name != mname
84        mname = name
85        si
86      end
87
88      @methods << [mname, meth_name || mname, sig, help]
89    end
90
91    private
92
93    def parse_sig(sig)
94      # sig is a String
95      if sig =~ /^\s*(\w+)\s+([^(]+)(\(([^)]*)\))?\s*$/
96        params = [$1]
97        name   = $2.strip
98        $4.split(",").each {|i| params << i.strip} if $4 != nil
99        return name, params
100      else
101        raise "Syntax error in signature"
102      end
103    end
104
105  end # class BasicInterface
106
107  #
108  # Class which wraps a XMLRPC::Service::Interface definition, used
109  # by XMLRPC::BasicServer#add_handler
110  #
111  class Interface < BasicInterface
112    def initialize(prefix, &p)
113      raise "No interface specified" if p.nil?
114      super(prefix)
115      instance_eval(&p)
116    end
117
118    def get_methods(obj, delim=".")
119      prefix = @prefix + delim
120      @methods.collect { |name, meth, sig, help|
121        [prefix + name.to_s, obj.method(meth).to_proc, sig, help]
122      }
123    end
124
125    private
126
127    def meth(*a)
128      add_method(*a)
129    end
130
131  end # class Interface
132
133  class PublicInstanceMethodsInterface < BasicInterface
134    def initialize(prefix)
135      super(prefix)
136    end
137
138    def get_methods(obj, delim=".")
139      prefix = @prefix + delim
140      obj.class.public_instance_methods(false).collect { |name|
141        [prefix + name.to_s, obj.method(name).to_proc, nil, nil]
142      }
143    end
144  end
145
146
147  end # module Service
148
149
150  #
151  # Short-form to create a XMLRPC::Service::Interface
152  #
153  def self.interface(prefix, &p)
154    Service::Interface.new(prefix, &p)
155  end
156
157  # Short-cut for creating a XMLRPC::Service::PublicInstanceMethodsInterface
158  def self.iPIMethods(prefix)
159    Service::PublicInstanceMethodsInterface.new(prefix)
160  end
161
162
163  module ParseContentType
164    def parse_content_type(str)
165      a, *b = str.split(";")
166      return a.strip.downcase, *b
167    end
168  end
169
170end # module XMLRPC
171
172