cloudkit 0.11.1 → 0.11.2
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGES +8 -0
- data/README +1 -1
- data/TODO +1 -3
- data/cloudkit.gemspec +5 -5
- data/doc/curl.html +4 -2
- data/doc/index.html +1 -1
- data/lib/cloudkit.rb +2 -2
- data/lib/cloudkit/oauth_filter.rb +1 -1
- data/lib/cloudkit/openid_filter.rb +9 -0
- data/lib/cloudkit/rack/builder.rb +1 -1
- data/lib/cloudkit/request.rb +5 -0
- data/lib/cloudkit/service.rb +17 -8
- data/lib/cloudkit/store.rb +5 -4
- data/lib/cloudkit/store/resource.rb +3 -3
- data/lib/cloudkit/store/response_helpers.rb +18 -7
- data/lib/cloudkit/uri.rb +2 -2
- data/spec/flash_session_spec.rb +1 -1
- data/spec/openid_filter_spec.rb +2 -0
- data/spec/request_spec.rb +6 -0
- data/spec/service_spec.rb +30 -4
- data/spec/uri_spec.rb +1 -1
- metadata +8 -8
data/CHANGES
CHANGED
@@ -1,3 +1,11 @@
|
|
1
|
+
0.11.2
|
2
|
+
- Added Location header for 201s
|
3
|
+
- Fixed JSON response for DELETE operations
|
4
|
+
- Updated MD5 dependency for Ruby 1.9 (Andreas Haller)
|
5
|
+
- Updated spec setup for RSpec 1.2 (Andreas Haller)
|
6
|
+
- Updated gem dependencies for Rack, OpenID, and JSON
|
7
|
+
- Other minor fixes
|
8
|
+
|
1
9
|
0.11.1
|
2
10
|
- Added a block option for configuring OpenID bypassed routes (Devlin Daley)
|
3
11
|
- Added write locks for Tokyo Tyrant Tables
|
data/README
CHANGED
@@ -17,7 +17,7 @@ In a rackup file called config.ru:
|
|
17
17
|
require 'cloudkit'
|
18
18
|
expose :notes, :todos
|
19
19
|
|
20
|
-
The above creates a versioned HTTP service using JSON to represent two types of resource collections -- Notes and ToDos.
|
20
|
+
The above creates a versioned HTTP/REST service using JSON to represent two types of resource collections -- Notes and ToDos.
|
21
21
|
|
22
22
|
In a different rackup file:
|
23
23
|
|
data/TODO
CHANGED
@@ -2,18 +2,16 @@
|
|
2
2
|
- openid sreg
|
3
3
|
- oauth token management
|
4
4
|
- oauth consumer registration
|
5
|
-
- acls i.e. allowed methods per user per uri
|
6
|
-
- jsonpath
|
7
5
|
- jsonquery
|
8
6
|
- jsonschema
|
9
7
|
- user lookup via a block for integration with existing stores
|
10
8
|
- custom templates for openid / oauth
|
11
9
|
|
12
10
|
Backlog
|
11
|
+
- acls i.e. allowed methods per user per uri
|
13
12
|
- method filtering on collections
|
14
13
|
- js functions as observers (validation, mapping, etc.)
|
15
14
|
- complete user data export
|
16
|
-
- batch updates (post, put, delete)
|
17
15
|
- expect header/100-continue
|
18
16
|
- deployable gem + admin app
|
19
17
|
- cappuccino adapter
|
data/cloudkit.gemspec
CHANGED
@@ -2,8 +2,8 @@ Gem::Specification.new do |s|
|
|
2
2
|
s.specification_version = 2 if s.respond_to? :specification_version=
|
3
3
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
4
4
|
s.name = "cloudkit"
|
5
|
-
s.version = "0.11.
|
6
|
-
s.date = "2008-03
|
5
|
+
s.version = "0.11.2"
|
6
|
+
s.date = "2008-05-03"
|
7
7
|
s.summary = "An Open Web JSON Appliance."
|
8
8
|
s.description = "An Open Web JSON Appliance."
|
9
9
|
s.authors = ["Jon Crosby"]
|
@@ -77,9 +77,9 @@ Gem::Specification.new do |s|
|
|
77
77
|
s.test_files = s.files.select {|path| path =~ /^spec\/.*_spec.rb/}
|
78
78
|
s.rubyforge_project = "cloudkit"
|
79
79
|
s.rubygems_version = "1.1.1"
|
80
|
-
s.add_dependency 'rack', '
|
80
|
+
s.add_dependency 'rack', '>= 1.0'
|
81
81
|
s.add_dependency 'uuid', '= 2.0.1'
|
82
82
|
s.add_dependency 'oauth', '~> 0.3'
|
83
|
-
s.add_dependency 'ruby-openid', '
|
84
|
-
s.add_dependency 'json', '
|
83
|
+
s.add_dependency 'ruby-openid', '~> 2.1'
|
84
|
+
s.add_dependency 'json', '~> 1.1'
|
85
85
|
end
|
data/doc/curl.html
CHANGED
@@ -38,13 +38,13 @@ If you haven't already installed the gem:
|
|
38
38
|
</p>
|
39
39
|
|
40
40
|
<p>
|
41
|
-
If you already have the gem, make sure you're running the latest version (0.11.
|
41
|
+
If you already have the gem, make sure you're running the latest version (0.11.2):
|
42
42
|
<div class="code">
|
43
43
|
$ gem list cloudkit<br/>
|
44
44
|
cloudkit (0.10.0) <-- need to upgrade<br/>
|
45
45
|
$ gem update cloudkit<br/>
|
46
46
|
$ gem list cloudkit<br/>
|
47
|
-
cloudkit (0.11.
|
47
|
+
cloudkit (0.11.2, 0.10.0) <-- 0.11.2 is now in the list
|
48
48
|
</div>
|
49
49
|
</p>
|
50
50
|
|
@@ -120,6 +120,7 @@ Let's move on, creating a note using <a href="http://tools.ietf.org/html/rfc2616
|
|
120
120
|
$ curl -i -XPOST -d'{"title":"projects"}' http://localhost:9292/notes<br/>
|
121
121
|
HTTP/1.1 201 Created<br/>
|
122
122
|
Cache-Control: no-cache<br/>
|
123
|
+
Location: http://localhost:9292/notes/0dda06f0-b134-012b-a2d8-0017f2c62348<br/>
|
123
124
|
Content-Type: application/json<br/>
|
124
125
|
Content-Length: 159<br/><br/>
|
125
126
|
|
@@ -139,6 +140,7 @@ so that we can specify its location:
|
|
139
140
|
$ curl -i -XPUT -d'{"title":"reminders"}' http://localhost:9292/notes/abc<br/>
|
140
141
|
HTTP/1.1 201 Created<br/>
|
141
142
|
Cache-Control: no-cache<br/>
|
143
|
+
Location: http://localhost:9292/notes/abc<br/>
|
142
144
|
Content-Type: application/json<br/>
|
143
145
|
Content-Length: 126<br/><br/>
|
144
146
|
|
data/doc/index.html
CHANGED
@@ -24,7 +24,7 @@
|
|
24
24
|
</div>
|
25
25
|
<div class="meta">
|
26
26
|
<p class="wrapper">
|
27
|
-
Version 0.11.
|
27
|
+
Version 0.11.2 released with Tokyo Cabinet support. Install with <em>gem install cloudkit</em>.
|
28
28
|
</p>
|
29
29
|
</div>
|
30
30
|
<div class="wrapper intro-row">
|
data/lib/cloudkit.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'rubygems'
|
2
2
|
require 'erb'
|
3
3
|
require 'json'
|
4
|
-
require 'md5'
|
4
|
+
require 'digest/md5'
|
5
5
|
require 'openid'
|
6
6
|
require 'time'
|
7
7
|
require 'uuid'
|
@@ -34,7 +34,7 @@ require 'cloudkit/user_store'
|
|
34
34
|
include CloudKit::Constants
|
35
35
|
|
36
36
|
module CloudKit
|
37
|
-
VERSION = '0.11.
|
37
|
+
VERSION = '0.11.2'
|
38
38
|
|
39
39
|
# Sets up the storage adapter. Defaults to development-time
|
40
40
|
# CloudKit::MemoryTable. Also supports Rufus Tokyo Table instances. See the
|
@@ -6,8 +6,17 @@ module CloudKit
|
|
6
6
|
# The root URI, "/", is always bypassed. More URIs can also be bypassed using
|
7
7
|
# the :allow option:
|
8
8
|
#
|
9
|
+
# use Rack::Session::Pool
|
9
10
|
# use OpenIDFilter, :allow => ['/foo', '/bar']
|
10
11
|
#
|
12
|
+
# In addition to the :allow option, a block can also be used for more complex
|
13
|
+
# decisions:
|
14
|
+
#
|
15
|
+
# use Rack::Session::Pool
|
16
|
+
# use OpenIDFilter, :allow => ['/foo'] do |url|
|
17
|
+
# bar(url) # some method returning true or false
|
18
|
+
# end
|
19
|
+
#
|
11
20
|
# Responds to the following URIs:
|
12
21
|
# /login
|
13
22
|
# /logout
|
@@ -4,7 +4,7 @@ module Rack #:nodoc:
|
|
4
4
|
|
5
5
|
# Extends Rack::Builder's to_app method to detect if the last piece of
|
6
6
|
# middleware in the stack is a CloudKit shortcut (contain or expose), adding
|
7
|
-
#
|
7
|
+
# a default developer page at the root and a 404 everywhere else.
|
8
8
|
def to_app
|
9
9
|
default_app = lambda do |env|
|
10
10
|
if (env['PATH_INFO'] == '/')
|
data/lib/cloudkit/request.rb
CHANGED
data/lib/cloudkit/service.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
module CloudKit
|
2
2
|
|
3
3
|
# A CloudKit Service is Rack middleware providing a REST/HTTP 1.1 interface to
|
4
|
-
# a Store. Its primary purpose is initialize and adapt a Store for use in a
|
4
|
+
# a Store. Its primary purpose is to initialize and adapt a Store for use in a
|
5
5
|
# Rack middleware stack.
|
6
6
|
#
|
7
7
|
# ==Examples
|
@@ -68,18 +68,22 @@ module CloudKit
|
|
68
68
|
if tunnel_methods.include?(request['_method'].try(:upcase))
|
69
69
|
return send(request['_method'].downcase, request)
|
70
70
|
end
|
71
|
-
@store.post(
|
71
|
+
response = @store.post(
|
72
72
|
request.uri,
|
73
73
|
{:json => request.json}.filter_merge!(
|
74
|
-
:remote_user => request.current_user))
|
74
|
+
:remote_user => request.current_user))
|
75
|
+
update_location_header(request, response)
|
76
|
+
response.to_rack
|
75
77
|
end
|
76
78
|
|
77
79
|
def put(request)
|
78
|
-
@store.put(
|
80
|
+
response = @store.put(
|
79
81
|
request.uri,
|
80
82
|
{:json => request.json}.filter_merge!(
|
81
83
|
:remote_user => request.current_user,
|
82
|
-
:etag => request.if_match))
|
84
|
+
:etag => request.if_match))
|
85
|
+
update_location_header(request, response)
|
86
|
+
response.to_rack
|
83
87
|
end
|
84
88
|
|
85
89
|
def delete(request)
|
@@ -114,21 +118,26 @@ module CloudKit
|
|
114
118
|
end
|
115
119
|
|
116
120
|
def versions_link_header(request)
|
117
|
-
base_url = "#{request.
|
121
|
+
base_url = "#{request.domain_root}#{request.path_info}"
|
118
122
|
"<#{base_url}/versions>; rel=\"http://joncrosby.me/cloudkit/1.0/rel/versions\""
|
119
123
|
end
|
120
124
|
|
121
125
|
def resolved_link_header(request)
|
122
|
-
base_url = "#{request.
|
126
|
+
base_url = "#{request.domain_root}#{request.path_info}"
|
123
127
|
"<#{base_url}/_resolved>; rel=\"http://joncrosby.me/cloudkit/1.0/rel/resolved\""
|
124
128
|
end
|
125
129
|
|
126
130
|
def index_link_header(request)
|
127
131
|
index_path = request.path_info.sub(/\/_resolved(\/)*$/, '')
|
128
|
-
base_url = "#{request.
|
132
|
+
base_url = "#{request.domain_root}#{index_path}"
|
129
133
|
"<#{base_url}>; rel=\"index\""
|
130
134
|
end
|
131
135
|
|
136
|
+
def update_location_header(request, response)
|
137
|
+
return unless response['Location']
|
138
|
+
response['Location'] = "#{request.domain_root}#{response['Location']}"
|
139
|
+
end
|
140
|
+
|
132
141
|
def auth_missing?(request)
|
133
142
|
request.current_user == nil
|
134
143
|
end
|
data/lib/cloudkit/store.rb
CHANGED
@@ -117,7 +117,8 @@ module CloudKit
|
|
117
117
|
return status_412 if resource.etag != options[:etag]
|
118
118
|
|
119
119
|
resource.delete
|
120
|
-
|
120
|
+
archived_resource = resource.previous_version
|
121
|
+
return json_meta_response(archived_resource.uri.string, archived_resource.etag, resource.last_modified)
|
121
122
|
end
|
122
123
|
|
123
124
|
# Build a response containing the allowed methods for a given URI.
|
@@ -276,7 +277,7 @@ module CloudKit
|
|
276
277
|
def create_resource(uri, options)
|
277
278
|
JSON.parse(options[:json]) rescue (return status_422)
|
278
279
|
resource = CloudKit::Resource.create(uri, options[:json], options[:remote_user])
|
279
|
-
|
280
|
+
json_create_response(resource.uri.string, resource.etag, resource.last_modified)
|
280
281
|
end
|
281
282
|
|
282
283
|
# Update the resource at the specified URI. Requires the :etag option.
|
@@ -288,7 +289,7 @@ module CloudKit
|
|
288
289
|
return etag_required unless options[:etag]
|
289
290
|
return status_412 unless options[:etag] == resource.etag
|
290
291
|
resource.update(options[:json])
|
291
|
-
return json_meta_response(
|
292
|
+
return json_meta_response(uri.string, resource.etag, resource.last_modified)
|
292
293
|
end
|
293
294
|
|
294
295
|
# Bundle a collection of results as a list of URIs for the response.
|
@@ -337,7 +338,7 @@ module CloudKit
|
|
337
338
|
# optimization for GETs. This method is used for collections of resources
|
338
339
|
# where the optimization is not practical.
|
339
340
|
def build_etag(data)
|
340
|
-
MD5
|
341
|
+
Digest::MD5.hexdigest(data.to_s)
|
341
342
|
end
|
342
343
|
|
343
344
|
# Returns true if the collection type is valid for this Store.
|
@@ -1,8 +1,8 @@
|
|
1
1
|
module CloudKit
|
2
2
|
|
3
3
|
# A CloudKit::Resource represents a "resource" in the REST/HTTP sense of the
|
4
|
-
# word. It encapsulates a JSON document and its metadata such as
|
5
|
-
# Last-Modified date, remote user, and
|
4
|
+
# word. It encapsulates a JSON document and its metadata such as its URI, ETag,
|
5
|
+
# Last-Modified date, remote user, and historical versions.
|
6
6
|
class Resource
|
7
7
|
|
8
8
|
attr_reader :uri, :etag, :last_modified, :json, :remote_user
|
@@ -60,7 +60,7 @@ module CloudKit
|
|
60
60
|
end
|
61
61
|
|
62
62
|
# Delete the given resource. This is a soft delete, archiving the previous
|
63
|
-
# resource and
|
63
|
+
# resource and inserting a deleted resource placeholder at the old URI.
|
64
64
|
# Raises HistoricalIntegrityViolation for attempts to delete resources that
|
65
65
|
# are not current.
|
66
66
|
def delete
|
@@ -46,21 +46,32 @@ module CloudKit::ResponseHelpers
|
|
46
46
|
|
47
47
|
def response(status, content='', etag=nil, last_modified=nil, options={})
|
48
48
|
cache_control = options[:cache] == false ? 'no-cache' : 'proxy-revalidate'
|
49
|
-
|
49
|
+
etag = "\"#{etag}\"" if etag
|
50
|
+
headers = {}.filter_merge!(
|
50
51
|
'Content-Type' => 'application/json',
|
51
|
-
'Cache-Control' => cache_control
|
52
|
-
|
53
|
-
|
52
|
+
'Cache-Control' => cache_control,
|
53
|
+
'Last-Modified' => last_modified,
|
54
|
+
'Location' => options[:location],
|
55
|
+
'ETag' => etag)
|
54
56
|
CloudKit::Response.new(status, headers, content)
|
55
57
|
end
|
56
58
|
|
57
|
-
def json_meta_response(
|
58
|
-
json =
|
59
|
+
def json_meta_response(uri, etag, last_modified)
|
60
|
+
json = json_metadata(uri, etag, last_modified)
|
61
|
+
response(200, json, nil, nil, :cache => false)
|
62
|
+
end
|
63
|
+
|
64
|
+
def json_create_response(uri, etag, last_modified)
|
65
|
+
json = json_metadata(uri, etag, last_modified)
|
66
|
+
response(201, json, nil, nil, {:cache => false, :location => uri})
|
67
|
+
end
|
68
|
+
|
69
|
+
def json_metadata(uri, etag, last_modified)
|
70
|
+
JSON.generate(
|
59
71
|
:ok => true,
|
60
72
|
:uri => uri,
|
61
73
|
:etag => etag,
|
62
74
|
:last_modified => last_modified)
|
63
|
-
response(status, json, nil, nil, :cache => false)
|
64
75
|
end
|
65
76
|
|
66
77
|
def json_error(message)
|
data/lib/cloudkit/uri.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
module CloudKit
|
2
2
|
|
3
|
-
# A CloudKit::URI wraps a URI string,
|
3
|
+
# A CloudKit::URI wraps a URI string, adding methods useful for routing
|
4
4
|
# in CloudKit as well as caching URI components for future comparisons.
|
5
5
|
class URI
|
6
6
|
|
@@ -42,7 +42,7 @@ module CloudKit
|
|
42
42
|
|
43
43
|
# Returns true if URI matches /{collection}
|
44
44
|
def resource_collection_uri?
|
45
|
-
return components.size == 1
|
45
|
+
return components.size == 1 && components[0] != 'cloudkit-meta'
|
46
46
|
end
|
47
47
|
|
48
48
|
# Returns true if URI matches /{collection}/_resolved
|
data/spec/flash_session_spec.rb
CHANGED
data/spec/openid_filter_spec.rb
CHANGED
@@ -34,6 +34,8 @@ describe "An OpenIDFilter" do
|
|
34
34
|
request = Rack::MockRequest.new(openid_app)
|
35
35
|
response = request.get('/bar')
|
36
36
|
response.status.should == 200
|
37
|
+
response = request.get('/foo')
|
38
|
+
response.status.should == 200
|
37
39
|
end
|
38
40
|
|
39
41
|
it "should redirect to the login page if authorization is required" do
|
data/spec/request_spec.rb
CHANGED
@@ -182,4 +182,10 @@ describe "A Request" do
|
|
182
182
|
request.last_path_element.should == 'def'
|
183
183
|
end
|
184
184
|
|
185
|
+
it "should know its domain root" do
|
186
|
+
request = CloudKit::Request.new(Rack::MockRequest.env_for(
|
187
|
+
'/', 'HTTP_HOST' => 'example.com'))
|
188
|
+
request.domain_root.should == "http://example.com"
|
189
|
+
end
|
190
|
+
|
185
191
|
end
|
data/spec/service_spec.rb
CHANGED
@@ -570,7 +570,7 @@ describe "A CloudKit::Service" do
|
|
570
570
|
before(:each) do
|
571
571
|
json = JSON.generate(:this => 'that')
|
572
572
|
@response = @request.post(
|
573
|
-
'/items', {:input => json}.merge(VALID_TEST_AUTH))
|
573
|
+
'/items', {:input => json, 'HTTP_HOST' => 'example.org'}.merge(VALID_TEST_AUTH))
|
574
574
|
@body = JSON.parse(@response.body)
|
575
575
|
end
|
576
576
|
|
@@ -600,6 +600,10 @@ describe "A CloudKit::Service" do
|
|
600
600
|
@response['Last-Modified'].should be_nil
|
601
601
|
end
|
602
602
|
|
603
|
+
it "should return a Location header" do
|
604
|
+
@response['Location'].should match(/http:\/\/example.org#{@body['uri']}/)
|
605
|
+
end
|
606
|
+
|
603
607
|
it "should return a 422 if parsing fails" do
|
604
608
|
response = @request.post('/items', {:input => 'fail'}.merge(VALID_TEST_AUTH))
|
605
609
|
response.status.should == 422
|
@@ -607,7 +611,7 @@ describe "A CloudKit::Service" do
|
|
607
611
|
|
608
612
|
end
|
609
613
|
|
610
|
-
describe "on PUT /:collection/:id" do
|
614
|
+
describe "on PUT /:collection/:id" do
|
611
615
|
|
612
616
|
before(:each) do
|
613
617
|
json = JSON.generate(:this => 'that')
|
@@ -626,11 +630,15 @@ describe "A CloudKit::Service" do
|
|
626
630
|
it "should create a document if it does not already exist" do
|
627
631
|
json = JSON.generate(:this => 'thing')
|
628
632
|
response = @request.put(
|
629
|
-
'/items/xyz', {
|
633
|
+
'/items/xyz', {
|
634
|
+
:input => json,
|
635
|
+
'HTTP_HOST' => 'example.org'}.merge(VALID_TEST_AUTH))
|
630
636
|
response.status.should == 201
|
631
637
|
result = @request.get('/items/xyz', VALID_TEST_AUTH)
|
632
638
|
result.status.should == 200
|
633
|
-
JSON.parse(result.body)['this']
|
639
|
+
parsed_json = JSON.parse(result.body)['this']
|
640
|
+
parsed_json.should == 'thing'
|
641
|
+
response['Location'].should match(/http:\/\/example.org#{parsed_json['uri']}/)
|
634
642
|
end
|
635
643
|
|
636
644
|
it "should not create new resources using deleted resource URIs" do
|
@@ -782,6 +790,24 @@ describe "A CloudKit::Service" do
|
|
782
790
|
json.keys.sort.should == ['etag', 'last_modified', 'ok', 'uri']
|
783
791
|
end
|
784
792
|
|
793
|
+
it "should use the archived URI in the JSON result" do
|
794
|
+
response = @request.delete(
|
795
|
+
'/items/abc',
|
796
|
+
'HTTP_IF_MATCH' => @etag,
|
797
|
+
CLOUDKIT_AUTH_KEY => TEST_REMOTE_USER)
|
798
|
+
json = JSON.parse(response.body)
|
799
|
+
json['uri'].should match(/\/items\/abc\/versions\/.+/)
|
800
|
+
end
|
801
|
+
|
802
|
+
it "should not change the ETag for the archived version" do
|
803
|
+
response = @request.delete(
|
804
|
+
'/items/abc',
|
805
|
+
'HTTP_IF_MATCH' => @etag,
|
806
|
+
CLOUDKIT_AUTH_KEY => TEST_REMOTE_USER)
|
807
|
+
json = JSON.parse(response.body)
|
808
|
+
json['etag'].should == @etag
|
809
|
+
end
|
810
|
+
|
785
811
|
it "should set the Content-Type header" do
|
786
812
|
response = @request.delete(
|
787
813
|
'/items/abc',
|
data/spec/uri_spec.rb
CHANGED
@@ -36,7 +36,7 @@ describe "A URI" do
|
|
36
36
|
end
|
37
37
|
|
38
38
|
it "should know if it is a resource collection URI" do
|
39
|
-
['/items/123', '/items/123/versions', '/items/123/versions/abc'].each { |uri|
|
39
|
+
['/cloudkit-meta', '/items/123', '/items/123/versions', '/items/123/versions/abc'].each { |uri|
|
40
40
|
CloudKit::URI.new(uri).should_not be_resource_collection_uri
|
41
41
|
}
|
42
42
|
CloudKit::URI.new('/items').should be_resource_collection_uri
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cloudkit
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.11.
|
4
|
+
version: 0.11.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jon Crosby
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2008-03
|
12
|
+
date: 2008-05-03 00:00:00 -07:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -18,9 +18,9 @@ dependencies:
|
|
18
18
|
version_requirement:
|
19
19
|
version_requirements: !ruby/object:Gem::Requirement
|
20
20
|
requirements:
|
21
|
-
- -
|
21
|
+
- - ">="
|
22
22
|
- !ruby/object:Gem::Version
|
23
|
-
version: "0
|
23
|
+
version: "1.0"
|
24
24
|
version:
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: uuid
|
@@ -48,9 +48,9 @@ dependencies:
|
|
48
48
|
version_requirement:
|
49
49
|
version_requirements: !ruby/object:Gem::Requirement
|
50
50
|
requirements:
|
51
|
-
- -
|
51
|
+
- - ~>
|
52
52
|
- !ruby/object:Gem::Version
|
53
|
-
version: 2.1
|
53
|
+
version: "2.1"
|
54
54
|
version:
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: json
|
@@ -58,9 +58,9 @@ dependencies:
|
|
58
58
|
version_requirement:
|
59
59
|
version_requirements: !ruby/object:Gem::Requirement
|
60
60
|
requirements:
|
61
|
-
- -
|
61
|
+
- - ~>
|
62
62
|
- !ruby/object:Gem::Version
|
63
|
-
version: 1.1
|
63
|
+
version: "1.1"
|
64
64
|
version:
|
65
65
|
description: An Open Web JSON Appliance.
|
66
66
|
email: jon@joncrosby.me
|