coin_rack 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -0,0 +1,5 @@
1
+ require File.join(File.dirname(__FILE__), "lib", "coin_rack")
2
+
3
+ use Rack::Static
4
+ use Rack::AbstractFormat
5
+ run CoinRack.new
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,3 @@
1
+ class CoinRack
2
+ VERSION = "0.0.3"
3
+ 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: