cistern 2.1.0 → 2.2.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.
- checksums.yaml +4 -4
- data/Gemfile +1 -1
- data/README.md +55 -0
- data/lib/cistern/client.rb +89 -50
- data/lib/cistern/request.rb +4 -0
- data/lib/cistern/version.rb +1 -1
- data/spec/client_spec.rb +68 -0
- data/spec/spec_helper.rb +0 -2
- 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: 32675f1c34663bf47fbea19c1f56e009884b8851
|
4
|
+
data.tar.gz: bd418e9510d7dfde5bc563a0e8a3471b174c6a2a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4f5044d67c9c3195a7ea0ec3f50186c4746aba1dec07cb16e582dc92d5b35219e913b9eeaef651ea75f71e6fc143603216339179627a516975741ccbf0c26014
|
7
|
+
data.tar.gz: 9db86cbe754c36b2c3f07e33b1b44c01d1c10dc97a746a61dd59cc1f616dd7574477b09c3ef0af24a5d1c7c025ff8a6d7162591c81ab4679746b2a1223bef0c7
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -9,6 +9,61 @@ Cistern helps you consistently build your API clients and faciliates building mo
|
|
9
9
|
|
10
10
|
## Usage
|
11
11
|
|
12
|
+
### Custom Architecture
|
13
|
+
|
14
|
+
By default a service's `Request`, `Collection`, and `Model` are all classes. In Cistern ~> 3.0, the default will be modules.
|
15
|
+
|
16
|
+
You can modify your client's architecture to be forwards compatible by using `Cistern::Client.with`
|
17
|
+
|
18
|
+
```ruby
|
19
|
+
class Foo::Client
|
20
|
+
include Cistern::Client.with(interface: :module)
|
21
|
+
end
|
22
|
+
```
|
23
|
+
|
24
|
+
Now request classes would look like:
|
25
|
+
|
26
|
+
```ruby
|
27
|
+
class Foo::GetBar
|
28
|
+
include Foo::Request
|
29
|
+
|
30
|
+
def real
|
31
|
+
"bar"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
```
|
35
|
+
|
36
|
+
Other options include `:collection`, `:request`, and `:model`. This options define the name of module or class interface for the service component.
|
37
|
+
|
38
|
+
If `Request` is to reserved for a model, then the `Request` component name can be remapped to `Prayer`
|
39
|
+
|
40
|
+
For example:
|
41
|
+
|
42
|
+
```ruby
|
43
|
+
class Foo::Client
|
44
|
+
include Cistern::Client.with(request: "Prayer")
|
45
|
+
end
|
46
|
+
```
|
47
|
+
|
48
|
+
allows a model named `Request` to exist
|
49
|
+
|
50
|
+
```ruby
|
51
|
+
class Foo::Request < Foo::Model
|
52
|
+
identity :jovi
|
53
|
+
end
|
54
|
+
```
|
55
|
+
|
56
|
+
while living on a `Prayer`
|
57
|
+
|
58
|
+
```ruby
|
59
|
+
class Foo::GetBar < Foo::Prayer
|
60
|
+
def real
|
61
|
+
service.request.get("/wing")
|
62
|
+
end
|
63
|
+
end
|
64
|
+
```
|
65
|
+
|
66
|
+
|
12
67
|
### Service
|
13
68
|
|
14
69
|
This represents the remote service that you are wrapping. If the service name is `foo` then a good name is `Foo::Client`.
|
data/lib/cistern/client.rb
CHANGED
@@ -10,79 +10,120 @@ module Cistern::Client
|
|
10
10
|
end
|
11
11
|
end
|
12
12
|
|
13
|
+
# custom include
|
14
|
+
def self.with(options={})
|
15
|
+
client_module = Module.new
|
16
|
+
|
17
|
+
custom_include = <<-EOS
|
18
|
+
def self.included(klass)
|
19
|
+
Cistern::Client.setup(klass, #{options.inspect})
|
20
|
+
|
21
|
+
super
|
22
|
+
end
|
23
|
+
EOS
|
24
|
+
|
25
|
+
client_module.class_eval(custom_include, __FILE__, __LINE__)
|
26
|
+
|
27
|
+
client_module
|
28
|
+
end
|
29
|
+
|
30
|
+
# vanilla include
|
13
31
|
def self.included(klass)
|
32
|
+
self.setup(klass)
|
33
|
+
|
34
|
+
super
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.setup(klass, options={})
|
38
|
+
request_class = options[:request] || "Request"
|
39
|
+
collection_class = options[:collection] || "Collection"
|
40
|
+
model_class = options[:model] || "Model"
|
41
|
+
|
42
|
+
interface = options[:interface] || :class
|
43
|
+
interface_callback = (:class == interface) ? :inherited : :included
|
44
|
+
|
45
|
+
unless klass.name
|
46
|
+
raise ArgumentError, "can't turn anonymous class into a Cistern service"
|
47
|
+
end
|
48
|
+
|
14
49
|
klass.class_eval <<-EOS, __FILE__, __LINE__
|
15
|
-
|
16
|
-
|
50
|
+
module Collections
|
51
|
+
include ::Cistern::Client::Collections
|
17
52
|
|
18
|
-
|
19
|
-
|
20
|
-
end
|
53
|
+
def service
|
54
|
+
#{klass.name}
|
21
55
|
end
|
56
|
+
end
|
22
57
|
|
23
|
-
|
24
|
-
|
25
|
-
|
58
|
+
def self.service
|
59
|
+
#{klass.name}
|
60
|
+
end
|
26
61
|
|
27
|
-
|
28
|
-
|
29
|
-
end
|
62
|
+
class Real
|
63
|
+
def initialize(options={})
|
30
64
|
end
|
65
|
+
end
|
31
66
|
|
32
|
-
|
33
|
-
|
34
|
-
end
|
67
|
+
class Mock
|
68
|
+
def initialize(options={})
|
35
69
|
end
|
70
|
+
end
|
36
71
|
|
37
|
-
|
38
|
-
|
72
|
+
#{interface} #{model_class}
|
73
|
+
def self.#{interface_callback}(klass)
|
74
|
+
service.models << klass
|
39
75
|
|
40
|
-
|
41
|
-
|
42
|
-
|
76
|
+
klass.send(:include, ::Cistern::Model)
|
77
|
+
|
78
|
+
super
|
79
|
+
end
|
43
80
|
|
44
|
-
|
45
|
-
|
46
|
-
end
|
81
|
+
def self.service
|
82
|
+
#{klass.name}
|
47
83
|
end
|
84
|
+
end
|
48
85
|
|
49
|
-
|
50
|
-
|
86
|
+
#{interface} #{collection_class}
|
87
|
+
include ::Cistern::Collection
|
51
88
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
89
|
+
def self.#{interface_callback}(klass)
|
90
|
+
klass.send(:extend, Cistern::Attributes::ClassMethods)
|
91
|
+
klass.send(:extend, Cistern::Collection::ClassMethods)
|
92
|
+
klass.send(:include, Cistern::Attributes::InstanceMethods)
|
56
93
|
|
57
|
-
|
58
|
-
end
|
94
|
+
service.collections << klass
|
59
95
|
|
60
|
-
|
61
|
-
#{klass.name}
|
62
|
-
end
|
96
|
+
super
|
63
97
|
end
|
64
98
|
|
65
|
-
|
66
|
-
|
99
|
+
def self.service
|
100
|
+
#{klass.name}
|
101
|
+
end
|
102
|
+
end
|
67
103
|
|
68
|
-
|
69
|
-
|
104
|
+
#{interface} #{request_class}
|
105
|
+
include ::Cistern::Request
|
70
106
|
|
71
|
-
|
72
|
-
|
107
|
+
def self.service
|
108
|
+
#{klass.name}
|
109
|
+
end
|
73
110
|
|
74
|
-
|
75
|
-
|
76
|
-
end
|
111
|
+
def self.#{interface_callback}(klass)
|
112
|
+
klass.extend(::Cistern::Request::ClassMethods)
|
77
113
|
|
78
|
-
|
79
|
-
mock(*args)
|
80
|
-
end
|
114
|
+
service.requests << klass
|
81
115
|
|
82
|
-
|
83
|
-
real(*args)
|
84
|
-
end
|
116
|
+
super
|
85
117
|
end
|
118
|
+
|
119
|
+
def _mock(*args)
|
120
|
+
mock(*args)
|
121
|
+
end
|
122
|
+
|
123
|
+
def _real(*args)
|
124
|
+
real(*args)
|
125
|
+
end
|
126
|
+
end
|
86
127
|
EOS
|
87
128
|
|
88
129
|
klass.send(:extend, Cistern::Client::ClassMethods)
|
@@ -97,8 +138,6 @@ module Cistern::Client
|
|
97
138
|
klass::Real.send(:include, klass::Collections)
|
98
139
|
klass::Real.send(:extend, Cistern::WaitFor)
|
99
140
|
klass::Real.timeout_error = klass::Timeout
|
100
|
-
|
101
|
-
super
|
102
141
|
end
|
103
142
|
|
104
143
|
module ClassMethods
|
data/lib/cistern/request.rb
CHANGED
@@ -1,5 +1,9 @@
|
|
1
1
|
module Cistern::Request
|
2
2
|
def self.service_request(service, klass, name)
|
3
|
+
unless klass.name
|
4
|
+
raise ArgumentError, "can't turn anonymous class into a Cistern request"
|
5
|
+
end
|
6
|
+
|
3
7
|
service::Mock.module_eval <<-EOS, __FILE__, __LINE__
|
4
8
|
def #{name}(*args)
|
5
9
|
#{klass}.new(self)._mock(*args)
|
data/lib/cistern/version.rb
CHANGED
data/spec/client_spec.rb
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe "client" do
|
4
|
+
context "with specific architecture" do
|
5
|
+
it "allows module-based interfaces" do
|
6
|
+
class ModuleClient
|
7
|
+
include Cistern::Client.with(interface: :module)
|
8
|
+
end
|
9
|
+
|
10
|
+
class ModuleClient::Shoot
|
11
|
+
include ModuleClient::Request
|
12
|
+
|
13
|
+
def real(mod)
|
14
|
+
mod % 9
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
class ModuleClient::Moon
|
19
|
+
include ModuleClient::Model
|
20
|
+
|
21
|
+
identity :on
|
22
|
+
|
23
|
+
def save
|
24
|
+
self.identity % 3
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
class ModuleClient::Moons
|
29
|
+
include ModuleClient::Collection
|
30
|
+
|
31
|
+
model ModuleClient::Moon
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
expect(
|
36
|
+
ModuleClient.new.shoot(12)
|
37
|
+
).to eq(3)
|
38
|
+
|
39
|
+
expect(ModuleClient.collections).to contain_exactly(ModuleClient::Moons)
|
40
|
+
expect(ModuleClient.models).to contain_exactly(ModuleClient::Moon)
|
41
|
+
expect(ModuleClient.requests).to contain_exactly(ModuleClient::Shoot)
|
42
|
+
|
43
|
+
expect(
|
44
|
+
ModuleClient.new.moons.new(on: 5).save
|
45
|
+
).to eq(2)
|
46
|
+
end
|
47
|
+
|
48
|
+
it "allows custom model interface" do
|
49
|
+
class AskClient
|
50
|
+
include Cistern::Client.with(model: "Ask", interface: :module)
|
51
|
+
end
|
52
|
+
|
53
|
+
class AskClient::Model
|
54
|
+
include AskClient::Ask
|
55
|
+
|
56
|
+
identity :id
|
57
|
+
|
58
|
+
def save
|
59
|
+
9 % identity
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
expect(
|
64
|
+
AskClient.new.model(id: 9).save
|
65
|
+
).to eq(0)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -11,8 +11,6 @@ Bundler.require(:test)
|
|
11
11
|
Cistern.deprecation_warnings = false
|
12
12
|
|
13
13
|
RSpec.configure do |c|
|
14
|
-
c.treat_symbols_as_metadata_keys_with_true_values = true
|
15
|
-
|
16
14
|
if Kernel.respond_to?(:caller_locations)
|
17
15
|
require File.expand_path('../../lib/cistern/coverage', __FILE__)
|
18
16
|
else
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cistern
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.1
|
4
|
+
version: 2.2.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Josh Lane
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-10-02 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: API client framework extracted from Fog
|
14
14
|
email:
|
@@ -50,6 +50,7 @@ files:
|
|
50
50
|
- lib/cistern/timeout.rb
|
51
51
|
- lib/cistern/version.rb
|
52
52
|
- lib/cistern/wait_for.rb
|
53
|
+
- spec/client_spec.rb
|
53
54
|
- spec/collection_spec.rb
|
54
55
|
- spec/dirty_spec.rb
|
55
56
|
- spec/formatter_spec.rb
|
@@ -87,6 +88,7 @@ signing_key:
|
|
87
88
|
specification_version: 4
|
88
89
|
summary: API client framework
|
89
90
|
test_files:
|
91
|
+
- spec/client_spec.rb
|
90
92
|
- spec/collection_spec.rb
|
91
93
|
- spec/dirty_spec.rb
|
92
94
|
- spec/formatter_spec.rb
|