File: type_loader.rb

package info (click to toggle)
ruby-rbvmomi 1.8.2-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 1,756 kB
  • sloc: ruby: 5,590; sh: 36; makefile: 7
file content (136 lines) | stat: -rw-r--r-- 3,498 bytes parent folder | download
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
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
# Copyright (c) 2010 VMware, Inc.  All Rights Reserved.
require 'set'
require 'monitor'

module RbVmomi

class TypeLoader
  def initialize fn, extension_dirs, namespace
    @extension_dirs = extension_dirs
    @namespace = namespace
    @lock = Monitor.new
    @db = {}
    @id2wsdl = {}
    @loaded = {}
    add_types Hash[BasicTypes::BUILTIN.map { |k| [k,nil] }]
    vmodl_database = File.open(fn, 'r') { |io| Marshal.load io }
    vmodl_database.reject! { |k,v| k =~ /^_/ }
    add_types vmodl_database
    preload
  end

  def preload
    names = (@namespace.constants + Object.constants).map(&:to_s).uniq.
                                                      select { |x| has? x }
    names.each { |x| get(x) }
  end

  # Reload all extensions for loaded VMODL types
  def reload_extensions
    @extension_dirs.each do |path|
      reload_extensions_dir path
    end
  end

  # Reload all extensions for loaded VMODL types from the given directory
  def reload_extensions_dir path
    loaded = Set.new(typenames.select { |x| @namespace.const_defined? x })
    Dir.open(path) do |dir|
      dir.each do |file|
        next unless file =~ /\.rb$/
        next unless loaded.member? $`
        file_path = File.join(dir, file)
        load file_path
      end
    end
  end

  def has? name
    fail unless name.is_a? String

    @db.member?(name) or BasicTypes::BUILTIN.member?(name)
  end

  def get name
    fail "name '#{name}' is #{name.class} expecting String" unless name.is_a? String

    first_char = name[0].chr
    if first_char.downcase == first_char
      name = "%s%s" % [first_char.upcase, name[1..-1]]
    end

    return @loaded[name] if @loaded.member? name
    @lock.synchronize do
      return @loaded[name] if @loaded.member? name
      klass = make_type(name)
      @namespace.const_set name, klass
      load_extension name
      @loaded[name] = klass
    end
  end

  def add_types types
    @lock.synchronize do
      @db.merge! types
      @db = Hash[@db.map do |name, value|
        if value
          value['wsdl_name'] ||= name
        end
        first_char = name[0].chr
        if first_char.downcase == first_char
          name = "%s%s" % [first_char.upcase, name[1..-1]]
        end
        [name, value]
      end]
    end
  end

  def typenames
    @db.keys
  end

  private

  def load_extension name
    @extension_dirs.map { |x| File.join(x, "#{name}.rb") }.
                    select { |x| File.exist? x }.
                    each { |x| load x }
  end

  def make_type name
    name = name.to_s
    return BasicTypes.const_get(name) if BasicTypes::BUILTIN.member? name
    desc = @db[name] or fail "unknown VMODL type #{name}"
    case desc['kind']
    when 'data' then make_data_type name, desc
    when 'managed' then make_managed_type name, desc
    when 'enum' then make_enum_type name, desc
    else fail desc.inspect
    end
  end

  def make_data_type name, desc
    superclass = get desc['wsdl_base']
    Class.new(superclass).tap do |klass|
      klass.init name, desc['props']
      klass.wsdl_name = desc['wsdl_name']
    end
  end

  def make_managed_type name, desc
    superclass = get desc['wsdl_base']
    Class.new(superclass).tap do |klass|
      klass.init name, desc['props'], desc['methods']
      klass.wsdl_name = desc['wsdl_name']
    end
  end

  def make_enum_type name, desc
    Class.new(BasicTypes::Enum).tap do |klass|
      klass.init name, desc['values']
      klass.wsdl_name = desc['wsdl_name']
    end
  end
end

end