sinatra-backbone 0.1.0.rc1
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/.gitignore +1 -0
- data/HISTORY.md +4 -0
- data/README.md +47 -0
- data/Rakefile +31 -0
- data/lib/sinatra/backbone.rb +11 -0
- data/lib/sinatra/jstpages.rb +196 -0
- data/lib/sinatra/restapi.rb +202 -0
- data/sinatra-backbone.gemspec +18 -0
- data/test/app/views/chrome.jst.tpl +1 -0
- data/test/app/views/editor/edit.jst.jade +2 -0
- data/test/app_test.rb +50 -0
- data/test/jst_test.rb +26 -0
- data/test/test_helper.rb +17 -0
- data/test/to_json_test.rb +44 -0
- metadata +116 -0
data/.gitignore
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
/doc
|
data/HISTORY.md
ADDED
data/README.md
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
# Sinatra-backbone
|
2
|
+
#### Neat integration of Backbone.js with Sinatra
|
3
|
+
|
4
|
+
Do you like [Backbone.js][bb]? Do you like [Sinatra][sn]? Did you ever wish you
|
5
|
+
can use them together? Well now you can, with the new Sinatra Backbone!
|
6
|
+
|
7
|
+
[bb]: http://documentcloud.github.com/backbone/
|
8
|
+
[sn]: http://sinatrarb.com
|
9
|
+
|
10
|
+
#### Usage
|
11
|
+
|
12
|
+
This is a Ruby gem.
|
13
|
+
`$ gem install sinatra-backbone --pre`
|
14
|
+
|
15
|
+
Or do you use Bundler?
|
16
|
+
`gem 'sinatra-backbone', :require => 'sinatra/backbone'`
|
17
|
+
|
18
|
+
Contents
|
19
|
+
--------
|
20
|
+
|
21
|
+
__Sinatra-backbone__ is comprised of two Sinatra plugins:
|
22
|
+
|
23
|
+
* `Sinatra::JstPages` – Provides support for JavaScript server templates (JST)
|
24
|
+
for use in Backbone views.
|
25
|
+
|
26
|
+
* `Sinatra::RestAPI` – Provides restful API for your models for use in Backbone
|
27
|
+
models.
|
28
|
+
|
29
|
+
For usage and API reference, please see http://ricostacruz.com/sinatra-backbone. [](#api_reference)
|
30
|
+
|
31
|
+
Acknowledgements
|
32
|
+
----------------
|
33
|
+
|
34
|
+
© 2011, Rico Sta. Cruz. Released under the [MIT
|
35
|
+
License](http://www.opensource.org/licenses/mit-license.php).
|
36
|
+
|
37
|
+
Sinatra-Backbone is authored and maintained by [Rico Sta. Cruz][rsc] with help
|
38
|
+
from it's [contributors][c]. It is sponsored by my startup, [Sinefunc, Inc][sf].
|
39
|
+
|
40
|
+
* [My website](http://ricostacruz.com) (ricostacruz.com)
|
41
|
+
* [Sinefunc, Inc.](http://sinefunc.com) (sinefunc.com)
|
42
|
+
* [Github](http://github.com/rstacruz) (@rstacruz)
|
43
|
+
* [Twitter](http://twitter.com/rstacruz) (@rstacruz)
|
44
|
+
|
45
|
+
[rsc]: http://ricostacruz.com
|
46
|
+
[c]: http://github.com/rstacruz/xxxxx
|
47
|
+
[sf]: http://sinefunc.com
|
data/Rakefile
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
desc "Invokes the test suite in multiple RVM environments"
|
2
|
+
task :'test!' do
|
3
|
+
# Override this by adding RVM_TEST_ENVS=".." in .rvmrc
|
4
|
+
envs = ENV['RVM_TEST_ENVS'] || '1.9.2@sinatra,1.8.7@sinatra'
|
5
|
+
puts "* Testing in the following RVM environments: #{envs.gsub(',', ', ')}"
|
6
|
+
system "rvm #{envs} rake test" or abort
|
7
|
+
end
|
8
|
+
|
9
|
+
desc "Runs tests"
|
10
|
+
task :test do
|
11
|
+
Dir['test/*_test.rb'].each { |f| load f }
|
12
|
+
end
|
13
|
+
|
14
|
+
task :default => :test
|
15
|
+
|
16
|
+
repo = ENV['GITHUB_REPO'] || 'rstacruz/sinatra-backbone'
|
17
|
+
namespace :doc do
|
18
|
+
desc "Builds documentation"
|
19
|
+
task :build do
|
20
|
+
# github.com/rstacruz/reacco
|
21
|
+
system "reacco -a --api lib --github #{repo}"
|
22
|
+
end
|
23
|
+
|
24
|
+
desc "Uploads documentation"
|
25
|
+
task :deploy => :build do
|
26
|
+
# github.com/rstacruz/git-update-ghpages
|
27
|
+
system "git update-ghpages -i doc #{repo}"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
task :doc => :'doc:build'
|
@@ -0,0 +1,196 @@
|
|
1
|
+
# ## Sinatra::JstPages [module]
|
2
|
+
# A Sinatra plugin that adds support for JST (JavaScript Server Templates).
|
3
|
+
#
|
4
|
+
# #### Basic usage
|
5
|
+
# Register the `Sinatra::JstPages` plugin in your application, and use
|
6
|
+
# `serve_jst`. This example serves all JST files found in `/views/**/*.jst.*`
|
7
|
+
# (where `/views` is your views directory as defined in Sinatra's
|
8
|
+
# `settings.views`) as `http://localhost:4567/jst.js`.
|
9
|
+
#
|
10
|
+
# require 'sinatra/jstpages'
|
11
|
+
#
|
12
|
+
# class App < Sinatra::Base
|
13
|
+
# register Sinatra::JstPages
|
14
|
+
# serve_jst '/jst.js'
|
15
|
+
# end
|
16
|
+
#
|
17
|
+
# You will need to link to the JST route in your layout. Make a `<script>` tag
|
18
|
+
# where the `src='...'` attribute is the same path you provide to `serve_jst`.
|
19
|
+
#
|
20
|
+
# <script type='text/javascript' src='/jst.js'></script>
|
21
|
+
#
|
22
|
+
# So, if you have a JST view written in Jade, placed in `views/editor/edit.jst.jade`:
|
23
|
+
#
|
24
|
+
# # views/editor/edit.jst.jade
|
25
|
+
# h1= "Edit "+name
|
26
|
+
# form
|
27
|
+
# button Save
|
28
|
+
#
|
29
|
+
# Now in your browser you may invoke `JST['templatename']`:
|
30
|
+
#
|
31
|
+
# // Renders the editor/edit template
|
32
|
+
# JST['editor/edit']();
|
33
|
+
#
|
34
|
+
# // Renders the editor/edit template with template parameters
|
35
|
+
# JST['editor/edit']({name: 'Item Name'});
|
36
|
+
#
|
37
|
+
# #### Using Sinatra-AssetPack?
|
38
|
+
#
|
39
|
+
# __TIP:__ If you're using the [sinatra-assetpack][sap] gem, just add `/jst.js`
|
40
|
+
# to a package. (If you're not using Sinatra AssetPack yet, you probably
|
41
|
+
# should.)
|
42
|
+
#
|
43
|
+
# [sap]: http://ricostacruz.com/sinatra-assetpack
|
44
|
+
#
|
45
|
+
# #### Supported templates
|
46
|
+
# Currently supports the following templates:
|
47
|
+
#
|
48
|
+
# * [Jade][jade] (`.jst.jade`) -- Jade templates. This requires
|
49
|
+
# [jade.js][jade]. For older browsers, you will also need [json2.js][json2],
|
50
|
+
# and an implementation of [String.prototype.trim][trim].
|
51
|
+
#
|
52
|
+
# * [Underscore templates][under_tpl] (`.jst.tpl`) -- Simple templates by
|
53
|
+
# underscore. This requires [underscore.js][under], which Backbone also
|
54
|
+
# requires.
|
55
|
+
#
|
56
|
+
# * [Haml.js][haml] (`.jst.haml`) -- A JavaScript implementation of Haml.
|
57
|
+
# Requires [haml.js][haml].
|
58
|
+
#
|
59
|
+
# * [Eco][eco] (`.jst.eco`) -- Embedded CoffeeScript templates. Requires
|
60
|
+
# [eco.js][eco] and [coffee-script.js][cs].
|
61
|
+
#
|
62
|
+
# [jade]: http://github.com/visionmedia/jade
|
63
|
+
# [json2]: https://github.com/douglascrockford/JSON-js
|
64
|
+
# [trim]: http://snippets.dzone.com/posts/show/701
|
65
|
+
# [under_tpl]: http://documentcloud.github.com/underscore/#template
|
66
|
+
# [under]: http://documentcloud.github.com/underscore
|
67
|
+
# [haml]: https://github.com/creationix/haml-js
|
68
|
+
# [eco]: https://github.com/sstephenson/eco
|
69
|
+
# [cs]: http://coffeescript.org
|
70
|
+
#
|
71
|
+
module Sinatra
|
72
|
+
module JstPages
|
73
|
+
def self.registered(app)
|
74
|
+
app.extend ClassMethods
|
75
|
+
app.helpers Helpers
|
76
|
+
end
|
77
|
+
|
78
|
+
# Returns a hash to determine which engine is mapped onto a given extension.
|
79
|
+
def self.mappings
|
80
|
+
@mappings ||= Hash.new
|
81
|
+
end
|
82
|
+
|
83
|
+
def self.register(ext, engine)
|
84
|
+
mappings[ext] = engine
|
85
|
+
end
|
86
|
+
|
87
|
+
module Helpers
|
88
|
+
# Returns a list of JST files.
|
89
|
+
def jst_files
|
90
|
+
# Tuples of [ name, Engine instance ]
|
91
|
+
tuples = Dir.chdir(settings.views) {
|
92
|
+
Dir["**/*.jst.*"].map { |fn|
|
93
|
+
fn =~ %r{^(.*)\.jst\.([^\.]+)$}
|
94
|
+
name, ext = $1, $2
|
95
|
+
engine = JstPages.mappings[ext]
|
96
|
+
|
97
|
+
[ name, engine.new(File.join(settings.views, fn)) ] if engine
|
98
|
+
}.compact
|
99
|
+
}
|
100
|
+
|
101
|
+
Hash[*tuples.flatten]
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
module ClassMethods
|
106
|
+
# ### serve_jst(path, [options]) [class method]
|
107
|
+
# Serves JST files in given `path`.
|
108
|
+
#
|
109
|
+
def serve_jst(path, options={})
|
110
|
+
get path do
|
111
|
+
content_type :js
|
112
|
+
jsts = jst_files.map { |(name, engine)|
|
113
|
+
%{
|
114
|
+
JST[#{name.inspect}] = function() {
|
115
|
+
if (!c[#{name.inspect}]) c[#{name.inspect}] = (#{engine.function});
|
116
|
+
return c[#{name.inspect}].apply(this, arguments);
|
117
|
+
};
|
118
|
+
}.strip.gsub(/^ {12}/, '')
|
119
|
+
}
|
120
|
+
|
121
|
+
%{
|
122
|
+
(function(){
|
123
|
+
var c = {};
|
124
|
+
if (!window.JST) window.JST = {};
|
125
|
+
#{jsts.join("\n ")}
|
126
|
+
})();
|
127
|
+
}.strip.gsub(/^ {12}/, '')
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
|
135
|
+
# ## Sinatra::JstPages::Engine [class]
|
136
|
+
# A template engine.
|
137
|
+
#
|
138
|
+
# #### Adding support for new template engines
|
139
|
+
# You will need to subclass `Engine`, override at least the `function` method,
|
140
|
+
# then use `JstPages.register`.
|
141
|
+
#
|
142
|
+
# This example will register `.jst.my` files to a new engine that uses
|
143
|
+
# `My.compile`.
|
144
|
+
#
|
145
|
+
# module Sinatra::JstPages
|
146
|
+
# class MyEngine < Engine
|
147
|
+
# def function() "My.compile(%s)"; end
|
148
|
+
# end
|
149
|
+
#
|
150
|
+
# register 'my', MyEngine
|
151
|
+
# end
|
152
|
+
#
|
153
|
+
module Sinatra::JstPages
|
154
|
+
class Engine
|
155
|
+
# ### file [attribute]
|
156
|
+
# The string path of the template file.
|
157
|
+
attr_reader :file
|
158
|
+
def initialize(file)
|
159
|
+
@file = file
|
160
|
+
end
|
161
|
+
|
162
|
+
# ### contents [method]
|
163
|
+
# Returns the contents of the template file as a string.
|
164
|
+
def contents
|
165
|
+
File.read(@file)
|
166
|
+
end
|
167
|
+
|
168
|
+
# ### function [method]
|
169
|
+
# The JavaScript function to invoke on the precompile'd object.
|
170
|
+
#
|
171
|
+
# What this returns should, in JavaScript, return a function that can be
|
172
|
+
# called with an object hash of the params to be passed onto the template.
|
173
|
+
def function
|
174
|
+
"_.template(#{contents.inspect})"
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
class HamlEngine < Engine
|
179
|
+
def function() "Haml.compile(#{contents.inspect})"; end
|
180
|
+
end
|
181
|
+
|
182
|
+
class JadeEngine < Engine
|
183
|
+
def function() "require('jade').compile(#{contents.inspect})"; end
|
184
|
+
end
|
185
|
+
|
186
|
+
class EcoEngine < Engine
|
187
|
+
def function
|
188
|
+
"function() { var a = arguments.slice(); a.unshift(#{contents.inspect}); return eco.compile.apply(eco, a); }"
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
register 'tpl', Engine
|
193
|
+
register 'jade', JadeEngine
|
194
|
+
register 'haml', HamlEngine
|
195
|
+
register 'eco', EcoEngine
|
196
|
+
end
|
@@ -0,0 +1,202 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
3
|
+
# ## Sinatra::RestAPI [module]
|
4
|
+
# A plugin for providing rest API to models. Great for Backbone.js.
|
5
|
+
#
|
6
|
+
# To use this, simply `register` it to your Sinatra Application. You can then
|
7
|
+
# use `rest_create` and `rest_resource` to create your routes.
|
8
|
+
#
|
9
|
+
# require 'sinatra/restapi'
|
10
|
+
#
|
11
|
+
# class App < Sinatra::Base
|
12
|
+
# register Sinatra::RestAPI
|
13
|
+
# end
|
14
|
+
#
|
15
|
+
module Sinatra::RestAPI
|
16
|
+
def self.registered(app)
|
17
|
+
app.helpers Helpers
|
18
|
+
end
|
19
|
+
|
20
|
+
# ### rest_create(path, &block) [method]
|
21
|
+
# Creates a *create* route on the given `path`.
|
22
|
+
#
|
23
|
+
# This creates a `POST` route in */documents* that accepts JSON data.
|
24
|
+
# This route will return the created object as JSON.
|
25
|
+
#
|
26
|
+
# When getting a request, it does the following:
|
27
|
+
#
|
28
|
+
# * A new object is created by *yielding* the block you give. (Let's
|
29
|
+
# call it `object`.)
|
30
|
+
#
|
31
|
+
# * For each of the attributes, it uses the `attrib_name=` method in
|
32
|
+
# your record. For instance, for an attrib like `title`, it wil lbe
|
33
|
+
# calling `object.title = "hello"`.
|
34
|
+
#
|
35
|
+
# * `object.save` will be called.
|
36
|
+
#
|
37
|
+
# * `object`'s contents will then be returned to the client as JSON.
|
38
|
+
#
|
39
|
+
# See the example.
|
40
|
+
#
|
41
|
+
# class App < Sinatra::Base
|
42
|
+
# rest_create "/documents" do
|
43
|
+
# Document.new
|
44
|
+
# end
|
45
|
+
# end
|
46
|
+
#
|
47
|
+
def rest_create(path, options={}, &blk)
|
48
|
+
# Create
|
49
|
+
post path do
|
50
|
+
@object = yield
|
51
|
+
rest_params.each { |k, v| @object.send :"#{k}=", v }
|
52
|
+
@object.save
|
53
|
+
rest_respond @object.to_hash
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
# ### rest_resource(path, &block) [method]
|
58
|
+
# Creates a *get*, *edit* and *delete* route on the given `path`.
|
59
|
+
#
|
60
|
+
# The block given will be yielded to do a record lookup. If the block returns
|
61
|
+
# `nil`, RestAPI will return a *404*.
|
62
|
+
#
|
63
|
+
# In the example, it creates routes for `/document/:id` to accept HTTP *GET*
|
64
|
+
# (for object retrieval), *PUT* (for editing), and *DELETE* (for destroying).
|
65
|
+
#
|
66
|
+
# Your model needs to implement the following methods:
|
67
|
+
#
|
68
|
+
# * `save` (called on edit)
|
69
|
+
# * `destroy` (called on delete)
|
70
|
+
# * `<attrib_name_here>=` (called for each of the attributes on edit)
|
71
|
+
#
|
72
|
+
# If you only want to create routes for only one or two of the actions, you
|
73
|
+
# may individually use:
|
74
|
+
#
|
75
|
+
# * `rest_get`
|
76
|
+
# * `rest_edit`
|
77
|
+
# * `rest_delete`
|
78
|
+
#
|
79
|
+
# All the methods above take the same arguments as `rest_resource`.
|
80
|
+
#
|
81
|
+
# class App < Sinatra::Base
|
82
|
+
# rest_resource "/document/:id" do
|
83
|
+
# Document.find(id)
|
84
|
+
# end
|
85
|
+
# end
|
86
|
+
#
|
87
|
+
def rest_resource(path, options={}, &blk)
|
88
|
+
rest_get path, options, &blk
|
89
|
+
rest_edit path, options, &blk
|
90
|
+
rest_delete path, options, &blk
|
91
|
+
end
|
92
|
+
|
93
|
+
# ### rest_get(path, &block) [method]
|
94
|
+
# This is the same as `rest_resource`, but only handles *GET* requests.
|
95
|
+
#
|
96
|
+
def rest_get(path, options={}, &blk)
|
97
|
+
get path do |id|
|
98
|
+
@object = yield(id) or pass
|
99
|
+
rest_respond @object
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
# ### rest_edit(path, &block) [method]
|
104
|
+
# This is the same as `rest_resource`, but only handles *PUT*/*POST* (edit)
|
105
|
+
# requests.
|
106
|
+
#
|
107
|
+
def rest_edit(path, options={}, &blk)
|
108
|
+
callback = Proc.new { |id|
|
109
|
+
@object = yield(id) or pass
|
110
|
+
rest_params.each { |k, v| @object.send :"#{k}=", v unless k == 'id' }
|
111
|
+
@object.save
|
112
|
+
rest_respond @object
|
113
|
+
}
|
114
|
+
|
115
|
+
# Make it work with `Backbone.emulateHTTP` on.
|
116
|
+
put path, &callback
|
117
|
+
post path, &callback
|
118
|
+
end
|
119
|
+
|
120
|
+
# ### rest_delete(path, &block) [method]
|
121
|
+
# This is the same as `rest_resource`, but only handles *DELETE* (edit)
|
122
|
+
# requests. This uses `Model#destroy` on your model.
|
123
|
+
#
|
124
|
+
def rest_delete(path, options={}, &blk)
|
125
|
+
delete path do |id|
|
126
|
+
@object = yield(id) or pass
|
127
|
+
@object.destroy
|
128
|
+
rest_respond :result => :success
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
# ### JSON conversion
|
133
|
+
#
|
134
|
+
# The *create* and *get* routes all need to return objects as JSON. RestAPI
|
135
|
+
# attempts to convert your model instances to JSON by first trying
|
136
|
+
# `object.to_json` on it, then trying `object.to_hash.to_json`.
|
137
|
+
#
|
138
|
+
# It's recommended you implement `#to_hash` in your models.
|
139
|
+
|
140
|
+
# ### Helper methods
|
141
|
+
# There are some helper methods that are used internally be `RestAPI`,
|
142
|
+
# but you can use them too if you need them.
|
143
|
+
#
|
144
|
+
module Helpers
|
145
|
+
# #### rest_respond(object)
|
146
|
+
# Responds with a request with the given `object`.
|
147
|
+
#
|
148
|
+
# This will convert that object to either JSON or XML as needed, depending
|
149
|
+
# on the client's preferred type (dictated by the HTTP *Accepts* header).
|
150
|
+
#
|
151
|
+
def rest_respond(obj)
|
152
|
+
case request.preferred_type('*/json', '*/xml')
|
153
|
+
when '*/json'
|
154
|
+
content_type :json
|
155
|
+
rest_convert_to_json obj
|
156
|
+
|
157
|
+
else
|
158
|
+
pass
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
# #### rest_params
|
163
|
+
# Returns the object from the request.
|
164
|
+
#
|
165
|
+
# If the client sent `application/json` (or `text/json`) as the content
|
166
|
+
# type, it tries to parse the request body as JSON.
|
167
|
+
#
|
168
|
+
# If the client sent a standard URL-encoded POST with a `model` key
|
169
|
+
# (happens when Backbone uses `Backbone.emulateJSON = true`), it tries
|
170
|
+
# to parse it's key as JSON.
|
171
|
+
#
|
172
|
+
# Otherwise, the params will be returned as is.
|
173
|
+
#
|
174
|
+
def rest_params
|
175
|
+
if File.fnmatch('*/json', request.content_type)
|
176
|
+
JSON.parse request.body.read
|
177
|
+
|
178
|
+
elsif params['model']
|
179
|
+
# Account for Backbone.emulateJSON.
|
180
|
+
JSON.parse params['model']
|
181
|
+
|
182
|
+
else
|
183
|
+
params
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
def rest_convert_to_json(obj)
|
188
|
+
# Convert to JSON. This will almost always work as the JSON lib adds
|
189
|
+
# #to_json to everything.
|
190
|
+
json = obj.to_json
|
191
|
+
|
192
|
+
# The default to_json of objects is to JSONify the #to_s of an object,
|
193
|
+
# which defaults to #inspect. We don't want that.
|
194
|
+
return json unless json[0..2] == '"#<'
|
195
|
+
|
196
|
+
# Let's hope they redefined to_hash.
|
197
|
+
return obj.to_hash.to_json if obj.respond_to?(:to_hash)
|
198
|
+
|
199
|
+
raise "Can't convert object to JSON"
|
200
|
+
end
|
201
|
+
end
|
202
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require './lib/sinatra/backbone'
|
2
|
+
Gem::Specification.new do |s|
|
3
|
+
s.name = "sinatra-backbone"
|
4
|
+
s.version = Sinatra::Backbone.version
|
5
|
+
s.summary = "Helpful stuff using Sinatra with Backbone."
|
6
|
+
s.description = "Provides Rest API access to your models and serves JST pages."
|
7
|
+
s.authors = ["Rico Sta. Cruz"]
|
8
|
+
s.email = ["rico@sinefunc.com"]
|
9
|
+
s.homepage = "http://github.com/rstacruz/sinatra-backbone"
|
10
|
+
s.files = `git ls-files`.strip.split("\n")
|
11
|
+
s.executables = Dir["bin/*"].map { |f| File.basename(f) }
|
12
|
+
|
13
|
+
s.add_dependency "sinatra"
|
14
|
+
s.add_development_dependency "sequel", ">= 3.25.0"
|
15
|
+
s.add_development_dependency "sqlite3", ">= 1.3.4"
|
16
|
+
s.add_development_dependency "contest"
|
17
|
+
s.add_development_dependency "rack-test"
|
18
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
<%= chrome %>
|
data/test/app_test.rb
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
require File.expand_path('../test_helper', __FILE__)
|
2
|
+
|
3
|
+
DB.create_table :books do
|
4
|
+
primary_key :id
|
5
|
+
String :name
|
6
|
+
String :author
|
7
|
+
end
|
8
|
+
|
9
|
+
class Book < Sequel::Model
|
10
|
+
def to_hash
|
11
|
+
{ :name => name, :author => author }
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
class AppTest < UnitTest
|
16
|
+
class App < Sinatra::Base
|
17
|
+
register Sinatra::RestAPI
|
18
|
+
disable :show_exceptions
|
19
|
+
enable :raise_errors
|
20
|
+
rest_resource("/book/:id") { |id| Book[id] }
|
21
|
+
end
|
22
|
+
def app() App; end
|
23
|
+
|
24
|
+
describe "Sinatra::RestAPI" do
|
25
|
+
setup do
|
26
|
+
@book = Book.new
|
27
|
+
@book.name = "Darkly Dreaming Dexter"
|
28
|
+
@book.author = "Jeff Lindsay"
|
29
|
+
@book.save
|
30
|
+
header 'Accept', 'application/json, */*'
|
31
|
+
end
|
32
|
+
|
33
|
+
teardown do
|
34
|
+
@book.destroy if Book[@book.id]
|
35
|
+
end
|
36
|
+
|
37
|
+
test "should work properly" do
|
38
|
+
get "/book/#{@book.id}"
|
39
|
+
|
40
|
+
assert json_response['name'] == @book.name
|
41
|
+
assert json_response['author'] == @book.author
|
42
|
+
end
|
43
|
+
|
44
|
+
test "should 404" do
|
45
|
+
get "/book/823978"
|
46
|
+
|
47
|
+
assert last_response.status == 404
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
data/test/jst_test.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
require File.expand_path('../test_helper', __FILE__)
|
2
|
+
|
3
|
+
class JstTest < UnitTest
|
4
|
+
class App < Sinatra::Base
|
5
|
+
register Sinatra::JstPages
|
6
|
+
disable :show_exceptions
|
7
|
+
enable :raise_errors
|
8
|
+
|
9
|
+
set :views, File.expand_path('../app/views', __FILE__)
|
10
|
+
serve_jst '/jst.js'
|
11
|
+
end
|
12
|
+
def app() App; end
|
13
|
+
|
14
|
+
test "jst" do
|
15
|
+
get '/jst.js'
|
16
|
+
body = last_response.body
|
17
|
+
|
18
|
+
assert body.include? 'window.JST'
|
19
|
+
|
20
|
+
assert body.include? '["editor/edit"]'
|
21
|
+
assert body.include? "Hello"
|
22
|
+
|
23
|
+
assert body.include? '["chrome"]'
|
24
|
+
assert body.include? "chrome"
|
25
|
+
end
|
26
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
$:.unshift File.expand_path('../../lib', __FILE__)
|
2
|
+
require 'contest'
|
3
|
+
require 'sinatra/base'
|
4
|
+
require 'sequel'
|
5
|
+
require 'rack/test'
|
6
|
+
require 'json'
|
7
|
+
require 'sinatra/backbone'
|
8
|
+
|
9
|
+
class UnitTest < Test::Unit::TestCase
|
10
|
+
include Rack::Test::Methods
|
11
|
+
|
12
|
+
def json_response
|
13
|
+
JSON.parse last_response.body
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
DB = Sequel.connect('sqlite::memory:')
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require File.expand_path('../test_helper', __FILE__)
|
2
|
+
|
3
|
+
DB.create_table :albums do
|
4
|
+
primary_key :id
|
5
|
+
String :title
|
6
|
+
String :artist
|
7
|
+
end
|
8
|
+
|
9
|
+
class Album < Sequel::Model
|
10
|
+
def to_json
|
11
|
+
"X"
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_hash
|
15
|
+
{ :name => name, :author => author }
|
16
|
+
end
|
17
|
+
|
18
|
+
def to_xml
|
19
|
+
"lol"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
class ToJsonTest < UnitTest
|
24
|
+
class App < Sinatra::Base
|
25
|
+
register Sinatra::RestAPI
|
26
|
+
disable :show_exceptions
|
27
|
+
enable :raise_errors
|
28
|
+
rest_resource("/album/:id") { |id| Album[id] }
|
29
|
+
end
|
30
|
+
def app() App; end
|
31
|
+
|
32
|
+
setup do
|
33
|
+
@album = Album.new
|
34
|
+
@album.title = "Tanto Tempo"
|
35
|
+
@album.artist = "Bebel Gilberto"
|
36
|
+
@album.save
|
37
|
+
header 'Accept', 'application/json, */*'
|
38
|
+
end
|
39
|
+
|
40
|
+
test "use to_json" do
|
41
|
+
get "/album/#{@album.id}"
|
42
|
+
assert last_response.body == @album.to_json
|
43
|
+
end
|
44
|
+
end
|
metadata
ADDED
@@ -0,0 +1,116 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: sinatra-backbone
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0.rc1
|
5
|
+
prerelease: 6
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Rico Sta. Cruz
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2011-09-12 00:00:00.000000000 +08:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: sinatra
|
17
|
+
requirement: &2161564340 !ruby/object:Gem::Requirement
|
18
|
+
none: false
|
19
|
+
requirements:
|
20
|
+
- - ! '>='
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: '0'
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: *2161564340
|
26
|
+
- !ruby/object:Gem::Dependency
|
27
|
+
name: sequel
|
28
|
+
requirement: &2161563580 !ruby/object:Gem::Requirement
|
29
|
+
none: false
|
30
|
+
requirements:
|
31
|
+
- - ! '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 3.25.0
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: *2161563580
|
37
|
+
- !ruby/object:Gem::Dependency
|
38
|
+
name: sqlite3
|
39
|
+
requirement: &2161562920 !ruby/object:Gem::Requirement
|
40
|
+
none: false
|
41
|
+
requirements:
|
42
|
+
- - ! '>='
|
43
|
+
- !ruby/object:Gem::Version
|
44
|
+
version: 1.3.4
|
45
|
+
type: :development
|
46
|
+
prerelease: false
|
47
|
+
version_requirements: *2161562920
|
48
|
+
- !ruby/object:Gem::Dependency
|
49
|
+
name: contest
|
50
|
+
requirement: &2161562440 !ruby/object:Gem::Requirement
|
51
|
+
none: false
|
52
|
+
requirements:
|
53
|
+
- - ! '>='
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: '0'
|
56
|
+
type: :development
|
57
|
+
prerelease: false
|
58
|
+
version_requirements: *2161562440
|
59
|
+
- !ruby/object:Gem::Dependency
|
60
|
+
name: rack-test
|
61
|
+
requirement: &2161561800 !ruby/object:Gem::Requirement
|
62
|
+
none: false
|
63
|
+
requirements:
|
64
|
+
- - ! '>='
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
version: '0'
|
67
|
+
type: :development
|
68
|
+
prerelease: false
|
69
|
+
version_requirements: *2161561800
|
70
|
+
description: Provides Rest API access to your models and serves JST pages.
|
71
|
+
email:
|
72
|
+
- rico@sinefunc.com
|
73
|
+
executables: []
|
74
|
+
extensions: []
|
75
|
+
extra_rdoc_files: []
|
76
|
+
files:
|
77
|
+
- .gitignore
|
78
|
+
- HISTORY.md
|
79
|
+
- README.md
|
80
|
+
- Rakefile
|
81
|
+
- lib/sinatra/backbone.rb
|
82
|
+
- lib/sinatra/jstpages.rb
|
83
|
+
- lib/sinatra/restapi.rb
|
84
|
+
- sinatra-backbone.gemspec
|
85
|
+
- test/app/views/chrome.jst.tpl
|
86
|
+
- test/app/views/editor/edit.jst.jade
|
87
|
+
- test/app_test.rb
|
88
|
+
- test/jst_test.rb
|
89
|
+
- test/test_helper.rb
|
90
|
+
- test/to_json_test.rb
|
91
|
+
has_rdoc: true
|
92
|
+
homepage: http://github.com/rstacruz/sinatra-backbone
|
93
|
+
licenses: []
|
94
|
+
post_install_message:
|
95
|
+
rdoc_options: []
|
96
|
+
require_paths:
|
97
|
+
- lib
|
98
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
99
|
+
none: false
|
100
|
+
requirements:
|
101
|
+
- - ! '>='
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - ! '>'
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: 1.3.1
|
110
|
+
requirements: []
|
111
|
+
rubyforge_project:
|
112
|
+
rubygems_version: 1.6.2
|
113
|
+
signing_key:
|
114
|
+
specification_version: 3
|
115
|
+
summary: Helpful stuff using Sinatra with Backbone.
|
116
|
+
test_files: []
|