1

I am coming from a C# background and trying to learn Ruby and Ruby on Rails. I have the following Car class - note the build_xml method I need in order to build XML in that syntax and then pass to a WebService

class Car

  @@array = Array.new
  #this will allow us to get list of all instances of cars created if needed
  def self.all_instances
    @@array
  end

  def initialize(id, model_number, engine_size, no_doors)
    # Instance variables
    @id = id
    @model_number = model_number
    @engine_size = engine_size
    @no_doors = no_doors
    @@array << self
  end

  def build_car_xml
    car = { 'abc:Id'=> @id, 'abc:ModelNo' => @model_number, 'abc:ES' => @engine_size, 'abc:ND' => @no_doors}
   cars = {'abc:Car' => [car] }   
  end

end

In another class then I was using this as below:

car1 = Car.new('1', 18, 3.0, 4)
request = car1.build_car_xml

This works as expected and the request is formatted how I need and the webservice returns the results. I now want to expand this however so I can pass in an array of cars and produce the request XML - however I am struggling to get this part working.

So far I have been trying the following (for now I am ok with just the Id changing as it is the only parameter required to be unique):

  car_array = []
  (1..10).each do |i|
    car_array << Car.new(i.to_s, 18, 3.0, 4)
  end

Am I correct in saying that I would need to define a new build_car_xml method on my Car class that can take an array of cars and then build the xml so my request call would be something like:

request = Car.build_car_xml(car_array)

What i am unsure of is 1) - is this the correct way of doing things in Ruby and 2) how to construct the method so that it is Building the XML in the correct format in the way it was when I call it on the single object - i.e - I need the namespaces added before the actual value.

def build_car_xml(car_array)
 #here is where I am unsure how to contruct this method   
end
Ctrl_Alt_Defeat
  • 3,933
  • 12
  • 66
  • 116
  • 1
    There may come a point soon when using `Car` class as a placeholder for methods that apply to "a collection of cars" is not tenable, and you will want to properly reify the collection. If a "collection of cars" has properties not already covered in a Ruby `Array` (such as XML start and end elements), then make a new class. – Neil Slater Apr 02 '14 at 11:13
  • 1
    This feels like it shouldn't be tagged with ruby-on-rails. Rails has a lot of infrastructure for organising collections of objects via database tables, whereas you appear to be rolling your own organisation here. – Max Williams Apr 02 '14 at 11:20
  • Also I agree with Neil that you shouldn't use the Car class to hold all instances of Car objects currently in memory, this feels wrong to me. I would have another class for this, that has an instance variable holding an array of Car objects. – Max Williams Apr 02 '14 at 11:23
  • @mbratch - could you expand with an answer as to how to call the build_car_xml on each object in the array as is - and how that would be built up? – Ctrl_Alt_Defeat Apr 02 '14 at 11:26

1 Answers1

1

Possible solution ('abc:Car' is a wrong name, should be Cars if you want it to hold an array):

class Car

...

  def self.build_cars_xml(cars)
    { 'abc:Car' => cars.map(&:build_car_xml) }   
  end

  def build_car_xml
    { 'abc:Id'=> @id, 'abc:ModelNo' => @model_number, 'abc:ES' => @engine_size, 'abc:ND' => @no_doors }
  end
end

cars =
  (1..10).map do |i|
    Car.new(i.to_s, 18, 3.0, 4)
  end
Car.build_cars_xml(cars)

It doesn't meet your requirements as instance build_car_xml doesn't generate Car namespace, but for me it's some inconsistency. Your XML is actually a collection, even if it has just one element, instance method should not be responsible for collection. Car.build_cars_xml([Car.new(...)] looks more logical to me.

Victor Moroz
  • 9,167
  • 1
  • 19
  • 23