rabl 0.0.5 → 0.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.md +44 -24
- data/TODO +7 -0
- data/examples/base.json.rabl +8 -0
- data/examples/demo.json.rabl +42 -0
- data/examples/inherited.json.rabl +11 -0
- data/lib/rabl/builder.rb +1 -1
- data/lib/rabl/engine.rb +3 -3
- data/lib/rabl/version.rb +1 -1
- metadata +12 -6
data/README.md
CHANGED
@@ -1,16 +1,17 @@
|
|
1
1
|
# RABL #
|
2
2
|
|
3
|
-
RABL is a ruby templating system for Rails that takes a
|
3
|
+
RABL is a ruby templating system for Rails and [Padrino](http://padrinorb.com) that takes a new approach to generating JSON and other formats. Rather than using the ActiveRecord 'to_json', I generally find myself wanting a more expressive and powerful system for generating my APIs. This is especially important when the json representation is complex or doesn't match the exact schema defined in the database itself.
|
4
4
|
|
5
5
|
There were a few things in particular I wanted to do easily:
|
6
6
|
|
7
|
-
* Create arbitrary nodes named based on combining data in
|
8
|
-
* Include nodes only if a condition is met
|
9
|
-
* Pass arguments to methods and store the result as a node
|
10
|
-
*
|
11
|
-
* Easily
|
7
|
+
* Create arbitrary nodes named based on combining data in an object
|
8
|
+
* Include nodes only if a certain condition is met
|
9
|
+
* Pass arguments to methods and store the result as a child node
|
10
|
+
* Partial templates and inheritance to reduce code duplication
|
11
|
+
* Easily renaming attributes from their name in the model
|
12
|
+
* Simple way to append attributes from a child into the parent
|
12
13
|
|
13
|
-
|
14
|
+
The list goes on. Anyone who has used the 'to_json' approach used in ActiveRecord for generating a json response has felt the pain of the extremely restrictive system. RABL is a general templating system created to solve all of those problems. When I created RABL, I wanted a simple, expressive DRY ruby DSL for defining JSON responses for my APIs.
|
14
15
|
|
15
16
|
## Installation ##
|
16
17
|
|
@@ -25,17 +26,17 @@ or add to your Gemfile:
|
|
25
26
|
|
26
27
|
and run `bundle install` to install the dependency.
|
27
28
|
|
28
|
-
If you are using Rails 2.X or Padrino, RABL works
|
29
|
+
If you are using Rails 2.X or Padrino, RABL works without configuration. With Sinatra, or any other tilt-based framework, simply register:
|
29
30
|
|
30
31
|
Rabl.register!
|
31
32
|
|
32
|
-
and RABL will be initialized.
|
33
|
+
and RABL will be initialized and ready for use.
|
33
34
|
|
34
35
|
## Usage ##
|
35
36
|
|
36
37
|
### Object Assignment ###
|
37
38
|
|
38
|
-
To declare the data object
|
39
|
+
To declare the data object for use in the template:
|
39
40
|
|
40
41
|
# app/views/users/show.json.rabl
|
41
42
|
object @user
|
@@ -48,40 +49,43 @@ and this will be used as the default data object for the rendering.
|
|
48
49
|
|
49
50
|
### Attributes ###
|
50
51
|
|
51
|
-
Basic usage of the templater:
|
52
|
+
Basic usage of the templater to define a few simple attributes for the response:
|
52
53
|
|
53
54
|
# app/views/users/show.json.rabl
|
54
55
|
attributes :id, :foo, :bar
|
55
56
|
|
56
|
-
or with aliased attributes:
|
57
|
+
or use with aliased attributes:
|
57
58
|
|
58
59
|
# Take the value of model attribute `foo` and name the node `bar`
|
59
60
|
# { bar : 5 }
|
60
61
|
attribute :foo => :bar
|
61
62
|
|
62
|
-
or multiple aliased attributes:
|
63
|
+
or even multiple aliased attributes:
|
63
64
|
|
64
65
|
# { baz : <bar value>, animal : <dog value> }
|
65
66
|
attributes :bar => :baz, :dog => :animal
|
66
67
|
|
67
68
|
### Child Nodes ###
|
68
69
|
|
69
|
-
You can also add
|
70
|
+
You can also add child nodes from an arbitrary source:
|
70
71
|
|
71
72
|
child @posts => :foobar do
|
72
73
|
attributes :id, :title
|
73
74
|
end
|
74
75
|
|
75
|
-
or use existing model associations:
|
76
|
+
or simply use existing model associations:
|
76
77
|
|
78
|
+
# Renders all the 'posts' association
|
79
|
+
# from the model into a node called 'foobar'
|
77
80
|
child :posts => :foobar do
|
78
81
|
attributes :id, :title
|
79
82
|
end
|
80
83
|
|
81
|
-
###
|
84
|
+
### Gluing Attributes ###
|
82
85
|
|
83
|
-
You can also append attributes to the root node:
|
86
|
+
You can also append child attributes back to the root node:
|
84
87
|
|
88
|
+
# Appends post_id and post_name to parent json object
|
85
89
|
glue @post do
|
86
90
|
attributes :id => :post_id, :name => :post_name
|
87
91
|
end
|
@@ -90,18 +94,18 @@ Use glue to add additional attributes to the parent object.
|
|
90
94
|
|
91
95
|
### Custom Nodes ###
|
92
96
|
|
93
|
-
This will generate a json response
|
97
|
+
This will generate a json response based on the result of the code block:
|
94
98
|
|
95
99
|
# app/views/users/show.json.rabl
|
96
100
|
code :full_name do |u|
|
97
101
|
u.first_name + " " + u.last_name
|
98
102
|
end
|
99
103
|
|
100
|
-
You can use custom "code" nodes to create flexible representations of a value utilizing data from the model.
|
104
|
+
You can use custom "code" nodes to create flexible representations of a value utilizing all the data from the model.
|
101
105
|
|
102
106
|
### Partials ###
|
103
107
|
|
104
|
-
Often you need to access sub-objects in order to construct your own custom nodes for more complex associations. You can get access to the
|
108
|
+
Often you need to access sub-objects in order to construct your own custom nodes for more complex associations. You can get access to the rabl representation of another object with:
|
105
109
|
|
106
110
|
code :location do
|
107
111
|
{ :city => @city, :address => partial("web/users/address", :object => @address) }
|
@@ -113,11 +117,11 @@ or an object associated to the parent model:
|
|
113
117
|
{ :city => m.city, :address => partial("web/users/address", :object => m.address) }
|
114
118
|
end
|
115
119
|
|
116
|
-
You can use
|
120
|
+
You can use this method to construct arbitrarily complex nodes for your APIs.
|
117
121
|
|
118
122
|
### Inheritance ###
|
119
123
|
|
120
|
-
Another common
|
124
|
+
Another common issue of many template builders is unnecessary code redundancy. Typically many representations of an object across multiple endpoints share common attributes or nodes. The nodes for a 'post' object are probably the same or similar in most references throughout the various endpoints.
|
121
125
|
|
122
126
|
RABL has the ability to extend other "base" rabl templates and additional attributes:
|
123
127
|
|
@@ -128,7 +132,7 @@ RABL has the ability to extend other "base" rabl templates and additional attrib
|
|
128
132
|
m.age > 21
|
129
133
|
end
|
130
134
|
|
131
|
-
You can also extend other rabl templates
|
135
|
+
You can also extend other rabl templates while constructing child nodes to reduce duplication:
|
132
136
|
|
133
137
|
# app/views/users/show.json.rabl
|
134
138
|
child @address do
|
@@ -139,4 +143,20 @@ Using partials and inheritance can significantly reduce code duplication in your
|
|
139
143
|
|
140
144
|
## Issues ##
|
141
145
|
|
142
|
-
* I am sloppy and once again failed to unit test this. Don't use it in production until I do obviously.
|
146
|
+
* I am sloppy and once again failed to unit test this. Don't use it in production until I do obviously.
|
147
|
+
* No support for Rails 3
|
148
|
+
|
149
|
+
## Authors and Contributors ##
|
150
|
+
|
151
|
+
* [Nathan Esquenazi](https://github.com/nesquena) - Creator of the project
|
152
|
+
* [Arthur Chiu](https://github.com/achiu) - Core Maintainer, Riot Testing Guru
|
153
|
+
|
154
|
+
## Inspirations ##
|
155
|
+
|
156
|
+
There are a few excellent libraries that helped inspire RABL and they are listed below:
|
157
|
+
|
158
|
+
* [Tequila](https://github.com/inem/tequila)
|
159
|
+
* [JSON Builder](https://github.com/dewski/json_builder)
|
160
|
+
* [Argonaut](https://github.com/jbr/argonaut)
|
161
|
+
|
162
|
+
Thanks again for all of these great projects.
|
data/TODO
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
# Use the @media object set in route
|
2
|
+
object @media
|
3
|
+
|
4
|
+
# Include these three attributes
|
5
|
+
attributes :title, :kind, :id
|
6
|
+
# Rename 'studio' to be the 'company' node
|
7
|
+
attributes :studio => :company
|
8
|
+
|
9
|
+
# Arbitrary code blocks can be defined
|
10
|
+
# Creates a 'release_year' node
|
11
|
+
code :release_year do |m|
|
12
|
+
date = m.release_date || m.series_start
|
13
|
+
date.try(:year)
|
14
|
+
end
|
15
|
+
|
16
|
+
# Creates a node 'users' with an array of the nested users for media
|
17
|
+
# Block is the same rabl syntax for the sub object
|
18
|
+
child @users do
|
19
|
+
attributes :full_name, :first_name
|
20
|
+
end
|
21
|
+
|
22
|
+
# Uses the associations of the parent media object
|
23
|
+
# Rename 'users' association to 'people' node
|
24
|
+
child :users => :people do
|
25
|
+
attributes :full_name, :first_name
|
26
|
+
end
|
27
|
+
|
28
|
+
# Creates the "actor" association as a 'user' node
|
29
|
+
# Use the information from another rabl template to describe the representation
|
30
|
+
child :actor => :user do
|
31
|
+
extends "users/simple"
|
32
|
+
end
|
33
|
+
|
34
|
+
# Append attributes to the root node with prefixed names
|
35
|
+
glue @users.first do
|
36
|
+
attributes :full_name => :user_full_name, :first_name => :user_first_name
|
37
|
+
end
|
38
|
+
|
39
|
+
# Render an arbitrary hash with a partial rabl json as one of the keys
|
40
|
+
code :topics do |m|
|
41
|
+
{ :fake => partial("media/user", :object => @users.first), :raw => @users.first }
|
42
|
+
end
|
data/lib/rabl/builder.rb
CHANGED
@@ -77,7 +77,7 @@ module Rabl
|
|
77
77
|
# Extends an existing rabl template with additional attributes in the block
|
78
78
|
# extends("users/show") { attribute :full_name }
|
79
79
|
def extends(file, options={}, &block)
|
80
|
-
options = options.merge
|
80
|
+
options = options.merge(:object => @_object)
|
81
81
|
result = @options[:engine].partial(file, options, &block)
|
82
82
|
@_result.merge!(result)
|
83
83
|
end
|
data/lib/rabl/engine.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
module Rabl
|
2
2
|
class Engine
|
3
3
|
# Constructs a new ejs engine based on given vars, handler and declarations
|
4
|
-
# Rabl::Engine.new("...source...", { :format => "xml" })
|
4
|
+
# Rabl::Engine.new("...source...", { :format => "xml", :root => true, :view_path => "/path/to/views" })
|
5
5
|
def initialize(source, options={})
|
6
6
|
@_source = source
|
7
7
|
@_options = options.reverse_merge(:format => "json")
|
@@ -13,7 +13,7 @@ module Rabl
|
|
13
13
|
@_locals = locals
|
14
14
|
@_scope = scope
|
15
15
|
@_options = @_options.merge(:scope => @_scope, :locals => @_locals, :engine => self)
|
16
|
-
self.copy_instance_variables_from(@_scope, [:@assigns, :@helpers])
|
16
|
+
self.copy_instance_variables_from(@_scope, [:@assigns, :@helpers])
|
17
17
|
@_object = locals[:object] || self.default_object
|
18
18
|
instance_eval(@_source) if @_source.present?
|
19
19
|
instance_eval(&block) if block_given?
|
@@ -118,7 +118,7 @@ module Rabl
|
|
118
118
|
def fetch_source(file)
|
119
119
|
root_path = Rails.root if defined?(Rails)
|
120
120
|
root_path = Padrino.root if defined?(Padrino)
|
121
|
-
view_path = File.join(root_path, "app/views/")
|
121
|
+
view_path = @_options[:view_path] || File.join(root_path, "app/views/")
|
122
122
|
file_path = Dir[File.join(view_path, file + "*.rabl")].first
|
123
123
|
File.read(file_path) if file_path
|
124
124
|
end
|
data/lib/rabl/version.rb
CHANGED
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rabl
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
5
|
-
prerelease:
|
4
|
+
hash: 19
|
5
|
+
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 0
|
9
|
-
-
|
10
|
-
version: 0.0.
|
9
|
+
- 6
|
10
|
+
version: 0.0.6
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Nathan Esquenazi
|
@@ -15,7 +15,8 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-04-12 00:00:00
|
18
|
+
date: 2011-04-12 00:00:00 -07:00
|
19
|
+
default_executable:
|
19
20
|
dependencies:
|
20
21
|
- !ruby/object:Gem::Dependency
|
21
22
|
name: riot
|
@@ -63,6 +64,10 @@ files:
|
|
63
64
|
- Gemfile
|
64
65
|
- README.md
|
65
66
|
- Rakefile
|
67
|
+
- TODO
|
68
|
+
- examples/base.json.rabl
|
69
|
+
- examples/demo.json.rabl
|
70
|
+
- examples/inherited.json.rabl
|
66
71
|
- lib/rabl.rb
|
67
72
|
- lib/rabl/builder.rb
|
68
73
|
- lib/rabl/engine.rb
|
@@ -75,6 +80,7 @@ files:
|
|
75
80
|
- test/engine_test.rb
|
76
81
|
- test/template_test.rb
|
77
82
|
- test/teststrap.rb
|
83
|
+
has_rdoc: true
|
78
84
|
homepage: https://github.com/nesquena/rabl
|
79
85
|
licenses: []
|
80
86
|
|
@@ -104,7 +110,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
104
110
|
requirements: []
|
105
111
|
|
106
112
|
rubyforge_project: rabl
|
107
|
-
rubygems_version: 1.7
|
113
|
+
rubygems_version: 1.3.7
|
108
114
|
signing_key:
|
109
115
|
specification_version: 3
|
110
116
|
summary: General ruby templating for json or xml
|