bbrowning-virtualbox 0.7.6.dev
Sign up to get free protection for your applications and to get access to all the features.
- 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
|