bbrowning-virtualbox 0.7.6.dev
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.
- data/.gitignore +8 -0
- data/.yardopts +3 -0
- data/Gemfile +16 -0
- data/LICENSE +19 -0
- data/Rakefile +33 -0
- data/Readme.md +70 -0
- data/docs/GettingStarted.md +196 -0
- data/docs/WhatsNew.md +12 -0
- data/features/README.md +33 -0
- data/features/global.feature +19 -0
- data/features/global_extra_data.feature +27 -0
- data/features/step_definitions/abstract_model_steps.rb +39 -0
- data/features/step_definitions/extra_data_steps.rb +36 -0
- data/features/step_definitions/global_steps.rb +29 -0
- data/features/step_definitions/nat_engine_steps.rb +76 -0
- data/features/step_definitions/network_adapter_steps.rb +38 -0
- data/features/step_definitions/shared_folder_steps.rb +76 -0
- data/features/step_definitions/snapshot_steps.rb +74 -0
- data/features/step_definitions/storage_controller_steps.rb +16 -0
- data/features/step_definitions/virtualbox_steps.rb +17 -0
- data/features/step_definitions/vm_steps.rb +50 -0
- data/features/support/env.rb +61 -0
- data/features/support/helpers.rb +38 -0
- data/features/support/hooks.rb +30 -0
- data/features/support/ordered_hash.rb +49 -0
- data/features/support/vboxmanage.rb +191 -0
- data/features/version.feature +16 -0
- data/features/vm.feature +13 -0
- data/features/vm_bios.feature +29 -0
- data/features/vm_cpu.feature +29 -0
- data/features/vm_extra_data.feature +35 -0
- data/features/vm_hw_virt.feature +29 -0
- data/features/vm_nat_engine.feature +57 -0
- data/features/vm_network_adapters.feature +27 -0
- data/features/vm_shared_folders.feature +42 -0
- data/features/vm_snapshots.feature +29 -0
- data/features/vm_storage_controllers.feature +11 -0
- data/lib/virtualbox.rb +11 -0
- data/lib/virtualbox/abstract_model.rb +281 -0
- data/lib/virtualbox/abstract_model/attributable.rb +290 -0
- data/lib/virtualbox/abstract_model/dirty.rb +177 -0
- data/lib/virtualbox/abstract_model/interface_attributes.rb +98 -0
- data/lib/virtualbox/abstract_model/relatable.rb +332 -0
- data/lib/virtualbox/abstract_model/validatable.rb +167 -0
- data/lib/virtualbox/abstract_model/version_matcher.rb +35 -0
- data/lib/virtualbox/appliance.rb +62 -0
- data/lib/virtualbox/audio_adapter.rb +52 -0
- data/lib/virtualbox/bios.rb +50 -0
- data/lib/virtualbox/com.rb +23 -0
- data/lib/virtualbox/com/abstract_enum.rb +43 -0
- data/lib/virtualbox/com/abstract_implementer.rb +45 -0
- data/lib/virtualbox/com/abstract_interface.rb +167 -0
- data/lib/virtualbox/com/base_interface.rb +38 -0
- data/lib/virtualbox/com/ffi/interface.rb +150 -0
- data/lib/virtualbox/com/ffi/interfaces.rb +54 -0
- data/lib/virtualbox/com/ffi/util.rb +119 -0
- data/lib/virtualbox/com/ffi/vboxxpcomc.rb +31 -0
- data/lib/virtualbox/com/ffi_interface.rb +96 -0
- data/lib/virtualbox/com/implementer/base.rb +59 -0
- data/lib/virtualbox/com/implementer/ffi.rb +361 -0
- data/lib/virtualbox/com/implementer/mscom.rb +175 -0
- data/lib/virtualbox/com/implementer/nil.rb +10 -0
- data/lib/virtualbox/com/interface/3.1.x/access_mode.rb +11 -0
- data/lib/virtualbox/com/interface/3.1.x/appliance.rb +22 -0
- data/lib/virtualbox/com/interface/3.1.x/audio_adapter.rb +15 -0
- data/lib/virtualbox/com/interface/3.1.x/audio_controller_type.rb +11 -0
- data/lib/virtualbox/com/interface/3.1.x/audio_driver_type.rb +11 -0
- data/lib/virtualbox/com/interface/3.1.x/bios_boot_menu_mode.rb +11 -0
- data/lib/virtualbox/com/interface/3.1.x/bios_settings.rb +21 -0
- data/lib/virtualbox/com/interface/3.1.x/clipboard_mode.rb +11 -0
- data/lib/virtualbox/com/interface/3.1.x/console.rb +50 -0
- data/lib/virtualbox/com/interface/3.1.x/cpu_property_type.rb +11 -0
- data/lib/virtualbox/com/interface/3.1.x/device_type.rb +11 -0
- data/lib/virtualbox/com/interface/3.1.x/dhcp_server.rb +22 -0
- data/lib/virtualbox/com/interface/3.1.x/firmware_type.rb +11 -0
- data/lib/virtualbox/com/interface/3.1.x/guest_os_type.rb +23 -0
- data/lib/virtualbox/com/interface/3.1.x/host.rb +42 -0
- data/lib/virtualbox/com/interface/3.1.x/host_network_interface.rb +30 -0
- data/lib/virtualbox/com/interface/3.1.x/host_network_interface_medium_type.rb +11 -0
- data/lib/virtualbox/com/interface/3.1.x/host_network_interface_status.rb +11 -0
- data/lib/virtualbox/com/interface/3.1.x/host_network_interface_type.rb +11 -0
- data/lib/virtualbox/com/interface/3.1.x/host_usb_device.rb +13 -0
- data/lib/virtualbox/com/interface/3.1.x/host_usb_device_filter.rb +13 -0
- data/lib/virtualbox/com/interface/3.1.x/hw_virt_ex_property_type.rb +11 -0
- data/lib/virtualbox/com/interface/3.1.x/machine.rb +105 -0
- data/lib/virtualbox/com/interface/3.1.x/machine_state.rb +14 -0
- data/lib/virtualbox/com/interface/3.1.x/medium.rb +50 -0
- data/lib/virtualbox/com/interface/3.1.x/medium_attachment.rb +18 -0
- data/lib/virtualbox/com/interface/3.1.x/medium_format.rb +18 -0
- data/lib/virtualbox/com/interface/3.1.x/medium_state.rb +11 -0
- data/lib/virtualbox/com/interface/3.1.x/medium_type.rb +11 -0
- data/lib/virtualbox/com/interface/3.1.x/medium_variant.rb +11 -0
- data/lib/virtualbox/com/interface/3.1.x/network_adapter.rb +30 -0
- data/lib/virtualbox/com/interface/3.1.x/network_adapter_type.rb +11 -0
- data/lib/virtualbox/com/interface/3.1.x/network_attachment_type.rb +11 -0
- data/lib/virtualbox/com/interface/3.1.x/nsiexception.rb +23 -0
- data/lib/virtualbox/com/interface/3.1.x/nsisupports.rb +15 -0
- data/lib/virtualbox/com/interface/3.1.x/parallel_port.rb +17 -0
- data/lib/virtualbox/com/interface/3.1.x/port_mode.rb +11 -0
- data/lib/virtualbox/com/interface/3.1.x/progress.rb +63 -0
- data/lib/virtualbox/com/interface/3.1.x/serial_port.rb +19 -0
- data/lib/virtualbox/com/interface/3.1.x/session.rb +18 -0
- data/lib/virtualbox/com/interface/3.1.x/session_state.rb +11 -0
- data/lib/virtualbox/com/interface/3.1.x/session_type.rb +11 -0
- data/lib/virtualbox/com/interface/3.1.x/shared_folder.rb +17 -0
- data/lib/virtualbox/com/interface/3.1.x/snapshot.rb +20 -0
- data/lib/virtualbox/com/interface/3.1.x/storage_bus.rb +11 -0
- data/lib/virtualbox/com/interface/3.1.x/storage_controller.rb +23 -0
- data/lib/virtualbox/com/interface/3.1.x/storage_controller_type.rb +11 -0
- data/lib/virtualbox/com/interface/3.1.x/system_properties.rb +37 -0
- data/lib/virtualbox/com/interface/3.1.x/usb_controller.rb +20 -0
- data/lib/virtualbox/com/interface/3.1.x/usb_device.rb +24 -0
- data/lib/virtualbox/com/interface/3.1.x/usb_device_filter.rb +23 -0
- data/lib/virtualbox/com/interface/3.1.x/usb_device_filter_action.rb +11 -0
- data/lib/virtualbox/com/interface/3.1.x/usb_device_state.rb +11 -0
- data/lib/virtualbox/com/interface/3.1.x/virtual_box_error_info.rb +17 -0
- data/lib/virtualbox/com/interface/3.1.x/virtual_system_description.rb +19 -0
- data/lib/virtualbox/com/interface/3.1.x/virtual_system_description_type.rb +14 -0
- data/lib/virtualbox/com/interface/3.1.x/virtual_system_description_value_type.rb +11 -0
- data/lib/virtualbox/com/interface/3.1.x/virtualbox.rb +67 -0
- data/lib/virtualbox/com/interface/3.1.x/vrdp_auth_type.rb +11 -0
- data/lib/virtualbox/com/interface/3.1.x/vrdp_server.rb +19 -0
- data/lib/virtualbox/com/interface/3.2.x/access_mode.rb +11 -0
- data/lib/virtualbox/com/interface/3.2.x/appliance.rb +22 -0
- data/lib/virtualbox/com/interface/3.2.x/audio_adapter.rb +15 -0
- data/lib/virtualbox/com/interface/3.2.x/audio_controller_type.rb +11 -0
- data/lib/virtualbox/com/interface/3.2.x/audio_driver_type.rb +11 -0
- data/lib/virtualbox/com/interface/3.2.x/bios_boot_menu_mode.rb +11 -0
- data/lib/virtualbox/com/interface/3.2.x/bios_settings.rb +21 -0
- data/lib/virtualbox/com/interface/3.2.x/clipboard_mode.rb +11 -0
- data/lib/virtualbox/com/interface/3.2.x/console.rb +50 -0
- data/lib/virtualbox/com/interface/3.2.x/cpu_property_type.rb +11 -0
- data/lib/virtualbox/com/interface/3.2.x/device_type.rb +11 -0
- data/lib/virtualbox/com/interface/3.2.x/dhcp_server.rb +22 -0
- data/lib/virtualbox/com/interface/3.2.x/firmware_type.rb +11 -0
- data/lib/virtualbox/com/interface/3.2.x/guest.rb +13 -0
- data/lib/virtualbox/com/interface/3.2.x/guest_os_type.rb +33 -0
- data/lib/virtualbox/com/interface/3.2.x/host.rb +43 -0
- data/lib/virtualbox/com/interface/3.2.x/host_network_interface.rb +30 -0
- data/lib/virtualbox/com/interface/3.2.x/host_network_interface_medium_type.rb +11 -0
- data/lib/virtualbox/com/interface/3.2.x/host_network_interface_status.rb +11 -0
- data/lib/virtualbox/com/interface/3.2.x/host_network_interface_type.rb +11 -0
- data/lib/virtualbox/com/interface/3.2.x/host_usb_device.rb +13 -0
- data/lib/virtualbox/com/interface/3.2.x/host_usb_device_filter.rb +13 -0
- data/lib/virtualbox/com/interface/3.2.x/hw_virt_ex_property_type.rb +11 -0
- data/lib/virtualbox/com/interface/3.2.x/keyboard_hid_type.rb +11 -0
- data/lib/virtualbox/com/interface/3.2.x/machine.rb +118 -0
- data/lib/virtualbox/com/interface/3.2.x/machine_state.rb +14 -0
- data/lib/virtualbox/com/interface/3.2.x/medium.rb +51 -0
- data/lib/virtualbox/com/interface/3.2.x/medium_attachment.rb +18 -0
- data/lib/virtualbox/com/interface/3.2.x/medium_format.rb +18 -0
- data/lib/virtualbox/com/interface/3.2.x/medium_state.rb +11 -0
- data/lib/virtualbox/com/interface/3.2.x/medium_type.rb +11 -0
- data/lib/virtualbox/com/interface/3.2.x/medium_variant.rb +11 -0
- data/lib/virtualbox/com/interface/3.2.x/nat_alias_mode.rb +11 -0
- data/lib/virtualbox/com/interface/3.2.x/nat_engine.rb +27 -0
- data/lib/virtualbox/com/interface/3.2.x/nat_protocol.rb +11 -0
- data/lib/virtualbox/com/interface/3.2.x/network_adapter.rb +34 -0
- data/lib/virtualbox/com/interface/3.2.x/network_adapter_type.rb +11 -0
- data/lib/virtualbox/com/interface/3.2.x/network_attachment_type.rb +11 -0
- data/lib/virtualbox/com/interface/3.2.x/nsiexception.rb +23 -0
- data/lib/virtualbox/com/interface/3.2.x/nsisupports.rb +15 -0
- data/lib/virtualbox/com/interface/3.2.x/parallel_port.rb +17 -0
- data/lib/virtualbox/com/interface/3.2.x/pointing_hid_type.rb +11 -0
- data/lib/virtualbox/com/interface/3.2.x/port_mode.rb +11 -0
- data/lib/virtualbox/com/interface/3.2.x/progress.rb +63 -0
- data/lib/virtualbox/com/interface/3.2.x/serial_port.rb +19 -0
- data/lib/virtualbox/com/interface/3.2.x/session.rb +18 -0
- data/lib/virtualbox/com/interface/3.2.x/session_state.rb +11 -0
- data/lib/virtualbox/com/interface/3.2.x/session_type.rb +11 -0
- data/lib/virtualbox/com/interface/3.2.x/shared_folder.rb +17 -0
- data/lib/virtualbox/com/interface/3.2.x/snapshot.rb +20 -0
- data/lib/virtualbox/com/interface/3.2.x/storage_bus.rb +11 -0
- data/lib/virtualbox/com/interface/3.2.x/storage_controller.rb +24 -0
- data/lib/virtualbox/com/interface/3.2.x/storage_controller_type.rb +11 -0
- data/lib/virtualbox/com/interface/3.2.x/system_properties.rb +42 -0
- data/lib/virtualbox/com/interface/3.2.x/usb_controller.rb +21 -0
- data/lib/virtualbox/com/interface/3.2.x/usb_device.rb +24 -0
- data/lib/virtualbox/com/interface/3.2.x/usb_device_filter.rb +23 -0
- data/lib/virtualbox/com/interface/3.2.x/usb_device_filter_action.rb +11 -0
- data/lib/virtualbox/com/interface/3.2.x/usb_device_state.rb +11 -0
- data/lib/virtualbox/com/interface/3.2.x/virtual_box_error_info.rb +17 -0
- data/lib/virtualbox/com/interface/3.2.x/virtual_system_description.rb +19 -0
- data/lib/virtualbox/com/interface/3.2.x/virtual_system_description_type.rb +14 -0
- data/lib/virtualbox/com/interface/3.2.x/virtual_system_description_value_type.rb +11 -0
- data/lib/virtualbox/com/interface/3.2.x/virtualbox.rb +67 -0
- data/lib/virtualbox/com/interface/3.2.x/vrdp_auth_type.rb +11 -0
- data/lib/virtualbox/com/interface/3.2.x/vrdp_server.rb +21 -0
- data/lib/virtualbox/com/mscom_interface.rb +44 -0
- data/lib/virtualbox/com/nil_interface.rb +7 -0
- data/lib/virtualbox/com/util.rb +32 -0
- data/lib/virtualbox/cpu.rb +61 -0
- data/lib/virtualbox/dhcp_server.rb +89 -0
- data/lib/virtualbox/dvd.rb +27 -0
- data/lib/virtualbox/exceptions.rb +39 -0
- data/lib/virtualbox/ext/byte_normalizer.rb +17 -0
- data/lib/virtualbox/ext/glob_loader.rb +22 -0
- data/lib/virtualbox/ext/logger.rb +38 -0
- data/lib/virtualbox/ext/platform.rb +27 -0
- data/lib/virtualbox/ext/subclass_listing.rb +24 -0
- data/lib/virtualbox/extra_data.rb +127 -0
- data/lib/virtualbox/forwarded_port.rb +222 -0
- data/lib/virtualbox/global.rb +102 -0
- data/lib/virtualbox/guest_property.rb +116 -0
- data/lib/virtualbox/hard_drive.rb +246 -0
- data/lib/virtualbox/host.rb +71 -0
- data/lib/virtualbox/host_network_interface.rb +137 -0
- data/lib/virtualbox/hw_virtualization.rb +63 -0
- data/lib/virtualbox/lib.rb +84 -0
- data/lib/virtualbox/media.rb +20 -0
- data/lib/virtualbox/medium.rb +145 -0
- data/lib/virtualbox/medium_attachment.rb +61 -0
- data/lib/virtualbox/nat_engine.rb +71 -0
- data/lib/virtualbox/nat_forwarded_port.rb +171 -0
- data/lib/virtualbox/network_adapter.rb +166 -0
- data/lib/virtualbox/proxies/collection.rb +57 -0
- data/lib/virtualbox/shared_folder.rb +220 -0
- data/lib/virtualbox/snapshot.rb +185 -0
- data/lib/virtualbox/storage_controller.rb +160 -0
- data/lib/virtualbox/system_properties.rb +74 -0
- data/lib/virtualbox/usb_controller.rb +59 -0
- data/lib/virtualbox/usb_device_filter.rb +74 -0
- data/lib/virtualbox/version.rb +36 -0
- data/lib/virtualbox/virtual_system_description.rb +47 -0
- data/lib/virtualbox/vm.rb +684 -0
- data/lib/virtualbox/vrdp_server.rb +59 -0
- data/test/test_helper.rb +18 -0
- data/test/virtualbox/abstract_model/attributable_test.rb +269 -0
- data/test/virtualbox/abstract_model/dirty_test.rb +83 -0
- data/test/virtualbox/abstract_model/interface_attributes_test.rb +194 -0
- data/test/virtualbox/abstract_model/relatable_test.rb +348 -0
- data/test/virtualbox/abstract_model/validatable_test.rb +308 -0
- data/test/virtualbox/abstract_model/version_matcher_test.rb +41 -0
- data/test/virtualbox/abstract_model_test.rb +462 -0
- data/test/virtualbox/appliance_test.rb +159 -0
- data/test/virtualbox/audio_adapter_test.rb +83 -0
- data/test/virtualbox/bios_test.rb +83 -0
- data/test/virtualbox/com/abstract_enum_test.rb +49 -0
- data/test/virtualbox/com/abstract_implementer_test.rb +40 -0
- data/test/virtualbox/com/abstract_interface_test.rb +140 -0
- data/test/virtualbox/com/ffi/interface_test.rb +249 -0
- data/test/virtualbox/com/ffi/util_test.rb +108 -0
- data/test/virtualbox/com/ffi_interface_test.rb +42 -0
- data/test/virtualbox/com/implementer/base_test.rb +38 -0
- data/test/virtualbox/com/implementer/ffi_test.rb +527 -0
- data/test/virtualbox/com/implementer/mscom_test.rb +247 -0
- data/test/virtualbox/com/mscom_interface_test.rb +17 -0
- data/test/virtualbox/com/util_test.rb +17 -0
- data/test/virtualbox/cpu_test.rb +103 -0
- data/test/virtualbox/dhcp_server_test.rb +165 -0
- data/test/virtualbox/dvd_test.rb +28 -0
- data/test/virtualbox/ext/byte_normalizer_test.rb +34 -0
- data/test/virtualbox/ext/platform_test.rb +50 -0
- data/test/virtualbox/ext/subclass_listing_test.rb +25 -0
- data/test/virtualbox/extra_data_test.rb +155 -0
- data/test/virtualbox/forwarded_port_test.rb +286 -0
- data/test/virtualbox/global_test.rb +46 -0
- data/test/virtualbox/hard_drive_test.rb +141 -0
- data/test/virtualbox/host_network_interface_test.rb +254 -0
- data/test/virtualbox/host_test.rb +94 -0
- data/test/virtualbox/hw_virtualization_test.rb +103 -0
- data/test/virtualbox/lib_test.rb +93 -0
- data/test/virtualbox/medium_attachment_test.rb +147 -0
- data/test/virtualbox/medium_test.rb +192 -0
- data/test/virtualbox/nat_engine_test.rb +106 -0
- data/test/virtualbox/nat_forwarded_port_test.rb +222 -0
- data/test/virtualbox/network_adapter_test.rb +191 -0
- data/test/virtualbox/proxies/collection_test.rb +102 -0
- data/test/virtualbox/shared_folder_test.rb +219 -0
- data/test/virtualbox/snapshot_test.rb +231 -0
- data/test/virtualbox/storage_controller_test.rb +197 -0
- data/test/virtualbox/system_properties_test.rb +87 -0
- data/test/virtualbox/usb_controller_test.rb +112 -0
- data/test/virtualbox/usb_device_filter_test.rb +93 -0
- data/test/virtualbox/version_test.rb +59 -0
- data/test/virtualbox/virtual_system_description_test.rb +61 -0
- data/test/virtualbox/vm_test.rb +637 -0
- data/test/virtualbox/vrdp_server_test.rb +83 -0
- data/test/virtualbox_test.rb +11 -0
- data/virtualbox.gemspec +25 -0
- metadata +397 -0
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
require 'virtualbox/abstract_model/version_matcher'
|
|
2
|
+
|
|
3
|
+
module VirtualBox
|
|
4
|
+
class AbstractModel
|
|
5
|
+
# Module which can be included into any other class which allows
|
|
6
|
+
# that class to have attributes using the "attribute" class method.
|
|
7
|
+
# This creates the reader/writer for the attribute but also provides
|
|
8
|
+
# other useful options such as readonly attributes, default values,
|
|
9
|
+
# and more.
|
|
10
|
+
#
|
|
11
|
+
# Make sure to also see the {ClassMethods}.
|
|
12
|
+
#
|
|
13
|
+
# ## Defining a Basic Attribute
|
|
14
|
+
#
|
|
15
|
+
# attribute :name
|
|
16
|
+
#
|
|
17
|
+
# The example above would put the "name" attribute on the class. This
|
|
18
|
+
# would give the class the following abilities
|
|
19
|
+
#
|
|
20
|
+
# instance.name = "Harry!"
|
|
21
|
+
# puts instance.name # => "Harry!"
|
|
22
|
+
#
|
|
23
|
+
# Basic attributes alone are not different than ruby's built-in
|
|
24
|
+
# `attr_*` methods.
|
|
25
|
+
#
|
|
26
|
+
# ## Defining a Readonly Attribute
|
|
27
|
+
#
|
|
28
|
+
# attribute :age, :readonly => true
|
|
29
|
+
#
|
|
30
|
+
# The example above allows age to be read, but not written to via the
|
|
31
|
+
# `age=` method. The attribute is still able to written using
|
|
32
|
+
# {#write_attribute} but this is generally only for
|
|
33
|
+
# inter-class use, and not for users of it.
|
|
34
|
+
#
|
|
35
|
+
# ## Defining Default Values
|
|
36
|
+
#
|
|
37
|
+
# attribute :format, :default => "VDI"
|
|
38
|
+
#
|
|
39
|
+
# The example above applies a default value to format. So if no value
|
|
40
|
+
# is ever given to it, `format` would return `VDI`.
|
|
41
|
+
#
|
|
42
|
+
# ## Attributes for a Specific VirtualBox Version
|
|
43
|
+
#
|
|
44
|
+
# Attributes change with different VirtualBox versions. One way to
|
|
45
|
+
# provide version-specific behavior is to specify the version
|
|
46
|
+
# which the attribute applies to.
|
|
47
|
+
#
|
|
48
|
+
# attribute :name, :version => "3.2"
|
|
49
|
+
# attribute :age, :version => "3.1"
|
|
50
|
+
#
|
|
51
|
+
# These versions only apply to major and minor releases of
|
|
52
|
+
# VirtualBox. Patch releases can't be specified (such as "3.2.4")
|
|
53
|
+
#
|
|
54
|
+
# ## Populating Multiple Attributes
|
|
55
|
+
#
|
|
56
|
+
# Attributes can be mass populated using {#populate_attributes}. Below
|
|
57
|
+
# is an example of the use.
|
|
58
|
+
#
|
|
59
|
+
# class Person
|
|
60
|
+
# include Attributable
|
|
61
|
+
#
|
|
62
|
+
# attribute :name
|
|
63
|
+
# attribute :age, :readonly => true
|
|
64
|
+
#
|
|
65
|
+
# def initialize
|
|
66
|
+
# populate_attributes({
|
|
67
|
+
# :name => "Steven",
|
|
68
|
+
# :age => 27
|
|
69
|
+
# })
|
|
70
|
+
# end
|
|
71
|
+
# end
|
|
72
|
+
#
|
|
73
|
+
# **Note:** Populating attributes is not the same as mass-updating attributes.
|
|
74
|
+
# {#populate_attributes} is meant to do initial population only. There is
|
|
75
|
+
# currently no method for mass assignment for updating.
|
|
76
|
+
#
|
|
77
|
+
# ## Custom Populate Keys
|
|
78
|
+
#
|
|
79
|
+
# Sometimes the attribute names don't match the keys of the hash that will be
|
|
80
|
+
# used to populate it. For this purpose, you can define a custom
|
|
81
|
+
# `populate_key`. Example:
|
|
82
|
+
#
|
|
83
|
+
# attribute :path, :populate_key => :location
|
|
84
|
+
#
|
|
85
|
+
# def initialize
|
|
86
|
+
# populate_attributes(:location => "Home")
|
|
87
|
+
# puts path # => "Home"
|
|
88
|
+
# end
|
|
89
|
+
#
|
|
90
|
+
# ## Lazy Loading Attributes
|
|
91
|
+
#
|
|
92
|
+
# While most attributes are fairly trivial to calculate and populate, sometimes
|
|
93
|
+
# attributes may have an expensive cost to populate, and are generally not worth
|
|
94
|
+
# populating unless a user of the class requests that attribute. This is known as
|
|
95
|
+
# _lazy loading_ the attributes. This is possibly by specifying the `:lazy` option
|
|
96
|
+
# on the attribute. In this case, the first time (and _only_ the first time) the
|
|
97
|
+
# attribute is requested, `load_attribute` will be called with the name of the
|
|
98
|
+
# attribute as the parameter. This method is then expected to call `write_attribute`
|
|
99
|
+
# on that attribute to give it a value.
|
|
100
|
+
#
|
|
101
|
+
# class ExpensiveAttributeModel
|
|
102
|
+
# include VirtualBox::AbstractModel::Attributable
|
|
103
|
+
# attribute :expensive_attribute, :lazy => true
|
|
104
|
+
#
|
|
105
|
+
# def load_attribute(name)
|
|
106
|
+
# if name == :expensive_attribute
|
|
107
|
+
# write_attribute(name, perform_expensive_calculation)
|
|
108
|
+
# end
|
|
109
|
+
# end
|
|
110
|
+
# end
|
|
111
|
+
#
|
|
112
|
+
# Using the above definition, we could use the class like so:
|
|
113
|
+
#
|
|
114
|
+
# # Initializing is fast, since no attribute population is done
|
|
115
|
+
# model = ExpensiveAttributeModel.new
|
|
116
|
+
#
|
|
117
|
+
# # But this is slow, since it has to calculate.
|
|
118
|
+
# puts model.expensive_attribute
|
|
119
|
+
#
|
|
120
|
+
# # But ONLY THE FIRST TIME. This time is FAST!
|
|
121
|
+
# puts model.expensive_attribute
|
|
122
|
+
#
|
|
123
|
+
# In addition to calling `load_attribute` on initial read, `write_attribute`
|
|
124
|
+
# when performed on a lazy loaded attribute will mark it as "loaded" so there
|
|
125
|
+
# will be no load called on the first request. Example, using the above class
|
|
126
|
+
# once again:
|
|
127
|
+
#
|
|
128
|
+
# model = ExpensiveAttributeModel.new
|
|
129
|
+
# model.write_attribute(:expensive_attribute, 42)
|
|
130
|
+
#
|
|
131
|
+
# # This is FAST, since "load_attribute" is not called
|
|
132
|
+
# puts model.expensive_attribute # => 42
|
|
133
|
+
#
|
|
134
|
+
module Attributable
|
|
135
|
+
include VersionMatcher
|
|
136
|
+
|
|
137
|
+
def self.included(base)
|
|
138
|
+
base.extend ClassMethods
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
# Defines the class methods for the {Attributable} module. For
|
|
142
|
+
# detailed overview documentation, see {Attributable}.
|
|
143
|
+
module ClassMethods
|
|
144
|
+
# Defines an attribute on the model.
|
|
145
|
+
#
|
|
146
|
+
# @param [Symbol] name The name of the attribute, which will also be
|
|
147
|
+
# used to set the accessor methods.
|
|
148
|
+
# @option options [Boolean] :readonly (false) If true, attribute will be readonly.
|
|
149
|
+
# More specifically, the `attribute=` method won't be defined for it.
|
|
150
|
+
# @option options [Object] :default (nil) Specifies a default value for the
|
|
151
|
+
# attribute.
|
|
152
|
+
# @option options [Symbol] :populate_key (attribute name) Specifies
|
|
153
|
+
# a custom populate key to use for {Attributable#populate_attributes}
|
|
154
|
+
def attribute(name, options = {})
|
|
155
|
+
name = name.to_sym
|
|
156
|
+
attributes[name] = defined?(@__attribute_scope) ? @__attribute_scope : {}
|
|
157
|
+
attributes[name].merge!(options)
|
|
158
|
+
|
|
159
|
+
# Create the method for reading this attribute
|
|
160
|
+
define_method("#{name}?") { read_attribute(name) } if options[:boolean]
|
|
161
|
+
define_method(name) { read_attribute(name) }
|
|
162
|
+
|
|
163
|
+
# Create the writer method for it unless the attribute is readonly,
|
|
164
|
+
# then remove the method if it exists
|
|
165
|
+
if !options[:readonly]
|
|
166
|
+
define_method("#{name}=") do |value|
|
|
167
|
+
write_attribute(name, value)
|
|
168
|
+
end
|
|
169
|
+
elsif method_defined?("#{name}=")
|
|
170
|
+
undef_method("#{name}=")
|
|
171
|
+
end
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
# Defines the specified scope for all attributes within the block.
|
|
175
|
+
# The scope is reset to the previous value once the block ends. Multiple
|
|
176
|
+
# scopes can be nested and they'll inherit from each other.
|
|
177
|
+
def attribute_scope(options, &block)
|
|
178
|
+
@__attribute_scope ||= {}
|
|
179
|
+
old_value = @__attribute_scope
|
|
180
|
+
@__attribute_scope = old_value.merge(options)
|
|
181
|
+
|
|
182
|
+
instance_eval(&block)
|
|
183
|
+
|
|
184
|
+
@__attribute_scope = old_value
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
# Returns the hash of attributes and their associated options.
|
|
188
|
+
def attributes
|
|
189
|
+
@attributes ||= {}
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
# Used to propagate attributes to subclasses. This method makes sure that
|
|
193
|
+
# subclasses of a class with {Attributable} included will inherit the
|
|
194
|
+
# attributes as well, which would be the expected behaviour.
|
|
195
|
+
def inherited(subclass)
|
|
196
|
+
super rescue NoMethodError
|
|
197
|
+
|
|
198
|
+
attributes.each do |name, option|
|
|
199
|
+
subclass.attribute(name, option)
|
|
200
|
+
end
|
|
201
|
+
end
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
# Does the initial population of the various attributes. It will
|
|
205
|
+
# ignore attributes which are not defined or have no value in the
|
|
206
|
+
# hash.
|
|
207
|
+
#
|
|
208
|
+
# Population uses the attributes `populate_key` if present to
|
|
209
|
+
# determine which value to take. Example:
|
|
210
|
+
#
|
|
211
|
+
# attribute :name, :populate_key => :namae
|
|
212
|
+
# attribute :age
|
|
213
|
+
#
|
|
214
|
+
# def initialize
|
|
215
|
+
# populate_attributes(:namae => "Henry", :age => 27)
|
|
216
|
+
# end
|
|
217
|
+
#
|
|
218
|
+
# The above example would set `name` to `Henry` since that is
|
|
219
|
+
# the `populate_key`. If a `populate_key` is not present, the
|
|
220
|
+
# attribute name is used.
|
|
221
|
+
def populate_attributes(attribs)
|
|
222
|
+
self.class.attributes.each do |key, options|
|
|
223
|
+
value_key = options[:populate_key] || key
|
|
224
|
+
write_attribute(key, attribs[value_key]) if attribs.has_key?(value_key)
|
|
225
|
+
end
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
# Writes an attribute. This method ignores the `readonly` option
|
|
229
|
+
# on attribute definitions. This method is mostly meant for
|
|
230
|
+
# internal use on setting attributes (including readonly
|
|
231
|
+
# attributes), whereas users of a class which includes this
|
|
232
|
+
# module should use the accessor methods, such as `name=`.
|
|
233
|
+
def write_attribute(name, value)
|
|
234
|
+
attributes[name] = value
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
# Reads an attribute. This method will return `nil` if the
|
|
238
|
+
# attribute doesn't exist. If the attribute does exist but
|
|
239
|
+
# doesn't have a value set, it'll use the `default` value
|
|
240
|
+
# if specified.
|
|
241
|
+
def read_attribute(name)
|
|
242
|
+
if has_attribute?(name)
|
|
243
|
+
options = self.class.attributes[name]
|
|
244
|
+
|
|
245
|
+
assert_version_match(options[:version], VirtualBox.version) if options[:version]
|
|
246
|
+
if lazy_attribute?(name) && !loaded_attribute?(name)
|
|
247
|
+
# Load the lazy attribute
|
|
248
|
+
load_attribute(name.to_sym)
|
|
249
|
+
end
|
|
250
|
+
|
|
251
|
+
if attributes[name].nil?
|
|
252
|
+
options[:default]
|
|
253
|
+
else
|
|
254
|
+
attributes[name]
|
|
255
|
+
end
|
|
256
|
+
end
|
|
257
|
+
end
|
|
258
|
+
|
|
259
|
+
# Returns a hash of all attributes and their options.
|
|
260
|
+
def attributes
|
|
261
|
+
@attribute_values ||= {}
|
|
262
|
+
end
|
|
263
|
+
|
|
264
|
+
# Returns boolean value denoting if an attribute exists.
|
|
265
|
+
def has_attribute?(name)
|
|
266
|
+
self.class.attributes.has_key?(name.to_sym)
|
|
267
|
+
end
|
|
268
|
+
|
|
269
|
+
# Returns boolean value denoting if an attribute is "lazy loaded"
|
|
270
|
+
def lazy_attribute?(name)
|
|
271
|
+
has_attribute?(name) && self.class.attributes[name.to_sym][:lazy]
|
|
272
|
+
end
|
|
273
|
+
|
|
274
|
+
# Returns boolean value denoting if an attribute has been loaded
|
|
275
|
+
# yet.
|
|
276
|
+
def loaded_attribute?(name)
|
|
277
|
+
attributes.has_key?(name)
|
|
278
|
+
end
|
|
279
|
+
|
|
280
|
+
# Returns a boolean value denoting if an attribute is readonly.
|
|
281
|
+
# This method also returns false for **nonexistent attributes**
|
|
282
|
+
# so it should be used in conjunction with {#has_attribute?} if
|
|
283
|
+
# existence is important.
|
|
284
|
+
def readonly_attribute?(name)
|
|
285
|
+
name = name.to_sym
|
|
286
|
+
has_attribute?(name) && self.class.attributes[name][:readonly]
|
|
287
|
+
end
|
|
288
|
+
end
|
|
289
|
+
end
|
|
290
|
+
end
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
module VirtualBox
|
|
2
|
+
class AbstractModel
|
|
3
|
+
# Tracks "dirtiness" of values for a class. Its not tied to AbstractModel
|
|
4
|
+
# in any way other than the namespace.
|
|
5
|
+
#
|
|
6
|
+
# # Checking if a Value was Changed
|
|
7
|
+
#
|
|
8
|
+
# Dynamic methods allow functionality for checking if values changed:
|
|
9
|
+
#
|
|
10
|
+
# obj.foo_changed?
|
|
11
|
+
#
|
|
12
|
+
# # Previous Value
|
|
13
|
+
#
|
|
14
|
+
# Can also view the previous value of an attribute:
|
|
15
|
+
#
|
|
16
|
+
# obj.foo # => "foo" initially
|
|
17
|
+
# obj.foo = "bar"
|
|
18
|
+
# obj.foo_was # => "foo"
|
|
19
|
+
#
|
|
20
|
+
# # Previous and Current Value
|
|
21
|
+
#
|
|
22
|
+
# Using the `_change` dynamic method, can view the changes of a field.
|
|
23
|
+
#
|
|
24
|
+
# obj.foo # => "foo" initially
|
|
25
|
+
# obj.foo = "bar"
|
|
26
|
+
# obj.foo_change # => ["foo", "bar"]
|
|
27
|
+
#
|
|
28
|
+
# # All Changes
|
|
29
|
+
#
|
|
30
|
+
# Can also view all changes for a class with the `changes` method.
|
|
31
|
+
#
|
|
32
|
+
# obj.foo # => "foo" initially
|
|
33
|
+
# obj.bar # => "bar" initially
|
|
34
|
+
# obj.foo = "far"
|
|
35
|
+
# obj.bar = "baz"
|
|
36
|
+
# obj.changes # => { :foo => ["foo", "far"], :bar => ["bar", "baz"]}
|
|
37
|
+
#
|
|
38
|
+
# # Setting Dirty
|
|
39
|
+
#
|
|
40
|
+
# Dirtiness tracking only occurs for values which the implementor
|
|
41
|
+
# explicitly sets as dirty. This is done with the {#set_dirty!}
|
|
42
|
+
# method. Example implementation below:
|
|
43
|
+
#
|
|
44
|
+
# class Person
|
|
45
|
+
# include VirtualBox::AbstractModel::Dirty
|
|
46
|
+
#
|
|
47
|
+
# attr_reader :name
|
|
48
|
+
#
|
|
49
|
+
# def name=(value)
|
|
50
|
+
# set_dirty!(:name, @name, value)
|
|
51
|
+
# @name = value
|
|
52
|
+
# end
|
|
53
|
+
# end
|
|
54
|
+
#
|
|
55
|
+
# The above example has all the changes necessary to track changes
|
|
56
|
+
# on an attribute.
|
|
57
|
+
#
|
|
58
|
+
# # Ignoring Dirtiness Tracking
|
|
59
|
+
#
|
|
60
|
+
# Sometimes, for features such as mass assignment, dirtiness tracking
|
|
61
|
+
# should be disabled. This can be done with the `ignore_dirty` method.
|
|
62
|
+
#
|
|
63
|
+
# ignore_dirty do |obj|
|
|
64
|
+
# obj.name = "Foo"
|
|
65
|
+
# end
|
|
66
|
+
#
|
|
67
|
+
# obj.changed? # => false
|
|
68
|
+
#
|
|
69
|
+
# # Clearing Dirty State
|
|
70
|
+
#
|
|
71
|
+
# Sometimes, such as after saving a model, dirty states should be cleared.
|
|
72
|
+
# This can be done with the `clear_dirty!` method.
|
|
73
|
+
#
|
|
74
|
+
# obj.clear_dirty!(:name)
|
|
75
|
+
# obj.name_changed? # => false
|
|
76
|
+
#
|
|
77
|
+
# If no specific field is speciied, `clear_dirty!` will clear the dirty
|
|
78
|
+
# status on the entire model.
|
|
79
|
+
#
|
|
80
|
+
# obj.changed? # => assume true
|
|
81
|
+
# obj.clear_dirty!
|
|
82
|
+
# obj.changed? # => false
|
|
83
|
+
#
|
|
84
|
+
module Dirty
|
|
85
|
+
# Manages dirty state for an attribute. This method will handle
|
|
86
|
+
# setting the dirty state of an attribute (or even clearing it
|
|
87
|
+
# if the old value is reset). Any implementors of this mixin should
|
|
88
|
+
# call this for any fields they want tracked.
|
|
89
|
+
#
|
|
90
|
+
# @param [Symbol] name Name of field
|
|
91
|
+
# @param [Object] current Current value (not necessarilly the
|
|
92
|
+
# original value, but the **current** value)
|
|
93
|
+
# @param [Object] value The new value being set
|
|
94
|
+
def set_dirty!(name, current, value)
|
|
95
|
+
if current != value
|
|
96
|
+
name = name.to_sym
|
|
97
|
+
|
|
98
|
+
# If its the first time this attribute has changed, store the
|
|
99
|
+
# original value in the first field
|
|
100
|
+
changes[name] ||= [current, nil]
|
|
101
|
+
|
|
102
|
+
# Then store the changed value
|
|
103
|
+
changes[name][1] = value
|
|
104
|
+
|
|
105
|
+
# If the value changed back to the original value, remove from the
|
|
106
|
+
# dirty hash
|
|
107
|
+
if changes[name][0] == changes[name][1]
|
|
108
|
+
changes.delete(name)
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
# Clears dirty state for a field.
|
|
114
|
+
#
|
|
115
|
+
# @param [Symbol] key The field to clear dirty state.
|
|
116
|
+
def clear_dirty!(key=nil)
|
|
117
|
+
if key.nil?
|
|
118
|
+
@changed_attributes = {}
|
|
119
|
+
else
|
|
120
|
+
changes.delete(key)
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
# Ignores any dirty changes during the duration of the block.
|
|
125
|
+
# Guarantees the dirty state will be the same before and after
|
|
126
|
+
# the method call, but not within the block itself.
|
|
127
|
+
def ignore_dirty(&block)
|
|
128
|
+
current_changes = changes.dup
|
|
129
|
+
yield self
|
|
130
|
+
@changed_attributes = current_changes
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
# Returns boolean denoting if field changed or not. If no attribute
|
|
134
|
+
# is specified, returns true of false showing whether the model
|
|
135
|
+
# changed at all.
|
|
136
|
+
#
|
|
137
|
+
# @param [Symbol] attribute The attribute to check, or if nil,
|
|
138
|
+
# all fields checked.
|
|
139
|
+
def changed?(attribute = nil)
|
|
140
|
+
if attribute.nil?
|
|
141
|
+
!changes.empty?
|
|
142
|
+
else
|
|
143
|
+
changes.has_key?(attribute)
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
# Returns hash of changes. Keys are fields, values are an
|
|
148
|
+
# array of the original value and the current value.
|
|
149
|
+
#
|
|
150
|
+
# @return [Hash]
|
|
151
|
+
def changes
|
|
152
|
+
@changed_attributes ||= {}
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
# Method missing is used to implement the "magic" methods of
|
|
156
|
+
# `field_changed`, `field_change`, and `field_was`.
|
|
157
|
+
def method_missing(meth, *args)
|
|
158
|
+
meth_string = meth.to_s
|
|
159
|
+
|
|
160
|
+
if meth_string =~ /^(.+?)_changed\?$/
|
|
161
|
+
changed?($1.to_sym)
|
|
162
|
+
elsif meth_string =~ /^(.+?)_change$/
|
|
163
|
+
changes[$1.to_sym]
|
|
164
|
+
elsif meth_string =~ /^(.+?)_was$/
|
|
165
|
+
change = changes[$1.to_sym]
|
|
166
|
+
if change.nil?
|
|
167
|
+
nil
|
|
168
|
+
else
|
|
169
|
+
change[0]
|
|
170
|
+
end
|
|
171
|
+
else
|
|
172
|
+
super
|
|
173
|
+
end
|
|
174
|
+
end
|
|
175
|
+
end
|
|
176
|
+
end
|
|
177
|
+
end
|