Class: Plist4r::Backend

Defined in:
lib/plist4r/backend.rb,
lib/plist4r/backend_base.rb,
lib/plist4r/backend/test/output.rb,
lib/plist4r/backend/test/harness.rb,
lib/plist4r/backend/test/data_types.rb

Direct Known Subclasses

Modules

Instance Methods

Overview

This class is the Backend broker. The purpose of this object is to manage and handle API calls, passing them over to the appropriate Plist4r backends. Also see the Backends Rdoc page.

Constant Summary

ApiMethods =

The list backend API methods. A Plist4r::Backend should implement 1 or more of these methods

See Also:

%w[ from_xml from_binary from_gnustep to_xml to_binary to_gnustep ]
PrivateApiMethods =

The set of Plist4r API methods which are generated by the #generic_call method These methods don’t need to be implemented by a Plist4r::Backend

%w[ from_string open save ]
PlistCacheApiMethods =

The set of Plist4r API methods with are invoked by Plist4r::PlistCache

%w[from_string to_xml to_binary to_gnustep open save]

Constructor Details

- (Backend) initialize(plist, *args, &blk)

A new instance of Backend. A single Backend will exist for the the life of the Plist object. The attribute @plist is set during initialization and refers back to the plist instance object.



25
26
27
# File 'lib/plist4r/backend.rb', line 25

def initialize plist, *args, &blk
  @plist = plist
end

Instance Method Details

- (Object) call(method_sym)

Call a Plist4r API Method. Here, we usually pass a Plist4r::Plist object as one of the parameters, which will also contain all the input data to work on.

This function loops through the array of available backends, and calls the first backend found to implement the appropriate fullfilment request.

If the request fails, the call is re-executed on the next available backend.

The plist object is updated in-place and also usually placed as the return argument.

Parameters:

  • (Symbol) method_sym

    The API method call to execute

Raises:

  • if no backend was able to sucessfully execute the request.



91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
# File 'lib/plist4r/backend.rb', line 91

def call method_sym
  raise "Unsupported api call #{method_sym.inspect}" unless PlistCacheApiMethods.include? method_sym.to_s
  exceptions = []
  generic_call_exception = nil

  @plist.backends.each do |b_sym|
  backend = eval "Plist4r::Backend::#{b_sym.to_s.camelcase}"

    begin
      if backend.respond_to?(method_sym) && method_sym != :from_string
        Timeout::timeout(Plist4r::Config[:backend_timeout]) do
          return eval("#{backend}.#{method_sym} @plist")
        end

      elsif PrivateApiMethods.include? method_sym.to_s
        result = generic_call backend, method_sym
        if result.is_a? Exception
          generic_call_exception = result
        else
          return result
        end
      end

    rescue LoadError
      exceptions << $!
    rescue RuntimeError
      exceptions << $!
    rescue SyntaxError
      exceptions << $!
    rescue Exception
      exceptions << $!
    rescue Timeout::Error
      exceptions << $!
    rescue
      exceptions << $!
    end

    if Config[:raise_any_failure] && exceptions.first
      raise exceptions.first
    end
  end
  
  if exceptions.empty?
    if generic_call_exception
      raise generic_call_exception
    else
      raise "Plist4r: No backend found to handle method #{method_sym.inspect}. Could not execute method #{method_sym.inspect} on plist #{@plist.inspect}"
    end
  else
    # $stderr.puts "Failure(s) while executing method #{method_sym.inspect} on plist #{@plist}."
    exceptions.each do |e|
      $stderr.puts e.inspect
      $stderr.puts e.backtrace.collect { |l| "\tfrom #{l}"}.join "\n"
    end
    # raise exceptions.first
    raise "Failure(s) while executing method #{method_sym.inspect} on plist #{@plist}."
  end
end

- (Object) generic_call(backend, method_sym)

Implements a generic version of each of the Plist4r Private API Calls.

Parameters:

  • (Symbol) backend

    the currently iterated backend from which we will try to generate the API call

  • (Symbol) method_sym

    The API method call to execute. One of PrivateApiMethods



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
# File 'lib/plist4r/backend.rb', line 32

def generic_call backend, method_sym
  case method_sym

  when :save
    fmt = @plist.file_format || Plist4r::Config[:default_format]
    unless backend.respond_to? "to_#{fmt}"
      return Exception.new "Plist4r: No backend found to handle method :to_#{fmt}. Could not execute method :save on plist #{@plist.inspect}"
    end
    File.open(@plist.filename_path,'w') do |out|
      out << @plist.instance_eval { @plist_cache.send("to_#{fmt}".to_sym) }
    end

  when :open
    unless @open_fmt
      @plist.instance_eval "@from_string = File.read(filename_path)"
      @open_fmt = Plist4r.string_detect_format @plist.from_string
    end
    fmt = @open_fmt
    if backend.respond_to? "from_#{fmt}"
      @from_string_fmt = @open_fmt
      @open_fmt = nil

      @plist.instance_eval { @plist_cache.send :from_string }
    else
      return Exception.new "Plist4r: No backend found to handle method :from_#{fmt}. Could not execute method :open on plist #{@plist.inspect}"
    end

  when :from_string
    unless @from_string_fmt
      @from_string_fmt = Plist4r.string_detect_format @plist.from_string
    end
    fmt = @from_string_fmt
    if backend.respond_to? "from_#{fmt}"
      @from_string_fmt = nil

      Timeout::timeout(Plist4r::Config[:backend_timeout]) do
        backend.send("from_#{fmt}".to_sym, @plist)
      end
      @plist.file_format fmt
      @plist
    else
      return Exception.new "Plist4r: No backend found to handle method :from_#{fmt}. Could not execute method :from_string on plist #{@plist.inspect}"
    end
  end
end