spec_forge 0.6.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +112 -2
- data/README.md +133 -8
- data/flake.lock +3 -3
- data/flake.nix +3 -3
- data/lib/spec_forge/attribute/factory.rb +1 -1
- data/lib/spec_forge/callbacks.rb +9 -0
- data/lib/spec_forge/cli/docs/generate.rb +72 -0
- data/lib/spec_forge/cli/docs.rb +92 -0
- data/lib/spec_forge/cli/init.rb +39 -7
- data/lib/spec_forge/cli/new.rb +13 -3
- data/lib/spec_forge/cli/run.rb +12 -4
- data/lib/spec_forge/cli/serve.rb +155 -0
- data/lib/spec_forge/cli.rb +14 -6
- data/lib/spec_forge/configuration.rb +2 -2
- data/lib/spec_forge/context/store.rb +23 -40
- data/lib/spec_forge/core_ext/array.rb +27 -0
- data/lib/spec_forge/documentation/builder.rb +383 -0
- data/lib/spec_forge/documentation/document/operation.rb +47 -0
- data/lib/spec_forge/documentation/document/parameter.rb +22 -0
- data/lib/spec_forge/documentation/document/request_body.rb +24 -0
- data/lib/spec_forge/documentation/document/response.rb +39 -0
- data/lib/spec_forge/documentation/document/response_body.rb +27 -0
- data/lib/spec_forge/documentation/document.rb +48 -0
- data/lib/spec_forge/documentation/generators/base.rb +81 -0
- data/lib/spec_forge/documentation/generators/openapi/base.rb +100 -0
- data/lib/spec_forge/documentation/generators/openapi/error_formatter.rb +149 -0
- data/lib/spec_forge/documentation/generators/openapi/v3_0.rb +65 -0
- data/lib/spec_forge/documentation/generators/openapi.rb +59 -0
- data/lib/spec_forge/documentation/generators.rb +17 -0
- data/lib/spec_forge/documentation/loader/cache.rb +138 -0
- data/lib/spec_forge/documentation/loader.rb +159 -0
- data/lib/spec_forge/documentation/openapi/base.rb +33 -0
- data/lib/spec_forge/documentation/openapi/v3_0/example.rb +44 -0
- data/lib/spec_forge/documentation/openapi/v3_0/media_type.rb +42 -0
- data/lib/spec_forge/documentation/openapi/v3_0/operation.rb +175 -0
- data/lib/spec_forge/documentation/openapi/v3_0/response.rb +65 -0
- data/lib/spec_forge/documentation/openapi/v3_0/schema.rb +80 -0
- data/lib/spec_forge/documentation/openapi/v3_0/tag.rb +71 -0
- data/lib/spec_forge/documentation/openapi.rb +23 -0
- data/lib/spec_forge/documentation.rb +27 -0
- data/lib/spec_forge/error.rb +17 -0
- data/lib/spec_forge/factory.rb +2 -2
- data/lib/spec_forge/filter.rb +3 -4
- data/lib/spec_forge/forge.rb +5 -4
- data/lib/spec_forge/http/backend.rb +2 -0
- data/lib/spec_forge/http/request.rb +14 -3
- data/lib/spec_forge/loader.rb +14 -24
- data/lib/spec_forge/normalizer/default.rb +51 -0
- data/lib/spec_forge/normalizer/definition.rb +248 -0
- data/lib/spec_forge/normalizer/validators.rb +99 -0
- data/lib/spec_forge/normalizer.rb +356 -199
- data/lib/spec_forge/normalizers/_shared.yml +74 -0
- data/lib/spec_forge/normalizers/configuration.yml +23 -0
- data/lib/spec_forge/normalizers/constraint.yml +8 -0
- data/lib/spec_forge/normalizers/expectation.yml +47 -0
- data/lib/spec_forge/normalizers/factory.yml +12 -0
- data/lib/spec_forge/normalizers/factory_reference.yml +15 -0
- data/lib/spec_forge/normalizers/global_context.yml +28 -0
- data/lib/spec_forge/normalizers/spec.yml +50 -0
- data/lib/spec_forge/runner/adapter.rb +183 -0
- data/lib/spec_forge/runner/debug_proxy.rb +3 -3
- data/lib/spec_forge/runner/state.rb +4 -5
- data/lib/spec_forge/runner.rb +40 -124
- data/lib/spec_forge/spec/expectation/constraint.rb +13 -5
- data/lib/spec_forge/spec/expectation.rb +7 -3
- data/lib/spec_forge/spec.rb +13 -58
- data/lib/spec_forge/version.rb +1 -1
- data/lib/spec_forge.rb +30 -23
- data/lib/templates/openapi.yml.tt +22 -0
- data/lib/templates/redoc.html.tt +28 -0
- data/lib/templates/swagger.html.tt +59 -0
- metadata +92 -14
- data/lib/spec_forge/normalizer/configuration.rb +0 -90
- data/lib/spec_forge/normalizer/constraint.rb +0 -60
- data/lib/spec_forge/normalizer/expectation.rb +0 -105
- data/lib/spec_forge/normalizer/factory.rb +0 -78
- data/lib/spec_forge/normalizer/factory_reference.rb +0 -85
- data/lib/spec_forge/normalizer/global_context.rb +0 -88
- data/lib/spec_forge/normalizer/spec.rb +0 -97
- /data/lib/templates/{forge_helper.tt → forge_helper.rb.tt} +0 -0
- /data/lib/templates/{new_factory.tt → new_factory.yml.tt} +0 -0
- /data/lib/templates/{new_spec.tt → new_spec.yml.tt} +0 -0
@@ -12,21 +12,24 @@ module SpecForge
|
|
12
12
|
# @example In code
|
13
13
|
# constraint = Constraint.new(
|
14
14
|
# status: 200,
|
15
|
-
#
|
15
|
+
# headers: {response_header: "kind_of.string"},
|
16
|
+
# json: {name: {"matcher.eq" => "John"}}
|
16
17
|
# )
|
17
18
|
#
|
18
|
-
class Constraint < Data.define(:status, :json) # :xml, :html
|
19
|
+
class Constraint < Data.define(:status, :headers, :json) # :xml, :html
|
19
20
|
#
|
20
21
|
# Creates a new constraint
|
21
22
|
#
|
22
23
|
# @param status [Integer, String] The expected HTTP status code, or reference to one
|
24
|
+
# @param headers [Hash] The expected headers with matchers
|
23
25
|
# @param json [Hash, Array] The expected JSON with matchers
|
24
26
|
#
|
25
27
|
# @return [Constraint] A new constraint instance
|
26
28
|
#
|
27
|
-
def initialize(status:, json: {})
|
29
|
+
def initialize(status:, headers: {}, json: {})
|
28
30
|
super(
|
29
31
|
status: Attribute.from(status),
|
32
|
+
headers: Attribute.from(headers),
|
30
33
|
json: Attribute.from(json)
|
31
34
|
)
|
32
35
|
end
|
@@ -58,7 +61,8 @@ module SpecForge
|
|
58
61
|
def as_matchers
|
59
62
|
{
|
60
63
|
status: status.resolve_as_matcher,
|
61
|
-
json: resolve_json_matcher
|
64
|
+
json: resolve_json_matcher,
|
65
|
+
headers: resolve_hash_matcher(headers)
|
62
66
|
}
|
63
67
|
end
|
64
68
|
|
@@ -108,11 +112,15 @@ module SpecForge
|
|
108
112
|
def resolve_json_matcher
|
109
113
|
case json
|
110
114
|
when HashLike
|
111
|
-
json
|
115
|
+
resolve_hash_matcher(json)
|
112
116
|
else
|
113
117
|
json.resolve_as_matcher
|
114
118
|
end
|
115
119
|
end
|
120
|
+
|
121
|
+
def resolve_hash_matcher(hash)
|
122
|
+
hash.transform_values(&:resolve_as_matcher).stringify_keys
|
123
|
+
end
|
116
124
|
end
|
117
125
|
end
|
118
126
|
end
|
@@ -15,7 +15,10 @@ module SpecForge
|
|
15
15
|
# json:
|
16
16
|
# name: kind_of.string
|
17
17
|
#
|
18
|
-
class Expectation < Data.define(
|
18
|
+
class Expectation < Data.define(
|
19
|
+
:id, :name, :line_number,
|
20
|
+
:debug, :store_as, :documentation, :constraints
|
21
|
+
)
|
19
22
|
#
|
20
23
|
# @return [Boolean] True if debugging is enabled
|
21
24
|
#
|
@@ -34,14 +37,15 @@ module SpecForge
|
|
34
37
|
# @param line_number [Integer] Line number in source
|
35
38
|
# @param debug [Boolean] Whether to enable debugging
|
36
39
|
# @param store_as [String] Unique Context::Store identifier
|
40
|
+
# @param documentation [Boolean] Whether to include in documentation generation
|
37
41
|
# @param expect [Hash] Expected constraints
|
38
42
|
#
|
39
43
|
# @return [Expectation] A new expectation instance
|
40
44
|
#
|
41
|
-
def initialize(id:, name:, line_number:, debug:, store_as:, expect:)
|
45
|
+
def initialize(id:, name:, line_number:, debug:, store_as:, expect:, documentation:)
|
42
46
|
constraints = Constraint.new(**expect)
|
43
47
|
|
44
|
-
super(id:, name:, line_number:, debug:, store_as:, constraints:)
|
48
|
+
super(id:, name:, line_number:, debug:, store_as:, documentation:, constraints:)
|
45
49
|
end
|
46
50
|
|
47
51
|
#
|
data/lib/spec_forge/spec.rb
CHANGED
@@ -14,61 +14,15 @@ module SpecForge
|
|
14
14
|
# - expect:
|
15
15
|
# status: 200
|
16
16
|
#
|
17
|
-
class Spec
|
17
|
+
class Spec < Data.define(
|
18
|
+
:id, :name, :file_path, :file_name, :line_number,
|
19
|
+
:debug, :documentation, :expectations
|
20
|
+
)
|
18
21
|
#
|
19
22
|
# @return [Boolean] True if debugging is enabled
|
20
23
|
#
|
21
24
|
attr_predicate :debug
|
22
25
|
|
23
|
-
#
|
24
|
-
# Unique identifier for this spec
|
25
|
-
#
|
26
|
-
# @return [String] The spec ID
|
27
|
-
#
|
28
|
-
attr_reader :id
|
29
|
-
|
30
|
-
#
|
31
|
-
# Human-readable name for this spec
|
32
|
-
#
|
33
|
-
# @return [String] The spec name
|
34
|
-
#
|
35
|
-
attr_reader :name
|
36
|
-
|
37
|
-
#
|
38
|
-
# Absolute path to the file containing this spec
|
39
|
-
#
|
40
|
-
# @return [String] The file path
|
41
|
-
#
|
42
|
-
attr_reader :file_path
|
43
|
-
|
44
|
-
#
|
45
|
-
# Base name of the file without path or extension
|
46
|
-
#
|
47
|
-
# @return [String] The file name
|
48
|
-
#
|
49
|
-
attr_reader :file_name
|
50
|
-
|
51
|
-
#
|
52
|
-
# Whether to enable debugging for this spec
|
53
|
-
#
|
54
|
-
# @return [Boolean] Debug flag
|
55
|
-
#
|
56
|
-
attr_reader :debug
|
57
|
-
|
58
|
-
#
|
59
|
-
# Line number in the source file where this spec is defined
|
60
|
-
#
|
61
|
-
# @return [Integer] The line number
|
62
|
-
#
|
63
|
-
attr_reader :line_number
|
64
|
-
|
65
|
-
#
|
66
|
-
# The expectations to test for this spec
|
67
|
-
#
|
68
|
-
# @return [Array<Expectation>] The expectations
|
69
|
-
#
|
70
|
-
attr_accessor :expectations
|
71
|
-
|
72
26
|
#
|
73
27
|
# Creates a new spec instance
|
74
28
|
#
|
@@ -78,18 +32,18 @@ module SpecForge
|
|
78
32
|
# @param file_name [String] Base name of file
|
79
33
|
# @param debug [Boolean] Whether to enable debugging
|
80
34
|
# @param line_number [Integer] Line number in source
|
35
|
+
# @param documentation [Boolean] Whether to include in documentation generation
|
81
36
|
# @param expectations [Array<Hash>] Expectation configurations
|
82
37
|
#
|
83
38
|
# @return [Spec] A new spec instance
|
84
39
|
#
|
85
|
-
def initialize(
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
@expectations = expectations.map { |e| Expectation.new(**e) }
|
40
|
+
def initialize(
|
41
|
+
id:, name:, file_path:, file_name:, line_number:,
|
42
|
+
debug:, documentation:, expectations:
|
43
|
+
)
|
44
|
+
expectations = expectations.map { |e| Expectation.new(**e) }
|
45
|
+
|
46
|
+
super
|
93
47
|
end
|
94
48
|
|
95
49
|
#
|
@@ -104,6 +58,7 @@ module SpecForge
|
|
104
58
|
file_name:,
|
105
59
|
debug:,
|
106
60
|
line_number:,
|
61
|
+
documentation:,
|
107
62
|
expectations: expectations.map(&:to_h)
|
108
63
|
}
|
109
64
|
end
|
data/lib/spec_forge/version.rb
CHANGED
data/lib/spec_forge.rb
CHANGED
@@ -5,15 +5,19 @@ require "logger"
|
|
5
5
|
require "active_support"
|
6
6
|
require "active_support/core_ext"
|
7
7
|
require "commander"
|
8
|
-
require "everythingrb"
|
8
|
+
require "everythingrb/prelude"
|
9
|
+
require "everythingrb/all"
|
9
10
|
require "factory_bot"
|
10
11
|
require "faker"
|
11
12
|
require "faraday"
|
12
13
|
require "mime/types"
|
14
|
+
require "openapi3_parser"
|
13
15
|
require "pathname"
|
14
16
|
require "rspec"
|
17
|
+
require "sem_version"
|
15
18
|
require "singleton"
|
16
19
|
require "thor"
|
20
|
+
require "webrick"
|
17
21
|
require "yaml"
|
18
22
|
|
19
23
|
#
|
@@ -57,28 +61,8 @@ module SpecForge
|
|
57
61
|
# @param expectation_name [String, nil] Optional name of expectation to run
|
58
62
|
#
|
59
63
|
def run(file_name: nil, spec_name: nil, expectation_name: nil)
|
60
|
-
|
61
|
-
|
62
|
-
require_relative forge_helper if File.exist?(forge_helper)
|
63
|
-
|
64
|
-
# Validate in case anything was changed
|
65
|
-
configuration.validate
|
66
|
-
|
67
|
-
# Load factories
|
68
|
-
Factory.load_and_register
|
69
|
-
|
70
|
-
# Load the specs from their files and create forges from them
|
71
|
-
forges = Loader.load_from_files.map { |f| Forge.new(*f) }
|
72
|
-
|
73
|
-
# Filter out the specs and expectations
|
74
|
-
forges = Filter.apply(forges, file_name:, spec_name:, expectation_name:)
|
75
|
-
|
76
|
-
# Tell the user that we filtered if we did
|
77
|
-
Filter.announce(forges, file_name:, spec_name:, expectation_name:)
|
78
|
-
|
79
|
-
# Define and run everything
|
80
|
-
Runner.define(forges)
|
81
|
-
Runner.run
|
64
|
+
forges = Runner.prepare(file_name:, spec_name:, expectation_name:)
|
65
|
+
Runner.run(forges, exit_on_finish: true)
|
82
66
|
end
|
83
67
|
|
84
68
|
#
|
@@ -99,6 +83,15 @@ module SpecForge
|
|
99
83
|
@forge_path ||= root.join("spec_forge")
|
100
84
|
end
|
101
85
|
|
86
|
+
#
|
87
|
+
# Returns SpecForge's openapi directory
|
88
|
+
#
|
89
|
+
# @return [Pathname] The spec_forge openapi directory path
|
90
|
+
#
|
91
|
+
def openapi_path
|
92
|
+
@openapi_path ||= forge_path.join("openapi")
|
93
|
+
end
|
94
|
+
|
102
95
|
#
|
103
96
|
# Returns SpecForge's configuration
|
104
97
|
#
|
@@ -168,6 +161,19 @@ module SpecForge
|
|
168
161
|
def register_callback(name, &)
|
169
162
|
Callbacks.register(name, &)
|
170
163
|
end
|
164
|
+
|
165
|
+
#
|
166
|
+
# Generates a unique ID for an object based on hash and object_id
|
167
|
+
#
|
168
|
+
# @param object [Object] The object to generate an ID for
|
169
|
+
#
|
170
|
+
# @return [String] A unique ID string
|
171
|
+
#
|
172
|
+
# @private
|
173
|
+
#
|
174
|
+
def generate_id(object)
|
175
|
+
"#{object.hash.abs.to_s(36)}_#{object.object_id.to_s(36)}"
|
176
|
+
end
|
171
177
|
end
|
172
178
|
end
|
173
179
|
|
@@ -178,6 +184,7 @@ require_relative "spec_forge/cli"
|
|
178
184
|
require_relative "spec_forge/configuration"
|
179
185
|
require_relative "spec_forge/context"
|
180
186
|
require_relative "spec_forge/core_ext"
|
187
|
+
require_relative "spec_forge/documentation"
|
181
188
|
require_relative "spec_forge/error"
|
182
189
|
require_relative "spec_forge/factory"
|
183
190
|
require_relative "spec_forge/filter"
|
@@ -0,0 +1,22 @@
|
|
1
|
+
info:
|
2
|
+
title: My API
|
3
|
+
version: 1.0.0
|
4
|
+
description: A description of My API
|
5
|
+
contact:
|
6
|
+
name: My API Team
|
7
|
+
email: api@example.com
|
8
|
+
license:
|
9
|
+
name: MIT
|
10
|
+
url: https://opensource.org/licenses/MIT
|
11
|
+
|
12
|
+
# servers:
|
13
|
+
# - url: https://api.example.com/v1
|
14
|
+
# description: Production
|
15
|
+
# - url: https://staging-api.example.com/v1
|
16
|
+
# description: Staging
|
17
|
+
#
|
18
|
+
# tags:
|
19
|
+
# - name: users
|
20
|
+
# description: User account management
|
21
|
+
# - name: posts
|
22
|
+
# description: Blog post management
|
@@ -0,0 +1,28 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
|
4
|
+
<head>
|
5
|
+
<title>Redoc</title>
|
6
|
+
<!-- needed for adaptive design -->
|
7
|
+
<meta charset="utf-8" />
|
8
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
9
|
+
<link href="https://fonts.googleapis.com/css?family=Montserrat:300,400,700|Roboto:300,400,700" rel="stylesheet">
|
10
|
+
|
11
|
+
<!--
|
12
|
+
Redoc doesn't change outer page styles
|
13
|
+
-->
|
14
|
+
<style>
|
15
|
+
body {
|
16
|
+
margin: 0;
|
17
|
+
padding: 0;
|
18
|
+
}
|
19
|
+
</style>
|
20
|
+
</head>
|
21
|
+
|
22
|
+
<body>
|
23
|
+
<redoc spec-url="<%= spec_url %>"></redoc>
|
24
|
+
<script src=" https://cdn.redoc.ly/redoc/latest/bundles/redoc.standalone.js">
|
25
|
+
</script>
|
26
|
+
</body>
|
27
|
+
|
28
|
+
</html>
|
@@ -0,0 +1,59 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html lang="en">
|
3
|
+
|
4
|
+
<head>
|
5
|
+
<meta charset="UTF-8">
|
6
|
+
<title>Swagger UI</title>
|
7
|
+
<style>
|
8
|
+
html {
|
9
|
+
box-sizing: border-box;
|
10
|
+
overflow: -moz-scrollbars-vertical;
|
11
|
+
overflow-y: scroll;
|
12
|
+
}
|
13
|
+
|
14
|
+
*,
|
15
|
+
*:before,
|
16
|
+
*:after {
|
17
|
+
box-sizing: inherit;
|
18
|
+
}
|
19
|
+
|
20
|
+
body {
|
21
|
+
margin: 0;
|
22
|
+
background: #fafafa;
|
23
|
+
}
|
24
|
+
</style>
|
25
|
+
|
26
|
+
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/swagger-ui/5.24.0/swagger-ui.min.css"
|
27
|
+
integrity="sha512-wWpxfn2bFvPwxuqDyiJbVB0WR3ffSqJNMMryNP07frPJ1h5Xg9HIDMV1wRr1rpxT5E+KTxDrKTuWfGb1RcV8SA=="
|
28
|
+
crossorigin="anonymous" referrerpolicy="no-referrer" />
|
29
|
+
</head>
|
30
|
+
|
31
|
+
<body>
|
32
|
+
<div id="swagger-ui"></div>
|
33
|
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/swagger-ui/5.24.0/swagger-ui-bundle.min.js"
|
34
|
+
integrity="sha512-nEy/zRjIvuFMSr5ljsQUaUW4l7DoSHz8+SRybclmCjCh3MeF9UaooWYdr/SqjGCiyi4RIvBvn9DxCCV0ZDhiNA=="
|
35
|
+
crossorigin="anonymous" referrerpolicy="no-referrer"></script>
|
36
|
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/swagger-ui/5.24.0/swagger-ui-standalone-preset.min.js"
|
37
|
+
integrity="sha512-yJlD9FXQ7YaxAKXhviHSt/0KqWDCkLFdCnk0Ti23HXDMEQtHLAAWMHZ+POglC1mx/MOUB//h8kci3U1JYrywpQ=="
|
38
|
+
crossorigin="anonymous" referrerpolicy="no-referrer"></script>
|
39
|
+
|
40
|
+
<script>
|
41
|
+
window.onload = function () {
|
42
|
+
const ui = SwaggerUIBundle({
|
43
|
+
url: "<%= spec_url %>",
|
44
|
+
dom_id: "#swagger-ui",
|
45
|
+
deepLinking: true,
|
46
|
+
presets: [
|
47
|
+
SwaggerUIBundle.presets.apis,
|
48
|
+
SwaggerUIStandalonePreset
|
49
|
+
],
|
50
|
+
plugins: [
|
51
|
+
SwaggerUIBundle.plugins.DownloadUrl
|
52
|
+
],
|
53
|
+
layout: "StandaloneLayout"
|
54
|
+
});
|
55
|
+
};
|
56
|
+
</script>
|
57
|
+
</body>
|
58
|
+
|
59
|
+
</html>
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: spec_forge
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.7.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Bryan
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2025-
|
11
|
+
date: 2025-06-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -44,14 +44,14 @@ dependencies:
|
|
44
44
|
requirements:
|
45
45
|
- - "~>"
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version: '0.
|
47
|
+
version: '0.8'
|
48
48
|
type: :runtime
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
52
|
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version: '0.
|
54
|
+
version: '0.8'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: factory_bot
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -108,6 +108,20 @@ dependencies:
|
|
108
108
|
- - "~>"
|
109
109
|
- !ruby/object:Gem::Version
|
110
110
|
version: '3.6'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: openapi3_parser
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - "~>"
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: 0.10.1
|
118
|
+
type: :runtime
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - "~>"
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: 0.10.1
|
111
125
|
- !ruby/object:Gem::Dependency
|
112
126
|
name: rspec
|
113
127
|
requirement: !ruby/object:Gem::Requirement
|
@@ -122,6 +136,20 @@ dependencies:
|
|
122
136
|
- - "~>"
|
123
137
|
- !ruby/object:Gem::Version
|
124
138
|
version: '3.13'
|
139
|
+
- !ruby/object:Gem::Dependency
|
140
|
+
name: sem_version
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - "~>"
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: '2.0'
|
146
|
+
type: :runtime
|
147
|
+
prerelease: false
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
149
|
+
requirements:
|
150
|
+
- - "~>"
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: '2.0'
|
125
153
|
- !ruby/object:Gem::Dependency
|
126
154
|
name: thor
|
127
155
|
requirement: !ruby/object:Gem::Requirement
|
@@ -136,6 +164,20 @@ dependencies:
|
|
136
164
|
- - "~>"
|
137
165
|
- !ruby/object:Gem::Version
|
138
166
|
version: '1.3'
|
167
|
+
- !ruby/object:Gem::Dependency
|
168
|
+
name: webrick
|
169
|
+
requirement: !ruby/object:Gem::Requirement
|
170
|
+
requirements:
|
171
|
+
- - "~>"
|
172
|
+
- !ruby/object:Gem::Version
|
173
|
+
version: '1.9'
|
174
|
+
type: :runtime
|
175
|
+
prerelease: false
|
176
|
+
version_requirements: !ruby/object:Gem::Requirement
|
177
|
+
requirements:
|
178
|
+
- - "~>"
|
179
|
+
- !ruby/object:Gem::Version
|
180
|
+
version: '1.9'
|
139
181
|
description: Write API tests in YAML without sacrificing power. SpecForge combines
|
140
182
|
RSpec's matcher system, Faker's data generation, and factory patterns into a clean,
|
141
183
|
declarative syntax that eliminates boilerplate while preserving control over your
|
@@ -179,9 +221,12 @@ files:
|
|
179
221
|
- lib/spec_forge/cli.rb
|
180
222
|
- lib/spec_forge/cli/actions.rb
|
181
223
|
- lib/spec_forge/cli/command.rb
|
224
|
+
- lib/spec_forge/cli/docs.rb
|
225
|
+
- lib/spec_forge/cli/docs/generate.rb
|
182
226
|
- lib/spec_forge/cli/init.rb
|
183
227
|
- lib/spec_forge/cli/new.rb
|
184
228
|
- lib/spec_forge/cli/run.rb
|
229
|
+
- lib/spec_forge/cli/serve.rb
|
185
230
|
- lib/spec_forge/configuration.rb
|
186
231
|
- lib/spec_forge/context.rb
|
187
232
|
- lib/spec_forge/context/callbacks.rb
|
@@ -189,7 +234,32 @@ files:
|
|
189
234
|
- lib/spec_forge/context/store.rb
|
190
235
|
- lib/spec_forge/context/variables.rb
|
191
236
|
- lib/spec_forge/core_ext.rb
|
237
|
+
- lib/spec_forge/core_ext/array.rb
|
192
238
|
- lib/spec_forge/core_ext/rspec.rb
|
239
|
+
- lib/spec_forge/documentation.rb
|
240
|
+
- lib/spec_forge/documentation/builder.rb
|
241
|
+
- lib/spec_forge/documentation/document.rb
|
242
|
+
- lib/spec_forge/documentation/document/operation.rb
|
243
|
+
- lib/spec_forge/documentation/document/parameter.rb
|
244
|
+
- lib/spec_forge/documentation/document/request_body.rb
|
245
|
+
- lib/spec_forge/documentation/document/response.rb
|
246
|
+
- lib/spec_forge/documentation/document/response_body.rb
|
247
|
+
- lib/spec_forge/documentation/generators.rb
|
248
|
+
- lib/spec_forge/documentation/generators/base.rb
|
249
|
+
- lib/spec_forge/documentation/generators/openapi.rb
|
250
|
+
- lib/spec_forge/documentation/generators/openapi/base.rb
|
251
|
+
- lib/spec_forge/documentation/generators/openapi/error_formatter.rb
|
252
|
+
- lib/spec_forge/documentation/generators/openapi/v3_0.rb
|
253
|
+
- lib/spec_forge/documentation/loader.rb
|
254
|
+
- lib/spec_forge/documentation/loader/cache.rb
|
255
|
+
- lib/spec_forge/documentation/openapi.rb
|
256
|
+
- lib/spec_forge/documentation/openapi/base.rb
|
257
|
+
- lib/spec_forge/documentation/openapi/v3_0/example.rb
|
258
|
+
- lib/spec_forge/documentation/openapi/v3_0/media_type.rb
|
259
|
+
- lib/spec_forge/documentation/openapi/v3_0/operation.rb
|
260
|
+
- lib/spec_forge/documentation/openapi/v3_0/response.rb
|
261
|
+
- lib/spec_forge/documentation/openapi/v3_0/schema.rb
|
262
|
+
- lib/spec_forge/documentation/openapi/v3_0/tag.rb
|
193
263
|
- lib/spec_forge/error.rb
|
194
264
|
- lib/spec_forge/factory.rb
|
195
265
|
- lib/spec_forge/filter.rb
|
@@ -202,14 +272,19 @@ files:
|
|
202
272
|
- lib/spec_forge/loader.rb
|
203
273
|
- lib/spec_forge/matchers.rb
|
204
274
|
- lib/spec_forge/normalizer.rb
|
205
|
-
- lib/spec_forge/normalizer/
|
206
|
-
- lib/spec_forge/normalizer/
|
207
|
-
- lib/spec_forge/normalizer/
|
208
|
-
- lib/spec_forge/
|
209
|
-
- lib/spec_forge/
|
210
|
-
- lib/spec_forge/
|
211
|
-
- lib/spec_forge/
|
275
|
+
- lib/spec_forge/normalizer/default.rb
|
276
|
+
- lib/spec_forge/normalizer/definition.rb
|
277
|
+
- lib/spec_forge/normalizer/validators.rb
|
278
|
+
- lib/spec_forge/normalizers/_shared.yml
|
279
|
+
- lib/spec_forge/normalizers/configuration.yml
|
280
|
+
- lib/spec_forge/normalizers/constraint.yml
|
281
|
+
- lib/spec_forge/normalizers/expectation.yml
|
282
|
+
- lib/spec_forge/normalizers/factory.yml
|
283
|
+
- lib/spec_forge/normalizers/factory_reference.yml
|
284
|
+
- lib/spec_forge/normalizers/global_context.yml
|
285
|
+
- lib/spec_forge/normalizers/spec.yml
|
212
286
|
- lib/spec_forge/runner.rb
|
287
|
+
- lib/spec_forge/runner/adapter.rb
|
213
288
|
- lib/spec_forge/runner/callbacks.rb
|
214
289
|
- lib/spec_forge/runner/debug_proxy.rb
|
215
290
|
- lib/spec_forge/runner/listener.rb
|
@@ -220,9 +295,12 @@ files:
|
|
220
295
|
- lib/spec_forge/spec/expectation/constraint.rb
|
221
296
|
- lib/spec_forge/type.rb
|
222
297
|
- lib/spec_forge/version.rb
|
223
|
-
- lib/templates/forge_helper.tt
|
224
|
-
- lib/templates/new_factory.tt
|
225
|
-
- lib/templates/new_spec.tt
|
298
|
+
- lib/templates/forge_helper.rb.tt
|
299
|
+
- lib/templates/new_factory.yml.tt
|
300
|
+
- lib/templates/new_spec.yml.tt
|
301
|
+
- lib/templates/openapi.yml.tt
|
302
|
+
- lib/templates/redoc.html.tt
|
303
|
+
- lib/templates/swagger.html.tt
|
226
304
|
homepage: https://github.com/itsthedevman/spec_forge
|
227
305
|
licenses:
|
228
306
|
- MIT
|
@@ -1,90 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module SpecForge
|
4
|
-
class Normalizer
|
5
|
-
#
|
6
|
-
# Normalizes configuration hash structure for SpecForge
|
7
|
-
#
|
8
|
-
# Ensures that the global configuration has the correct structure
|
9
|
-
# and default values for all required settings.
|
10
|
-
#
|
11
|
-
class Configuration < Normalizer
|
12
|
-
#
|
13
|
-
# Defines the normalized structure for configuration validation
|
14
|
-
#
|
15
|
-
# Specifies validation rules for configuration attributes:
|
16
|
-
# - Enforces specific data types
|
17
|
-
# - Provides default values
|
18
|
-
# - Supports alternative key names
|
19
|
-
#
|
20
|
-
# @return [Hash] Configuration attribute validation rules
|
21
|
-
#
|
22
|
-
STRUCTURE = {
|
23
|
-
base_url: SHARED_ATTRIBUTES[:base_url].except(:default), # Make it required
|
24
|
-
headers: SHARED_ATTRIBUTES[:headers],
|
25
|
-
query: SHARED_ATTRIBUTES[:query],
|
26
|
-
factories: {
|
27
|
-
type: Hash,
|
28
|
-
default: {},
|
29
|
-
structure: {
|
30
|
-
auto_discover: {
|
31
|
-
type: [TrueClass, FalseClass],
|
32
|
-
default: true
|
33
|
-
},
|
34
|
-
paths: {
|
35
|
-
type: Array,
|
36
|
-
default: []
|
37
|
-
}
|
38
|
-
}
|
39
|
-
},
|
40
|
-
on_debug: {
|
41
|
-
type: Proc
|
42
|
-
}
|
43
|
-
}.freeze
|
44
|
-
end
|
45
|
-
|
46
|
-
# On Normalizer
|
47
|
-
class << self
|
48
|
-
#
|
49
|
-
# Generates an empty configuration hash
|
50
|
-
#
|
51
|
-
# @return [Hash] Default configuration hash
|
52
|
-
#
|
53
|
-
def default_configuration
|
54
|
-
Configuration.default
|
55
|
-
end
|
56
|
-
|
57
|
-
#
|
58
|
-
# Normalizes a configuration hash with validation
|
59
|
-
#
|
60
|
-
# @param input [Hash] The hash to normalize
|
61
|
-
#
|
62
|
-
# @return [Hash] A normalized hash with defaults applied
|
63
|
-
#
|
64
|
-
# @raise [Error::InvalidStructureError] If validation fails
|
65
|
-
#
|
66
|
-
def normalize_configuration!(input)
|
67
|
-
raise_errors! do
|
68
|
-
normalize_configuration(input)
|
69
|
-
end
|
70
|
-
end
|
71
|
-
|
72
|
-
#
|
73
|
-
# Normalize a configuration hash
|
74
|
-
#
|
75
|
-
# @param configuration [Hash] Configuration hash
|
76
|
-
#
|
77
|
-
# @return [Array] [normalized_hash, errors]
|
78
|
-
#
|
79
|
-
# @private
|
80
|
-
#
|
81
|
-
def normalize_configuration(configuration)
|
82
|
-
if !Type.hash?(configuration)
|
83
|
-
raise Error::InvalidTypeError.new(configuration, Hash, for: "configuration")
|
84
|
-
end
|
85
|
-
|
86
|
-
Normalizer::Configuration.new("configuration", configuration).normalize
|
87
|
-
end
|
88
|
-
end
|
89
|
-
end
|
90
|
-
end
|