# Spectifly Say you've been tasked with building a web service that accepts a purchase order in XML format, adds some additional fields, sends the modified purchase order to another web service via JSON, receives a JSON response with fulfillment details, and finally sends back the same order with all this additional data back to the original client, via XML. You've been given specifications for what fields the purchase order needs to have at every step of the process, and you need to validate the object differently for each transaction. Spectifly is here to help. It's a library with a highly opinionated markup language (based on YAML) for specifying entities and their presentations (using `*.entity` files), and uses these entity specifications to generate XSDs, JSON validators, and fixture data for testing. ## Installation Add this line to your application's Gemfile: gem 'spectifly' And then execute: $ bundle Or install it yourself as: $ gem install spectifly ## Usage The Spectifly markup language is a subset of YAML. Only one root node is allowed per file (since a single `.entity` file represents a single business entity), and there are other restrictions, as well as additional features, which we'll discuss here. Here's an example entity: ```YAML Widget: Description: A widget produced by WidgetCo Fields: Name*: Description: Display name of widget Created At: Description: When the widget was built Type: DateTime Awesome?: Description: Whether or not the widget is awesome Related Entities: Belongs To: Manufacturing Plant*: Description: The WidgetCo location that constructed the widget Type: Manufacturing Location Has Many: Accessories: Description: Widget Add-ons that augment the widget's functionality Type: Add On ``` The root node, `Widget:` above, is required, and there can be only one node at this level. Directly below the root node, the only valid nodes are `Description` (optional), `Fields` (required), and `Related Entities` (optional). The `Description` is a plain language description of the entity. The `Related Entities` node includes associations to other entities, grouped by how the entity is related. ### Fields `Fields` is a YAML tree with one or more field entries, which have their own specification. The key of a field node is the field's name, and the value can either be null, or another tree with several possible keys, all of which are optional themselves: * `Description` (string): A plain-language description of the variable * `Multiple` (Boolean): Whether or not this variable can occur multiple times * `Type` (string): Type of data contained in this field (defaults to String) * `Validations` (string or list of strings): Restrictions on the values allowed in this field * `Valid Values` (list of strings): List of possible literal values for this field * `Minimum Value` (numeric): Minimum value allowed for this field (numeric fields only) * `Maximum Value` (numeric): Maximum value allowed for this field (numeric fields only) #### Special Tokens The key of the field node (the name of the field) can also end with one or two special "tokens": * The `*` token, as in the `Name*` field in the above example, makes the field required, which means it must occur once (or at least once, for Multiple fields). * The `?` token, as in the example's `Awesome?` field, sets `Type` to Boolean. These tokens can be combined, if you have a required Boolean field. If the `?` shortcut conflicts with the explicit key (e.g. a `Rad?` field with `Type: String`), an exception will be thrown during parsing. ### Related Entities `Related Entities` is a YAML tree that enumerates the entities with which the defined entity is associated. They are grouped by type of relationship and include the name of the association and which type of entity that association links to. Like `Fields`, the `*` special token can be used to mark an association as required. If a plural association (such as has_many or has_and_belongs_to_many) is marked as required, that relationship must have *at least one* member. * `Belongs To` is a singular association, where the owner is the other entity (e.g. a kitten belongs to a litter of kittens) * `Has One` is a singular association, where the owner is this entity (e.g. a kitten has one (and only one) nose) -- an inverse of `Belongs To` * `Has Many` is a plural association, where the owner is this entity (e.g. a kitten has many toys) -- also can be an inverse of `Belongs To` * `Has and Belongs To Many` is a many-to-many relationship between two entities, and plural on both sides (e.g. a dish is made up of many ingredients, and an ingredient is a component of many dishes) Under each of these association nodes, the YAML tree lists entities that relate to the described entity in that way. ## Contributing 1. Fork it 2. Create your feature branch (`git checkout -b my-new-feature`) 3. Commit your changes (`git commit -am 'Add some feature'`) 4. Push to the branch (`git push origin my-new-feature`) 5. Create new Pull Request