specr 0.0.1.beta1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: cde21d78fee811f0a9f53137f5adaddcb82199be
4
+ data.tar.gz: 88adee928d0cd54c716ce620bc3f9b515b822cfa
5
+ SHA512:
6
+ metadata.gz: 3292f93ba0c20241876b31656253f85ad8dc21fb95dee2cb4c06022b6d6b39b5a5e6dd0dff4cf0553b59c3a87130cafa6e6aae0e6c8d125b490868a6e9403469
7
+ data.tar.gz: 0d3e876118e04c83a9c87a91a4ad076613bd0736b0fb9648f71bf3ba79f42f131d0f4637c660b17faa9c92d5ab9378bcdef7801f0b21b9e78f8514e446b9226f
@@ -0,0 +1,4 @@
1
+ scenarios.json
2
+ *.iml
3
+ api_spec.json
4
+ pkg/
@@ -0,0 +1,43 @@
1
+ inherit_from: .rubocop_todo.yml
2
+
3
+ AllCops:
4
+ TargetRubyVersion: 2.3
5
+ Exclude:
6
+ - !ruby/regexp /(vendor|bundle|bin|db|tmp)\/.*/
7
+ DisplayCopNames: true
8
+ DisplayStyleGuide: true
9
+
10
+ Rails:
11
+ Enabled: true
12
+
13
+ Style/WordArray:
14
+ Exclude:
15
+ - 'app/forms/*_form.rb'
16
+ - 'test/fabricators/extension_package_fabricator.rb'
17
+
18
+ Style/RegexpLiteral:
19
+ AllowInnerSlashes: true
20
+
21
+ Lint/UnusedMethodArgument:
22
+ Exclude:
23
+ - 'lib/tasks/populate.rake'
24
+
25
+ Metrics/LineLength:
26
+ Exclude:
27
+ - 'test/**/*.rb'
28
+ - 'Gemfile*'
29
+
30
+ Style/IndentArray:
31
+ EnforcedStyle: consistent
32
+
33
+ Style/MultilineMethodCallIndentation:
34
+ EnforcedStyle: indented
35
+
36
+ Style/MultilineOperationIndentation:
37
+ EnforcedStyle: indented
38
+
39
+ Documentation:
40
+ Enabled: false
41
+
42
+ Style/ClassAndModuleChildren:
43
+ Enabled: false
@@ -0,0 +1,65 @@
1
+ # This configuration was generated by
2
+ # `rubocop --auto-gen-config`
3
+ # on 2016-06-21 14:42:30 -0600 using RuboCop version 0.40.0.
4
+ # The point is for the user to remove these configuration records
5
+ # one by one as the offenses are removed from the code base.
6
+ # Note that changes in the inspected code, or installation of new
7
+ # versions of RuboCop, may require this file to be generated again.
8
+
9
+ # Offense count: 1
10
+ Lint/AmbiguousRegexpLiteral:
11
+ Exclude:
12
+ - 'lib/specr/step_definitions/http_steps.rb'
13
+
14
+ # Offense count: 1
15
+ # Cop supports --auto-correct.
16
+ # Configuration parameters: AlignWith, SupportedStyles, AutoCorrect.
17
+ # SupportedStyles: keyword, variable, start_of_line
18
+ Lint/EndAlignment:
19
+ Enabled: false
20
+
21
+ # Offense count: 1
22
+ Lint/Loop:
23
+ Exclude:
24
+ - 'lib/specr/step_definitions/async_steps.rb'
25
+
26
+ # Offense count: 3
27
+ Lint/UselessAssignment:
28
+ Exclude:
29
+ - 'lib/specr/tiny_client.rb'
30
+
31
+ # Offense count: 5
32
+ Metrics/AbcSize:
33
+ Max: 25
34
+
35
+ # Offense count: 1
36
+ # Configuration parameters: CountComments.
37
+ Metrics/ClassLength:
38
+ Max: 109
39
+
40
+ # Offense count: 2
41
+ Metrics/CyclomaticComplexity:
42
+ Max: 10
43
+
44
+ # Offense count: 18
45
+ # Configuration parameters: AllowHeredoc, AllowURI, URISchemes.
46
+ # URISchemes: http, https
47
+ Metrics/LineLength:
48
+ Max: 131
49
+
50
+ # Offense count: 6
51
+ # Configuration parameters: CountComments.
52
+ Metrics/MethodLength:
53
+ Max: 28
54
+
55
+ # Offense count: 2
56
+ Metrics/PerceivedComplexity:
57
+ Max: 11
58
+
59
+ # Offense count: 2
60
+ # Cop supports --auto-correct.
61
+ # Configuration parameters: EnforcedStyle, SupportedStyles, AllowInnerSlashes.
62
+ # SupportedStyles: slashes, percent_r, mixed
63
+ Style/RegexpLiteral:
64
+ Exclude:
65
+ - 'compliance.gemspec'
@@ -0,0 +1,4 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.2.2
4
+ before_install: gem install bundler -v 1.10.5
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+ source 'https://rubygems.org'
3
+
4
+ gemspec
@@ -0,0 +1,83 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ specr (0.0.1.beta1)
5
+ cucumber (~> 2.4.0)
6
+ httmultiparty (~> 0.3.16)
7
+ json-schema (~> 2.6)
8
+ rake (~> 10.0)
9
+ test-unit
10
+
11
+ GEM
12
+ remote: https://rubygems.org/
13
+ specs:
14
+ addressable (2.5.1)
15
+ public_suffix (~> 2.0, >= 2.0.2)
16
+ ast (2.3.0)
17
+ builder (3.2.3)
18
+ byebug (9.0.5)
19
+ coderay (1.1.1)
20
+ cucumber (2.4.0)
21
+ builder (>= 2.1.2)
22
+ cucumber-core (~> 1.5.0)
23
+ cucumber-wire (~> 0.0.1)
24
+ diff-lcs (>= 1.1.3)
25
+ gherkin (~> 4.0)
26
+ multi_json (>= 1.7.5, < 2.0)
27
+ multi_test (>= 0.1.2)
28
+ cucumber-core (1.5.0)
29
+ gherkin (~> 4.0)
30
+ cucumber-wire (0.0.1)
31
+ diff-lcs (1.3)
32
+ gherkin (4.1.3)
33
+ httmultiparty (0.3.16)
34
+ httparty (>= 0.7.3)
35
+ mimemagic
36
+ multipart-post
37
+ httparty (0.15.3)
38
+ multi_xml (>= 0.5.2)
39
+ json-schema (2.8.0)
40
+ addressable (>= 2.4)
41
+ method_source (0.8.2)
42
+ mimemagic (0.3.2)
43
+ multi_json (1.12.1)
44
+ multi_test (0.1.2)
45
+ multi_xml (0.6.0)
46
+ multipart-post (2.0.0)
47
+ parser (2.3.1.2)
48
+ ast (~> 2.2)
49
+ power_assert (1.0.2)
50
+ powerpack (0.1.1)
51
+ pry (0.10.3)
52
+ coderay (~> 1.1.0)
53
+ method_source (~> 0.8.1)
54
+ slop (~> 3.4)
55
+ pry-byebug (3.4.0)
56
+ byebug (~> 9.0)
57
+ pry (~> 0.10)
58
+ public_suffix (2.0.5)
59
+ rainbow (2.1.0)
60
+ rake (10.5.0)
61
+ rubocop (0.40.0)
62
+ parser (>= 2.3.1.0, < 3.0)
63
+ powerpack (~> 0.1)
64
+ rainbow (>= 1.99.1, < 3.0)
65
+ ruby-progressbar (~> 1.7)
66
+ unicode-display_width (~> 1.0, >= 1.0.1)
67
+ ruby-progressbar (1.8.1)
68
+ slop (3.6.0)
69
+ test-unit (3.2.3)
70
+ power_assert
71
+ unicode-display_width (1.0.5)
72
+
73
+ PLATFORMS
74
+ ruby
75
+
76
+ DEPENDENCIES
77
+ bundler (~> 1.10)
78
+ pry-byebug
79
+ rubocop (~> 0.40.0)
80
+ specr!
81
+
82
+ BUNDLED WITH
83
+ 1.14.4
@@ -0,0 +1,28 @@
1
+ # Specr
2
+
3
+ A toolkit to assist in validating APIs.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'specr'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install specr
20
+
21
+ ## Usage
22
+
23
+ TODO: Write usage instructions here
24
+
25
+ ## Contributing
26
+
27
+ Bug reports and pull requests are welcome on GitHub at https://github.com/remear/specr.
28
+
@@ -0,0 +1,2 @@
1
+ # frozen_string_literal: true
2
+ require 'bundler/gem_tasks'
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "specr"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start
@@ -0,0 +1,7 @@
1
+ #!/bin/bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+
5
+ bundle install
6
+
7
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+ require 'httmultiparty'
3
+ require 'json'
4
+ require 'json-schema'
5
+
6
+ require 'specr/version'
7
+ require 'specr/extracer'
8
+ require 'specr/tiny_client'
9
+ require 'specr/step_definitions/async_steps'
10
+ require 'specr/step_definitions/debugging_steps'
11
+ require 'specr/step_definitions/http_steps'
12
+ require 'specr/step_definitions/jsonapi_steps'
13
+ require 'specr/step_definitions/validation_steps'
14
+ require 'specr/step_definitions/jsonapi_validation_steps'
15
+
16
+ require 'specr/features/support/initial_setup'
17
+
18
+ module Specr
19
+ class << self
20
+ attr_accessor :configuration, :client, :logger
21
+ end
22
+
23
+ def self.configure
24
+ self.configuration ||= Configuration.new
25
+ yield configuration
26
+ end
27
+
28
+ class Configuration
29
+ attr_accessor :root_url
30
+ attr_accessor :default_headers
31
+ attr_accessor :max_request_attempts
32
+ attr_accessor :request_attempt_delay
33
+
34
+ def initialize
35
+ @root_url = 'http://localhost:3000'
36
+ @default_headers = {
37
+ 'Accept' => 'application/json',
38
+ 'Content-Type' => 'application/json'
39
+ }
40
+ @max_request_attempts = 5
41
+ @request_attempt_delay = 2
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,107 @@
1
+ # frozen_string_literal: true
2
+ module Specr
3
+ class Extracer
4
+ def initialize
5
+ @scenarios = Array.new
6
+ @resources_create = Hash.new([])
7
+ @resources_update = Hash.new([])
8
+ end
9
+
10
+ def log_request(method, endpoint, request, response, response_code,
11
+ response_message)
12
+ if request.is_a? String
13
+ begin
14
+ request = JSON.parse(request)
15
+ rescue
16
+ # WHAT ARE WE EVEN GETTING
17
+ return
18
+ end
19
+ end
20
+ scenario = {
21
+ name: scenario_name,
22
+ endpoint: endpoint,
23
+ method: method,
24
+ request: request,
25
+ response: response,
26
+ response_code: response_code,
27
+ response_message: response_message
28
+ }
29
+ @scenarios << scenario
30
+ return unless response
31
+ # TODO: make these extract from arrays when those are being used
32
+ if endpoint.start_with?(Specr.configuration.root_url)
33
+ endpoint = endpoint[Specr.configuration.root_url.length..-1]
34
+ end
35
+ if method == 'POST'
36
+ # the path is either /[resource_name] or /[some_other_resource]/[guid]/[resource_name]
37
+ # and the resource is getting created
38
+ resource = endpoint.split('/').last
39
+ @resources_create[resource] += [scenario]
40
+ elsif method == 'PATCH'
41
+ # the path will be /[resource_name]/[guid]
42
+ resource = endpoint.split('/')[1]
43
+ @resources_update[resource] += [scenario]
44
+ end
45
+ # 'GET' & 'DELETE' requests are ignored, and 'PUT' can be similar to a 'PATCH' in updating
46
+ end
47
+
48
+ def save
49
+ file = File.join('specification.json')
50
+ json = {
51
+ endpoints: load_endpoints,
52
+ scenarios: @scenarios,
53
+ resources_create: @resources_create,
54
+ resources_update: @resources_update,
55
+ forms: load_forms,
56
+ schemas: load_schemas
57
+ }
58
+ File.open(file, 'w') { |f| f.write(JSON.pretty_generate(json)) }
59
+ end
60
+
61
+ private
62
+
63
+ def scenario_name
64
+ scenario = Specr.client.current_scenario
65
+ [scenario.feature.name.parameterize.underscore,
66
+ scenario.name.parameterize.underscore].join('.')
67
+ end
68
+
69
+ def resolve_refs(json, path)
70
+ if json.is_a? Hash
71
+ if json['$ref']
72
+ path = File.join(File.dirname(path), json['$ref'])
73
+ json.delete('$ref')
74
+ Hash[resolve_refs(JSON.parse(File.read(path)), path).to_a + json.to_a]
75
+ else
76
+ Hash[json.map do |key, value|
77
+ [key, resolve_refs(value, path)]
78
+ end]
79
+ end
80
+ elsif json.is_a? Array
81
+ json.map do |j|
82
+ resolve_refs j, path
83
+ end
84
+ else
85
+ json
86
+ end
87
+ end
88
+
89
+ def load_schemas
90
+ ret = {}
91
+ path = File.join('fixtures')
92
+ Dir.glob("#{path}/**/*.json") do |f|
93
+ json = resolve_refs(JSON.parse(File.read(f)), f)
94
+ ret[f] = json
95
+ end
96
+ ret
97
+ end
98
+
99
+ def load_endpoints
100
+ JSON.parse(File.read('endpoints.json'))
101
+ end
102
+
103
+ def load_forms
104
+ JSON.parse(File.read('forms.json'))
105
+ end
106
+ end
107
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+ require 'logger'
3
+ require 'test/unit/assertions'
4
+
5
+ World(Test::Unit::Assertions)
6
+
7
+ extracer = Specr::Extracer.new
8
+
9
+ AfterConfiguration do
10
+ Specr.logger = Logger.new(STDOUT)
11
+ Specr.logger.level = Logger::FATAL
12
+ Specr.client = Specr::TinyClient.new(extracer)
13
+ end
14
+
15
+ Before do |scenario|
16
+ Specr.client.clear_storage
17
+ Specr.client.current_scenario = scenario
18
+ end
19
+
20
+ Before('@cleanroom') do
21
+ Specr.client.clear_storage
22
+ end
23
+
24
+ at_exit do
25
+ Specr.client.extracer.save
26
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+ And(/^I await processing for ((?:https?:\/)?\/\S*) with the condition "(\S*?)" "(\S*)" "(.*?)"$/) do |url, keys, comperator, value|
3
+ await_resource_processing(url, comperator, keys, value)
4
+ end
5
+
6
+ def await_resource_processing(href, comperator, watched_attribute, desired_value)
7
+ attempts = 0
8
+ max_attempts = 5
9
+ pending = true
10
+ response = nil
11
+ begin
12
+ response = JSON.parse(Specr.client.get(href))
13
+ current_value = Specr.client.get_link(watched_attribute)
14
+ if current_value.method(comperator).call(desired_value)
15
+ pending = false
16
+ else
17
+ sleep 5
18
+ end
19
+ attempts += 1
20
+ end while pending && (attempts < max_attempts)
21
+ raise ArgumentError, 'Timed out waiting for resource processing!' if pending == true
22
+ response
23
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+ Then(/^debug$/) do
3
+ Specr.logger.debug "HTTP status code: #{@client.last_code}"
4
+ Specr.logger.debug "HTTP body: #{@client.last_body}"
5
+ Specr.logger.debug "Storage: #{@client.storage}"
6
+ end
7
+
8
+ When(/^debugging is enabled$/) do
9
+ Specr.logger.level = Logger::DEBUG
10
+ end
11
+
12
+ When(/^debugging is disabled$/) do
13
+ Specr.logger.level = Logger::FATAL
14
+ end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+ When /^I set headers:$/ do |request_headers|
3
+ Specr.client.headers = Specr.configuration.default_headers.merge(request_headers.rows_hash)
4
+ end
5
+
6
+ When(/^I (\w+) to ((?:https?:\/)?\/\S*)$/) do |verb, url|
7
+ Specr.client.send(verb.downcase, url)
8
+ end
9
+
10
+ When(/^I (\w+) to ((?:https?:\/)?\/\S*) with the body:$/) do |verb, url, body|
11
+ Specr.client.send(verb.downcase.to_sym, url, body)
12
+ end
13
+
14
+ When(/^I (POST|PATCH) to (\/\S*?) with the file "(.*?)" as "(.*?)"$/) do |verb, url, file, file_field|
15
+ Specr.client.send("#{verb.downcase}_multipart",
16
+ Specr.client.hydrater(url), file, file_field, nil)
17
+ end
18
+
19
+ When(/^I (POST|PATCH) to (\/\S*?) with the "(.*?)" file as "(.*?)" and the body:$/) do |verb, url, file, file_field, body|
20
+ Specr.client.send("#{verb.downcase}_multipart",
21
+ Specr.client.hydrater(url), file, file_field, body)
22
+ end
23
+
24
+ When(/^I (\w+) to the "(.*?)" link with the body:$/) do |verb, keys, body|
25
+ step "I #{verb} to #{Specr.client.get_link(keys)} with the body:", body
26
+ end
27
+
28
+ When(/^I (\w+) to the "(.*?)" link$/) do |verb, keys|
29
+ step "I #{verb} to #{Specr.client.get_link(keys)}"
30
+ end
31
+
32
+ Then(/^the response has this schema:$/) do |schema|
33
+ Specr.client.validate(schema)
34
+ end
35
+
36
+ Then(/^the response is valid according to the "(.*?)" schema$/) do |filename|
37
+ Specr.client.validate(filename)
38
+ end
39
+
40
+ Then(/^I should get a (.+) status code$/) do |code|
41
+ message = Specr.client.last_body.fetch('description', '') if Specr.client.last_body
42
+ assert_equal code.to_i, Specr.client.last_code, message
43
+ end
44
+
45
+ Then(/^there should be no response body$/) do
46
+ assert_nil Specr.client.last_body
47
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+ When(/^I (\w+) to the (top|resource)\-level (\w+) link$/) do |verb, level, link|
3
+ step "I #{verb} to the #{level}-level \"#{link}\" link with the body:", nil
4
+ end
5
+
6
+ When(/^I (\w+) to the (top|resource)\-level (\w+) link with the body:$/) do |verb, level, link, body|
7
+ keys = case level
8
+ when 'resource' then "data.links.#{link}"
9
+ when 'top' then "links.#{link}"
10
+ end
11
+ step "I #{verb} to the \"#{keys}\" link with the body:", body
12
+ end
@@ -0,0 +1,10 @@
1
+ Then(/^the attributes match:$/) do |against|
2
+ checker JSON.parse(Specr.client.hydrater(against)), Specr.client['data']['attributes'], ''
3
+ end
4
+
5
+ Then(/^the errors match:$/) do |against|
6
+ against = JSON.parse(Specr.client.hydrater(against))
7
+ Specr.client['errors'].each do |error|
8
+ checker against, error, ''
9
+ end
10
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+ # TODO: move to a validator
3
+ def checker(from, of, nesting)
4
+ assert_not_nil from, nesting
5
+ from.each_pair do |key, val|
6
+ if val.is_a?(String) || val.is_a?(Integer) || val.is_a?(TrueClass) || val.is_a?(FalseClass)
7
+ assert_equal val, of[key], "#{nesting}>#{key}"
8
+ elsif val.nil?
9
+ assert_nil of[key]
10
+ elsif of.is_a?(Array)
11
+ checker val, of[0][key], "#{nesting}>#{key}"
12
+ else
13
+ checker val, of[key], "#{nesting}>#{key}"
14
+ end
15
+ end
16
+ end
17
+
18
+ Then(/^the fields match:$/) do |against|
19
+ checker JSON.parse(Specr.client.hydrater(against)), Specr.client['data'], ''
20
+ end
21
+
22
+ Then(/^the fields match:$/) do |against|
23
+ against = JSON.parse(Specr.client.hydrater(against))
24
+ Specr.client.last_body[resource].each do |body|
25
+ checker against, body, ''
26
+ end
27
+ end
@@ -0,0 +1,140 @@
1
+ # frozen_string_literal: true
2
+ module Specr
3
+ class TinyClient
4
+ attr_accessor :headers, :current_scenario
5
+ attr_reader :extracer, :responses, :storage
6
+
7
+ def initialize(extracer)
8
+ @extracer = extracer
9
+ @root_url = Specr.configuration.root_url
10
+ @headers = Specr.configuration.default_headers
11
+ @responses = []
12
+ @storage = {}
13
+ end
14
+
15
+ def clear_storage
16
+ @storage = {}
17
+ end
18
+
19
+ def build_options(opts)
20
+ multipart = opts.delete(:multipart)
21
+ body = opts.delete(:body)
22
+ body = JSON.parse(body) unless [Hash, NilClass].include? body.class # TODO: is this necessary?
23
+ body = hydrater(JSON.dump(body)) if body
24
+ options = {
25
+ headers: headers
26
+ }.tap do |o|
27
+ o[:body] = body if body
28
+ if multipart
29
+ file = opts.delete(:file)
30
+ field = opts.delete(:field)
31
+ o[:body] = {} unless o[:body]
32
+ o[:body][field] = file
33
+ end
34
+ end
35
+ end
36
+
37
+ def build_url(endpoint)
38
+ endpoint = hydrater(endpoint)
39
+ url = endpoint =~ /https?:\/\// ? endpoint : "#{@root_url}#{endpoint}"
40
+ end
41
+
42
+ def refine_endpoint(ep)
43
+ ep =~ /^\/\S*\/:\S*_id$/ ? ep.sub(/:(\S*_)id/, ':id') : ep
44
+ end
45
+
46
+ def request(verb, endpoint, opts = {})
47
+ raise 'HTTP Verb must be a symbol' unless verb.is_a? Symbol
48
+ multipart = opts[:multipart]
49
+ url = build_url(endpoint)
50
+ options = build_options(opts)
51
+ Specr.logger.debug(options)
52
+ response = if multipart
53
+ HTTMultiParty.post(url, options)
54
+ else
55
+ HTTParty.send(verb, url, options)
56
+ end
57
+ Specr.logger.debug(response)
58
+ responses << response
59
+ extracer.log_request(
60
+ verb.to_s.upcase,
61
+ refine_endpoint(endpoint),
62
+ options.fetch(:body, nil),
63
+ last_body,
64
+ response.code,
65
+ response.message
66
+ ) if last_code < 400
67
+ response
68
+ end
69
+
70
+ def post(endpoint, body = nil, opts = {})
71
+ request(:post, endpoint, opts.merge!(body: body))
72
+ end
73
+
74
+ def post_multipart(endpoint, file, field, _body, opts = {})
75
+ file_name = File.join('fixtures', 'files', file)
76
+ options = opts.merge!(multipart: true,
77
+ file: File.new(file_name),
78
+ field: field)
79
+ request(:post, endpoint, options)
80
+ end
81
+
82
+ def put(endpoint, body, opts = {})
83
+ request(:put, endpoint, opts.merge!(body: body))
84
+ end
85
+
86
+ def patch(endpoint, body, opts = {})
87
+ request(:patch, endpoint, opts.merge!(body: body))
88
+ end
89
+
90
+ def get(endpoint)
91
+ request(:get, endpoint)
92
+ end
93
+
94
+ def delete(endpoint, body = nil, opts = {})
95
+ request(:delete, endpoint, body ? opts.merge!(body: body) : opts)
96
+ end
97
+
98
+ def add_response(response)
99
+ responses << response
100
+ end
101
+
102
+ def last_code
103
+ responses.last.code
104
+ end
105
+
106
+ def last_body
107
+ JSON.parse(responses.last.body) if responses.last.body
108
+ end
109
+
110
+ def get_link(keys)
111
+ last_body.dig(*keys.split('.'))
112
+ end
113
+
114
+ def hydrater(what)
115
+ return unless what
116
+ what.gsub(/:\w+/) do |match|
117
+ key = match.tr(':', '')
118
+ hydrated_value = storage[key] ? storage[key] : storage[key.to_sym]
119
+ hydrated_value ? hydrated_value : match
120
+ end
121
+ end
122
+
123
+ def validate(against)
124
+ file_name = File.join('fixtures', "#{against}.json")
125
+ if File.exist?(file_name) && (!against.is_a? Hash)
126
+ JSON::Validator.validate!(file_name, last_body)
127
+ else
128
+ JSON::Validator.validate!(against, last_body)
129
+ end
130
+ end
131
+
132
+ def [](name)
133
+ if last_body.key? name
134
+ last_body[name]
135
+ else
136
+ last_body.select { |x| x != 'links' && x != 'meta' }.values.first[name]
137
+ end
138
+ end
139
+ end
140
+ end
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+ module Specr
3
+ VERSION = '0.0.1.beta1'
4
+ end
@@ -0,0 +1,31 @@
1
+ # coding: utf-8
2
+ # frozen_string_literal: true
3
+ lib = File.expand_path('../lib', __FILE__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+ require 'specr/version'
6
+
7
+ Gem::Specification.new do |spec|
8
+ spec.name = 'specr'
9
+ spec.version = Specr::VERSION
10
+ spec.authors = ['Ben Mills']
11
+ spec.email = ['ben@unfiniti.com']
12
+
13
+ spec.summary = 'A toolkit for building API specifications.'
14
+ spec.description = 'A toolkit for building API specifications.'
15
+ spec.homepage = 'http://github.com/remear/specr'
16
+
17
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
18
+ spec.bindir = 'exe'
19
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
20
+ spec.require_paths = ['lib']
21
+
22
+ spec.add_dependency 'cucumber', '~> 2.4.0'
23
+ spec.add_dependency 'httmultiparty', '~> 0.3.16'
24
+ spec.add_dependency 'json-schema', '~> 2.6'
25
+ spec.add_dependency 'test-unit'
26
+ spec.add_dependency 'rake', '~> 10.0'
27
+
28
+ spec.add_development_dependency 'bundler', '~> 1.10'
29
+ spec.add_development_dependency 'pry-byebug'
30
+ spec.add_development_dependency 'rubocop', '~> 0.40.0'
31
+ end
metadata ADDED
@@ -0,0 +1,177 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: specr
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1.beta1
5
+ platform: ruby
6
+ authors:
7
+ - Ben Mills
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2017-07-19 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: cucumber
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 2.4.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 2.4.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: httmultiparty
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: 0.3.16
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 0.3.16
41
+ - !ruby/object:Gem::Dependency
42
+ name: json-schema
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '2.6'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '2.6'
55
+ - !ruby/object:Gem::Dependency
56
+ name: test-unit
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rake
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '10.0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '10.0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: bundler
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '1.10'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '1.10'
97
+ - !ruby/object:Gem::Dependency
98
+ name: pry-byebug
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: rubocop
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: 0.40.0
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: 0.40.0
125
+ description: A toolkit for building API specifications.
126
+ email:
127
+ - ben@unfiniti.com
128
+ executables: []
129
+ extensions: []
130
+ extra_rdoc_files: []
131
+ files:
132
+ - ".gitignore"
133
+ - ".rubocop.yml"
134
+ - ".rubocop_todo.yml"
135
+ - ".travis.yml"
136
+ - Gemfile
137
+ - Gemfile.lock
138
+ - README.md
139
+ - Rakefile
140
+ - bin/console
141
+ - bin/setup
142
+ - lib/specr.rb
143
+ - lib/specr/extracer.rb
144
+ - lib/specr/features/support/initial_setup.rb
145
+ - lib/specr/step_definitions/async_steps.rb
146
+ - lib/specr/step_definitions/debugging_steps.rb
147
+ - lib/specr/step_definitions/http_steps.rb
148
+ - lib/specr/step_definitions/jsonapi_steps.rb
149
+ - lib/specr/step_definitions/jsonapi_validation_steps.rb
150
+ - lib/specr/step_definitions/validation_steps.rb
151
+ - lib/specr/tiny_client.rb
152
+ - lib/specr/version.rb
153
+ - specr.gemspec
154
+ homepage: http://github.com/remear/specr
155
+ licenses: []
156
+ metadata: {}
157
+ post_install_message:
158
+ rdoc_options: []
159
+ require_paths:
160
+ - lib
161
+ required_ruby_version: !ruby/object:Gem::Requirement
162
+ requirements:
163
+ - - ">="
164
+ - !ruby/object:Gem::Version
165
+ version: '0'
166
+ required_rubygems_version: !ruby/object:Gem::Requirement
167
+ requirements:
168
+ - - ">"
169
+ - !ruby/object:Gem::Version
170
+ version: 1.3.1
171
+ requirements: []
172
+ rubyforge_project:
173
+ rubygems_version: 2.6.8
174
+ signing_key:
175
+ specification_version: 4
176
+ summary: A toolkit for building API specifications.
177
+ test_files: []