coin_rack 0.0.3
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/Gemfile +15 -0
- data/Gemfile.lock +49 -0
- data/LICENSE.txt +22 -0
- data/README.md +126 -0
- data/bin/coin_rack +39 -0
- data/config.ru +5 -0
- data/lib/coin_rack.rb +92 -0
- data/lib/coin_rack/version.rb +3 -0
- data/test/coin_rack_test.rb +219 -0
- metadata +168 -0
data/Gemfile
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
source "https://rubygems.org"
|
2
|
+
|
3
|
+
gem "rack"
|
4
|
+
gem "coin"
|
5
|
+
gem "footing", ">=0.1.5"
|
6
|
+
gem "rack-abstract-format", :require => "rack/abstract_format"
|
7
|
+
gem "rack-accept-media-types", :require => "rack/accept_media_types"
|
8
|
+
gem "builder"
|
9
|
+
gem "activesupport", :require => "active_support/all"
|
10
|
+
|
11
|
+
group :development do
|
12
|
+
gem "pry"
|
13
|
+
gem "pry-stack_explorer"
|
14
|
+
gem "micro_test"
|
15
|
+
end
|
data/Gemfile.lock
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
GEM
|
2
|
+
remote: https://rubygems.org/
|
3
|
+
specs:
|
4
|
+
activesupport (3.2.9)
|
5
|
+
i18n (~> 0.6)
|
6
|
+
multi_json (~> 1.0)
|
7
|
+
binding_of_caller (0.6.8)
|
8
|
+
builder (3.1.4)
|
9
|
+
coderay (1.0.8)
|
10
|
+
coin (0.1.2)
|
11
|
+
footing (0.1.5)
|
12
|
+
i18n (0.6.1)
|
13
|
+
method_source (0.8.1)
|
14
|
+
micro_test (0.3.1)
|
15
|
+
os
|
16
|
+
multi_json (1.4.0)
|
17
|
+
os (0.9.6)
|
18
|
+
pry (0.9.10)
|
19
|
+
coderay (~> 1.0.5)
|
20
|
+
method_source (~> 0.8)
|
21
|
+
slop (~> 3.3.1)
|
22
|
+
pry (0.9.10-java)
|
23
|
+
coderay (~> 1.0.5)
|
24
|
+
method_source (~> 0.8)
|
25
|
+
slop (~> 3.3.1)
|
26
|
+
spoon (~> 0.0)
|
27
|
+
pry-stack_explorer (0.4.7)
|
28
|
+
binding_of_caller (~> 0.6.8)
|
29
|
+
rack (1.4.1)
|
30
|
+
rack-abstract-format (0.9.9)
|
31
|
+
rack-accept-media-types (0.9)
|
32
|
+
slop (3.3.3)
|
33
|
+
spoon (0.0.1)
|
34
|
+
|
35
|
+
PLATFORMS
|
36
|
+
java
|
37
|
+
ruby
|
38
|
+
|
39
|
+
DEPENDENCIES
|
40
|
+
activesupport
|
41
|
+
builder
|
42
|
+
coin
|
43
|
+
footing (>= 0.1.5)
|
44
|
+
micro_test
|
45
|
+
pry
|
46
|
+
pry-stack_explorer
|
47
|
+
rack
|
48
|
+
rack-abstract-format
|
49
|
+
rack-accept-media-types
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2012 Nathan Hopkins
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,126 @@
|
|
1
|
+
# CoinRack
|
2
|
+
|
3
|
+
A simple [Rack](http://rack.github.com/) application that provides a
|
4
|
+
REST interface to [Coin's API](https://github.com/hopsoft/coin).
|
5
|
+
|
6
|
+
## Quick Start
|
7
|
+
|
8
|
+
### Run the server
|
9
|
+
|
10
|
+
```bash
|
11
|
+
$ gem install coin_rack
|
12
|
+
$ coin_rack --run
|
13
|
+
```
|
14
|
+
|
15
|
+
### Make some client requests
|
16
|
+
|
17
|
+
```bash
|
18
|
+
$ curl --data "value=true" http://localhost:9292/example.json
|
19
|
+
# => {"example":true}
|
20
|
+
|
21
|
+
$ curl http://localhost:9292/example.json
|
22
|
+
# => {"example":true}
|
23
|
+
|
24
|
+
$ curl -X DELETE http://localhost:9292/example.json
|
25
|
+
# => {"example":null}
|
26
|
+
|
27
|
+
$ curl http://localhost:9292/example.json
|
28
|
+
# => {"example":null}
|
29
|
+
```
|
30
|
+
|
31
|
+
#### Prefer XML?
|
32
|
+
```bash
|
33
|
+
$ curl --data "value=true" http://localhost:9292/example.xml
|
34
|
+
# <?xml version="1.0" encoding="UTF-8"?>
|
35
|
+
# <hash>
|
36
|
+
# <example type="boolean">true</example>
|
37
|
+
# </hash>
|
38
|
+
|
39
|
+
$ curl http://localhost:9292/example.xml
|
40
|
+
# <?xml version="1.0" encoding="UTF-8"?>
|
41
|
+
# <hash>
|
42
|
+
# <example type="boolean">true</example>
|
43
|
+
# </hash>
|
44
|
+
|
45
|
+
$ curl -X DELETE http://localhost:9292/example.xml
|
46
|
+
# <?xml version="1.0" encoding="UTF-8"?>
|
47
|
+
# <hash>
|
48
|
+
# <example nil="true"/>
|
49
|
+
# </hash>
|
50
|
+
|
51
|
+
$ curl http://localhost:9292/example.xml
|
52
|
+
# <?xml version="1.0" encoding="UTF-8"?>
|
53
|
+
# <hash>
|
54
|
+
# <example nil="true"/>
|
55
|
+
# </hash>
|
56
|
+
```
|
57
|
+
|
58
|
+
## URL Definition
|
59
|
+
|
60
|
+
```
|
61
|
+
cache key
|
62
|
+
|
|
63
|
+
http://localhost:9292/KEY.FORMAT
|
64
|
+
|
|
65
|
+
response format
|
66
|
+
```
|
67
|
+
|
68
|
+
*Note: The XML format is also supported but XML examples have been omitted for brevity.*
|
69
|
+
|
70
|
+
## POST/PUT
|
71
|
+
|
72
|
+
Create and/or update the key to a new value.
|
73
|
+
|
74
|
+
#### Params
|
75
|
+
|
76
|
+
* **value** - the value to assign
|
77
|
+
|
78
|
+
#### Request URI
|
79
|
+
|
80
|
+
```
|
81
|
+
http://localhost:9292/example.json
|
82
|
+
```
|
83
|
+
|
84
|
+
#### Request Body
|
85
|
+
|
86
|
+
```
|
87
|
+
value=true
|
88
|
+
```
|
89
|
+
|
90
|
+
#### Response
|
91
|
+
|
92
|
+
```
|
93
|
+
"{\"example\":\"true\"}"
|
94
|
+
```
|
95
|
+
|
96
|
+
## GET
|
97
|
+
|
98
|
+
Get the current value for the specified key.
|
99
|
+
|
100
|
+
#### Request URI
|
101
|
+
|
102
|
+
```
|
103
|
+
http://localhost:9292/example.json
|
104
|
+
```
|
105
|
+
|
106
|
+
#### Response
|
107
|
+
|
108
|
+
```
|
109
|
+
"{\"example\":\"true\"}"
|
110
|
+
```
|
111
|
+
|
112
|
+
## DELETE
|
113
|
+
|
114
|
+
Deletes the key.
|
115
|
+
|
116
|
+
#### Request URI
|
117
|
+
|
118
|
+
```
|
119
|
+
http://localhost:9292/example.json
|
120
|
+
```
|
121
|
+
|
122
|
+
#### Response
|
123
|
+
|
124
|
+
```
|
125
|
+
"{\"example\":null}"
|
126
|
+
```
|
data/bin/coin_rack
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
#!/usr/bin/env ruby --
|
2
|
+
require "optparse"
|
3
|
+
|
4
|
+
# setup the options -----------------------------------------------------------
|
5
|
+
options = {}
|
6
|
+
parser = OptionParser.new do |opts|
|
7
|
+
opts.banner = "CoinRack Usage: coin_rack [options]"
|
8
|
+
|
9
|
+
desc = "Prints the location of the rackup file."
|
10
|
+
opts.on("-p", "--print", desc) { |value| options[:print] = value }
|
11
|
+
|
12
|
+
desc = "Starts the Rack server."
|
13
|
+
opts.on("-r", "--run", desc) { |value| options[:run] = value }
|
14
|
+
|
15
|
+
opts.on_tail("-h", "--help", "Show this message.") do
|
16
|
+
puts opts
|
17
|
+
exit
|
18
|
+
end
|
19
|
+
end
|
20
|
+
parser.parse!
|
21
|
+
|
22
|
+
if options.values.compact.empty?
|
23
|
+
puts parser.banner
|
24
|
+
puts parser.summarize
|
25
|
+
exit
|
26
|
+
end
|
27
|
+
|
28
|
+
path = File.expand_path(File.join(File.dirname(__FILE__), ".."))
|
29
|
+
rackup_file = File.join(path, "config.ru")
|
30
|
+
|
31
|
+
if options[:print]
|
32
|
+
puts rackup_file
|
33
|
+
exit
|
34
|
+
end
|
35
|
+
|
36
|
+
if options[:run]
|
37
|
+
exec "cd #{path} && rackup"
|
38
|
+
exit
|
39
|
+
end
|
data/config.ru
ADDED
data/lib/coin_rack.rb
ADDED
@@ -0,0 +1,92 @@
|
|
1
|
+
require "bundler"
|
2
|
+
Bundler.require
|
3
|
+
require File.join(File.dirname(__FILE__), "coin_rack", "version")
|
4
|
+
|
5
|
+
Footing.patch! String, Footing::String
|
6
|
+
Footing.patch! Array, Footing::Array
|
7
|
+
Footing.patch! Hash, Footing::Hash
|
8
|
+
|
9
|
+
class CoinRack
|
10
|
+
|
11
|
+
def call(env)
|
12
|
+
begin
|
13
|
+
request = Rack::Request.new(env)
|
14
|
+
request.POST.cast_values!
|
15
|
+
return favicon if request.path == "/favicon.ico"
|
16
|
+
return get(request) if request.get?
|
17
|
+
return post(request) if request.post?
|
18
|
+
return put(request) if request.put?
|
19
|
+
return delete(request) if request.delete?
|
20
|
+
rescue Exception => ex
|
21
|
+
[500, {"Content-Type" => "text/html"}, ["ERROR: #{ex}"]]
|
22
|
+
end
|
23
|
+
|
24
|
+
[400, {"Content-Type" => "text/html"}, ["BAD REQUEST"]]
|
25
|
+
end
|
26
|
+
|
27
|
+
protected
|
28
|
+
|
29
|
+
def key(request)
|
30
|
+
request.path.gsub(/\A\//, "")
|
31
|
+
end
|
32
|
+
|
33
|
+
def format(request)
|
34
|
+
case request.accept_media_types.prefered
|
35
|
+
when "application/json" then :json
|
36
|
+
when "application/xml" then :xml
|
37
|
+
else :unknown
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
# CREATE
|
42
|
+
def post(request)
|
43
|
+
put(request)
|
44
|
+
end
|
45
|
+
|
46
|
+
# READ
|
47
|
+
def get(request)
|
48
|
+
k = key(request)
|
49
|
+
f = format(request)
|
50
|
+
result = {}
|
51
|
+
result[k] = Coin.read(k)
|
52
|
+
send f, result
|
53
|
+
end
|
54
|
+
|
55
|
+
# UPDATE
|
56
|
+
def put(request)
|
57
|
+
k = key(request)
|
58
|
+
f = format(request)
|
59
|
+
value = request.POST["value"]
|
60
|
+
Coin.write k, value
|
61
|
+
result = {}
|
62
|
+
result[k] = value
|
63
|
+
send f, result
|
64
|
+
end
|
65
|
+
|
66
|
+
# DELETE
|
67
|
+
def delete(request)
|
68
|
+
k = key(request)
|
69
|
+
f = format(request)
|
70
|
+
Coin.delete k
|
71
|
+
result = {}
|
72
|
+
result[k] = nil
|
73
|
+
send f, result
|
74
|
+
end
|
75
|
+
|
76
|
+
def json(result)
|
77
|
+
[200, {"Content-Type" => "text/json"}, [result.to_json]]
|
78
|
+
end
|
79
|
+
|
80
|
+
def xml(result)
|
81
|
+
[200, {"Content-Type" => "text/xml"}, [result.to_xml]]
|
82
|
+
end
|
83
|
+
|
84
|
+
def unknown
|
85
|
+
[400, {"Content-Type" => "text/html"}, ["UNKNOWN FORMAT"]]
|
86
|
+
end
|
87
|
+
|
88
|
+
def favicon
|
89
|
+
[200, { "Content-Type" => "test/plain" }, ["about:blank"]]
|
90
|
+
end
|
91
|
+
|
92
|
+
end
|
@@ -0,0 +1,219 @@
|
|
1
|
+
require "net/http"
|
2
|
+
require "net/telnet"
|
3
|
+
require "uri"
|
4
|
+
require "json"
|
5
|
+
require "rexml/document"
|
6
|
+
require "bundler"
|
7
|
+
Bundler.require :default, :development
|
8
|
+
|
9
|
+
class CoinRackTest < MicroTest::Test
|
10
|
+
|
11
|
+
before do
|
12
|
+
@path = File.join(File.dirname(__FILE__), "..", "config.ru")
|
13
|
+
@pid = spawn({}, "rackup #{@path}")
|
14
|
+
|
15
|
+
# wait for the server to come up
|
16
|
+
sleep 0.1
|
17
|
+
t = nil
|
18
|
+
begin
|
19
|
+
t = Net::Telnet.new "Host" => "localhost", "Port" => 9292
|
20
|
+
rescue Exception => ex
|
21
|
+
end
|
22
|
+
while t.nil?
|
23
|
+
begin
|
24
|
+
t = Net::Telnet.new "Host" => "localhost", "Port" => 9292
|
25
|
+
rescue Exception => ex
|
26
|
+
sleep 0.1
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
@uri = URI.parse("http://localhost:9292")
|
31
|
+
end
|
32
|
+
|
33
|
+
after do
|
34
|
+
Coin.stop_server
|
35
|
+
Process.kill(9, @pid)
|
36
|
+
end
|
37
|
+
|
38
|
+
test "GET JSON data" do
|
39
|
+
Coin.write "example", "value"
|
40
|
+
http = Net::HTTP.new(@uri.host, @uri.port)
|
41
|
+
request = Net::HTTP::Get.new("/example.json")
|
42
|
+
response = http.request(request)
|
43
|
+
data = JSON.parse(response.body)
|
44
|
+
assert response.header["Content-Type"] == "text/json"
|
45
|
+
assert response.code == "200"
|
46
|
+
assert response.body == "{\"example\":\"value\"}"
|
47
|
+
assert data["example"] == "value"
|
48
|
+
end
|
49
|
+
|
50
|
+
test "GET complex JSON data" do
|
51
|
+
Coin.write "example", {
|
52
|
+
"value1" => true,
|
53
|
+
"value2" => [1, 2, 3],
|
54
|
+
"nested" => {
|
55
|
+
"value1" => false,
|
56
|
+
"value2" => [4, 5, 6]
|
57
|
+
}
|
58
|
+
}
|
59
|
+
http = Net::HTTP.new(@uri.host, @uri.port)
|
60
|
+
request = Net::HTTP::Get.new("/example.json")
|
61
|
+
response = http.request(request)
|
62
|
+
assert response.header["Content-Type"] == "text/json"
|
63
|
+
assert response.code == "200"
|
64
|
+
assert response.body == "{\"example\":{\"value1\":true,\"value2\":[1,2,3],\"nested\":{\"value1\":false,\"value2\":[4,5,6]}}}"
|
65
|
+
assert JSON.parse(response.body)
|
66
|
+
end
|
67
|
+
|
68
|
+
test "GET XML data" do
|
69
|
+
Coin.write "example", "value"
|
70
|
+
http = Net::HTTP.new(@uri.host, @uri.port)
|
71
|
+
request = Net::HTTP::Get.new("/example.xml")
|
72
|
+
response = http.request(request)
|
73
|
+
assert response.header["Content-Type"] == "text/xml"
|
74
|
+
assert response.code == "200"
|
75
|
+
assert response.body == "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<hash>\n <example>value</example>\n</hash>\n"
|
76
|
+
assert REXML::Document.new(response.body)
|
77
|
+
end
|
78
|
+
|
79
|
+
test "GET complex XML data" do
|
80
|
+
Coin.write "example", {
|
81
|
+
"value1" => true,
|
82
|
+
"value2" => [1, 2, 3],
|
83
|
+
"nested" => {
|
84
|
+
"value1" => false,
|
85
|
+
"value2" => [4, 5, 6]
|
86
|
+
}
|
87
|
+
}
|
88
|
+
http = Net::HTTP.new(@uri.host, @uri.port)
|
89
|
+
request = Net::HTTP::Get.new("/example.xml")
|
90
|
+
response = http.request(request)
|
91
|
+
assert response.header["Content-Type"] == "text/xml"
|
92
|
+
assert response.code == "200"
|
93
|
+
assert response.body == "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<hash>\n <example>\n <value1 type=\"boolean\">true</value1>\n <value2 type=\"array\">\n <value2 type=\"integer\">1</value2>\n <value2 type=\"integer\">2</value2>\n <value2 type=\"integer\">3</value2>\n </value2>\n <nested>\n <value1 type=\"boolean\">false</value1>\n <value2 type=\"array\">\n <value2 type=\"integer\">4</value2>\n <value2 type=\"integer\">5</value2>\n <value2 type=\"integer\">6</value2>\n </value2>\n </nested>\n </example>\n</hash>\n"
|
94
|
+
assert REXML::Document.new(response.body)
|
95
|
+
end
|
96
|
+
|
97
|
+
test "POST returning JSON" do
|
98
|
+
example = {
|
99
|
+
"value" => {
|
100
|
+
"value1" => true,
|
101
|
+
"value2" => [1, 2, 3],
|
102
|
+
"nested" => {
|
103
|
+
"value1" => false,
|
104
|
+
"value2" => [4, 5, 6]
|
105
|
+
}
|
106
|
+
}
|
107
|
+
}
|
108
|
+
http = Net::HTTP.new(@uri.host, @uri.port)
|
109
|
+
request = Net::HTTP::Post.new("/example.json")
|
110
|
+
request.body = example.to_param
|
111
|
+
response = http.request(request)
|
112
|
+
assert response.header["Content-Type"] == "text/json"
|
113
|
+
assert response.code == "200"
|
114
|
+
assert response.body == "{\"example\":{\"nested\":{\"value1\":false,\"value2\":[4,5,6]},\"value1\":true,\"value2\":[1,2,3]}}"
|
115
|
+
assert JSON.parse(response.body)
|
116
|
+
cached = Coin.read("example")
|
117
|
+
assert (cached.keys - example["value"].keys).empty?
|
118
|
+
assert (cached.values - example["value"].values).empty?
|
119
|
+
end
|
120
|
+
|
121
|
+
test "POST returning XML" do
|
122
|
+
example = {
|
123
|
+
"value" => {
|
124
|
+
"value1" => true,
|
125
|
+
"value2" => [1, 2, 3],
|
126
|
+
"nested" => {
|
127
|
+
"value1" => false,
|
128
|
+
"value2" => [4, 5, 6]
|
129
|
+
}
|
130
|
+
}
|
131
|
+
}
|
132
|
+
http = Net::HTTP.new(@uri.host, @uri.port)
|
133
|
+
request = Net::HTTP::Post.new("/example.xml")
|
134
|
+
request.body = example.to_param
|
135
|
+
response = http.request(request)
|
136
|
+
assert response.header["Content-Type"] == "text/xml"
|
137
|
+
assert response.code == "200"
|
138
|
+
assert response.body == "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<hash>\n <example>\n <nested>\n <value1 type=\"boolean\">false</value1>\n <value2 type=\"array\">\n <value2 type=\"integer\">4</value2>\n <value2 type=\"integer\">5</value2>\n <value2 type=\"integer\">6</value2>\n </value2>\n </nested>\n <value1 type=\"boolean\">true</value1>\n <value2 type=\"array\">\n <value2 type=\"integer\">1</value2>\n <value2 type=\"integer\">2</value2>\n <value2 type=\"integer\">3</value2>\n </value2>\n </example>\n</hash>\n"
|
139
|
+
assert REXML::Document.new(response.body)
|
140
|
+
cached = Coin.read("example")
|
141
|
+
assert (cached.keys - example["value"].keys).empty?
|
142
|
+
assert (cached.values - example["value"].values).empty?
|
143
|
+
end
|
144
|
+
|
145
|
+
test "PUT returning JSON" do
|
146
|
+
example = {
|
147
|
+
"value" => {
|
148
|
+
"value1" => true,
|
149
|
+
"value2" => [1, 2, 3],
|
150
|
+
"nested" => {
|
151
|
+
"value1" => false,
|
152
|
+
"value2" => [4, 5, 6]
|
153
|
+
}
|
154
|
+
}
|
155
|
+
}
|
156
|
+
http = Net::HTTP.new(@uri.host, @uri.port)
|
157
|
+
request = Net::HTTP::Put.new("/example.json")
|
158
|
+
request.body = example.to_param
|
159
|
+
response = http.request(request)
|
160
|
+
assert response.header["Content-Type"] == "text/json"
|
161
|
+
assert response.code == "200"
|
162
|
+
assert response.body == "{\"example\":{\"nested\":{\"value1\":false,\"value2\":[4,5,6]},\"value1\":true,\"value2\":[1,2,3]}}"
|
163
|
+
assert JSON.parse(response.body)
|
164
|
+
cached = Coin.read("example")
|
165
|
+
assert (cached.keys - example["value"].keys).empty?
|
166
|
+
assert (cached.values - example["value"].values).empty?
|
167
|
+
end
|
168
|
+
|
169
|
+
test "PUT returning XML" do
|
170
|
+
example = {
|
171
|
+
"value" => {
|
172
|
+
"value1" => true,
|
173
|
+
"value2" => [1, 2, 3],
|
174
|
+
"nested" => {
|
175
|
+
"value1" => false,
|
176
|
+
"value2" => [4, 5, 6]
|
177
|
+
}
|
178
|
+
}
|
179
|
+
}
|
180
|
+
http = Net::HTTP.new(@uri.host, @uri.port)
|
181
|
+
request = Net::HTTP::Put.new("/example.xml")
|
182
|
+
request.body = example.to_param
|
183
|
+
response = http.request(request)
|
184
|
+
assert response.header["Content-Type"] == "text/xml"
|
185
|
+
assert response.code == "200"
|
186
|
+
assert response.body == "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<hash>\n <example>\n <nested>\n <value1 type=\"boolean\">false</value1>\n <value2 type=\"array\">\n <value2 type=\"integer\">4</value2>\n <value2 type=\"integer\">5</value2>\n <value2 type=\"integer\">6</value2>\n </value2>\n </nested>\n <value1 type=\"boolean\">true</value1>\n <value2 type=\"array\">\n <value2 type=\"integer\">1</value2>\n <value2 type=\"integer\">2</value2>\n <value2 type=\"integer\">3</value2>\n </value2>\n </example>\n</hash>\n"
|
187
|
+
assert REXML::Document.new(response.body)
|
188
|
+
cached = Coin.read("example")
|
189
|
+
assert (cached.keys - example["value"].keys).empty?
|
190
|
+
assert (cached.values - example["value"].values).empty?
|
191
|
+
end
|
192
|
+
|
193
|
+
test "DELETE returning JSON" do
|
194
|
+
Coin.write "example", "value"
|
195
|
+
assert Coin.read("example") == "value"
|
196
|
+
http = Net::HTTP.new(@uri.host, @uri.port)
|
197
|
+
request = Net::HTTP::Delete.new("/example.json")
|
198
|
+
response = http.request(request)
|
199
|
+
data = JSON.parse(response.body)
|
200
|
+
assert response.header["Content-Type"] == "text/json"
|
201
|
+
assert response.code == "200"
|
202
|
+
assert response.body == "{\"example\":null}"
|
203
|
+
assert Coin.read("example").nil?
|
204
|
+
end
|
205
|
+
|
206
|
+
test "DELETE returning XML" do
|
207
|
+
Coin.write "example", "value"
|
208
|
+
assert Coin.read("example") == "value"
|
209
|
+
http = Net::HTTP.new(@uri.host, @uri.port)
|
210
|
+
request = Net::HTTP::Delete.new("/example.xml")
|
211
|
+
response = http.request(request)
|
212
|
+
assert response.header["Content-Type"] == "text/xml"
|
213
|
+
assert response.code == "200"
|
214
|
+
assert response.body == "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<hash>\n <example nil=\"true\"/>\n</hash>\n"
|
215
|
+
assert REXML::Document.new(response.body)
|
216
|
+
assert Coin.read("example").nil?
|
217
|
+
end
|
218
|
+
|
219
|
+
end
|
metadata
ADDED
@@ -0,0 +1,168 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: coin_rack
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.3
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Nathan Hopkins
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-12-04 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rack
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: coin
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :runtime
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: footing
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :runtime
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: rack-abstract-format
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ! '>='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
70
|
+
type: :runtime
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: rack-accept-media-types
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ! '>='
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '0'
|
86
|
+
type: :runtime
|
87
|
+
prerelease: false
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ! '>='
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '0'
|
94
|
+
- !ruby/object:Gem::Dependency
|
95
|
+
name: builder
|
96
|
+
requirement: !ruby/object:Gem::Requirement
|
97
|
+
none: false
|
98
|
+
requirements:
|
99
|
+
- - ! '>='
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: '0'
|
102
|
+
type: :runtime
|
103
|
+
prerelease: false
|
104
|
+
version_requirements: !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - ! '>='
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '0'
|
110
|
+
- !ruby/object:Gem::Dependency
|
111
|
+
name: activesupport
|
112
|
+
requirement: !ruby/object:Gem::Requirement
|
113
|
+
none: false
|
114
|
+
requirements:
|
115
|
+
- - ! '>='
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :runtime
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
none: false
|
122
|
+
requirements:
|
123
|
+
- - ! '>='
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
version: '0'
|
126
|
+
description:
|
127
|
+
email:
|
128
|
+
- natehop@gmail.com
|
129
|
+
executables:
|
130
|
+
- coin_rack
|
131
|
+
extensions: []
|
132
|
+
extra_rdoc_files: []
|
133
|
+
files:
|
134
|
+
- lib/coin_rack/version.rb
|
135
|
+
- lib/coin_rack.rb
|
136
|
+
- bin/coin_rack
|
137
|
+
- test/coin_rack_test.rb
|
138
|
+
- config.ru
|
139
|
+
- Gemfile
|
140
|
+
- Gemfile.lock
|
141
|
+
- LICENSE.txt
|
142
|
+
- README.md
|
143
|
+
homepage: https://github.com/hopsoft/coin_rack
|
144
|
+
licenses: []
|
145
|
+
post_install_message:
|
146
|
+
rdoc_options: []
|
147
|
+
require_paths:
|
148
|
+
- lib
|
149
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
150
|
+
none: false
|
151
|
+
requirements:
|
152
|
+
- - ! '>='
|
153
|
+
- !ruby/object:Gem::Version
|
154
|
+
version: '0'
|
155
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
156
|
+
none: false
|
157
|
+
requirements:
|
158
|
+
- - ! '>='
|
159
|
+
- !ruby/object:Gem::Version
|
160
|
+
version: '0'
|
161
|
+
requirements: []
|
162
|
+
rubyforge_project:
|
163
|
+
rubygems_version: 1.8.23
|
164
|
+
signing_key:
|
165
|
+
specification_version: 3
|
166
|
+
summary: A Simple Rack application that provides a REST interface for Coin.
|
167
|
+
test_files: []
|
168
|
+
has_rdoc:
|