azure-sdk-for-ruby icon indicating copy to clipboard operation
azure-sdk-for-ruby copied to clipboard

Models: Allow options to be passed as hash in initializer

Open jsmartt opened this issue 6 years ago • 0 comments

Initializing new instances of models is a bit of a pain right now without the option to pass any attributes at initialization time. Using #tap to set attributes as shown in the docs is pretty uncommon in the Ruby world.

Step 1

I propose adding an initializer with the ability to receive attributes. For example, all models could include something like:

# @param attributes [Hash]
def initialize(attributes = nil)
  attributes.each do |key, val|
    public_send("#{key}=", val)
  end
end

Result:

# Previous way of doing things (still works, but is ugly):
os_profile = Azure::Compute::Profiles::V2018_03_01::Mgmt::Models::OSProfile.new.tap do |os_profile|
  os_profile.computer_name = 'my_vm'
  os_profile.admin_username = 'azure-user'
  os_profile.admin_password = 'secret_123'
end

# Using new initializer method:
os_profile = Azure::Compute::Profiles::V2018_03_01::Mgmt::Models::OSProfile.new(
  computer_name: 'my_vm',
  admin_username: 'azure-user'
  admin_password: 'secret_123'
)

This allows things to be much more condensed, even on a single line.

You could get much fancier if you want, similar to how ActiveRecord does it (see here & here).

Step 2

To take this one step further, I think it the whole data model of a model with nested objects should be able to be passed in this way. Instead of requiring the user to create giant nested structures of Ruby objects, let the user provide the data in a form that makes sense for a human, and can be easily passed in from formats like JSON.

There are a few different ways you could do this, but since the code is generated and the docs show what the type of the attribute should be, it should be very easy to convert hashes, etc. to the correct data type.

Result:

# Previous way of doing things (still works, but is ugly):
vm_params = Azure::Compute::Profiles::V2018_03_01::Mgmt::Models::VirtualMachine.new.tap do |vm|
  vm.network_profile = Azure::Compute::Profiles::V2018_03_01::Mgmt::Models::NetworkProfile.new.tap do |net_profile|
    net_profile.network_interfaces = [
      Azure::Compute::Profiles::V2018_03_01::Mgmt::Models::NetworkInterfaceReference.new.tap do |ref|
        ref.id = nic.id
        ref.primary = true
      end
    ]
  end
end

# Using new data-centric auto-type-conversions:
vm_params = Azure::Compute::Profiles::V2018_03_01::Mgmt::Models::VirtualMachine.new(
  network_profile: {
    network_interfaces: [
      { id: nic.id primary: true }
    ]
  }
)

The types can be converted before setting the attributes that require it (e.g. network_profile & network_interfaces in the example above) to keep the data consistent, but it makes a night-and-day difference in usability. SDKs are supposed to make things easier after all, not harder.

Repo owners: Please let me know if you are open to these improvements; I'd be glad to contribute if you're open to them (assuming I can figure out how the code is generated), but don't want to waste my time with a PR if not.

jsmartt avatar Feb 12 '19 00:02 jsmartt