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,98 @@
|
|
|
1
|
+
module VirtualBox
|
|
2
|
+
class AbstractModel
|
|
3
|
+
# Module which can be included which defines helper methods to DRY out the
|
|
4
|
+
# code which handles attributes with {VirtualBox::COM} interfaces. This
|
|
5
|
+
# module works _alongside_ the {Attributable} module, so **both are required**.
|
|
6
|
+
module InterfaceAttributes
|
|
7
|
+
# Loads the attributes which have an interface getter and writes
|
|
8
|
+
# their values.
|
|
9
|
+
#
|
|
10
|
+
# @param [VirtualBox::COM::Interface] interface
|
|
11
|
+
def load_interface_attributes(interface)
|
|
12
|
+
self.class.attributes.each do |key, options|
|
|
13
|
+
load_interface_attribute(key, interface)
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# Loads a single interface attribute.
|
|
18
|
+
#
|
|
19
|
+
# @param [Symbol] key The attribute to load
|
|
20
|
+
# @param [VirtualBox::COM::Interface] interface The interface
|
|
21
|
+
def load_interface_attribute(key, interface)
|
|
22
|
+
# Return unless we have a valid interface attribute with a getter
|
|
23
|
+
return unless has_attribute?(key)
|
|
24
|
+
options = self.class.attributes[key.to_sym]
|
|
25
|
+
return if options.has_key?(:property) && !options[:property]
|
|
26
|
+
return if options.has_key?(:version) && !version_match?(options[:version], VirtualBox.version)
|
|
27
|
+
getter = options[:property] || options[:property_getter] || key.to_sym
|
|
28
|
+
return unless getter
|
|
29
|
+
|
|
30
|
+
# Convert the getter to a proc and call it
|
|
31
|
+
getter = spec_to_proc(getter)
|
|
32
|
+
write_attribute(key, getter.call(self, interface, key))
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Saves all the attributes which have an interface setter.
|
|
36
|
+
def save_interface_attributes(interface)
|
|
37
|
+
self.class.attributes.each do |key, options|
|
|
38
|
+
save_interface_attribute(key, interface)
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Saves a single interface attribute
|
|
43
|
+
#
|
|
44
|
+
# @param [Symbol] key The attribute to write
|
|
45
|
+
# @param [VirtualBox::COM::Interface] interface The interface
|
|
46
|
+
# @param [Object] value The value to write
|
|
47
|
+
def save_interface_attribute(key, interface)
|
|
48
|
+
# Return unless we have a valid interface attribute with a setter
|
|
49
|
+
return unless has_attribute?(key)
|
|
50
|
+
options = self.class.attributes[key.to_sym]
|
|
51
|
+
return if options[:readonly]
|
|
52
|
+
return if options.has_key?(:property) && !options[:property]
|
|
53
|
+
return if options.has_key?(:version) && !version_match?(options[:version], VirtualBox.version)
|
|
54
|
+
|
|
55
|
+
setter = options[:property] || options[:property_setter] || "#{key}=".to_sym
|
|
56
|
+
return unless setter
|
|
57
|
+
|
|
58
|
+
# Convert the setter to a proc and call it
|
|
59
|
+
setter = spec_to_proc(setter)
|
|
60
|
+
setter.call(self, interface, key, read_attribute(key))
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# Converts a getter/setter specification to a Proc which can be called
|
|
64
|
+
# to obtain or set a value. There are multiple ways to specify the getter
|
|
65
|
+
# and/or setter of an interface attribute:
|
|
66
|
+
#
|
|
67
|
+
# ## Symbol
|
|
68
|
+
#
|
|
69
|
+
# A symbol represents a method to call on the interface. An example of the
|
|
70
|
+
# declaration and resulting method call are shown below:
|
|
71
|
+
#
|
|
72
|
+
# attribute :foo, :property_getter => :get_foo
|
|
73
|
+
#
|
|
74
|
+
# Converts to:
|
|
75
|
+
#
|
|
76
|
+
# interface.get_foo
|
|
77
|
+
#
|
|
78
|
+
# ## Proc
|
|
79
|
+
#
|
|
80
|
+
# A proc is called with the interface and it is expected to return the value
|
|
81
|
+
# for a getter. For a setter, the interface and the value is sent in as
|
|
82
|
+
# parameters to the Proc.
|
|
83
|
+
#
|
|
84
|
+
# attribute :foo, :property_getter => Proc.new { |i| i.get_foo }
|
|
85
|
+
#
|
|
86
|
+
def spec_to_proc(spec)
|
|
87
|
+
# Return the spec as-is if its a proc
|
|
88
|
+
return spec if spec.is_a?(Proc)
|
|
89
|
+
|
|
90
|
+
if spec.is_a?(Symbol)
|
|
91
|
+
# For symbols, wrap up a method send in a Proc and return
|
|
92
|
+
# that
|
|
93
|
+
return Proc.new { |this, m, key, *args| m.send(spec, *args) }
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
end
|
|
@@ -0,0 +1,332 @@
|
|
|
1
|
+
require 'virtualbox/abstract_model/version_matcher'
|
|
2
|
+
|
|
3
|
+
module VirtualBox
|
|
4
|
+
class AbstractModel
|
|
5
|
+
# Provides simple relationship features to any class. These relationships
|
|
6
|
+
# can be anything, since this module makes no assumptions and doesn't
|
|
7
|
+
# differentiate between "has many" or "belongs to" or any of that.
|
|
8
|
+
#
|
|
9
|
+
# The way it works is simple:
|
|
10
|
+
#
|
|
11
|
+
# 1. Relationships are defined with a relationship name and a
|
|
12
|
+
# class of the relationship objects.
|
|
13
|
+
# 2. When {#populate_relationships} is called, `populate_relationship` is
|
|
14
|
+
# called on each relationship class (example: {StorageController.populate_relationship}).
|
|
15
|
+
# This is expected to return the relationship, which can be any object.
|
|
16
|
+
# 3. When {#save_relationships} is called, `save_relationship` is
|
|
17
|
+
# called on each relationship class, which manages saving its own
|
|
18
|
+
# relationship.
|
|
19
|
+
# 4. When {#destroy_relationships} is called, `destroy_relationship` is
|
|
20
|
+
# called on each relationship class, which manages destroying
|
|
21
|
+
# its own relationship.
|
|
22
|
+
#
|
|
23
|
+
# Be sure to read {ClassMethods} for complete documentation of methods.
|
|
24
|
+
#
|
|
25
|
+
# # Defining Relationships
|
|
26
|
+
#
|
|
27
|
+
# Every relationship has two mandatory parameters: the name and the class.
|
|
28
|
+
#
|
|
29
|
+
# relationship :bacons, Bacon
|
|
30
|
+
#
|
|
31
|
+
# In this case, there is a relationship `bacons` which refers to the `Bacon`
|
|
32
|
+
# class.
|
|
33
|
+
#
|
|
34
|
+
# # Accessing Relationships
|
|
35
|
+
#
|
|
36
|
+
# Relatable offers up dynamically generated accessors for every relationship
|
|
37
|
+
# which simply returns the relationship data.
|
|
38
|
+
#
|
|
39
|
+
# relationship :bacons, Bacon
|
|
40
|
+
#
|
|
41
|
+
# # Accessing through an instance "instance"
|
|
42
|
+
# instance.bacons # => whatever Bacon.populate_relationship created
|
|
43
|
+
#
|
|
44
|
+
# # Settable Relationships
|
|
45
|
+
#
|
|
46
|
+
# It is often convenient that relationships become "settable." That is,
|
|
47
|
+
# for a relationship `foos`, there would exist a `foos=` method. This is
|
|
48
|
+
# possible by implementing the `set_relationship` method on the relationship
|
|
49
|
+
# class. Consider the following relationship:
|
|
50
|
+
#
|
|
51
|
+
# relationship :foos, Foo
|
|
52
|
+
#
|
|
53
|
+
# If `Foo` has the `set_relationship` method, then it will be called by
|
|
54
|
+
# `foos=`. It is expected to return the new value for the relationship. To
|
|
55
|
+
# facilitate this need, the `set_relationship` method is given three
|
|
56
|
+
# parameters: caller, old value, and new value. An example implementation,
|
|
57
|
+
# albeit a silly one, is below:
|
|
58
|
+
#
|
|
59
|
+
# class Foo
|
|
60
|
+
# def self.set_relationship(caller, old_value, new_value)
|
|
61
|
+
# return "Changed to: #{new_value}"
|
|
62
|
+
# end
|
|
63
|
+
# end
|
|
64
|
+
#
|
|
65
|
+
# In this case, the following behavior would occur:
|
|
66
|
+
#
|
|
67
|
+
# instance.foos # => assume "foo"
|
|
68
|
+
# instance.foos = "bar"
|
|
69
|
+
# instance.foos # => "Changed to: bar"
|
|
70
|
+
#
|
|
71
|
+
# If the relationship class _does not implement_ the `set_relationship`
|
|
72
|
+
# method, then a {Exceptions::NonSettableRelationshipException} will be raised if
|
|
73
|
+
# a user attempts to set that relationship.
|
|
74
|
+
#
|
|
75
|
+
# # Dependent Relationships
|
|
76
|
+
#
|
|
77
|
+
# By setting `:dependent => :destroy` on relationships, {AbstractModel}
|
|
78
|
+
# will automatically call {#destroy_relationships} when {AbstractModel#destroy}
|
|
79
|
+
# is called.
|
|
80
|
+
#
|
|
81
|
+
# This is not a feature built-in to Relatable but figured it should be
|
|
82
|
+
# mentioned here.
|
|
83
|
+
#
|
|
84
|
+
# # Lazy Relationships
|
|
85
|
+
#
|
|
86
|
+
# Often, relationships are pretty heavy things to load. Data may have to be
|
|
87
|
+
# retrieved, classes instantiated, etc. If a class has many relationships, or
|
|
88
|
+
# many relationships within many relationships, the time and memory required
|
|
89
|
+
# for relationships really begins to add up. To address this issue, _lazy relationships_
|
|
90
|
+
# are available. Lazy relationships defer loading their content until the
|
|
91
|
+
# last possible moment, or rather, when a user requests the data. By specifing
|
|
92
|
+
# the `:lazy => true` option to relationships, relationships will not be loaded
|
|
93
|
+
# immediately. Instead, when they're first requested, `load_relationship` will
|
|
94
|
+
# be called on the model, with the name of the relationship given as a
|
|
95
|
+
# parameter. It is up to this method to call {#populate_relationship} at some
|
|
96
|
+
# point with the data to setup the relationship. An example follows:
|
|
97
|
+
#
|
|
98
|
+
# class SomeModel
|
|
99
|
+
# include VirtualBox::AbstractModel::Relatable
|
|
100
|
+
#
|
|
101
|
+
# relationship :foos, Foo, :lazy => true
|
|
102
|
+
#
|
|
103
|
+
# def load_relationship(name)
|
|
104
|
+
# if name == :foos
|
|
105
|
+
# populate_relationship(name, get_data_for_a_long_time)
|
|
106
|
+
# end
|
|
107
|
+
# end
|
|
108
|
+
# end
|
|
109
|
+
#
|
|
110
|
+
# Using the above class, we can use it like so:
|
|
111
|
+
#
|
|
112
|
+
# model = SomeModel.new
|
|
113
|
+
#
|
|
114
|
+
# # This initial load takes awhile as it loads...
|
|
115
|
+
# model.foos
|
|
116
|
+
#
|
|
117
|
+
# # Instant! (Just a hash lookup. No load necessary)
|
|
118
|
+
# model.foos
|
|
119
|
+
#
|
|
120
|
+
# One catch: If a model attempts to {#destroy_relationship destroy} a lazy
|
|
121
|
+
# relationship, it will first load the relationship, since destroy typically
|
|
122
|
+
# depends on some data of the relationship.
|
|
123
|
+
module Relatable
|
|
124
|
+
include VersionMatcher
|
|
125
|
+
|
|
126
|
+
def self.included(base)
|
|
127
|
+
base.extend ClassMethods
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
module ClassMethods
|
|
131
|
+
# Define a relationship. The name and class must be specified. This
|
|
132
|
+
# class will be used to call the `populate_relationship,
|
|
133
|
+
# `save_relationship`, etc. methods.
|
|
134
|
+
#
|
|
135
|
+
# @param [Symbol] name Relationship name. This will also be used for
|
|
136
|
+
# the dynamically generated accessor.
|
|
137
|
+
# @param [Class] klass Class of the relationship.
|
|
138
|
+
# @option options [Symbol] :dependent (nil) - If set to `:destroy`
|
|
139
|
+
# {AbstractModel#destroy} will propagate through to relationships.
|
|
140
|
+
def relationship(name, klass, options = {})
|
|
141
|
+
name = name.to_sym
|
|
142
|
+
|
|
143
|
+
relationships << [name, { :klass => klass }.merge(options)]
|
|
144
|
+
|
|
145
|
+
# Define the method to read the relationship
|
|
146
|
+
define_method(name) { read_relationship(name) }
|
|
147
|
+
|
|
148
|
+
# Define the method to set the relationship
|
|
149
|
+
define_method("#{name}=") { |*args| set_relationship(name, *args) }
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
# Returns a hash of all the relationships.
|
|
153
|
+
#
|
|
154
|
+
# @return [Hash]
|
|
155
|
+
def relationships_hash
|
|
156
|
+
Hash[*relationships.flatten]
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
# Returns an array of the relationships in order of being added.
|
|
160
|
+
#
|
|
161
|
+
# @return [Array]
|
|
162
|
+
def relationships
|
|
163
|
+
@relationships ||= []
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
# Returns a boolean of whether a relationship exists.
|
|
167
|
+
#
|
|
168
|
+
# @return [Boolean]
|
|
169
|
+
def has_relationship?(name)
|
|
170
|
+
!!relationships.detect { |r| r[0] == name }
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
# Used to propagate relationships to subclasses. This method makes sure that
|
|
174
|
+
# subclasses of a class with {Relatable} included will inherit the
|
|
175
|
+
# relationships as well, which would be the expected behaviour.
|
|
176
|
+
def inherited(subclass)
|
|
177
|
+
super rescue NoMethodError
|
|
178
|
+
|
|
179
|
+
relationships.each do |name, options|
|
|
180
|
+
subclass.relationship(name, nil, options)
|
|
181
|
+
end
|
|
182
|
+
end
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
# Reads a relationship. This is equivalent to {Attributable#read_attribute},
|
|
186
|
+
# but for relationships.
|
|
187
|
+
def read_relationship(name)
|
|
188
|
+
options = self.class.relationships_hash[name.to_sym]
|
|
189
|
+
assert_version_match(options[:version], VirtualBox.version) if options[:version]
|
|
190
|
+
|
|
191
|
+
if lazy_relationship?(name) && !loaded_relationship?(name)
|
|
192
|
+
load_relationship(name)
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
relationship_data[name.to_sym]
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
# Saves the model, calls save_relationship on all relations. It is up to
|
|
199
|
+
# the relation to determine whether anything changed, etc. Simply
|
|
200
|
+
# calls `save_relationship` on each relationship class passing in the
|
|
201
|
+
# following parameters:
|
|
202
|
+
#
|
|
203
|
+
# * **caller** - The class which is calling save
|
|
204
|
+
# * **data** - The data associated with the relationship
|
|
205
|
+
#
|
|
206
|
+
# In addition to those two args, any arbitrary args may be tacked on to the
|
|
207
|
+
# end and they'll be pushed through to the `save_relationship` method.
|
|
208
|
+
def save_relationships(*args)
|
|
209
|
+
# Can't use `all?` here since it short circuits
|
|
210
|
+
results = self.class.relationships.collect do |data|
|
|
211
|
+
name, options = data
|
|
212
|
+
!!save_relationship(name, *args)
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
!results.include?(false)
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
# Saves a single relationship. It is up to the relationship class to
|
|
219
|
+
# determine whether anything changed and how saving is implemented. Simply
|
|
220
|
+
# calls `save_relationship` on the relationship class.
|
|
221
|
+
def save_relationship(name, *args)
|
|
222
|
+
options = self.class.relationships_hash[name]
|
|
223
|
+
return if lazy_relationship?(name) && !loaded_relationship?(name)
|
|
224
|
+
return if options[:version] && !version_match?(options[:version], VirtualBox.version)
|
|
225
|
+
return unless relationship_class(name).respond_to?(:save_relationship)
|
|
226
|
+
relationship_class(name).save_relationship(self, relationship_data[name], *args)
|
|
227
|
+
end
|
|
228
|
+
|
|
229
|
+
# The equivalent to {Attributable#populate_attributes}, but with
|
|
230
|
+
# relationships.
|
|
231
|
+
def populate_relationships(data)
|
|
232
|
+
self.class.relationships.each do |name, options|
|
|
233
|
+
populate_relationship(name, data) unless lazy_relationship?(name)
|
|
234
|
+
end
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
# Populate a single relationship.
|
|
238
|
+
def populate_relationship(name, data)
|
|
239
|
+
options = self.class.relationships_hash[name]
|
|
240
|
+
return unless relationship_class(name).respond_to?(:populate_relationship)
|
|
241
|
+
return if options[:version] && !version_match?(options[:version], VirtualBox.version)
|
|
242
|
+
relationship_data[name] = relationship_class(name).populate_relationship(self, data)
|
|
243
|
+
end
|
|
244
|
+
|
|
245
|
+
# Calls `destroy_relationship` on each of the relationships. Any
|
|
246
|
+
# arbitrary args may be added and they will be forarded to the
|
|
247
|
+
# relationship's `destroy_relationship` method.
|
|
248
|
+
def destroy_relationships(*args)
|
|
249
|
+
self.class.relationships.each do |name, options|
|
|
250
|
+
destroy_relationship(name, *args)
|
|
251
|
+
end
|
|
252
|
+
end
|
|
253
|
+
|
|
254
|
+
# Destroys only a single relationship. Any arbitrary args
|
|
255
|
+
# may be added to the end and they will be pushed through to
|
|
256
|
+
# the class's `destroy_relationship` method.
|
|
257
|
+
#
|
|
258
|
+
# @param [Symbol] name The name of the relationship
|
|
259
|
+
def destroy_relationship(name, *args)
|
|
260
|
+
options = self.class.relationships_hash[name]
|
|
261
|
+
return unless options && relationship_class(name).respond_to?(:destroy_relationship)
|
|
262
|
+
|
|
263
|
+
# Read relationship, which forces lazy relationships to load, which is
|
|
264
|
+
# probably necessary for destroying
|
|
265
|
+
read_relationship(name)
|
|
266
|
+
|
|
267
|
+
relationship_class(name).destroy_relationship(self, relationship_data[name], *args)
|
|
268
|
+
end
|
|
269
|
+
|
|
270
|
+
# Hash to data associated with relationships. You should instead
|
|
271
|
+
# use the accessors created by Relatable.
|
|
272
|
+
#
|
|
273
|
+
# @return [Hash]
|
|
274
|
+
def relationship_data
|
|
275
|
+
@relationship_data ||= {}
|
|
276
|
+
end
|
|
277
|
+
|
|
278
|
+
# Returns boolean denoting if a relationship exists.
|
|
279
|
+
#
|
|
280
|
+
# @return [Boolean]
|
|
281
|
+
def has_relationship?(key)
|
|
282
|
+
self.class.has_relationship?(key.to_sym)
|
|
283
|
+
end
|
|
284
|
+
|
|
285
|
+
# Returns boolean denoting if a relationship is to be lazy loaded.
|
|
286
|
+
#
|
|
287
|
+
# @return [Boolean]
|
|
288
|
+
def lazy_relationship?(key)
|
|
289
|
+
options = self.class.relationships_hash[key.to_sym]
|
|
290
|
+
!options.nil? && options[:lazy]
|
|
291
|
+
end
|
|
292
|
+
|
|
293
|
+
# Returns boolean denoting if a relationship has been loaded.
|
|
294
|
+
def loaded_relationship?(key)
|
|
295
|
+
relationship_data.has_key?(key)
|
|
296
|
+
end
|
|
297
|
+
|
|
298
|
+
# Returns the class for a given relationship. This method handles converting
|
|
299
|
+
# a string/symbol into the proper class.
|
|
300
|
+
#
|
|
301
|
+
# @return [Class]
|
|
302
|
+
def relationship_class(key)
|
|
303
|
+
options = self.class.relationships_hash[key.to_sym]
|
|
304
|
+
klass = options[:klass]
|
|
305
|
+
klass = Object.module_eval("#{klass}") unless klass.is_a?(Class)
|
|
306
|
+
klass
|
|
307
|
+
end
|
|
308
|
+
|
|
309
|
+
# Sets a relationship to the given value. This is not guaranteed to
|
|
310
|
+
# do anything, since "set_relationship" will be called on the class
|
|
311
|
+
# that the relationship is associated with and its expected to return
|
|
312
|
+
# the resulting relationship to set.
|
|
313
|
+
#
|
|
314
|
+
# If the relationship class doesn't respond to the set_relationship
|
|
315
|
+
# method, then an exception {Exceptions::NonSettableRelationshipException} will
|
|
316
|
+
# be raised.
|
|
317
|
+
#
|
|
318
|
+
# This method is called by the "magic" method of `relationship=`.
|
|
319
|
+
#
|
|
320
|
+
# @param [Symbol] key Relationship key.
|
|
321
|
+
# @param [Object] value The new value of the relationship.
|
|
322
|
+
def set_relationship(key, value)
|
|
323
|
+
key = key.to_sym
|
|
324
|
+
relationship = self.class.relationships_hash[key]
|
|
325
|
+
return unless relationship
|
|
326
|
+
|
|
327
|
+
raise Exceptions::NonSettableRelationshipException.new unless relationship_class(key).respond_to?(:set_relationship)
|
|
328
|
+
relationship_data[key] = relationship_class(key).set_relationship(self, relationship_data[key], value)
|
|
329
|
+
end
|
|
330
|
+
end
|
|
331
|
+
end
|
|
332
|
+
end
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
module VirtualBox
|
|
2
|
+
class AbstractModel
|
|
3
|
+
# Provides validation methods for a class. Unlike ActiveRecord,
|
|
4
|
+
# validations are instance-level rather than class-level.
|
|
5
|
+
module Validatable
|
|
6
|
+
# Returns the errors on a model. The structure of this is a hash, keyed
|
|
7
|
+
# by the field name. The value of each member in the hash is an array of
|
|
8
|
+
# error messages.
|
|
9
|
+
#
|
|
10
|
+
# @return [Hash]
|
|
11
|
+
def errors
|
|
12
|
+
@errors ||= {}
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# Returns the errors on a specific field. This returns nil if there are
|
|
16
|
+
# no errors, otherwise it returns an array of error messages.
|
|
17
|
+
def errors_on(field)
|
|
18
|
+
@errors[field.to_sym]
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# Adds an error to a field. The error is a message.
|
|
22
|
+
def add_error(field, error)
|
|
23
|
+
errors[field] ||= []
|
|
24
|
+
errors[field].push(error)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Clears all the errors from a model.
|
|
28
|
+
def clear_errors
|
|
29
|
+
@errors = {}
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def full_error_messages
|
|
33
|
+
full_error_messages = Array.new
|
|
34
|
+
errors.each do |field_name, messages|
|
|
35
|
+
messages.each do |message|
|
|
36
|
+
human_field_name = field_name.to_s.gsub('_', ' ').capitalize
|
|
37
|
+
full_error_messages << "#{human_field_name} #{message}"
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
full_error_messages
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# This method calls the validate method on the model (which any subclass
|
|
44
|
+
# is expected to implement), and then checks that the validations didn't
|
|
45
|
+
# add any errors.
|
|
46
|
+
#
|
|
47
|
+
# @return [Boolean]
|
|
48
|
+
def valid?
|
|
49
|
+
validate
|
|
50
|
+
errors.empty?
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Subclasses should override this method. Validation can be done any
|
|
54
|
+
# way an implementer feels. Helper methods such as {#validates_presence_of},
|
|
55
|
+
# {#validates_inclusion_of}, etc. exist, but they're use isn't required.
|
|
56
|
+
# {#add_error} can be used to add an error to any field. By convention
|
|
57
|
+
# this method should return `true` or `false` to signal any errors.
|
|
58
|
+
#
|
|
59
|
+
# @return [Boolean]
|
|
60
|
+
def validate
|
|
61
|
+
true
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# Validates the presence (non-emptiness) of a field or fields. This
|
|
65
|
+
# validation fails if the specified fields are either blank ("") or
|
|
66
|
+
# nil.
|
|
67
|
+
#
|
|
68
|
+
# Additionally, a custom error message can be specified:
|
|
69
|
+
#
|
|
70
|
+
# validates_presence_of :foo, :bar
|
|
71
|
+
# validates_presence_of :baz, :message => "must not be blank!"
|
|
72
|
+
#
|
|
73
|
+
# @return [Boolean]
|
|
74
|
+
def validates_presence_of(*fields)
|
|
75
|
+
options = __validates_extract_options(fields, {
|
|
76
|
+
:message => "can't be blank."
|
|
77
|
+
})
|
|
78
|
+
|
|
79
|
+
fields.collect { |field|
|
|
80
|
+
value = send(field)
|
|
81
|
+
if value.nil? || value.to_s.empty?
|
|
82
|
+
add_error(field, options[:message])
|
|
83
|
+
false
|
|
84
|
+
else
|
|
85
|
+
true
|
|
86
|
+
end
|
|
87
|
+
}.compact.all? { |v| v == true }
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
# Validates the format of a field with a given regular expression.
|
|
91
|
+
#
|
|
92
|
+
# validates_format_of :foo, :with => /\d+/
|
|
93
|
+
#
|
|
94
|
+
def validates_format_of(*fields)
|
|
95
|
+
options = __validates_extract_options(fields, {
|
|
96
|
+
:with => nil,
|
|
97
|
+
:message => "is not properly formatted."
|
|
98
|
+
})
|
|
99
|
+
|
|
100
|
+
fields.collect { |field|
|
|
101
|
+
value = send(field)
|
|
102
|
+
# Use validates_presence_of if you need it to be set
|
|
103
|
+
next if value.nil? || value.to_s.empty?
|
|
104
|
+
if options[:with] && value =~ options[:with]
|
|
105
|
+
true
|
|
106
|
+
else
|
|
107
|
+
add_error(field, options[:message])
|
|
108
|
+
false
|
|
109
|
+
end
|
|
110
|
+
}.compact.all? { |v| v == true }
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
# Validates the numericality of a specific field.
|
|
114
|
+
#
|
|
115
|
+
# validates_numericality_of :field
|
|
116
|
+
#
|
|
117
|
+
def validates_numericality_of(*fields)
|
|
118
|
+
options = __validates_extract_options(fields, {
|
|
119
|
+
:message => "is not a number."
|
|
120
|
+
})
|
|
121
|
+
|
|
122
|
+
fields.collect { |field|
|
|
123
|
+
value = send(field)
|
|
124
|
+
# Use validates_presence_of if you need it to be set
|
|
125
|
+
next if value.nil? || value.to_s.empty?
|
|
126
|
+
if value.is_a?(Numeric) && value.to_s =~ /^\d$/
|
|
127
|
+
true
|
|
128
|
+
else
|
|
129
|
+
add_error(field, options[:message])
|
|
130
|
+
false
|
|
131
|
+
end
|
|
132
|
+
}.compact.all? { |v| v == true }
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
# Validates that a field's value is within a specific range,
|
|
136
|
+
# array, etc.
|
|
137
|
+
#
|
|
138
|
+
# validates_inclusion_of :foo, :in => [1,2,3]
|
|
139
|
+
# validates_inclusion_of :bar, :in => (1..6)
|
|
140
|
+
#
|
|
141
|
+
def validates_inclusion_of(*fields)
|
|
142
|
+
options = __validates_extract_options(fields, {
|
|
143
|
+
:in => nil,
|
|
144
|
+
:message => "value %s is not included in the list."
|
|
145
|
+
})
|
|
146
|
+
|
|
147
|
+
fields.collect { |field|
|
|
148
|
+
value = send(field)
|
|
149
|
+
# Use validates_presence_of if you need it to be set
|
|
150
|
+
return if value.nil? || value.to_s.empty?
|
|
151
|
+
if options[:in] && options[:in].include?(value)
|
|
152
|
+
true
|
|
153
|
+
else
|
|
154
|
+
message = options[:message] % value
|
|
155
|
+
add_error(field, message)
|
|
156
|
+
false
|
|
157
|
+
end
|
|
158
|
+
}.compact.all? { |v| v == true }
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
# Internal method. Should never be called.
|
|
162
|
+
def __validates_extract_options(fields, defaults)
|
|
163
|
+
defaults.merge(fields.last.is_a?(Hash) ? fields.pop : {})
|
|
164
|
+
end
|
|
165
|
+
end
|
|
166
|
+
end
|
|
167
|
+
end
|