whisperer 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +15 -0
- data/.gitignore +17 -0
- data/.rspec +2 -0
- data/.travis.yml +13 -0
- data/Gemfile +7 -0
- data/LICENSE.txt +22 -0
- data/README.md +293 -0
- data/Rakefile +1 -0
- data/TODO.md +47 -0
- data/lib/whisperer.rb +102 -0
- data/lib/whisperer/config.rb +40 -0
- data/lib/whisperer/convertors/hash.rb +39 -0
- data/lib/whisperer/convertors/interaction.rb +21 -0
- data/lib/whisperer/dsl.rb +19 -0
- data/lib/whisperer/dsl/base.rb +47 -0
- data/lib/whisperer/dsl/body.rb +33 -0
- data/lib/whisperer/dsl/headers.rb +20 -0
- data/lib/whisperer/dsl/request.rb +15 -0
- data/lib/whisperer/dsl/response.rb +15 -0
- data/lib/whisperer/dsl/response/status.rb +10 -0
- data/lib/whisperer/generator.rb +43 -0
- data/lib/whisperer/helpers.rb +16 -0
- data/lib/whisperer/placeholder.rb +14 -0
- data/lib/whisperer/preprocessors.rb +19 -0
- data/lib/whisperer/preprocessors/base.rb +13 -0
- data/lib/whisperer/preprocessors/content_length.rb +17 -0
- data/lib/whisperer/preprocessors/response_body.rb +23 -0
- data/lib/whisperer/record.rb +48 -0
- data/lib/whisperer/record/body.rb +15 -0
- data/lib/whisperer/record/headers.rb +22 -0
- data/lib/whisperer/record/request.rb +16 -0
- data/lib/whisperer/record/response.rb +18 -0
- data/lib/whisperer/record/response/status.rb +10 -0
- data/lib/whisperer/samples/cassette_builder.rb +24 -0
- data/lib/whisperer/serializers/base.rb +24 -0
- data/lib/whisperer/serializers/json.rb +33 -0
- data/lib/whisperer/serializers/json_multiple.rb +14 -0
- data/lib/whisperer/tasks/whisperer.rake +88 -0
- data/lib/whisperer/version.rb +3 -0
- data/spec/cassette_builders/arya_stark.rb +26 -0
- data/spec/cassette_builders/bran_stark.rb +19 -0
- data/spec/cassette_builders/empty_robb_stark.rb +20 -0
- data/spec/cassette_builders/robb_stark.rb +30 -0
- data/spec/cassette_builders/robb_stark_without_content_length.rb +20 -0
- data/spec/cassette_builders/sansa_stark.rb +9 -0
- data/spec/cassette_builders/starks.rb +31 -0
- data/spec/cassette_builders/wolfs.rb +7 -0
- data/spec/cassettes/empty_robb_stark.yml +22 -0
- data/spec/cassettes/girls/arya_stark.yml +24 -0
- data/spec/cassettes/robb_stark.yml +28 -0
- data/spec/cassettes/robb_stark_without_content_length.yml +22 -0
- data/spec/cassettes/sansa_stark.yml +24 -0
- data/spec/cassettes/starks.yml +28 -0
- data/spec/cassettes/wolfs.yml +28 -0
- data/spec/factories/arya_stark.rb +7 -0
- data/spec/factories/bran_stark.rb +7 -0
- data/spec/factories/ned_stark.rb +7 -0
- data/spec/factories/robb_stark.rb +7 -0
- data/spec/factories/sansa_stark.rb +7 -0
- data/spec/integration/whisperer_spec.rb +51 -0
- data/spec/spec_helper.rb +25 -0
- data/spec/spec_integration_helper.rb +6 -0
- data/spec/support/cassettes.rb +16 -0
- data/spec/support/custom_serializer.rb +5 -0
- data/spec/unit/config_spec.rb +94 -0
- data/spec/unit/convertors/hash_spec.rb +59 -0
- data/spec/unit/convertors/interaction_spec.rb +46 -0
- data/spec/unit/dsl/base_spec.rb +99 -0
- data/spec/unit/dsl/body_spec.rb +73 -0
- data/spec/unit/dsl/headers_spec.rb +31 -0
- data/spec/unit/dsl/request_spec.rb +4 -0
- data/spec/unit/dsl/response_spec.rb +4 -0
- data/spec/unit/dsl/status_spec.rb +4 -0
- data/spec/unit/dsl_spec.rb +4 -0
- data/spec/unit/generator_spec.rb +77 -0
- data/spec/unit/helpers_spec.rb +38 -0
- data/spec/unit/preprocessors/content_length_spec.rb +39 -0
- data/spec/unit/preprocessors/response_body_spec.rb +55 -0
- data/spec/unit/preprocessors_spec.rb +8 -0
- data/spec/unit/record/headers_spec.rb +21 -0
- data/spec/unit/record/response_spec.rb +11 -0
- data/spec/unit/record_spec.rb +77 -0
- data/spec/unit/serializers/base_spec.rb +19 -0
- data/spec/unit/serializers/json_multiple_spec.rb +24 -0
- data/spec/unit/serializers/json_spec.rb +37 -0
- data/spec/unit/whisperer_spec.rb +189 -0
- data/whisperer.gemspec +28 -0
- metadata +277 -0
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
NDliMDRjMTM4ZDRiMDMyZDIwMTc1Y2U1NjBiZWNjNzdhYWM2ZjY3ZQ==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
YjQzMTBmMmMzZmIyYTQ4ZGRmZmZlM2ZiZTI1MjMwNjJmNGJkY2Q1Nw==
|
7
|
+
SHA512:
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
MzllODJkNDVmYzgyZTQzYzYzZjBhMWM4YmE2NmMzOWEwOGU0YmI2ZTdmMTEw
|
10
|
+
YzU2Y2E2MTg2ZGI2Njc3NTQ0N2I2YTU2YmFhZDc4NzdiZDk3ZTI5ZTFkN2Ix
|
11
|
+
ZGU5ZjJhMzc4NDkwM2U4NDljNmUyNmU5YjY3YzY2NzZjM2M2NDE=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
YTAwZjBlMzAwY2NmOTFlMmU1NGEwYzE4ODI3NWJmNjc0ZTIxNzNiMTAzMTNh
|
14
|
+
MTIxYzZiYTU4NzM2YzE5ZWZlNGFlMmIzNTIxOTYzN2U2NDNjMzIzNThmZDRm
|
15
|
+
N2NkZmJiZWIxMDQ5ZDdkMWEwNzI0ZThmYjg4OGFiMmM2Njg5YjI=
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Dmitriy Nesteryuk
|
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,293 @@
|
|
1
|
+
# Whisperer
|
2
|
+
|
3
|
+
[![Code Climate](https://codeclimate.com/github/dnesteryuk/whisperer/badges/gpa.svg)](https://codeclimate.com/github/dnesteryuk/whisperer)
|
4
|
+
[![Build Status](https://secure.travis-ci.org/dnesteryuk/whisperer.png?branch=master)](https://travis-ci.org/dnesteryuk/whisperer)
|
5
|
+
[![Dependency Status](https://gemnasium.com/dnesteryuk/whisperer.png)](https://gemnasium.com/dnesteryuk/whisperer)
|
6
|
+
|
7
|
+
Do you hate fixtures? I do as well. The purpose of this library is to make your life easier when your application works with external API and you use VCR to stub that API.
|
8
|
+
|
9
|
+
## Installation
|
10
|
+
|
11
|
+
**Requirments**:
|
12
|
+
- Ruby 2.0.x or 2.1.x
|
13
|
+
|
14
|
+
Add this line to your application's Gemfile:
|
15
|
+
|
16
|
+
gem 'whisperer'
|
17
|
+
|
18
|
+
And then execute:
|
19
|
+
|
20
|
+
$ bundle
|
21
|
+
|
22
|
+
Or install it yourself as:
|
23
|
+
|
24
|
+
$ gem install whisperer
|
25
|
+
|
26
|
+
To create default directories' structure and the config file with default options, you need to execute:
|
27
|
+
|
28
|
+
$ rake whisperer:install
|
29
|
+
|
30
|
+
It will create `cassette_builders` directory in your `spec` folder and `.whisperer.yml` file in your root directory of the project.
|
31
|
+
|
32
|
+
If you want to create only the config file, you need to execute:
|
33
|
+
|
34
|
+
$ rake whisperer:config:create
|
35
|
+
|
36
|
+
## Usage
|
37
|
+
|
38
|
+
### Describing VCR cassettes
|
39
|
+
|
40
|
+
VCR cassettes are described in `cassette builders`. It is Ruby DSL which repeats structure of VCR cassette:
|
41
|
+
|
42
|
+
```ruby
|
43
|
+
Whisperer.define(:arya_stark) do
|
44
|
+
request do
|
45
|
+
uri 'http://example.com/users/1'
|
46
|
+
method :get
|
47
|
+
end
|
48
|
+
|
49
|
+
response do
|
50
|
+
status do
|
51
|
+
code 200
|
52
|
+
message 'OK'
|
53
|
+
end
|
54
|
+
|
55
|
+
headers do
|
56
|
+
content_type 'application/json;charset=utf-8'
|
57
|
+
end
|
58
|
+
|
59
|
+
body do
|
60
|
+
encoding 'UTF-8'
|
61
|
+
factory 'arya_stark', :json
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
recorded_at 'Mon, 13 Jan 2014 21:01:47 GMT'
|
66
|
+
end
|
67
|
+
```
|
68
|
+
|
69
|
+
But, it is Ruby, hence, we can benefit from that. Whisperer uses [FactoryGirl](/thoughtbot/factory_girl) to describe a response body. If you are not familar with FactoryGirl, please, make sure, you know how to use it bofore going on. There are a few ways how factories can be used.
|
70
|
+
|
71
|
+
You can use one single factory:
|
72
|
+
|
73
|
+
```ruby
|
74
|
+
body do
|
75
|
+
factory 'arya_stark' # we provide only name of the factory
|
76
|
+
end
|
77
|
+
```
|
78
|
+
|
79
|
+
`arya_stark` factory is taken to generate the response body:
|
80
|
+
|
81
|
+
```
|
82
|
+
string: '{"first_name":"Arya","last_name":"Stark","group":"member"}'
|
83
|
+
```
|
84
|
+
|
85
|
+
You can use multiple factories to generate collection for your response:
|
86
|
+
|
87
|
+
```ruby
|
88
|
+
body do
|
89
|
+
factories ['robb_stark', 'ned_stark'] # again we provide only names of factories
|
90
|
+
end
|
91
|
+
```
|
92
|
+
|
93
|
+
`robb_stark` and `ned_stark` are taken to generate the response body:
|
94
|
+
|
95
|
+
```
|
96
|
+
string: '[{"first_name":"Robb","last_name":"Stark","group":"member"},{"first_name":"Ned","last_name":"Stark","group":"member"}]'
|
97
|
+
```
|
98
|
+
|
99
|
+
You can pass factory objects instead of their names:
|
100
|
+
|
101
|
+
```ruby
|
102
|
+
body do
|
103
|
+
factories = (1..20).to_a.map do |i|
|
104
|
+
factories << FactoryGirl.build(
|
105
|
+
:article,
|
106
|
+
id: 'testid' + i,
|
107
|
+
title: 'test name' + i,
|
108
|
+
body: 'desc' + i
|
109
|
+
)
|
110
|
+
end
|
111
|
+
|
112
|
+
raw_data factories, :json_multiple
|
113
|
+
end
|
114
|
+
```
|
115
|
+
|
116
|
+
It is very useful, when you need generate dynamically instances of a factory.
|
117
|
+
|
118
|
+
#### Inheritance in cassette builders
|
119
|
+
|
120
|
+
If you need to generate almost the same VCR cassette, but with a bit differ data, you can do it via inheritance:
|
121
|
+
|
122
|
+
```ruby
|
123
|
+
Whisperer.define(:robb_stark, parent: :arya_stark) do
|
124
|
+
response do
|
125
|
+
body do
|
126
|
+
factory :robb_stark
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
```
|
131
|
+
|
132
|
+
In this case all data is taken from `aray_stark` cassette builder, only the response body is different.
|
133
|
+
|
134
|
+
You can redefine any option of VCR cassette:
|
135
|
+
|
136
|
+
```ruby
|
137
|
+
Whisperer.define(:robb_stark, parent: :arya_stark) do
|
138
|
+
request do
|
139
|
+
uri 'http://example.com/users/10'
|
140
|
+
end
|
141
|
+
end
|
142
|
+
```
|
143
|
+
|
144
|
+
#### Request/Response Headers
|
145
|
+
|
146
|
+
While describing headers for a request or response you can use any kind of headers, they are dynamically created:
|
147
|
+
|
148
|
+
```ruby
|
149
|
+
headers do
|
150
|
+
content_length 100
|
151
|
+
content_type 'application/json'
|
152
|
+
x_requested_with 'XMLHttpRequest'
|
153
|
+
end
|
154
|
+
```
|
155
|
+
|
156
|
+
In a cassette it will look like:
|
157
|
+
|
158
|
+
```
|
159
|
+
Content-Length:
|
160
|
+
- '100'
|
161
|
+
Content-Type:
|
162
|
+
- application/json
|
163
|
+
X-Requested-With
|
164
|
+
- XMLHttpRequest
|
165
|
+
```
|
166
|
+
|
167
|
+
#### Placeholder for FactoryGirl
|
168
|
+
|
169
|
+
Since VCR is used to stub interractions with external services, there is a big chance that you don't have Ruby model to be used for defining factories. In most cases, you don't need them to generate VCR cassettes. Whisperer offers the placeholder class:
|
170
|
+
|
171
|
+
```ruby
|
172
|
+
FactoryGirl.define do
|
173
|
+
factory :arya_stark, class: Placeholder do
|
174
|
+
first_name 'Arya'
|
175
|
+
last_name 'Stark'
|
176
|
+
group 'member'
|
177
|
+
end
|
178
|
+
end
|
179
|
+
```
|
180
|
+
|
181
|
+
Placeholder is a simple class inheriting `OpenStruct` class:
|
182
|
+
|
183
|
+
```ruby
|
184
|
+
Placeholder = Class.new(OpenStruct)
|
185
|
+
```
|
186
|
+
|
187
|
+
It decouples factories from your application.
|
188
|
+
|
189
|
+
### Serializers for a response body
|
190
|
+
|
191
|
+
When an external API is subbed with VCR, API response has some format like Json, XML or any other formats. Whisperer supports possibility to convert factories into a format your external API uses. Such mechanism is provided by **serializers** which are used along with building a response body. Whisperer has only 2 serializers:
|
192
|
+
|
193
|
+
- json
|
194
|
+
- multiple json
|
195
|
+
|
196
|
+
`Json` serializer is used for serializing one single factory:
|
197
|
+
|
198
|
+
```ruby
|
199
|
+
response do
|
200
|
+
body do
|
201
|
+
factory :robb_stark
|
202
|
+
serializer :json
|
203
|
+
end
|
204
|
+
end
|
205
|
+
```
|
206
|
+
|
207
|
+
The purpose of `json `serializer is to convert a given factory into Json format.
|
208
|
+
|
209
|
+
`Multiple Json` serializer is used for serializing a collection of factories:
|
210
|
+
|
211
|
+
```ruby
|
212
|
+
body do
|
213
|
+
factories ['robb_stark', 'ned_stark']
|
214
|
+
serializer :json_multiple
|
215
|
+
end
|
216
|
+
```
|
217
|
+
|
218
|
+
It is very similar to `Json` serializer, but in this case it goes through the array, builds factories, serializes a received array of objects.
|
219
|
+
|
220
|
+
If you need to define your own serializer, it is very easy to do. At first you need to define your own serializer class inhering `Whisperer::Serializes::Base` class:
|
221
|
+
|
222
|
+
```ruby
|
223
|
+
class MySerializer < Whisperer::Serializers::Base
|
224
|
+
def serialize
|
225
|
+
do_something_with(@obj)
|
226
|
+
end
|
227
|
+
end
|
228
|
+
```
|
229
|
+
|
230
|
+
*Note:* `@obj` is an `OpenStruct` instance in this example.
|
231
|
+
|
232
|
+
Then you need to register the new serializer:
|
233
|
+
|
234
|
+
```ruby
|
235
|
+
Whisperer.register_serializer(:my_serializer, Serializers::MySerializer)
|
236
|
+
```
|
237
|
+
|
238
|
+
Now, it can be used as any other serializer:
|
239
|
+
|
240
|
+
```ruby
|
241
|
+
response do
|
242
|
+
body do
|
243
|
+
factory :robb_stark
|
244
|
+
serializer :my_serializer
|
245
|
+
end
|
246
|
+
end
|
247
|
+
```
|
248
|
+
|
249
|
+
### Configuration
|
250
|
+
|
251
|
+
You can configure Whisperer through `.whisperer.yml` which should be created in a root directory of your project. It gives you following options:
|
252
|
+
|
253
|
+
- generate_to - the path to save generated cassettes
|
254
|
+
- builders_matcher - the pattern to find builders
|
255
|
+
- factories_matcher - the pattern to find factories
|
256
|
+
|
257
|
+
Example of such file:
|
258
|
+
|
259
|
+
```
|
260
|
+
generate_to: 'spec/cassettes/vcr_cassettes/'
|
261
|
+
builders_matcher: './spec/cassette_builders/**/*.rb'
|
262
|
+
factories_matcher: './spec/factories/*.rb'
|
263
|
+
```
|
264
|
+
|
265
|
+
### Generating cassettes
|
266
|
+
|
267
|
+
To generate cassettes based on cassette builders, you need to launch command:
|
268
|
+
|
269
|
+
$ rake whisperer:cassettes:generate_all
|
270
|
+
|
271
|
+
This command will generate new cassettes and re-generate all existing cassettes for VCR.
|
272
|
+
|
273
|
+
To generate only on particular cassette, you can use this command
|
274
|
+
|
275
|
+
$ rake whisperer:cassettes:generate[cassette_builder]
|
276
|
+
|
277
|
+
`cassette_builder` is a name of the cassette builder.
|
278
|
+
|
279
|
+
### Generating a sample for the cassette builder
|
280
|
+
|
281
|
+
Manual creation of cassette builders is painful. There is a command which can help you with that:
|
282
|
+
|
283
|
+
$ rake whisperer:cassettes:builders:sample
|
284
|
+
|
285
|
+
It creates a sample for you in the directory with cassette builders, you need to edit it only.
|
286
|
+
|
287
|
+
## Contributing
|
288
|
+
|
289
|
+
1. Fork it
|
290
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
291
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
292
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
293
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/TODO.md
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
## Release 0.0.1
|
2
|
+
|
3
|
+
1. Add info to doc:
|
4
|
+
- subpath for generating cassettes
|
5
|
+
- factories for requests
|
6
|
+
|
7
|
+
## Release 0.0.2
|
8
|
+
|
9
|
+
1. Think about the better way for inheriting serializes, now it looks like:
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
class Whisperer::Serializers::Base
|
13
|
+
# ...
|
14
|
+
end
|
15
|
+
|
16
|
+
class Whisperer::Serializers::Json < Whisperer::Serializers::Base
|
17
|
+
# ...
|
18
|
+
end
|
19
|
+
|
20
|
+
class Whisperer::Serializers::JsonMultiple < Whisperer::Serializers::Json
|
21
|
+
# ...
|
22
|
+
end
|
23
|
+
```
|
24
|
+
|
25
|
+
If an user wants to inherit `Whisperer::Serializers::JsonMultiple` it will look even more crazy.
|
26
|
+
|
27
|
+
2. In most cases if we have a serializer for one single factory, we need a serializer for multiple factories. We need to write code which will create a multiple serializer automatically.
|
28
|
+
3. The Whisperer::Config.load method is too complex.
|
29
|
+
4. Create rake task for generating factories based on Vcr responses.
|
30
|
+
5. Try to find better way for defining dynamic attributes for headers, it doesn't work when you write:
|
31
|
+
|
32
|
+
```ruby
|
33
|
+
Whisperer::Record.new(
|
34
|
+
response: {
|
35
|
+
headers: {
|
36
|
+
content_length: 10
|
37
|
+
}
|
38
|
+
}
|
39
|
+
)
|
40
|
+
```
|
41
|
+
|
42
|
+
6. Refactore Whisperer::Record#merge_attrs! method, it should be moved to some another class
|
43
|
+
7. Refactore Whisperer.define method, it is another responsibility which should not leave in this module.
|
44
|
+
8. Think about the issue with touching Whisperer::cassette_records, it is not ok
|
45
|
+
9. `Whisperer::generate` and `Whisperer::generate_all` receive cassette records twice. Also, it is needless to check existence of a cassette record if it is passed from `generate_all` to `generate`.
|
46
|
+
10. Serializers must be stored similar to preprocessors (in the own module/class).
|
47
|
+
11. Check whether we can use a real model instead of OpenStruct while describing factories.
|
data/lib/whisperer.rb
ADDED
@@ -0,0 +1,102 @@
|
|
1
|
+
require 'whisperer/version'
|
2
|
+
|
3
|
+
require 'virtus'
|
4
|
+
require 'vcr'
|
5
|
+
|
6
|
+
require 'whisperer/config'
|
7
|
+
|
8
|
+
require 'whisperer/placeholder'
|
9
|
+
require 'whisperer/dsl'
|
10
|
+
require 'whisperer/helpers'
|
11
|
+
|
12
|
+
require 'whisperer/generator'
|
13
|
+
|
14
|
+
require 'whisperer/convertors/hash'
|
15
|
+
require 'whisperer/convertors/interaction'
|
16
|
+
|
17
|
+
require 'whisperer/serializers/json'
|
18
|
+
require 'whisperer/serializers/json_multiple'
|
19
|
+
|
20
|
+
require 'whisperer/preprocessors'
|
21
|
+
require 'whisperer/preprocessors/content_length'
|
22
|
+
require 'whisperer/preprocessors/response_body'
|
23
|
+
|
24
|
+
module Whisperer
|
25
|
+
@cassette_records = ThreadSafe::Hash.new
|
26
|
+
@serializers = ThreadSafe::Hash.new
|
27
|
+
|
28
|
+
class << self
|
29
|
+
attr_reader :cassette_records
|
30
|
+
attr_reader :serializers
|
31
|
+
|
32
|
+
def define(name, options = {}, &block)
|
33
|
+
dsl = Dsl.build
|
34
|
+
dsl.instance_eval &block
|
35
|
+
record = dsl.container
|
36
|
+
|
37
|
+
if options[:parent]
|
38
|
+
original_record = cassette_records[options[:parent]]
|
39
|
+
|
40
|
+
if original_record.nil?
|
41
|
+
raise ArgumentError.new("Parent record \"#{options[:parent]}\" is not declared.")
|
42
|
+
else
|
43
|
+
record.merge!(original_record)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
cassette_records[name.to_sym] = record
|
48
|
+
end
|
49
|
+
|
50
|
+
# Returns true if at least one factory is defined, otherwise returns false.
|
51
|
+
def defined_any?
|
52
|
+
cassette_records.size > 0
|
53
|
+
end
|
54
|
+
|
55
|
+
def generate(name)
|
56
|
+
name = name.to_sym
|
57
|
+
|
58
|
+
unless cassette_records[name]
|
59
|
+
raise NocassetteRecordError.new("There is not cassette builder with \"#{name}\" name.")
|
60
|
+
end
|
61
|
+
|
62
|
+
container = cassette_records[name]
|
63
|
+
|
64
|
+
Generator.generate(container, name)
|
65
|
+
end
|
66
|
+
|
67
|
+
def generate_all
|
68
|
+
if defined_any?
|
69
|
+
cassette_records.each do |name, container|
|
70
|
+
generate(name)
|
71
|
+
end
|
72
|
+
else
|
73
|
+
raise NocassetteRecordError.new('cassette builders are not found.')
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def serializer(name)
|
78
|
+
unless serializers[name]
|
79
|
+
raise ArgumentError.new("There is not serializer registered with \"#{name}\" name")
|
80
|
+
end
|
81
|
+
|
82
|
+
serializers[name]
|
83
|
+
end
|
84
|
+
|
85
|
+
def register_serializer(name, class_name)
|
86
|
+
serializers[name] = class_name
|
87
|
+
end
|
88
|
+
|
89
|
+
def register_preprocessor(name, class_name)
|
90
|
+
Preprocessors.register(name, class_name)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
class NocassetteRecordError < ArgumentError; end
|
95
|
+
end
|
96
|
+
|
97
|
+
|
98
|
+
Whisperer.register_serializer(:json, Whisperer::Serializers::Json)
|
99
|
+
Whisperer.register_serializer(:json_multiple, Whisperer::Serializers::JsonMultiple)
|
100
|
+
|
101
|
+
Whisperer::register_preprocessor(:response_body, Whisperer::Preprocessors::ResponseBody)
|
102
|
+
Whisperer::register_preprocessor(:content_length, Whisperer::Preprocessors::ContentLength)
|