README.md in jsonify-0.0.3 vs README.md in jsonify-0.0.4
- old
+ new
@@ -1,6 +1,6 @@
-# Jsonify -- a builder for JSON <a href="http://travis-ci.org/bsiggelkow/jsonify"><img src="https://secure.travis-ci.org/bsiggelkow/jsonify.png" alt=""></a>
+# Jsonify — a builder for JSON [![Build Status](http://travis-ci.org/bsiggelkow/jsonify.png)](http://travis-ci.org/bsiggelkow/jsonify)
[Jsonify](https://github.com/bsiggelkow/jsonify) is to JSON as [Builder](https://github.com/jimweirich/builder) is to XML.
## Goal
@@ -29,10 +29,16 @@
`gem install jsonify`
## Usage
+In the examples that follow, the JSON output is usually shown "prettified". Is this only
+for illustration purposes, as the default behavior for Jsonify is not to prettify the output.
+You can enable prettification by passing `:pretty => true` to the Jsonify::Builder constructor; however,
+pretty printing is a relatively costly operation and should not be used in production (unless, of course, you explicitly
+want to show this format).
+
### Standalone
# Create some objects that represent a person and associated hyperlinks
@person = Struct.new(:first_name,:last_name).new('George','Burdell')
@links = [
['self', 'http://example.com/people/123'],
@@ -84,28 +90,266 @@
json.hello do
json.world "Jsonify is Working!"
end
+#### Partials
+
+You can use partials with Jsonify view templates, but how you use them will
+depend on how the information they return is structured. An important to keep in
+mind is that a partial, no matter what kind it is, always a returns a string.
+
+##### Jsonify partials
+
+Any Jsonify partial — that is, the file has a `.jsonify` extension —
+will return, by design, a string that is valid JSON. It will represent either a JSON object,
+and be wrapped in curly braces ({}), or a JSON array, and be wrapped in square brackets ([]).
+
+To incorporate such a value into a Jsonify template, Jsonify provides the `ingest!` method.
+
+You can use this method to add JSON, rendered by a partial, to the builder.
+Let's assume this our main template, `index.jsonify`:
+
+ json << 1
+ json.ingest! (render :partial=>'my_partial')
+
+From the first line, you can tell that an array will be created so this line uses the append operator.
+On the second line, a partial is being added to the builder. Note that you cannot simply place `render :parial ...`
+on a line by itself as you can do with other templates like `erb` and `haml`; you have to explicitly tell Jsonify
+to add it.
+
+Let's say that the partial file, `_my_partial.jsonify`, is as follows:
+
+ json << 3
+ json << 4
+
+This `json` variable is a separate instance of the Jsonify::Builder, distinct from the builder instance,
+in the main template. This partial will end up generating the following string:
+
+ "[3,4]"
+
+The `ingest!` method will actually parse this string back into a Jsonify-based object, and add it
+to the builder's current state. The resulting output will be:
+
+ "[1,[3,4]]"
+
+##### Other partials
+
+You can also use output from non-Jsonify templates (e.g. erb); just remember that the output from a template
+is always a string and that you have to tell the builder how to include the result of the partial.
+For example, suppose I have the partial `_today.erb` with the following content:
+
+ <%= Date.today %>
+
+You can then incorporate this partial into your Jsonify template just as you would any other string value:
+
+ json << 1
+ json.ingest! (render :partial=>'my_partial')
+ json << {:date => (render :partial => 'today')}
+
+ renders ...
+
+ [1,[3,4],{"date":"2011-07-30"}]
+
+### Usage Patterns
+
+Jsonify is designed to support construction of an valid JSON representation and
+is entirely based on the [JSON specification](http://json.org).
+
+JSON is built on two fundamental structures:
+
+ * __object__: a collection of name-value pairs -- in Jsonify this is a `JsonObject`
+ * __array__: an ordered list of values -- in Jsonify this is a `JsonArray`
+
+Jsonify adheres to the JSON specification and provides explicit support
+for working with these primary structures. At the top most level, a JSON string
+must be one of these structures and Jsonify ensures that this condition is met.
+
+#### JSON Objects
+
+A JSON object, sometimes
+referred to as an ___object literal___, is a common structure familiar
+to most developers. Its analogous to the nested element structured common
+in XML. The [JSON RFC](http://www.ietf.org/rfc/rfc4627.txt) states that
+"the names within an object SHOULD be unique". Jsonify elevates this recommendation
+by backing the JsonObject with a `Hash`; an object must have unique keys and the last one in, wins.
+
+ json = Jsonify::Builder.new
+ json.person do # start a new JsonObject where the key is 'foo'
+ json.name 'George Burdell' # add a pair to this object
+ json.skills ['engineering','bombing'] # adds a pair with an array value
+ json.name 'George P. Burdell'
+ end
+
+compiles to ...
+
+ {
+ "person": {
+ "name": "George P. Burdell",
+ "skills": [
+ "engineering",
+ "bombing"
+ ]
+ }
+ }
+
+It's perfectly legitimate for a JSON representation to simply be a collection
+of name-value pairs without a ___root___ element. Jsonify supports this by
+simply allowing you to specify the pairs that make up the object.
+
+ json = Jsonify::Builder.new
+ json.location 'Library Coffeehouse'
+ json.neighborhood 'Brookhaven'
+
+ compiles to ...
+
+ {
+ "location": "Library Coffeehouse",
+ "neighborhood": "Brookhaven"
+ }
+
+If the ___name___ you want contains whitespace or other characters not allowed in a Ruby method name, use `tag!`.
+
+ json.tag!("my location", 'Library Coffeehouse')
+ json.neighborhood 'Brookhaven'
+
+ {
+ "my location": "Library Coffeehouse",
+ "neighborhood": "Brookhaven"
+ }
+
+Jsonify also supports a hash-style interface for creating JSON objects.
+
+ json = Jsonify::Builder.new
+
+ json[:foo] = :bar
+ json[:go] = :far
+
+ compiles to ...
+
+ {
+ "foo": "bar",
+ "go": "far"
+ }
+
+You can these hash-style methods within a block as well ...
+
+ json.homer do
+ json[:beer] = "Duffs"
+ json[:spouse] = "Marge"
+ end
+
+ compiles to ...
+
+ {
+ "homer": {
+ "beer": "Duffs",
+ "spouse": "Marge"
+ }
+ }
+
+If you prefer a more method-based approach, you can use the `store!` method passing it the key and value.
+
+ json.store!(:foo, :bar)
+ json.store!(:go, :far)
+
+#### JSON Arrays
+
+A JSON array is an ordered list of JSON values. A JSON value can be a simple value,
+like a string or a number, or a supported JavaScript primitive like true, false, or null.
+A JSON value can also be a JSON object or another JSON array. Jsonify strives to make
+this kind of construction possible in a buider-style.
+
+Jsonify supports JSON array construction through two approaches: `method_missing` and `append!`.
+
+##### method_missing
+
+Pass an array and a block to `method_missing` (or `tag!`), and Jsonify will iterate
+over that array, and create a JSON array where each array item is the result of the block.
+If you pass an array that has a length of 5, you will end up with a JSON array that has 5 items.
+That JSON array is then set as the value of the name-value pair, where the name comes from the method name (for `method_missing`)
+or symbol (for `tag!`).
+
+So this construct is really doing two things -- creating a JSON pair, and creating a JSON array as the value of the pair.
+
+ json = Jsonify::Builder.new(:pretty => true)
+ json.letters('a'..'c') do |letter|
+ letter.upcase
+ end
+
+compiles to ...
+
+ {
+ "letters": [
+ "A",
+ "B",
+ "C"
+ ]
+ }
+
+Another way to handle this particular example is to get rid of the block entirely.
+Simply pass the array directly — the result will be the same.
+
+ json.letters ('a'..'c').map(&:upcase)
+
+##### append!
+
+But what if we don't want to start with an object? How do we tell Jsonify to start with an array instead?
+
+You can use `append!` (passing one or more values), or `<<` (which accepts only a single value) to
+the builder and it will assume you are adding values to a JSON array.
+
+ json = Jsonify::Builder.new
+ json.append! 'a'.upcase, 'b'.upcase, 'c'.upcase
+
+ [
+ "A",
+ "B",
+ "C"
+ ]
+
+or more idiomatically ...
+
+ json.append! *('a'..'c').map(&:upcase)
+
+The append ___operator___, `<<`, can be used to push a single value into the array:
+
+ json << 'a'.upcase
+ json << 'b'.upcase
+ json << 'c'.upcase
+
+Of course, standard iteration works here as well ...
+
+ json = Jsonify::Builder.new
+ ('a'..'c').each do |letter|
+ json << letter.upcase
+ end
+
+#### Mixing JSON Arrays and Objects
+
+___coming soon___
+
## Documentation
[Yard Docs](http://rubydoc.info/github/bsiggelkow/jsonify/master/frames)
<a name='related'/>
<h2>Related Projects</h2>
- [Argonaut](https://github.com/jbr/argonaut)
- [JSON Builder](https://github.com/dewski/json_builder)
- [RABL](https://github.com/nesquena/rabl)
+- [Representative](https://github.com/mdub/representative)
- [Tokamak](https://github.com/abril/tokamak)
## TODOs
1. Benchmark performance
1. Document how partials can be used
+1. Clean up specs
## Roadmap
1. Split Rails template handling into separate gem
-1. Add support for Sinatra and Padrino (maybe separate gems)
+1. Add support for Sinatra and Padrino (Tilt integration?)
## License
This project is released under the MIT license.