sliver 0.0.5 → 0.1.0
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.
- checksums.yaml +4 -4
- data/README.md +3 -3
- data/lib/sliver/action.rb +10 -7
- data/lib/sliver/api.rb +3 -7
- data/lib/sliver/endpoints.rb +5 -9
- data/lib/sliver/path.rb +43 -0
- data/lib/sliver/runner.rb +32 -0
- data/lib/sliver.rb +2 -0
- data/sliver.gemspec +1 -1
- data/spec/acceptance/class_api_spec.rb +94 -0
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0bdc908dcc8c917965d1acfd2b79b8f290917e7a
|
4
|
+
data.tar.gz: cb6fcbcbe3f42041052410562e6d9d7cf68edbd9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bd4f2fb4cf61ee61a845ddeaa5c4e37ab737c152727aafc016a6379601e619a9cf802ba5fcc019987e3989d95f4e03d65ddacdf55a9a3d592ff9ea52dbaf2f80
|
7
|
+
data.tar.gz: 4b93baa6b44dd3eadb0914bae0e10fba15687933642cbca7b36c5f25ae352c6835bda079667362b0adc409259e2546ca6a057a8bb24eb438e4f3296c014ad11f
|
data/README.md
CHANGED
@@ -13,7 +13,7 @@ Early days of development, so things may change dramatically. Or not. Who knows.
|
|
13
13
|
Add it to your Gemfile like any other gem, or install it manually.
|
14
14
|
|
15
15
|
```ruby
|
16
|
-
gem 'sliver', '~> 0.0
|
16
|
+
gem 'sliver', '~> 0.1.0'
|
17
17
|
```
|
18
18
|
|
19
19
|
## Usage
|
@@ -26,8 +26,8 @@ array with three items: status code, headers, and body).
|
|
26
26
|
So, a response can be as simple as a lambda/proc, or it can be a complex class.
|
27
27
|
If you want to deal with classes, you can mix in `Sliver::Action` to take
|
28
28
|
advantage of some helper methods (and it already stores environment via
|
29
|
-
`attr_reader`), and it returns a `Sliver::Response` class which is translated
|
30
|
-
the standard Rack response. Each instance of a class that mixes in
|
29
|
+
`attr_reader`), and it returns a `Sliver::Response` class which is translated
|
30
|
+
to the standard Rack response. Each instance of a class that mixes in
|
31
31
|
`Sliver::Action` is handling a specific API request.
|
32
32
|
|
33
33
|
```ruby
|
data/lib/sliver/action.rb
CHANGED
@@ -5,12 +5,11 @@ module Sliver::Action
|
|
5
5
|
|
6
6
|
module ClassMethods
|
7
7
|
def call(environment)
|
8
|
-
|
9
|
-
|
10
|
-
action = new(environment, response)
|
11
|
-
action.call unless action.skip?
|
8
|
+
Sliver::Runner.new(self, environment).call
|
9
|
+
end
|
12
10
|
|
13
|
-
|
11
|
+
def guards
|
12
|
+
[]
|
14
13
|
end
|
15
14
|
end
|
16
15
|
|
@@ -18,6 +17,10 @@ module Sliver::Action
|
|
18
17
|
@environment, @response = environment, response
|
19
18
|
end
|
20
19
|
|
20
|
+
def request
|
21
|
+
@request ||= Rack::Request.new environment
|
22
|
+
end
|
23
|
+
|
21
24
|
def skip?
|
22
25
|
false
|
23
26
|
end
|
@@ -26,7 +29,7 @@ module Sliver::Action
|
|
26
29
|
|
27
30
|
attr_reader :environment, :response
|
28
31
|
|
29
|
-
def
|
30
|
-
@
|
32
|
+
def path_params
|
33
|
+
@path_params ||= environment['sliver.path'].to_params environment
|
31
34
|
end
|
32
35
|
end
|
data/lib/sliver/api.rb
CHANGED
@@ -2,15 +2,13 @@ class Sliver::API
|
|
2
2
|
NOT_FOUND = lambda { |environment| [404, {}, ['Not Found']] }
|
3
3
|
|
4
4
|
def initialize(&block)
|
5
|
-
@endpoints =
|
5
|
+
@endpoints = Sliver::Endpoints.new
|
6
6
|
|
7
7
|
block.call self
|
8
8
|
end
|
9
9
|
|
10
10
|
def call(environment)
|
11
|
-
|
12
|
-
path = environment['PATH_INFO']
|
13
|
-
endpoint = endpoints[method].find(path)
|
11
|
+
endpoint = endpoints.find environment
|
14
12
|
|
15
13
|
endpoint.nil? ? NOT_FOUND.call(environment) : invoke(endpoint, environment)
|
16
14
|
end
|
@@ -20,9 +18,7 @@ class Sliver::API
|
|
20
18
|
end
|
21
19
|
|
22
20
|
def connect(method, path, action)
|
23
|
-
method
|
24
|
-
|
25
|
-
endpoints[method].append path, action
|
21
|
+
endpoints.append Sliver::Path.new(method, path), action
|
26
22
|
end
|
27
23
|
|
28
24
|
private
|
data/lib/sliver/endpoints.rb
CHANGED
@@ -4,19 +4,15 @@ class Sliver::Endpoints
|
|
4
4
|
end
|
5
5
|
|
6
6
|
def append(path, action)
|
7
|
-
path = '/' if path == ''
|
8
|
-
|
9
7
|
paths[path] = action
|
10
8
|
end
|
11
9
|
|
12
|
-
def find(
|
13
|
-
|
14
|
-
|
15
|
-
key = paths.keys.detect { |key|
|
16
|
-
key.is_a?(String) ? (key == path) : path[/\A#{key}\z/]
|
17
|
-
}
|
10
|
+
def find(environment)
|
11
|
+
key = paths.keys.detect { |key| key.matches?(environment) }
|
12
|
+
return nil unless key
|
18
13
|
|
19
|
-
|
14
|
+
environment['sliver.path'] = key
|
15
|
+
paths[key]
|
20
16
|
end
|
21
17
|
|
22
18
|
private
|
data/lib/sliver/path.rb
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
class Sliver::Path
|
2
|
+
def initialize(http_method, string)
|
3
|
+
@http_method = http_method.to_s.upcase
|
4
|
+
@string = normalised_path string
|
5
|
+
end
|
6
|
+
|
7
|
+
def matches?(environment)
|
8
|
+
method = environment['REQUEST_METHOD']
|
9
|
+
path = normalised_path environment['PATH_INFO']
|
10
|
+
|
11
|
+
http_method == method && path[string_to_regexp]
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_params(environment)
|
15
|
+
return {} unless matches?(environment)
|
16
|
+
|
17
|
+
path = normalised_path environment['PATH_INFO']
|
18
|
+
values = path.scan(string_to_regexp).flatten
|
19
|
+
|
20
|
+
string_keys.each_with_index.inject({}) do |hash, (key, index)|
|
21
|
+
hash[key] = values[index]
|
22
|
+
hash
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
attr_reader :http_method, :string
|
29
|
+
|
30
|
+
def normalised_path(string)
|
31
|
+
string == '' ? '/' : string
|
32
|
+
end
|
33
|
+
|
34
|
+
def string_keys
|
35
|
+
@string_keys ||= string.to_s.scan(/:([\w-]+)/i).flatten
|
36
|
+
end
|
37
|
+
|
38
|
+
def string_to_regexp
|
39
|
+
@string_to_regexp ||= Regexp.new(
|
40
|
+
"\\A" + string.to_s.gsub(/:[\w-]+/, "([\\w-]+)") + "\\z"
|
41
|
+
)
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
class Sliver::Runner
|
2
|
+
def initialize(klass, environment)
|
3
|
+
@klass, @environment = klass, environment
|
4
|
+
end
|
5
|
+
|
6
|
+
def call
|
7
|
+
guard_classes.each do |guard_class|
|
8
|
+
guard = guard_class.new(action)
|
9
|
+
return guard.response unless guard.continue?
|
10
|
+
end
|
11
|
+
|
12
|
+
action.call unless action.skip?
|
13
|
+
|
14
|
+
response.to_a
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
attr_reader :klass, :environment
|
20
|
+
|
21
|
+
def action
|
22
|
+
@action ||= klass.new environment, response
|
23
|
+
end
|
24
|
+
|
25
|
+
def guard_classes
|
26
|
+
klass.guards
|
27
|
+
end
|
28
|
+
|
29
|
+
def response
|
30
|
+
@response ||= Sliver::Response.new
|
31
|
+
end
|
32
|
+
end
|
data/lib/sliver.rb
CHANGED
data/sliver.gemspec
CHANGED
@@ -42,6 +42,61 @@ class SkippedAction
|
|
42
42
|
end
|
43
43
|
end
|
44
44
|
|
45
|
+
class MyParamGuard
|
46
|
+
def initialize(action)
|
47
|
+
@action = action
|
48
|
+
end
|
49
|
+
|
50
|
+
def continue?
|
51
|
+
action.request.params['hello'] == 'world'
|
52
|
+
end
|
53
|
+
|
54
|
+
def response
|
55
|
+
[404, {}, ['Not Found']]
|
56
|
+
end
|
57
|
+
|
58
|
+
private
|
59
|
+
|
60
|
+
attr_reader :action
|
61
|
+
end
|
62
|
+
|
63
|
+
class GuardedAction
|
64
|
+
include Sliver::Action
|
65
|
+
|
66
|
+
def self.guards
|
67
|
+
[MyParamGuard]
|
68
|
+
end
|
69
|
+
|
70
|
+
def call
|
71
|
+
response.status = 200
|
72
|
+
response.body = ['Welcome']
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
class UnguardedAction < GuardedAction
|
77
|
+
def self.guards
|
78
|
+
super - [MyParamGuard]
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
class IdAction
|
83
|
+
include Sliver::Action
|
84
|
+
|
85
|
+
def call
|
86
|
+
response.status = 200
|
87
|
+
response.body = [path_params['id']]
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
class MultiPathPartAction
|
92
|
+
include Sliver::Action
|
93
|
+
|
94
|
+
def call
|
95
|
+
response.status = 200
|
96
|
+
response.body = ["#{path_params['first']}:#{path_params['second']}"]
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
45
100
|
describe 'Class-based Sliver API' do
|
46
101
|
include Rack::Test::Methods
|
47
102
|
|
@@ -50,6 +105,10 @@ describe 'Class-based Sliver API' do
|
|
50
105
|
api.connect :put, '/echo', EchoAction
|
51
106
|
api.connect :get, '/addition', AdditionAction
|
52
107
|
api.connect :get, '/skip', SkippedAction
|
108
|
+
api.connect :get, '/guard', GuardedAction
|
109
|
+
api.connect :get, '/unguard', UnguardedAction
|
110
|
+
api.connect :get, '/my/:id', IdAction
|
111
|
+
api.connect :get, '/my/:first/:second', MultiPathPartAction
|
53
112
|
end }
|
54
113
|
|
55
114
|
it 'constructs responses' do
|
@@ -78,4 +137,39 @@ describe 'Class-based Sliver API' do
|
|
78
137
|
expect(last_response.status).to eq(400)
|
79
138
|
expect(last_response.body).to eq('Invalid')
|
80
139
|
end
|
140
|
+
|
141
|
+
it 'blocks guarded actions if they cannot continue' do
|
142
|
+
get '/guard'
|
143
|
+
|
144
|
+
expect(last_response.status).to eq(404)
|
145
|
+
expect(last_response.body).to eq('Not Found')
|
146
|
+
end
|
147
|
+
|
148
|
+
it 'accepts guarded actions that meet criteria' do
|
149
|
+
get '/guard', 'hello' => 'world'
|
150
|
+
|
151
|
+
expect(last_response.status).to eq(200)
|
152
|
+
expect(last_response.body).to eq('Welcome')
|
153
|
+
end
|
154
|
+
|
155
|
+
it 'respects subclass guard changes' do
|
156
|
+
get '/unguard'
|
157
|
+
|
158
|
+
expect(last_response.status).to eq(200)
|
159
|
+
expect(last_response.body).to eq('Welcome')
|
160
|
+
end
|
161
|
+
|
162
|
+
it 'handles path parameter markers' do
|
163
|
+
get '/my/10'
|
164
|
+
|
165
|
+
expect(last_response.status).to eq(200)
|
166
|
+
expect(last_response.body).to eq('10')
|
167
|
+
end
|
168
|
+
|
169
|
+
it 'handles multiple path parameter markers' do
|
170
|
+
get '/my/10/foo'
|
171
|
+
|
172
|
+
expect(last_response.status).to eq(200)
|
173
|
+
expect(last_response.body).to eq('10:foo')
|
174
|
+
end
|
81
175
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sliver
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Pat Allan
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-02-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rack
|
@@ -69,7 +69,9 @@ files:
|
|
69
69
|
- lib/sliver/action.rb
|
70
70
|
- lib/sliver/api.rb
|
71
71
|
- lib/sliver/endpoints.rb
|
72
|
+
- lib/sliver/path.rb
|
72
73
|
- lib/sliver/response.rb
|
74
|
+
- lib/sliver/runner.rb
|
73
75
|
- sliver.gemspec
|
74
76
|
- spec/acceptance/class_api_spec.rb
|
75
77
|
- spec/acceptance/lambda_api_spec.rb
|