Full Code of thoughtworks/pacto for AI

master a1bd9668deca cached
200 files
283.1 KB
74.7k tokens
581 symbols
1 requests
Download .txt
Showing preview only (327K chars total). Download the full file or copy to clipboard to get everything.
Repository: thoughtworks/pacto
Branch: master
Commit: a1bd9668deca
Files: 200
Total size: 283.1 KB

Directory structure:
gitextract__ymcm0w_/

├── .gitignore
├── .rspec
├── .rubocop.yml
├── .travis.yml
├── CONTRIBUTING.md
├── Gemfile
├── Guardfile
├── LICENSE.txt
├── Procfile
├── README.md
├── Rakefile
├── TODO.md
├── appveyor.yml
├── bin/
│   ├── pacto
│   └── pacto-server
├── changelog.md
├── docs/
│   ├── configuration.md
│   ├── consumer.md
│   ├── cops.md
│   ├── forensics.md
│   ├── generation.md
│   ├── rake_tasks.md
│   ├── rspec.md
│   ├── samples.md
│   ├── server.md
│   ├── server_cli.md
│   └── stenographer.md
├── features/
│   ├── configuration/
│   │   └── strict_matchers.feature
│   ├── evolve/
│   │   ├── README.md
│   │   └── existing_services.feature
│   ├── generate/
│   │   ├── README.md
│   │   └── generation.feature
│   ├── steps/
│   │   └── pacto_steps.rb
│   ├── stub/
│   │   ├── README.md
│   │   └── templates.feature
│   ├── support/
│   │   └── env.rb
│   └── validate/
│       ├── README.md
│       ├── meta_validation.feature
│       └── validation.feature
├── lib/
│   ├── pacto/
│   │   ├── actor.rb
│   │   ├── actors/
│   │   │   ├── from_examples.rb
│   │   │   └── json_generator.rb
│   │   ├── body_parsing.rb
│   │   ├── cli/
│   │   │   └── helpers.rb
│   │   ├── cli.rb
│   │   ├── consumer/
│   │   │   └── faraday_driver.rb
│   │   ├── consumer.rb
│   │   ├── contract.rb
│   │   ├── contract_factory.rb
│   │   ├── contract_files.rb
│   │   ├── contract_set.rb
│   │   ├── cops/
│   │   │   ├── body_cop.rb
│   │   │   ├── request_body_cop.rb
│   │   │   ├── response_body_cop.rb
│   │   │   ├── response_header_cop.rb
│   │   │   └── response_status_cop.rb
│   │   ├── cops.rb
│   │   ├── core/
│   │   │   ├── configuration.rb
│   │   │   ├── contract_registry.rb
│   │   │   ├── hook.rb
│   │   │   ├── http_middleware.rb
│   │   │   ├── investigation_registry.rb
│   │   │   ├── modes.rb
│   │   │   ├── pacto_request.rb
│   │   │   └── pacto_response.rb
│   │   ├── dash.rb
│   │   ├── erb_processor.rb
│   │   ├── errors.rb
│   │   ├── extensions.rb
│   │   ├── forensics/
│   │   │   ├── investigation_filter.rb
│   │   │   └── investigation_matcher.rb
│   │   ├── formats/
│   │   │   ├── legacy/
│   │   │   │   ├── contract.rb
│   │   │   │   ├── contract_builder.rb
│   │   │   │   ├── contract_factory.rb
│   │   │   │   ├── contract_generator.rb
│   │   │   │   ├── generator/
│   │   │   │   │   └── filters.rb
│   │   │   │   ├── generator_hint.rb
│   │   │   │   ├── request_clause.rb
│   │   │   │   └── response_clause.rb
│   │   │   └── swagger/
│   │   │       ├── contract.rb
│   │   │       ├── contract_factory.rb
│   │   │       ├── request_clause.rb
│   │   │       └── response_clause.rb
│   │   ├── generator.rb
│   │   ├── handlers/
│   │   │   ├── json_handler.rb
│   │   │   └── text_handler.rb
│   │   ├── hooks/
│   │   │   └── erb_hook.rb
│   │   ├── investigation.rb
│   │   ├── logger.rb
│   │   ├── meta_schema.rb
│   │   ├── observers/
│   │   │   └── stenographer.rb
│   │   ├── provider.rb
│   │   ├── rake_task.rb
│   │   ├── request_clause.rb
│   │   ├── request_pattern.rb
│   │   ├── resettable.rb
│   │   ├── response_clause.rb
│   │   ├── rspec.rb
│   │   ├── server/
│   │   │   ├── cli.rb
│   │   │   ├── config.rb
│   │   │   ├── proxy.rb
│   │   │   └── settings.rb
│   │   ├── server.rb
│   │   ├── stubs/
│   │   │   ├── uri_pattern.rb
│   │   │   └── webmock_adapter.rb
│   │   ├── test_helper.rb
│   │   ├── ui.rb
│   │   ├── uri.rb
│   │   └── version.rb
│   └── pacto.rb
├── pacto-server.gemspec
├── pacto.gemspec
├── resources/
│   ├── contract_schema.json
│   ├── draft-03.json
│   └── draft-04.json
├── sample_apis/
│   ├── album/
│   │   └── cover_api.rb
│   ├── config.ru
│   ├── echo_api.rb
│   ├── files_api.rb
│   ├── hello_api.rb
│   ├── ping_api.rb
│   ├── reverse_api.rb
│   └── user_api.rb
├── samples/
│   ├── README.md
│   ├── Rakefile
│   ├── configuration.rb
│   ├── consumer.rb
│   ├── contracts/
│   │   ├── README.md
│   │   ├── contract.js
│   │   ├── get_album_cover.json
│   │   ├── localhost/
│   │   │   └── api/
│   │   │       ├── echo.json
│   │   │       └── ping.json
│   │   └── user.json
│   ├── cops.rb
│   ├── forensics.rb
│   ├── generation.rb
│   ├── rake_tasks.sh
│   ├── rspec.rb
│   ├── samples.rb
│   ├── scripts/
│   │   ├── bootstrap
│   │   └── wrapper
│   ├── server.rb
│   ├── server_cli.sh
│   └── stenographer.rb
├── spec/
│   ├── coveralls_helper.rb
│   ├── fabricators/
│   │   ├── contract_fabricator.rb
│   │   ├── http_fabricator.rb
│   │   └── webmock_fabricator.rb
│   ├── fixtures/
│   │   └── contracts/
│   │       ├── deprecated/
│   │       │   └── deprecated_contract.json
│   │       ├── legacy/
│   │       │   ├── contract.json
│   │       │   ├── contract_with_examples.json
│   │       │   ├── simple_contract.json
│   │       │   ├── strict_contract.json
│   │       │   └── templating_contract.json
│   │       └── swagger/
│   │           └── petstore.yaml
│   ├── integration/
│   │   ├── e2e_spec.rb
│   │   ├── forensics/
│   │   │   └── integration_matcher_spec.rb
│   │   ├── rspec_spec.rb
│   │   └── templating_spec.rb
│   ├── spec_helper.rb
│   └── unit/
│       ├── actors/
│       │   ├── from_examples_spec.rb
│       │   └── json_generator_spec.rb
│       └── pacto/
│           ├── actor_spec.rb
│           ├── configuration_spec.rb
│           ├── consumer/
│           │   └── faraday_driver_spec.rb
│           ├── contract_factory_spec.rb
│           ├── contract_files_spec.rb
│           ├── contract_set_spec.rb
│           ├── contract_spec.rb
│           ├── cops/
│           │   ├── body_cop_spec.rb
│           │   ├── response_header_cop_spec.rb
│           │   └── response_status_cop_spec.rb
│           ├── cops_spec.rb
│           ├── core/
│           │   ├── configuration_spec.rb
│           │   ├── contract_registry_spec.rb
│           │   ├── http_middleware_spec.rb
│           │   ├── investigation_spec.rb
│           │   └── modes_spec.rb
│           ├── erb_processor_spec.rb
│           ├── extensions_spec.rb
│           ├── formats/
│           │   ├── legacy/
│           │   │   ├── contract_builder_spec.rb
│           │   │   ├── contract_factory_spec.rb
│           │   │   ├── contract_generator_spec.rb
│           │   │   ├── contract_spec.rb
│           │   │   ├── generator/
│           │   │   │   └── filters_spec.rb
│           │   │   ├── request_clause_spec.rb
│           │   │   └── response_clause_spec.rb
│           │   └── swagger/
│           │       ├── contract_factory_spec.rb
│           │       └── contract_spec.rb
│           ├── hooks/
│           │   └── erb_hook_spec.rb
│           ├── investigation_registry_spec.rb
│           ├── logger_spec.rb
│           ├── meta_schema_spec.rb
│           ├── pacto_spec.rb
│           ├── request_pattern_spec.rb
│           ├── stubs/
│           │   ├── observers/
│           │   │   └── stenographer_spec.rb
│           │   ├── uri_pattern_spec.rb
│           │   └── webmock_adapter_spec.rb
│           └── uri_spec.rb
└── tasks/
    └── release.rake

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================
*.gem
*.log
*.pid
*.rbc
.bundle
.config
.yardoc
Gemfile.lock
InstalledFiles
_yardoc
coverage
doc/
lib/bundler/man
pkg
rdoc
spec/reports
test/tmp
test/version_tmp
tmp
*.swp
*.swo
.idea/
.floo*
.sublime*
tags
pacto.log
.polytrix/


================================================
FILE: .rspec
================================================
--colour
--require spec_helper


================================================
FILE: .rubocop.yml
================================================
require: rubocop-rspec

Documentation:
  Enabled: false

DotPosition:
  Enabled: false

LineLength:
  Enabled: false

MethodLength:
  Max: 20

Style/Encoding:
  EnforcedStyle: when_needed

AllCops:
  Include:
    - Guardfile
    - '**/Rakefile'
    - pacto*.gemspec
  Exclude:
    - bin/**/*
    - tmp/**/*
RSpec/DescribeClass:
  Exclude:
    - samples/**/*
    - spec/integration/**/*
RSpec/MultipleDescribes:
  Exclude:
    - samples/**/*


================================================
FILE: .travis.yml
================================================
language: ruby
rvm:
  - 2.1.0
  - 2.0.0
  - 1.9.3
  # There is a bug in jruby-1.7.15
  # that is blocking testing
  - jruby
before_script:
  - gem install foreman
  - foreman start &
matrix:
  allow_failures:
    - rvm: jruby



================================================
FILE: CONTRIBUTING.md
================================================
# Contributing

You are welcome to contribute to Pacto and this guide will help you to:

- [Setup](#setup) all the needed dependencies in order to start hacking.
- Follow [conventions](#code-conventions) agreed among the project 
contributors.
- Follow Pacto's suggested [workflow](#workflow).
- [Submit](#submit-code) new code to the project.
- Run the automated suite of [tests](#run-tests) that is bundled with Pacto.
- Find easily code annotations for [technical debt](#technical-debt) (TODOs,
FIXMEs, etc)
- Be aware of some [troubleshooting tips](#troubleshooting) when running issues
with Pacto.

## <a name="workflow"></a>Development (suggested) workflow

Pacto comes with [`guard`](https://github.com/guard/guard) enabled, this means
that guard will trigger the tests after any change is made on the source code.
We try to keep the feedback loop as fast as we can, so you can be able to run
all the tests everytime you make a change on the project. If you want to follow
this workflow just run:

`bundle exec guard`

Guard will run first the static analysis and then will run the unit test related
with the file that was changed, later the integration test and last the user
journey tests.

## <a name="submit-code"></a>Submit code

Any contribution has to come from a Pull Request via GitHub, to do it just
follow these steps:

1. Fork it (`git clone git@github.com:thoughtworks/pacto.git`).
2. Create your feature branch (`git checkout -b my-new-feature`).
3. Commit your changes (`git commit -am 'Add some feature'`).
4. Verify that the tests are passing (`bundle exec rake`).
5. Push to the branch (`git push origin my-new-feature`).
6. Create new Pull Request.

## <a name="setup"></a>Setting up

You will need to have installed:

- Ruby 1.9.3 or greater installed.
- Bundler gem installed (`gem install bundler`).
- Install all the dependencies (`bundle install`).

## <a name="code-conventions"></a>Coding conventions

### Style guide

Contributing in a project among several authors could lead to different styles
of writting code. In order to create some basic baseline on the source code
Pacto comes with an static code analyzer that will enforce the code to follow
the [Ruby Style Guide](https://github.com/bbatsov/ruby-style-guide). To execute
the analyzer just run:

`bundle exec rubocop`

### Writing tests

Pacto unit tests and integration test are written in RSpec and the user journey
tests are written in Cucumber. For the RSpec tests we suggest to follow the
[Better Specs](http://betterspecs.org/) guideline.

## <a name="run-tests"></a>Running tests

Pacto comes with a set of automated tests. All the tests are runnable via rake
tasks:

- Unit tests (`bundle exec rake unit`).
- Integration tests (`bundle exec rake integration`).
- User journey tests (`bundle exec rake journeys`).

It is also possible run specific tests:

- Unit tests (`bundle exec rspec spec/unit/[file_path]`
- Integration tests  (`bundle exec rspec spec/integration/[file_path]`)
- User journey tests (`bundle exec cucumber features/[file_path] -r features/support/env.rb`)

### Checking that all is green

To know that both tests and static analysis is working fine you just have to
run:

`bundle exec rake`

## <a name="technical-debt"></a>Technical Debt

Some of the code in Pacto is commented with the anotations TODO or
FIXME that might point to some potencial technical debt on the source code. If
you are interested to list where are all these, just run:

`bundle exec notes`

## <a name="troubleshooting"></a>Troubleshooting

### Debugging pacto

If you run into some strange behaviour that Pacto might have, you can take
advantage of the debugging capabilities of Pacto. Running the tests with the
environment variable PACTO_DEBUG=true will show (on the standard output) more
details what Pacto is doing behind the scenes.

### Gemfile.lock

Because Pacto is a gem we don't include the Gemfile.lock into the repository
([here is the reason](http://yehudakatz.com/2010/12/16/clarifying-the-roles-of-the-gemspec-and-gemfile/)).
This could lead to some problems in your daily job as contributor specially
when there is an upgrade in any of the gems that Pacto depends upon. That is
why we recomend you to remove the Gemfile.lock and generate it
(`bundle install`) everytime there are changes on the dependencies.



================================================
FILE: Gemfile
================================================
source 'https://rubygems.org'

# Specify your gem's dependencies in pacto.gemspec
gemspec name: 'pacto'
gemspec name: 'pacto-server'

# This is only used by Relish tests.  Putting it here let's travis
# pre-install so we can speed up the test with `bundle install --local`,
# avoiding Aruba timeouts.
gem 'excon'
gem 'octokit'

group :samples do
  gem 'grape'
  gem 'grape-swagger'
  gem 'puma'
  gem 'rake'
  gem 'pry'
  gem 'rack'
end


================================================
FILE: Guardfile
================================================
# vim: syntax=ruby filetype=ruby

guard :rubocop, all_on_start: false do
  watch(/.+\.rb$/)
  watch(/\.gemspec$/)
  watch('Guardfile')
  watch('Rakefile')
  watch('.rubocop.yml')      { '.' }
  watch('.rubocop-todo.yml') { '.' }
end

group :tests, halt_on_fail: true do
  guard :rspec, cmd: 'bundle exec rspec' do
    # Unit tests
    watch(%r{^spec/unit/.+_spec\.rb$})
    watch(/^lib\/(.+)\.rb$/)             { |_m| 'spec/unit/#{m[1]}_spec.rb' }
    watch('spec/spec_helper.rb')         { 'spec/unit' }
    watch('spec/unit/spec_helper.rb')    { 'spec/unit' }
    watch(%r{^spec/unit/data/.+\.json$}) { 'spec/unit' }

    # Integration tests
    watch(%r{^spec/integration/.+_spec\.rb$})
    watch(%r{^spec/integration/utils/.+\.rb$})  { 'spec/integration' }
    watch(/^lib\/.+\.rb$/)                       { 'spec/integration' }
    watch('spec/spec_helper.rb')                { 'spec/integration' }
    watch('spec/integration/spec_helper.rb')    { 'spec/integration' }
    watch(%r{^spec/integration/data/.+\.json$}) { 'spec/integration' }
  end

  guard :cucumber, cmd: 'bundle exec cucumber', all_on_start: false do
    watch(/^features\/.+\.feature$/)
    watch(%r{^features/support/.+$})                      { 'features' }
    watch(%r{^features/step_definitions/(.+)_steps\.rb$}) { |_m| Dir[File.join('**/#{m[1]}.feature')][0] || 'features' }
  end
end


================================================
FILE: LICENSE.txt
================================================
Copyright (c) 2013 ThoughtWorks Brasil & Abril Midia

MIT License

Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

================================================
FILE: Procfile
================================================
sample_apis: sh -c 'bundle exec rackup -s puma -o localhost -p $PORT sample_apis/config.ru'


================================================
FILE: README.md
================================================
[![Gem Version](https://badge.fury.io/rb/pacto.png)](http://badge.fury.io/rb/pacto)
[![Build Status](https://travis-ci.org/thoughtworks/pacto.png)](https://travis-ci.org/thoughtworks/pacto)
[![Code Climate](https://codeclimate.com/github/thoughtworks/pacto.png)](https://codeclimate.com/github/thoughtworks/pacto)
[![Dependency Status](https://gemnasium.com/thoughtworks/pacto.png)](https://gemnasium.com/thoughtworks/pacto)
[![Coverage Status](https://coveralls.io/repos/thoughtworks/pacto/badge.png)](https://coveralls.io/r/thoughtworks/pacto)

**Pacto is currently INACTIVE. Unfortunately none of the maintainers have had enough time to maintain it. While we feel that Pacto had good ideas, we also feel that a lot has changed since Pacto was first conceived (including the [OpenAPIs initiative](https://openapis.org/)) and that too much work would be required to maintain & update Pacto. Instead, we encourage others to use other projects that have focused on Consumer-Driven Contracts, like [Pact](https://github.com/realestate-com-au/pact), or to write their own Pacto-inspired project.**

# [INACTIVE] Pacto

Pacto is a judge that arbitrates contract disputes between a **service provider** and one or more **consumers**.  In other words, it is a framework for [Integration Contract Testing](http://martinfowler.com/bliki/IntegrationContractTest.html), and helps guide service evolution patterns like [Consumer-Driven Contracts](http://thoughtworks.github.io/pacto/patterns/cdc/) or [Documentation-Driven Contracts](http://thoughtworks.github.io/pacto/patterns/documentation_driven/).

Pacto considers two major terms in order decide if there has been a breach of contract: the **request clause** and the **response clause**.

The **request clause** defines what information must be sent by the **consumer** to the **provider** in order to compel them to render a service.  The request clause often describes the required HTTP request headers like `Content-Type`, the required parameters, and the required request body (defined in [json-schema](http://json-schema.org/)) when applicable.  Providers are not held liable for failing to deliver services for invalid requests.

The **response clause** defines what information must be returned by the **provider** to the **consumer** in order to successfully complete the transaction.  This commonly includes HTTP response headers like `Location` as well as the required response body (also defined in [json-schema](http://json-schema.org/)).

## Test Doubles

The consumer may also enter into an agreement with **test doubles** like [WebMock](http://robots.thoughtbot.com/how-to-stub-external-services-in-tests), [vcr](https://github.com/vcr/vcr) or [mountebank](http://www.mbtest.org/).  The services delivered by the **test doubles** for the purposes of development and testing will be held to the same conditions as the service the final services rendered by the parent **provider**.  This prevents misrepresentation of sample services as realistic, leading to damages during late integration.

Pacto can provide a [**test double**](#stubbing) if you cannot afford your own.

## Due Diligence

Pacto usually makes it clear if the **consumer** or **provider** is at fault, but if a contract is too vague Pacto cannot assign blame, and if it is too specific the matter may become litigious.

Pacto can provide a [**contract writer**](#generating) that tries to strike a balance, but you may still need to adjust the terms.

## Implied Terms

- Pacto only arbitrates contracts for JSON services.
- Pacto requires Ruby 1.9.3 or newer, though you can use [Polyglot Testing](http://thoughtworks.github.io/pacto/patterns/polyglot/) techniques to support older Rubies and non-Ruby projects.

## Roadmap

- The **test double** provided by Pacto is only semi-competent.  It handles simple cases, but we expect to find a more capable replacement in the near future.
- Pacto will provide additional Contract Writers for converting from apiblueprint, WADL, or other documentation formats in the future.  It's part of our goal to support [Documentation-Driven Contracts](http://thoughtworks.github.io/pacto/patterns/documentation_driven/)
- Pacto reserves the right to consider other clauses in the future, like security and compliance to industry specifications.

## Usage

**See also: http://thoughtworks.github.io/pacto/usage/**

Pacto can perform three activities: generating, validating, or stubbing services.  You can do each of these activities against either live or stubbed services.

You can also use [Pacto Server](#pacto-server-non-ruby-usage) if you are working with non-Ruby projects.

### Configuration

In order to start with Pacto, you just need to require it and optionally customize the default [Configuration](docs/configuration.md).  For example:

```ruby
require 'pacto'

Pacto.configure do |config|
  config.contracts_path = 'contracts'
end
```

### Generating

The easiest way to get started with Pacto is to run a suite of live tests and tell Pacto to generate the contracts:

```ruby
Pacto.generate!
# run your tests
```

If you're using the same configuration as above, this will produce Contracts in the contracts/ folder.

We know we cannot generate perfect Contracts, especially if we only have one sample request.  So we do our best to give you a good starting point, but you will likely want to customize the contract so the validation is more strict in some places and less strict in others.

### Contract Lists

In order to stub or validate a group of contracts you need to create a ContractList.
A ContractList represent a collection of endpoints attached to the same host.

```ruby
require 'pacto'

default_contracts = Pacto.load_contracts('contracts/services', 'http://example.com')
authentication_contracts = Pacto.load_contracts('contracts/auth', 'http://example.com')
legacy_contracts = Pacto.load_contracts('contracts/legacy', 'http://example.com')
```

### Validating

Once you have a ContractList, you can validate all the contracts against the live host.

```ruby
contracts = Pacto.load_contracts('contracts/services', 'http://example.com')
contracts.simulate_consumers
```

This method will hit the real endpoint, with a request created based on the request part of the contract.  
The response will be compared against the response part of the contract and any structural difference will
generate a validation error.

Running this in your build pipeline will ensure that your contracts actually match the real world, and that
you can run your acceptance tests against the contract stubs without worries.

### Stubbing

To generate stubs based on a ContractList you can run:

```ruby
contracts = Pacto.load_contracts('contracts/services', 'http://example.com')
contracts.stub_providers
```

This method uses webmock to ensure that whenever you make a request against one of contracts you actually get a stubbed response,
based on the default values specified on the contract, instead of hitting the real provider.

You can override any default value on the contracts by providing a hash of optional values to the stub_providers method. This
will override the keys for every contract in the list

```ruby
contracts = Pacto.load_contracts('contracts/services', 'http://example.com')
contracts.stub_providers(request_id: 14, name: "Marcos")
```

## Pacto Server (non-Ruby usage)

**See also: http://thoughtworks.github.io/pacto/patterns/polyglot/**

We've bundled a small server that embeds pacto so you can use it for non-Ruby projects.  If you want to take advantage of the full features, you'll still need to use Ruby (usually rspec) to drive your API testing.  You can run just the server in order to stub or to write validation issues to a log, but you won't have access to the full API fail your tests if there were validation problems.

### Command-line

The command-line version of the server will show you all the options.  These same options are used when you launch the server from within rspec.  In order to see the options:
`bundle exec pacto-server --help`

Some examples:
```sh
$ bundle exec pacto-server -sv --generate
# Runs a server that will generate Contracts for each request received
$ bundle exec pacto-server -sv --stub --validate
# Runs the server that provides stubs and checks them against Contracts
$ bundle exec pacto-server -sv --live --validate --host
# Runs the server that acts as a proxy to http://example.com, validating each request/response against a Contract
```

### RSpec test helper

You can also launch a server from within an rspec test.  The server does start up an external port and runs asynchronously so it doens't block your main test thread from kicking off your consumer code.  This gives you an externally accessable server that non-Ruby clients can hit, but still gives you the full Pacto API in order to validate and spy on HTTP interactions.

Example usage of the rspec test helper:
```ruby
require 'rspec'
require 'pacto/rspec'
require 'pacto/test_helper'

describe 'my consumer' do
  include Pacto::TestHelper

  it 'calls a service' do
    with_pacto(
      :port => 5000,
      :directory => '../spec/integration/data',
      :stub => true) do |pacto_endpoint|
      # call your code
      system "curl #{pacto_endpoint}/echo"
      # check results
      expect(Pacto).to have_validated(:get, 'https://localhost/echo')
    end
  end
end
```

## Rake Tasks

Pacto includes a few Rake tasks to help with common tasks.  If you want to use these tasks, just add this top your Rakefile:

```ruby
require 'pacto/rake_task'
```

This should add several new tasks to you project:
```sh
rake pacto:generate[input_dir,output_dir,host]  # Generates contracts from partial contracts
rake pacto:meta_validate[dir]                   # Validates a directory of contract definitions
rake pacto:validate[host,dir]                   # Validates all contracts in a given directory against a given host
```

The pacto:generate task will take partially defined Contracts and generate the missing pieces.  See [Generate](docs/generation.md) for more details.

The pacto:meta_validate task makes sure that your Contracts are valid.  It only checks the Contracts, not the services that implement them.

The pacto:validate task sends a request to an actual provider and ensures their response complies with the Contract.

## Contracts

Pacto works by associating a service with a Contract.  The Contract is a JSON description of the service that uses json-schema to describe the response body.  You don't need to write your contracts by hand.  In fact, we recommend generating a Contract from your documentation or a service.

A contract is composed of a request that has:

- Method: the method of the HTTP request (e.g. GET, POST, PUT, DELETE);
- Path: the relative path (without host) of the provider's endpoint;
- Headers: headers sent in the HTTP request;
- Params: any data or parameters of the HTTP request (e.g. query string for GET, body for POST).

And a response has that has:

- Status: the HTTP response status code (e.g. 200, 404, 500);
- Headers: the HTTP response headers;
- Body: a JSON Schema defining the expected structure of the HTTP response body.

Below is an example contract for a GET request
to the /hello_world endpoint of a provider:

```json
{
  "request": {
    "method": "GET",
    "path": "/hello_world",
    "headers": {
      "Accept": "application/json"
    },
    "params": {}
  },

  "response": {
    "status": 200,
    "headers": {
      "Content-Type": "application/json"
    },
    "body": {
      "description": "A simple response",
      "type": "object",
      "properties": {
        "message": {
          "type": "string"
        }
      }
    }
  }
}
```

## Constraints

- Pacto only works with JSON services
- Pacto requires Ruby 1.9.3 or newer (though you can older Rubies or non-Ruby projects with a [Pacto Server](#pacto-server-non-ruby-usage))
- Pacto cannot currently specify multiple acceptable status codes (e.g. 200 or 201)

## Contributing

Read the [CONTRIBUTING.md](CONTRIBUTING.md) file.


================================================
FILE: Rakefile
================================================
require 'rspec/core/rake_task'
require 'cucumber'
require 'cucumber/rake/task'
require 'coveralls/rake/task'
require 'rubocop/rake_task'
require 'rake/notes/rake_task'
require 'rake/packagetask'
Dir.glob('tasks/*.rake').each { |r| import r }
Coveralls::RakeTask.new

require 'pacto/rake_task' # FIXME: This require turns on WebMock
WebMock.allow_net_connect!

RuboCop::RakeTask.new(:rubocop) do |task|
  task.fail_on_error = true
end

Cucumber::Rake::Task.new(:journeys) do |t|
  t.cucumber_opts = 'features --format progress'
end

RSpec::Core::RakeTask.new(:unit) do |t|
  t.pattern = 'spec/unit/**/*_spec.rb'
end

RSpec::Core::RakeTask.new(:integration) do |t|
  t.pattern = 'spec/integration/**/*_spec.rb'
end

task default: [:unit, :integration, :journeys, :samples, :rubocop, 'coveralls:push']

%w(unit integration journeys samples).each do |taskname|
  task taskname => 'smoke_test_services'
end

desc 'Run the samples'
task :samples do
  FileUtils.rm_rf('samples/tmp')
  sh 'bundle exec polytrix exec --solo=samples --solo-glob="*.{rb,sh}"'
  sh 'bundle exec polytrix generate code2doc --solo=samples --solo-glob="*.{rb,sh}"'
end

desc 'Build gems into the pkg directory'
task :build do
  FileUtils.rm_rf('pkg')
  Dir['*.gemspec'].each do |gemspec|
    system "gem build #{gemspec}"
  end
  FileUtils.mkdir_p('pkg')
  FileUtils.mv(Dir['*.gem'], 'pkg')
end

Rake::PackageTask.new('pacto_docs', Pacto::VERSION) do |p|
  p.need_zip = true
  p.need_tar = true
  p.package_files.include('docs/**/*')
end

def changelog
  changelog = File.read('CHANGELOG').split("\n\n\n", 2).first
  confirm 'Does the CHANGELOG look correct? ', changelog
end

def confirm(question, data)
  puts 'Please confirm...'
  puts data
  print question
  abort 'Aborted' unless $stdin.gets.strip == 'y'
  puts 'Confirmed'
  data
end

desc 'Make sure the sample services are running'
task :smoke_test_services do
  require 'faraday'
  begin
    retryable(tries: 5, sleep: 1) do
      Faraday.get('http://localhost:5000/api/ping')
    end
  rescue
    abort 'Could not connect to the demo services, please start them with `foreman start`'
  end
end

# Retries a given block a specified number of times in the
# event the specified exception is raised. If the retries
# run out, the final exception is raised.
#
# This code is slightly adapted from https://github.com/mitchellh/vagrant/blob/master/lib/vagrant/util/retryable.rb,
# which is in turn adapted slightly from the following blog post:
# http://blog.codefront.net/2008/01/14/retrying-code-blocks-in-ruby-on-exceptions-whatever/
def retryable(opts = nil)
  opts   = { tries: 1, on: Exception }.merge(opts || {})

  begin
    return yield
  rescue *opts[:on] => e
    if (opts[:tries] -= 1) > 0
      $stderr.puts("Retryable exception raised: #{e.inspect}")

      sleep opts[:sleep].to_f if opts[:sleep]
      retry
    end
    raise
  end
end


================================================
FILE: TODO.md
================================================
# TODO

# v0.4

## Thor
- Kill rake tasks, replace w/ pacto binary
- Split Pacto server to separate repo??

## Swagger converter
- Legacy contracts -> Swagger

## Swagger concepts not yet supported by Pacto
- Support schemes (multiple)
- Support multiple report types
- Validate parameters
- Support Swagger formats/serializations
- Support Swagger examples, or extension for examples

## Documentation

- Polytrix samples -> docs

# v0.5

## Swagger
- Support multiple media types (not just JSON)
- Extension: templates for more advanced stubbing
- Patterns: detect creation, auto-delete
- Configure multiple producers: pacto server w/ multiple ports

# v0.6

## Nice to have


# Someday

- Pretty output for hash difference (using something like [hashdiff](https://github.com/liufengyun/hashdiff)).
- A default header in the response marking the response as "mocked"

## Assumptions

- JSON Schema references are stored in the 'definitions' attribute, in the schema's root element.


================================================
FILE: appveyor.yml
================================================
version: 0.0.{build}
init:
- choco install openssl.light
- gem install bundler --quiet --no-ri --no-rdoc
- gem install foreman --quiet --no-ri --no-rdoc
install:
- bundle install
build: off
test_script:
- START /B foreman start
- bundle exec rake



================================================
FILE: bin/pacto
================================================
#!/usr/bin/env ruby
require 'pacto/cli'

Pacto::CLI::Main.start


================================================
FILE: bin/pacto-server
================================================
#!/usr/bin/env ruby
require 'pacto/server/cli'

Pacto::Server::CLI.start


================================================
FILE: changelog.md
================================================
## 0.3.2

  *New Features:*
    - #105: Add pacto-server for non-ruby tests.  Use the pacto-server gem.

  *Breaking Changes:*
    
    - #107: Change default URI pattern to be less greedy.
      /magazine will now not match also /magazine/last_edition.
      query parameters after ? are still a match (ie /magazine?lastest=true)

  *Bug Fixes:*
    
    - #106: Remove dead, undocumented tag feature


## 0.3.1

  *Enhancements:*
    
    - #103: Display file URI instead of meaningless schema identifier in messages

  *Bug Fixes:*
    
    - #102: - Fix rake pacto:generate task


## 0.3.0

  First stable release


================================================
FILE: docs/configuration.md
================================================
Just require pacto to add it to your project.

```rb
require 'pacto'
```

Pacto will disable live connections, so you will get an error if
your code unexpectedly calls an service that was not stubbed.  If you
want to re-enable connections, run `WebMock.allow_net_connect!`

```rb
WebMock.allow_net_connect!
```

Pacto can be configured via a block:

```rb
Pacto.configure do |c|
```

Path for loading/storing contracts.

```rb
  c.contracts_path = 'contracts'
```

If the request matching should be strict (especially regarding HTTP Headers).

```rb
  c.strict_matchers = true
```

You can set the Ruby Logger used by Pacto.

```rb
  c.logger = Pacto::Logger::SimpleLogger.instance
```

(Deprecated) You can specify a callback for post-processing responses.  Note that only one hook
can be active, and specifying your own will disable ERB post-processing.

```rb
  c.register_hook do |_contracts, request, _response|
    puts "Received #{request}"
  end
```

Options to pass to the [json-schema-generator](https://github.com/maxlinc/json-schema-generator) while generating contracts.

```rb
  c.generator_options = { schema_version: 'draft3' }
end
```

You can also do inline configuration.  This example tells the json-schema-generator to store default values in the schema.

```rb
Pacto.configuration.generator_options = { defaults: true }
```

If you're using Pacto's rspec matchers you might want to configure a reset between each scenario

```rb
require 'pacto/rspec'
RSpec.configure do |c|
  c.after(:each)  { Pacto.clear! }
end
```



================================================
FILE: docs/consumer.md
================================================

```rb
require 'pacto'
Pacto.load_contracts 'contracts', 'http://localhost:5000'
WebMock.allow_net_connect!

interactions = Pacto.simulate_consumer :my_client do
  request 'Ping'
  request 'Echo', body: ->(body) { body.reverse },
                  headers: (proc do |headers|
                    headers['Content-Type'] = 'text/json'
                    headers['Accept'] = 'none'
                    headers
                  end)
end
puts interactions
```



================================================
FILE: docs/cops.md
================================================

```rb
require 'pacto'
Pacto.configure do |c|
  c.contracts_path = 'contracts'
end
Pacto.validate!
```

You can create a custom cop that investigates the request/response and sees if it complies with a
contract. The cop should return a list of citations if it finds any problems.

```rb
class MyCustomCop
  def investigate(_request, _response, contract)
    citations = []
    citations << 'Contract must have a request schema' if contract.request.schema.empty?
    citations << 'Contract must have a response schema' if contract.response.schema.empty?
    citations
  end
end

Pacto::Cops.active_cops << MyCustomCop.new

contracts = Pacto.load_contracts('contracts', 'http://localhost:5000')
contracts.stub_providers
puts contracts.simulate_consumers
```

Or you can completely replace the default set of validators

```rb
Pacto::Cops.registered_cops.clear
Pacto::Cops.register_cop Pacto::Cops::ResponseBodyCop

contracts = Pacto.load_contracts('contracts', 'http://localhost:5000')
puts contracts.simulate_consumers
```



================================================
FILE: docs/forensics.md
================================================
Pacto has a few RSpec matchers to help you ensure a **consumer** and **producer** are
interacting properly. First, let's setup the rspec suite.

```rb
require 'rspec/autorun' # Not generally needed
require 'pacto/rspec'
WebMock.allow_net_connect!
Pacto.validate!
Pacto.load_contracts('contracts', 'http://localhost:5000').stub_providers
```

It's usually a good idea to reset Pacto between each scenario. `Pacto.reset` just clears the
data and metrics about which services were called. `Pacto.clear!` also resets all configuration
and plugins.

```rb
RSpec.configure do |c|
  c.after(:each)  { Pacto.reset }
end
```

Pacto provides some RSpec matchers related to contract testing, like making sure
Pacto didn't received any unrecognized requests (`have_unmatched_requests`) and that
the HTTP requests matched up with the terms of the contract (`have_failed_investigations`).

```rb
describe Faraday do
  let(:connection) { described_class.new(url: 'http://localhost:5000') }

  it 'passes contract tests' do
    connection.get '/api/ping'
    expect(Pacto).to_not have_failed_investigations
    expect(Pacto).to_not have_unmatched_requests
  end
end
```

There are also some matchers for collaboration testing, so you can make sure each scenario is
calling the expected services and sending the right type of data.

```rb
describe Faraday do
  let(:connection) { described_class.new(url: 'http://localhost:5000') }
  before(:each) do
    connection.get '/api/ping'

    connection.post do |req|
      req.url '/api/echo'
      req.headers['Content-Type'] = 'application/json'
      req.body = '{"foo": "bar"}'
    end
  end

  it 'calls the ping service' do
    expect(Pacto).to have_validated(:get, 'http://localhost:5000/api/ping').against_contract('Ping')
  end

  it 'sends data to the echo service' do
    expect(Pacto).to have_investigated('Ping').with_response(body: hash_including('ping' => 'pong - from the example!'))
    expect(Pacto).to have_investigated('Echo').with_request(body: hash_including('foo' => 'bar'))
    echoed_body = { 'foo' => 'bar' }
    expect(Pacto).to have_investigated('Echo').with_request(body: echoed_body).with_response(body: echoed_body)
  end
end
```



================================================
FILE: docs/generation.md
================================================
Some generation related [configuration](configuration.rb).

```rb
require 'pacto'
WebMock.allow_net_connect!
Pacto.configure do |c|
  c.contracts_path = 'contracts'
end
WebMock.allow_net_connect!
```

Once we call `Pacto.generate!`, Pacto will record contracts for all requests it detects.

```rb
Pacto.generate!
```

Now, if we run any code that makes an HTTP call (using an
[HTTP library supported by WebMock](https://github.com/bblimke/webmock#supported-http-libraries))
then Pacto will generate a Contract based on the HTTP request/response.

This code snippet will generate a Contract and save it to `contracts/samples/contracts/localhost/api/ping.json`.

```rb
require 'faraday'
conn = Faraday.new(url: 'http://localhost:5000')
response = conn.get '/api/ping'
```

We're getting back real data from GitHub, so this should be the actual file encoding.

```rb
puts response.body
```

The generated contract will contain expectations based on the request/response we observed,
including a best-guess at an appropriate json-schema.  Our heuristics certainly aren't foolproof,
so you might want to customize schema!
Here's another sample that sends a post request.

```rb
conn.post do |req|
  req.url '/api/echo'
  req.headers['Content-Type'] = 'application/json'
  req.body = '{"red fish": "blue fish"}'
end
```

You can provide hints to Pacto to help it generate contracts. For example, Pacto doesn't have
a good way to know a good name and correct URI template for the service. That means that Pacto
will not know if two similar requests are for the same service or two different services, and
will be forced to give names based on the URI that are not good display names.
The hint below tells Pacto that requests to http://localhost:5000/album/1/cover and http://localhost:5000/album/2/cover
are both going to the same service, which is known as "Get Album Cover". This hint will cause Pacto to
generate a Contract for "Get Album Cover" and save it to `contracts/get_album_cover.json`, rather than two
contracts that are stored at `contracts/localhost/album/1/cover.json` and `contracts/localhost/album/2/cover.json`.

```rb
Pacto::Generator.configure do |c|
  c.hint 'Get Album Cover', http_method: :get, host: 'http://localhost:5000', path: '/api/album/{id}/cover'
end
conn.get '/api/album/1/cover'
conn.get '/api/album/2/cover'
```



================================================
FILE: docs/rake_tasks.md
================================================
# Rake tasks
## This is a test!
[That](www.google.com) markdown works

```sh
bundle exec rake pacto:meta_validate['contracts']

bundle exec rake pacto:validate['http://localhost:5000','contracts']
```



================================================
FILE: docs/rspec.md
================================================


================================================
FILE: docs/samples.md
================================================
# Overview
Welcome to the Pacto usage samples!
This document gives a quick overview of the main features.

You can browse the Table of Contents (upper right corner) to view additional samples.

In addition to this document, here are some highlighted samples:
<ul>
  <li><a href="configuration">Configuration</a>: Shows all available configuration options</li>
  <li><a href="generation">Generation</a>: More details on generation</li>
  <li><a href="rspec">RSpec</a>: More samples for RSpec expectations</li>
</ul>
You can also find other samples using the Table of Content (upper right corner), including sample contracts.
# Getting started
Once you've installed the Pacto gem, you just require it.  If you want, you can also require the Pacto rspec expectations.

```rb
require 'pacto'
require 'pacto/rspec'
```

Pacto will disable live connections, so you will get an error if
your code unexpectedly calls an service that was not stubbed.  If you
want to re-enable connections, run `WebMock.allow_net_connect!`

```rb
WebMock.allow_net_connect!
```

Pacto can be configured via a block.  The `contracts_path` option tells Pacto where it should load or save contracts.  See the [Configuration](configuration.html) for all the available options.

```rb
Pacto.configure do |c|
  c.contracts_path = 'contracts'
end
```

# Generating a Contract
Calling `Pacto.generate!` enables contract generation.
Pacto.generate!
Now, if we run any code that makes an HTTP call (using an
[HTTP library supported by WebMock](https://github.com/bblimke/webmock#supported-http-libraries))
then Pacto will generate a Contract based on the HTTP request/response.

We're using the sample APIs in the sample_apis directory.

```rb
require 'faraday'
conn = Faraday.new(url: 'http://localhost:5000')
response = conn.get '/api/ping'
```

This is the real request, so you should see {"ping":"pong"}

```rb
puts response.body
```

# Testing providers by simulating consumers
The generated contract will contain expectations based on the request/response we observed,
including a best-guess at an appropriate json-schema.  Our heuristics certainly aren't foolproof,
so you might want to modify the output!
We can load the contract and validate it, by sending a new request and making sure
the response matches the JSON schema.  Obviously it will pass since we just recorded it,
but if the service has made a change, or if you alter the contract with new expectations,
then you will see a contract investigation message.

```rb
contracts = Pacto.load_contracts('contracts', 'http://localhost:5000')
contracts.simulate_consumers
```

# Stubbing providers for consumer testing
We can also use Pacto to stub the service based on the contract.

```rb
contracts.stub_providers
```

The stubbed data won't be very realistic, the default behavior is to return the simplest data
that complies with the schema.  That basically means that you'll have "bar" for every string.

```rb
response = conn.get '/api/ping'
```

You're now getting stubbed data.  You should see {"ping":"bar"} unless you recorded with
the `defaults` option enabled, in which case you will still seee {"ping":"pong"}.

```rb
puts response.body
```

# Collaboration tests with RSpec
Pacto comes with rspec matchers

```rb
require 'pacto/rspec'
```

It's probably a good idea to reset Pacto between each rspec scenario

```rb
RSpec.configure do |c|
  c.after(:each)  { Pacto.clear! }
end
```

Load your contracts, and stub them if you'd like.

```rb
Pacto.load_contracts('contracts', 'http://localhost:5000').stub_providers
```

You can turn on investigation mode so Pacto will detect and validate HTTP requests.

```rb
Pacto.validate!

describe 'my_code' do
  it 'calls a service' do
    conn = Faraday.new(url: 'http://localhost:5000')
    response = conn.get '/api/ping'
```

The have_validated matcher makes sure that Pacto received and successfully validated a request

```rb
    expect(Pacto).to have_validated(:get, 'http://localhost:5000/api/ping')
  end
end
```



================================================
FILE: docs/server.md
================================================

```rb
require 'pacto/rspec'
require 'pacto/test_helper'

describe 'ping service' do
  include Pacto::TestHelper

  it 'pongs' do
    with_pacto(
      port: 6000,
      backend_host: 'http://localhost:5000',
      live: true,
      stub: false,
      generate: false,
      directory: 'contracts'
      ) do |pacto_endpoint|
```

call your code

```rb
      system "curl #{pacto_endpoint}/api/ping"
    end
```

check citations

```rb
    expect(Pacto).to have_validated(:get, 'http://localhost:5000/api/ping')
  end
end
```



================================================
FILE: docs/server_cli.md
================================================
# Standalone server
You can run Pacto as a server in order to test non-Ruby projects. In order to get the full set
of options, run:

```sh
bundle exec pacto-server -h
```

You probably want to run with the -sv option, which will display verbose output to stdout. You can
run server that proxies to a live endpoint:

```sh
bundle exec pacto-server -sv --port 9000 --live http://example.com &
bundle exec pacto-server -sv --port 9001 --stub &

pkill -f pacto-server
```



================================================
FILE: docs/stenographer.md
================================================

```rb
require 'pacto'
Pacto.configure do |c|
  c.contracts_path = 'contracts'
end
contracts = Pacto.load_contracts('contracts', 'http://localhost:5000')
contracts.stub_providers

Pacto.simulate_consumer do
  request 'Echo', values: nil, response: { status: 200 } # 0 contract violations
  request 'Ping', values: nil, response: { status: 200 } # 0 contract violations
  request 'Unknown (http://localhost:8000/404)', values: nil, response: { status: 500 } # 0 contract violations
end

Pacto.simulate_consumer :my_consumer do
  playback 'pacto_stenographer.log'
end
```



================================================
FILE: features/configuration/strict_matchers.feature
================================================
Feature: Strict Matching

  By default, Pacto matches requests to contracts (and stubs) using exact request paths, parameters, and headers.  This strict behavior is useful for Consumer-Driven Contracts.

  You can use less strict matching so the same contract can match multiple similar requests.  This is useful for matching contracts with resource identifiers in the path.  Any placeholder in the path (like :id in /beers/:id) is considered a resource identifier and will match any alphanumeric combination.

  You can change the default behavior to the behavior that allows placeholders and ignores headers or request parameters by setting the strict_matchers configuration option:

  ```ruby
    Pacto.configure do |config|
      config.strict_matchers = false
    end
  ```

  Background:
    Given a file named "contracts/hello_contract.json" with:
      """json
      {
        "request": {
          "http_method": "GET",
          "path": "/hello/{id}",
          "headers": {
            "Accept": "application/json"
          },
          "params": {}
        },

        "response": {
          "status": 200,
          "headers": { "Content-Type": "application/json" },
          "schema": {
            "type": "object",
            "required": true,
            "properties": {
              "message": { "type": "string", "required": true, "default": "Hello, world!" }
            }
          }
        }
      }
      """

    Given a file named "requests.rb" with:
      """ruby
      require 'pacto'

      strict = ARGV[0] == "true"
      puts "Pacto.configuration.strict_matchers = #{strict}"
      puts

      Pacto.configure do |config|
        config.strict_matchers = strict
      end
      Pacto.load_contracts('contracts', 'http://dummyprovider.com').stub_providers

      def response url, headers
        begin
          response = Faraday.get(url) do |req|
            req.headers = headers[:headers]
          end
          response.body
        rescue WebMock::NetConnectNotAllowedError => e
          e.class
        end
      end

      print 'Exact: '
      puts response URI.encode('http://dummyprovider.com/hello/{id}'), headers: {'Accept' => 'application/json' }

      print 'Wrong headers: '
      puts response 'http://dummyprovider.com/hello/123', headers: {'Content-Type' => 'application/json' }

      print 'ID placeholder: '
      puts response 'http://dummyprovider.com/hello/123', headers: {'Accept' => 'application/json' }
      """

  Scenario: Default (strict) behavior
    When I run `bundle exec ruby requests.rb true`
    Then the stdout should contain:
      """
      Pacto.configuration.strict_matchers = true

      Exact: {"message":"Hello, world!"}
      Wrong headers: WebMock::NetConnectNotAllowedError
      ID placeholder: {"message":"Hello, world!"}

      """

  Scenario: Non-strict matching
    When I run `bundle exec ruby requests.rb false`
    Then the stdout should contain:
      """
      Pacto.configuration.strict_matchers = false

      Exact: {"message":"Hello, world!"}
      Wrong headers: {"message":"Hello, world!"}
      ID placeholder: {"message":"Hello, world!"}
      """


================================================
FILE: features/evolve/README.md
================================================
## Consumer-Driven Contract Recommendations

If you are using Pacto for Consumer-Driven Contracts, we recommend avoiding the advanced features so you'll test with the strictest Contract possible.  We recommend:

- Do not use templating, let Pacto use the json-generator
- Use strict request matching
- Use multiple contracts for the same service to capture attributes that are required in some situations but not others

The host address is intentionally left out of the request specification so that we can validate a contract against any provider.
It also reinforces the fact that a contract defines the expectation of a consumer, and not the implementation of any specific provider.



================================================
FILE: features/evolve/existing_services.feature
================================================
Feature: Existing services journey

  Scenario: Generating the contracts
    Given I have a Rakefile
    Given an existing set of services
    When I execute:
    """ruby
    require 'pacto'

    Pacto.configure do | c |
      c.contracts_path = 'contracts'
    end

    Pacto.generate!

    Faraday.get 'http://www.example.com/service1'
    Faraday.get 'http://www.example.com/service2'
    """
    Then the following files should exist:
    | contracts/www.example.com/service1.json |
    | contracts/www.example.com/service2.json |

  @no-clobber
  Scenario: Ensuring all contracts are valid
    When I successfully run `bundle exec rake pacto:meta_validate['contracts']`
    Then the stdout should contain exactly:
    """
       validated  contracts/www.example.com/service1.json
       validated  contracts/www.example.com/service2.json
    All contracts successfully meta-validated

    """

  # TODO: find where Webmock is being called with and an empty :with
  # and update it, to not use with so we can upgrade Webmock past 1.20.2
  @no-clobber
  Scenario: Stubbing with the contracts
    Given a file named "test.rb" with:
    """ruby
    require 'pacto'

    Pacto.configure do | c |
      c.contracts_path = 'contracts'
    end

    contracts = Pacto.load_contracts('contracts/www.example.com/', 'http://www.example.com')
    contracts.stub_providers

    puts Faraday.get('http://www.example.com/service1').body
    puts Faraday.get('http://www.example.com/service2').body
    """
    When I successfully run `bundle exec ruby test.rb`
    Then the stdout should contain exactly:
    """
    {"thoughtworks":"pacto"}
    {"service2":["thoughtworks","pacto"]}

    """

  @no-clobber
  Scenario: Expecting a change
    When I make replacements in "contracts/www.example.com/service1.json":
    | pattern | replacement |
    | string  | integer     |
    When I execute:
    """ruby
    require 'pacto'

    Pacto.stop_generating!

    Pacto.configure do | c |
      c.contracts_path = 'contracts'
    end

    Pacto.load_contracts('contracts', 'http://www.example.com').stub_providers
    Pacto.validate!

    Faraday.get 'http://www.example.com/service1'
    Faraday.get 'http://www.example.com/service2'
    """
    Then the stdout should contain exactly:
    """

    """


================================================
FILE: features/generate/README.md
================================================
We know - json-schema can get pretty verbose!  It's a powerful tool, but writing the entire Contract by hand for a complex service is a painstaking task.  We've created a simple generator to speed this process up.  You can invoke it programmatically, or with the provided rake task.

The basic generate we've bundled with Pacto completes partially defined Contracts - Contracts that have a request defined but no response.  We haven't bundled any other generates, but you could use the API to generate from other sources, like existing [VCR](https://github.com/vcr/vcr) cassettes, [apiblueprint](http://apiblueprint.org/), or [WADL](https://wadl.java.net/).  If you want some help or ideas, try the [pacto mailing-list](https://groups.google.com/forum/#!forum/pacto-gem).

Note: Request headers are only recorded if they are in the response's [Vary header](http://www.subbu.org/blog/2007/12/vary-header-for-restful-applications), so make sure your services return a proper Vary for best results!

================================================
FILE: features/generate/generation.feature
================================================
@needs_server
Feature: Contract Generation

  We know - json-schema can get pretty verbose!  It's a powerful tool, but writing the entire Contract by hand for a complex service is a painstaking task.  We've created a simple generator to speed this process up.  You can invoke it programmatically, or with the provided rake task.

  You just need to create a partial Contract that only describes the request.  The generator will then execute the request, and use the response to generate a full Contract.

  Remember, we only record request headers if they are in the response's [Vary header](http://www.subbu.org/blog/2007/12/vary-header-for-restful-applications), so make sure your services return a proper Vary for best results!

  Background:
    Given a file named "requests/my_contract.json" with:
    """
      {
        "request": {
          "http_method": "GET",
          "path": "/api/ping",
          "headers": {
            "Accept": "application/json"
          }
        },
        "response": {
          "status": 200,
          "schema": {
            "required": true
          }
        }
      }
    """

  Scenario: Generating a contract using the rake task
    Given a directory named "contracts"
    When I successfully run `bundle exec rake pacto:generate['tmp/aruba/requests','tmp/aruba/contracts','http://localhost:5000']`
    Then the stdout should contain "Successfully generated all contracts"

  Scenario: Generating a contract programmatically
    Given a file named "generate.rb" with:
    """ruby
    require 'pacto'
    Pacto.configuration.generator_options[:no_examples] = true

    WebMock.allow_net_connect!
    generator = Pacto::Generator.contract_generator
    contract = generator.generate_from_partial_contract('requests/my_contract.json', 'http://localhost:5000')
    puts contract
    """
    When I successfully run `bundle exec ruby generate.rb`
    Then the stdout should match this contract:
    """json
    {
      "name": "/api/ping",
      "request": {
        "headers": {
        },
        "http_method": "get",
        "path": "/api/ping"
      },
      "response": {
        "headers": {
          "Content-Type": "application/json"
        },
        "status": 200,
        "schema": {
          "$schema": "http://json-schema.org/draft-03/schema#",
          "description": "Generated from requests/my_contract.json with shasum 210fa3b144ef2db8d1c160c4d9e8d8bf738ed851",
          "type": "object",
          "required": true,
          "properties": {
            "ping": {
              "type": "string",
              "required": true
            }
          }
        }
      }
    }

    """


================================================
FILE: features/steps/pacto_steps.rb
================================================
# -*- encoding : utf-8 -*-
Given(/^Pacto is configured with:$/) do |string|
  steps %(
    Given a file named "pacto_config.rb" with:
    """ruby
    #{string}
    """
  )
end

Given(/^I have a Rakefile$/) do
  steps %(
    Given a file named "Rakefile" with:
    """ruby
    require 'pacto/rake_task'
    """
  )
end

When(/^I request "(.*?)"$/) do |url|
  steps %{
    Given a file named "request.rb" with:
    """ruby
    require 'pacto'
    require_relative 'pacto_config'
    require 'faraday'

    resp = Faraday.get('#{url}') do |req|
      req.headers = { 'Accept' => 'application/json' }
    end
    puts resp.body
    """
    When I run `bundle exec ruby request.rb`
  }
end

Given(/^an existing set of services$/) do
  WebMock.stub_request(:get, 'www.example.com/service1').to_return(body: { 'thoughtworks' => 'pacto' }.to_json)
  WebMock.stub_request(:post, 'www.example.com/service1').with(body: 'thoughtworks').to_return(body: 'pacto')
  WebMock.stub_request(:get, 'www.example.com/service2').to_return(body: { 'service2' => %w(thoughtworks pacto) }.to_json)
  WebMock.stub_request(:post, 'www.example.com/service2').with(body: 'thoughtworks').to_return(body: 'pacto')
end

When(/^I execute:$/) do |script|
  FileUtils.mkdir_p 'tmp/aruba'
  Dir.chdir 'tmp/aruba' do
    begin
      script = <<-eof
      require 'stringio'
      begin $stdout = StringIO.new
        #{ script }
        $stdout.string
      ensure
        $stdout = STDOUT
      end
eof
      eval(script) # rubocop:disable Eval
    # It's just for testing...

    rescue SyntaxError => e
      raise e
    end
  end
end

When(/^I make replacements in "([^"]*)":$/) do |file_name, replacements|
  Dir.chdir 'tmp/aruba' do
    content = File.read file_name
    replacements.rows.each do | pattern, replacement |
      content.gsub! Regexp.new(pattern), replacement
    end

    File.open(file_name, 'w') { |file| file.write content }
  end
end

Then(/^the stdout should match this contract:$/) do |expected_contract|
  actual_contract = all_stdout
  expect(actual_contract).to be_json_eql(expected_contract).excluding('description')
end


================================================
FILE: features/stub/README.md
================================================
You can write your own stubs and use Pacto to [validate](https://www.relishapp.com/maxlinc/pacto/docs/validate) them, or you can just let Pacto create stubs for you.



================================================
FILE: features/stub/templates.feature
================================================
Feature: Templating

  If you want to create more dynamic stubs, you can use Pacto templating.  Currently the only supported templating mechanism is to use ERB in the "default" attributes of the json-schema.

  Background:
    Given Pacto is configured with:
      """ruby
      Pacto.configure do |c|
        c.register_hook Pacto::Hooks::ERBHook.new
      end
      Pacto.load_contracts('contracts', 'http://example.com').stub_providers
      """
    Given a file named "contracts/template.json" with:
      """json
      {
        "request": {
          "http_method": "GET",
          "path": "/hello",
          "headers": {
            "Accept": "application/json"
          },
          "params": {}
        },

        "response": {
          "status": 200,
          "headers": { "Content-Type": "application/json" },
          "schema": {
            "type": "object",
            "required": true,
            "properties": {
              "message": { "type": "string", "required": true,
                "default": "<%= 'Hello, world!'.reverse %>"
              }
            }
          }
        }
      }
      """

  Scenario: ERB Template
    When I request "http://example.com/hello"
    Then the stdout should contain:
      """
      {"message":"!dlrow ,olleH"}
      """


================================================
FILE: features/support/env.rb
================================================
# -*- encoding : utf-8 -*-
require_relative '../../spec/coveralls_helper'
require 'aruba'
require 'aruba/cucumber'
require 'json_spec/cucumber'
require 'aruba/jruby' if RUBY_PLATFORM == 'java'
require 'pacto/test_helper'

Pacto.configuration.hide_deprecations = true

Before do
  # Given I successfully run `bundle install` can take a while.
  @aruba_timeout_seconds = RUBY_PLATFORM == 'java' ? 60 : 10
end

class PactoWorld
  include Pacto::TestHelper
end

World do
  PactoWorld.new
end

Around do | _scenario, block |
  WebMock.allow_net_connect!
  world = self || PactoWorld.new
  world.with_pacto(port: 8000, live: true, backend_host: 'http://localhost:5000') do
    block.call
  end
end


================================================
FILE: features/validate/README.md
================================================
You can use Pacto to do Integration Contract Testing - making sure your service and any test double that simulates the service are similar.  If you generate your Contracts from documentation, you can be fairly confident that all three - live services, test doubles, and documentation - are in sync.

================================================
FILE: features/validate/meta_validation.feature
================================================
Feature: Meta-validation

  Meta-validation ensures that a Contract file matches the Contract format.  It does not validation actual responses, just the Contract itself.

  You can easily do meta-validation with the Rake task pacto:meta_validate, or programmatically.

  Background:
    Given a file named "contracts/my_contract.json" with:
      """
          {
          "request": {
            "http_method": "GET",
            "path": "/hello_world",
            "headers": {
              "Accept": "application/json"
            },
            "params": {}
          },

          "response": {
            "status": 200,
            "headers": {
              "Content-Type": "application/json"
            },
            "schema": {
              "description": "A simple response",
              "type": "object",
              "required": ["message"],
              "properties": {
                "message": {
                  "type": "string"
                }
              }
            }
          }
        }
      """

  Scenario: Meta-validation via a rake task
    When I successfully run `bundle exec rake pacto:meta_validate['tmp/aruba/contracts/my_contract.json']`
    Then the stdout should contain "All contracts successfully meta-validated"

# The tests from here down should probably be specs instead of relish

  Scenario: Meta-validation of an invalid contract
    Given a file named "contracts/my_contract.json" with:
    """
    {"request": "yes"}
    """
    When I run `bundle exec rake pacto:meta_validate['tmp/aruba/contracts/my_contract.json']`
    Then the exit status should be 1
    And the stdout should contain "did not match the following type"


  Scenario: Meta-validation of a contract with empty request and response
    Given a file named "contracts/my_contract.json" with:
    """
    {"request": {}, "response": {}}
    """
    When I run `bundle exec rake pacto:meta_validate['tmp/aruba/contracts/my_contract.json']`
    Then the exit status should be 1
    And the stdout should contain "did not contain a required property"

  Scenario: Meta-validation of a contracts response body
    Given a file named "contracts/my_contract.json" with:
    """
        {
        "request": {
          "http_method": "GET",
          "path": "/hello_world"
        },

        "response": {
          "status": 200,
          "schema": {
            "required": "anystring"
            }
          }
        }
    """
    When I run `bundle exec rake pacto:meta_validate['tmp/aruba/contracts/my_contract.json']`
    Then the exit status should be 1
    And the stdout should contain "did not match the following type"


================================================
FILE: features/validate/validation.feature
================================================
Feature: Validation

  Validation ensures that a external service conform to a Contract.

  Scenario: Validation via a rake task
    Given a file named "contracts/simple_contract.json" with:
      """
          {
          "request": {
            "http_method": "GET",
            "path": "/api/hello",
            "headers": { "Accept": "application/json" },
            "params": {}
          },

          "response": {
            "status": 200,
            "headers": { "Content-Type": "application/json" },
            "schema": {
              "description": "A simple response",
              "type": "object",
              "properties": {
                "message": { "type": "string" }
              }
            }
          }
        }
      """
      When I successfully run `bundle exec rake pacto:validate['http://localhost:5000','tmp/aruba/contracts/simple_contract.json']`
      Then the stdout should contain:
        """"
        Validating contracts against host http://localhost:5000
                 OK!  simple_contract.json
        1 valid contract
        """


================================================
FILE: lib/pacto/actor.rb
================================================
# -*- encoding : utf-8 -*-
module Pacto
  class Actor
  end
end


================================================
FILE: lib/pacto/actors/from_examples.rb
================================================
# -*- encoding : utf-8 -*-
module Pacto
  module Actors
    class FirstExampleSelector
      def self.select(examples, _values)
        Hashie::Mash.new examples.values.first
      end
    end
    class RandomExampleSelector
      def self.select(examples, _values)
        Hashie::Mash.new examples.values.sample
      end
    end
    class NamedExampleSelector
      def self.select(examples, values)
        name = values[:example_name]
        if name.nil?
          RandomExampleSelector.select(examples, values)
        else
          Hashie::Mash.new examples[name]
        end
      end
    end
    class FromExamples < Actor
      def initialize(fallback_actor = JSONGenerator.new, selector = Pacto::Actors::FirstExampleSelector)
        @fallback_actor = fallback_actor
        @selector = selector
      end

      def build_request(contract, values = {})
        request_values = (values || {}).dup
        if contract.examples?
          example = @selector.select(contract.examples, values)
          data = contract.request.to_hash
          request_values.merge! example_uri_values(contract)
          data['uri'] = contract.request.uri(request_values)
          data['body'] = example.request.body
          data['method'] = contract.request.http_method
          Pacto::PactoRequest.new(data)
        else
          @fallback_actor.build_request contract, values
        end
      end

      def build_response(contract, values = {})
        if contract.examples?
          example = @selector.select(contract.examples, values)
          data = contract.response.to_hash
          data['body'] = example.response.body
          Pacto::PactoResponse.new(data)
        else
          @fallback_actor.build_response contract, values
        end
      end

      def example_uri_values(contract)
        uri_template = contract.request.pattern.uri_template
        if contract.examples && contract.examples.values.first[:request][:uri]
          example_uri = contract.examples.values.first[:request][:uri]
          uri_template.extract example_uri
        else
          {}
        end
      end
    end
  end
end


================================================
FILE: lib/pacto/actors/json_generator.rb
================================================
# -*- encoding : utf-8 -*-
module Pacto
  module Actors
    class JSONGenerator < Actor
      def build_request(contract, values = {})
        data = contract.request.to_hash
        data['uri'] = contract.request.uri(values)
        data['body'] = JSON::Generator.generate(data['schema']) if data['schema']
        data['method'] = contract.request.http_method
        Pacto::PactoRequest.new(data)
      end

      def build_response(contract, _values = {})
        data = contract.response.to_hash
        data['body'] = JSON::Generator.generate(data['schema'])
        Pacto::PactoResponse.new(data)
      end
    end
  end
end


================================================
FILE: lib/pacto/body_parsing.rb
================================================
# -*- encoding : utf-8 -*-

module Pacto
  module Handlers
    autoload :JSONHandler, 'pacto/handlers/json_handler'
    autoload :TextHandler, 'pacto/handlers/text_handler'
    autoload :XMLHandler,  'pacto/handlers/xml_handler'
  end
  module BodyParsing
    def raw_body
      return nil if body.nil?
      return body if body.respond_to? :to_str

      body_handler.raw(body)
    end

    def parsed_body
      return nil if body.nil?

      body_handler.parse(body)
    end

    def content_type
      headers['Content-Type']
    end

    def body_handler
      case content_type
      when /\bjson$/
        Pacto::Handlers::JSONHandler
      when /\btext$/
        Pacto::Handlers::TextHandler
      # No XML support - yet
      # when /\bxml$/
      #   XMLHandler
      else
        # JSON is still the default
        Pacto::Handlers::JSONHandler
      end
    end
  end
end


================================================
FILE: lib/pacto/cli/helpers.rb
================================================
module Pacto
  module CLI
    module Helpers
      def each_contract(*contracts)
        [*contracts].each do |contract|
          if File.file? contract
            yield contract
          else # Should we assume it's a dir, or also support glob patterns?
            contracts = Dir[File.join(contract, '**/*{.json.erb,.json}')]
            fail Pacto::UI.colorize("No contracts found in directory #{contract}", :yellow) if contracts.empty?

            contracts.sort.each do |contract_file|
              yield contract_file
            end
          end
        end
      end
    end
  end
end


================================================
FILE: lib/pacto/cli.rb
================================================
require 'thor'
require 'pacto'
require 'pacto/cli/helpers'

module Pacto
  module CLI
    class Main < Thor
      include Pacto::CLI::Helpers

      desc 'meta_validate [CONTRACTS...]', 'Validates a directory of contract definitions'
      def meta_validate(*contracts)
        invalid = []
        each_contract(*contracts) do |contract_file|
          begin
            Pacto.validate_contract(contract_file)
            say_status :validated, contract_file
          rescue InvalidContract => exception
            invalid << contract_file
            shell.say_status :invalid, contract_file, :red
            exception.errors.each do |error|
              say set_color("  Error: #{error}", :red)
            end
          end
        end
        abort "The following contracts were invalid: #{invalid.join(',')}" unless invalid.empty?
        say 'All contracts successfully meta-validated'
      end

      desc 'validate [CONTRACTS...]', 'Validates all contracts in a given directory against a given host'
      method_option :host, type: :string, desc: 'Override host in contracts for validation'
      def validate(*contracts)
        host = options[:host]
        WebMock.allow_net_connect!
        banner = 'Validating contracts'
        banner << " against host #{host}" unless host.nil?
        say banner

        invalid_contracts = []
        tested_contracts = []
        each_contract(*contracts) do |contract_file|
          tested_contracts << contract_file
          invalid_contracts << contract_file unless contract_is_valid?(contract_file, host)
        end

        validation_summary(tested_contracts, invalid_contracts)
      end

      private

      def validation_summary(contracts, invalid_contracts)
        if invalid_contracts.empty?
          say set_color("#{contracts.size} valid contract#{contracts.size > 1 ? 's' : nil}", :green)
        else
          abort set_color("#{invalid_contracts.size} of #{contracts.size} failed. Check output for detailed error messages.", :red)
        end
      end

      def contract_is_valid?(contract_file, host)
        name = File.split(contract_file).last
        contract = Pacto.load_contract(contract_file, host)
        investigation = contract.simulate_request

        if investigation.successful?
          say_status 'OK!', name
          true
        else
          say_status 'FAILED!', name, :red
          say set_color(investigation.summary, :red)
          say set_color(investigation.to_s, :red)
          false
        end
      end
    end
  end
end


================================================
FILE: lib/pacto/consumer/faraday_driver.rb
================================================
# -*- encoding : utf-8 -*-
module Pacto
  class Consumer
    class FaradayDriver
      include Pacto::Logger
      # Sends a Pacto::PactoRequest
      def execute(req)
        conn_options = { url: req.uri.site }
        conn_options[:proxy] = Pacto.configuration.proxy if Pacto.configuration.proxy
        conn = Faraday.new(conn_options) do |faraday|
          faraday.response :logger if Pacto.configuration.logger.level == :debug
          faraday.adapter Faraday.default_adapter
        end

        response = conn.send(req.method) do |faraday_request|
          faraday_request.url(req.uri.path, req.uri.query_values)
          faraday_request.headers = req.headers
          faraday_request.body = req.raw_body
        end

        faraday_to_pacto_response response
      end

      private

      # This belongs in an adapter
      def faraday_to_pacto_response(faraday_response)
        data = {
          status: faraday_response.status,
          headers: faraday_response.headers,
          body: faraday_response.body
        }
        Pacto::PactoResponse.new(data)
      end
    end
  end
end


================================================
FILE: lib/pacto/consumer.rb
================================================
# -*- encoding : utf-8 -*-
module Pacto
  def self.consumers
    @consumers ||= {}
  end

  def self.simulate_consumer(consumer_name = :consumer, &block)
    consumers[consumer_name] ||= Consumer.new(consumer_name)
    consumers[consumer_name].simulate(&block)
  end

  class Consumer
    include Logger
    include Resettable

    def initialize(name = :consumer)
      @name = name
    end

    def simulate(&block)
      instance_eval(&block)
    end

    def playback(stenographer_script)
      script = File.read(stenographer_script)
      instance_eval script, stenographer_script
    end

    def self.reset!
      Pacto.consumers.clear
    end

    def actor
      @actor ||= Pacto::Actors::FromExamples.new
    end

    def actor=(actor)
      fail ArgumentError, 'The actor must respond to :build_request' unless actor.respond_to? :build_request
      @actor = actor
    end

    def request(contract, data = {})
      contract = Pacto.contract_registry.find_by_name(contract) if contract.is_a? String
      logger.info "Sending request to #{contract.name.inspect}"
      logger.info "  with #{data.inspect}"
      reenact(contract, data)
    rescue ContractNotFound => e
      logger.warn "Ignoring request: #{e.message}"
    end

    def reenact(contract, data = {})
      request = build_request contract, data
      response = driver.execute request
      [request, response]
    end

    # Returns the current driver
    def driver
      @driver ||= Pacto::Consumer::FaradayDriver.new
    end

    # Changes the driver
    def driver=(driver)
      fail ArgumentError, 'The driver must respond to :execute' unless driver.respond_to? :execute
      @driver = driver
    end

    # @api private
    def build_request(contract, data = {})
      actor.build_request(contract, data[:values]).tap do |request|
        if data[:headers] && data[:headers].respond_to?(:call)
          request.headers = data[:headers].call(request.headers)
        end
        if data[:body] && data[:body].respond_to?(:call)
          request.body = data[:body].call(request.body)
        end
      end
    end
  end
end


================================================
FILE: lib/pacto/contract.rb
================================================
# -*- encoding : utf-8 -*-
module Pacto
  module Contract
    include Logger

    attr_reader :id
    attr_reader :file
    attr_reader :request
    attr_reader :response
    attr_reader :values
    attr_reader :examples
    attr_reader :name
    attr_writer :adapter
    attr_writer :consumer
    attr_writer :provider

    def adapter
      @adapter ||= Pacto.configuration.adapter
    end

    def consumer
      @consumer ||= Pacto.configuration.default_consumer
    end

    def provider
      @provider ||= Pacto.configuration.default_provider
    end

    def examples?
      examples && !examples.empty?
    end

    def stub_contract!(values = {})
      self.values = values
      adapter.stub_request!(self)
    end

    def simulate_request
      pacto_request, pacto_response = execute
      validate_response pacto_request, pacto_response
    end

    # Should this be deprecated?
    def validate_response(request, response)
      Pacto::Cops.perform_investigation request, response, self
    end

    def matches?(request_signature)
      request_pattern.matches? request_signature
    end

    def request_pattern
      request.pattern
    end

    def response_for(pacto_request)
      provider.response_for self, pacto_request
    end

    def execute(additional_values = {})
      # FIXME: Do we really need to store on the Contract, or just as a param for #stub_contact! and #execute?
      full_values = values.merge(additional_values)
      consumer.reenact(self, full_values)
    end
  end
end


================================================
FILE: lib/pacto/contract_factory.rb
================================================
# -*- encoding : utf-8 -*-
module Pacto
  class ContractFactory
    include Singleton
    include Logger

    def initialize
      @factories = {}
    end

    def add_factory(format, factory)
      @factories[format.to_sym] = factory
    end

    def remove_factory(format)
      @factories.delete format
    end

    def build(contract_files, host, format = :legacy)
      factory = @factories[format.to_sym]
      fail "No Contract factory registered for #{format}" if factory.nil?

      contract_files.map { |file| factory.build_from_file(file, host) }.flatten
    end

    def load_contracts(contracts_path, host, format = :legacy)
      factory = @factories[format.to_sym]
      files = factory.files_for(contracts_path)
      contracts = ContractFactory.build(files, host, format)
      contracts
    end

    class << self
      extend Forwardable
      def_delegators :instance, *ContractFactory.instance_methods(false)
    end
  end
end

require 'pacto/formats/legacy/contract_factory'
require 'pacto/formats/swagger/contract_factory'


================================================
FILE: lib/pacto/contract_files.rb
================================================
# -*- encoding : utf-8 -*-
require 'pathname'
module Pacto
  class ContractFiles
    def self.for(path)
      full_path = Pathname.new(path).realpath

      if  full_path.directory?
        all_json_files = "#{full_path}/**/*.json"
        Dir.glob(all_json_files).map do |f|
          Pathname.new(f)
        end
      else
        [full_path]
      end
    end
  end
end


================================================
FILE: lib/pacto/contract_set.rb
================================================
# -*- encoding : utf-8 -*-
module Pacto
  class ContractSet < Set
    def stub_providers(values = {})
      each { |contract| contract.stub_contract!(values) }
    end

    def simulate_consumers
      map(&:simulate_request)
    end
  end
end


================================================
FILE: lib/pacto/cops/body_cop.rb
================================================
# -*- encoding : utf-8 -*-
module Pacto
  module Cops
    class BodyCop
      KNOWN_CLAUSES = [:request, :response]

      def self.validates(clause)
        fail ArgumentError, "Unknown clause: #{clause}" unless KNOWN_CLAUSES.include? clause
        @clause = clause
      end

      def self.investigate(request, response, contract)
        # eval "is a security risk" and local_variable_get is ruby 2.1+ only, so...
        body = { request: request, response: response }[@clause].body
        schema = contract.send(@clause).schema
        if schema && !schema.empty?
          schema['id'] = contract.file unless schema.key? 'id'
          JSON::Validator.fully_validate(schema, body, version: :draft3)
        end || []
      end
    end
  end
end


================================================
FILE: lib/pacto/cops/request_body_cop.rb
================================================
# -*- encoding : utf-8 -*-
module Pacto
  module Cops
    class RequestBodyCop < BodyCop
      validates :request
    end
  end
end

Pacto::Cops.register_cop Pacto::Cops::RequestBodyCop


================================================
FILE: lib/pacto/cops/response_body_cop.rb
================================================
# -*- encoding : utf-8 -*-
module Pacto
  module Cops
    class ResponseBodyCop < BodyCop
      validates :response
    end
  end
end

Pacto::Cops.register_cop Pacto::Cops::ResponseBodyCop


================================================
FILE: lib/pacto/cops/response_header_cop.rb
================================================
# -*- encoding : utf-8 -*-
module Pacto
  module Cops
    class ResponseHeaderCop
      def self.investigate(_request, response, contract)
        expected_headers = contract.response.headers
        actual_headers = response.headers
        actual_headers = Pacto::Extensions.normalize_header_keys actual_headers
        headers_to_validate = Pacto::Extensions.normalize_header_keys expected_headers

        headers_to_validate.map do |expected_header, expected_value|
          if actual_headers.key? expected_header
            actual_value = actual_headers[expected_header]
            HeaderValidatorMap[expected_header].call(expected_value, actual_value)
          else
            "Missing expected response header: #{expected_header}"
          end
        end.compact
      end

      private

      HeaderValidatorMap = Hash.new do |_map, key|
        proc do |expected_value, actual_value|
          unless expected_value.eql? actual_value
            "Invalid response header #{key}: expected #{expected_value.inspect} but received #{actual_value.inspect}"
          end
        end
      end

      HeaderValidatorMap['Location'] = proc do |expected_value, actual_value|
        location_template = Addressable::Template.new(expected_value)
        if location_template.match(Addressable::URI.parse(actual_value))
          nil
        else
          "Invalid response header Location: expected URI #{actual_value} to match URI Template #{location_template.pattern}"
        end
      end
    end
  end
end

Pacto::Cops.register_cop Pacto::Cops::ResponseHeaderCop


================================================
FILE: lib/pacto/cops/response_status_cop.rb
================================================
# -*- encoding : utf-8 -*-
module Pacto
  module Cops
    class ResponseStatusCop
      def self.investigate(_request, response, contract)
        expected_status = contract.response.status
        actual_status = response.status
        errors = []
        if expected_status != actual_status
          errors << "Invalid status: expected #{expected_status} but got #{actual_status}"
        end
        errors
      end
    end
  end
end

Pacto::Cops.register_cop Pacto::Cops::ResponseStatusCop


================================================
FILE: lib/pacto/cops.rb
================================================
# -*- encoding : utf-8 -*-
module Pacto
  module Cops
    extend Pacto::Resettable

    class << self
      def reset!
        @active_cops = nil
      end

      def register_cop(cop)
        fail TypeError "#{cop} does not respond to investigate" unless cop.respond_to? :investigate
        registered_cops << cop
      end

      def registered_cops
        @registered_cops ||= Set.new
      end

      def active_cops
        @active_cops ||= registered_cops.dup
      end

      def investigate(request_signature, pacto_response)
        return unless Pacto.validating?

        contract = Pacto.contracts_for(request_signature).first
        if contract
          investigation = perform_investigation request_signature, pacto_response, contract
        else
          investigation = Investigation.new request_signature, pacto_response
        end

        Pacto::InvestigationRegistry.instance.register_investigation investigation
      end

      def perform_investigation(request, response, contract)
        citations = []
        active_cops.map do | cop |
          citations.concat cop.investigate(request, response, contract)
        end
        Investigation.new(request, response, contract, citations.compact)
      end
    end
  end
end


================================================
FILE: lib/pacto/core/configuration.rb
================================================
# -*- encoding : utf-8 -*-
module Pacto
  class Configuration
    attr_accessor :adapter, :strict_matchers,
                  :contracts_path, :logger, :generator_options,
                  :hide_deprecations, :default_consumer, :default_provider,
                  :stenographer_log_file, :color, :proxy
    attr_reader :hook

    def initialize # rubocop:disable Metrics/MethodLength
      @middleware = Pacto::Core::HTTPMiddleware.new
      @middleware.add_observer Pacto::Cops, :investigate
      @generator = Pacto::Generator.contract_generator
      @middleware.add_observer @generator, :generate
      @default_consumer = Pacto::Consumer.new
      @default_provider = Pacto::Provider.new
      @adapter = Stubs::WebMockAdapter.new(@middleware)
      @strict_matchers = true
      @contracts_path = '.'
      @hook = Hook.new {}
      @generator_options = { schema_version: 'draft3' }
      @color = $stdout.tty?
      @proxy = ENV['PACTO_PROXY']
    end

    def logger
      @logger ||= new_simple_logger
    end

    def stenographer_log_file
      @stenographer_log_file ||= File.expand_path('pacto_stenographer.log')
    end

    def register_hook(hook = nil, &block)
      if block_given?
        @hook = Hook.new(&block)
      else
        fail 'Expected a Pacto::Hook' unless hook.is_a? Hook
        @hook = hook
      end
    end

    private

    def new_simple_logger
      Logger::SimpleLogger.instance.tap do | logger |
        if ENV['PACTO_DEBUG']
          logger.level = :debug
        else
          logger.level = :default
        end
      end
    end
  end
end


================================================
FILE: lib/pacto/core/contract_registry.rb
================================================
# -*- encoding : utf-8 -*-
module Pacto
  class ContractNotFound < StandardError; end

  class ContractRegistry < Set
    include Logger

    def register(contract)
      fail ArgumentError, 'expected a Pacto::Contract' unless contract.is_a? Contract
      logger.debug "Registering #{contract.request_pattern} as #{contract.name}"
      add contract
    end

    def find_by_name(name)
      contract = select { |c| c.name == name }.first
      fail ContractNotFound, "No contract found for #{name}" unless contract
      contract
    end

    def contracts_for(request_signature)
      select { |c| c.matches? request_signature }
    end
  end
end


================================================
FILE: lib/pacto/core/hook.rb
================================================
# -*- encoding : utf-8 -*-
module Pacto
  class Hook
    def initialize(&block)
      @hook = block
    end

    def process(contracts, request_signature, response)
      @hook.call contracts, request_signature, response
    end
  end
end


================================================
FILE: lib/pacto/core/http_middleware.rb
================================================
# -*- encoding : utf-8 -*-
require 'observer'

module Pacto
  module Core
    class HTTPMiddleware
      include Logger
      include Observable

      def process(request, response)
        contracts = Pacto.contracts_for request
        Pacto.configuration.hook.process contracts, request, response

        changed
        begin
          notify_observers request, response
        rescue StandardError => e
          logger.error Pacto::Errors.formatted_trace(e)
        end
      end
    end
  end
end


================================================
FILE: lib/pacto/core/investigation_registry.rb
================================================
# -*- encoding : utf-8 -*-
module Pacto
  class InvestigationRegistry
    include Singleton
    include Logger
    include Resettable
    attr_reader :investigations

    def initialize
      @investigations = []
    end

    def self.reset!
      instance.reset!
    end

    def reset!
      @investigations.clear
      @stenographer = nil
    end

    def validated?(request_pattern)
      matched_investigations = @investigations.select do |investigation|
        request_pattern.matches? investigation.request
      end
      matched_investigations unless matched_investigations.empty?
    end

    def register_investigation(investigation)
      @investigations << investigation
      stenographer.log_investigation investigation
      logger.info "Detected #{investigation.summary}"
      logger.debug(investigation.to_s) unless investigation.successful?
      investigation
    end

    def unmatched_investigations
      @investigations.select do |investigation|
        investigation.contract.nil?
      end
    end

    def failed_investigations
      @investigations.select do |investigation|
        !investigation.successful?
      end
    end

    protected

    def stenographer
      @stenographer ||= create_stenographer
    end

    def create_stenographer
      stenographer_log = File.open(Pacto.configuration.stenographer_log_file, 'a+')
      Pacto::Observers::Stenographer.new stenographer_log
    end
  end
end


================================================
FILE: lib/pacto/core/modes.rb
================================================
# -*- encoding : utf-8 -*-
module Pacto
  class << self
    def generate!
      modes << :generate
    end

    def stop_generating!
      modes.delete :generate
    end

    def generating?
      modes.include? :generate
    end

    def validate!
      modes << :validate
    end

    def stop_validating!
      modes.delete :validate
    end

    def validating?
      modes.include? :validate
    end

    private

    def modes
      @modes ||= []
    end
  end
end


================================================
FILE: lib/pacto/core/pacto_request.rb
================================================
# -*- encoding : utf-8 -*-
require 'hashie/mash'

module Pacto
  class PactoRequest
    # FIXME: Need case insensitive header lookup, but case-sensitive storage
    attr_accessor :headers, :body, :method, :uri

    include BodyParsing

    def initialize(data)
      mash = Hashie::Mash.new data
      @headers = mash.headers.nil? ? {} : mash.headers
      @body    = mash.body
      @method  = mash[:method]
      @uri     = mash.uri
      normalize
    end

    def to_hash
      {
        method: method,
        uri: uri,
        headers: headers,
        body: body
      }
    end

    def to_s
      string = Pacto::UI.colorize_method(method)
      string << " #{relative_uri}"
      string << " with body (#{raw_body.bytesize} bytes)" if raw_body
      string
    end

    def relative_uri
      uri.to_s.tap do |s|
        s.slice!(uri.normalized_site)
      end
    end

    def normalize
      @method = @method.to_s.downcase.to_sym
      @uri = @uri.normalize if @uri
    end
  end
end


================================================
FILE: lib/pacto/core/pacto_response.rb
================================================
# -*- encoding : utf-8 -*-
module Pacto
  class PactoResponse
    # FIXME: Need case insensitive header lookup, but case-sensitive storage
    attr_accessor :headers, :body, :status, :parsed_body
    attr_reader :parsed_body

    include BodyParsing

    def initialize(data)
      mash = Hashie::Mash.new data
      @headers = mash.headers.nil? ? {} : mash.headers
      @body = mash.body
      @status  = mash.status.to_i
    end

    def to_hash
      {
        status: status,
        headers: headers,
        body: body
      }
    end

    def to_s
      string = "STATUS: #{status}"
      string << " with body (#{raw_body.bytesize} bytes)" if raw_body
      string
    end
  end
end


================================================
FILE: lib/pacto/dash.rb
================================================
# -*- encoding : utf-8 -*-
require 'hashie'

module Pacto
  class Dash < Hashie::Dash
    include Hashie::Extensions::Coercion
    include Hashie::Extensions::Dash::IndifferentAccess
  end
end


================================================
FILE: lib/pacto/erb_processor.rb
================================================
# -*- encoding : utf-8 -*-
module Pacto
  class ERBProcessor
    include Logger
    def process(contract, values = {})
      erb = ERB.new(contract)
      erb_result = erb.result hash_binding(values)
      logger.debug "Processed contract: #{erb_result.inspect}"
      erb_result
    end

    private

    def hash_binding(values)
      namespace = OpenStruct.new(values)
      namespace.instance_eval { binding }
    end
  end
end


================================================
FILE: lib/pacto/errors.rb
================================================
module Pacto
  class InvalidContract < ArgumentError
    attr_reader :errors

    def initialize(errors)
      @errors = errors
    end

    def message
      @errors.join "\n"
    end
  end

  module Errors
    # Creates an array of strings, representing a formatted exception,
    # containing backtrace and nested exception info as necessary, that can
    # be viewed by a human.
    #
    # For example:
    #
    #     ------Exception-------
    #     Class: Crosstest::StandardError
    #     Message: Failure starting the party
    #     ---Nested Exception---
    #     Class: IOError
    #     Message: not enough directories for a party
    #     ------Backtrace-------
    #     nil
    #     ----------------------
    #
    # @param exception [::StandardError] an exception
    # @return [Array<String>] a formatted message
    def self.formatted_trace(exception)
      arr = formatted_exception(exception).dup
      last = arr.pop
      if exception.respond_to?(:original) && exception.original
        arr += formatted_exception(exception.original, 'Nested Exception')
        last = arr.pop
      end
      arr += ['Backtrace'.center(22, '-'), exception.backtrace, last].flatten
      arr
    end

    # Creates an array of strings, representing a formatted exception that
    # can be viewed by a human. Thanks to MiniTest for the inspiration
    # upon which this output has been designed.
    #
    # For example:
    #
    #     ------Exception-------
    #     Class: Crosstest::StandardError
    #     Message: I have failed you
    #     ----------------------
    #
    # @param exception [::StandardError] an exception
    # @param title [String] a custom title for the message
    #   (default: `"Exception"`)
    # @return [Array<String>] a formatted message
    def self.formatted_exception(exception, title = 'Exception')
      [
        title.center(22, '-'),
        "Class: #{exception.class}",
        "Message: #{exception.message}",
        ''.center(22, '-')
      ]
    end
  end
end


================================================
FILE: lib/pacto/extensions.rb
================================================
# -*- encoding : utf-8 -*-
module Pacto
  module Extensions
    # Adapted from Faraday
    HeaderKeyMap = Hash.new do |map, key|
      split_char = key.to_s.include?('-') ? '-' : '_'
      map[key] = key.to_s.split(split_char).     # :user_agent => %w(user agent)
          each(&:capitalize!).   # => %w(User Agent)
          join('-')                     # => "User-Agent"
    end
    HeaderKeyMap[:etag] = 'ETag'

    def self.normalize_header_keys(headers)
      headers.each_with_object({}) do |(key, value), normalized|
        normalized[HeaderKeyMap[key]] = value
      end
    end
  end
end


================================================
FILE: lib/pacto/forensics/investigation_filter.rb
================================================
# -*- encoding : utf-8 -*-
module Pacto
  module Forensics
    class FilterExhaustedError < StandardError
      attr_reader :suspects

      def initialize(msg, filter, suspects = [])
        @suspects = suspects
        if filter.respond_to? :description
          msg = "#{msg} #{filter.description}"
        else
          msg = "#{msg} #{filter}"
        end
        super(msg)
      end
    end

    class InvestigationFilter
      # CaseEquality makes sense for some of the rspec matchers and compound matching behavior
      # rubocop:disable Style/CaseEquality
      attr_reader :investigations, :filtered_investigations

      def initialize(investigations, track_suspects = true)
        investigations ||= []
        @investigations = investigations.dup
        @filtered_investigations = @investigations.dup
        @track_suspects = track_suspects
      end

      def with_name(contract_name)
        @filtered_investigations.keep_if do |investigation|
          return false if investigation.contract.nil?

          contract_name === investigation.contract.name
        end
        self
      end

      def with_request(request_constraints)
        return self if request_constraints.nil?
        [:headers, :body].each do |section|
          filter_request_section(section, request_constraints[section])
        end
        self
      end

      def with_response(response_constraints)
        return self if response_constraints.nil?
        [:headers, :body].each do |section|
          filter_response_section(section, response_constraints[section])
        end
        self
      end

      def successful_investigations
        @filtered_investigations.select(&:successful?)
      end

      def unsuccessful_investigations
        @filtered_investigations - successful_investigations
      end

      protected

      def filter_request_section(section, filter)
        suspects = []
        section = :parsed_body if section == :body
        @filtered_investigations.keep_if do |investigation|
          candidate = investigation.request.send(section)
          suspects << candidate if @track_suspects
          filter === candidate
        end if filter
        fail FilterExhaustedError.new("no requests matched #{section}", filter, suspects) if @filtered_investigations.empty?
      end

      def filter_response_section(section, filter)
        section = :parsed_body if section == :body
        suspects = []
        @filtered_investigations.keep_if do |investigation|
          candidate = investigation.response.send(section)
          suspects << candidate if @track_suspects
          filter === candidate
        end if filter
        fail FilterExhaustedError.new("no responses matched #{section}", filter, suspects) if @filtered_investigations.empty?
      end

      # rubocop:enable Style/CaseEquality
    end
  end
end


================================================
FILE: lib/pacto/forensics/investigation_matcher.rb
================================================
# -*- encoding : utf-8 -*-
RSpec::Matchers.define :have_investigated do |service_name|
  match do
    investigations = Pacto::InvestigationRegistry.instance.investigations
    @service_name = service_name

    begin
      @investigation_filter = Pacto::Forensics::InvestigationFilter.new(investigations)
      @investigation_filter.with_name(@service_name)
        .with_request(@request_constraints)
        .with_response(@response_constraints)

      @matched_investigations = @investigation_filter.filtered_investigations
      @unsuccessful_investigations = @investigation_filter.unsuccessful_investigations

      !@matched_investigations.empty? && (@allow_citations || @unsuccessful_investigations.empty?)
    rescue Pacto::Forensics::FilterExhaustedError => e
      @filter_error = e
      false
    end
  end

  def describe(obj)
    obj.respond_to?(:description) ? obj.description : obj.to_s
  end

  description do
    buffer = StringIO.new
    buffer.puts "to have investigated #{@service_name}"
    if @request_constraints
      buffer.puts '  with request matching'
      @request_constraints.each do |k, v|
        buffer.puts "    #{k}: #{describe(v)}"
      end
    end
    buffer.puts '  and' if @request_constraints && @response_constraints
    if @response_constraint
      buffer.puts '  with response matching'
      @request_constraints.each do |k, v|
        buffer.puts "    #{k}: #{describe(v)}"
      end
    end
    buffer.string
  end

  chain :with_request do |request_constraints|
    @request_constraints = request_constraints
  end

  chain :with_response do |response_constraints|
    @response_constraints = response_constraints
  end

  chain :allow_citations do
    @allow_citations = true
  end

  failure_message do | group |
    buffer = StringIO.new
    buffer.puts "expected #{group} " + description
    if @filter_error
      buffer.puts "but #{@filter_error.message}"
      unless @filter_error.suspects.empty?
        buffer.puts '  suspects:'
        @filter_error.suspects.each do |suspect|
          buffer.puts "    #{suspect}"
        end
      end
    elsif @matched_investigations.empty?
      investigated_services = @investigation_filter.investigations.map(&:contract).compact.map(&:name).uniq
      buffer.puts "but it was not among the services investigated: #{investigated_services}"
    elsif @unsuccessful_investigations
      buffer.puts 'but investigation errors were found:'
      @unsuccessful_investigations.each do |investigation|
        buffer.puts "  #{investigation}"
      end
    end
    buffer.string
  end
end


================================================
FILE: lib/pacto/formats/legacy/contract.rb
================================================
# -*- encoding : utf-8 -*-
require 'pacto/formats/legacy/request_clause'
require 'pacto/formats/legacy/response_clause'

module Pacto
  module Formats
    module Legacy
      class Contract < Pacto::Dash
        include Pacto::Contract

        property :id
        property :file
        property :request,  required: true
        # Although I'd like response to be required, it complicates
        # the partial contracts used the rake generation task...
        # yet another reason I'd like to deprecate that feature
        property :response # , required: true
        property :values, default: {}
        # Gotta figure out how to use test doubles w/ coercion
        coerce_key :request,  RequestClause
        coerce_key :response, ResponseClause
        property :examples
        property :name, required: true
        property :adapter, default: proc { Pacto.configuration.adapter }
        property :consumer, default: proc { Pacto.configuration.default_consumer }
        property :provider, default: proc { Pacto.configuration.default_provider }

        def initialize(opts)
          skip_freeze = opts.delete(:skip_freeze)

          if opts[:file]
            opts[:file] = Addressable::URI.convert_path(File.expand_path(opts[:file])).to_s
            opts[:name] ||= opts[:file]
          end
          opts[:id] ||= (opts[:summary] || opts[:file])
          super
          freeze unless skip_freeze
        end

        def freeze
          (keys.map(&:to_sym) - [:values, :adapter, :consumer, :provider]).each do | key |
            send(key).freeze
          end
          self
        end
      end
    end
  end
end


================================================
FILE: lib/pacto/formats/legacy/contract_builder.rb
================================================
# -*- encoding : utf-8 -*-
module Pacto
  module Formats
    module Legacy
      class ContractBuilder < Hashie::Dash # rubocop:disable Metrics/ClassLength
        extend Forwardable
        attr_accessor :source

        def initialize(options = {})
          @schema_generator = options[:schema_generator] ||= JSON::SchemaGenerator
          @filters = options[:filters] ||= Generator::Filters.new
          @data = { request: {}, response: {}, examples: {} }
          @source = 'Pacto' # Currently used by JSONSchemaGeneator, but not really useful
        end

        def name=(name)
          @data[:name] = name
        end

        def add_example(name, pacto_request, pacto_response)
          @data[:examples][name] ||= {}
          @data[:examples][name][:request] = clean(pacto_request.to_hash)
          @data[:examples][name][:response] = clean(pacto_response.to_hash)
          self
        end

        def infer_all
          # infer_file # The target file is being chosen inferred by the Generator
          infer_name
          infer_schemas
        end

        def infer_name
          if @data[:examples].empty?
            @data[:name] = @data[:request][:path] if @data[:request]
            return self
          end

          example, hint = example_and_hint
          @data[:name] = hint.nil? ? PactoRequest.new(example[:request]).uri.path : hint.service_name
          self
        end

        def infer_schemas
          return self if @data[:examples].empty?

          # TODO: It'd be awesome if we could infer across all examples
          example, _hint = example_and_hint
          sample_request_body = example[:request][:body]
          sample_response_body = example[:response][:body]
          @data[:request][:schema] = generate_schema(sample_request_body) if sample_request_body && !sample_request_body.empty?
          @data[:response][:schema] = generate_schema(sample_response_body) if sample_response_body && !sample_response_body.empty?
          self
        end

        def without_examples
          @export_examples = false
          self
        end

        def generate_contract(request, response)
          generate_request(request, response)
          generate_response(request, response)
          infer_all
          self
        end

        def generate_request(request, response)
          hint = hint_for(request)
          request = clean(
                            headers: @filters.filter_request_headers(request, response),
                            http_method: request.method,
                            params: request.uri.query_values,
                            path: hint.nil? ? request.uri.path : hint.path
                          )
          @data[:request] = request
          self
        end

        def generate_response(request, response)
          response = clean(
                             headers: @filters.filter_response_headers(request, response),
                             status: response.status
                           )
          @data[:response] = response
          self
        end

        def build_hash
          instance_eval(&block) if block_given?
          @final_data = @data.dup
          @final_data.delete(:examples) if exclude_examples?
          clean(@final_data)
        end

        def build(&block)
          Contract.new build_hash(&block)
        end

        protected

        def example_and_hint
          example = @data[:examples].values.first
          example_request = PactoRequest.new example[:request]
          [example, Pacto::Generator.hint_for(example_request)]
        end

        def exclude_examples?
          @export_examples == false
        end

        def generate_schema(body, generator_options = Pacto.configuration.generator_options)
          return if body.nil? || body.empty?

          body_schema = @schema_generator.generate @source, body, generator_options
          MultiJson.load(body_schema)
        end

        def clean(data)
          data.delete_if { |_k, v| v.nil? }
        end

        def hint_for(pacto_request)
          Pacto::Generator.hint_for(pacto_request)
        end
      end
    end
  end
end


================================================
FILE: lib/pacto/formats/legacy/contract_factory.rb
================================================
# -*- encoding : utf-8 -*-
require 'pacto/formats/legacy/contract'

module Pacto
  module Formats
    module Legacy
      # Builds {Pacto::Formats::Legacy::Contract} instances from Pacto's legacy Contract format.
      class ContractFactory
        attr_reader :schema

        def initialize(options = {})
          @schema = options[:schema] || MetaSchema.new
        end

        def build_from_file(contract_path, host)
          contract_definition = File.read(contract_path)
          definition = JSON.parse(contract_definition)
          schema.validate definition
          definition['request'].merge!('host' => host)
          body_to_schema(definition, 'request', contract_path)
          body_to_schema(definition, 'response', contract_path)
          method_to_http_method(definition, contract_path)
          request = RequestClause.new(definition['request'])
          response = ResponseClause.new(definition['response'])
          Contract.new(request: request, response: response, file: contract_path, name: definition['name'], examples: definition['examples'])
        end

        def files_for(contracts_dir)
          full_path = Pathname.new(contracts_dir).realpath

          if  full_path.directory?
            all_json_files = "#{full_path}/**/*.json"
            Dir.glob(all_json_files).map do |f|
              Pathname.new(f)
            end
          else
            [full_path]
          end
        end

        private

        def body_to_schema(definition, section, file)
          schema = definition[section].delete 'body'
          return nil unless schema

          Pacto::UI.deprecation "Contract format deprecation: #{section}:body will be moved to #{section}:schema (#{file})"
          definition[section]['schema'] = schema
        end

        def method_to_http_method(definition, file)
          method = definition['request'].delete 'method'
          return nil unless method

          Pacto::UI.deprecation "Contract format deprecation: request:method will be moved to request:http_method (#{file})"
          definition['request']['http_method'] = method
        end

        Pacto::ContractFactory.add_factory(:legacy, ContractFactory.new)
      end
    end
  end
end


================================================
FILE: lib/pacto/formats/legacy/contract_generator.rb
================================================
# -*- encoding : utf-8 -*-
require 'json/schema_generator'
require 'pacto/formats/legacy/contract_builder'
require 'pacto/formats/legacy/generator/filters'

module Pacto
  module Formats
    module Legacy
      class ContractGenerator
        include Logger

        def initialize(_schema_version = 'draft3',
          schema_generator = JSON::SchemaGenerator,
          validator = Pacto::MetaSchema.new,
          filters = Generator::Filters.new,
          consumer = Pacto::Consumer.new)
          @contract_builder = ContractBuilder.new(schema_generator: schema_generator, filters: filters)
          @consumer = consumer
          @validator = validator
        end

        def generate(pacto_request, pacto_response)
          return unless Pacto.generating?
          logger.debug("Generating Contract for #{pacto_request}, #{pacto_response}")
          begin
            contract_file = load_contract_file(pacto_request)

            unless File.exist? contract_file
              uri = URI(pacto_request.uri)
              FileUtils.mkdir_p(File.dirname contract_file)
              raw_contract = save(uri, pacto_request, pacto_response)
              File.write(contract_file, raw_contract)
              logger.debug("Generating #{contract_file}")

              Pacto.load_contract contract_file, uri.host
            end
          rescue => e
            raise StandardError, "Error while generating Contract #{contract_file}: #{e.message}", e.backtrace
          end
        end

        def generate_from_partial_contract(request_file, host)
          contract = Pacto.load_contract request_file, host
          request, response = @consumer.request(contract)
          save(request_file, request, response)
        end

        def save(source, request, response)
          @contract_builder.source = source
          # TODO: Get rid of the generate_contract call, just use add_example/infer_all
          @contract_builder.add_example('default', request, response).generate_contract(request, response) # .infer_all
          @contract_builder.without_examples if Pacto.configuration.generator_options[:no_examples]
          contract = @contract_builder.build_hash
          pretty_contract = MultiJson.encode(contract, pretty: true)
          # This is because of a discrepency w/ jruby vs MRI pretty json
          pretty_contract.gsub!(/^$\n/, '')
          @validator.validate pretty_contract
          pretty_contract
        end

        private

        def load_contract_file(pacto_request)
          hint = Pacto::Generator.hint_for(pacto_request)
          if hint.nil?
            uri = URI(pacto_request.uri)
            path = uri.path
            basename = File.basename(path, '.json') + '.json'
            File.join(Pacto.configuration.contracts_path, uri.host, File.dirname(path), basename)
          else
            File.expand_path(hint.target_file, Pacto.configuration.contracts_path)
          end
        end
      end
    end
  end
end


================================================
FILE: lib/pacto/formats/legacy/generator/filters.rb
================================================
# -*- encoding : utf-8 -*-
module Pacto
  module Formats
    module Legacy
      module Generator
        class Filters
          CONNECTION_CONTROL_HEADERS = %w(
            Via
            Server
            Connection
            Transfer-Encoding
            Content-Length
          )

          FRESHNESS_HEADERS =
          %w(
            Date
            Last-Modified
            ETag
          )

          HEADERS_TO_FILTER = CONNECTION_CONTROL_HEADERS + FRESHNESS_HEADERS

          def filter_request_headers(request, response)
            # FIXME: Do we need to handle all these cases in real situations, or just because of stubbing?
            vary_headers = response.headers['vary'] || response.headers['Vary'] || []
            vary_headers = [vary_headers] if vary_headers.is_a? String
            vary_headers = vary_headers.map do |h|
              h.split(',').map(&:strip)
            end.flatten

            request.headers.select do |header|
              vary_headers.map(&:downcase).include? header.downcase
            end
          end

          def filter_response_headers(_request, response)
            Pacto::Extensions.normalize_header_keys(response.headers).reject do |header|
              (HEADERS_TO_FILTER.include? header) || (header.start_with?('X-'))
            end
          end
        end
      end
    end
  end
end


================================================
FILE: lib/pacto/formats/legacy/generator_hint.rb
================================================
# -*- encoding : utf-8 -*-
module Pacto
  module Formats
    module Legacy
      class GeneratorHint < Pacto::Dash
        extend Forwardable

        property :request_clause
        coerce_key :request_clause, RequestClause
        property :service_name, required: true
        property :target_file

        def_delegators :request_clause, *RequestClause::Data.properties.map(&:to_sym)

        def initialize(data)
          data[:request_clause] = RequestClause::Data.properties.each_with_object({}) do | prop, hash |
            hash[prop] = data.delete prop
          end
          super
          self.target_file ||= "#{slugify(service_name)}.json"
        end

        def matches?(pacto_request)
          return false if pacto_request.nil?
          Pacto::RequestPattern.for(request_clause).matches?(pacto_request)
        end

        private

        def slugify(path)
          path.downcase.gsub(' ', '_')
        end
      end
    end
  end
end


================================================
FILE: lib/pacto/formats/legacy/request_clause.rb
================================================
# -*- encoding : utf-8 -*-
module Pacto
  module Formats
    module Legacy
      class RequestClause < Pacto::Dash
        include Pacto::RequestClause
        extend Forwardable
        attr_reader :data
        def_delegators :data, :to_hash
        def_delegators :data, :host, :http_method, :schema, :path, :headers, :params
        def_delegators :data, :host=, :http_method=, :schema=, :path=, :headers=, :params=

        class Data < Pacto::Dash
          property :host # required?
          property :http_method, required: true
          property :schema, default: {}
          property :path, default: '/'
          property :headers, default: {}
          property :params, default: {}
        end

        def initialize(data)
          skip_freeze = data.delete(:skip_freeze)
          mash = Hashie::Mash.new data
          mash['http_method'] = normalize(mash['http_method'])
          @data = Data.new(mash)
          freeze unless skip_freeze
          super({})
          @pattern = Pacto::RequestPattern.for(self)
        end

        def freeze
          @data.freeze
          self
        end
      end
    end
  end
end


================================================
FILE: lib/pacto/formats/legacy/response_clause.rb
================================================
module Pacto
  module Formats
    module Legacy
      class ResponseClause
        include Pacto::ResponseClause
        extend Forwardable
        attr_reader :data
        def_delegators :data, :to_hash
        def_delegators :data, :status, :headers, :schema
        def_delegators :data, :status=, :headers=, :schema=

        class Data < Pacto::Dash
          property :status
          property :headers, default: {}
          property :schema, default: {}
        end

        def initialize(data)
          skip_freeze = data.delete(:skip_freeze)
          @data = Data.new(data)
          freeze unless skip_freeze
        end

        def freeze
          @data.freeze
          self
        end
      end
    end
  end
end


================================================
FILE: lib/pacto/formats/swagger/contract.rb
================================================
# -*- encoding : utf-8 -*-

require 'pacto/formats/swagger/request_clause'
require 'pacto/formats/swagger/response_clause'

module Pacto
  module Formats
    module Swagger
      class Contract < Pacto::Dash
        include Pacto::Contract

        attr_reader :swagger_api_operation

        property :id
        property :file
        property :request,  required: true
        # Although I'd like response to be required, it complicates
        # the partial contracts used the rake generation task...
        # yet another reason I'd like to deprecate that feature
        property :response # , required: true
        property :values, default: {}
        # Gotta figure out how to use test doubles w/ coercion
        coerce_key :request,  RequestClause
        coerce_key :response, ResponseClause
        property :examples
        property :name, required: true
        property :adapter, default: proc { Pacto.configuration.adapter }
        property :consumer, default: proc { Pacto.configuration.default_consumer }
        property :provider, default: proc { Pacto.configuration.default_provider }

        def initialize(swagger_api_operation, base_data = {}) # rubocop:disable Metrics/MethodLength
          if base_data[:file]
            base_data[:file] = Addressable::URI.convert_path(File.expand_path(base_data[:file])).to_s
            base_data[:name] ||= base_data[:file]
          end
          base_data[:id] ||= (base_data[:summary] || base_data[:file])

          @swagger_api_operation = swagger_api_operation
          host = base_data.delete(:host) || swagger_api_operation.host
          default_response = swagger_api_operation.default_response
          request_clause = Pacto::Formats::Swagger::RequestClause.new(swagger_api_operation, host: host)

          if default_response.nil?
            logger.warn("No response defined for #{swagger_api_operation.full_name}")
            response_clause = ResponseClause.new(status: 200)
          else
            response_clause = ResponseClause.new(default_response)
          end

          examples = build_examples(default_response)
          super base_data.merge(
                  id: swagger_api_operation.operationId,
                  name: swagger_api_operation.full_name,
                  request: request_clause, response: response_clause,
                  examples: examples
                )
        end

        private

        def build_examples(response)
          return nil if response.nil? || response.examples.nil? || response.examples.empty?

          if response.examples.empty?
            response_body = nil
          else
            response_body = response.examples.values.first
          end

          {
            default: {
              request: {}, # Swagger doesn't have a clear way to capture request examples
              response: {
                body: response_body
              }
            }
          }
        rescue => e # FIXME: Only parsing errors?
          logger.warn("Error while trying to parse response example for #{swagger_api_operation.full_name}")
          logger.debug("  Error details: #{e.inspect}")
          nil
        end
      end
    end
  end
end


================================================
FILE: lib/pacto/formats/swagger/contract_factory.rb
================================================
# -*- encoding : utf-8 -*-
require 'swagger'
require 'pacto/formats/swagger/contract'

module Pacto
  module Formats
    module Swagger
      # Builds {Pacto::Formats::Swagger::Contract} instances from Swagger documents
      class ContractFactory
        include Logger

        def load_hints(_contract_path, _host = nil)
          fail NotImplementedError, 'Contract generation from hints is not currently supported for Swagger'
        end

        def build_from_file(contract_path, host = nil)
          app = ::Swagger.load(contract_path)
          app.operations.map do |op|
            Contract.new(op,
                         file: contract_path,
                         host: host
            )
          end
        rescue ArgumentError => e
          logger.error(e)
          raise "Could not load #{contract_path}: #{e.message}"
        end

        def files_for(contracts_dir)
          full_path = Pathname.new(contracts_dir).realpath

          if  full_path.directory?
            all_json_files = "#{full_path}/**/*.{json,yaml,yml}"
            Dir.glob(all_json_files).map do |f|
              Pathname.new(f)
            end
          else
            [full_path]
          end
        end
      end
      Pacto::ContractFactory.add_factory(:swagger, ContractFactory.new)
    end
  end
end


================================================
FILE: lib/pacto/formats/swagger/request_clause.rb
================================================
# -*- encoding : utf-8 -*-
module Pacto
  module Formats
    module Swagger
      class RequestClause
        include Pacto::RequestClause

        extend Forwardable
        attr_writer :host
        attr_reader :swagger_api_operation
        def_delegator :swagger_api_operation, :verb, :http_method
        def_delegators :swagger_api_operation, :path

        def initialize(swagger_api_operation, base_data = {})
          @swagger_api_operation = swagger_api_operation
          @host = base_data[:host] || swagger_api_operation.host
          @pattern = Pacto::RequestPattern.for(self)
        end

        def schema
          return nil if body_parameter.nil?
          return nil if body_parameter.schema.nil?
          body_parameter.schema.parse
        end

        def params
          return {} if swagger_api_operation.parameters.nil?

          swagger_api_operation.parameters.select { |p| p.in == 'query' }
        end

        def headers
          return {} if swagger_api_operation.parameters.nil?

          swagger_api_operation.parameters.select { |p| p.in == 'header' }
        end

        def to_hash
          [:http_method, :schema, :path, :headers, :params].each_with_object({}) do | key, hash |
            hash[key.to_s] = send key
          end
        end

        private

        def body_parameter
          return nil if swagger_api_operation.parameters.nil?
          swagger_api_operation.parameters.find { |p| p.in == 'body' }
        end
      end
    end
  end
end


================================================
FILE: lib/pacto/formats/swagger/response_clause.rb
================================================
# -*- encoding : utf-8 -*-
module Pacto
  module Formats
    module Swagger
      class ResponseClause
        extend Forwardable
        include Pacto::ResponseClause
        attr_reader :swagger_response

        def_delegators :swagger_response, :schema

        def initialize(swagger_response, _base_data = {})
          @swagger_response = swagger_response
        end

        def status
          swagger_response.status_code || 200
        end

        def headers
          swagger_response.headers || {}
        end

        def schema
          return nil unless swagger_response.schema
          swagger_response.schema.parse
        end
      end
    end
  end
end


================================================
FILE: lib/pacto/generator.rb
================================================
# -*- encoding : utf-8 -*-
require 'pacto/formats/legacy/contract_generator'
require 'pacto/formats/legacy/generator_hint'

module Pacto
  module Generator
    include Logger

    class << self
      # Factory method to return the active contract generator implementation
      def contract_generator
        Pacto::Formats::Legacy::ContractGenerator.new
      end

      # Factory method to return the active contract generator implementation
      def schema_generator
        JSON::SchemaGenerator
      end

      def configuration
        @configuration ||= Configuration.new
      end

      def configure
        yield(configuration)
      end

      def hint_for(pacto_request)
        configuration.hints.find { |hint| hint.matches? pacto_request }
      end
    end

    class Configuration
      attr_reader :hints

      def initialize
        @hints = Set.new
      end

      def hint(name, hint_data)
        @hints << Formats::Legacy::GeneratorHint.new(hint_data.merge(service_name: name))
      end
    end
  end
end


================================================
FILE: lib/pacto/handlers/json_handler.rb
================================================
require 'json'

module Pacto
  module Handlers
    module JSONHandler
      class << self
        def raw(body)
          JSON.dump(body)
        end

        def parse(body)
          JSON.parse(body)
        end

        # TODO: Something like validate(contract, body)
      end
    end
  end
end


================================================
FILE: lib/pacto/handlers/text_handler.rb
================================================
module Pacto
  module Handlers
    module TextHandler
      class << self
        def raw(body)
          body.to_s
        end

        def parse(body)
          body.to_s
        end

        # TODO: Something like validate(contract, body)
      end
    end
  end
end


================================================
FILE: lib/pacto/hooks/erb_hook.rb
================================================
# -*- encoding : utf-8 -*-
require_relative '../erb_processor'

module Pacto
  module Hooks
    class ERBHook < Pacto::Hook
      def initialize
        @processor = ERBProcessor.new
      end

      def process(contracts, request_signature, response)
        bound_values = contracts.empty? ? {} : contracts.first.values
        bound_values.merge!(req: { 'HEADERS' => request_signature.headers })
        response.body = @processor.process response.body, bound_values
        response.body
      end
    end
  end
end


================================================
FILE: lib/pacto/investigation.rb
================================================
# -*- encoding : utf-8 -*-
module Pacto
  class Investigation
    include Logger
    attr_reader :request, :response, :contract, :citations

    def initialize(request, response, contract = nil, citations = nil)
      @request = request
      @response = response
      @contract = contract
      @citations = citations || []
    end

    def successful?
      @citations.empty?
    end

    def against_contract?(contract_pattern)
      return nil if @contract.nil?

      case contract_pattern
      when String
        @contract if @contract.file.eql? contract_pattern
      when Regexp
        @contract if @contract.file =~ contract_pattern
      end
    end

    def to_s
      contract_name = @contract.nil? ? 'nil' : contract.name
      citation_string = Pacto::UI.colorize(@citations.join("\n\t\t"), :red)
      ''"
      Investigation:
      \tContract: #{contract_name}
      \tRequest: #{@request}
      \tCitations: \n\t\t#{citation_string}
      "''
    end

    def summary
      if @contract.nil?
        "Missing contract for services provided by #{@request.uri.host}"
      else
        status = successful? ? 'successful' : 'unsuccessful'
        "#{status} investigation of #{@contract.name}"
      end
    end
  end
end


================================================
FILE: lib/pacto/logger.rb
================================================
# -*- encoding : utf-8 -*-
require 'forwardable'

module Pacto
  module Logger
    def logger
      Pacto.configuration.logger
    end

    class SimpleLogger
      include Singleton
      extend Forwardable

      def_delegators :@log, :debug, :info, :warn, :error, :fatal

      def initialize
        log ::Logger.new STDOUT
      end

      def log(log)
        @log = log
        @log.level = default_level
        @log.progname = 'Pacto'
      end

      def level=(level)
        @log.level = log_levels.fetch(level, default_level)
      end

      def level
        log_levels.key @log.level
      end

      private

      def default_level
        ::Logger::ERROR
      end

      def log_levels
        {
          debug: ::Logger::DEBUG,
          info:  ::Logger::INFO,
          warn:  ::Logger::WARN,
          error: ::Logger::ERROR,
          fatal: ::Logger::FATAL
        }
      end
    end
  end
end


================================================
FILE: lib/pacto/meta_schema.rb
================================================
# -*- encoding : utf-8 -*-
module Pacto
  class MetaSchema
    attr_accessor :schema, :engine

    def initialize(engine = JSON::Validator)
      @schema = File.join(File.dirname(File.expand_path(__FILE__)), '../../resources/contract_schema.json')
      base_schemas = ['../../resources/draft-03.json', '../../resources/draft-04.json']
      validatable = false
      base_schemas.each do |base_schema|
        base_schema_file = File.join(File.dirname(File.expand_path(__FILE__)), base_schema)
        # This has a side-effect of caching local schemas, so we don't
        # look up json-schemas over HTTP.
        validatable ||= JSON::Validator.validate(base_schema_file, @schema)
      end
      fail 'Could not validate metaschema against any known version of json-schema' unless validatable
      @engine = engine
    end

    def validate(definition)
      errors = engine.fully_validate(schema, definition)
      fail InvalidContract, errors unless errors.empty?
    end
  end
end


================================================
FILE: lib/pacto/observers/stenographer.rb
================================================
# -*- encoding : utf-8 -*-
module Pacto
  module Observers
    class Stenographer
      def initialize(output)
        @output = output
      end

      def log_investigation(investigation)
        return if @output.nil?

        contract = investigation.contract
        request = investigation.request
        response = investigation.response
        name = name_for(contract, request)
        values = values_for(contract, request)

        msg = "request #{name.inspect}, values: #{values.inspect}, response: {status: #{response.status}} # #{number_of_citations(investigation)} contract violations"
        @output.puts msg
        @output.flush
      end

      protected

      def name_for(contract, request)
        return "Unknown (#{request.uri})" if contract.nil?
        contract.name
      end

      def number_of_citations(investigation)
        return 0 if investigation.nil?
        return 0 if investigation.citations.nil?
        investigation.citations.size.to_s
      end

      def values_for(_contract, request)
        # FIXME: Extract vars w/ URI::Template
        request.uri.query_values
      end
    end
  end
end


================================================
FILE: lib/pacto/provider.rb
================================================
# -*- encoding : utf-8 -*-
module Pacto
  def self.providers
    @providers ||= {}
  end

  class Provider
    include Resettable

    def self.reset!
      Pacto.providers.clear
    end

    def actor
      @actor ||= Pacto::Actors::FromExamples.new
    end

    def actor=(actor)
      fail ArgumentError, 'The actor must respond to :build_response' unless actor.respond_to? :build_response
      @actor = actor
    end

    def response_for(contract, data = {})
      actor.build_response contract, data
    end
  end
end


================================================
FILE: lib/pacto/rake_task.rb
================================================
# -*- encoding : utf-8 -*-
require 'pacto'
require 'thor'
require 'pacto/cli'
require 'pacto/cli/helpers'

# FIXME: RakeTask is a huge class, refactor this please
# rubocop:disable ClassLength
module Pacto
  class RakeTask
    extend Forwardable
    include Thor::Actions
    include Rake::DSL
    include Pacto::CLI::Helpers

    def initialize
      @exit_with_error = false
      @cli = Pacto::CLI::Main.new
    end

    def run(task, args, opts = {})
      Pacto::CLI::Main.new([], opts).public_send(task, *args)
    end

    def install
      desc 'Tasks for Pacto gem'
      namespace :pacto do
        validate_task
        generate_task
        meta_validate
      end
    end

    def validate_task
      desc 'Validates all contracts in a given directory against a given host'
      task :validate, :host, :dir do |_t, args|
        opts = args.to_hash
        dir = opts.delete :dir
        run(:validate, dir, opts)
      end
    end

    def generate_task
      desc 'Generates contracts from partial contracts'
      task :generate, :input_dir, :output_dir, :host do |_t, args|
        if args.to_a.size < 3
          fail Pacto::UI.colorize('USAGE: rake pacto:generate[<request_contract_dir>, <output_dir>, <record_host>]', :yellow)
        end

        generate_contracts(args[:input_dir], args[:output_dir], args[:host])
      end
    end

    def meta_validate
      desc 'Validates a directory of contract definitions'
      task :meta_validate, :dir do |_t, args|
        run(:meta_validate, *args)
      end
    end

    # rubocop:enable MethodLength

    # FIXME: generate_contracts is a big method =(. Needs refactoring
    # rubocop:disable MethodLength
    def generate_contracts(input_dir, output_dir, host)
      WebMock.allow_net_connect!
      generator = Pacto::Generator.contract_generator
      puts "Generating contracts from partial contracts in #{input_dir} and recording to #{output_dir}\n\n"

      failed_contracts = []
      each_contract(input_dir) do |contract_file|
        begin
          contract = generator.generate_from_partial_contract(contract_file, host)
          output_file = File.expand_path(File.basename(contract_file), output_dir)
          output_file = File.open(output_file, 'wb')
          output_file.write contract
          output_file.flush
          output_file.close
        rescue InvalidContract => e
          failed_contracts << contract_file
          puts Pacto::UI.colorize(e.message, :red)
        end
      end

      if failed_contracts.empty?
        puts Pacto::UI.colorize('Successfully generated all contracts', :green)
      else
        fail Pacto::UI.colorize("The following contracts could not be generated: #{failed_contracts.join ','}", :red)
      end
    end
    # rubocop:enable MethodLength
  end
end
# rubocop:enable ClassLength

Pacto::RakeTask.new.install


================================================
FILE: lib/pacto/request_clause.rb
================================================
# -*- encoding : utf-8 -*-
module Pacto
  module RequestClause
    include Logger
    attr_reader :host
    attr_reader :http_method
    attr_reader :schema
    attr_reader :path
    attr_reader :headers
    attr_reader :params
    attr_reader :pattern

    def http_method=(method)
      normalize(method)
    end

    def uri(values = {})
      values ||= {}
      uri_template = pattern.uri_template
      missing_keys = uri_template.keys.map(&:to_sym) - values.keys.map(&:to_sym)
      values[:scheme] = 'http' if missing_keys.delete(:scheme)
      values[:server] = 'localhost' if missing_keys.delete(:server)
      logger.warn "Missing keys for building a complete URL: #{missing_keys.inspect}" unless missing_keys.empty?
      Addressable::URI.heuristic_parse(uri_template.expand(values)).tap do |uri|
        uri.query_values = params unless params.nil? || params.empty?
      end
    end

    private

    def normalize(method)
      method.to_s.downcase.to_sym
    end
  end
end


================================================
FILE: lib/pacto/request_pattern.rb
================================================
# -*- encoding : utf-8 -*-
module Pacto
  class RequestPattern < WebMock::RequestPattern
    attr_accessor :uri_template

    def self.for(base_request)
      new(base_request.http_method, UriPattern.for(base_request))
    end

    def initialize(http_method, uri_template)
      @uri_template = uri_template
      super
    end

    def to_s
      string = Pacto::UI.colorize_method(@method_pattern.to_s)
      string << " #{@uri_pattern}"
      # WebMock includes this info, but I don't think we should. Pacto should match on URIs only and then validate the rest...
      # string << " with body #{@body_pattern.to_s}" if @body_pattern
      # string << " with headers #{@headers_pattern.to_s}" if @headers_pattern
      # string << " with given block" if @with_block
      string
    end
  end
end


================================================
FILE: lib/pacto/resettable.rb
================================================
# -*- encoding : utf-8 -*-
module Pacto
  # Included this module so that Pacto::Resettable.reset_all will call your class/module's self.reset! method.
  module Resettable
    def self.resettables
      @resettables ||= []
    end

    def self.extended(base)
      resettables << base
    end

    def self.included(base)
      resettables << base
    end

    def self.reset_all
      resettables.each(&:reset!)
      true
    end
  end
end


================================================
FILE: lib/pacto/response_clause.rb
================================================
# -*- encoding : utf-8 -*-
module Pacto
  module ResponseClause
    attr_reader :status
    attr_reader :headers
    attr_reader :schema
  end
end


================================================
FILE: lib/pacto/rspec.rb
================================================
# -*- encoding : utf-8 -*-
require 'pacto'

begin
  require 'rspec/core'
  require 'rspec/expectations'
rescue LoadError
  raise 'pacto/rspec requires rspec 2 or later'
end

require 'pacto/forensics/investigation_filter'
require 'pacto/forensics/investigation_matcher'

RSpec::Matchers.define :have_unmatched_requests do |_method, _uri|
  match do
    @unmatched_investigations = Pacto::InvestigationRegistry.instance.unmatched_investigations
    !@unmatched_investigations.empty?
  end

  failure_message do
    'Expected Pacto to have not matched all requests to a Contract, but all requests were matched.'
  end

  failure_message_when_negated do
    unmatched_requests = @unmatched_investigations.map(&:request).join("\n  ")
    "Expected Pacto to have matched all requests to a Contract, but the following requests were not matched: \n  #{unmatched_requests}"
  end
end

RSpec::Matchers.define :have_failed_investigations do |_method, _uri|
  match do
    @failed_investigations = Pacto::InvestigationRegistry.instance.failed_investigations
    !@failed_investigations.empty?
  end

  failure_message do
    'Expected Pacto to have found investigation problems, but none were found.'
  end

  failure_message_when_negated do
    "Expected Pacto to have successfully validated all requests, but the following issues were found: #{@failed_investigations}"
  end
end

RSpec::Matchers.define :have_validated do |method, uri|
  match do
    @request_pattern = Pacto::RequestPattern.new(method, uri)
    @request_pattern.with(@options) if @options
    validated? @request_pattern
  end

  chain :against_contract do |contract|
    @contract = contract
  end

  chain :with do |options|
    @options = options
  end

  def validated?(_request_pattern)
    @matching_investigations = Pacto::InvestigationRegistry.instance.validated? @request_pattern
    validated = !@matching_investigations.nil?
    validated && successfully? && contract_matches?
  end

  def investigation_citations
    @investigation_citations ||= @matching_investigations.map(&:citations).flatten.compact
  end

  def successfully?
    @matching_investigations.map(&:successful?).uniq.eql? [true]
  end

  def contract_matches?
    if @contract
      validated_contracts = @matching_investigations.map(&:contract).compact
      # Is there a better option than case equality for string & regex support?
      validated_contracts.any? do |contract|
        @contract === contract.file || @contract === contract.name # rubocop:disable CaseEquality
      end
    else
      true
    end
  end

  failure_message do
    buffer = StringIO.new
    buffer.puts "expected Pacto to have validated #{@request_pattern}"
    if @matching_investigations.nil? || @matching_investigations.empty?
      buffer.puts '  but no matching request was received'
      buffer.puts '    received:'
      buffer.puts "#{WebMock::RequestRegistry.instance}"
    elsif @matching_investigations.map(&:contract).compact.empty?
      buffer.puts '  but a matching Contract was not found'
    elsif !successfully?
      buffer.puts '  but investigation errors were found:'
      buffer.print '    '
      buffer.puts investigation_citations.join "\n    "
      # investigation_citations.each do |investigation_result|
      #   buffer.puts "    #{investigation_result}"
      # end
    elsif @contract
      validated_against = @matching_investigations.map { |v| v.against_contract? @contract }.compact.join ','
      buffer.puts "  against Contract #{@contract}"
      buffer.puts "    but it was validated against #{validated_against}"
    end
    buffer.string
  end
end


================================================
FILE: lib/pacto/server/cli.rb
================================================
require 'thor'
require 'pacto/server'

module Pacto
  module Server
    class CLI < Thor
      class << self
        DEFAULTS = {
          stdout: true,
          log_file: 'pacto.log',
          # :config => 'pacto/config/pacto_server.rb',
          strict: false,
          stub: true,
          live: false,
          generate: false,
          verbose: true,
          validate: true,
          directory: File.join(Dir.pwd, 'contracts'),
          port: 9000,
          format: :legacy,
          stenographer_log_file: File.expand_path('pacto_stenographer.log', Dir.pwd),
          strip_port: true
        }

        def server_options
          method_option :port, default: 4567, desc: 'The port to run the server on'
          method_option :directory, default: DEFAULTS[:directory], desc: 'The directory containing contracts'
          method_option :strict, default: DEFAULTS[:strict], desc: 'Whether Pacto should use strict matching or not'
          method_option :format, default: DEFAULTS[:format], desc: 'The contract format to use'
          method_option :strip_port, default: DEFAULTS[:strip_port], desc: 'If pacto should remove the port from URLs before forwarding'
        end
      end

      desc 'stub [CONTRACTS...]', 'Launches a stub server for a set of contracts'
      method_option :port, type: :numeric, desc: 'The port to listen on', default: 3000
      method_option :spy, type: :boolean, desc: 'Display traffic received by Pacto'
      server_options
      def stub(*_contracts)
        setup_interrupt
        server_options = @options.dup
        server_options[:stub] = true
        Pacto::Server::HTTP.run('0.0.0.0', options.port, server_options)
      end

      desc 'proxy [CONTRACTS...]', 'Launches an intercepting proxy server for a set of contracts'
      method_option :to, type: :string, desc: 'The target host for forwarded requests'
      method_option :port, type: :numeric, desc: 'The port to listen on', default: 3000
      method_option :spy, type: :boolean, desc: 'Display traffic received by Pacto'
      def proxy(*_contracts)
        setup_interrupt
        server_options = @options.dup
        server_options[:live] = true
        Pacto::Server::HTTP.run('0.0.0.0', options.port, server_options)
      end

      private

      def setup_interrupt
        trap('INT') do
          say 'Exiting...'
          exit
        end
      end
    end
  end
end


================================================
FILE: lib/pacto/server/config.rb
================================================
# -*- encoding : utf-8 -*-
Pacto::Server::Settings::OptionHandler.new(port, logger, config).handle(options)


================================================
FILE: lib/pacto/server/proxy.rb
================================================
module Pacto
  module Server
    module Proxy
      def proxy_request(pacto_request)
        prepare_to_forward(pacto_request)
        pacto_response = forward(pacto_request)
        prepare_to_respond(pacto_response)
        pacto_response.body = rewrite(pacto_response.body)
        pacto_response
      end

      def prepare_to_forward(pacto_request)
        host = host_for(pacto_request)
        fail 'Could not determine request host' if host.nil?
        host.gsub!('.dev', '.com') if settings[:strip_dev]
        scheme, host = host.split('://')
        host, scheme = scheme, host if host.nil?
        host, _port = host.split(':')
        scheme ||= 'https'
        pacto_request.uri = Addressable::URI.heuristic_parse("#{scheme}://#{host}#{pacto_request.uri}")
        # FIXME: We're stripping accept-encoding and transfer-encoding rather than dealing with the encodings
        pacto_request.headers.delete_if { |k, _v| %w(host content-length accept-encoding transfer-encoding).include? k.downcase }
      end

      def rewrite(body)
        return body unless settings[:strip_dev]
        # FIXME: This is pretty hacky and needs to be rethought, but here to support hypermedia APIs
        # This rewrites the response body so that URLs that may link to other services are rewritten
        # to also passs through the Pacto server.
        body.gsub('.com', ".dev:#{settings[:port]}").gsub(/https\:([\w\-\.\\\/]+).dev/, 'http:\1.dev')
      end

      def forward(pacto_request)
        Pacto::Consumer::FaradayDriver.new.execute(pacto_request)
      end

      def prepare_to_respond(pacto_response)
        pacto_response.headers.delete_if { |k, _v| %w(connection content-encoding content-length transfer-encoding).include? k.downcase }
      end

      private

      def host_for(pacto_request)
        # FIXME: Need case insensitive fetch for headers
        pacto_request.uri.site || pacto_request.headers.find { |key, _| key.downcase == 'host' }[1]
      end
    end
  end
end


================================================
FILE: lib/pacto/server/settings.rb
================================================
# -*- encoding : utf-8 -*-
module Pacto
  module Server
    module Settings
      def options_parser(opts, options) # rubocop:disable MethodLength
        options[:format] ||= :legacy
        options[:strict] ||= false
        options[:directory] ||= File.expand_path('contracts', @original_pwd)
        options[:config] ||= File.expand_path('../config.rb', __FILE__)
        options[:stenographer_log_file] ||= File.expand_path('pacto_stenographer.log', @original_pwd)
        options[:strip_port] ||= true

        opts.on('-l', '--live', 'Send requests to live services (instead of stubs)') { |_val| options[:live] = true }
        opts.on('-f', '--format FORMAT', 'Contract format') { |val| options[:format] = val }
        opts.on('--stub', 'Stub responses based on contracts') { |_val| options[:stub] = true }
        opts.on('-g', '--generate', 'Generate Contracts from requests') { |_val| options[:generate] = true }
        opts.on('-V', '--validate', 'Validate requests/responses against Contracts') { |_val| options[:validate] = true }
        opts.on('-m', '--match-strict', 'Enforce strict request matching rules') { |_val| options[:strict] = true }
        opts.on('-x', '--contracts_dir DIR', 'Directory that contains the contracts to be registered') { |val| options[:directory] = File.expand_path(val, @original_pwd) }
        opts.on('-H', '--host HOST', 'Host of the real service, for generating or validating live requests') { |val| options[:backend_host] = val }
        opts.on('-r', '--recursive-loading', 'Load contracts from folders named after the host to be stubbed') { |_val| options[:recursive_loading] = true }
        opts.on('--strip-port', 'Strip the port from the request URI to build the proxied URI') { |_val| options[:strip_port] = true }
        opts.on('--strip-dev', 'Strip .dev from the request domain to build the proxied URI') { |_val| options[:strip_dev] = true }
        opts.on('--stenographer-log-file', 'Location for the stenographer log file') { |val| options[:stenographer_log_file] = val }
        opts.on('--log-level [LEVEL]', [:debug, :info, :warn, :error, :fatal], 'Pacto log level ( debug, info, warn, error or fatal)') { |val| options[:pacto_log_level] = val }
      end

      class OptionHandler
        attr_reader :port, :logger, :config, :options

        def initialize(port, logger, config = {})
          @port, @logger, @config = port, logger, config
        end

        def token_map
          if File.readable? '.tokens.json'
            MultiJson.load(File.read '.tokens.json')
          else
            {}
          end
        end

        def prepare_contracts(contracts)
          contracts.stub_providers if options[:stub]
        end

        def handle(options) # rubocop:disable Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
          @options = options
          config[:backend_host] = options[:backend_host]
          config[:strip_port] = options[:strip_port]
          config[:strip_dev] = options[:strip_dev]
          config[:port] = port
          contracts_path = options[:directory] || File.expand_path('contracts', Dir.pwd)
          Pacto.configure do |pacto_config|
            pacto_config.logger = options[:pacto_logger] || logger
            pacto_config.loggerl.log_level = config[:pacto_log_level] if config[:pacto_log_level]
            pacto_config.contracts_path = contracts_path
            pacto_config.strict_matchers = options[:strict]
            pacto_config.generator_options = {
              schema_version: :draft3,
              token_map: token_map
            }
            pacto_config.stenographer_log_file = options[:stenographer_log_file]
          end

          if options[:generate]
            Pacto.generate!
            logger.info 'Pacto generation mode enabled'
          end

          if options[:recursive_loading]
            Dir["#{contracts_path}/*"].each do |host_dir|
              host = File.basename host_dir
              prepare_contracts Pacto.load_contracts(host_dir, "https://#{host}", options[:format])
            end
          else
            host_pattern = options[:backend_host] || '{scheme}://{server}'
            if File.exist? contracts_path
              prepare_contracts Pacto.load_contracts(contracts_path, host_pattern, options[:format])
            end
          end

          Pacto.validate! if options[:validate]

          if options[:live]
            #  WebMock.reset!
            WebMock.allow_net_connect!
          end

          config
        end
      end
    end
  end
end


================================================
FILE: lib/pacto/server.rb
================================================
# -*- encoding : utf-8 -*-
require 'reel'
require 'pacto'
require_relative 'server/settings'
require_relative 'server/proxy'

module Pacto
  module Server
    class HTTP < Reel::Server::HTTP
      attr_reader :settings, :logger
      include Proxy

      def initialize(host = '127.0.0.1', port = 3000, options = {})
        @logger = options[:pacto_logger] || Pacto.configuration.logger
        @settings = Settings::OptionHandler.new(port, @logger).handle(options)
        logger.info "Pacto Server starting on #{host}:#{port}"
        super(host, port, spy: options[:spy], &method(:on_connection))
      end

      def on_connection(connection)
        # Support multiple keep-alive requests per connection
        connection.each_request do |reel_request|
          begin
            pacto_request = # exclusive do
              Pacto::PactoRequest.new(
                headers: reel_request.headers, body: reel_request.read,
                method: reel_request.method, uri: Addressable::URI.heuristic_parse(reel_request.uri)
              )
            # end

            pacto_response = proxy_request(pacto_request)
            reel_response = ::Reel::Response.new(pacto_response.status, pacto_response.headers, pacto_response.body)
            reel_request.respond(reel_response)
          rescue WebMock::NetConnectNotAllowedError, Faraday::ConnectionFailed => e
            reel_request.respond 502, e.message
          rescue => e
            reel_request.respond 500, Pacto::Errors.formatted_trace(e)
          end
        end
      end
    end
  end
end


================================================
FILE: lib/pacto/stubs/uri_pattern.rb
================================================
# -*- encoding : utf-8 -*-
module Pacto
  class UriPattern
    class << self
      def for(request, strict = Pacto.configuration.strict_matchers)
        fail_deprecations(request)

        build_template_uri_pattern(request, strict)
      end

      def build_template_uri_pattern(request, strict)
        path = request.path.respond_to?(:pattern) ? request.path.pattern : request.path
        host = request.host
        host ||= '{server}'
        scheme, host = host.split('://') if host.include?('://')
        scheme ||= '{scheme}'

        if strict
          Addressable::Template.new("#{scheme}://#{host}#{path}")
        else
          Addressable::Template.new("#{scheme}://#{host}#{path}{?anyvars*}")
        end
      end

      def fail_deprecations(request)
        return if request.path.is_a? Addressable::Template
        return if request.path == (corrected_path = request.path.gsub(/\/:(\w+)/, '/{\\1}'))

        fail "please change path #{request.path} to uri template: #{corrected_path} - old syntax no longer supported"
      end
    end
  end
end


================================================
FILE: lib/pacto/stubs/webmock_adapter.rb
================================================
# -*- encoding : utf-8 -*-
module Pacto
  module Adapters
    module WebMock
      class PactoRequest < Pacto::PactoRequest
        extend Forwardable
        def_delegators :@webmock_request_signature, :headers, :method, :body, :uri, :to_s, :inspect

        def initialize(webmock_request_signature)
          @webmock_request_signature = webmock_request_signature
        end

        def params
          @webmock_request_signature.uri.query_values
        end

        def path
          @webmock_request_signature.uri.path
        end
      end

      class PactoResponse < Pacto::PactoResponse
        extend Forwardable
        def_delegators :@webmock_response, :body, :body=, :headers=, :status=, :to_s, :inspect

        def initialize(webmock_response)
          @webmock_response = webmock_response
        end

        def headers
          @webmock_response.headers || {}
        end

        def status
          status, _ = @webmock_response.status
          status
        end
      end
    end
  end
  module Stubs
    class WebMockAdapter
      include Resettable

      def initialize(middleware)
        @middleware = middleware

        WebMock.after_request do |webmock_request_signature, webmock_response|
          process_hooks webmock_request_signature, webmock_response
        end
      end

      def stub_request!(contract)
        request_clause = contract.request
        uri_pattern = UriPattern.for(request_clause)
        stub = WebMock.stub_request(request_clause.http_method, uri_pattern)

        if Pacto.configuration.strict_matchers
          with_opts = strict_details(request_clause)
          stub.request_pattern.with(with_opts) unless with_opts.empty?
        end

        stub.to_return do |request|
          pacto_request = Pacto::Adapters::WebMock::PactoRequest.new request
          response = contract.response_for pacto_request
          {
            status: response.status,
            headers: response.headers,
            body: format_body(response.body)
          }
        end
      end

      def self.reset!
        WebMock.reset!
        WebMock.reset_callbacks
      end

      def process_hooks(webmock_request_signature, webmock_response)
        pacto_request = Pacto::Adapters::WebMock::PactoRequest.new webmock_request_signature
        pacto_response = Pacto::Adapters::WebMock::PactoResponse.new webmock_response
        @middleware.process pacto_request, pacto_response
      end

      private

      def format_body(body)
        if body.is_a?(Hash) || body.is_a?(Array)
          body.to_json
        else
          body
        end
      end

      def strict_details(request)
        {}.tap do |details|
          details[webmock_params_key(request)] = request.params unless request.params.empty?
          details[:headers] = request.headers unless request.headers.empty?
        end
      end

      def webmock_params_key(request)
        request.http_method == :get ? :query : :body
      end
    end
  end
end


================================================
FILE: lib/pacto/test_helper.rb
================================================
# -*- encoding : utf-8 -*-
begin
  require 'pacto'
  require 'pacto/server'
rescue LoadError
  raise 'pacto/test_helper requires the pacto-server gem'
end

module Pacto
  module TestHelper
    DEFAULT_ARGS = {
      stdout: true,
      log_file: 'pacto.log',
      # :config => 'pacto/config/pacto_server.rb',
      strict: false,
      stub: true,
      live: false,
      generate: false,
      verbose: true,
      validate: true,
      directory: File.join(Dir.pwd, 'contracts'),
      port: 9000,
      format: :legacy,
      stenographer_log_file: File.expand_path('pacto_stenographer.log', Dir.pwd),
      strip_port: true
    }

    def with_pacto(args = {})
      start_index = ::Pacto::InvestigationRegistry.instance.investigations.size
      ::Pacto::InvestigationRegistry.instance.investigations.clear
      args = DEFAULT_ARGS.merge(args)
      args[:spy] = args[:verbose]
      server = Pacto::Server::HTTP.supervise('0.0.0.0', args[:port], args)
      yield "http://localhost:#{args[:port]}"
      ::Pacto::InvestigationRegistry.instance.investigations[start_index, -1]
    ensure
      server.terminate unless server.nil?
    end
  end
end


================================================
FILE: lib/pacto/ui.rb
================================================
# -*- encoding : utf-8 -*-
require 'thor'

module Pacto
  module UI
    # Colors for HTTP Methods, intended to match colors of Swagger-UI (as close as possible with ANSI Colors)
    METHOD_COLORS = {
      'POST' => :green,
      'PUT'  => :yellow,
      'DELETE' => :red,
      'GET' => :blue,
      'PATCH' => :yellow,
      'HEAD' => :green
    }

    def self.shell
      @shell ||= Thor::Shell::Color.new
    end

    def self.deprecation(msg)
      $stderr.puts colorize(msg, :yellow) unless Pacto.configuration.hide_deprecations
    end

    def self.colorize(msg, color)
      return msg unless Pacto.configuration.color

      shell.set_color(msg, color)
    end

    def self.colorize_method(method)
      method_string = method.to_s.upcase

      color = METHOD_COLORS[method_string] || :red # red for unknown methods
      colorize(method_string, color)
    end
  end
end


================================================
FILE: lib/pacto/uri.rb
================================================
# -*- encoding : utf-8 -*-
module Pacto
  class URI
    def self.for(host, path, params = {})
      Addressable::URI.heuristic_parse("#{host}#{path}").tap do |uri|
        uri.query_values = params unless params.nil? || params.empty?
      end
    end
  end
end


================================================
FILE: lib/pacto/version.rb
================================================
# -*- encoding : utf-8 -*-
module Pacto
  VERSION = '0.4.0.rc3'
end


================================================
FILE: lib/pacto.rb
================================================
# -*- encoding : utf-8 -*-
require 'pacto/version'

require 'addressable/template'
require 'swagger'
require 'middleware'
require 'faraday'
require 'multi_json'
require 'json-schema'
require 'json-generator'
require 'webmock'
require 'ostruct'
require 'erb'
require 'logger'

# FIXME: There's soo much stuff here! I'd both like to re-roganize and to use autoloading.
require 'pacto/errors'
require 'pacto/dash'
require 'pacto/resettable'
require 'pacto/logger'
require 'pacto/ui'
require 'pacto/request_pattern'
require 'pacto/core/http_middleware'
require 'pacto/consumer/faraday_driver'
require 'pacto/actor'
require 'pacto/consumer'
require 'pacto/provider'
require 'pacto/actors/json_generator'
require 'pacto/actors/from_examples'
require 'pacto/body_parsing'
require 'pacto/core/pacto_request'
require 'pacto/core/pacto_response'
require 'pacto/core/contract_registry'
require 'pacto/core/investigation_registry'
require 'pacto/core/configuration'
require 'pacto/core/modes'
require 'pacto/core/hook'
require 'pacto/extensions'
require 'pacto/request_clause'
require 'pacto/response_clause'
require 'pacto/stubs/webmock_adapter'
require 'pacto/stubs/uri_pattern'
require 'pacto/contract'
require 'pacto/cops'
require 'pacto/meta_schema'
require 'pacto/contract_factory'
require 'pacto/investigation'
require 'pacto/hooks/erb_hook'
require 'pacto/observers/stenographer'
require 'pacto/generator'
require 'pacto/contract_files'
require 'pacto/contract_set'
require 'pacto/uri'

# Cops
require 'pacto/cops/body_cop'
require 'pacto/cops/request_body_cop'
require 'pacto/cops/response_body_cop'
require 'pacto/cops/response_status_cop'
require 'pacto/cops/response_header_cop'

module Pacto
  class << self
    def configuration
      @configuration ||= Configuration.new
    end

    def contract_registry
      @registry ||= ContractRegistry.new
    end

    # Resets data and metrics only. It usually makes sense to call this between test scenarios.
    def reset
      Pacto::InvestigationRegistry.instance.reset!
      # Pacto::Resettable.reset_all
    end

    # Resets but also clears configuration, loaded contracts, and plugins.
    def clear!
      Pacto::Resettable.reset_all
      @modes = nil
      @configuration = nil
      @registry = nil
    end

    def configure
      yield(configuration)
    end

    def contracts_for(request_signature)
      contract_registry.contracts_for(request_signature)
    end

    # @throws Pacto::InvalidContract
    def validate_contract(contract)
      Pacto::MetaSchema.new.validate contract
      true
    end

    def load_contract(contract_path, host, format = :legacy)
      load_contracts(contract_path, host, format).first
    end

    def load_contracts(contracts_path, host, format = :legacy)
      contracts = ContractFactory.load_contracts(contracts_path, host, format)
      contracts.each do |contract|
        contract_registry.register(contract)
      end
      ContractSet.new(contracts)
    end
  end
end


================================================
FILE: pacto-server.gemspec
================================================
lib = File.expand_path('../lib', __FILE__)
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
require 'pacto/version'

Gem::Specification.new do |gem|
  gem.name          = 'pacto-server'
  gem.version       = Pacto::VERSION
  gem.authors       = ['ThoughtWorks']
  gem.email         = ['pacto-gem@googlegroups.com']
  gem.description   = "Pacto Server let's you run Pacto as a standalone server to arbitrate contract disputes between a service provider and one or more consumers in any programming language. It's Pacto beyond Ruby"
  gem.summary       = 'Polyglot Integration Contract Testing server'
  gem.homepage      = 'http://thoughtworks.github.io/pacto/'
  gem.license       = 'MIT'

  gem.files         = `git ls-files -- bin/pacto-server lib/pacto/server.rb lib/pacto/server`.split($/) # rubocop:disable SpecialGlobalVars
  gem.executables   = gem.files.grep(/^bin\//).map { |f| File.basename(f) }
  gem.test_files    = gem.files.grep(/^(test|spec|features)\//)
  gem.require_paths = ['lib']

  gem.add_dependency 'pacto', Pacto::VERSION
  gem.add_dependency 'reel', '~> 0.5'
end


================================================
FILE: pacto.gemspec
================================================
lib = File.expand_path('../lib', __FILE__)
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
require 'pacto/version'

plugin_files = Dir['pacto-*.gemspec'].map do |gemspec|
  eval(File.read(gemspec)).files # rubocop:disable Eval
end.flatten.uniq

Gem::Specification.new do |gem|
  gem.name          = 'pacto'
  gem.version       = Pacto::VERSION
  gem.authors       = ['ThoughtWorks & Abril']
  gem.email         = ['pacto-gem@googlegroups.com']
  gem.description   = 'Pacto is a judge that arbitrates contract disputes between a service provider and one or more consumers. In other words, it is a framework for Integration Contract Testing, and helps guide service evolution patterns like Consumer-Driven Contracts or Documentation-Driven Contracts.'
  gem.summary       = 'Integration Contract Testing framework'
  gem.homepage      = 'http://thoughtworks.github.io/pacto/'
  gem.license       = 'MIT'

  gem.files         = `git ls-files`.split($/) - plugin_files # rubocop:disable SpecialGlobalVars
  gem.executables   = gem.files.grep(/^bin\//).map { |f| File.basename(f) }
  gem.test_files    = gem.files.grep(/^(test|spec|features)\//)
  gem.require_paths = ['lib']

  gem.add_dependency 'webmock', '~> 1.18'
  gem.add_dependency 'swagger-core', '~> 0.2', '>= 0.2.1'
  gem.add_dependency 'middleware', '~> 0.1'
  gem.add_dependency 'multi_json', '~> 1.8'
  gem.add_dependency 'json-schema', '~> 2.0'
  gem.add_dependency 'json-generator', '~> 0.0', '>= 0.0.5'
  gem.add_dependency 'hashie', '~> 3.0'
  gem.add_dependency 'faraday', '~> 0.9'
  gem.add_dependency 'addressable', '~> 2.3'
  gem.add_dependency 'json-schema-generator', '~> 0.0', '>= 0.0.7'
  gem.add_dependency 'thor', '~> 0.19'

  gem.add_development_dependency 'polytrix', '~> 0.1', '>= 0.1.4'
  gem.add_development_dependency 'coveralls', '~> 0'
  gem.add_development_dependency 'fabrication', '~> 2.11'
  gem.add_development_dependency 'rake', '~> 10.0'
  gem.add_development_dependency 'rake-notes', '~> 0'
  gem.add_development_dependency 'rspec', '~> 3.0'
  gem.add_development_dependency 'aruba', '~> 0'
  gem.add_development_dependency 'json_spec', '~> 1.0'
  # Only required to push documentation, and not easily installed on Windows
  # gem.add_development_dependency 'relish'
  gem.add_development_dependency 'guard-rspec', '~> 4.2'
  # FIXME: Rubocop upgrade needed... rubocop -a will do most of the work
  gem.add_development_dependency 'rubocop', '~> 0.23', '< 0.27.0'
  gem.add_development_dependency 'rubocop-rspec', '~> 1.0.rc3'
  gem.add_development_dependency 'guard-rubocop', '~> 1.0'
  gem.add_development_dependency 'guard-cucumber', '~> 1.4'
  gem.add_development_dependency 'rb-fsevent', '~> 0' if RUBY_PLATFORM =~ /darwin/i
  gem.add_development_dependency 'terminal-notifier-guard', '~> 1.5' if RUBY_PLATFORM =~ /darwin/i
end


================================================
FILE: resources/contract_schema.json
================================================
{
  "title": "Example Schema",
  "type": "object",
  "required": ["request", "response"],
  "definitions": {
    "subschema": {
      "anyOf": [
        { "$ref": "http://json-schema.org/draft-03/schema#" },
        { "$ref": "http://json-schema.org/draft-04/schema#" }
      ]
    }
  },
  "properties": {
    "name": {
      "type": "string"
    },
    "request": {
      "type": "object",
      "required": ["path"],
      "properties": {
        "method": {
          "_deprecated": true,
          "type": "string"
        },
        "http_method": {
          "type": "string"
        },
        "path": {
          "type": "string"
        },
        "headers": {
          "type": "object"
        },
        "params": {
          "type": "object"
        },
        "body": {
          "description": "body is deprecated, use schema",
          "$ref": "#/definitions/subschema"
        },
        "schema": {
          "$ref": "#/definitions/subschema"
        }
      }
    },
    "response": {
      "type": "object",
      "required": ["status"],
      "properties": {
        "status":{
          "type": "integer"
        },
        "body": {
          "description": "body is deprecated, use schema",
          "$ref": "#/definitions/subschema"
        },
        "schema": {
          "$ref": "#/definitions/subschema"
        }
      }
    },
    "examples": {
      "type": "object",
      "additionalProperties": {
        "type": "object",
        "required": ["request", "response"],
        "properties": {
          "request": {
          },
          "response": {
          }
        }
      }
    }
  }
}


================================================
FILE: resources/draft-03.json
================================================
{
  "$schema" : "http://json-schema.org/draft-03/schema#",
  "id" : "http://json-schema.org/draft-03/schema#",
  "type" : "object",
  
  "properties" : {
    "type" : {
      "type" : ["string", "array"],
      "items" : {
        "type" : ["string", {"$ref" : "#"}]
      },
      "uniqueItems" : true,
      "default" : "any"
    },
    
    "properties" : {
      "type" : "object",
      "additionalProperties" : {"$ref" : "#"},
      "default" : {}
    },
    
    "patternProperties" : {
      "type" : "object",
      "additionalProperties" : {"$ref" : "#"},
      "default" : {}
    },
    
    "additionalProperties" : {
      "type" : [{"$ref" : "#"}, "boolean"],
      "default" : {}
    },
    
    "items" : {
      "type" : [{"$ref" : "#"}, "array"],
      "items" : {"$ref" : "#"},
      "default" : {}
    },
    
    "additionalItems" : {
      "type" : [{"$ref" : "#"}, "boolean"],
      "default" : {}
    },
    
    "required" : {
      "type" : "boolean",
      "default" : false
    },
    
    "dependencies" : {
      "type" : "object",
      "additionalProperties" : {
        "type" : ["string", "array", {"$ref" : "#"}],
        "items" : {
          "type" : "string"
        }
      },
      "default" : {}
    },
    
    "minimum" : {
      "type" : "number"
    },
    
    "maximum" : {
      "type" : "number"
    },
    
    "exclusiveMinimum" : {
      "type" : "boolean",
      "default" : false
    },
    
    "exclusiveMaximum" : {
      "type" : "boolean",
      "default" : false
    },
    
    "minItems" : {
      "type" : "integer",
      "minimum" : 0,
      "default" : 0
    },
    
    "maxItems" : {
      "type" : "integer",
      "minimum" : 0
    },
    
    "uniqueItems" : {
      "type" : "boolean",
      "default" : false
    },
    
    "pattern" : {
      "type" : "string",
      "format" : "regex"
    },
    
    "minLength" : {
      "type" : "integer",
      "minimum" : 0,
      "default" : 0
    },
    
    "maxLength" : {
      "type" : "integer"
    },
    
    "enum" : {
      "type" : "array",
      "minItems" : 1,
      "uniqueItems" : true
    },
    
    "default" : {
      "type" : "any"
    },
    
    "title" : {
      "type" : "string"
    },
    
    "description" : {
      "type" : "string"
    },
    
    "format" : {
      "type" : "string"
    },
    
    "divisibleBy" : {
      "type" : "number",
      "minimum" : 0,
      "exclusiveMinimum" : true,
      "default" : 1
    },
    
    "disallow" : {
      "type" : ["string", "array"],
      "items" : {
        "type" : ["string", {"$ref" : "#"}]
      },
      "uniqueItems" : true
    },
    
    "extends" : {
      "type" : [{"$ref" : "#"}, "array"],
      "items" : {"$ref" : "#"},
      "default" : {}
    },
    
    "id" : {
      "type" : "string",
      "format" : "uri"
    },
    
    "$ref" : {
      "type" : "string",
      "format" : "uri"
    },
    
    "$schema" : {
      "type" : "string",
      "format" : "uri"
    }
  },
  
  "dependencies" : {
    "exclusiveMinimum" : "minimum",
    "exclusiveMaximum" : "maximum"
  },
  
  "default" : {}
}

================================================
FILE: resources/draft-04.json
================================================
{
    "id": "http://json-schema.org/draft-04/schema#",
    "$schema": "http://json-schema.org/draft-04/schema#",
    "description": "Core schema meta-schema",
    "definitions": {
        "schemaArray": {
            "type": "array",
            "minItems": 1,
            "items": { "$ref": "#" }
        },
        "positiveInteger": {
            "type": "integer",
            "minimum": 0
        },
        "positiveIntegerDefault0": {
            "allOf": [ { "$ref": "#/definitions/positiveInteger" }, { "default": 0 } ]
        },
        "simpleTypes": {
            "enum": [ "array", "boolean", "integer", "null", "number", "object", "string" ]
        },
        "stringArray": {
            "type": "array",
            "items": { "type": "string" },
            "minItems": 1,
            "uniqueItems": true
        }
    },
    "type": "object",
    "properties": {
        "id": {
            "type": "string",
            "format": "uri"
        },
        "$schema": {
            "type": "string",
            "format": "uri"
        },
        "title": {
            "type": "string"
        },
        "description": {
            "type": "string"
        },
        "default": {},
        "multipleOf": {
            "type": "number",
            "minimum": 0,
            "exclusiveMinimum": true
        },
        "maximum": {
            "type": "number"
        },
        "exclusiveMaximum": {
            "type": "boolean",
            "default": false
        },
        "minimum": {
            "type": "number"
        },
        "exclusiveMinimum": {
            "type": "boolean",
            "default": false
        },
        "maxLength": { "$ref": "#/definitions/positiveInteger" },
        "minLength": { "$ref": "#/definitions/positiveIntegerDefault0" },
        "pattern": {
            "type": "string",
            "format": "regex"
        },
        "additionalItems": {
            "anyOf": [
                { "type": "boolean" },
                { "$ref": "#" }
            ],
            "default": {}
        },
        "items": {
            "anyOf": [
                { "$ref": "#" },
                { "$ref": "#/definitions/schemaArray" }
            ],
            "default": {}
        },
        "maxItems": { "$ref": "#/definitions/positiveInteger" },
        "minItems": { "$ref": "#/definitions/positiveIntegerDefault0" },
        "uniqueItems": {
            "type": "boolean",
            "default": false
        },
        "maxProperties": { "$ref": "#/definitions/positiveInteger" },
        "minProperties": { "$ref": "#/definitions/positiveIntegerDefault0" },
        "required": { "$ref": "#/definitions/stringArray" },
        "additionalProperties": {
            "anyOf": [
                { "type": "boolean" },
                { "$ref": "#" }
            ],
            "default": {}
        },
        "definitions": {
            "type": "object",
            "additionalProperties": { "$ref": "#" },
            "default": {}
        },
        "properties": {
            "type": "object",
            "additionalProperties": { "$ref": "#" },
            "default": {}
        },
        "patternProperties": {
            "type": "object",
            "additionalProperties": { "$ref": "#" },
            "default": {}
        },
        "dependencies": {
            "type": "object",
            "additionalProperties": {
                "anyOf": [
                    { "$ref": "#" },
                    { "$ref": "#/definitions/stringArray" }
                ]
            }
        },
        "enum": {
            "type": "array",
            "minItems": 1,
            "uniqueItems": true
        },
        "type": {
            "anyOf": [
                { "$ref": "#/definitions/simpleTypes" },
                {
                    "type": "array",
                    "items": { "$ref": "#/definitions/simpleTypes" },
                    "minItems": 1,
                    "uniqueItems": true
                }
            ]
        },
        "allOf": { "$ref": "#/definitions/schemaArray" },
        "anyOf": { "$ref": "#/definitions/schemaArray" },
        "oneOf": { "$ref": "#/definitions/schemaArray" },
        "not": { "$ref": "#" }
    },
    "dependencies": {
        "exclusiveMaximum": [ "maximum" ],
        "exclusiveMinimum": [ "minimum" ]
    },
    "default": {}
}

================================================
FILE: sample_apis/album/cover_api.rb
================================================
# -*- encoding : utf-8 -*-
module AlbumServices
  class Cover < Grape::API
    format :json
    desc 'Ping'
    namespace :album do
      get ':id/cover' do
        { cover: 'image' }
      end
    end
  end
end


================================================
FILE: sample_apis/config.ru
================================================
require 'grape'
require 'grape-swagger'
require 'json'
Dir[File.expand_path('../**/*_api.rb', __FILE__)].each do |f|
    puts "Requiring #{f}"
  require f
end

module DummyServices
  class API < Grape::API
    prefix 'api'
    format :json
    mount DummyServices::Hello
    mount DummyServices::Ping
    mount DummyServices::Echo
    mount DummyServices::Files
    mount DummyServices::Reverse
    mount AlbumServices::Cover
    add_swagger_documentation # api_version: 'v1'
  end
end
DummyServices::API.routes.each do |route|
  p route
end
run DummyServices::API


================================================
FILE: sample_apis/echo_api.rb
================================================
# -*- encoding : utf-8 -*-
# This illustrates simple get w/ params and post w/ body services
# It also illustrates having two services w/ the same endpoint (just different HTTP methods)
module DummyServices
  class Echo < Grape::API
    format :json
    content_type :txt, 'text/plain'

    helpers do
      def echo(message)
        error!('Bad Request', 400) unless message
        message
      end
    end

    # curl localhost:5000/api/echo --get --data-urlencode 'msg={"one fish": "two fish"}' -vv
    get '/echo' do
      echo params[:msg]
    end

    # curl localhost:5000/api/echo -H 'Content-Type: text/plain' -d '{"red fish": "blue fish"}' -vv
    post '/echo' do
      echo env['api.request.body']
    end
  end
end


================================================
FILE: sample_apis/files_api.rb
================================================
# -*- encoding : utf-8 -*-
# This example should illustrate
#   - Authentication
#   - Expect: 100-continue
#   - Binary data
#   - Content negotiation
#   - Etags
#   - Collections
module DummyServices
  class PartialRequestException < StandardError
    attr_reader :http_status, :msg
    def initialize(http_status, msg)
      @http_status = http_status
      @msg = msg
    end
  end

  class Files < Grape::API
    format :json
    content_type :binary, 'application/octet-stream'
    content_type :pdf, 'application/pdf'

    before do
      error!('Unauthorized', 401) unless env['HTTP_X_AUTH_TOKEN'] == '12345'

      if env['HTTP_EXPECT'] == '100-continue'
        # Can't use Content-Type because Grape tries to handle it, causing problems
        case env['CONTENT_TYPE']
        when 'application/pdf'
          fail DummyServices::PartialRequestException.new(100, 'Continue')
        when 'application/webm'
          fail DummyServices::PartialRequestException.new(415, 'Unsupported Media Type')
        else
          fail DummyServices::PartialRequestException.new(417, 'Expectation Failed')
        end
      end
    end

    rescue_from DummyServices::PartialRequestException do |e|
      Rack::Response.new([], e.http_status, {}).finish
    end

    namespace '/files' do
      # curl localhost:5000/api/files/myfile.txt -H 'X-Auth-Token: 12345' -d @myfile.txt -vv
      put ':name' do
        params[:name]
      end
    end
  end
end


================================================
FILE: sample_apis/hello_api.rb
================================================
# -*- encoding : utf-8 -*-
#  This illustrates a simple get service
module DummyServices
  class Hello < Grape::API
    format :json
    content_type :json, 'application/json'

    desc 'Hello'
    get '/hello' do
      header 'Vary', 'Accept'
      { message: 'Hello World!' }
    end
  end
end


================================================
FILE: sample_apis/ping_api.rb
================================================
# -*- encoding : utf-8 -*-
#  This illustrates a simple get service
module DummyServices
  class Ping < Grape::API
    format :json
    desc 'Ping'
    get '/ping' do
      { ping: 'pong' }
    end
  end
end


================================================
FILE: sample_apis/reverse_api.rb
================================================
# -*- encoding : utf-8 -*-
# This illustrates simple get w/ params and post w/ body services
# It also illustrates having two services w/ the same endpoint (just different HTTP methods)
module DummyServices
  class Reverse < Grape::API
    format :txt

    helpers do
      def echo(message)
        error!('Bad Request', 400) unless message
        message
      end
    end

    # curl localhost:5000/api/echo -H 'Content-Type: application/json' -d '{"red fish": "blue fish"}' -vv
    post '/reverse' do
      echo(env['api.request.body']).reverse
    end
  end
end


================================================
FILE: sample_apis/user_api.rb
================================================
# -*- encoding : utf-8 -*-
# A siple JSON service to demonstrate request/response bodies

require 'securerandom'

module DummyServices
  class Echo < Grape::API
    format :json

    post '/users' do
      user = env['api.request.body']
      user[:id] = SecureRandom.uuid
      user
    end
  end
end


================================================
FILE: samples/README.md
================================================
Welcome to the Pacto usage samples!

We have a listing of [sample contracts](contracts/README.html).

Highlighted samples:

- *[Configuration](configuration.html)*: Shows the available Pacto configuration
- *[Generation](generation.html)*: Shows how to generate Contracts
- *[RSpec](rspec.html)*: Shows the usage of RSpec expectations for collaboration tests

See the Table of Contents (upper right corner) for a full list of available samples.


================================================
FILE: samples/Rakefile
================================================
require 'pacto/rake_task' # FIXME: This require turns on WebMock
WebMock.allow_net_connect!


================================================
FILE: samples/configuration.rb
================================================
# -*- encoding : utf-8 -*-
# Just require pacto to add it to your project.
require 'pacto'
# Pacto will disable live connections, so you will get an error if
# your code unexpectedly calls an service that was not stubbed.  If you
# want to re-enable connections, run `WebMock.allow_net_connect!`
WebMock.allow_net_connect!

# Pacto can be configured via a block:
Pacto.configure do |c|
  # Path for loading/storing contracts.
  c.contracts_path = 'contracts'
  # If the request matching should be strict (especially regarding HTTP Headers).
  c.strict_matchers = true
  # You can set the Ruby Logger used by Pacto.
  c.logger = Pacto::Logger::SimpleLogger.instance
  # (Deprecated) You can specify a callback for post-processing responses.  Note that only one hook
  # can be active, and specifying your own will disable ERB post-processing.
  c.register_hook do |_contracts, request, _response|
    puts "Received #{request}"
  end
  # Options to pass to the [json-schema-generator](https://github.com/maxlinc/json-schema-generator) while generating contracts.
  c.generator_options = { schema_version: 'draft3' }
end

# You can also do inline configuration.  This example tells the json-schema-generator to store default values in the schema.
Pacto.configuration.generator_options = { defaults: true }

# If you're using Pacto's rspec matchers you might want to configure a reset between each scenario
require 'pacto/rspec'
RSpec.configure do |c|
  c.after(:each)  { Pacto.clear! }
end


================================================
FILE: samples/consumer.rb
================================================
# -*- encoding : utf-8 -*-
require 'pacto'
Pacto.load_contracts 'contracts', 'http://localhost:5000'
WebMock.allow_net_connect!

interactions = Pacto.simulate_consumer :my_client do
  request 'Ping'
  request 'Echo', body: ->(body) { body.reverse },
                  headers: (proc do |headers|
                    headers['Content-Type'] = 'text/json'
                    headers['Accept'] = 'none'
                    headers
                  end)
end
puts interactions


================================================
FILE: samples/contracts/README.md
================================================
This folder contains sample contracts.


================================================
FILE: samples/contracts/contract.js
================================================
// Pacto Contracts describe the constraints we want to put on interactions between a consumer and a provider.  It sets some expectations about the headers expected for both the request and response, the expected response status code.  It also uses [json-schema](http://json-schema.org/) to define the allowable request body (if one should exist) and response body.
{
  // The Request section comes first.  In this case, we're just describing a simple get request that does not require any parameters or a request body.
  "request": {
    "headers": {
      // A request must exactly match these headers for Pacto to believe the request matches the contract, unless `Pacto.configuration.strict_matchers` is false.
      "Accept": "application/vnd.github.beta+json",
      "Accept-Encoding": "gzip;q=1.0,deflate;q=0.6,identity;q=0.3"
    },
    // The `method` and `path` are required.  The `path` may be an [rfc6570 URI template](http://tools.ietf.org/html/rfc6570) for more flexible matching.
    "method": "get",
    "path": "/repos/thoughtworks/pacto/readme"
  },
  "response": {
    "headers": {
      "Content-Type": "application/json; charset=utf-8",
      "Status": "200 OK",
      "Cache-Control": "public, max-age=60, s-maxage=60",
      "Etag": "\"fc8e78b0a9694de66d47317768b20820\"",
      "Vary": "Accept, Accept-Encoding",
      "Access-Control-Allow-Credentials": "true",
      "Access-Control-Expose-Headers": "ETag, Link, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval",
      "Access-Control-Allow-Origin": "*"
    },
    "status": 200,
    "body": {
      "$schema": "http://json-schema.org/draft-03/schema#",
      "description": "Generated from https://api.github.com/repos/thoughtworks/pacto/readme with shasum 3ae59164c6d9f84c0a81f21fb63e17b3b8ce6894",
      "type": "object",
      "required": true,
      "properties": {
        "name": {
          "type": "string",
          "required": true
        },
        "path": {
          "type": "string",
          "required": true
        },
        "sha": {
          "type": "string",
          "required": true
        },
        "size": {
          "type": "integer",
          "required": true
        },
        "url": {
          "type": "string",
          "required": true
        },
        "html_url": {
          "type": "string",
          "required": true
        },
        "git_url": {
          "type": "string",
          "required": true
        },
        "type": {
          "type": "string",
          "required": true
        },
        "content": {
          "type": "string",
          "required": true
        },
        "encoding": {
          "type": "string",
          "required": true
        },
        "_links": {
          "type": "object",
          "required": true,
          "properties": {
            "self": {
              "type": "string",
              "required": true
            },
            "git": {
              "type": "string",
              "required": true
            },
            "html": {
              "type": "string",
              "required": true
            }
          }
        }
      }
    }
  }
}

================================================
FILE: samples/contracts/get_album_cover.json
================================================
{
  "request": {
    "headers": {
    },
    "http_method": "get",
    "path": "/api/album/{id}/cover"
  },
  "response": {
    "headers": {
      "Content-Type": "application/json"
    },
    "status": 200,
    "schema": {
      "$schema": "http://json-schema.org/draft-03/schema#",
      "description": "Generated from http://localhost:5000/api/album/1/cover with shasum db640385d2b346db760dbfd78058101663197bcf",
      "type": "object",
      "required": true,
      "properties": {
        "cover": {
          "type": "string",
          "required": true
        }
      }
    }
  },
  "examples": {
    "default": {
      "request": {
        "method": "get",
        "uri": "http://localhost:5000/api/album/1/cover",
        "headers": {
          "User-Agent": "Faraday v0.9.0",
          "Accept-Encoding": "gzip;q=1.0,deflate;q=0.6,identity;q=0.3",
          "Accept": "*/*"
        }
      },
      "response": {
        "status": 200,
        "headers": {
          "Content-Type": "application/json",
          "Content-Length": "17"
        },
        "body": "{\"cover\":\"image\"}"
      }
    }
  },
  "name": "Get Album Cover"
}

================================================
FILE: samples/contracts/localhost/api/echo.json
================================================
{
  "name": "Echo",
  "request": {
    "headers": {
      "Content-Type": "text/plain"
    },
    "http_method": "post",
    "path": "/api/echo",
    "schema": {
      "$schema": "http://json-schema.org/draft-03/schema#",
      "oneOf": [
        { "type": "string", "required": true },
        { "type": "object", "required": true }
      ]
    }
  },
  "response": {
    "status": 201,
    "schema": {
      "$schema": "http://json-schema.org/draft-03/schema#",
      "oneOf": [
        { "type": "string", "required": true },
        { "type": "object", "required": true }
      ]
    }
  },
  "examples": {
    "foo": {
      "request": {
        "body": "foo"
      },
      "response": {
        "body": "foo"
      }
    }
  }
}


================================================
FILE: samples/contracts/localhost/api/ping.json
================================================
{
  "name": "Ping",
  "request": {
    "headers": {
    },
    "http_method": "get",
    "path": "/api/ping"
  },
  "response": {
    "headers": {
      "Content-Type": "application/json"
    },
    "status": 200,
    "schema": {
      "$schema": "http://json-schema.org/draft-03/schema#",
      "description": "Generated from http://localhost:9292/api/ping with shasum 2cf3478c18e3ce877fb823ed435cb75b4a801aaa",
      "type": "object",
      "required": true,
      "properties": {
        "ping": {
          "type": "string",
          "required": true
        }
      }
    }
  },
  "examples": {
    "default": {
      "request": {
      },
      "response": {
        "body": {
          "ping": "pong - from the example!"
        }
      }
    }
  }
}


================================================
FILE: samples/contracts/user.json
================================================
{
  "name": "User",
  "request": {
    "headers": {
      "Content-Type": "application/json"
    },
    "http_method": "post",
    "path": "/api/users",
    "schema": {
      "$schema": "http://json-schema.org/draft-03/schema#",
      "type": "object",
      "properties": {
        "firstName": {"type": "string", "required": true},
        "lastName": {"type": "string", "required": true}
      }
    }
  },
  "response": {
    "status": 201,
    "schema": {
      "$schema": "http://json-schema.org/draft-03/schema#",
      "type": "object",
      "properties": {
        "id": { "type": "string", "required": true },
        "firstName": {"type": "string", "required": true},
        "lastName": {"type": "string", "required": true}
      }
    }
  },
  "examples": {
    "max": {
      "request": {
        "headers": {
          "Content-Type": "application/json"
        },
        "body": {
          "firstName": "Max",
          "lastName": "Lincoln"
        }
      },
      "response": {
        "body": {
          "id": "026ed411-6d12-4a76-a3c7-19758a872455",
          "firstName": "Max",
          "lastName": "Lincoln"
        }
      }
    }
  }
}



================================================
FILE: samples/cops.rb
================================================
# -*- encoding : utf-8 -*-
require 'rspec'
require 'rspec/autorun'
require 'pacto'

Pacto.configure do |c|
  c.contracts_path = 'contracts'
end
Pacto.validate!

# You can create a custom cop that investigates the request/response and sees if it complies with a
# contract. The cop should return a list of citations if it finds any problems.
class MyCustomCop
  def investigate(_request, _response, contract)
    citations = []
    citations << 'Contract must have a request schema' if contract.request.schema.empty?
    citations << 'Contract must have a response schema' if contract.response.schema.empty?
    citations
  end
end

Pacto::Cops.active_cops << MyCustomCop.new

contracts = Pacto.load_contracts('contracts', 'http://localhost:5000')
contracts.stub_providers
puts contracts.simulate_consumers

# Or you can completely replace the default set of validators
Pacto::Cops.registered_cops.clear
Pacto::Cops.register_cop Pacto::Cops::ResponseBodyCop

contracts = Pacto.load_contracts('contracts', 'http://localhost:5000')
puts contracts.simulate_consumers


================================================
FILE: samples/forensics.rb
================================================
# -*- encoding : utf-8 -*-
# Pacto has a few RSpec matchers to help you ensure a **consumer** and **producer** are
# interacting properly. First, let's setup the rspec suite.
require 'rspec/autorun' # Not generally needed
require 'pacto/rspec'
WebMock.allow_net_connect!
Pacto.validate!
Pacto.load_contracts('contracts', 'http://localhost:5000').stub_providers

# It's usually a good idea to reset Pacto between each scenario. `Pacto.reset` just clears the
# data and metrics about which services were called. `Pacto.clear!` also resets all configuration
# and plugins.
RSpec.configure do |c|
  c.after(:each)  { Pacto.reset }
end

# Pacto provides some RSpec matchers related to contract testing, like making sure
# Pacto didn't received any unrecognized requests (`have_unmatched_requests`) and that
# the HTTP requests matched up with the terms of the contract (`have_failed_investigations`).
describe Faraday do
  let(:connection) { described_class.new(url: 'http://localhost:5000') }

  it 'passes contract tests' do
    connection.get '/api/ping'
    expect(Pacto).to_not have_failed_investigations
    expect(Pacto).to_not have_unmatched_requests
  end
end

# There are also some matchers for collaboration testing, so you can make sure each scenario is
# calling the expected services and sending the right type of data.
describe Faraday do
  let(:connection) { described_class.new(url: 'http://localhost:5000') }
  before(:each) do
    connection.get '/api/ping'

    connection.post do |req|
      req.url '/api/echo'
      req.headers['Content-Type'] = 'application/json'
      req.body = '{"foo": "bar"}'
    end
  end

  it 'calls the ping service' do
    expect(Pacto).to have_validated(:get, 'http://localhost:5000/api/ping').against_contract('Ping')
  end

  it 'sends data to the echo service' do
    expect(Pacto).to have_investigated('Ping').with_response(body: hash_including('ping' => 'pong - from the example!'))
    expect(Pacto).to have_investigated('Echo').with_request(body: hash_including('foo' => 'bar'))
    echoed_body = { 'foo' => 'bar' }
    expect(Pacto).to have_investigated('Echo').with_request(body: echoed_body).with_response(body: echoed_body)
  end
end


================================================
FILE: samples/generation.rb
================================================
# -*- encoding : utf-8 -*-
# Some generation related [configuration](configuration.rb).
require 'pacto'
WebMock.allow_net_connect!
Pacto.configure do |c|
  c.contracts_path = 'contracts'
end
WebMock.allow_net_connect!

# Once we call `Pacto.generate!`, Pacto will record contracts for all requests it detects.
Pacto.generate!

# Now, if we run any code that makes an HTTP call (using an
# [HTTP library supported by WebMock](https://github.com/bblimke/webmock#supported-http-libraries))
# then Pacto will generate a Contract based on the HTTP request/response.
#
# This code snippet will generate a Contract and save it to `contracts/samples/contracts/localhost/api/ping.json`.
require 'faraday'
conn = Faraday.new(url: 'http://localhost:5000')
response = conn.get '/api/ping'
# We're getting back real data from GitHub, so this should be the actual file encoding.
puts response.body

# The generated contract will contain expectations based on the request/response we observed,
# including a best-guess at an appropriate json-schema.  Our heuristics certainly aren't foolproof,
# so you might want to customize schema!

# Here's another sample that sends a post request.
conn.post do |req|
  req.url '/api/echo'
  req.headers['Content-Type'] = 'application/json'
  req.body = '{"red fish": "blue fish"}'
end

# You can provide hints to Pacto to help it generate contracts. For example, Pacto doesn't have
# a good way to know a good name and correct URI template for the service. That means that Pacto
# will not know if two similar requests are for the same service or two different services, and
# will be forced to give names based on the URI that are not good display names.

# The hint below tells Pacto that requests to http://localhost:5000/album/1/cover and http://localhost:5000/album/2/cover
# are both going to the same service, which is known as "Get Album Cover". This hint will cause Pacto to
# generate a Contract for "Get Album Cover" and save it to `contracts/get_album_cover.json`, rather than two
# contracts that are stored at `contracts/localhost/album/1/cover.json` and `contracts/localhost/album/2/cover.json`.
Pacto::Generator.configure do |c|
  c.hint 'Get Album Cover', http_method: :get, host: 'http://localhost:5000', path: '/api/album/{id}/cover'
end
conn.get '/api/album/1/cover'
conn.get '/api/album/2/cover'


================================================
FILE: samples/rake_tasks.sh
================================================
# # Rake tasks

# ## This is a test!
# [That](www.google.com) markdown works
bundle exec rake pacto:meta_validate['contracts']

bundle exec rake pacto:validate['http://localhost:5000','contracts']


================================================
FILE: samples/rspec.rb
================================================
# -*- encoding : utf-8 -*-


================================================
FILE: samples/samples.rb
================================================
# -*- encoding : utf-8 -*-
# # Overview
# Welcome to the Pacto usage samples!
# This document gives a quick overview of the main features.
#
# You can browse the Table of Contents (upper right corner) to view additional samples.
#
# In addition to this document, here are some highlighted samples:
# <ul>
#   <li><a href="configuration">Configuration</a>: Shows all available configuration options</li>
#   <li><a href="generation">Generation</a>: More details on generation</li>
#   <li><a href="rspec">RSpec</a>: More samples for RSpec expectations</li>
# </ul>

# You can also find other samples using the Table of Content (upper right corner), including sample contracts.

# # Getting started
# Once you've installed the Pacto gem, you just require it.  If you want, you can also require the Pacto rspec expectations.
require 'pacto'
require 'pacto/rspec'
# Pacto will disable live connections, so you will get an error if
# your code unexpectedly calls an service that was not stubbed.  If you
# want to re-enable connections, run `WebMock.allow_net_connect!`
WebMock.allow_net_connect!

# Pacto can be configured via a block.  The `contracts_path` option tells Pacto where it should load or save contracts.  See the [Configuration](configuration.html) for all the available options.
Pacto.configure do |c|
  c.contracts_path = 'contracts'
end

# # Generating a Contract

# Calling `Pacto.generate!` enables contract generation.
# Pacto.generate!

# Now, if we run any code t
Download .txt
gitextract__ymcm0w_/

├── .gitignore
├── .rspec
├── .rubocop.yml
├── .travis.yml
├── CONTRIBUTING.md
├── Gemfile
├── Guardfile
├── LICENSE.txt
├── Procfile
├── README.md
├── Rakefile
├── TODO.md
├── appveyor.yml
├── bin/
│   ├── pacto
│   └── pacto-server
├── changelog.md
├── docs/
│   ├── configuration.md
│   ├── consumer.md
│   ├── cops.md
│   ├── forensics.md
│   ├── generation.md
│   ├── rake_tasks.md
│   ├── rspec.md
│   ├── samples.md
│   ├── server.md
│   ├── server_cli.md
│   └── stenographer.md
├── features/
│   ├── configuration/
│   │   └── strict_matchers.feature
│   ├── evolve/
│   │   ├── README.md
│   │   └── existing_services.feature
│   ├── generate/
│   │   ├── README.md
│   │   └── generation.feature
│   ├── steps/
│   │   └── pacto_steps.rb
│   ├── stub/
│   │   ├── README.md
│   │   └── templates.feature
│   ├── support/
│   │   └── env.rb
│   └── validate/
│       ├── README.md
│       ├── meta_validation.feature
│       └── validation.feature
├── lib/
│   ├── pacto/
│   │   ├── actor.rb
│   │   ├── actors/
│   │   │   ├── from_examples.rb
│   │   │   └── json_generator.rb
│   │   ├── body_parsing.rb
│   │   ├── cli/
│   │   │   └── helpers.rb
│   │   ├── cli.rb
│   │   ├── consumer/
│   │   │   └── faraday_driver.rb
│   │   ├── consumer.rb
│   │   ├── contract.rb
│   │   ├── contract_factory.rb
│   │   ├── contract_files.rb
│   │   ├── contract_set.rb
│   │   ├── cops/
│   │   │   ├── body_cop.rb
│   │   │   ├── request_body_cop.rb
│   │   │   ├── response_body_cop.rb
│   │   │   ├── response_header_cop.rb
│   │   │   └── response_status_cop.rb
│   │   ├── cops.rb
│   │   ├── core/
│   │   │   ├── configuration.rb
│   │   │   ├── contract_registry.rb
│   │   │   ├── hook.rb
│   │   │   ├── http_middleware.rb
│   │   │   ├── investigation_registry.rb
│   │   │   ├── modes.rb
│   │   │   ├── pacto_request.rb
│   │   │   └── pacto_response.rb
│   │   ├── dash.rb
│   │   ├── erb_processor.rb
│   │   ├── errors.rb
│   │   ├── extensions.rb
│   │   ├── forensics/
│   │   │   ├── investigation_filter.rb
│   │   │   └── investigation_matcher.rb
│   │   ├── formats/
│   │   │   ├── legacy/
│   │   │   │   ├── contract.rb
│   │   │   │   ├── contract_builder.rb
│   │   │   │   ├── contract_factory.rb
│   │   │   │   ├── contract_generator.rb
│   │   │   │   ├── generator/
│   │   │   │   │   └── filters.rb
│   │   │   │   ├── generator_hint.rb
│   │   │   │   ├── request_clause.rb
│   │   │   │   └── response_clause.rb
│   │   │   └── swagger/
│   │   │       ├── contract.rb
│   │   │       ├── contract_factory.rb
│   │   │       ├── request_clause.rb
│   │   │       └── response_clause.rb
│   │   ├── generator.rb
│   │   ├── handlers/
│   │   │   ├── json_handler.rb
│   │   │   └── text_handler.rb
│   │   ├── hooks/
│   │   │   └── erb_hook.rb
│   │   ├── investigation.rb
│   │   ├── logger.rb
│   │   ├── meta_schema.rb
│   │   ├── observers/
│   │   │   └── stenographer.rb
│   │   ├── provider.rb
│   │   ├── rake_task.rb
│   │   ├── request_clause.rb
│   │   ├── request_pattern.rb
│   │   ├── resettable.rb
│   │   ├── response_clause.rb
│   │   ├── rspec.rb
│   │   ├── server/
│   │   │   ├── cli.rb
│   │   │   ├── config.rb
│   │   │   ├── proxy.rb
│   │   │   └── settings.rb
│   │   ├── server.rb
│   │   ├── stubs/
│   │   │   ├── uri_pattern.rb
│   │   │   └── webmock_adapter.rb
│   │   ├── test_helper.rb
│   │   ├── ui.rb
│   │   ├── uri.rb
│   │   └── version.rb
│   └── pacto.rb
├── pacto-server.gemspec
├── pacto.gemspec
├── resources/
│   ├── contract_schema.json
│   ├── draft-03.json
│   └── draft-04.json
├── sample_apis/
│   ├── album/
│   │   └── cover_api.rb
│   ├── config.ru
│   ├── echo_api.rb
│   ├── files_api.rb
│   ├── hello_api.rb
│   ├── ping_api.rb
│   ├── reverse_api.rb
│   └── user_api.rb
├── samples/
│   ├── README.md
│   ├── Rakefile
│   ├── configuration.rb
│   ├── consumer.rb
│   ├── contracts/
│   │   ├── README.md
│   │   ├── contract.js
│   │   ├── get_album_cover.json
│   │   ├── localhost/
│   │   │   └── api/
│   │   │       ├── echo.json
│   │   │       └── ping.json
│   │   └── user.json
│   ├── cops.rb
│   ├── forensics.rb
│   ├── generation.rb
│   ├── rake_tasks.sh
│   ├── rspec.rb
│   ├── samples.rb
│   ├── scripts/
│   │   ├── bootstrap
│   │   └── wrapper
│   ├── server.rb
│   ├── server_cli.sh
│   └── stenographer.rb
├── spec/
│   ├── coveralls_helper.rb
│   ├── fabricators/
│   │   ├── contract_fabricator.rb
│   │   ├── http_fabricator.rb
│   │   └── webmock_fabricator.rb
│   ├── fixtures/
│   │   └── contracts/
│   │       ├── deprecated/
│   │       │   └── deprecated_contract.json
│   │       ├── legacy/
│   │       │   ├── contract.json
│   │       │   ├── contract_with_examples.json
│   │       │   ├── simple_contract.json
│   │       │   ├── strict_contract.json
│   │       │   └── templating_contract.json
│   │       └── swagger/
│   │           └── petstore.yaml
│   ├── integration/
│   │   ├── e2e_spec.rb
│   │   ├── forensics/
│   │   │   └── integration_matcher_spec.rb
│   │   ├── rspec_spec.rb
│   │   └── templating_spec.rb
│   ├── spec_helper.rb
│   └── unit/
│       ├── actors/
│       │   ├── from_examples_spec.rb
│       │   └── json_generator_spec.rb
│       └── pacto/
│           ├── actor_spec.rb
│           ├── configuration_spec.rb
│           ├── consumer/
│           │   └── faraday_driver_spec.rb
│           ├── contract_factory_spec.rb
│           ├── contract_files_spec.rb
│           ├── contract_set_spec.rb
│           ├── contract_spec.rb
│           ├── cops/
│           │   ├── body_cop_spec.rb
│           │   ├── response_header_cop_spec.rb
│           │   └── response_status_cop_spec.rb
│           ├── cops_spec.rb
│           ├── core/
│           │   ├── configuration_spec.rb
│           │   ├── contract_registry_spec.rb
│           │   ├── http_middleware_spec.rb
│           │   ├── investigation_spec.rb
│           │   └── modes_spec.rb
│           ├── erb_processor_spec.rb
│           ├── extensions_spec.rb
│           ├── formats/
│           │   ├── legacy/
│           │   │   ├── contract_builder_spec.rb
│           │   │   ├── contract_factory_spec.rb
│           │   │   ├── contract_generator_spec.rb
│           │   │   ├── contract_spec.rb
│           │   │   ├── generator/
│           │   │   │   └── filters_spec.rb
│           │   │   ├── request_clause_spec.rb
│           │   │   └── response_clause_spec.rb
│           │   └── swagger/
│           │       ├── contract_factory_spec.rb
│           │       └── contract_spec.rb
│           ├── hooks/
│           │   └── erb_hook_spec.rb
│           ├── investigation_registry_spec.rb
│           ├── logger_spec.rb
│           ├── meta_schema_spec.rb
│           ├── pacto_spec.rb
│           ├── request_pattern_spec.rb
│           ├── stubs/
│           │   ├── observers/
│           │   │   └── stenographer_spec.rb
│           │   ├── uri_pattern_spec.rb
│           │   └── webmock_adapter_spec.rb
│           └── uri_spec.rb
└── tasks/
    └── release.rake
Download .txt
SYMBOL INDEX (581 symbols across 118 files)

FILE: features/support/env.rb
  class PactoWorld (line 16) | class PactoWorld

FILE: lib/pacto.rb
  type Pacto (line 62) | module Pacto
    function configuration (line 64) | def configuration
    function contract_registry (line 68) | def contract_registry
    function reset (line 73) | def reset
    function clear! (line 79) | def clear!
    function configure (line 86) | def configure
    function contracts_for (line 90) | def contracts_for(request_signature)
    function validate_contract (line 95) | def validate_contract(contract)
    function load_contract (line 100) | def load_contract(contract_path, host, format = :legacy)
    function load_contracts (line 104) | def load_contracts(contracts_path, host, format = :legacy)

FILE: lib/pacto/actor.rb
  type Pacto (line 2) | module Pacto
    class Actor (line 3) | class Actor

FILE: lib/pacto/actors/from_examples.rb
  type Pacto (line 2) | module Pacto
    type Actors (line 3) | module Actors
      class FirstExampleSelector (line 4) | class FirstExampleSelector
        method select (line 5) | def self.select(examples, _values)
      class RandomExampleSelector (line 9) | class RandomExampleSelector
        method select (line 10) | def self.select(examples, _values)
      class NamedExampleSelector (line 14) | class NamedExampleSelector
        method select (line 15) | def self.select(examples, values)
      class FromExamples (line 24) | class FromExamples < Actor
        method initialize (line 25) | def initialize(fallback_actor = JSONGenerator.new, selector = Pact...
        method build_request (line 30) | def build_request(contract, values = {})
        method build_response (line 45) | def build_response(contract, values = {})
        method example_uri_values (line 56) | def example_uri_values(contract)

FILE: lib/pacto/actors/json_generator.rb
  type Pacto (line 2) | module Pacto
    type Actors (line 3) | module Actors
      class JSONGenerator (line 4) | class JSONGenerator < Actor
        method build_request (line 5) | def build_request(contract, values = {})
        method build_response (line 13) | def build_response(contract, _values = {})

FILE: lib/pacto/body_parsing.rb
  type Pacto (line 3) | module Pacto
    type Handlers (line 4) | module Handlers
    type BodyParsing (line 9) | module BodyParsing
      function raw_body (line 10) | def raw_body
      function parsed_body (line 17) | def parsed_body
      function content_type (line 23) | def content_type
      function body_handler (line 27) | def body_handler

FILE: lib/pacto/cli.rb
  type Pacto (line 5) | module Pacto
    type CLI (line 6) | module CLI
      class Main (line 7) | class Main < Thor
        method meta_validate (line 11) | def meta_validate(*contracts)
        method validate (line 31) | def validate(*contracts)
        method validation_summary (line 50) | def validation_summary(contracts, invalid_contracts)
        method contract_is_valid? (line 58) | def contract_is_valid?(contract_file, host)

FILE: lib/pacto/cli/helpers.rb
  type Pacto (line 1) | module Pacto
    type CLI (line 2) | module CLI
      type Helpers (line 3) | module Helpers
        function each_contract (line 4) | def each_contract(*contracts)

FILE: lib/pacto/consumer.rb
  type Pacto (line 2) | module Pacto
    function consumers (line 3) | def self.consumers
    function simulate_consumer (line 7) | def self.simulate_consumer(consumer_name = :consumer, &block)
    class Consumer (line 12) | class Consumer
      method initialize (line 16) | def initialize(name = :consumer)
      method simulate (line 20) | def simulate(&block)
      method playback (line 24) | def playback(stenographer_script)
      method reset! (line 29) | def self.reset!
      method actor (line 33) | def actor
      method actor= (line 37) | def actor=(actor)
      method request (line 42) | def request(contract, data = {})
      method reenact (line 51) | def reenact(contract, data = {})
      method driver (line 58) | def driver
      method driver= (line 63) | def driver=(driver)
      method build_request (line 69) | def build_request(contract, data = {})

FILE: lib/pacto/consumer/faraday_driver.rb
  type Pacto (line 2) | module Pacto
    class Consumer (line 3) | class Consumer
      class FaradayDriver (line 4) | class FaradayDriver
        method execute (line 7) | def execute(req)
        method faraday_to_pacto_response (line 27) | def faraday_to_pacto_response(faraday_response)

FILE: lib/pacto/contract.rb
  type Pacto (line 2) | module Pacto
    type Contract (line 3) | module Contract
      function adapter (line 17) | def adapter
      function consumer (line 21) | def consumer
      function provider (line 25) | def provider
      function examples? (line 29) | def examples?
      function stub_contract! (line 33) | def stub_contract!(values = {})
      function simulate_request (line 38) | def simulate_request
      function validate_response (line 44) | def validate_response(request, response)
      function matches? (line 48) | def matches?(request_signature)
      function request_pattern (line 52) | def request_pattern
      function response_for (line 56) | def response_for(pacto_request)
      function execute (line 60) | def execute(additional_values = {})

FILE: lib/pacto/contract_factory.rb
  type Pacto (line 2) | module Pacto
    class ContractFactory (line 3) | class ContractFactory
      method initialize (line 7) | def initialize
      method add_factory (line 11) | def add_factory(format, factory)
      method remove_factory (line 15) | def remove_factory(format)
      method build (line 19) | def build(contract_files, host, format = :legacy)
      method load_contracts (line 26) | def load_contracts(contracts_path, host, format = :legacy)

FILE: lib/pacto/contract_files.rb
  type Pacto (line 3) | module Pacto
    class ContractFiles (line 4) | class ContractFiles
      method for (line 5) | def self.for(path)

FILE: lib/pacto/contract_set.rb
  type Pacto (line 2) | module Pacto
    class ContractSet (line 3) | class ContractSet < Set
      method stub_providers (line 4) | def stub_providers(values = {})
      method simulate_consumers (line 8) | def simulate_consumers

FILE: lib/pacto/cops.rb
  type Pacto (line 2) | module Pacto
    type Cops (line 3) | module Cops
      function reset! (line 7) | def reset!
      function register_cop (line 11) | def register_cop(cop)
      function registered_cops (line 16) | def registered_cops
      function active_cops (line 20) | def active_cops
      function investigate (line 24) | def investigate(request_signature, pacto_response)
      function perform_investigation (line 37) | def perform_investigation(request, response, contract)

FILE: lib/pacto/cops/body_cop.rb
  type Pacto (line 2) | module Pacto
    type Cops (line 3) | module Cops
      class BodyCop (line 4) | class BodyCop
        method validates (line 7) | def self.validates(clause)
        method investigate (line 12) | def self.investigate(request, response, contract)

FILE: lib/pacto/cops/request_body_cop.rb
  type Pacto (line 2) | module Pacto
    type Cops (line 3) | module Cops
      class RequestBodyCop (line 4) | class RequestBodyCop < BodyCop

FILE: lib/pacto/cops/response_body_cop.rb
  type Pacto (line 2) | module Pacto
    type Cops (line 3) | module Cops
      class ResponseBodyCop (line 4) | class ResponseBodyCop < BodyCop

FILE: lib/pacto/cops/response_header_cop.rb
  type Pacto (line 2) | module Pacto
    type Cops (line 3) | module Cops
      class ResponseHeaderCop (line 4) | class ResponseHeaderCop
        method investigate (line 5) | def self.investigate(_request, response, contract)

FILE: lib/pacto/cops/response_status_cop.rb
  type Pacto (line 2) | module Pacto
    type Cops (line 3) | module Cops
      class ResponseStatusCop (line 4) | class ResponseStatusCop
        method investigate (line 5) | def self.investigate(_request, response, contract)

FILE: lib/pacto/core/configuration.rb
  type Pacto (line 2) | module Pacto
    class Configuration (line 3) | class Configuration
      method initialize (line 10) | def initialize # rubocop:disable Metrics/MethodLength
      method logger (line 26) | def logger
      method stenographer_log_file (line 30) | def stenographer_log_file
      method register_hook (line 34) | def register_hook(hook = nil, &block)
      method new_simple_logger (line 45) | def new_simple_logger

FILE: lib/pacto/core/contract_registry.rb
  type Pacto (line 2) | module Pacto
    class ContractNotFound (line 3) | class ContractNotFound < StandardError; end
    class ContractRegistry (line 5) | class ContractRegistry < Set
      method register (line 8) | def register(contract)
      method find_by_name (line 14) | def find_by_name(name)
      method contracts_for (line 20) | def contracts_for(request_signature)

FILE: lib/pacto/core/hook.rb
  type Pacto (line 2) | module Pacto
    class Hook (line 3) | class Hook
      method initialize (line 4) | def initialize(&block)
      method process (line 8) | def process(contracts, request_signature, response)

FILE: lib/pacto/core/http_middleware.rb
  type Pacto (line 4) | module Pacto
    type Core (line 5) | module Core
      class HTTPMiddleware (line 6) | class HTTPMiddleware
        method process (line 10) | def process(request, response)

FILE: lib/pacto/core/investigation_registry.rb
  type Pacto (line 2) | module Pacto
    class InvestigationRegistry (line 3) | class InvestigationRegistry
      method initialize (line 9) | def initialize
      method reset! (line 13) | def self.reset!
      method reset! (line 17) | def reset!
      method validated? (line 22) | def validated?(request_pattern)
      method register_investigation (line 29) | def register_investigation(investigation)
      method unmatched_investigations (line 37) | def unmatched_investigations
      method failed_investigations (line 43) | def failed_investigations
      method stenographer (line 51) | def stenographer
      method create_stenographer (line 55) | def create_stenographer

FILE: lib/pacto/core/modes.rb
  type Pacto (line 2) | module Pacto
    function generate! (line 4) | def generate!
    function stop_generating! (line 8) | def stop_generating!
    function generating? (line 12) | def generating?
    function validate! (line 16) | def validate!
    function stop_validating! (line 20) | def stop_validating!
    function validating? (line 24) | def validating?
    function modes (line 30) | def modes

FILE: lib/pacto/core/pacto_request.rb
  type Pacto (line 4) | module Pacto
    class PactoRequest (line 5) | class PactoRequest
      method initialize (line 11) | def initialize(data)
      method to_hash (line 20) | def to_hash
      method to_s (line 29) | def to_s
      method relative_uri (line 36) | def relative_uri
      method normalize (line 42) | def normalize

FILE: lib/pacto/core/pacto_response.rb
  type Pacto (line 2) | module Pacto
    class PactoResponse (line 3) | class PactoResponse
      method initialize (line 10) | def initialize(data)
      method to_hash (line 17) | def to_hash
      method to_s (line 25) | def to_s

FILE: lib/pacto/dash.rb
  type Pacto (line 4) | module Pacto
    class Dash (line 5) | class Dash < Hashie::Dash

FILE: lib/pacto/erb_processor.rb
  type Pacto (line 2) | module Pacto
    class ERBProcessor (line 3) | class ERBProcessor
      method process (line 5) | def process(contract, values = {})
      method hash_binding (line 14) | def hash_binding(values)

FILE: lib/pacto/errors.rb
  type Pacto (line 1) | module Pacto
    class InvalidContract (line 2) | class InvalidContract < ArgumentError
      method initialize (line 5) | def initialize(errors)
      method message (line 9) | def message
    type Errors (line 14) | module Errors
      function formatted_trace (line 33) | def self.formatted_trace(exception)
      function formatted_exception (line 59) | def self.formatted_exception(exception, title = 'Exception')

FILE: lib/pacto/extensions.rb
  type Pacto (line 2) | module Pacto
    type Extensions (line 3) | module Extensions
      function normalize_header_keys (line 13) | def self.normalize_header_keys(headers)

FILE: lib/pacto/forensics/investigation_filter.rb
  type Pacto (line 2) | module Pacto
    type Forensics (line 3) | module Forensics
      class FilterExhaustedError (line 4) | class FilterExhaustedError < StandardError
        method initialize (line 7) | def initialize(msg, filter, suspects = [])
      class InvestigationFilter (line 18) | class InvestigationFilter
        method initialize (line 23) | def initialize(investigations, track_suspects = true)
        method with_name (line 30) | def with_name(contract_name)
        method with_request (line 39) | def with_request(request_constraints)
        method with_response (line 47) | def with_response(response_constraints)
        method successful_investigations (line 55) | def successful_investigations
        method unsuccessful_investigations (line 59) | def unsuccessful_investigations
        method filter_request_section (line 65) | def filter_request_section(section, filter)
        method filter_response_section (line 76) | def filter_response_section(section, filter)

FILE: lib/pacto/forensics/investigation_matcher.rb
  function describe (line 23) | def describe(obj)

FILE: lib/pacto/formats/legacy/contract.rb
  type Pacto (line 5) | module Pacto
    type Formats (line 6) | module Formats
      type Legacy (line 7) | module Legacy
        class Contract (line 8) | class Contract < Pacto::Dash
          method initialize (line 28) | def initialize(opts)
          method freeze (line 40) | def freeze

FILE: lib/pacto/formats/legacy/contract_builder.rb
  type Pacto (line 2) | module Pacto
    type Formats (line 3) | module Formats
      type Legacy (line 4) | module Legacy
        class ContractBuilder (line 5) | class ContractBuilder < Hashie::Dash # rubocop:disable Metrics/Cla...
          method initialize (line 9) | def initialize(options = {})
          method name= (line 16) | def name=(name)
          method add_example (line 20) | def add_example(name, pacto_request, pacto_response)
          method infer_all (line 27) | def infer_all
          method infer_name (line 33) | def infer_name
          method infer_schemas (line 44) | def infer_schemas
          method without_examples (line 56) | def without_examples
          method generate_contract (line 61) | def generate_contract(request, response)
          method generate_request (line 68) | def generate_request(request, response)
          method generate_response (line 80) | def generate_response(request, response)
          method build_hash (line 89) | def build_hash
          method build (line 96) | def build(&block)
          method example_and_hint (line 102) | def example_and_hint
          method exclude_examples? (line 108) | def exclude_examples?
          method generate_schema (line 112) | def generate_schema(body, generator_options = Pacto.configuratio...
          method clean (line 119) | def clean(data)
          method hint_for (line 123) | def hint_for(pacto_request)

FILE: lib/pacto/formats/legacy/contract_factory.rb
  type Pacto (line 4) | module Pacto
    type Formats (line 5) | module Formats
      type Legacy (line 6) | module Legacy
        class ContractFactory (line 8) | class ContractFactory
          method initialize (line 11) | def initialize(options = {})
          method build_from_file (line 15) | def build_from_file(contract_path, host)
          method files_for (line 28) | def files_for(contracts_dir)
          method body_to_schema (line 43) | def body_to_schema(definition, section, file)
          method method_to_http_method (line 51) | def method_to_http_method(definition, file)

FILE: lib/pacto/formats/legacy/contract_generator.rb
  type Pacto (line 6) | module Pacto
    type Formats (line 7) | module Formats
      type Legacy (line 8) | module Legacy
        class ContractGenerator (line 9) | class ContractGenerator
          method initialize (line 12) | def initialize(_schema_version = 'draft3',
          method generate (line 22) | def generate(pacto_request, pacto_response)
          method generate_from_partial_contract (line 42) | def generate_from_partial_contract(request_file, host)
          method save (line 48) | def save(source, request, response)
          method load_contract_file (line 63) | def load_contract_file(pacto_request)

FILE: lib/pacto/formats/legacy/generator/filters.rb
  type Pacto (line 2) | module Pacto
    type Formats (line 3) | module Formats
      type Legacy (line 4) | module Legacy
        type Generator (line 5) | module Generator
          class Filters (line 6) | class Filters
            method filter_request_headers (line 24) | def filter_request_headers(request, response)
            method filter_response_headers (line 37) | def filter_response_headers(_request, response)

FILE: lib/pacto/formats/legacy/generator_hint.rb
  type Pacto (line 2) | module Pacto
    type Formats (line 3) | module Formats
      type Legacy (line 4) | module Legacy
        class GeneratorHint (line 5) | class GeneratorHint < Pacto::Dash
          method initialize (line 15) | def initialize(data)
          method matches? (line 23) | def matches?(pacto_request)
          method slugify (line 30) | def slugify(path)

FILE: lib/pacto/formats/legacy/request_clause.rb
  type Pacto (line 2) | module Pacto
    type Formats (line 3) | module Formats
      type Legacy (line 4) | module Legacy
        class RequestClause (line 5) | class RequestClause < Pacto::Dash
          class Data (line 13) | class Data < Pacto::Dash
          method initialize (line 22) | def initialize(data)
          method freeze (line 32) | def freeze

FILE: lib/pacto/formats/legacy/response_clause.rb
  type Pacto (line 1) | module Pacto
    type Formats (line 2) | module Formats
      type Legacy (line 3) | module Legacy
        class ResponseClause (line 4) | class ResponseClause
          class Data (line 12) | class Data < Pacto::Dash
          method initialize (line 18) | def initialize(data)
          method freeze (line 24) | def freeze

FILE: lib/pacto/formats/swagger/contract.rb
  type Pacto (line 6) | module Pacto
    type Formats (line 7) | module Formats
      type Swagger (line 8) | module Swagger
        class Contract (line 9) | class Contract < Pacto::Dash
          method initialize (line 31) | def initialize(swagger_api_operation, base_data = {}) # rubocop:...
          method build_examples (line 61) | def build_examples(response)

FILE: lib/pacto/formats/swagger/contract_factory.rb
  type Pacto (line 5) | module Pacto
    type Formats (line 6) | module Formats
      type Swagger (line 7) | module Swagger
        class ContractFactory (line 9) | class ContractFactory
          method load_hints (line 12) | def load_hints(_contract_path, _host = nil)
          method build_from_file (line 16) | def build_from_file(contract_path, host = nil)
          method files_for (line 29) | def files_for(contracts_dir)

FILE: lib/pacto/formats/swagger/request_clause.rb
  type Pacto (line 2) | module Pacto
    type Formats (line 3) | module Formats
      type Swagger (line 4) | module Swagger
        class RequestClause (line 5) | class RequestClause
          method initialize (line 14) | def initialize(swagger_api_operation, base_data = {})
          method schema (line 20) | def schema
          method params (line 26) | def params
          method headers (line 32) | def headers
          method to_hash (line 38) | def to_hash
          method body_parameter (line 46) | def body_parameter

FILE: lib/pacto/formats/swagger/response_clause.rb
  type Pacto (line 2) | module Pacto
    type Formats (line 3) | module Formats
      type Swagger (line 4) | module Swagger
        class ResponseClause (line 5) | class ResponseClause
          method initialize (line 12) | def initialize(swagger_response, _base_data = {})
          method status (line 16) | def status
          method headers (line 20) | def headers
          method schema (line 24) | def schema

FILE: lib/pacto/generator.rb
  type Pacto (line 5) | module Pacto
    type Generator (line 6) | module Generator
      function contract_generator (line 11) | def contract_generator
      function schema_generator (line 16) | def schema_generator
      function configuration (line 20) | def configuration
      function configure (line 24) | def configure
      function hint_for (line 28) | def hint_for(pacto_request)
      class Configuration (line 33) | class Configuration
        method initialize (line 36) | def initialize
        method hint (line 40) | def hint(name, hint_data)

FILE: lib/pacto/handlers/json_handler.rb
  type Pacto (line 3) | module Pacto
    type Handlers (line 4) | module Handlers
      type JSONHandler (line 5) | module JSONHandler
        function raw (line 7) | def raw(body)
        function parse (line 11) | def parse(body)

FILE: lib/pacto/handlers/text_handler.rb
  type Pacto (line 1) | module Pacto
    type Handlers (line 2) | module Handlers
      type TextHandler (line 3) | module TextHandler
        function raw (line 5) | def raw(body)
        function parse (line 9) | def parse(body)

FILE: lib/pacto/hooks/erb_hook.rb
  type Pacto (line 4) | module Pacto
    type Hooks (line 5) | module Hooks
      class ERBHook (line 6) | class ERBHook < Pacto::Hook
        method initialize (line 7) | def initialize
        method process (line 11) | def process(contracts, request_signature, response)

FILE: lib/pacto/investigation.rb
  type Pacto (line 2) | module Pacto
    class Investigation (line 3) | class Investigation
      method initialize (line 7) | def initialize(request, response, contract = nil, citations = nil)
      method successful? (line 14) | def successful?
      method against_contract? (line 18) | def against_contract?(contract_pattern)
      method to_s (line 29) | def to_s
      method summary (line 40) | def summary

FILE: lib/pacto/logger.rb
  type Pacto (line 4) | module Pacto
    type Logger (line 5) | module Logger
      function logger (line 6) | def logger
      class SimpleLogger (line 10) | class SimpleLogger
        method initialize (line 16) | def initialize
        method log (line 20) | def log(log)
        method level= (line 26) | def level=(level)
        method level (line 30) | def level
        method default_level (line 36) | def default_level
        method log_levels (line 40) | def log_levels

FILE: lib/pacto/meta_schema.rb
  type Pacto (line 2) | module Pacto
    class MetaSchema (line 3) | class MetaSchema
      method initialize (line 6) | def initialize(engine = JSON::Validator)
      method validate (line 20) | def validate(definition)

FILE: lib/pacto/observers/stenographer.rb
  type Pacto (line 2) | module Pacto
    type Observers (line 3) | module Observers
      class Stenographer (line 4) | class Stenographer
        method initialize (line 5) | def initialize(output)
        method log_investigation (line 9) | def log_investigation(investigation)
        method name_for (line 25) | def name_for(contract, request)
        method number_of_citations (line 30) | def number_of_citations(investigation)
        method values_for (line 36) | def values_for(_contract, request)

FILE: lib/pacto/provider.rb
  type Pacto (line 2) | module Pacto
    function providers (line 3) | def self.providers
    class Provider (line 7) | class Provider
      method reset! (line 10) | def self.reset!
      method actor (line 14) | def actor
      method actor= (line 18) | def actor=(actor)
      method response_for (line 23) | def response_for(contract, data = {})

FILE: lib/pacto/rake_task.rb
  type Pacto (line 9) | module Pacto
    class RakeTask (line 10) | class RakeTask
      method initialize (line 16) | def initialize
      method run (line 21) | def run(task, args, opts = {})
      method install (line 25) | def install
      method validate_task (line 34) | def validate_task
      method generate_task (line 43) | def generate_task
      method meta_validate (line 54) | def meta_validate
      method generate_contracts (line 65) | def generate_contracts(input_dir, output_dir, host)

FILE: lib/pacto/request_clause.rb
  type Pacto (line 2) | module Pacto
    type RequestClause (line 3) | module RequestClause
      function http_method= (line 13) | def http_method=(method)
      function uri (line 17) | def uri(values = {})
      function normalize (line 31) | def normalize(method)

FILE: lib/pacto/request_pattern.rb
  type Pacto (line 2) | module Pacto
    class RequestPattern (line 3) | class RequestPattern < WebMock::RequestPattern
      method for (line 6) | def self.for(base_request)
      method initialize (line 10) | def initialize(http_method, uri_template)
      method to_s (line 15) | def to_s

FILE: lib/pacto/resettable.rb
  type Pacto (line 2) | module Pacto
    type Resettable (line 4) | module Resettable
      function resettables (line 5) | def self.resettables
      function extended (line 9) | def self.extended(base)
      function included (line 13) | def self.included(base)
      function reset_all (line 17) | def self.reset_all

FILE: lib/pacto/response_clause.rb
  type Pacto (line 2) | module Pacto
    type ResponseClause (line 3) | module ResponseClause

FILE: lib/pacto/rspec.rb
  function validated? (line 60) | def validated?(_request_pattern)
  function investigation_citations (line 66) | def investigation_citations
  function successfully? (line 70) | def successfully?
  function contract_matches? (line 74) | def contract_matches?

FILE: lib/pacto/server.rb
  type Pacto (line 7) | module Pacto
    type Server (line 8) | module Server
      class HTTP (line 9) | class HTTP < Reel::Server::HTTP
        method initialize (line 13) | def initialize(host = '127.0.0.1', port = 3000, options = {})
        method on_connection (line 20) | def on_connection(connection)

FILE: lib/pacto/server/cli.rb
  type Pacto (line 4) | module Pacto
    type Server (line 5) | module Server
      class CLI (line 6) | class CLI < Thor
        method server_options (line 25) | def server_options
        method stub (line 38) | def stub(*_contracts)
        method proxy (line 49) | def proxy(*_contracts)
        method setup_interrupt (line 58) | def setup_interrupt

FILE: lib/pacto/server/proxy.rb
  type Pacto (line 1) | module Pacto
    type Server (line 2) | module Server
      type Proxy (line 3) | module Proxy
        function proxy_request (line 4) | def proxy_request(pacto_request)
        function prepare_to_forward (line 12) | def prepare_to_forward(pacto_request)
        function rewrite (line 25) | def rewrite(body)
        function forward (line 33) | def forward(pacto_request)
        function prepare_to_respond (line 37) | def prepare_to_respond(pacto_response)
        function host_for (line 43) | def host_for(pacto_request)

FILE: lib/pacto/server/settings.rb
  type Pacto (line 2) | module Pacto
    type Server (line 3) | module Server
      type Settings (line 4) | module Settings
        function options_parser (line 5) | def options_parser(opts, options) # rubocop:disable MethodLength
        class OptionHandler (line 28) | class OptionHandler
          method initialize (line 31) | def initialize(port, logger, config = {})
          method token_map (line 35) | def token_map
          method prepare_contracts (line 43) | def prepare_contracts(contracts)
          method handle (line 47) | def handle(options) # rubocop:disable Metrics/CyclomaticComplexi...

FILE: lib/pacto/stubs/uri_pattern.rb
  type Pacto (line 2) | module Pacto
    class UriPattern (line 3) | class UriPattern
      method for (line 5) | def for(request, strict = Pacto.configuration.strict_matchers)
      method build_template_uri_pattern (line 11) | def build_template_uri_pattern(request, strict)
      method fail_deprecations (line 25) | def fail_deprecations(request)

FILE: lib/pacto/stubs/webmock_adapter.rb
  type Pacto (line 2) | module Pacto
    type Adapters (line 3) | module Adapters
      type WebMock (line 4) | module WebMock
        class PactoRequest (line 5) | class PactoRequest < Pacto::PactoRequest
          method initialize (line 9) | def initialize(webmock_request_signature)
          method params (line 13) | def params
          method path (line 17) | def path
        class PactoResponse (line 22) | class PactoResponse < Pacto::PactoResponse
          method initialize (line 26) | def initialize(webmock_response)
          method headers (line 30) | def headers
          method status (line 34) | def status
    type Stubs (line 41) | module Stubs
      class WebMockAdapter (line 42) | class WebMockAdapter
        method initialize (line 45) | def initialize(middleware)
        method stub_request! (line 53) | def stub_request!(contract)
        method reset! (line 74) | def self.reset!
        method process_hooks (line 79) | def process_hooks(webmock_request_signature, webmock_response)
        method format_body (line 87) | def format_body(body)
        method strict_details (line 95) | def strict_details(request)
        method webmock_params_key (line 102) | def webmock_params_key(request)

FILE: lib/pacto/test_helper.rb
  type Pacto (line 9) | module Pacto
    type TestHelper (line 10) | module TestHelper
      function with_pacto (line 28) | def with_pacto(args = {})

FILE: lib/pacto/ui.rb
  type Pacto (line 4) | module Pacto
    type UI (line 5) | module UI
      function shell (line 16) | def self.shell
      function deprecation (line 20) | def self.deprecation(msg)
      function colorize (line 24) | def self.colorize(msg, color)
      function colorize_method (line 30) | def self.colorize_method(method)

FILE: lib/pacto/uri.rb
  type Pacto (line 2) | module Pacto
    class URI (line 3) | class URI
      method for (line 4) | def self.for(host, path, params = {})

FILE: lib/pacto/version.rb
  type Pacto (line 2) | module Pacto

FILE: sample_apis/album/cover_api.rb
  type AlbumServices (line 2) | module AlbumServices
    class Cover (line 3) | class Cover < Grape::API

FILE: sample_apis/echo_api.rb
  type DummyServices (line 4) | module DummyServices
    class Echo (line 5) | class Echo < Grape::API
      method echo (line 10) | def echo(message)

FILE: sample_apis/files_api.rb
  type DummyServices (line 9) | module DummyServices
    class PartialRequestException (line 10) | class PartialRequestException < StandardError
      method initialize (line 12) | def initialize(http_status, msg)
    class Files (line 18) | class Files < Grape::API

FILE: sample_apis/hello_api.rb
  type DummyServices (line 3) | module DummyServices
    class Hello (line 4) | class Hello < Grape::API

FILE: sample_apis/ping_api.rb
  type DummyServices (line 3) | module DummyServices
    class Ping (line 4) | class Ping < Grape::API

FILE: sample_apis/reverse_api.rb
  type DummyServices (line 4) | module DummyServices
    class Reverse (line 5) | class Reverse < Grape::API
      method echo (line 9) | def echo(message)

FILE: sample_apis/user_api.rb
  type DummyServices (line 6) | module DummyServices
    class Echo (line 7) | class Echo < Grape::API

FILE: samples/cops.rb
  class MyCustomCop (line 13) | class MyCustomCop
    method investigate (line 14) | def investigate(_request, _response, contract)

FILE: spec/integration/e2e_spec.rb
  function get_json (line 49) | def get_json(url)

FILE: spec/integration/forensics/integration_matcher_spec.rb
  type Pacto (line 4) | module Pacto
    function expect_to_raise (line 9) | def expect_to_raise(message_pattern = nil, &blk)
    function json_response (line 13) | def json_response(url)
    function play_bad_response (line 20) | def play_bad_response

FILE: spec/integration/rspec_spec.rb
  function expect_to_raise (line 14) | def expect_to_raise(message_pattern = nil, &blk)
  function json_response (line 18) | def json_response(url)
  function play_bad_response (line 25) | def play_bad_response

FILE: spec/spec_helper.rb
  function default_pacto_format (line 24) | def default_pacto_format
  function contracts_folder (line 28) | def contracts_folder(format = default_pacto_format)
  function contract_file (line 32) | def contract_file(name, format = default_pacto_format)
  function sample_contract (line 38) | def sample_contract

FILE: spec/unit/actors/from_examples_spec.rb
  type Pacto (line 2) | module Pacto
    type Actors (line 3) | module Actors

FILE: spec/unit/actors/json_generator_spec.rb
  type Pacto (line 24) | module Pacto
    type Actors (line 25) | module Actors

FILE: spec/unit/pacto/configuration_spec.rb
  type Pacto (line 2) | module Pacto

FILE: spec/unit/pacto/consumer/faraday_driver_spec.rb
  type Pacto (line 2) | module Pacto
    class Consumer (line 3) | class Consumer

FILE: spec/unit/pacto/contract_factory_spec.rb
  type Pacto (line 4) | module Pacto
    class CustomContractFactory (line 25) | class CustomContractFactory
      method initialize (line 26) | def initialize(dummy_contract)
      method build_from_file (line 30) | def build_from_file(_contract_path, _host)
    class MultiContractFactory (line 47) | class MultiContractFactory
      method initialize (line 48) | def initialize(contracts)
      method build_from_file (line 52) | def build_from_file(_contract_path, _host)

FILE: spec/unit/pacto/contract_files_spec.rb
  type Pacto (line 5) | module Pacto

FILE: spec/unit/pacto/contract_set_spec.rb
  type Pacto (line 4) | module Pacto

FILE: spec/unit/pacto/cops/body_cop_spec.rb
  type Pacto (line 97) | module Pacto
    type Cops (line 98) | module Cops

FILE: spec/unit/pacto/cops/response_header_cop_spec.rb
  type Pacto (line 2) | module Pacto
    type Cops (line 3) | module Cops

FILE: spec/unit/pacto/cops/response_status_cop_spec.rb
  type Pacto (line 2) | module Pacto
    type Cops (line 3) | module Cops

FILE: spec/unit/pacto/cops_spec.rb
  type Pacto (line 2) | module Pacto

FILE: spec/unit/pacto/core/contract_registry_spec.rb
  type Pacto (line 4) | module Pacto
    function create_contracts (line 40) | def create_contracts(total, matches)
    function register_contracts (line 48) | def register_contracts(contracts)

FILE: spec/unit/pacto/core/http_middleware_spec.rb
  type Pacto (line 2) | module Pacto
    type Core (line 3) | module Core
      class FailingObserver (line 9) | class FailingObserver
        method raise_error (line 10) | def raise_error(_pacto_request, _pacto_response)

FILE: spec/unit/pacto/core/investigation_spec.rb
  type Pacto (line 2) | module Pacto

FILE: spec/unit/pacto/erb_processor_spec.rb
  type Pacto (line 2) | module Pacto

FILE: spec/unit/pacto/extensions_spec.rb
  type Pacto (line 2) | module Pacto

FILE: spec/unit/pacto/formats/legacy/contract_builder_spec.rb
  type Pacto (line 2) | module Pacto
    type Formats (line 3) | module Formats
      type Legacy (line 4) | module Legacy

FILE: spec/unit/pacto/formats/legacy/contract_factory_spec.rb
  type Pacto (line 4) | module Pacto
    type Formats (line 5) | module Formats
      type Legacy (line 6) | module Legacy

FILE: spec/unit/pacto/formats/legacy/contract_generator_spec.rb
  type Pacto (line 2) | module Pacto
    type Formats (line 3) | module Formats
      type Legacy (line 4) | module Legacy
        function pretty (line 39) | def pretty(obj)

FILE: spec/unit/pacto/formats/legacy/contract_spec.rb
  type Pacto (line 4) | module Pacto
    type Formats (line 5) | module Formats
      type Legacy (line 6) | module Legacy

FILE: spec/unit/pacto/formats/legacy/generator/filters_spec.rb
  type Pacto (line 2) | module Pacto
    type Formats (line 3) | module Formats
      type Legacy (line 4) | module Legacy
        type Generator (line 5) | module Generator

FILE: spec/unit/pacto/formats/legacy/request_clause_spec.rb
  type Pacto (line 2) | module Pacto
    type Formats (line 3) | module Formats
      type Legacy (line 4) | module Legacy

FILE: spec/unit/pacto/formats/legacy/response_clause_spec.rb
  type Pacto (line 2) | module Pacto
    type Formats (line 3) | module Formats
      type Legacy (line 4) | module Legacy

FILE: spec/unit/pacto/formats/swagger/contract_factory_spec.rb
  type Pacto (line 2) | module Pacto
    type Formats (line 3) | module Formats
      type Swagger (line 4) | module Swagger

FILE: spec/unit/pacto/formats/swagger/contract_spec.rb
  type Pacto (line 4) | module Pacto
    type Formats (line 5) | module Formats
      type Swagger (line 6) | module Swagger

FILE: spec/unit/pacto/hooks/erb_hook_spec.rb
  function mock_erb (line 55) | def mock_erb(hash)

FILE: spec/unit/pacto/logger_spec.rb
  type Pacto (line 2) | module Pacto
    type Logger (line 3) | module Logger

FILE: spec/unit/pacto/meta_schema_spec.rb
  type Pacto (line 2) | module Pacto

FILE: spec/unit/pacto/pacto_spec.rb
  function output (line 11) | def output
  function mock_investigation (line 15) | def mock_investigation(errors)

FILE: spec/unit/pacto/request_pattern_spec.rb
  type Pacto (line 4) | module Pacto

FILE: spec/unit/pacto/stubs/observers/stenographer_spec.rb
  type Pacto (line 4) | module Pacto
    type Observers (line 5) | module Observers

FILE: spec/unit/pacto/stubs/uri_pattern_spec.rb
  type Pacto (line 4) | module Pacto

FILE: spec/unit/pacto/stubs/webmock_adapter_spec.rb
  type Pacto (line 2) | module Pacto
    type Stubs (line 3) | module Stubs

FILE: spec/unit/pacto/uri_spec.rb
  type Pacto (line 4) | module Pacto

FILE: tasks/release.rake
  function github (line 3) | def github
  function release_tag (line 7) | def release_tag
  function release (line 11) | def release
  function changelog (line 15) | def changelog
  function confirm (line 20) | def confirm(question, data)
Condensed preview — 200 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (314K chars).
[
  {
    "path": ".gitignore",
    "chars": 228,
    "preview": "*.gem\n*.log\n*.pid\n*.rbc\n.bundle\n.config\n.yardoc\nGemfile.lock\nInstalledFiles\n_yardoc\ncoverage\ndoc/\nlib/bundler/man\npkg\nrd"
  },
  {
    "path": ".rspec",
    "chars": 31,
    "preview": "--colour\n--require spec_helper\n"
  },
  {
    "path": ".rubocop.yml",
    "chars": 441,
    "preview": "require: rubocop-rspec\n\nDocumentation:\n  Enabled: false\n\nDotPosition:\n  Enabled: false\n\nLineLength:\n  Enabled: false\n\nMe"
  },
  {
    "path": ".travis.yml",
    "chars": 227,
    "preview": "language: ruby\nrvm:\n  - 2.1.0\n  - 2.0.0\n  - 1.9.3\n  # There is a bug in jruby-1.7.15\n  # that is blocking testing\n  - jr"
  },
  {
    "path": "CONTRIBUTING.md",
    "chars": 4324,
    "preview": "# Contributing\n\nYou are welcome to contribute to Pacto and this guide will help you to:\n\n- [Setup](#setup) all the neede"
  },
  {
    "path": "Gemfile",
    "chars": 437,
    "preview": "source 'https://rubygems.org'\n\n# Specify your gem's dependencies in pacto.gemspec\ngemspec name: 'pacto'\ngemspec name: 'p"
  },
  {
    "path": "Guardfile",
    "chars": 1365,
    "preview": "# vim: syntax=ruby filetype=ruby\n\nguard :rubocop, all_on_start: false do\n  watch(/.+\\.rb$/)\n  watch(/\\.gemspec$/)\n  watc"
  },
  {
    "path": "LICENSE.txt",
    "chars": 1089,
    "preview": "Copyright (c) 2013 ThoughtWorks Brasil & Abril Midia\n\nMIT License\n\nPermission is hereby granted, free of charge, to any "
  },
  {
    "path": "Procfile",
    "chars": 92,
    "preview": "sample_apis: sh -c 'bundle exec rackup -s puma -o localhost -p $PORT sample_apis/config.ru'\n"
  },
  {
    "path": "README.md",
    "chars": 12067,
    "preview": "[![Gem Version](https://badge.fury.io/rb/pacto.png)](http://badge.fury.io/rb/pacto)\n[![Build Status](https://travis-ci.o"
  },
  {
    "path": "Rakefile",
    "chars": 2875,
    "preview": "require 'rspec/core/rake_task'\nrequire 'cucumber'\nrequire 'cucumber/rake/task'\nrequire 'coveralls/rake/task'\nrequire 'ru"
  },
  {
    "path": "TODO.md",
    "chars": 984,
    "preview": "# TODO\n\n# v0.4\n\n## Thor\n- Kill rake tasks, replace w/ pacto binary\n- Split Pacto server to separate repo??\n\n## Swagger c"
  },
  {
    "path": "appveyor.yml",
    "chars": 260,
    "preview": "version: 0.0.{build}\r\ninit:\r\n- choco install openssl.light\r\n- gem install bundler --quiet --no-ri --no-rdoc\r\n- gem insta"
  },
  {
    "path": "bin/pacto",
    "chars": 64,
    "preview": "#!/usr/bin/env ruby\nrequire 'pacto/cli'\n\nPacto::CLI::Main.start\n"
  },
  {
    "path": "bin/pacto-server",
    "chars": 73,
    "preview": "#!/usr/bin/env ruby\nrequire 'pacto/server/cli'\n\nPacto::Server::CLI.start\n"
  },
  {
    "path": "changelog.md",
    "chars": 618,
    "preview": "## 0.3.2\n\n  *New Features:*\n    - #105: Add pacto-server for non-ruby tests.  Use the pacto-server gem.\n\n  *Breaking Cha"
  },
  {
    "path": "docs/configuration.md",
    "chars": 1540,
    "preview": "Just require pacto to add it to your project.\n\n```rb\nrequire 'pacto'\n```\n\nPacto will disable live connections, so you wi"
  },
  {
    "path": "docs/consumer.md",
    "chars": 459,
    "preview": "\n```rb\nrequire 'pacto'\nPacto.load_contracts 'contracts', 'http://localhost:5000'\nWebMock.allow_net_connect!\n\ninteraction"
  },
  {
    "path": "docs/cops.md",
    "chars": 1023,
    "preview": "\n```rb\nrequire 'pacto'\nPacto.configure do |c|\n  c.contracts_path = 'contracts'\nend\nPacto.validate!\n```\n\nYou can create a"
  },
  {
    "path": "docs/forensics.md",
    "chars": 2190,
    "preview": "Pacto has a few RSpec matchers to help you ensure a **consumer** and **producer** are\ninteracting properly. First, let's"
  },
  {
    "path": "docs/generation.md",
    "chars": 2341,
    "preview": "Some generation related [configuration](configuration.rb).\n\n```rb\nrequire 'pacto'\nWebMock.allow_net_connect!\nPacto.confi"
  },
  {
    "path": "docs/rake_tasks.md",
    "chars": 202,
    "preview": "# Rake tasks\n## This is a test!\n[That](www.google.com) markdown works\n\n```sh\nbundle exec rake pacto:meta_validate['contr"
  },
  {
    "path": "docs/rspec.md",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "docs/samples.md",
    "chars": 4002,
    "preview": "# Overview\nWelcome to the Pacto usage samples!\nThis document gives a quick overview of the main features.\n\nYou can brows"
  },
  {
    "path": "docs/server.md",
    "chars": 527,
    "preview": "\n```rb\nrequire 'pacto/rspec'\nrequire 'pacto/test_helper'\n\ndescribe 'ping service' do\n  include Pacto::TestHelper\n\n  it '"
  },
  {
    "path": "docs/server_cli.md",
    "chars": 469,
    "preview": "# Standalone server\nYou can run Pacto as a server in order to test non-Ruby projects. In order to get the full set\nof op"
  },
  {
    "path": "docs/stenographer.md",
    "chars": 571,
    "preview": "\n```rb\nrequire 'pacto'\nPacto.configure do |c|\n  c.contracts_path = 'contracts'\nend\ncontracts = Pacto.load_contracts('con"
  },
  {
    "path": "features/configuration/strict_matchers.feature",
    "chars": 3158,
    "preview": "Feature: Strict Matching\n\n  By default, Pacto matches requests to contracts (and stubs) using exact request paths, param"
  },
  {
    "path": "features/evolve/README.md",
    "chars": 687,
    "preview": "## Consumer-Driven Contract Recommendations\n\nIf you are using Pacto for Consumer-Driven Contracts, we recommend avoiding"
  },
  {
    "path": "features/evolve/existing_services.feature",
    "chars": 2288,
    "preview": "Feature: Existing services journey\n\n  Scenario: Generating the contracts\n    Given I have a Rakefile\n    Given an existi"
  },
  {
    "path": "features/generate/README.md",
    "chars": 995,
    "preview": "We know - json-schema can get pretty verbose!  It's a powerful tool, but writing the entire Contract by hand for a compl"
  },
  {
    "path": "features/generate/generation.feature",
    "chars": 2657,
    "preview": "@needs_server\nFeature: Contract Generation\n\n  We know - json-schema can get pretty verbose!  It's a powerful tool, but w"
  },
  {
    "path": "features/steps/pacto_steps.rb",
    "chars": 2116,
    "preview": "# -*- encoding : utf-8 -*-\nGiven(/^Pacto is configured with:$/) do |string|\n  steps %(\n    Given a file named \"pacto_con"
  },
  {
    "path": "features/stub/README.md",
    "chars": 167,
    "preview": "You can write your own stubs and use Pacto to [validate](https://www.relishapp.com/maxlinc/pacto/docs/validate) them, or"
  },
  {
    "path": "features/stub/templates.feature",
    "chars": 1292,
    "preview": "Feature: Templating\n\n  If you want to create more dynamic stubs, you can use Pacto templating.  Currently the only suppo"
  },
  {
    "path": "features/support/env.rb",
    "chars": 692,
    "preview": "# -*- encoding : utf-8 -*-\nrequire_relative '../../spec/coveralls_helper'\nrequire 'aruba'\nrequire 'aruba/cucumber'\nrequi"
  },
  {
    "path": "features/validate/README.md",
    "chars": 298,
    "preview": "You can use Pacto to do Integration Contract Testing - making sure your service and any test double that simulates the s"
  },
  {
    "path": "features/validate/meta_validation.feature",
    "chars": 2658,
    "preview": "Feature: Meta-validation\n\n  Meta-validation ensures that a Contract file matches the Contract format.  It does not valid"
  },
  {
    "path": "features/validate/validation.feature",
    "chars": 1087,
    "preview": "Feature: Validation\n\n  Validation ensures that a external service conform to a Contract.\n\n  Scenario: Validation via a r"
  },
  {
    "path": "lib/pacto/actor.rb",
    "chars": 64,
    "preview": "# -*- encoding : utf-8 -*-\nmodule Pacto\n  class Actor\n  end\nend\n"
  },
  {
    "path": "lib/pacto/actors/from_examples.rb",
    "chars": 2130,
    "preview": "# -*- encoding : utf-8 -*-\nmodule Pacto\n  module Actors\n    class FirstExampleSelector\n      def self.select(examples, _"
  },
  {
    "path": "lib/pacto/actors/json_generator.rb",
    "chars": 632,
    "preview": "# -*- encoding : utf-8 -*-\nmodule Pacto\n  module Actors\n    class JSONGenerator < Actor\n      def build_request(contract"
  },
  {
    "path": "lib/pacto/body_parsing.rb",
    "chars": 884,
    "preview": "# -*- encoding : utf-8 -*-\n\nmodule Pacto\n  module Handlers\n    autoload :JSONHandler, 'pacto/handlers/json_handler'\n    "
  },
  {
    "path": "lib/pacto/cli/helpers.rb",
    "chars": 600,
    "preview": "module Pacto\n  module CLI\n    module Helpers\n      def each_contract(*contracts)\n        [*contracts].each do |contract|"
  },
  {
    "path": "lib/pacto/cli.rb",
    "chars": 2545,
    "preview": "require 'thor'\nrequire 'pacto'\nrequire 'pacto/cli/helpers'\n\nmodule Pacto\n  module CLI\n    class Main < Thor\n      includ"
  },
  {
    "path": "lib/pacto/consumer/faraday_driver.rb",
    "chars": 1110,
    "preview": "# -*- encoding : utf-8 -*-\nmodule Pacto\n  class Consumer\n    class FaradayDriver\n      include Pacto::Logger\n      # Sen"
  },
  {
    "path": "lib/pacto/consumer.rb",
    "chars": 2112,
    "preview": "# -*- encoding : utf-8 -*-\nmodule Pacto\n  def self.consumers\n    @consumers ||= {}\n  end\n\n  def self.simulate_consumer(c"
  },
  {
    "path": "lib/pacto/contract.rb",
    "chars": 1517,
    "preview": "# -*- encoding : utf-8 -*-\nmodule Pacto\n  module Contract\n    include Logger\n\n    attr_reader :id\n    attr_reader :file\n"
  },
  {
    "path": "lib/pacto/contract_factory.rb",
    "chars": 1046,
    "preview": "# -*- encoding : utf-8 -*-\nmodule Pacto\n  class ContractFactory\n    include Singleton\n    include Logger\n\n    def initia"
  },
  {
    "path": "lib/pacto/contract_files.rb",
    "chars": 373,
    "preview": "# -*- encoding : utf-8 -*-\nrequire 'pathname'\nmodule Pacto\n  class ContractFiles\n    def self.for(path)\n      full_path "
  },
  {
    "path": "lib/pacto/contract_set.rb",
    "chars": 244,
    "preview": "# -*- encoding : utf-8 -*-\nmodule Pacto\n  class ContractSet < Set\n    def stub_providers(values = {})\n      each { |cont"
  },
  {
    "path": "lib/pacto/cops/body_cop.rb",
    "chars": 754,
    "preview": "# -*- encoding : utf-8 -*-\nmodule Pacto\n  module Cops\n    class BodyCop\n      KNOWN_CLAUSES = [:request, :response]\n\n   "
  },
  {
    "path": "lib/pacto/cops/request_body_cop.rb",
    "chars": 186,
    "preview": "# -*- encoding : utf-8 -*-\nmodule Pacto\n  module Cops\n    class RequestBodyCop < BodyCop\n      validates :request\n    en"
  },
  {
    "path": "lib/pacto/cops/response_body_cop.rb",
    "chars": 189,
    "preview": "# -*- encoding : utf-8 -*-\nmodule Pacto\n  module Cops\n    class ResponseBodyCop < BodyCop\n      validates :response\n    "
  },
  {
    "path": "lib/pacto/cops/response_header_cop.rb",
    "chars": 1578,
    "preview": "# -*- encoding : utf-8 -*-\nmodule Pacto\n  module Cops\n    class ResponseHeaderCop\n      def self.investigate(_request, r"
  },
  {
    "path": "lib/pacto/cops/response_status_cop.rb",
    "chars": 497,
    "preview": "# -*- encoding : utf-8 -*-\nmodule Pacto\n  module Cops\n    class ResponseStatusCop\n      def self.investigate(_request, r"
  },
  {
    "path": "lib/pacto/cops.rb",
    "chars": 1256,
    "preview": "# -*- encoding : utf-8 -*-\nmodule Pacto\n  module Cops\n    extend Pacto::Resettable\n\n    class << self\n      def reset!\n "
  },
  {
    "path": "lib/pacto/core/configuration.rb",
    "chars": 1588,
    "preview": "# -*- encoding : utf-8 -*-\nmodule Pacto\n  class Configuration\n    attr_accessor :adapter, :strict_matchers,\n            "
  },
  {
    "path": "lib/pacto/core/contract_registry.rb",
    "chars": 650,
    "preview": "# -*- encoding : utf-8 -*-\nmodule Pacto\n  class ContractNotFound < StandardError; end\n\n  class ContractRegistry < Set\n  "
  },
  {
    "path": "lib/pacto/core/hook.rb",
    "chars": 239,
    "preview": "# -*- encoding : utf-8 -*-\nmodule Pacto\n  class Hook\n    def initialize(&block)\n      @hook = block\n    end\n\n    def pro"
  },
  {
    "path": "lib/pacto/core/http_middleware.rb",
    "chars": 507,
    "preview": "# -*- encoding : utf-8 -*-\nrequire 'observer'\n\nmodule Pacto\n  module Core\n    class HTTPMiddleware\n      include Logger\n"
  },
  {
    "path": "lib/pacto/core/investigation_registry.rb",
    "chars": 1436,
    "preview": "# -*- encoding : utf-8 -*-\nmodule Pacto\n  class InvestigationRegistry\n    include Singleton\n    include Logger\n    inclu"
  },
  {
    "path": "lib/pacto/core/modes.rb",
    "chars": 471,
    "preview": "# -*- encoding : utf-8 -*-\nmodule Pacto\n  class << self\n    def generate!\n      modes << :generate\n    end\n\n    def stop"
  },
  {
    "path": "lib/pacto/core/pacto_request.rb",
    "chars": 998,
    "preview": "# -*- encoding : utf-8 -*-\nrequire 'hashie/mash'\n\nmodule Pacto\n  class PactoRequest\n    # FIXME: Need case insensitive h"
  },
  {
    "path": "lib/pacto/core/pacto_response.rb",
    "chars": 692,
    "preview": "# -*- encoding : utf-8 -*-\nmodule Pacto\n  class PactoResponse\n    # FIXME: Need case insensitive header lookup, but case"
  },
  {
    "path": "lib/pacto/dash.rb",
    "chars": 193,
    "preview": "# -*- encoding : utf-8 -*-\nrequire 'hashie'\n\nmodule Pacto\n  class Dash < Hashie::Dash\n    include Hashie::Extensions::Co"
  },
  {
    "path": "lib/pacto/erb_processor.rb",
    "chars": 432,
    "preview": "# -*- encoding : utf-8 -*-\nmodule Pacto\n  class ERBProcessor\n    include Logger\n    def process(contract, values = {})\n "
  },
  {
    "path": "lib/pacto/errors.rb",
    "chars": 2021,
    "preview": "module Pacto\n  class InvalidContract < ArgumentError\n    attr_reader :errors\n\n    def initialize(errors)\n      @errors ="
  },
  {
    "path": "lib/pacto/extensions.rb",
    "chars": 600,
    "preview": "# -*- encoding : utf-8 -*-\nmodule Pacto\n  module Extensions\n    # Adapted from Faraday\n    HeaderKeyMap = Hash.new do |m"
  },
  {
    "path": "lib/pacto/forensics/investigation_filter.rb",
    "chars": 2861,
    "preview": "# -*- encoding : utf-8 -*-\nmodule Pacto\n  module Forensics\n    class FilterExhaustedError < StandardError\n      attr_rea"
  },
  {
    "path": "lib/pacto/forensics/investigation_matcher.rb",
    "chars": 2583,
    "preview": "# -*- encoding : utf-8 -*-\nRSpec::Matchers.define :have_investigated do |service_name|\n  match do\n    investigations = P"
  },
  {
    "path": "lib/pacto/formats/legacy/contract.rb",
    "chars": 1643,
    "preview": "# -*- encoding : utf-8 -*-\nrequire 'pacto/formats/legacy/request_clause'\nrequire 'pacto/formats/legacy/response_clause'\n"
  },
  {
    "path": "lib/pacto/formats/legacy/contract_builder.rb",
    "chars": 4182,
    "preview": "# -*- encoding : utf-8 -*-\nmodule Pacto\n  module Formats\n    module Legacy\n      class ContractBuilder < Hashie::Dash # "
  },
  {
    "path": "lib/pacto/formats/legacy/contract_factory.rb",
    "chars": 2226,
    "preview": "# -*- encoding : utf-8 -*-\nrequire 'pacto/formats/legacy/contract'\n\nmodule Pacto\n  module Formats\n    module Legacy\n    "
  },
  {
    "path": "lib/pacto/formats/legacy/contract_generator.rb",
    "chars": 2982,
    "preview": "# -*- encoding : utf-8 -*-\nrequire 'json/schema_generator'\nrequire 'pacto/formats/legacy/contract_builder'\nrequire 'pact"
  },
  {
    "path": "lib/pacto/formats/legacy/generator/filters.rb",
    "chars": 1365,
    "preview": "# -*- encoding : utf-8 -*-\nmodule Pacto\n  module Formats\n    module Legacy\n      module Generator\n        class Filters\n"
  },
  {
    "path": "lib/pacto/formats/legacy/generator_hint.rb",
    "chars": 964,
    "preview": "# -*- encoding : utf-8 -*-\nmodule Pacto\n  module Formats\n    module Legacy\n      class GeneratorHint < Pacto::Dash\n     "
  },
  {
    "path": "lib/pacto/formats/legacy/request_clause.rb",
    "chars": 1145,
    "preview": "# -*- encoding : utf-8 -*-\nmodule Pacto\n  module Formats\n    module Legacy\n      class RequestClause < Pacto::Dash\n     "
  },
  {
    "path": "lib/pacto/formats/legacy/response_clause.rb",
    "chars": 735,
    "preview": "module Pacto\n  module Formats\n    module Legacy\n      class ResponseClause\n        include Pacto::ResponseClause\n       "
  },
  {
    "path": "lib/pacto/formats/swagger/contract.rb",
    "chars": 3205,
    "preview": "# -*- encoding : utf-8 -*-\n\nrequire 'pacto/formats/swagger/request_clause'\nrequire 'pacto/formats/swagger/response_claus"
  },
  {
    "path": "lib/pacto/formats/swagger/contract_factory.rb",
    "chars": 1315,
    "preview": "# -*- encoding : utf-8 -*-\nrequire 'swagger'\nrequire 'pacto/formats/swagger/contract'\n\nmodule Pacto\n  module Formats\n   "
  },
  {
    "path": "lib/pacto/formats/swagger/request_clause.rb",
    "chars": 1509,
    "preview": "# -*- encoding : utf-8 -*-\nmodule Pacto\n  module Formats\n    module Swagger\n      class RequestClause\n        include Pa"
  },
  {
    "path": "lib/pacto/formats/swagger/response_clause.rb",
    "chars": 679,
    "preview": "# -*- encoding : utf-8 -*-\nmodule Pacto\n  module Formats\n    module Swagger\n      class ResponseClause\n        extend Fo"
  },
  {
    "path": "lib/pacto/generator.rb",
    "chars": 1034,
    "preview": "# -*- encoding : utf-8 -*-\nrequire 'pacto/formats/legacy/contract_generator'\nrequire 'pacto/formats/legacy/generator_hin"
  },
  {
    "path": "lib/pacto/handlers/json_handler.rb",
    "chars": 299,
    "preview": "require 'json'\n\nmodule Pacto\n  module Handlers\n    module JSONHandler\n      class << self\n        def raw(body)\n        "
  },
  {
    "path": "lib/pacto/handlers/text_handler.rb",
    "chars": 270,
    "preview": "module Pacto\n  module Handlers\n    module TextHandler\n      class << self\n        def raw(body)\n          body.to_s\n    "
  },
  {
    "path": "lib/pacto/hooks/erb_hook.rb",
    "chars": 520,
    "preview": "# -*- encoding : utf-8 -*-\nrequire_relative '../erb_processor'\n\nmodule Pacto\n  module Hooks\n    class ERBHook < Pacto::H"
  },
  {
    "path": "lib/pacto/investigation.rb",
    "chars": 1241,
    "preview": "# -*- encoding : utf-8 -*-\nmodule Pacto\n  class Investigation\n    include Logger\n    attr_reader :request, :response, :c"
  },
  {
    "path": "lib/pacto/logger.rb",
    "chars": 921,
    "preview": "# -*- encoding : utf-8 -*-\nrequire 'forwardable'\n\nmodule Pacto\n  module Logger\n    def logger\n      Pacto.configuration."
  },
  {
    "path": "lib/pacto/meta_schema.rb",
    "chars": 989,
    "preview": "# -*- encoding : utf-8 -*-\nmodule Pacto\n  class MetaSchema\n    attr_accessor :schema, :engine\n\n    def initialize(engine"
  },
  {
    "path": "lib/pacto/observers/stenographer.rb",
    "chars": 1144,
    "preview": "# -*- encoding : utf-8 -*-\nmodule Pacto\n  module Observers\n    class Stenographer\n      def initialize(output)\n        @"
  },
  {
    "path": "lib/pacto/provider.rb",
    "chars": 525,
    "preview": "# -*- encoding : utf-8 -*-\nmodule Pacto\n  def self.providers\n    @providers ||= {}\n  end\n\n  class Provider\n    include R"
  },
  {
    "path": "lib/pacto/rake_task.rb",
    "chars": 2850,
    "preview": "# -*- encoding : utf-8 -*-\nrequire 'pacto'\nrequire 'thor'\nrequire 'pacto/cli'\nrequire 'pacto/cli/helpers'\n\n# FIXME: Rake"
  },
  {
    "path": "lib/pacto/request_clause.rb",
    "chars": 989,
    "preview": "# -*- encoding : utf-8 -*-\nmodule Pacto\n  module RequestClause\n    include Logger\n    attr_reader :host\n    attr_reader "
  },
  {
    "path": "lib/pacto/request_pattern.rb",
    "chars": 801,
    "preview": "# -*- encoding : utf-8 -*-\nmodule Pacto\n  class RequestPattern < WebMock::RequestPattern\n    attr_accessor :uri_template"
  },
  {
    "path": "lib/pacto/resettable.rb",
    "chars": 442,
    "preview": "# -*- encoding : utf-8 -*-\nmodule Pacto\n  # Included this module so that Pacto::Resettable.reset_all will call your clas"
  },
  {
    "path": "lib/pacto/response_clause.rb",
    "chars": 147,
    "preview": "# -*- encoding : utf-8 -*-\nmodule Pacto\n  module ResponseClause\n    attr_reader :status\n    attr_reader :headers\n    att"
  },
  {
    "path": "lib/pacto/rspec.rb",
    "chars": 3610,
    "preview": "# -*- encoding : utf-8 -*-\nrequire 'pacto'\n\nbegin\n  require 'rspec/core'\n  require 'rspec/expectations'\nrescue LoadError"
  },
  {
    "path": "lib/pacto/server/cli.rb",
    "chars": 2412,
    "preview": "require 'thor'\nrequire 'pacto/server'\n\nmodule Pacto\n  module Server\n    class CLI < Thor\n      class << self\n        DEF"
  },
  {
    "path": "lib/pacto/server/config.rb",
    "chars": 108,
    "preview": "# -*- encoding : utf-8 -*-\nPacto::Server::Settings::OptionHandler.new(port, logger, config).handle(options)\n"
  },
  {
    "path": "lib/pacto/server/proxy.rb",
    "chars": 2000,
    "preview": "module Pacto\n  module Server\n    module Proxy\n      def proxy_request(pacto_request)\n        prepare_to_forward(pacto_re"
  },
  {
    "path": "lib/pacto/server/settings.rb",
    "chars": 4576,
    "preview": "# -*- encoding : utf-8 -*-\nmodule Pacto\n  module Server\n    module Settings\n      def options_parser(opts, options) # ru"
  },
  {
    "path": "lib/pacto/server.rb",
    "chars": 1568,
    "preview": "# -*- encoding : utf-8 -*-\nrequire 'reel'\nrequire 'pacto'\nrequire_relative 'server/settings'\nrequire_relative 'server/pr"
  },
  {
    "path": "lib/pacto/stubs/uri_pattern.rb",
    "chars": 1072,
    "preview": "# -*- encoding : utf-8 -*-\nmodule Pacto\n  class UriPattern\n    class << self\n      def for(request, strict = Pacto.confi"
  },
  {
    "path": "lib/pacto/stubs/webmock_adapter.rb",
    "chars": 2995,
    "preview": "# -*- encoding : utf-8 -*-\nmodule Pacto\n  module Adapters\n    module WebMock\n      class PactoRequest < Pacto::PactoRequ"
  },
  {
    "path": "lib/pacto/test_helper.rb",
    "chars": 1156,
    "preview": "# -*- encoding : utf-8 -*-\nbegin\n  require 'pacto'\n  require 'pacto/server'\nrescue LoadError\n  raise 'pacto/test_helper "
  },
  {
    "path": "lib/pacto/ui.rb",
    "chars": 884,
    "preview": "# -*- encoding : utf-8 -*-\nrequire 'thor'\n\nmodule Pacto\n  module UI\n    # Colors for HTTP Methods, intended to match col"
  },
  {
    "path": "lib/pacto/uri.rb",
    "chars": 262,
    "preview": "# -*- encoding : utf-8 -*-\nmodule Pacto\n  class URI\n    def self.for(host, path, params = {})\n      Addressable::URI.heu"
  },
  {
    "path": "lib/pacto/version.rb",
    "chars": 68,
    "preview": "# -*- encoding : utf-8 -*-\nmodule Pacto\n  VERSION = '0.4.0.rc3'\nend\n"
  },
  {
    "path": "lib/pacto.rb",
    "chars": 2975,
    "preview": "# -*- encoding : utf-8 -*-\nrequire 'pacto/version'\n\nrequire 'addressable/template'\nrequire 'swagger'\nrequire 'middleware"
  },
  {
    "path": "pacto-server.gemspec",
    "chars": 1095,
    "preview": "lib = File.expand_path('../lib', __FILE__)\n$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)\nrequire 'pacto/versio"
  },
  {
    "path": "pacto.gemspec",
    "chars": 2829,
    "preview": "lib = File.expand_path('../lib', __FILE__)\n$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)\nrequire 'pacto/versio"
  },
  {
    "path": "resources/contract_schema.json",
    "chars": 1632,
    "preview": "{\n  \"title\": \"Example Schema\",\n  \"type\": \"object\",\n  \"required\": [\"request\", \"response\"],\n  \"definitions\": {\n    \"subsch"
  },
  {
    "path": "resources/draft-03.json",
    "chars": 3113,
    "preview": "{\n  \"$schema\" : \"http://json-schema.org/draft-03/schema#\",\n  \"id\" : \"http://json-schema.org/draft-03/schema#\",\n  \"type\" "
  },
  {
    "path": "resources/draft-04.json",
    "chars": 4374,
    "preview": "{\n    \"id\": \"http://json-schema.org/draft-04/schema#\",\n    \"$schema\": \"http://json-schema.org/draft-04/schema#\",\n    \"de"
  },
  {
    "path": "sample_apis/album/cover_api.rb",
    "chars": 212,
    "preview": "# -*- encoding : utf-8 -*-\nmodule AlbumServices\n  class Cover < Grape::API\n    format :json\n    desc 'Ping'\n    namespac"
  },
  {
    "path": "sample_apis/config.ru",
    "chars": 565,
    "preview": "require 'grape'\nrequire 'grape-swagger'\nrequire 'json'\nDir[File.expand_path('../**/*_api.rb', __FILE__)].each do |f|\n   "
  },
  {
    "path": "sample_apis/echo_api.rb",
    "chars": 729,
    "preview": "# -*- encoding : utf-8 -*-\n# This illustrates simple get w/ params and post w/ body services\n# It also illustrates havin"
  },
  {
    "path": "sample_apis/files_api.rb",
    "chars": 1454,
    "preview": "# -*- encoding : utf-8 -*-\n# This example should illustrate\n#   - Authentication\n#   - Expect: 100-continue\n#   - Binary"
  },
  {
    "path": "sample_apis/hello_api.rb",
    "chars": 296,
    "preview": "# -*- encoding : utf-8 -*-\n#  This illustrates a simple get service\nmodule DummyServices\n  class Hello < Grape::API\n    "
  },
  {
    "path": "sample_apis/ping_api.rb",
    "chars": 208,
    "preview": "# -*- encoding : utf-8 -*-\n#  This illustrates a simple get service\nmodule DummyServices\n  class Ping < Grape::API\n    f"
  },
  {
    "path": "sample_apis/reverse_api.rb",
    "chars": 568,
    "preview": "# -*- encoding : utf-8 -*-\n# This illustrates simple get w/ params and post w/ body services\n# It also illustrates havin"
  },
  {
    "path": "sample_apis/user_api.rb",
    "chars": 302,
    "preview": "# -*- encoding : utf-8 -*-\n# A siple JSON service to demonstrate request/response bodies\n\nrequire 'securerandom'\n\nmodule"
  },
  {
    "path": "samples/README.md",
    "chars": 445,
    "preview": "Welcome to the Pacto usage samples!\n\nWe have a listing of [sample contracts](contracts/README.html).\n\nHighlighted sample"
  },
  {
    "path": "samples/Rakefile",
    "chars": 92,
    "preview": "require 'pacto/rake_task' # FIXME: This require turns on WebMock\nWebMock.allow_net_connect!\n"
  },
  {
    "path": "samples/configuration.rb",
    "chars": 1488,
    "preview": "# -*- encoding : utf-8 -*-\n# Just require pacto to add it to your project.\nrequire 'pacto'\n# Pacto will disable live con"
  },
  {
    "path": "samples/consumer.rb",
    "chars": 474,
    "preview": "# -*- encoding : utf-8 -*-\nrequire 'pacto'\nPacto.load_contracts 'contracts', 'http://localhost:5000'\nWebMock.allow_net_c"
  },
  {
    "path": "samples/contracts/README.md",
    "chars": 39,
    "preview": "This folder contains sample contracts.\n"
  },
  {
    "path": "samples/contracts/contract.js",
    "chars": 3209,
    "preview": "// Pacto Contracts describe the constraints we want to put on interactions between a consumer and a provider.  It sets s"
  },
  {
    "path": "samples/contracts/get_album_cover.json",
    "chars": 1146,
    "preview": "{\n  \"request\": {\n    \"headers\": {\n    },\n    \"http_method\": \"get\",\n    \"path\": \"/api/album/{id}/cover\"\n  },\n  \"response\""
  },
  {
    "path": "samples/contracts/localhost/api/echo.json",
    "chars": 736,
    "preview": "{\n  \"name\": \"Echo\",\n  \"request\": {\n    \"headers\": {\n      \"Content-Type\": \"text/plain\"\n    },\n    \"http_method\": \"post\","
  },
  {
    "path": "samples/contracts/localhost/api/ping.json",
    "chars": 759,
    "preview": "{\n  \"name\": \"Ping\",\n  \"request\": {\n    \"headers\": {\n    },\n    \"http_method\": \"get\",\n    \"path\": \"/api/ping\"\n  },\n  \"res"
  },
  {
    "path": "samples/contracts/user.json",
    "chars": 1167,
    "preview": "{\n  \"name\": \"User\",\n  \"request\": {\n    \"headers\": {\n      \"Content-Type\": \"application/json\"\n    },\n    \"http_method\": \""
  },
  {
    "path": "samples/cops.rb",
    "chars": 1063,
    "preview": "# -*- encoding : utf-8 -*-\nrequire 'rspec'\nrequire 'rspec/autorun'\nrequire 'pacto'\n\nPacto.configure do |c|\n  c.contracts"
  },
  {
    "path": "samples/forensics.rb",
    "chars": 2192,
    "preview": "# -*- encoding : utf-8 -*-\n# Pacto has a few RSpec matchers to help you ensure a **consumer** and **producer** are\n# int"
  },
  {
    "path": "samples/generation.rb",
    "chars": 2341,
    "preview": "# -*- encoding : utf-8 -*-\n# Some generation related [configuration](configuration.rb).\nrequire 'pacto'\nWebMock.allow_ne"
  },
  {
    "path": "samples/rake_tasks.sh",
    "chars": 197,
    "preview": "# # Rake tasks\n\n# ## This is a test!\n# [That](www.google.com) markdown works\nbundle exec rake pacto:meta_validate['contr"
  },
  {
    "path": "samples/rspec.rb",
    "chars": 27,
    "preview": "# -*- encoding : utf-8 -*-\n"
  },
  {
    "path": "samples/samples.rb",
    "chars": 3972,
    "preview": "# -*- encoding : utf-8 -*-\n# # Overview\n# Welcome to the Pacto usage samples!\n# This document gives a quick overview of "
  },
  {
    "path": "samples/scripts/bootstrap",
    "chars": 27,
    "preview": "#!/bin/bash\nbundle install\n"
  },
  {
    "path": "samples/scripts/wrapper",
    "chars": 215,
    "preview": "#!/bin/bash\n\n# Polytrix should probably support different wrappers for different langauges\nextension=\"${1##*.}\"\nif [ $ex"
  },
  {
    "path": "samples/server.rb",
    "chars": 533,
    "preview": "# -*- encoding : utf-8 -*-\nrequire 'pacto/rspec'\nrequire 'pacto/test_helper'\n\ndescribe 'ping service' do\n  include Pacto"
  },
  {
    "path": "samples/server_cli.sh",
    "chars": 439,
    "preview": "# # Standalone server\n\n# You can run Pacto as a server in order to test non-Ruby projects. In order to get the full set\n"
  },
  {
    "path": "samples/stenographer.rb",
    "chars": 586,
    "preview": "# -*- encoding : utf-8 -*-\nrequire 'pacto'\nPacto.configure do |c|\n  c.contracts_path = 'contracts'\nend\ncontracts = Pacto"
  },
  {
    "path": "spec/coveralls_helper.rb",
    "chars": 263,
    "preview": "# -*- encoding : utf-8 -*-\nunless ENV['NO_COVERAGE']\n  require 'simplecov'\n  require 'coveralls'\n\n  SimpleCov.formatter "
  },
  {
    "path": "spec/fabricators/contract_fabricator.rb",
    "chars": 2945,
    "preview": "# -*- encoding : utf-8 -*-\nrequire 'pacto'\nrequire 'hashie/mash'\n\n# Fabricators for contracts or parts of contracts\nunle"
  },
  {
    "path": "spec/fabricators/http_fabricator.rb",
    "chars": 1154,
    "preview": "# -*- encoding : utf-8 -*-\nrequire 'pacto'\nrequire 'hashie/mash'\n\n# Fabricators for Pacto objects representing HTTP tran"
  },
  {
    "path": "spec/fabricators/webmock_fabricator.rb",
    "chars": 805,
    "preview": "# -*- encoding : utf-8 -*-\n# Fabricators for WebMock objects\n\nFabricator(:webmock_request_signature, from: WebMock::Requ"
  },
  {
    "path": "spec/fixtures/contracts/deprecated/deprecated_contract.json",
    "chars": 476,
    "preview": "{\n  \"request\": {\n    \"method\": \"GET\",\n    \"path\": \"/hello/:id\",\n    \"headers\": {\n      \"Accept\": \"application/json\"\n    "
  },
  {
    "path": "spec/fixtures/contracts/legacy/contract.json",
    "chars": 435,
    "preview": "{\n  \"request\": {\n    \"http_method\": \"GET\",\n    \"path\": \"/hello_world\",\n    \"headers\": {\n      \"Accept\": \"application/jso"
  },
  {
    "path": "spec/fixtures/contracts/legacy/contract_with_examples.json",
    "chars": 927,
    "preview": "{\n  \"request\": {\n    \"headers\": {\n    },\n    \"http_method\": \"get\",\n    \"path\": \"/api/echo\",\n    \"schema\": {\n      \"type\""
  },
  {
    "path": "spec/fixtures/contracts/legacy/simple_contract.json",
    "chars": 512,
    "preview": "{\n  \"name\": \"Simple Contract\",\n  \"request\": {\n    \"http_method\": \"GET\",\n    \"path\": \"/api/hello\",\n    \"headers\": {\n     "
  },
  {
    "path": "spec/fixtures/contracts/legacy/strict_contract.json",
    "chars": 839,
    "preview": "{\n  \"name\": \"Strict Contract\",\n  \"request\": {\n    \"http_method\": \"GET\",\n    \"path\": \"/strict\",\n    \"headers\": {\n      \"A"
  },
  {
    "path": "spec/fixtures/contracts/legacy/templating_contract.json",
    "chars": 603,
    "preview": "{\n  \"request\": {\n    \"http_method\": \"GET\",\n    \"path\": \"/echo\",\n    \"headers\": {\n      \"Accept\": \"application/json\",\n   "
  },
  {
    "path": "spec/fixtures/contracts/swagger/petstore.yaml",
    "chars": 2031,
    "preview": "swagger: 2.0\ninfo:\n  version: 1.0.0\n  title: Swagger Petstore\n  license:\n    name: MIT\nhost: petstore.swagger.wordnik.co"
  },
  {
    "path": "spec/integration/e2e_spec.rb",
    "chars": 1896,
    "preview": "# -*- encoding : utf-8 -*-\ndescribe Pacto do\n  let(:contract_path) { contract_file 'simple_contract' }\n  let(:strict_con"
  },
  {
    "path": "spec/integration/forensics/integration_matcher_spec.rb",
    "chars": 3120,
    "preview": "# -*- encoding : utf-8 -*-\nrequire 'pacto/rspec'\n\nmodule Pacto\n  describe '#have_investigated' do\n    let(:contract_path"
  },
  {
    "path": "spec/integration/rspec_spec.rb",
    "chars": 4354,
    "preview": "# -*- encoding : utf-8 -*-\nrequire 'pacto/rspec'\n\ndescribe 'pacto/rspec' do\n  let(:contract_path) { contract_file 'simpl"
  },
  {
    "path": "spec/integration/templating_spec.rb",
    "chars": 1380,
    "preview": "# -*- encoding : utf-8 -*-\nrequire 'securerandom'\n\ndescribe 'Templating' do\n  let(:contract_path) { contract_file 'templ"
  },
  {
    "path": "spec/spec_helper.rb",
    "chars": 937,
    "preview": "# -*- encoding : utf-8 -*-\nrequire 'coveralls_helper'\nrequire 'webmock/rspec'\nrequire 'pacto'\nrequire 'pacto/test_helper"
  },
  {
    "path": "spec/unit/actors/from_examples_spec.rb",
    "chars": 2779,
    "preview": "# -*- encoding : utf-8 -*-\nmodule Pacto\n  module Actors\n    describe FromExamples do\n\n      let(:fallback) { double('fal"
  },
  {
    "path": "spec/unit/actors/json_generator_spec.rb",
    "chars": 3246,
    "preview": "# -*- encoding : utf-8 -*-\nRSpec.shared_examples 'uses defaults' do\n  it 'uses the default values for the request' do\n  "
  },
  {
    "path": "spec/unit/pacto/actor_spec.rb",
    "chars": 670,
    "preview": "# -*- encoding : utf-8 -*-\nRSpec.shared_examples 'an actor' do\n  # let(:contract) { Fabricate(:contract) }\n  let(:data) "
  },
  {
    "path": "spec/unit/pacto/configuration_spec.rb",
    "chars": 1197,
    "preview": "# -*- encoding : utf-8 -*-\nmodule Pacto\n  describe Configuration do\n    subject(:configuration) { described_class.new }\n"
  },
  {
    "path": "spec/unit/pacto/consumer/faraday_driver_spec.rb",
    "chars": 1500,
    "preview": "# -*- encoding : utf-8 -*-\nmodule Pacto\n  class Consumer\n    describe FaradayDriver do\n      subject(:strategy) { descri"
  },
  {
    "path": "spec/unit/pacto/contract_factory_spec.rb",
    "chars": 2499,
    "preview": "# -*- encoding : utf-8 -*-\nrequire 'spec_helper'\n\nmodule Pacto\n  describe ContractFactory do\n    let(:host)             "
  },
  {
    "path": "spec/unit/pacto/contract_files_spec.rb",
    "chars": 1319,
    "preview": "# -*- encoding : utf-8 -*-\nrequire 'spec_helper'\nrequire 'fileutils'\n\nmodule Pacto\n  describe ContractFiles do\n    let(:"
  },
  {
    "path": "spec/unit/pacto/contract_set_spec.rb",
    "chars": 1069,
    "preview": "# -*- encoding : utf-8 -*-\nrequire 'spec_helper'\n\nmodule Pacto\n  describe ContractSet do\n    let(:contract1) { Fabricate"
  },
  {
    "path": "spec/unit/pacto/contract_spec.rb",
    "chars": 2343,
    "preview": "# -*- encoding : utf-8 -*-\nRSpec.shared_examples 'a contract' do\n  before do\n    Pacto.configuration.adapter = adapter\n "
  },
  {
    "path": "spec/unit/pacto/cops/body_cop_spec.rb",
    "chars": 3593,
    "preview": "# -*- encoding : utf-8 -*-\nRSpec.shared_examples 'a body cop' do | section_to_validate |\n  subject(:cop) { described_cla"
  },
  {
    "path": "spec/unit/pacto/cops/response_header_cop_spec.rb",
    "chars": 3800,
    "preview": "# -*- encoding : utf-8 -*-\nmodule Pacto\n  module Cops\n    describe ResponseHeaderCop do\n      subject(:cop) { described_"
  },
  {
    "path": "spec/unit/pacto/cops/response_status_cop_spec.rb",
    "chars": 834,
    "preview": "# -*- encoding : utf-8 -*-\nmodule Pacto\n  module Cops\n    describe ResponseStatusCop do\n      subject(:cop) { described_"
  },
  {
    "path": "spec/unit/pacto/cops_spec.rb",
    "chars": 3246,
    "preview": "# -*- encoding : utf-8 -*-\nmodule Pacto\n  describe Cops do\n    let(:investigation_errors) { ['some error', 'another erro"
  },
  {
    "path": "spec/unit/pacto/core/configuration_spec.rb",
    "chars": 670,
    "preview": "# -*- encoding : utf-8 -*-\ndescribe Pacto do\n  describe '.configure' do\n    let(:contracts_path) { 'path_to_contracts' }"
  },
  {
    "path": "spec/unit/pacto/core/contract_registry_spec.rb",
    "chars": 1557,
    "preview": "# -*- encoding : utf-8 -*-\nrequire_relative '../../../../lib/pacto/core/contract_registry'\n\nmodule Pacto\n  describe Cont"
  },
  {
    "path": "spec/unit/pacto/core/http_middleware_spec.rb",
    "chars": 1401,
    "preview": "# -*- encoding : utf-8 -*-\nmodule Pacto\n  module Core\n    describe HTTPMiddleware do\n      subject(:middleware) { Pacto:"
  },
  {
    "path": "spec/unit/pacto/core/investigation_spec.rb",
    "chars": 2473,
    "preview": "# -*- encoding : utf-8 -*-\nmodule Pacto\n  describe Investigation do\n    let(:request) { double('request') }\n    let(:res"
  },
  {
    "path": "spec/unit/pacto/core/modes_spec.rb",
    "chars": 631,
    "preview": "# -*- encoding : utf-8 -*-\ndescribe Pacto do\n  modes = %w(generate validate)\n  modes.each do |mode|\n    enable_method = "
  },
  {
    "path": "spec/unit/pacto/erb_processor_spec.rb",
    "chars": 643,
    "preview": "# -*- encoding : utf-8 -*-\nmodule Pacto\n  describe ERBProcessor do\n    subject(:processor) { described_class.new }\n\n    "
  },
  {
    "path": "spec/unit/pacto/extensions_spec.rb",
    "chars": 852,
    "preview": "# -*- encoding : utf-8 -*-\nmodule Pacto\n  describe Extensions do\n    describe '#normalize_header_keys' do\n      it 'matc"
  },
  {
    "path": "spec/unit/pacto/formats/legacy/contract_builder_spec.rb",
    "chars": 3272,
    "preview": "# -*- encoding : utf-8 -*-\nmodule Pacto\n  module Formats\n    module Legacy\n      describe ContractBuilder do\n        let"
  },
  {
    "path": "spec/unit/pacto/formats/legacy/contract_factory_spec.rb",
    "chars": 1039,
    "preview": "# -*- encoding : utf-8 -*-\nrequire 'spec_helper'\n\nmodule Pacto\n  module Formats\n    module Legacy\n      describe Contrac"
  },
  {
    "path": "spec/unit/pacto/formats/legacy/contract_generator_spec.rb",
    "chars": 8400,
    "preview": "# -*- encoding : utf-8 -*-\nmodule Pacto\n  module Formats\n    module Legacy\n      describe ContractGenerator do\n        l"
  },
  {
    "path": "spec/unit/pacto/formats/legacy/contract_spec.rb",
    "chars": 1044,
    "preview": "# -*- encoding : utf-8 -*-\nrequire 'unit/pacto/contract_spec'\n\nmodule Pacto\n  module Formats\n    module Legacy\n      des"
  },
  {
    "path": "spec/unit/pacto/formats/legacy/generator/filters_spec.rb",
    "chars": 3824,
    "preview": "# -*- encoding : utf-8 -*-\nmodule Pacto\n  module Formats\n    module Legacy\n      module Generator\n        describe Filte"
  },
  {
    "path": "spec/unit/pacto/formats/legacy/request_clause_spec.rb",
    "chars": 2233,
    "preview": "# -*- encoding : utf-8 -*-\nmodule Pacto\n  module Formats\n    module Legacy\n      describe RequestClause do\n        let(:"
  },
  {
    "path": "spec/unit/pacto/formats/legacy/response_clause_spec.rb",
    "chars": 1043,
    "preview": "# -*- encoding : utf-8 -*-\nmodule Pacto\n  module Formats\n    module Legacy\n      describe ResponseClause do\n        let("
  },
  {
    "path": "spec/unit/pacto/formats/swagger/contract_factory_spec.rb",
    "chars": 2135,
    "preview": "# -*- encoding : utf-8 -*-\nmodule Pacto\n  module Formats\n    module Swagger\n      describe ContractFactory do\n        le"
  },
  {
    "path": "spec/unit/pacto/formats/swagger/contract_spec.rb",
    "chars": 1153,
    "preview": "# -*- encoding : utf-8 -*-\nrequire 'unit/pacto/contract_spec'\n\nmodule Pacto\n  module Formats\n    module Swagger\n      de"
  },
  {
    "path": "spec/unit/pacto/hooks/erb_hook_spec.rb",
    "chars": 1692,
    "preview": "# -*- encoding : utf-8 -*-\ndescribe Pacto::Hooks::ERBHook do\n  describe '#process' do\n    let(:req) do\n      OpenStruct."
  },
  {
    "path": "spec/unit/pacto/investigation_registry_spec.rb",
    "chars": 3544,
    "preview": "# -*- encoding : utf-8 -*-\ndescribe Pacto::InvestigationRegistry do\n  subject(:registry) { described_class.instance }\n  "
  },
  {
    "path": "spec/unit/pacto/logger_spec.rb",
    "chars": 1120,
    "preview": "# -*- encoding : utf-8 -*-\nmodule Pacto\n  module Logger\n    describe SimpleLogger do\n      before do\n        logger.log "
  },
  {
    "path": "spec/unit/pacto/meta_schema_spec.rb",
    "chars": 2585,
    "preview": "# -*- encoding : utf-8 -*-\nmodule Pacto\n  describe MetaSchema do\n    let(:valid_contract) do\n      <<-EOF\n        {\n    "
  },
  {
    "path": "spec/unit/pacto/pacto_spec.rb",
    "chars": 1265,
    "preview": "# -*- encoding : utf-8 -*-\nrequire 'spec_helper'\n\ndescribe Pacto do\n  around(:each) do |example|\n    $stdout = StringIO."
  },
  {
    "path": "spec/unit/pacto/request_pattern_spec.rb",
    "chars": 648,
    "preview": "# -*- encoding : utf-8 -*-\nrequire 'spec_helper'\n\nmodule Pacto\n  describe RequestPattern do\n    let(:http_method) { :get"
  },
  {
    "path": "spec/unit/pacto/stubs/observers/stenographer_spec.rb",
    "chars": 1104,
    "preview": "# -*- encoding : utf-8 -*-\nrequire 'spec_helper'\n\nmodule Pacto\n  module Observers\n    describe Stenographer do\n      let"
  },
  {
    "path": "spec/unit/pacto/stubs/uri_pattern_spec.rb",
    "chars": 2301,
    "preview": "# -*- encoding : utf-8 -*-\nrequire 'spec_helper'\n\nmodule Pacto\n  describe UriPattern do\n    context 'with non-strict mat"
  },
  {
    "path": "spec/unit/pacto/stubs/webmock_adapter_spec.rb",
    "chars": 4591,
    "preview": "# -*- encoding : utf-8 -*-\nmodule Pacto\n  module Stubs\n    # FIXME: Review this test and see which requests are Pacto vs"
  },
  {
    "path": "spec/unit/pacto/uri_spec.rb",
    "chars": 619,
    "preview": "# -*- encoding : utf-8 -*-\nrequire 'spec_helper'\n\nmodule Pacto\n  describe URI do\n    it 'returns the path appended to th"
  },
  {
    "path": "tasks/release.rake",
    "chars": 1369,
    "preview": "require 'octokit'\n\ndef github\n  @client ||= Octokit::Client.new :access_token => ENV['GITHUB_TOKEN']\nend\n\ndef release_ta"
  }
]

About this extraction

This page contains the full source code of the thoughtworks/pacto GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 200 files (283.1 KB), approximately 74.7k tokens, and a symbol index with 581 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!