Petroglyph
A simple, terse, and unsurprising ruby dsl to create json views.
Usage
Add a node with a simple value:
node :beverage => current_user.favorite_drink
=> '{"beverage":"mead"}'
Add a node with nested content:
node :home do
merge {:location => {:city => 'Paris', :country => 'France'}}
end
=> '{"home":{"location":{"city":"Paris","country":"France"}}}'
Add sibling nodes within a node:
node :pet do
merge {:species => "turtle", :color => 'green'}
node :name => "Anthony"
end
=> '{"pet":{"species":"turtle","color":"green","name":"Anthony"}}'
It's all just ruby, unsurprisingly:
node :pet do
if user.child?
merge {:species => "turtle"}
node :name => "Anthony"
else
node :species => 'human'
node :name => 'Billy'
end
end
=> '{"pet":{"species":"turtle","name":"Anthony"}}'
Conveniently define which attributes to include. Create a new node with a different name for attributes you wish to alias.
alice = Person.create!(:name => 'Alice', :profession => 'surgeon', :created_at => 28.years.ago, :gender => 'female')
node :person => alice do
attributes :name, :gender
node :job => alice.profession
end
=> '{"person":{"name":"Alice","gender":"female","job":"surgeon"}}'
If you don't want to namespace the object, you can use merge
in place of node
:
merge alice do
attributes :name, :gender
node :job => alice.profession
end
=> '{"name":"Alice","gender":"female","job":"surgeon"}'
Iterate through collections:
wulong = Tea.new(:type => 'wulong')
lucha = Tea.new(:type => 'green')
collection :teas => [wulong, lucha] do
attributes :type
end
=> '{"teas":[{"type":"wulong"},{"type":"wulong"}]}'
You can also explicitly reference each item in the collection if you need to:
collection :teas => teas do |tea|
node :tea => tea do
attributes :type
end
node :provider => lookup_provider_for(tea)
end
=> '{"teas":[{"tea":{"type":"wulong"},{"provider":"Imperial Teas"}},{"tea":{"type":"wulong"},{"provider":"House of Tea"}}]}'
Partials have been implemented. This defaults to looking for a file in the same file as the template, or in a subdirectory called partials
.
There is a shortcut if you're looping over a collection to render a partial for each item in the collection:
collection :teas => teas, :partial => :tea
The name of the partials subdirectory can be overridden by re-implementing the Petroglyph.partial(name)
method.
collection :teas => teas do |tea|
# partial(template_name, local_variables)
partial :tea, :tea => tea
end
Rails 3
In your controller:
render 'index', :locals => {:teas => teas}, :layout => false
Support for partials is non-standard at this time: create a subdirectory in the directory that your template lives in and call it partials
.
Sinatra
This works with version 1.3 of Sinatra. It may work with earlier versions.
Config
You need to require the Sinatra petroglyph extension:
require 'sinatra/petroglyph'
Then you can use the pg
helper method in your endpoints:
get '/api/v1/widgets' do
pg :widgets, :locals => {:widgets => Widget.all}
end
Gotcha
There is a known incompatibility in Sinatra versions prior to 1.3 where a local variable named post
will crash with Sinatra's HTTP post
action.
The same goes for get
, head
, put
, etc, but these are less likely to be resources in your application.
Caveat
There is currently no support for instance variables in Sinatra and Rails 3.
Related Projects
Other json templating libraries exist, some of which also generate XML.
License
MIT License
Copyright (c) 2012 Katrina Owen