libvirt_ffi 0.2.1 → 0.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
 - data/.rubocop.yml +78 -0
 - data/Gemfile +7 -2
 - data/Rakefile +6 -1
 - data/bin/console +1 -0
 - data/exe/libvirt +1 -0
 - data/lib/libvirt.rb +14 -13
 - data/lib/libvirt/base_info.rb +34 -0
 - data/lib/libvirt/connection.rb +156 -47
 - data/lib/libvirt/domain.rb +136 -8
 - data/lib/libvirt/domain_callback_storage.rb +69 -0
 - data/lib/libvirt/errors.rb +65 -0
 - data/lib/libvirt/event.rb +60 -38
 - data/lib/libvirt/ffi.rb +17 -0
 - data/lib/libvirt/ffi/common.rb +8 -1
 - data/lib/libvirt/ffi/domain.rb +796 -69
 - data/lib/libvirt/ffi/error.rb +243 -0
 - data/lib/libvirt/ffi/event.rb +30 -36
 - data/lib/libvirt/ffi/helpers.rb +17 -0
 - data/lib/libvirt/ffi/host.rb +122 -0
 - data/lib/libvirt/ffi/storage.rb +149 -0
 - data/lib/libvirt/ffi/stream.rb +74 -0
 - data/lib/libvirt/node_info.rb +2 -41
 - data/lib/libvirt/storage_pool.rb +70 -0
 - data/lib/libvirt/storage_pool_info.rb +7 -0
 - data/lib/libvirt/storage_volume.rb +51 -0
 - data/lib/libvirt/storage_volume_info.rb +7 -0
 - data/lib/libvirt/stream.rb +124 -0
 - data/lib/libvirt/util.rb +75 -8
 - data/lib/libvirt/version.rb +1 -1
 - data/lib/libvirt/xml.rb +23 -0
 - data/lib/libvirt/xml/disk.rb +59 -0
 - data/lib/libvirt/xml/domain.rb +76 -0
 - data/lib/libvirt/xml/generic.rb +252 -0
 - data/lib/libvirt/xml/graphics.rb +14 -0
 - data/lib/libvirt/xml/max_vcpu.rb +12 -0
 - data/lib/libvirt/xml/memory.rb +14 -0
 - data/lib/libvirt/xml/storage_pool.rb +24 -0
 - data/lib/libvirt/xml/storage_volume.rb +32 -0
 - data/lib/libvirt/xml/vcpu.rb +12 -0
 - data/lib/libvirt_ffi.rb +2 -0
 - data/libvirt.gemspec +5 -1
 - data/test_usage/support/libvirt_async.rb +33 -31
 - data/test_usage/support/log_formatter.rb +5 -10
 - data/test_usage/test_domain.rb +43 -0
 - data/test_usage/test_event_loop.rb +134 -33
 - data/test_usage/test_libvirtd_restart.rb +63 -0
 - data/test_usage/test_metadata.rb +104 -0
 - data/test_usage/test_screenshot.rb +197 -0
 - data/test_usage/test_storage.rb +52 -0
 - metadata +46 -6
 - data/lib/libvirt/error.rb +0 -6
 - data/lib/libvirt/ffi/connection.rb +0 -84
 - data/lib/libvirt/ffi/libvirt.rb +0 -17
 - data/lib/libvirt/ffi/node_info.rb +0 -37
 
    
        data/lib/libvirt/util.rb
    CHANGED
    
    | 
         @@ -2,23 +2,36 @@ 
     | 
|
| 
       2 
2 
     | 
    
         | 
| 
       3 
3 
     | 
    
         
             
            module Libvirt
         
     | 
| 
       4 
4 
     | 
    
         
             
              module Util
         
     | 
| 
      
 5 
     | 
    
         
            +
                UNIT_TO_BYTES = {
         
     | 
| 
      
 6 
     | 
    
         
            +
                    b: 1,
         
     | 
| 
      
 7 
     | 
    
         
            +
                    bytes: 1,
         
     | 
| 
      
 8 
     | 
    
         
            +
                    KB: 1_000,
         
     | 
| 
      
 9 
     | 
    
         
            +
                    KiB: 1_024,
         
     | 
| 
      
 10 
     | 
    
         
            +
                    k: 1_024,
         
     | 
| 
      
 11 
     | 
    
         
            +
                    MB: 1_000_000,
         
     | 
| 
      
 12 
     | 
    
         
            +
                    M: 1_048_576,
         
     | 
| 
      
 13 
     | 
    
         
            +
                    MiB: 1_048_576,
         
     | 
| 
      
 14 
     | 
    
         
            +
                    GB: 1_000_000_000,
         
     | 
| 
      
 15 
     | 
    
         
            +
                    G: 1_073_741_824,
         
     | 
| 
      
 16 
     | 
    
         
            +
                    GiB: 1_073_741_824,
         
     | 
| 
      
 17 
     | 
    
         
            +
                    TB: 1_000_000_000_000,
         
     | 
| 
      
 18 
     | 
    
         
            +
                    T: 1_099_511_627_776,
         
     | 
| 
      
 19 
     | 
    
         
            +
                    TiB: 1_099_511_627_776
         
     | 
| 
      
 20 
     | 
    
         
            +
                }.freeze
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
       5 
22 
     | 
    
         
             
                class << self
         
     | 
| 
      
 23 
     | 
    
         
            +
                  attr_writer :logger
         
     | 
| 
       6 
24 
     | 
    
         | 
| 
       7 
     | 
    
         
            -
                   
     | 
| 
       8 
     | 
    
         
            -
                    @logger = logger
         
     | 
| 
       9 
     | 
    
         
            -
                  end
         
     | 
| 
       10 
     | 
    
         
            -
             
     | 
| 
       11 
     | 
    
         
            -
                  def logger
         
     | 
| 
       12 
     | 
    
         
            -
                    @logger
         
     | 
| 
       13 
     | 
    
         
            -
                  end
         
     | 
| 
      
 25 
     | 
    
         
            +
                  attr_reader :logger
         
     | 
| 
       14 
26 
     | 
    
         | 
| 
       15 
27 
     | 
    
         
             
                  def log(severity, prog = nil, &block)
         
     | 
| 
       16 
28 
     | 
    
         
             
                    return if @logger.nil?
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
       17 
30 
     | 
    
         
             
                    @logger.public_send(severity, prog, &block)
         
     | 
| 
       18 
31 
     | 
    
         
             
                  end
         
     | 
| 
       19 
32 
     | 
    
         | 
| 
       20 
33 
     | 
    
         
             
                  def library_path
         
     | 
| 
       21 
     | 
    
         
            -
                    %w 
     | 
| 
      
 34 
     | 
    
         
            +
                    %w[libvirt libvirt.so.0]
         
     | 
| 
       22 
35 
     | 
    
         
             
                  end
         
     | 
| 
       23 
36 
     | 
    
         | 
| 
       24 
37 
     | 
    
         
             
                  # @param [Integer] version_number ulong
         
     | 
| 
         @@ -29,6 +42,60 @@ module Libvirt 
     | 
|
| 
       29 
42 
     | 
    
         
             
                    "#{major}.#{minor}.#{release}"
         
     | 
| 
       30 
43 
     | 
    
         
             
                  end
         
     | 
| 
       31 
44 
     | 
    
         | 
| 
      
 45 
     | 
    
         
            +
                  # @param enum [FFI::Enum]
         
     | 
| 
      
 46 
     | 
    
         
            +
                  # @param value [Symbol, Integer]
         
     | 
| 
      
 47 
     | 
    
         
            +
                  # @return [Array] event_id, event_id_sym
         
     | 
| 
      
 48 
     | 
    
         
            +
                  # @raise ArgumentError
         
     | 
| 
      
 49 
     | 
    
         
            +
                  def parse_enum(enum, value)
         
     | 
| 
      
 50 
     | 
    
         
            +
                    if value.is_a?(Symbol)
         
     | 
| 
      
 51 
     | 
    
         
            +
                      raise ArgumentError, 'invalid enum value' unless enum.symbols.include?(value)
         
     | 
| 
      
 52 
     | 
    
         
            +
             
     | 
| 
      
 53 
     | 
    
         
            +
                      return [enum.find(value), value]
         
     | 
| 
      
 54 
     | 
    
         
            +
                    end
         
     | 
| 
      
 55 
     | 
    
         
            +
             
     | 
| 
      
 56 
     | 
    
         
            +
                    raise ArgumentError, 'invalid enum value' unless enum.symbol_map.values.include?(value)
         
     | 
| 
      
 57 
     | 
    
         
            +
             
     | 
| 
      
 58 
     | 
    
         
            +
                    [value, enum.symbol_map[value]]
         
     | 
| 
      
 59 
     | 
    
         
            +
                  end
         
     | 
| 
      
 60 
     | 
    
         
            +
             
     | 
| 
      
 61 
     | 
    
         
            +
                  # Bitwise OR integer flags calculation for C language.
         
     | 
| 
      
 62 
     | 
    
         
            +
                  # @param flags [Integer,Symbol,Array<Symbol>,Hash{Symbol=>Boolean},nil]
         
     | 
| 
      
 63 
     | 
    
         
            +
                  # @param enum [FFI::Enum]
         
     | 
| 
      
 64 
     | 
    
         
            +
                  # @param default [Integer] optional (default 0x0)
         
     | 
| 
      
 65 
     | 
    
         
            +
                  # @return [Integer] bitwise OR of keys
         
     | 
| 
      
 66 
     | 
    
         
            +
                  #  @example Usage:
         
     | 
| 
      
 67 
     | 
    
         
            +
                  #    parse_flags(nil, enum)
         
     | 
| 
      
 68 
     | 
    
         
            +
                  #    parse_flags({MANAGED_SAVE: true, SNAPSHOTS_METADATA: true, NVRAM: false}, enum)
         
     | 
| 
      
 69 
     | 
    
         
            +
                  #    parse_flags({managed_save: true, snapshots_metadata: true, keep_nvram: nil}, enum)
         
     | 
| 
      
 70 
     | 
    
         
            +
                  #    parse_flags(3, enum)
         
     | 
| 
      
 71 
     | 
    
         
            +
                  #    parse_flags([:MANAGED_SAVE, :SNAPSHOTS_METADATA], enum)
         
     | 
| 
      
 72 
     | 
    
         
            +
                  #    parse_flags([:managed_save, :snapshots_metadata], enum)
         
     | 
| 
      
 73 
     | 
    
         
            +
                  #
         
     | 
| 
      
 74 
     | 
    
         
            +
                  def parse_flags(flags, enum, default: 0x0)
         
     | 
| 
      
 75 
     | 
    
         
            +
                    flags = default if flags.nil?
         
     | 
| 
      
 76 
     | 
    
         
            +
                    flags = enum[flags] if flags.is_a?(Symbol)
         
     | 
| 
      
 77 
     | 
    
         
            +
                    return flags if flags.is_a?(Integer)
         
     | 
| 
      
 78 
     | 
    
         
            +
             
     | 
| 
      
 79 
     | 
    
         
            +
                    result = 0x0
         
     | 
| 
      
 80 
     | 
    
         
            +
                    flags = flags.select { |_, v| v }.keys if flags.is_a?(Hash)
         
     | 
| 
      
 81 
     | 
    
         
            +
             
     | 
| 
      
 82 
     | 
    
         
            +
                    raise ArgumentError, 'flags must be an Integer or a Hash or an Array' unless flags.is_a?(Array)
         
     | 
| 
      
 83 
     | 
    
         
            +
             
     | 
| 
      
 84 
     | 
    
         
            +
                    flags.each do |key|
         
     | 
| 
      
 85 
     | 
    
         
            +
                      result |= enum[key.to_s.upcase.to_sym]
         
     | 
| 
      
 86 
     | 
    
         
            +
                    end
         
     | 
| 
      
 87 
     | 
    
         
            +
             
     | 
| 
      
 88 
     | 
    
         
            +
                    result
         
     | 
| 
      
 89 
     | 
    
         
            +
                  end
         
     | 
| 
      
 90 
     | 
    
         
            +
             
     | 
| 
      
 91 
     | 
    
         
            +
                  # @param value [Integer,String]
         
     | 
| 
      
 92 
     | 
    
         
            +
                  # @param unit [String,Symbol] default 'bytes'
         
     | 
| 
      
 93 
     | 
    
         
            +
                  # @return [Integer] memory in bytes
         
     | 
| 
      
 94 
     | 
    
         
            +
                  def parse_memory(value, unit)
         
     | 
| 
      
 95 
     | 
    
         
            +
                    unit ||= 'bytes'
         
     | 
| 
      
 96 
     | 
    
         
            +
                    multiplier = UNIT_TO_BYTES.fetch(unit.to_sym)
         
     | 
| 
      
 97 
     | 
    
         
            +
                    Integer(value) * multiplier
         
     | 
| 
      
 98 
     | 
    
         
            +
                  end
         
     | 
| 
       32 
99 
     | 
    
         
             
                end
         
     | 
| 
       33 
100 
     | 
    
         
             
              end
         
     | 
| 
       34 
101 
     | 
    
         
             
            end
         
     | 
    
        data/lib/libvirt/version.rb
    CHANGED
    
    
    
        data/lib/libvirt/xml.rb
    ADDED
    
    | 
         @@ -0,0 +1,23 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            require 'nokogiri'
         
     | 
| 
      
 4 
     | 
    
         
            +
            require 'libvirt/util'
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
            module Libvirt
         
     | 
| 
      
 7 
     | 
    
         
            +
              module Xml
         
     | 
| 
      
 8 
     | 
    
         
            +
                # https://libvirt.org/format.html
         
     | 
| 
      
 9 
     | 
    
         
            +
                # namespace for libvirt xml objects.
         
     | 
| 
      
 10 
     | 
    
         
            +
                # does not loaded by default.
         
     | 
| 
      
 11 
     | 
    
         
            +
                # requires nokogiri.
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
                require 'libvirt/xml/generic'
         
     | 
| 
      
 14 
     | 
    
         
            +
                require 'libvirt/xml/storage_pool'
         
     | 
| 
      
 15 
     | 
    
         
            +
                require 'libvirt/xml/storage_volume'
         
     | 
| 
      
 16 
     | 
    
         
            +
                require 'libvirt/xml/memory'
         
     | 
| 
      
 17 
     | 
    
         
            +
                require 'libvirt/xml/graphics'
         
     | 
| 
      
 18 
     | 
    
         
            +
                require 'libvirt/xml/disk'
         
     | 
| 
      
 19 
     | 
    
         
            +
                require 'libvirt/xml/max_vcpu'
         
     | 
| 
      
 20 
     | 
    
         
            +
                require 'libvirt/xml/vcpu'
         
     | 
| 
      
 21 
     | 
    
         
            +
                require 'libvirt/xml/domain'
         
     | 
| 
      
 22 
     | 
    
         
            +
              end
         
     | 
| 
      
 23 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,59 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module Libvirt
         
     | 
| 
      
 4 
     | 
    
         
            +
              module Xml
         
     | 
| 
      
 5 
     | 
    
         
            +
                class Disk < Generic
         
     | 
| 
      
 6 
     | 
    
         
            +
                  # https://libvirt.org/formatdomain.html#elementsDisks
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
                  attribute :type, type: :attr
         
     | 
| 
      
 9 
     | 
    
         
            +
                  attribute :device, type: :attr
         
     | 
| 
      
 10 
     | 
    
         
            +
                  attribute :model, type: :attr
         
     | 
| 
      
 11 
     | 
    
         
            +
                  attribute :raw_io, type: :attr, name: :rawio, cast: :bool
         
     | 
| 
      
 12 
     | 
    
         
            +
                  attribute :sg_io, type: :attr, name: :sgio
         
     | 
| 
      
 13 
     | 
    
         
            +
                  attribute :snapshot, type: :attr
         
     | 
| 
      
 14 
     | 
    
         
            +
                  attribute :source_file, name: :file, path: './source', type: :attr
         
     | 
| 
      
 15 
     | 
    
         
            +
                  attribute :source_dev, name: :dev, path: './source', type: :attr
         
     | 
| 
      
 16 
     | 
    
         
            +
                  attribute :source_dir, name: :dir, path: './source', type: :attr
         
     | 
| 
      
 17 
     | 
    
         
            +
                  attribute :source_protocol, name: :protocol, path: './source', type: :attr
         
     | 
| 
      
 18 
     | 
    
         
            +
                  attribute :source_pool, name: :pool, path: './source', type: :attr
         
     | 
| 
      
 19 
     | 
    
         
            +
                  attribute :source_volume, name: :volume, path: './source', type: :attr
         
     | 
| 
      
 20 
     | 
    
         
            +
                  attribute :source_mode, name: :mode, path: './source', type: :attr
         
     | 
| 
      
 21 
     | 
    
         
            +
                  attribute :source_name, name: :name, path: './source', type: :attr
         
     | 
| 
      
 22 
     | 
    
         
            +
                  attribute :source_type, name: :type, path: './source', type: :attr
         
     | 
| 
      
 23 
     | 
    
         
            +
                  attribute :source_managed, name: :managed, path: './source', type: :attr, cast: :bool
         
     | 
| 
      
 24 
     | 
    
         
            +
                  attribute :source_namespace, name: :namespace, path: './source', type: :attr
         
     | 
| 
      
 25 
     | 
    
         
            +
                  attribute :source_index, name: :index, path: './source', type: :attr
         
     | 
| 
      
 26 
     | 
    
         
            +
                  attribute :source_host_name, name: :name, path: './source/host', type: :attr
         
     | 
| 
      
 27 
     | 
    
         
            +
                  attribute :source_host_port, name: :port, path: './source/host', type: :attr
         
     | 
| 
      
 28 
     | 
    
         
            +
                  attribute :source_host_transport, name: :transport, path: './source/host', type: :attr
         
     | 
| 
      
 29 
     | 
    
         
            +
                  attribute :source_host_socket, name: :socket, path: './source/host', type: :attr
         
     | 
| 
      
 30 
     | 
    
         
            +
                  attribute :source_snapshot_name, name: :name, path: './source/snapshot', type: :attr
         
     | 
| 
      
 31 
     | 
    
         
            +
                  attribute :source_config_file, name: :file, path: './source/config', type: :attr
         
     | 
| 
      
 32 
     | 
    
         
            +
                  # TODO: source/auth
         
     | 
| 
      
 33 
     | 
    
         
            +
                  # TODO: source/encryption
         
     | 
| 
      
 34 
     | 
    
         
            +
                  # TODO: source/reservations
         
     | 
| 
      
 35 
     | 
    
         
            +
                  # TODO: source/initiator
         
     | 
| 
      
 36 
     | 
    
         
            +
                  # TODO: source/address
         
     | 
| 
      
 37 
     | 
    
         
            +
                  # TODO: source/slices
         
     | 
| 
      
 38 
     | 
    
         
            +
                  # TODO: backingStore
         
     | 
| 
      
 39 
     | 
    
         
            +
                  # TODO: mirror
         
     | 
| 
      
 40 
     | 
    
         
            +
                  # TODO: target
         
     | 
| 
      
 41 
     | 
    
         
            +
                  # TODO: iotune
         
     | 
| 
      
 42 
     | 
    
         
            +
                  # TODO: driver
         
     | 
| 
      
 43 
     | 
    
         
            +
                  # TODO: backenddomain
         
     | 
| 
      
 44 
     | 
    
         
            +
                  # TODO: boot
         
     | 
| 
      
 45 
     | 
    
         
            +
                  # TODO: encryption
         
     | 
| 
      
 46 
     | 
    
         
            +
                  # TODO: readonly
         
     | 
| 
      
 47 
     | 
    
         
            +
                  # TODO: shareable
         
     | 
| 
      
 48 
     | 
    
         
            +
                  # TODO: transient
         
     | 
| 
      
 49 
     | 
    
         
            +
                  # TODO: serial
         
     | 
| 
      
 50 
     | 
    
         
            +
                  # TODO: wwn
         
     | 
| 
      
 51 
     | 
    
         
            +
                  # TODO: vendor
         
     | 
| 
      
 52 
     | 
    
         
            +
                  # TODO: product
         
     | 
| 
      
 53 
     | 
    
         
            +
                  # TODO: address
         
     | 
| 
      
 54 
     | 
    
         
            +
                  # TODO: auth
         
     | 
| 
      
 55 
     | 
    
         
            +
                  # TODO: geometry
         
     | 
| 
      
 56 
     | 
    
         
            +
                  # TODO: blockio
         
     | 
| 
      
 57 
     | 
    
         
            +
                end
         
     | 
| 
      
 58 
     | 
    
         
            +
              end
         
     | 
| 
      
 59 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,76 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module Libvirt
         
     | 
| 
      
 4 
     | 
    
         
            +
              module Xml
         
     | 
| 
      
 5 
     | 
    
         
            +
                class Domain < Generic
         
     | 
| 
      
 6 
     | 
    
         
            +
                  # https://libvirt.org/formatdomain.html
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
                  root_path './domain'
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
                  attribute :name
         
     | 
| 
      
 11 
     | 
    
         
            +
                  attribute :uuid
         
     | 
| 
      
 12 
     | 
    
         
            +
                  attribute :gen_id, path: './genid'
         
     | 
| 
      
 13 
     | 
    
         
            +
                  attribute :title
         
     | 
| 
      
 14 
     | 
    
         
            +
                  attribute :description
         
     | 
| 
      
 15 
     | 
    
         
            +
                  attribute :metadata, type: :raw
         
     | 
| 
      
 16 
     | 
    
         
            +
                  attribute :vcpu, type: :struct, class: MaxVcpu
         
     | 
| 
      
 17 
     | 
    
         
            +
                  attribute :vcpus, type: :struct, array: true, class: Vcpu, cast: ->(objects) { objects.sort_by(&:id) }
         
     | 
| 
      
 18 
     | 
    
         
            +
                  attribute :memory, type: :struct, class: Memory
         
     | 
| 
      
 19 
     | 
    
         
            +
                  attribute :current_memory, type: :struct, class: Memory
         
     | 
| 
      
 20 
     | 
    
         
            +
                  attribute :max_memory, type: :struct, class: Memory
         
     | 
| 
      
 21 
     | 
    
         
            +
                  attribute :resource_partitions, path: './resource/partition', array: true
         
     | 
| 
      
 22 
     | 
    
         
            +
                  attribute :on_power_off
         
     | 
| 
      
 23 
     | 
    
         
            +
                  attribute :on_reboot
         
     | 
| 
      
 24 
     | 
    
         
            +
                  attribute :on_crash
         
     | 
| 
      
 25 
     | 
    
         
            +
                  attribute :on_lock_failure
         
     | 
| 
      
 26 
     | 
    
         
            +
                  attribute :device_graphics, type: :struct, path: './devices/graphics', class: Graphics, array: true
         
     | 
| 
      
 27 
     | 
    
         
            +
                  attribute :device_disks, type: :struct, path: './devices/disk', class: Disk, array: true
         
     | 
| 
      
 28 
     | 
    
         
            +
                  # https://libvirt.org/formatdomain.html#elementsDevices
         
     | 
| 
      
 29 
     | 
    
         
            +
                  # todo devices/emulator
         
     | 
| 
      
 30 
     | 
    
         
            +
                  # todo devices/interface
         
     | 
| 
      
 31 
     | 
    
         
            +
                  # todo devices/filesystem
         
     | 
| 
      
 32 
     | 
    
         
            +
                  # todo devices/controller
         
     | 
| 
      
 33 
     | 
    
         
            +
                  # todo devices/lease
         
     | 
| 
      
 34 
     | 
    
         
            +
                  # todo devices/hostdev
         
     | 
| 
      
 35 
     | 
    
         
            +
                  # todo devices/redirdev
         
     | 
| 
      
 36 
     | 
    
         
            +
                  # todo devices/smartcard
         
     | 
| 
      
 37 
     | 
    
         
            +
                  # todo devices/input
         
     | 
| 
      
 38 
     | 
    
         
            +
                  # todo devices/hub
         
     | 
| 
      
 39 
     | 
    
         
            +
                  # todo devices/video
         
     | 
| 
      
 40 
     | 
    
         
            +
                  # todo devices/parallel
         
     | 
| 
      
 41 
     | 
    
         
            +
                  # todo devices/serial
         
     | 
| 
      
 42 
     | 
    
         
            +
                  # todo devices/console
         
     | 
| 
      
 43 
     | 
    
         
            +
                  # todo devices/channel
         
     | 
| 
      
 44 
     | 
    
         
            +
                  # todo devices/sound
         
     | 
| 
      
 45 
     | 
    
         
            +
                  # todo devices/watchdog
         
     | 
| 
      
 46 
     | 
    
         
            +
                  # todo devices/memballoon
         
     | 
| 
      
 47 
     | 
    
         
            +
                  # todo devices/rng
         
     | 
| 
      
 48 
     | 
    
         
            +
                  # todo devices/tpm
         
     | 
| 
      
 49 
     | 
    
         
            +
                  # todo devices/nvram
         
     | 
| 
      
 50 
     | 
    
         
            +
                  # todo devices/panic
         
     | 
| 
      
 51 
     | 
    
         
            +
                  # todo devices/shmem
         
     | 
| 
      
 52 
     | 
    
         
            +
                  # todo devices/memory
         
     | 
| 
      
 53 
     | 
    
         
            +
                  # todo devices/iommu
         
     | 
| 
      
 54 
     | 
    
         
            +
                  # todo devices/vsock
         
     | 
| 
      
 55 
     | 
    
         
            +
                  # todo os
         
     | 
| 
      
 56 
     | 
    
         
            +
                  # todo bootloader
         
     | 
| 
      
 57 
     | 
    
         
            +
                  # todo bootloader_args
         
     | 
| 
      
 58 
     | 
    
         
            +
                  # todo sysinfo
         
     | 
| 
      
 59 
     | 
    
         
            +
                  # todo iothreads
         
     | 
| 
      
 60 
     | 
    
         
            +
                  # todo iothreadids
         
     | 
| 
      
 61 
     | 
    
         
            +
                  # todo cputune
         
     | 
| 
      
 62 
     | 
    
         
            +
                  # todo memoryBacking
         
     | 
| 
      
 63 
     | 
    
         
            +
                  # todo memtune
         
     | 
| 
      
 64 
     | 
    
         
            +
                  # todo numatune
         
     | 
| 
      
 65 
     | 
    
         
            +
                  # todo blkiotune
         
     | 
| 
      
 66 
     | 
    
         
            +
                  # todo cpu
         
     | 
| 
      
 67 
     | 
    
         
            +
                  # todo pm
         
     | 
| 
      
 68 
     | 
    
         
            +
                  # todo features
         
     | 
| 
      
 69 
     | 
    
         
            +
                  # todo clock
         
     | 
| 
      
 70 
     | 
    
         
            +
                  # todo perf
         
     | 
| 
      
 71 
     | 
    
         
            +
                  # todo seclabel
         
     | 
| 
      
 72 
     | 
    
         
            +
                  # todo keywrap
         
     | 
| 
      
 73 
     | 
    
         
            +
                  # todo launchSecurity
         
     | 
| 
      
 74 
     | 
    
         
            +
                end
         
     | 
| 
      
 75 
     | 
    
         
            +
              end
         
     | 
| 
      
 76 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,252 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module Libvirt
         
     | 
| 
      
 4 
     | 
    
         
            +
              module Xml
         
     | 
| 
      
 5 
     | 
    
         
            +
                class Generic
         
     | 
| 
      
 6 
     | 
    
         
            +
                  class_attribute :_root_path, instance_writer: false, default: '.'
         
     | 
| 
      
 7 
     | 
    
         
            +
                  class_attribute :_attributes_opts, instance_writer: false, default: {}
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
                  def self.inherited(subclass)
         
     | 
| 
      
 10 
     | 
    
         
            +
                    subclass._root_path = '.'
         
     | 
| 
      
 11 
     | 
    
         
            +
                    subclass._attributes_opts = _attributes_opts.dup
         
     | 
| 
      
 12 
     | 
    
         
            +
                  end
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
                  def self.root_path(path)
         
     | 
| 
      
 15 
     | 
    
         
            +
                    self._root_path = path
         
     | 
| 
      
 16 
     | 
    
         
            +
                  end
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
                  def self.attributes(*names)
         
     | 
| 
      
 19 
     | 
    
         
            +
                    options = names.extract_options!
         
     | 
| 
      
 20 
     | 
    
         
            +
                    names.each do |name|
         
     | 
| 
      
 21 
     | 
    
         
            +
                      _attributes_opts.merge!(name.to_sym => options.dup)
         
     | 
| 
      
 22 
     | 
    
         
            +
                    end
         
     | 
| 
      
 23 
     | 
    
         
            +
                    attr_accessor(*names)
         
     | 
| 
      
 24 
     | 
    
         
            +
                  end
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
                  def self.attribute(name, options = {})
         
     | 
| 
      
 27 
     | 
    
         
            +
                    _attributes_opts.merge!(name.to_sym => options.dup)
         
     | 
| 
      
 28 
     | 
    
         
            +
                    attr_accessor name
         
     | 
| 
      
 29 
     | 
    
         
            +
                  end
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
                  # @param xml [String]
         
     | 
| 
      
 32 
     | 
    
         
            +
                  # @return [Class<LibvirtXml::Generic>]
         
     | 
| 
      
 33 
     | 
    
         
            +
                  def self.load(xml)
         
     | 
| 
      
 34 
     | 
    
         
            +
                    xml_node = Nokogiri::XML(xml).xpath(_root_path).first
         
     | 
| 
      
 35 
     | 
    
         
            +
                    new(xml_node)
         
     | 
| 
      
 36 
     | 
    
         
            +
                  end
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
                  # Build xml object with attributes.
         
     | 
| 
      
 39 
     | 
    
         
            +
                  # @param attrs [Hash]
         
     | 
| 
      
 40 
     | 
    
         
            +
                  # @return [Xml::Base]
         
     | 
| 
      
 41 
     | 
    
         
            +
                  def self.build(attrs = {})
         
     | 
| 
      
 42 
     | 
    
         
            +
                    xml_node = Nokogiri::XML(nil)
         
     | 
| 
      
 43 
     | 
    
         
            +
                    obj = new(xml_node)
         
     | 
| 
      
 44 
     | 
    
         
            +
                    attrs.each { |key, val| obj.public_send("#{key}=", val) }
         
     | 
| 
      
 45 
     | 
    
         
            +
                    obj
         
     | 
| 
      
 46 
     | 
    
         
            +
                  end
         
     | 
| 
      
 47 
     | 
    
         
            +
             
     | 
| 
      
 48 
     | 
    
         
            +
                  # @param xml_node [Nokogiri::XML::Element]
         
     | 
| 
      
 49 
     | 
    
         
            +
                  def initialize(xml_node)
         
     | 
| 
      
 50 
     | 
    
         
            +
                    @xml_node = xml_node
         
     | 
| 
      
 51 
     | 
    
         
            +
                    parse_xml_node
         
     | 
| 
      
 52 
     | 
    
         
            +
                  end
         
     | 
| 
      
 53 
     | 
    
         
            +
             
     | 
| 
      
 54 
     | 
    
         
            +
                  # @param attr [Symbol,String]
         
     | 
| 
      
 55 
     | 
    
         
            +
                  # @return [Object,nil]
         
     | 
| 
      
 56 
     | 
    
         
            +
                  def [](attr)
         
     | 
| 
      
 57 
     | 
    
         
            +
                    read_attribute(attr)
         
     | 
| 
      
 58 
     | 
    
         
            +
                  end
         
     | 
| 
      
 59 
     | 
    
         
            +
             
     | 
| 
      
 60 
     | 
    
         
            +
                  # @param attr [Symbol,String]
         
     | 
| 
      
 61 
     | 
    
         
            +
                  # @param value [Object,nil]
         
     | 
| 
      
 62 
     | 
    
         
            +
                  # @return [Object,nil]
         
     | 
| 
      
 63 
     | 
    
         
            +
                  def []=(attr, value)
         
     | 
| 
      
 64 
     | 
    
         
            +
                    write_attribute(attr, value)
         
     | 
| 
      
 65 
     | 
    
         
            +
                  end
         
     | 
| 
      
 66 
     | 
    
         
            +
             
     | 
| 
      
 67 
     | 
    
         
            +
                  # @return [Hash{Symbol=>(Object,nil)}]
         
     | 
| 
      
 68 
     | 
    
         
            +
                  def to_h
         
     | 
| 
      
 69 
     | 
    
         
            +
                    _attributes_opts.map do |name, _opts|
         
     | 
| 
      
 70 
     | 
    
         
            +
                      value = public_send(name)
         
     | 
| 
      
 71 
     | 
    
         
            +
                      [name, serialize_for_hash(value)]
         
     | 
| 
      
 72 
     | 
    
         
            +
                    end.to_h
         
     | 
| 
      
 73 
     | 
    
         
            +
                  end
         
     | 
| 
      
 74 
     | 
    
         
            +
             
     | 
| 
      
 75 
     | 
    
         
            +
                  # @return [String]
         
     | 
| 
      
 76 
     | 
    
         
            +
                  def to_xml
         
     | 
| 
      
 77 
     | 
    
         
            +
                    @xml_node.to_xml
         
     | 
| 
      
 78 
     | 
    
         
            +
                  end
         
     | 
| 
      
 79 
     | 
    
         
            +
             
     | 
| 
      
 80 
     | 
    
         
            +
                  delegate :as_json, :to_json, to: :to_h
         
     | 
| 
      
 81 
     | 
    
         
            +
             
     | 
| 
      
 82 
     | 
    
         
            +
                  private
         
     | 
| 
      
 83 
     | 
    
         
            +
             
     | 
| 
      
 84 
     | 
    
         
            +
                  def parse_xml_node
         
     | 
| 
      
 85 
     | 
    
         
            +
                    _attributes_opts.each do |name, opts|
         
     | 
| 
      
 86 
     | 
    
         
            +
                      value = parse_node(name, opts)
         
     | 
| 
      
 87 
     | 
    
         
            +
                      value = decode(value, opts)
         
     | 
| 
      
 88 
     | 
    
         
            +
                      write_attribute name, value
         
     | 
| 
      
 89 
     | 
    
         
            +
                    end
         
     | 
| 
      
 90 
     | 
    
         
            +
                  end
         
     | 
| 
      
 91 
     | 
    
         
            +
             
     | 
| 
      
 92 
     | 
    
         
            +
                  # Parse node value using "parse_node_#{type}" method.
         
     | 
| 
      
 93 
     | 
    
         
            +
                  # @param name [Symbol]
         
     | 
| 
      
 94 
     | 
    
         
            +
                  # @param opts [Hash{Symbol=>Object}]
         
     | 
| 
      
 95 
     | 
    
         
            +
                  # @return [Object, nil]
         
     | 
| 
      
 96 
     | 
    
         
            +
                  def parse_node(name, opts)
         
     | 
| 
      
 97 
     | 
    
         
            +
                    type = opts[:type] || :text
         
     | 
| 
      
 98 
     | 
    
         
            +
                    meth = "parse_node_#{type}"
         
     | 
| 
      
 99 
     | 
    
         
            +
             
     | 
| 
      
 100 
     | 
    
         
            +
                    if opts[:apply]
         
     | 
| 
      
 101 
     | 
    
         
            +
                      opts[:apply].call(@xml_node, opts)
         
     | 
| 
      
 102 
     | 
    
         
            +
                    elsif respond_to?(meth, true)
         
     | 
| 
      
 103 
     | 
    
         
            +
                      send(meth, name, opts)
         
     | 
| 
      
 104 
     | 
    
         
            +
                    else
         
     | 
| 
      
 105 
     | 
    
         
            +
                      raise ArgumentError, "Invalid :type option #{type.inspect} for attribute #{name}"
         
     | 
| 
      
 106 
     | 
    
         
            +
                    end
         
     | 
| 
      
 107 
     | 
    
         
            +
                  end
         
     | 
| 
      
 108 
     | 
    
         
            +
             
     | 
| 
      
 109 
     | 
    
         
            +
                  # Cast value using "decode_#{type}" method.
         
     | 
| 
      
 110 
     | 
    
         
            +
                  # @param value [String]
         
     | 
| 
      
 111 
     | 
    
         
            +
                  # @param opts [Hash{Symbol=>Object}]
         
     | 
| 
      
 112 
     | 
    
         
            +
                  # @return [Object, nil]
         
     | 
| 
      
 113 
     | 
    
         
            +
                  def decode(value, opts)
         
     | 
| 
      
 114 
     | 
    
         
            +
                    return if value.nil?
         
     | 
| 
      
 115 
     | 
    
         
            +
             
     | 
| 
      
 116 
     | 
    
         
            +
                    cast = opts[:cast]
         
     | 
| 
      
 117 
     | 
    
         
            +
                    return value if cast.nil?
         
     | 
| 
      
 118 
     | 
    
         
            +
             
     | 
| 
      
 119 
     | 
    
         
            +
                    meth = "decode_#{cast}"
         
     | 
| 
      
 120 
     | 
    
         
            +
             
     | 
| 
      
 121 
     | 
    
         
            +
                    if opts[:array]
         
     | 
| 
      
 122 
     | 
    
         
            +
                      value.map do |val|
         
     | 
| 
      
 123 
     | 
    
         
            +
                        if cast.is_a?(Proc)
         
     | 
| 
      
 124 
     | 
    
         
            +
                          cast.call(val, opts)
         
     | 
| 
      
 125 
     | 
    
         
            +
                        elsif respond_to?(meth, true)
         
     | 
| 
      
 126 
     | 
    
         
            +
                          send(meth, val, opts)
         
     | 
| 
      
 127 
     | 
    
         
            +
                        else
         
     | 
| 
      
 128 
     | 
    
         
            +
                          raise ArgumentError, "invalid :cast option #{cast.inspect}"
         
     | 
| 
      
 129 
     | 
    
         
            +
                        end
         
     | 
| 
      
 130 
     | 
    
         
            +
                      end
         
     | 
| 
      
 131 
     | 
    
         
            +
                    end
         
     | 
| 
      
 132 
     | 
    
         
            +
             
     | 
| 
      
 133 
     | 
    
         
            +
                    if cast.is_a?(Proc)
         
     | 
| 
      
 134 
     | 
    
         
            +
                      cast.call(value, opts)
         
     | 
| 
      
 135 
     | 
    
         
            +
                    elsif respond_to?(meth, true)
         
     | 
| 
      
 136 
     | 
    
         
            +
                      send(meth, value, opts)
         
     | 
| 
      
 137 
     | 
    
         
            +
                    else
         
     | 
| 
      
 138 
     | 
    
         
            +
                      raise ArgumentError, "invalid :cast option #{cast.inspect}"
         
     | 
| 
      
 139 
     | 
    
         
            +
                    end
         
     | 
| 
      
 140 
     | 
    
         
            +
                  end
         
     | 
| 
      
 141 
     | 
    
         
            +
             
     | 
| 
      
 142 
     | 
    
         
            +
                  # @param value [String, Boolean]
         
     | 
| 
      
 143 
     | 
    
         
            +
                  # @return [Boolean]
         
     | 
| 
      
 144 
     | 
    
         
            +
                  def decode_bool(value, _opts)
         
     | 
| 
      
 145 
     | 
    
         
            +
                    return value if value.is_a?(TrueClass) || value.is_a?(FalseClass)
         
     | 
| 
      
 146 
     | 
    
         
            +
             
     | 
| 
      
 147 
     | 
    
         
            +
                    return true if value == 'yes'
         
     | 
| 
      
 148 
     | 
    
         
            +
             
     | 
| 
      
 149 
     | 
    
         
            +
                    return false if value == 'no'
         
     | 
| 
      
 150 
     | 
    
         
            +
             
     | 
| 
      
 151 
     | 
    
         
            +
                    nil
         
     | 
| 
      
 152 
     | 
    
         
            +
                  end
         
     | 
| 
      
 153 
     | 
    
         
            +
             
     | 
| 
      
 154 
     | 
    
         
            +
                  # @param value [String, Integer]
         
     | 
| 
      
 155 
     | 
    
         
            +
                  # @return [Integer]
         
     | 
| 
      
 156 
     | 
    
         
            +
                  # @raise [ArgumentError]
         
     | 
| 
      
 157 
     | 
    
         
            +
                  def decode_int(value, _opts)
         
     | 
| 
      
 158 
     | 
    
         
            +
                    Integer(value)
         
     | 
| 
      
 159 
     | 
    
         
            +
                  end
         
     | 
| 
      
 160 
     | 
    
         
            +
             
     | 
| 
      
 161 
     | 
    
         
            +
                  def find_nodes(name, opts)
         
     | 
| 
      
 162 
     | 
    
         
            +
                    value_name = opts[:name]&.to_sym || name
         
     | 
| 
      
 163 
     | 
    
         
            +
                    path = opts[:path] || "./#{value_name}"
         
     | 
| 
      
 164 
     | 
    
         
            +
                    path == :root ? [@xml_node] : @xml_node.xpath(path)
         
     | 
| 
      
 165 
     | 
    
         
            +
                  end
         
     | 
| 
      
 166 
     | 
    
         
            +
             
     | 
| 
      
 167 
     | 
    
         
            +
                  def parse_node_text(name, opts)
         
     | 
| 
      
 168 
     | 
    
         
            +
                    nodes = find_nodes(name, opts)
         
     | 
| 
      
 169 
     | 
    
         
            +
             
     | 
| 
      
 170 
     | 
    
         
            +
                    nodes.map(&:text) if opts[:array]
         
     | 
| 
      
 171 
     | 
    
         
            +
             
     | 
| 
      
 172 
     | 
    
         
            +
                    node = nodes.first
         
     | 
| 
      
 173 
     | 
    
         
            +
                    return if node.nil?
         
     | 
| 
      
 174 
     | 
    
         
            +
             
     | 
| 
      
 175 
     | 
    
         
            +
                    node.text
         
     | 
| 
      
 176 
     | 
    
         
            +
                  end
         
     | 
| 
      
 177 
     | 
    
         
            +
             
     | 
| 
      
 178 
     | 
    
         
            +
                  def parse_node_attr(name, opts)
         
     | 
| 
      
 179 
     | 
    
         
            +
                    nodes = find_nodes name, { path: :root }.merge(opts)
         
     | 
| 
      
 180 
     | 
    
         
            +
                    value_name = opts[:name]&.to_sym || name
         
     | 
| 
      
 181 
     | 
    
         
            +
             
     | 
| 
      
 182 
     | 
    
         
            +
                    nodes.map { |node| node[value_name.to_s] } if opts[:array]
         
     | 
| 
      
 183 
     | 
    
         
            +
             
     | 
| 
      
 184 
     | 
    
         
            +
                    node = nodes.first
         
     | 
| 
      
 185 
     | 
    
         
            +
                    return if node.nil?
         
     | 
| 
      
 186 
     | 
    
         
            +
             
     | 
| 
      
 187 
     | 
    
         
            +
                    node[value_name.to_s]
         
     | 
| 
      
 188 
     | 
    
         
            +
                  end
         
     | 
| 
      
 189 
     | 
    
         
            +
             
     | 
| 
      
 190 
     | 
    
         
            +
                  def parse_node_struct(name, opts)
         
     | 
| 
      
 191 
     | 
    
         
            +
                    klass = opts[:class]
         
     | 
| 
      
 192 
     | 
    
         
            +
                    raise ArgumentError, "Invalid :class option nil for attribute #{name}" if klass.nil?
         
     | 
| 
      
 193 
     | 
    
         
            +
             
     | 
| 
      
 194 
     | 
    
         
            +
                    nodes = find_nodes(name, opts)
         
     | 
| 
      
 195 
     | 
    
         
            +
             
     | 
| 
      
 196 
     | 
    
         
            +
                    nodes.map { |node| klass.new(node) } if opts[:array]
         
     | 
| 
      
 197 
     | 
    
         
            +
             
     | 
| 
      
 198 
     | 
    
         
            +
                    node = nodes.first
         
     | 
| 
      
 199 
     | 
    
         
            +
                    return if node.nil?
         
     | 
| 
      
 200 
     | 
    
         
            +
             
     | 
| 
      
 201 
     | 
    
         
            +
                    klass.new(node)
         
     | 
| 
      
 202 
     | 
    
         
            +
                  end
         
     | 
| 
      
 203 
     | 
    
         
            +
             
     | 
| 
      
 204 
     | 
    
         
            +
                  def parse_node_raw(name, opts)
         
     | 
| 
      
 205 
     | 
    
         
            +
                    nodes = find_nodes(name, opts)
         
     | 
| 
      
 206 
     | 
    
         
            +
             
     | 
| 
      
 207 
     | 
    
         
            +
                    nodes.map(&:to_xml) if opts[:array]
         
     | 
| 
      
 208 
     | 
    
         
            +
             
     | 
| 
      
 209 
     | 
    
         
            +
                    node = nodes.first
         
     | 
| 
      
 210 
     | 
    
         
            +
                    return if node.nil?
         
     | 
| 
      
 211 
     | 
    
         
            +
             
     | 
| 
      
 212 
     | 
    
         
            +
                    node.to_xml
         
     | 
| 
      
 213 
     | 
    
         
            +
                  end
         
     | 
| 
      
 214 
     | 
    
         
            +
             
     | 
| 
      
 215 
     | 
    
         
            +
                  def parse_node_memory(name, opts)
         
     | 
| 
      
 216 
     | 
    
         
            +
                    nodes = find_nodes(name, opts)
         
     | 
| 
      
 217 
     | 
    
         
            +
             
     | 
| 
      
 218 
     | 
    
         
            +
                    if opts[:array]
         
     | 
| 
      
 219 
     | 
    
         
            +
                      return [] if nodes.empty?
         
     | 
| 
      
 220 
     | 
    
         
            +
             
     | 
| 
      
 221 
     | 
    
         
            +
                      nodes.map { |node| Util.parse_memory node.text, node['unit'] }
         
     | 
| 
      
 222 
     | 
    
         
            +
                    end
         
     | 
| 
      
 223 
     | 
    
         
            +
             
     | 
| 
      
 224 
     | 
    
         
            +
                    node = nodes.first
         
     | 
| 
      
 225 
     | 
    
         
            +
                    return if node.nil?
         
     | 
| 
      
 226 
     | 
    
         
            +
             
     | 
| 
      
 227 
     | 
    
         
            +
                    Util.parse_memory node.text, node['unit']
         
     | 
| 
      
 228 
     | 
    
         
            +
                  end
         
     | 
| 
      
 229 
     | 
    
         
            +
             
     | 
| 
      
 230 
     | 
    
         
            +
                  def read_attribute(attr)
         
     | 
| 
      
 231 
     | 
    
         
            +
                    attr = attr.to_sym
         
     | 
| 
      
 232 
     | 
    
         
            +
                    raise ArgumentError, "can't find attribute #{attr}" unless _attributes_opts.key?(attr)
         
     | 
| 
      
 233 
     | 
    
         
            +
             
     | 
| 
      
 234 
     | 
    
         
            +
                    instance_variable_get :"@#{attr}"
         
     | 
| 
      
 235 
     | 
    
         
            +
                  end
         
     | 
| 
      
 236 
     | 
    
         
            +
             
     | 
| 
      
 237 
     | 
    
         
            +
                  def write_attribute(attr, value)
         
     | 
| 
      
 238 
     | 
    
         
            +
                    attr = attr.to_sym
         
     | 
| 
      
 239 
     | 
    
         
            +
                    raise ArgumentError, "can't find attribute #{attr}" unless _attributes_opts.key?(attr)
         
     | 
| 
      
 240 
     | 
    
         
            +
             
     | 
| 
      
 241 
     | 
    
         
            +
                    instance_variable_set :"@#{attr}", value
         
     | 
| 
      
 242 
     | 
    
         
            +
                  end
         
     | 
| 
      
 243 
     | 
    
         
            +
             
     | 
| 
      
 244 
     | 
    
         
            +
                  def serialize_for_hash(value)
         
     | 
| 
      
 245 
     | 
    
         
            +
                    return value.to_h if value.is_a?(Generic)
         
     | 
| 
      
 246 
     | 
    
         
            +
                    return value.map { |val| serialize_for_hash(val) } if value.is_a?(Array)
         
     | 
| 
      
 247 
     | 
    
         
            +
             
     | 
| 
      
 248 
     | 
    
         
            +
                    value
         
     | 
| 
      
 249 
     | 
    
         
            +
                  end
         
     | 
| 
      
 250 
     | 
    
         
            +
                end
         
     | 
| 
      
 251 
     | 
    
         
            +
              end
         
     | 
| 
      
 252 
     | 
    
         
            +
            end
         
     |