spec_forge 0.5.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.
Files changed (116) hide show
  1. checksums.yaml +4 -4
  2. data/.standard.yml +3 -3
  3. data/CHANGELOG.md +217 -2
  4. data/README.md +162 -25
  5. data/flake.lock +3 -3
  6. data/flake.nix +11 -5
  7. data/lib/spec_forge/attribute/chainable.rb +208 -20
  8. data/lib/spec_forge/attribute/factory.rb +92 -15
  9. data/lib/spec_forge/attribute/faker.rb +62 -13
  10. data/lib/spec_forge/attribute/global.rb +96 -0
  11. data/lib/spec_forge/attribute/literal.rb +15 -2
  12. data/lib/spec_forge/attribute/matcher.rb +186 -11
  13. data/lib/spec_forge/attribute/parameterized.rb +45 -12
  14. data/lib/spec_forge/attribute/regex.rb +55 -5
  15. data/lib/spec_forge/attribute/resolvable.rb +48 -5
  16. data/lib/spec_forge/attribute/resolvable_array.rb +62 -4
  17. data/lib/spec_forge/attribute/resolvable_hash.rb +62 -4
  18. data/lib/spec_forge/attribute/store.rb +65 -0
  19. data/lib/spec_forge/attribute/transform.rb +33 -5
  20. data/lib/spec_forge/attribute/variable.rb +37 -6
  21. data/lib/spec_forge/attribute.rb +166 -66
  22. data/lib/spec_forge/backtrace_formatter.rb +26 -3
  23. data/lib/spec_forge/callbacks.rb +88 -0
  24. data/lib/spec_forge/cli/actions.rb +27 -0
  25. data/lib/spec_forge/cli/command.rb +78 -24
  26. data/lib/spec_forge/cli/docs/generate.rb +72 -0
  27. data/lib/spec_forge/cli/docs.rb +92 -0
  28. data/lib/spec_forge/cli/init.rb +51 -9
  29. data/lib/spec_forge/cli/new.rb +67 -6
  30. data/lib/spec_forge/cli/run.rb +32 -4
  31. data/lib/spec_forge/cli/serve.rb +155 -0
  32. data/lib/spec_forge/cli.rb +26 -7
  33. data/lib/spec_forge/configuration.rb +96 -24
  34. data/lib/spec_forge/context/callbacks.rb +91 -0
  35. data/lib/spec_forge/context/global.rb +72 -0
  36. data/lib/spec_forge/context/store.rb +131 -0
  37. data/lib/spec_forge/context/variables.rb +91 -0
  38. data/lib/spec_forge/context.rb +36 -0
  39. data/lib/spec_forge/core_ext/array.rb +27 -0
  40. data/lib/spec_forge/core_ext/rspec.rb +22 -4
  41. data/lib/spec_forge/documentation/builder.rb +383 -0
  42. data/lib/spec_forge/documentation/document/operation.rb +47 -0
  43. data/lib/spec_forge/documentation/document/parameter.rb +22 -0
  44. data/lib/spec_forge/documentation/document/request_body.rb +24 -0
  45. data/lib/spec_forge/documentation/document/response.rb +39 -0
  46. data/lib/spec_forge/documentation/document/response_body.rb +27 -0
  47. data/lib/spec_forge/documentation/document.rb +48 -0
  48. data/lib/spec_forge/documentation/generators/base.rb +81 -0
  49. data/lib/spec_forge/documentation/generators/openapi/base.rb +100 -0
  50. data/lib/spec_forge/documentation/generators/openapi/error_formatter.rb +149 -0
  51. data/lib/spec_forge/documentation/generators/openapi/v3_0.rb +65 -0
  52. data/lib/spec_forge/documentation/generators/openapi.rb +59 -0
  53. data/lib/spec_forge/documentation/generators.rb +17 -0
  54. data/lib/spec_forge/documentation/loader/cache.rb +138 -0
  55. data/lib/spec_forge/documentation/loader.rb +159 -0
  56. data/lib/spec_forge/documentation/openapi/base.rb +33 -0
  57. data/lib/spec_forge/documentation/openapi/v3_0/example.rb +44 -0
  58. data/lib/spec_forge/documentation/openapi/v3_0/media_type.rb +42 -0
  59. data/lib/spec_forge/documentation/openapi/v3_0/operation.rb +175 -0
  60. data/lib/spec_forge/documentation/openapi/v3_0/response.rb +65 -0
  61. data/lib/spec_forge/documentation/openapi/v3_0/schema.rb +80 -0
  62. data/lib/spec_forge/documentation/openapi/v3_0/tag.rb +71 -0
  63. data/lib/spec_forge/documentation/openapi.rb +23 -0
  64. data/lib/spec_forge/documentation.rb +27 -0
  65. data/lib/spec_forge/error.rb +284 -113
  66. data/lib/spec_forge/factory.rb +35 -16
  67. data/lib/spec_forge/filter.rb +86 -0
  68. data/lib/spec_forge/forge.rb +171 -0
  69. data/lib/spec_forge/http/backend.rb +101 -29
  70. data/lib/spec_forge/http/client.rb +23 -13
  71. data/lib/spec_forge/http/request.rb +85 -62
  72. data/lib/spec_forge/http/verb.rb +79 -0
  73. data/lib/spec_forge/http.rb +105 -0
  74. data/lib/spec_forge/loader.rb +244 -0
  75. data/lib/spec_forge/matchers.rb +130 -0
  76. data/lib/spec_forge/normalizer/default.rb +51 -0
  77. data/lib/spec_forge/normalizer/definition.rb +248 -0
  78. data/lib/spec_forge/normalizer/validators.rb +99 -0
  79. data/lib/spec_forge/normalizer.rb +486 -115
  80. data/lib/spec_forge/normalizers/_shared.yml +74 -0
  81. data/lib/spec_forge/normalizers/configuration.yml +23 -0
  82. data/lib/spec_forge/normalizers/constraint.yml +8 -0
  83. data/lib/spec_forge/normalizers/expectation.yml +47 -0
  84. data/lib/spec_forge/normalizers/factory.yml +12 -0
  85. data/lib/spec_forge/normalizers/factory_reference.yml +15 -0
  86. data/lib/spec_forge/normalizers/global_context.yml +28 -0
  87. data/lib/spec_forge/normalizers/spec.yml +50 -0
  88. data/lib/spec_forge/runner/adapter.rb +183 -0
  89. data/lib/spec_forge/runner/callbacks.rb +246 -0
  90. data/lib/spec_forge/runner/debug_proxy.rb +213 -0
  91. data/lib/spec_forge/runner/listener.rb +54 -0
  92. data/lib/spec_forge/runner/metadata.rb +58 -0
  93. data/lib/spec_forge/runner/state.rb +98 -0
  94. data/lib/spec_forge/runner.rb +50 -125
  95. data/lib/spec_forge/spec/expectation/constraint.rb +100 -21
  96. data/lib/spec_forge/spec/expectation.rb +47 -51
  97. data/lib/spec_forge/spec.rb +50 -108
  98. data/lib/spec_forge/type.rb +36 -4
  99. data/lib/spec_forge/version.rb +4 -1
  100. data/lib/spec_forge.rb +168 -76
  101. data/lib/templates/openapi.yml.tt +22 -0
  102. data/lib/templates/redoc.html.tt +28 -0
  103. data/lib/templates/swagger.html.tt +59 -0
  104. metadata +109 -16
  105. data/lib/spec_forge/normalizer/configuration.rb +0 -77
  106. data/lib/spec_forge/normalizer/constraint.rb +0 -47
  107. data/lib/spec_forge/normalizer/expectation.rb +0 -86
  108. data/lib/spec_forge/normalizer/factory.rb +0 -65
  109. data/lib/spec_forge/normalizer/factory_reference.rb +0 -71
  110. data/lib/spec_forge/normalizer/spec.rb +0 -74
  111. data/spec_forge/factories/user.yml +0 -4
  112. data/spec_forge/forge_helper.rb +0 -48
  113. data/spec_forge/specs/users.yml +0 -65
  114. /data/lib/templates/{forge_helper.tt → forge_helper.rb.tt} +0 -0
  115. /data/lib/templates/{new_factory.tt → new_factory.yml.tt} +0 -0
  116. /data/lib/templates/{new_spec.tt → new_spec.yml.tt} +0 -0
data/lib/spec_forge.rb CHANGED
@@ -5,103 +5,195 @@ 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
- require_relative "spec_forge/attribute"
20
- require_relative "spec_forge/backtrace_formatter"
21
- require_relative "spec_forge/cli"
22
- require_relative "spec_forge/configuration"
23
- require_relative "spec_forge/core_ext"
24
- require_relative "spec_forge/error"
25
- require_relative "spec_forge/factory"
26
- require_relative "spec_forge/http"
27
- require_relative "spec_forge/normalizer"
28
- require_relative "spec_forge/runner"
29
- require_relative "spec_forge/spec"
30
- require_relative "spec_forge/type"
31
- require_relative "spec_forge/version"
32
-
23
+ #
24
+ # SpecForge: Write expressive API tests in YAML with the power of RSpec matchers
25
+ #
26
+ # SpecForge is a testing framework that allows writing API tests in a YAML format
27
+ # that reads like documentation. It combines the readability of YAML with the
28
+ # power of RSpec matchers, Faker data generation, and FactoryBot test objects.
29
+ #
30
+ # @example Basic spec in YAML
31
+ # get_user:
32
+ # path: /users/1
33
+ # expectations:
34
+ # - expect:
35
+ # status: 200
36
+ # json:
37
+ # name: kind_of.string
38
+ # email: /@/
39
+ #
40
+ # @example Running specs
41
+ # # Run all specs
42
+ # SpecForge.run
43
+ #
44
+ # # Run specific file
45
+ # SpecForge.run(file_name: "users")
46
+ #
47
+ # # Run specific spec
48
+ # SpecForge.run(file_name: "users", spec_name: "create_user")
49
+ #
33
50
  module SpecForge
34
- #
35
- # Loads all factories and specs located in "path", then runs all of the specs
36
- #
37
- # @param path [String] The file path that contains factories and specs
38
- #
39
- def self.run(file_name: nil, spec_name: nil, expectation_name: nil)
40
- path = SpecForge.forge
51
+ class << self
52
+ #
53
+ # Loads all factories and specs and runs the tests with optional filtering
54
+ #
55
+ # This is the main entry point for running SpecForge tests. It loads the
56
+ # forge_helper.rb file if it exists, configures the environment, loads
57
+ # factories and specs, and runs the tests through RSpec.
58
+ #
59
+ # @param file_name [String, nil] Optional name of spec file to run
60
+ # @param spec_name [String, nil] Optional name of spec to run
61
+ # @param expectation_name [String, nil] Optional name of expectation to run
62
+ #
63
+ def run(file_name: nil, spec_name: nil, expectation_name: nil)
64
+ forges = Runner.prepare(file_name:, spec_name:, expectation_name:)
65
+ Runner.run(forges, exit_on_finish: true)
66
+ end
41
67
 
42
- # Initialize
43
- forge_helper = path.join("forge_helper.rb")
44
- require_relative forge_helper if File.exist?(forge_helper)
68
+ #
69
+ # Returns the directory root for the working directory
70
+ #
71
+ # @return [Pathname] The root directory path
72
+ #
73
+ def root
74
+ @root ||= Pathname.pwd
75
+ end
45
76
 
46
- # Validate
47
- configuration.validate
77
+ #
78
+ # Returns SpecForge's working directory
79
+ #
80
+ # @return [Pathname] The spec_forge directory path
81
+ #
82
+ def forge_path
83
+ @forge_path ||= root.join("spec_forge")
84
+ end
48
85
 
49
- # Prepare
50
- Factory.load_and_register
51
- Spec.load_and_define(file_name:, spec_name:, expectation_name:)
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
52
94
 
53
- # Run
54
- Runner.run
55
- end
95
+ #
96
+ # Returns SpecForge's configuration
97
+ #
98
+ # @return [Configuration] The current configuration
99
+ #
100
+ def configuration
101
+ @configuration ||= Configuration.new
102
+ end
56
103
 
57
- #
58
- # Returns the directory root for the working directory
59
- #
60
- # @return [Pathname]
61
- #
62
- def self.root
63
- @root ||= Pathname.pwd
64
- end
104
+ #
105
+ # Yields SpecForge's configuration to a block for modification
106
+ #
107
+ # @yield [config] Block that receives the configuration object
108
+ # @yieldparam config [Configuration] The configuration to modify
109
+ #
110
+ # @return [Configuration] The updated configuration
111
+ #
112
+ def configure(&block)
113
+ block&.call(configuration)
114
+ configuration
115
+ end
65
116
 
66
- #
67
- # Returns SpecForge's working directory
68
- #
69
- # @return [Pathname]
70
- #
71
- def self.forge
72
- @forge ||= root.join("spec_forge")
73
- end
117
+ #
118
+ # Returns a backtrace cleaner configured for SpecForge
119
+ #
120
+ # Creates and configures an ActiveSupport::BacktraceCleaner to improve
121
+ # error messages by removing unnecessary lines and root paths.
122
+ #
123
+ # @return [ActiveSupport::BacktraceCleaner] The configured backtrace cleaner
124
+ #
125
+ def backtrace_cleaner
126
+ @backtrace_cleaner ||= begin
127
+ root = "#{SpecForge.root}/"
74
128
 
75
- #
76
- # Returns SpecForge's configuration
77
- #
78
- # @return [Config]
79
- #
80
- def self.configuration
81
- @configuration ||= Configuration.new
82
- end
129
+ cleaner = ActiveSupport::BacktraceCleaner.new
130
+ cleaner.add_filter { |line| line.delete_prefix(root) }
131
+ cleaner.add_silencer { |line| /rubygems|backtrace_cleaner/.match?(line) }
132
+ cleaner
133
+ end
134
+ end
83
135
 
84
- #
85
- # Yields SpecForge's configuration to a block
86
- #
87
- def self.configure(&block)
88
- block&.call(configuration)
89
- configuration
90
- end
136
+ #
137
+ # Returns the current execution context
138
+ #
139
+ # @return [Context] The current context object
140
+ #
141
+ def context
142
+ @context ||= Context.new
143
+ end
91
144
 
92
- #
93
- # Returns a backtrace cleaner configured for SpecForge
94
- #
95
- # @return [ActiveSupport::BacktraceCleaner]
96
- #
97
- def self.backtrace_cleaner
98
- @backtrace_cleaner ||= begin
99
- root = "#{SpecForge.root}/"
145
+ #
146
+ # Registers a callback for a specific test lifecycle event
147
+ # Allows custom code execution at specific points during test execution
148
+ #
149
+ # @param name [Symbol, String] A unique identifier for this callback
150
+ # @yield A block to execute when the callback is triggered
151
+ # @yieldparam context [Object] An object containing context-specific state data, depending
152
+ # on which hook the callback is triggered from.
153
+ #
154
+ # @return [Proc] The registered callback
155
+ #
156
+ # @example Registering a custom debug handler
157
+ # SpecForge.register_callback(:clean_database) do |context|
158
+ # DatabaseCleaner.clean
159
+ # end
160
+ #
161
+ def register_callback(name, &)
162
+ Callbacks.register(name, &)
163
+ end
100
164
 
101
- cleaner = ActiveSupport::BacktraceCleaner.new
102
- cleaner.add_filter { |line| line.delete_prefix(root) }
103
- cleaner.add_silencer { |line| /rubygems|backtrace_cleaner/.match?(line) }
104
- cleaner
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)}"
105
176
  end
106
177
  end
107
178
  end
179
+
180
+ require_relative "spec_forge/attribute"
181
+ require_relative "spec_forge/backtrace_formatter"
182
+ require_relative "spec_forge/callbacks"
183
+ require_relative "spec_forge/cli"
184
+ require_relative "spec_forge/configuration"
185
+ require_relative "spec_forge/context"
186
+ require_relative "spec_forge/core_ext"
187
+ require_relative "spec_forge/documentation"
188
+ require_relative "spec_forge/error"
189
+ require_relative "spec_forge/factory"
190
+ require_relative "spec_forge/filter"
191
+ require_relative "spec_forge/forge"
192
+ require_relative "spec_forge/http"
193
+ require_relative "spec_forge/loader"
194
+ require_relative "spec_forge/matchers"
195
+ require_relative "spec_forge/normalizer"
196
+ require_relative "spec_forge/runner"
197
+ require_relative "spec_forge/spec"
198
+ require_relative "spec_forge/type"
199
+ require_relative "spec_forge/version"
@@ -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.5.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-02-28 00:00:00.000000000 Z
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.2'
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.2'
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
@@ -163,6 +205,7 @@ files:
163
205
  - lib/spec_forge/attribute/chainable.rb
164
206
  - lib/spec_forge/attribute/factory.rb
165
207
  - lib/spec_forge/attribute/faker.rb
208
+ - lib/spec_forge/attribute/global.rb
166
209
  - lib/spec_forge/attribute/literal.rb
167
210
  - lib/spec_forge/attribute/matcher.rb
168
211
  - lib/spec_forge/attribute/parameterized.rb
@@ -170,44 +213,94 @@ files:
170
213
  - lib/spec_forge/attribute/resolvable.rb
171
214
  - lib/spec_forge/attribute/resolvable_array.rb
172
215
  - lib/spec_forge/attribute/resolvable_hash.rb
216
+ - lib/spec_forge/attribute/store.rb
173
217
  - lib/spec_forge/attribute/transform.rb
174
218
  - lib/spec_forge/attribute/variable.rb
175
219
  - lib/spec_forge/backtrace_formatter.rb
220
+ - lib/spec_forge/callbacks.rb
176
221
  - lib/spec_forge/cli.rb
177
222
  - lib/spec_forge/cli/actions.rb
178
223
  - lib/spec_forge/cli/command.rb
224
+ - lib/spec_forge/cli/docs.rb
225
+ - lib/spec_forge/cli/docs/generate.rb
179
226
  - lib/spec_forge/cli/init.rb
180
227
  - lib/spec_forge/cli/new.rb
181
228
  - lib/spec_forge/cli/run.rb
229
+ - lib/spec_forge/cli/serve.rb
182
230
  - lib/spec_forge/configuration.rb
231
+ - lib/spec_forge/context.rb
232
+ - lib/spec_forge/context/callbacks.rb
233
+ - lib/spec_forge/context/global.rb
234
+ - lib/spec_forge/context/store.rb
235
+ - lib/spec_forge/context/variables.rb
183
236
  - lib/spec_forge/core_ext.rb
237
+ - lib/spec_forge/core_ext/array.rb
184
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
185
263
  - lib/spec_forge/error.rb
186
264
  - lib/spec_forge/factory.rb
265
+ - lib/spec_forge/filter.rb
266
+ - lib/spec_forge/forge.rb
187
267
  - lib/spec_forge/http.rb
188
268
  - lib/spec_forge/http/backend.rb
189
269
  - lib/spec_forge/http/client.rb
190
270
  - lib/spec_forge/http/request.rb
191
271
  - lib/spec_forge/http/verb.rb
272
+ - lib/spec_forge/loader.rb
273
+ - lib/spec_forge/matchers.rb
192
274
  - lib/spec_forge/normalizer.rb
193
- - lib/spec_forge/normalizer/configuration.rb
194
- - lib/spec_forge/normalizer/constraint.rb
195
- - lib/spec_forge/normalizer/expectation.rb
196
- - lib/spec_forge/normalizer/factory.rb
197
- - lib/spec_forge/normalizer/factory_reference.rb
198
- - lib/spec_forge/normalizer/spec.rb
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
199
286
  - lib/spec_forge/runner.rb
287
+ - lib/spec_forge/runner/adapter.rb
288
+ - lib/spec_forge/runner/callbacks.rb
289
+ - lib/spec_forge/runner/debug_proxy.rb
290
+ - lib/spec_forge/runner/listener.rb
291
+ - lib/spec_forge/runner/metadata.rb
292
+ - lib/spec_forge/runner/state.rb
200
293
  - lib/spec_forge/spec.rb
201
294
  - lib/spec_forge/spec/expectation.rb
202
295
  - lib/spec_forge/spec/expectation/constraint.rb
203
296
  - lib/spec_forge/type.rb
204
297
  - lib/spec_forge/version.rb
205
- - lib/templates/forge_helper.tt
206
- - lib/templates/new_factory.tt
207
- - lib/templates/new_spec.tt
208
- - spec_forge/factories/user.yml
209
- - spec_forge/forge_helper.rb
210
- - spec_forge/specs/users.yml
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
211
304
  homepage: https://github.com/itsthedevman/spec_forge
212
305
  licenses:
213
306
  - MIT
@@ -1,77 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module SpecForge
4
- class Normalizer
5
- class Configuration < Normalizer
6
- STRUCTURE = {
7
- base_url: SHARED_ATTRIBUTES[:base_url].except(:default), # Make it required
8
- headers: SHARED_ATTRIBUTES[:headers],
9
- query: SHARED_ATTRIBUTES[:query],
10
- factories: {
11
- type: Hash,
12
- default: {},
13
- structure: {
14
- auto_discover: {
15
- type: [TrueClass, FalseClass],
16
- default: true
17
- },
18
- paths: {
19
- type: Array,
20
- default: []
21
- }
22
- }
23
- },
24
- on_debug: {
25
- type: Proc
26
- }
27
- }.freeze
28
- end
29
-
30
- # On Normalizer
31
- class << self
32
- #
33
- # Generates an empty configuration hash
34
- #
35
- # @return [Hash]
36
- #
37
- def default_configuration
38
- Configuration.default
39
- end
40
-
41
- #
42
- # Normalizes a configuration hash by standardizing its keys while ensuring the required data
43
- # is provided or defaulted.
44
- # Raises InvalidStructureError if anything is missing/invalid type
45
- #
46
- # @param input [Hash] The hash to normalize
47
- #
48
- # @return [Hash] A normalized hash as a new instance
49
- #
50
- def normalize_configuration!(input)
51
- raise_errors! do
52
- normalize_configuration(input)
53
- end
54
- end
55
-
56
- #
57
- # Normalize a configuration hash
58
- # Used internally by .normalize_configuration!, but is available for utility
59
- #
60
- # @param configuration [Hash] Configuration representation as a Hash
61
- #
62
- # @return [Array] Two item array
63
- # First - The normalized hash
64
- # Second - Array of errors, if any
65
- #
66
- # @private
67
- #
68
- def normalize_configuration(configuration)
69
- if !Type.hash?(configuration)
70
- raise InvalidTypeError.new(configuration, Hash, for: "configuration")
71
- end
72
-
73
- Normalizer::Configuration.new("configuration", configuration).normalize
74
- end
75
- end
76
- end
77
- end