whisperer 0.0.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.
Files changed (88) hide show
  1. checksums.yaml +15 -0
  2. data/.gitignore +17 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +13 -0
  5. data/Gemfile +7 -0
  6. data/LICENSE.txt +22 -0
  7. data/README.md +293 -0
  8. data/Rakefile +1 -0
  9. data/TODO.md +47 -0
  10. data/lib/whisperer.rb +102 -0
  11. data/lib/whisperer/config.rb +40 -0
  12. data/lib/whisperer/convertors/hash.rb +39 -0
  13. data/lib/whisperer/convertors/interaction.rb +21 -0
  14. data/lib/whisperer/dsl.rb +19 -0
  15. data/lib/whisperer/dsl/base.rb +47 -0
  16. data/lib/whisperer/dsl/body.rb +33 -0
  17. data/lib/whisperer/dsl/headers.rb +20 -0
  18. data/lib/whisperer/dsl/request.rb +15 -0
  19. data/lib/whisperer/dsl/response.rb +15 -0
  20. data/lib/whisperer/dsl/response/status.rb +10 -0
  21. data/lib/whisperer/generator.rb +43 -0
  22. data/lib/whisperer/helpers.rb +16 -0
  23. data/lib/whisperer/placeholder.rb +14 -0
  24. data/lib/whisperer/preprocessors.rb +19 -0
  25. data/lib/whisperer/preprocessors/base.rb +13 -0
  26. data/lib/whisperer/preprocessors/content_length.rb +17 -0
  27. data/lib/whisperer/preprocessors/response_body.rb +23 -0
  28. data/lib/whisperer/record.rb +48 -0
  29. data/lib/whisperer/record/body.rb +15 -0
  30. data/lib/whisperer/record/headers.rb +22 -0
  31. data/lib/whisperer/record/request.rb +16 -0
  32. data/lib/whisperer/record/response.rb +18 -0
  33. data/lib/whisperer/record/response/status.rb +10 -0
  34. data/lib/whisperer/samples/cassette_builder.rb +24 -0
  35. data/lib/whisperer/serializers/base.rb +24 -0
  36. data/lib/whisperer/serializers/json.rb +33 -0
  37. data/lib/whisperer/serializers/json_multiple.rb +14 -0
  38. data/lib/whisperer/tasks/whisperer.rake +88 -0
  39. data/lib/whisperer/version.rb +3 -0
  40. data/spec/cassette_builders/arya_stark.rb +26 -0
  41. data/spec/cassette_builders/bran_stark.rb +19 -0
  42. data/spec/cassette_builders/empty_robb_stark.rb +20 -0
  43. data/spec/cassette_builders/robb_stark.rb +30 -0
  44. data/spec/cassette_builders/robb_stark_without_content_length.rb +20 -0
  45. data/spec/cassette_builders/sansa_stark.rb +9 -0
  46. data/spec/cassette_builders/starks.rb +31 -0
  47. data/spec/cassette_builders/wolfs.rb +7 -0
  48. data/spec/cassettes/empty_robb_stark.yml +22 -0
  49. data/spec/cassettes/girls/arya_stark.yml +24 -0
  50. data/spec/cassettes/robb_stark.yml +28 -0
  51. data/spec/cassettes/robb_stark_without_content_length.yml +22 -0
  52. data/spec/cassettes/sansa_stark.yml +24 -0
  53. data/spec/cassettes/starks.yml +28 -0
  54. data/spec/cassettes/wolfs.yml +28 -0
  55. data/spec/factories/arya_stark.rb +7 -0
  56. data/spec/factories/bran_stark.rb +7 -0
  57. data/spec/factories/ned_stark.rb +7 -0
  58. data/spec/factories/robb_stark.rb +7 -0
  59. data/spec/factories/sansa_stark.rb +7 -0
  60. data/spec/integration/whisperer_spec.rb +51 -0
  61. data/spec/spec_helper.rb +25 -0
  62. data/spec/spec_integration_helper.rb +6 -0
  63. data/spec/support/cassettes.rb +16 -0
  64. data/spec/support/custom_serializer.rb +5 -0
  65. data/spec/unit/config_spec.rb +94 -0
  66. data/spec/unit/convertors/hash_spec.rb +59 -0
  67. data/spec/unit/convertors/interaction_spec.rb +46 -0
  68. data/spec/unit/dsl/base_spec.rb +99 -0
  69. data/spec/unit/dsl/body_spec.rb +73 -0
  70. data/spec/unit/dsl/headers_spec.rb +31 -0
  71. data/spec/unit/dsl/request_spec.rb +4 -0
  72. data/spec/unit/dsl/response_spec.rb +4 -0
  73. data/spec/unit/dsl/status_spec.rb +4 -0
  74. data/spec/unit/dsl_spec.rb +4 -0
  75. data/spec/unit/generator_spec.rb +77 -0
  76. data/spec/unit/helpers_spec.rb +38 -0
  77. data/spec/unit/preprocessors/content_length_spec.rb +39 -0
  78. data/spec/unit/preprocessors/response_body_spec.rb +55 -0
  79. data/spec/unit/preprocessors_spec.rb +8 -0
  80. data/spec/unit/record/headers_spec.rb +21 -0
  81. data/spec/unit/record/response_spec.rb +11 -0
  82. data/spec/unit/record_spec.rb +77 -0
  83. data/spec/unit/serializers/base_spec.rb +19 -0
  84. data/spec/unit/serializers/json_multiple_spec.rb +24 -0
  85. data/spec/unit/serializers/json_spec.rb +37 -0
  86. data/spec/unit/whisperer_spec.rb +189 -0
  87. data/whisperer.gemspec +28 -0
  88. 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
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --colour
2
+ --profile
data/.travis.yml ADDED
@@ -0,0 +1,13 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.1.4
4
+ - 2.1.3
5
+ - 2.1.2
6
+ - 2.1.1
7
+ - 2.1.0
8
+ - 2.0.0
9
+ matrix:
10
+ before_install:
11
+ - "export DISPLAY=:99.0"
12
+ - "sh -e /etc/init.d/xvfb start"
13
+ script: bundle exec rspec spec
data/Gemfile ADDED
@@ -0,0 +1,7 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in whisperer.gemspec
4
+ gemspec
5
+
6
+ gem 'rspec', '~> 3.1'
7
+ gem 'rake'
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)