cloudkit 0.11.0 → 0.11.1
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/CHANGES +7 -0
- data/cloudkit.gemspec +3 -2
- data/doc/curl.html +3 -3
- data/doc/index.html +1 -1
- data/examples/6.ru +11 -0
- data/examples/TOC +3 -1
- data/lib/cloudkit.rb +2 -2
- data/lib/cloudkit/openid_filter.rb +5 -4
- data/lib/cloudkit/request.rb +3 -1
- data/lib/cloudkit/service.rb +1 -1
- data/lib/cloudkit/store/memory_table.rb +0 -6
- data/lib/cloudkit/store/resource.rb +15 -2
- data/spec/openid_filter_spec.rb +15 -0
- data/spec/resource_spec.rb +25 -6
- data/spec/service_spec.rb +39 -0
- metadata +3 -2
data/CHANGES
CHANGED
@@ -1,3 +1,10 @@
|
|
1
|
+
0.11.1
|
2
|
+
- Added a block option for configuring OpenID bypassed routes (Devlin Daley)
|
3
|
+
- Added write locks for Tokyo Tyrant Tables
|
4
|
+
- Added Tokyo Tyrant Table example
|
5
|
+
- Fixed POST method tunneling bug (Saimon Moore)
|
6
|
+
- Fixed escaping of nested JSON Objects and Arrays
|
7
|
+
|
1
8
|
0.11.0
|
2
9
|
- Added Tokyo Cabinet storage
|
3
10
|
- Added MemoryTable development-time storage
|
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.1"
|
6
|
+
s.date = "2008-03-24"
|
7
7
|
s.summary = "An Open Web JSON Appliance."
|
8
8
|
s.description = "An Open Web JSON Appliance."
|
9
9
|
s.authors = ["Jon Crosby"]
|
@@ -29,6 +29,7 @@ Gem::Specification.new do |s|
|
|
29
29
|
examples/3.ru
|
30
30
|
examples/4.ru
|
31
31
|
examples/5.ru
|
32
|
+
examples/6.ru
|
32
33
|
examples/TOC
|
33
34
|
lib/cloudkit.rb
|
34
35
|
lib/cloudkit/constants.rb
|
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.1):
|
42
42
|
<div class="code">
|
43
43
|
$ gem list cloudkit<br/>
|
44
|
-
cloudkit (0.
|
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.1, 0.10.0) <-- 0.11.1 is now in the list
|
48
48
|
</div>
|
49
49
|
</p>
|
50
50
|
|
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 released with Tokyo Cabinet support. Install with <em>gem install cloudkit</em>.
|
27
|
+
Version 0.11.1 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/examples/6.ru
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
$:.unshift File.expand_path(File.dirname(__FILE__)) + '/../lib'
|
2
|
+
require 'cloudkit'
|
3
|
+
require 'rufus/tokyo/tyrant' # gem install rufus-tokyo
|
4
|
+
# start Tokyo Tyrant with a table store...
|
5
|
+
# ttserver data.tct
|
6
|
+
CloudKit.setup_storage_adapter(Rufus::Tokyo::TyrantTable.new('127.0.0.1', 1978))
|
7
|
+
use Rack::Session::Pool
|
8
|
+
use CloudKit::OAuthFilter
|
9
|
+
use CloudKit::OpenIDFilter
|
10
|
+
use CloudKit::Service, :collections => [:notes]
|
11
|
+
run lambda{|env| [200, {'Content-Type' => 'text/html', 'Content-Length' => '5'}, ['HELLO']]}
|
data/examples/TOC
CHANGED
@@ -4,7 +4,7 @@ Index of Examples
|
|
4
4
|
When using the gem version of CloudKit, the first line of each example can be
|
5
5
|
removed.
|
6
6
|
|
7
|
-
1. Expose Notes - Mount a JSON "notes" API. Uses in-memory
|
7
|
+
1. Expose Notes - Mount a JSON "notes" API. Uses in-memory store.
|
8
8
|
|
9
9
|
2. Contain Notes - Same as #1, adding OpenID and OAuth.
|
10
10
|
|
@@ -13,3 +13,5 @@ removed.
|
|
13
13
|
4. Notes with OAuth - Same as #1 using only OAuth.
|
14
14
|
|
15
15
|
5. Tokyo Notes - Same as #2 with a Tokyo Cabinet Table store.
|
16
|
+
|
17
|
+
6. Tyrant Notes - Same as #2 with a Tokyo Tyrant Table store.
|
data/lib/cloudkit.rb
CHANGED
@@ -34,11 +34,11 @@ require 'cloudkit/user_store'
|
|
34
34
|
include CloudKit::Constants
|
35
35
|
|
36
36
|
module CloudKit
|
37
|
-
VERSION = '0.11.
|
37
|
+
VERSION = '0.11.1'
|
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
|
41
|
-
# examples directory for
|
41
|
+
# examples directory for Cabinet and Tyrant Table examples.
|
42
42
|
def self.setup_storage_adapter(adapter_instance=nil)
|
43
43
|
@storage_adapter = adapter_instance || CloudKit::MemoryTable.new
|
44
44
|
end
|
@@ -19,9 +19,10 @@ module CloudKit
|
|
19
19
|
@@lock = Mutex.new
|
20
20
|
@@store = nil
|
21
21
|
|
22
|
-
def initialize(app, options={})
|
22
|
+
def initialize(app, options={}, &bypass_route_callback)
|
23
23
|
@app = app
|
24
24
|
@options = options
|
25
|
+
@bypass_route_callback = bypass_route_callback || Proc.new {|url| url == '/'}
|
25
26
|
end
|
26
27
|
|
27
28
|
def call(env)
|
@@ -213,12 +214,12 @@ module CloudKit
|
|
213
214
|
end
|
214
215
|
|
215
216
|
def allow?(uri)
|
216
|
-
@
|
217
|
+
@bypass_route_callback.call(uri) ||
|
218
|
+
@options[:allow] && @options[:allow].include?(uri)
|
217
219
|
end
|
218
220
|
|
219
221
|
def bypass?(request)
|
220
|
-
|
221
|
-
allow?(request.path_info) ||
|
222
|
+
allow?(request.path_info) ||
|
222
223
|
valid_auth_key?(request) ||
|
223
224
|
logged_in?(request)
|
224
225
|
end
|
data/lib/cloudkit/request.rb
CHANGED
@@ -17,7 +17,9 @@ module CloudKit
|
|
17
17
|
# Return the JSON content from the request body
|
18
18
|
def json
|
19
19
|
self.body.rewind
|
20
|
-
self.body.read
|
20
|
+
raw = self.body.read
|
21
|
+
# extract the json from the body to avoid tunneled _method param from being parsed as json
|
22
|
+
(matches = raw.match(/(\{.*\})/)) ? matches[1] : raw
|
21
23
|
end
|
22
24
|
|
23
25
|
# Return a CloudKit::URI instance representing the rack request's path info.
|
data/lib/cloudkit/service.rb
CHANGED
@@ -49,7 +49,7 @@ module CloudKit
|
|
49
49
|
# modify resources that are not current.
|
50
50
|
def update(json, remote_user=nil)
|
51
51
|
raise HistoricalIntegrityViolation unless current?
|
52
|
-
|
52
|
+
transaction do
|
53
53
|
record = CloudKit.storage_adapter[@id]
|
54
54
|
record['uri'] = "#{@uri.string}/versions/#{@etag}"
|
55
55
|
record['archived'] = escape(true)
|
@@ -65,7 +65,7 @@ module CloudKit
|
|
65
65
|
# are not current.
|
66
66
|
def delete
|
67
67
|
raise HistoricalIntegrityViolation unless current?
|
68
|
-
|
68
|
+
transaction do
|
69
69
|
original_uri = @uri
|
70
70
|
record = CloudKit.storage_adapter[@id]
|
71
71
|
record['uri'] = "#{@uri.string}/versions/#{@etag}"
|
@@ -223,6 +223,8 @@ module CloudKit
|
|
223
223
|
"null"
|
224
224
|
when Fixnum, Bignum, Float
|
225
225
|
value.to_s
|
226
|
+
when Array, Hash
|
227
|
+
JSON.generate(value) # temporary bug fix prior to JSONQuery support
|
226
228
|
else
|
227
229
|
value
|
228
230
|
end
|
@@ -252,5 +254,16 @@ module CloudKit
|
|
252
254
|
def escape_values(hash)
|
253
255
|
hash.inject({}) { |memo, pair| memo.merge({pair[0] => escape(pair[1])}) }
|
254
256
|
end
|
257
|
+
|
258
|
+
def transaction
|
259
|
+
open('.lock', 'w+') do |f|
|
260
|
+
f.flock(File::LOCK_EX)
|
261
|
+
begin
|
262
|
+
yield
|
263
|
+
ensure
|
264
|
+
f.flock(File::LOCK_UN)
|
265
|
+
end
|
266
|
+
end
|
267
|
+
end
|
255
268
|
end
|
256
269
|
end
|
data/spec/openid_filter_spec.rb
CHANGED
@@ -22,6 +22,20 @@ describe "An OpenIDFilter" do
|
|
22
22
|
response.status.should == 200
|
23
23
|
end
|
24
24
|
|
25
|
+
it "should allow pass through of URIs defined in bypass route callback" do
|
26
|
+
openid_app = Rack::Builder.new {
|
27
|
+
use Rack::Lint
|
28
|
+
use Rack::Session::Pool
|
29
|
+
use CloudKit::OpenIDFilter, :allow => ['/foo'] do |url|
|
30
|
+
['/bar'].include? url
|
31
|
+
end
|
32
|
+
run echo_env(CLOUDKIT_AUTH_KEY)
|
33
|
+
}
|
34
|
+
request = Rack::MockRequest.new(openid_app)
|
35
|
+
response = request.get('/bar')
|
36
|
+
response.status.should == 200
|
37
|
+
end
|
38
|
+
|
25
39
|
it "should redirect to the login page if authorization is required" do
|
26
40
|
response = @request.get('/protected')
|
27
41
|
response.status.should == 302
|
@@ -61,4 +75,5 @@ describe "An OpenIDFilter" do
|
|
61
75
|
end
|
62
76
|
|
63
77
|
end
|
78
|
+
|
64
79
|
end
|
data/spec/resource_spec.rb
CHANGED
@@ -93,19 +93,38 @@ describe "A Resource" do
|
|
93
93
|
|
94
94
|
describe "on create" do
|
95
95
|
|
96
|
-
|
97
|
-
|
96
|
+
def store_json(hash)
|
97
|
+
CloudKit::Resource.create(
|
98
98
|
CloudKit::URI.new('/items/123'),
|
99
|
-
JSON.generate(
|
99
|
+
JSON.generate(hash),
|
100
100
|
'http://eric.dolphy.info')
|
101
|
-
|
101
|
+
CloudKit.storage_adapter.query { |q|
|
102
102
|
q.add_condition 'uri', :eql, '/items/123'
|
103
103
|
}
|
104
104
|
end
|
105
105
|
|
106
106
|
it "should save the resource" do
|
107
|
-
|
108
|
-
|
107
|
+
result = store_json({:foo => 'bar'})
|
108
|
+
result.size.should == 1
|
109
|
+
result.first['json'].should == "{\"foo\":\"bar\"}"
|
110
|
+
end
|
111
|
+
|
112
|
+
it "should accept nested array values" do
|
113
|
+
result = store_json({:foo => [1,2]})
|
114
|
+
result.size.should == 1
|
115
|
+
result.first['json'].should == '{"foo":[1,2]}'
|
116
|
+
end
|
117
|
+
|
118
|
+
it "should accept nested hash values" do
|
119
|
+
result = store_json({:foo => {:bar => 'baz'}})
|
120
|
+
result.size.should == 1
|
121
|
+
result.first['json'].should == '{"foo":{"bar":"baz"}}'
|
122
|
+
end
|
123
|
+
|
124
|
+
it "should accept recursively nested array/hash values" do
|
125
|
+
result = store_json({:foo => [1,{:bar => [2,3]}]})
|
126
|
+
result.size.should == 1
|
127
|
+
result.first['json'].should == '{"foo":[1,{"bar":[2,3]}]}'
|
109
128
|
end
|
110
129
|
|
111
130
|
end
|
data/spec/service_spec.rb
CHANGED
@@ -736,6 +736,21 @@ describe "A CloudKit::Service" do
|
|
736
736
|
new_etag.should_not == etag
|
737
737
|
end
|
738
738
|
|
739
|
+
describe "using POST method tunneling" do
|
740
|
+
|
741
|
+
it "should behave like a PUT" do
|
742
|
+
json = JSON.generate(:this => 'thing')
|
743
|
+
response = @request.post(
|
744
|
+
'/items/xyz?_method=PUT',
|
745
|
+
{:input => json}.merge(VALID_TEST_AUTH))
|
746
|
+
response.status.should == 201
|
747
|
+
result = @request.get('/items/xyz', VALID_TEST_AUTH)
|
748
|
+
result.status.should == 200
|
749
|
+
JSON.parse(result.body)['this'].should == 'thing'
|
750
|
+
end
|
751
|
+
|
752
|
+
end
|
753
|
+
|
739
754
|
end
|
740
755
|
|
741
756
|
describe "on DELETE /:collection/:id" do
|
@@ -848,6 +863,20 @@ describe "A CloudKit::Service" do
|
|
848
863
|
json['total'].should == 1
|
849
864
|
end
|
850
865
|
|
866
|
+
describe "using POST method tunneling" do
|
867
|
+
|
868
|
+
it "should behave like a DELETE" do
|
869
|
+
response = @request.post(
|
870
|
+
'/items/abc?_method=DELETE',
|
871
|
+
'HTTP_IF_MATCH' => @etag,
|
872
|
+
CLOUDKIT_AUTH_KEY => TEST_REMOTE_USER)
|
873
|
+
response.status.should == 200
|
874
|
+
result = @request.get('/items/abc', VALID_TEST_AUTH)
|
875
|
+
result.status.should == 410
|
876
|
+
end
|
877
|
+
|
878
|
+
end
|
879
|
+
|
851
880
|
end
|
852
881
|
|
853
882
|
describe "on OPTIONS /:collection" do
|
@@ -866,6 +895,16 @@ describe "A CloudKit::Service" do
|
|
866
895
|
methods.sort.should == ['GET', 'HEAD', 'OPTIONS', 'POST']
|
867
896
|
end
|
868
897
|
|
898
|
+
describe "using POST method tunneling" do
|
899
|
+
|
900
|
+
it "should behave like an OPTIONS request" do
|
901
|
+
response = @request.post('/items?_method=OPTIONS', VALID_TEST_AUTH)
|
902
|
+
response['Allow'].should_not be_nil
|
903
|
+
methods = response['Allow'].split(', ')
|
904
|
+
methods.sort.should == ['GET', 'HEAD', 'OPTIONS', 'POST']
|
905
|
+
end
|
906
|
+
end
|
907
|
+
|
869
908
|
end
|
870
909
|
|
871
910
|
describe "on OPTIONS /:collection/_resolved" do
|
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.1
|
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-03-24 00:00:00 -07:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -90,6 +90,7 @@ files:
|
|
90
90
|
- examples/3.ru
|
91
91
|
- examples/4.ru
|
92
92
|
- examples/5.ru
|
93
|
+
- examples/6.ru
|
93
94
|
- examples/TOC
|
94
95
|
- lib/cloudkit.rb
|
95
96
|
- lib/cloudkit/constants.rb
|