propershark / shark

An event publisher for realtime transit information.
3 stars 0 forks source link

How to add attributes via Middleware #20

Closed faultyserver closed 8 years ago

faultyserver commented 8 years ago

16 outlines a potential case where a Middleware would create a new attribute neighborhood on Vehicle. If the middleware is not present, this attribute will never be populated, and should therefore not be part of the default Vehicle model.

The question, then, is this: How can a middleware define new attributes for a model? These attributes need to be included in the appropriate object.class.attributes list in order to be serializable, but should not require users to modify the Object classes manually when adding middlewares.

A simple solution, it seems, would be to add a Middleware#installed callback that is called after a Middleware instance is installed into the stack for an agency. Middlewares could then do anything in response, including dynamically modify Object attributes. For example, to add a neighborhood attribute to Shark::Vehicle:

class AttributeModifyingMiddleware < Shark::Middleware
  # The callback will include a reference to the agency that this middleware
  # was just installed in.
  def installed agency
    # Add a new `neighborhood` attribute to `Shark::Vehicle`
    Shark::Vehicle.attribute :neighborhood
  end
end

An issue with this approach is that there is no longer a canonical location where all attributes of a model are listed. However, the list is always dynamically available through object.class.attributes, which should be sufficient for most cases.

elliottwilliams commented 8 years ago

Makes sense to me. The canonical attribute list, as it currently is, isn't perfect anyways. It's typelessness has made me usually look at serialized objects when building decoders. A future system could dynamically generate more thorough object attribute documentation (something like ActiveRecord's schema.rb), but I'm fine with this approach for now.

faultyserver commented 8 years ago

Agreed. I'm working on a schema system that supplies expectations and type requirements for Configuration right now, so hopefully I'll be able to apply that to models before long.

faultyserver commented 8 years ago

533c60755138bdd18c5f02d3942d9850bf252c24 and 65fde3ed50ff8c93c41a5c377372b9a464742d86 have been implementing a Schemable module, which should solve this, at least from a descriptive angle.

All Shark::Object classes have a schema property that contains all of the information about the expected structure of an Object. This currently includes attribute names, requiredness, default values, value aliases, and type information (though types are not currently enforced). All instances of these classes can reference their schema through self.class.schema.

There could potentially be a rake task or similar that loads an agency, reads these schemas, and dumps a schema.json or something for the sake of complete documentation.