This is an example from the Practical Object-Oriented Design in Ruby book. I am interested in translating this ruby code into javascript to have a better understanding of duck-typing in JS. Can anyone help translate this code to clarify how best to write this in Javascript or at least help get me started?
The trip class here is acting as the interface to the other classes (Mechanic, Trip_Coordinator, Driver). Where the prepare method in the class Trip uses the Duck type preparer.
class Trip
attr_reader :bicycles, :customers, :vehicle
def prepare(preparers)
preparers.each {|preparer|
preparer.prepare_trip(self)}
end
end
class Mechanic
def prepare_trip(trip)
# Does something with trip.bicycles
end
end
class Trip_Coordinator
def prepare_trip(trip)
# Does something with trip.customers
end
end
class Driver
def prepare_trip(trip)
# Does something with trip.vehicle
end
end
Update:
I have added code that I believe is a possible translation of the Ruby code above. However, when I run the code I get the following output and error:
mountain
2
jeep
/home/ubuntu/user/tests/trip.js:3
preparer.prepare_trip(this)
TypeError: Object [object Object] has no method 'prepare_trip'
Advice or suggestions would be appreciated to further improve the understanding of duck-typing in JS.
Javascript Code:
var Trip = function(preparers){
return preparers.forEach(function(preparer){
preparer.prepare_trip(this)
}
)};
var Mechanic = function(trip){
// does something with trip.bicycles
prepare_trip: console.log(trip.bicycles);
};
var TripCoordinator = function(trip){
//does something with trip.customers
prepare_trip: console.log(trip.customers);
};
var Driver = function(trip){
//does something with trip.vehicle
prepare_trip: console.log(trip.vehicle);
};
// customer wants to go on a trip for two and needs a car
var planA = {
bicycles: "mountain",
customers: 2,
vehicle: "jeep"
};
//customer wants to go a trip for one and only ride a bike
var planB = {
bicycles: "road",
customers: 1
};
Trip([new Mechanic(planA), new TripCoordinator(planA), new Driver(planA)]);
Trip([new Mechanic(planB), new TripCoordinator(planB)]);
UPDATE 2
Per the solution and advice from fgb below, I have place the final solution for my question below. I added an agent to remove the dependency of the caller having to know what prepares they would need when create a trip plan.
var Agent = function(plan){
if("bicycles" && "customers" && "vehicle" in plan){
Trip([new Mechanic(plan), new TripCoordinator(plan), new Driver(plan)]);
}
else if(!("vehicle" in plan) && "bicycles" && "customers" in plan){ //A driver is not needed
Trip([new Mechanic(plan), new TripCoordinator(plan)]);
}
};
var Trip = function(preparers){
return preparers.forEach(function(preparer){
preparer.prepare_trip(this)
}
)};
var Mechanic = function(trip){
// does something with trip.bicycles
this.prepare_trip = function() {
console.log(trip.bicycles);
}
};
var TripCoordinator = function(trip){
//does something with trip.customers
this.prepare_trip = function() {
console.log(trip.customers);
}
};
var Driver = function(trip){
//does something with trip.vehicle
this.prepare_trip = function() {
console.log(trip.vehicle);
}
};
// customer wants to go on a trip for two and needs a car
var planA = {
bicycles: "mountain",
customers: 2,
vehicle: "jeep"
};
//customer wants to go a trip for one and only ride a bike
var planB = {
bicycles: "road",
customers: 1
};
Agent(planB);
Related SO discussion Example of Javascript Duck Typing?
prepare_tripmethod? Have you tried to write this in JavaScript and come across any specific problems?