Support passing down a block to a property through PropertyLookup

* Blocks are used when defining properties that are actually nested
  schemas (an array in a hash, an array of hashes)
Add the NestedHash Property, allowing schemas to define nested hashes

* Called `NestedHash` because `hash` is a ruby method, leading to name
  conflicts during PropertyLookup
* Schemas might require a hash to be defined within their schema:
  * An array of hashes, which follow a specifi schema
  * A hash with a hash inside of it.
* This property requires a block to be given, which is uses to define
  a new instance of HashShema
* Handles common Property methods like checking requiredness and
  adding the error message if necessary
* Does not accept any validators
* Consults the schema defined to determine if the property is valid
* Provides access to schema methods like `allow_nil?` & `strict_mode?`
Array Schema returns an error hash, where keys are the array indices

* Properties have unique validation schemes and their own way of
  defining error messages. (e.g: nested hashes return a complex
  key-value pair detailing which properties were invalid)
* Array Schema's original error definition model was too simple and
  failed to take these nuances into account.
Prevent Property base class from adding "required" message twice

* Occurs when validating the same property multiple times
  e.g: validating an array of hashes.
Ensure the HashSchema's strict mode error message clears on validation

* protects against false positives when validating a hash
ArraySchema clears error messages each time an object is validated

* Prevents false positives when using the same instance to validate
  multiple objects.
Expand Tests for NestedHash when used with different types of schemas

* Ensures that nested hash schema works as expected.
Add Array Property, allowing schemas to define nested arrays

* Schemas might require an array to be defined within their schema:
  * An array of arrays
  * A hash with a property that expects an array
* This property requires a block to be given, which it uses to define
  a new instance of ArraySchema
* Handles common property methods like checking requirdness and adding
  the error message if necessary
* Does not accept any validators
* Consults the schema defined to determine if the property is valid
* Provides access to schema methods like `validates_uniqueness?`