spec_forge 0.7.1 → 1.0.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 (133) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +75 -1
  3. data/README.md +124 -202
  4. data/bin/spec_forge +1 -1
  5. data/flake.lock +76 -4
  6. data/flake.nix +5 -4
  7. data/lib/spec_forge/attribute/chainable.rb +6 -6
  8. data/lib/spec_forge/attribute/environment.rb +45 -0
  9. data/lib/spec_forge/attribute/factory.rb +26 -17
  10. data/lib/spec_forge/attribute/faker.rb +6 -1
  11. data/lib/spec_forge/attribute/generate.rb +114 -0
  12. data/lib/spec_forge/attribute/literal.rb +1 -14
  13. data/lib/spec_forge/attribute/matcher.rb +6 -2
  14. data/lib/spec_forge/attribute/parameterized.rb +20 -22
  15. data/lib/spec_forge/attribute/resolvable_array.rb +16 -16
  16. data/lib/spec_forge/attribute/resolvable_hash.rb +17 -16
  17. data/lib/spec_forge/attribute/resolvable_struct.rb +67 -0
  18. data/lib/spec_forge/attribute/template.rb +118 -0
  19. data/lib/spec_forge/attribute/transform.rb +14 -19
  20. data/lib/spec_forge/attribute/variable.rb +31 -31
  21. data/lib/spec_forge/attribute.rb +54 -100
  22. data/lib/spec_forge/blueprint.rb +27 -0
  23. data/lib/spec_forge/cli/docs/generate.rb +28 -8
  24. data/lib/spec_forge/cli/docs.rb +5 -2
  25. data/lib/spec_forge/cli/init.rb +4 -4
  26. data/lib/spec_forge/cli/new.rb +78 -27
  27. data/lib/spec_forge/cli/run.rb +84 -52
  28. data/lib/spec_forge/cli/serve.rb +5 -0
  29. data/lib/spec_forge/cli.rb +6 -14
  30. data/lib/spec_forge/configuration.rb +209 -79
  31. data/lib/spec_forge/documentation/{loader → builder}/cache.rb +26 -23
  32. data/lib/spec_forge/documentation/builder/compiler.rb +373 -0
  33. data/lib/spec_forge/documentation/builder/extractor.rb +75 -0
  34. data/lib/spec_forge/documentation/builder.rb +77 -329
  35. data/lib/spec_forge/documentation/document/operation.rb +4 -4
  36. data/lib/spec_forge/documentation/document.rb +0 -6
  37. data/lib/spec_forge/documentation/generator.rb +88 -0
  38. data/lib/spec_forge/documentation/{generators/openapi → openapi/v3_0}/error_formatter.rb +2 -2
  39. data/lib/spec_forge/documentation/openapi/v3_0/example.rb +1 -1
  40. data/lib/spec_forge/documentation/openapi/v3_0/media_type.rb +1 -1
  41. data/lib/spec_forge/documentation/openapi/v3_0/operation.rb +21 -5
  42. data/lib/spec_forge/documentation/openapi/v3_0/response.rb +28 -6
  43. data/lib/spec_forge/documentation/openapi/v3_0/schema.rb +20 -2
  44. data/lib/spec_forge/documentation/openapi/v3_0/tag.rb +1 -1
  45. data/lib/spec_forge/documentation/openapi/v3_0.rb +116 -0
  46. data/lib/spec_forge/documentation/openapi.rb +40 -12
  47. data/lib/spec_forge/documentation.rb +1 -7
  48. data/lib/spec_forge/error.rb +215 -41
  49. data/lib/spec_forge/factory.rb +38 -18
  50. data/lib/spec_forge/forge/action.rb +41 -0
  51. data/lib/spec_forge/forge/actions/call.rb +33 -0
  52. data/lib/spec_forge/forge/actions/debug.rb +47 -0
  53. data/lib/spec_forge/forge/actions/expect.rb +44 -0
  54. data/lib/spec_forge/forge/actions/request.rb +65 -0
  55. data/lib/spec_forge/forge/actions/store.rb +31 -0
  56. data/lib/spec_forge/forge/callbacks.rb +80 -0
  57. data/lib/spec_forge/forge/context.rb +41 -0
  58. data/lib/spec_forge/forge/display.rb +503 -0
  59. data/lib/spec_forge/forge/hooks.rb +131 -0
  60. data/lib/spec_forge/forge/runner/array_io.rb +81 -0
  61. data/lib/spec_forge/forge/runner/content_validator.rb +92 -0
  62. data/lib/spec_forge/forge/runner/header_validator.rb +66 -0
  63. data/lib/spec_forge/forge/runner/reporter.rb +56 -0
  64. data/lib/spec_forge/forge/runner/schema_validator.rb +113 -0
  65. data/lib/spec_forge/forge/runner.rb +118 -0
  66. data/lib/spec_forge/forge/timer.rb +94 -0
  67. data/lib/spec_forge/forge/variables.rb +38 -0
  68. data/lib/spec_forge/forge.rb +207 -133
  69. data/lib/spec_forge/http/backend.rb +49 -146
  70. data/lib/spec_forge/http/client.rb +14 -17
  71. data/lib/spec_forge/http/request.rb +37 -84
  72. data/lib/spec_forge/http/verb.rb +4 -0
  73. data/lib/spec_forge/http.rb +0 -5
  74. data/lib/spec_forge/loader/filter.rb +85 -0
  75. data/lib/spec_forge/loader/step_processor.rb +282 -0
  76. data/lib/spec_forge/loader.rb +105 -220
  77. data/lib/spec_forge/normalizer/default.rb +1 -1
  78. data/lib/spec_forge/normalizer/structure.rb +140 -0
  79. data/lib/spec_forge/normalizer/transformers.rb +168 -0
  80. data/lib/spec_forge/normalizer/validators.rb +50 -8
  81. data/lib/spec_forge/normalizer.rb +76 -119
  82. data/lib/spec_forge/normalizers/callback.yml +38 -0
  83. data/lib/spec_forge/normalizers/configuration.yml +59 -9
  84. data/lib/spec_forge/normalizers/factory.yml +53 -2
  85. data/lib/spec_forge/normalizers/factory_reference.yml +63 -2
  86. data/lib/spec_forge/normalizers/json_schema.yml +79 -0
  87. data/lib/spec_forge/normalizers/step.yml +506 -0
  88. data/lib/spec_forge/step/call.rb +36 -0
  89. data/lib/spec_forge/step/expect.rb +110 -0
  90. data/lib/spec_forge/step/source.rb +22 -0
  91. data/lib/spec_forge/step.rb +129 -0
  92. data/lib/spec_forge/type.rb +115 -66
  93. data/lib/spec_forge/version.rb +1 -1
  94. data/lib/spec_forge.rb +44 -106
  95. data/lib/templates/forge_helper.rb.tt +43 -22
  96. data/lib/templates/new_blueprint.yml.tt +54 -0
  97. metadata +75 -44
  98. data/lib/spec_forge/attribute/global.rb +0 -96
  99. data/lib/spec_forge/attribute/store.rb +0 -65
  100. data/lib/spec_forge/backtrace_formatter.rb +0 -50
  101. data/lib/spec_forge/callbacks.rb +0 -88
  102. data/lib/spec_forge/context/callbacks.rb +0 -91
  103. data/lib/spec_forge/context/global.rb +0 -72
  104. data/lib/spec_forge/context/store.rb +0 -131
  105. data/lib/spec_forge/context/variables.rb +0 -91
  106. data/lib/spec_forge/context.rb +0 -36
  107. data/lib/spec_forge/core_ext/rspec.rb +0 -55
  108. data/lib/spec_forge/core_ext.rb +0 -5
  109. data/lib/spec_forge/documentation/generators/base.rb +0 -81
  110. data/lib/spec_forge/documentation/generators/openapi/base.rb +0 -100
  111. data/lib/spec_forge/documentation/generators/openapi/v3_0.rb +0 -65
  112. data/lib/spec_forge/documentation/generators/openapi.rb +0 -59
  113. data/lib/spec_forge/documentation/generators.rb +0 -17
  114. data/lib/spec_forge/documentation/loader.rb +0 -159
  115. data/lib/spec_forge/documentation/openapi/base.rb +0 -33
  116. data/lib/spec_forge/filter.rb +0 -86
  117. data/lib/spec_forge/normalizer/definition.rb +0 -248
  118. data/lib/spec_forge/normalizers/_shared.yml +0 -76
  119. data/lib/spec_forge/normalizers/constraint.yml +0 -8
  120. data/lib/spec_forge/normalizers/expectation.yml +0 -47
  121. data/lib/spec_forge/normalizers/global_context.yml +0 -28
  122. data/lib/spec_forge/normalizers/spec.yml +0 -50
  123. data/lib/spec_forge/runner/adapter.rb +0 -181
  124. data/lib/spec_forge/runner/callbacks.rb +0 -246
  125. data/lib/spec_forge/runner/debug_proxy.rb +0 -215
  126. data/lib/spec_forge/runner/listener.rb +0 -54
  127. data/lib/spec_forge/runner/metadata.rb +0 -58
  128. data/lib/spec_forge/runner/state.rb +0 -98
  129. data/lib/spec_forge/runner.rb +0 -75
  130. data/lib/spec_forge/spec/expectation/constraint.rb +0 -127
  131. data/lib/spec_forge/spec/expectation.rb +0 -68
  132. data/lib/spec_forge/spec.rb +0 -68
  133. data/lib/templates/new_spec.yml.tt +0 -43
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9891353d8acd7d64ec4b2690e4e91d68c0d455913b8ca81c7f9e410859f51774
4
- data.tar.gz: 7ff9aa712f7d21a75ae8a383175702ed8973b25e2935458bd75dd713f59b6fb3
3
+ metadata.gz: 2a63a7870c53ed507204c4848b271094c53a5be8d2925e7b04b359f6885b61cc
4
+ data.tar.gz: 12684cb3c690072fe1ead4c4ef5d4e9b2fb13d2e40f27c5eeea75fba9cdbff0e
5
5
  SHA512:
6
- metadata.gz: 0637e96a8739579015af17ee0a6c8442b51c9fd189b2a220b7828ae68f0784760aad4d5312eabf450f18ee7e6db2789dad3fb55327cee0aa19f3a8e9b88be243
7
- data.tar.gz: 3d10cc2cafb76d2d14b42e104fba62a5e8ec35d70cb92f6769e3fcde9611d9949d707fdc287caae52454e04d6542c507274e357bb38f41090792efa40e5d6436
6
+ metadata.gz: f656557492767c8f2391f334461ee4efbcad40118f7608b9d26ba6e5ee1492c3adddce4d76565a79b145b4d2f017de9f43aabbdfdf7e9e837fc71c77b54a4555
7
+ data.tar.gz: dbaf154a1d50d7399d7c25d5655ad9809185dd410de71d3f2b62809435dfdf75b1d0948ddcc848059c2ee0b7053fc31c148dac164c63636edf2b823c5562a963
data/CHANGELOG.md CHANGED
@@ -15,6 +15,79 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
15
15
  ### Removed
16
16
  -->
17
17
 
18
+ ## [1.0.0] - 12026-01-29
19
+
20
+ ### ⚠️ Breaking Changes
21
+
22
+ This release is a complete architectural redesign. See the [Migration Guide](https://github.com/itsthedevman/spec_forge/wiki/Migration-Guide) for detailed upgrade instructions.
23
+
24
+ **Core changes:**
25
+ - Directory renamed: `spec_forge/specs/` → `spec_forge/blueprints/`
26
+ - CLI renamed: `spec_forge new spec` → `spec_forge new blueprint`
27
+ - YAML structure rewritten from spec-based to sequential step-based workflows
28
+ - Variable syntax changed: `variables.name` → `{{ name }}` template syntax
29
+ - Execution architecture changed: Forge now orchestrates workflows and delegates validation to RSpec, replacing the previous fully RSpec-driven approach
30
+
31
+ **Configuration:**
32
+ - Removed: `config.headers`, `config.query` (use explicit inheritance instead)
33
+ - Changed: `config.specs` → `config.rspec`
34
+ - Changed: `config.on_debug = proc` → `config.on_debug { block }`
35
+
36
+ ### Added
37
+
38
+ - **Step-based workflows**: Tests execute as sequential steps with explicit data flow between them. See [Writing Tests](https://github.com/itsthedevman/spec_forge/wiki/Writing-Tests).
39
+
40
+ ```yaml
41
+ - name: "Create user"
42
+ request:
43
+ url: /users
44
+ http_verb: POST
45
+ json:
46
+ email: "{{ faker.internet.email }}"
47
+ expect:
48
+ - status: 201
49
+ store:
50
+ user_id: "{{ response.body.id }}"
51
+
52
+ - name: "Fetch created user"
53
+ request:
54
+ url: "/users/{{ user_id }}"
55
+ expect:
56
+ - status: 200
57
+ ```
58
+
59
+ - **Template variable system**: New `{{ }}` syntax for dynamic values—supports variables, Faker, factories, and environment variables. See [Dynamic Features](https://github.com/itsthedevman/spec_forge/wiki/Dynamic-Features).
60
+
61
+ - **JSON validation modes**: Three modes for response validation—`shape:` for type checking with nullable/optional flags, `content:` for value matching, and `schema:` for explicit structure control. See [Validating Responses](https://github.com/itsthedevman/spec_forge/wiki/Validating-Responses).
62
+
63
+ - **Configuration inheritance**: The `shared:` wrapper applies request configuration and hooks to nested steps, making auth flows and grouped operations cleaner.
64
+
65
+ - **Lifecycle hooks**: Register callbacks for `before`/`after` events at forge, blueprint, and step levels. See [Callbacks](https://github.com/itsthedevman/spec_forge/wiki/Callbacks).
66
+
67
+ - **Tag-based filtering**: Organize steps with tags and run subsets via `--tags` and `--skip-tags` CLI options. See [Running Tests](https://github.com/itsthedevman/spec_forge/wiki/Running-Tests).
68
+
69
+ - **Improved output display**: Verbosity levels (`--verbose`, `--debug`, `--trace`) with colorized terminal output, detailed failure context, and YAML line number tracking in error messages.
70
+
71
+ - **File includes**: Extract common workflows into separate files and inject them with `include:`.
72
+
73
+ ### Changed
74
+
75
+ - Request options now nested under `request:` key
76
+ - Expectations simplified from `expectations: [{ expect: ... }]` to `expect: [...]`
77
+ - Error messages now include YAML line numbers and source file context
78
+ - Factory references now support traits and attribute overrides via expanded syntax
79
+ - Global variables defined in `forge_helper.rb` via `config.global_variables` instead of YAML
80
+
81
+ ### Removed
82
+
83
+ - Global context system (`Context::Global`, `Context::Store`, `Context::Variables`)
84
+ - Spec and Expectation classes (replaced with Step-based architecture)
85
+ - Global headers/query configuration (use `shared:` inheritance instead)
86
+
87
+ **[Full documentation](https://github.com/itsthedevman/spec_forge/wiki)** | **[Migration Guide](https://github.com/itsthedevman/spec_forge/wiki/Migration-Guide)**
88
+
89
+ ---
90
+
18
91
  ## [0.7.1] - 12025-10-08
19
92
 
20
93
  ### Added
@@ -394,7 +467,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
394
467
 
395
468
  - Initial commit
396
469
 
397
- [unreleased]: https://github.com/itsthedevman/spec_forge/compare/v0.7.1...HEAD
470
+ [unreleased]: https://github.com/itsthedevman/spec_forge/compare/v1.0.0...HEAD
471
+ [1.0.0]: https://github.com/itsthedevman/spec_forge/compare/v0.7.1...v1.0.0
398
472
  [0.7.1]: https://github.com/itsthedevman/spec_forge/compare/v0.7.0...v0.7.1
399
473
  [0.7.0]: https://github.com/itsthedevman/spec_forge/compare/v0.6.0...v0.7.0
400
474
  [0.6.0]: https://github.com/itsthedevman/spec_forge/compare/v0.5.0...v0.6.0
data/README.md CHANGED
@@ -4,254 +4,176 @@
4
4
  ![Ruby Version](https://img.shields.io/badge/ruby-3.2+-ruby)
5
5
  [![Tests](https://github.com/itsthedevman/spec_forge/actions/workflows/main.yml/badge.svg)](https://github.com/itsthedevman/spec_forge/actions/workflows/main.yml)
6
6
 
7
- > Note: The code in this repository represents the latest development version with new features and improvements that are being prepared for future releases. For the current stable version, check out [v0.7.1](https://github.com/itsthedevman/spec_forge/releases/tag/v0.7.1) on GitHub releases.
8
-
9
- Write API tests in YAML that read like documentation and generate OpenAPI specifications:
7
+ Write API tests as sequential workflows in YAML. Generate OpenAPI documentation automatically.
10
8
 
11
9
  ```yaml
12
- show_user:
13
- path: /users/{id}
14
- variables:
15
- expected_status: 200
16
- user_id: 1
17
- query:
18
- id: variables.user_id
19
- expectations:
20
- - expect:
21
- status: variables.expected_status
22
- json:
23
- name: kind_of.string
24
- email:
25
- matcher.and:
26
- - kind_of.string
27
- - /@/
28
- headers:
29
- Content-Type: "application/json"
30
- X-Request-ID: /^[0-9a-f-]{36}$/
10
+ # spec_forge/blueprints/users.yml
11
+ - name: "Create and verify user"
12
+ request:
13
+ url: /users
14
+ http_verb: POST
15
+ json:
16
+ name: "Jane Smith"
17
+ email: "jane@example.com"
18
+ expect:
19
+ - status: 201
20
+ json:
21
+ shape:
22
+ id: integer
23
+ name: string
24
+ email: string
25
+ store:
26
+ user_id: "{{ response.body.id }}"
27
+
28
+ - name: "Fetch created user"
29
+ request:
30
+ url: "/users/{{ user_id }}"
31
+ expect:
32
+ - status: 200
33
+ json:
34
+ content:
35
+ name: "Jane Smith"
31
36
  ```
32
37
 
33
- That's a complete test that validates your API and creates OpenAPI documentation. No Ruby code, no configuration files, no HTTP client setup - just clear, executable specifications.
38
+ Two steps. One workflow. No Ruby code required.
34
39
 
35
40
  ## Why SpecForge?
36
41
 
37
- **For Testing:**
38
-
39
- - **Reduce Boilerplate**: Write tests without repetitive setup code and HTTP configuration
40
- - **Quick Setup**: Start testing APIs in minutes instead of spending hours on test infrastructure
41
- - **Clear Syntax**: Tests that everyone can read and understand, regardless of Ruby expertise
42
-
43
- **For Documentation:**
44
-
45
- - **OpenAPI Generation**: Generate OpenAPI specifications from your test structure, with full customization through configuration files
46
- - **Living Documentation**: Your tests ensure the documentation always matches your actual API behavior
47
- - **Professional Output**: View your API docs in Swagger UI or Redoc with minimal setup
48
-
49
- **For Teams:**
50
-
51
- - **Developer & QA Collaboration**: Create specifications that both developers and QA can maintain
52
- - **Gradual Adoption**: Use alongside your existing test suite, introducing it incrementally where it makes sense
42
+ **For Testing**
43
+ - Write tests the way you think about APIs - as sequences of actions
44
+ - Zero boilerplate: no HTTP client setup, no configuration objects
45
+ - Full access to RSpec matchers, Faker, and FactoryBot without writing Ruby
53
46
 
54
- ## Key Features
47
+ **For Documentation**
48
+ - Auto-generate OpenAPI specs from your workflows
49
+ - Tests ensure documentation always matches your actual API
50
+ - View in Swagger UI or Redoc with one command
55
51
 
56
- - **Automatic Documentation Generation**: Transform tests into OpenAPI specifications with customizable configuration
57
- - **Live Documentation Server**: Local development server for viewing generated documentation
58
- - **YAML-Based Tests**: Write clear, declarative tests that read like documentation
59
- - **RSpec Integration**: Leverage all the power of RSpec matchers and expectations
60
- - **Header Testing**: Comprehensive HTTP header validation with compound matchers
61
- - **FactoryBot Integration**: Generate test data with FactoryBot integration
62
- - **Faker Integration**: Create realistic test data with Faker
63
- - **Variable System**: Define and reference variables for dynamic test data
64
- - **Context Storage**: Store API responses and reference them in subsequent tests
65
- - **Compound Matchers**: Combine multiple validations with `matcher.and` for precise expectations
66
- - **Global Variables**: Define shared configuration at the file level
67
- - **Callback System**: Hook into the test lifecycle using Ruby for setup, teardown, and much more!
52
+ **For Teams**
53
+ - YAML workflows are easier to review than Ruby test code
54
+ - QA, developers, and product can all read and contribute
55
+ - Version-controlled specifications that live with your code
68
56
 
69
57
  ## Quick Start
70
58
 
71
- Get started with SpecForge in 3 commands:
72
-
73
- ```bash
74
- # 1. Initialize SpecForge
75
- spec_forge init
76
-
77
- # 2. Create your first test
78
- spec_forge new spec users
79
-
80
- # 3. View your documentation
81
- spec_forge serve
82
- ```
83
-
84
- Then visit `http://localhost:8080` to see your API documentation!
85
-
86
- ## When Not to Use SpecForge
87
-
88
- Consider alternatives when you need:
89
-
90
- 1. **Complex Ruby Logic**: If your tests require custom Ruby code for data transformations or validations.
91
- 2. **Complex Test Setup**: When you need intricate database states or specific service mocks.
92
- 3. **Custom Response Validation**: For validation logic beyond what matchers provide.
93
- 4. **Complex Non-JSON Testing**: While SpecForge handles basic XML/HTML responses (coming soon), complex validation might need specialized tools.
94
-
95
- ## Installation
96
-
97
- Add this line to your application's Gemfile:
98
-
99
- ```ruby
100
- gem "spec_forge"
101
- ```
102
-
103
- And then execute:
104
-
105
- ```bash
106
- bundle install
107
- ```
108
-
109
- Or install it yourself as:
110
-
111
59
  ```bash
60
+ # Install
112
61
  gem install spec_forge
113
- ```
114
-
115
- ## Getting Started
116
62
 
117
- Initialize the required directory structure:
118
-
119
- ```bash
63
+ # Initialize project structure
120
64
  spec_forge init
121
- ```
122
-
123
- Create your first test:
124
-
125
- ```bash
126
- spec_forge new spec users
127
- ```
128
-
129
- Generate documentation (default command):
130
65
 
131
- ```bash
132
- spec_forge
133
- ```
66
+ # Create your first workflow
67
+ spec_forge new blueprint users
134
68
 
135
- Or start the live documentation server:
69
+ # Run it
70
+ spec_forge run
136
71
 
137
- ```bash
72
+ # Generate and view documentation
138
73
  spec_forge serve
139
74
  ```
140
75
 
141
- Run tests only (no documentation):
142
-
143
- ```bash
144
- spec_forge run
145
- ```
146
-
147
- ## Documentation Workflow
76
+ Visit `http://localhost:8080` to see your API documentation!
148
77
 
149
- SpecForge provides multiple ways to work with your API documentation:
78
+ ## Key Features
150
79
 
151
- ```bash
152
- # Generate OpenAPI specifications
153
- spec_forge docs # Smart caching
154
- spec_forge docs --fresh # Force regeneration
155
- spec_forge docs --format json # Output as JSON instead of YAML
156
-
157
- # View documentation in browser
158
- spec_forge serve # Generate if needed + serve
159
- spec_forge serve --fresh # Force regeneration + serve
160
- spec_forge serve --ui redoc # Use Redoc instead
161
- spec_forge serve --port 3001 # Custom port
162
-
163
- # Traditional testing
164
- spec_forge run # Pure testing mode
165
- spec_forge run users:show_user # Run specific tests
166
- ```
80
+ - **Step-based workflows**: Tests execute sequentially with explicit variable flow
81
+ - **Variable storage**: Capture response values with `store:`, reference them with `{{ variable }}`
82
+ - **Validation modes**: Simple `shape:` matching for structure, `schema:` for precise control
83
+ - **Tag filtering**: Run subsets with `--tags smoke` or `--skip-tags slow`
84
+ - **Lifecycle hooks**: Execute Ruby code at forge, blueprint, or step boundaries
85
+ - **Dynamic data**: Built-in Faker and FactoryBot integration
86
+ - **Nesting**: Group steps and share configuration with the `shared:` wrapper
167
87
 
168
- ## Example: Complete User API
88
+ ## Example: Authentication Flow
169
89
 
170
90
  ```yaml
171
- # spec_forge/specs/users.yml
172
- global:
173
- variables:
174
- admin_role: "admin"
175
-
176
- list_users:
177
- path: /users
178
- expectations:
179
- - expect:
180
- status: 200
181
- headers:
182
- Content-Type: "application/json"
183
- json:
184
- users:
185
- matcher.have_size:
186
- be.greater_than: 0
187
-
188
- create_user:
189
- path: /users
190
- method: POST
191
- variables:
192
- username: faker.internet.username
193
- email: faker.internet.email
194
- body:
195
- name: variables.username
196
- email: variables.email
197
- role: global.variables.admin_role
198
- store_as: new_user
199
- expectations:
200
- - expect:
201
- status: 201
91
+ - name: "Login"
92
+ request:
93
+ url: /auth/login
94
+ http_verb: POST
95
+ json:
96
+ email: "{{ faker.internet.email }}"
97
+ password: "testpass123"
98
+ expect:
99
+ - status: 200
100
+ json:
101
+ shape:
102
+ token: string
103
+ store:
104
+ auth_token: "{{ response.body.token }}"
105
+
106
+ - name: "Authenticated requests"
107
+ shared:
108
+ request:
202
109
  headers:
203
- Location: /\/users\/\d+/
110
+ Authorization: "Bearer {{ auth_token }}"
111
+ steps:
112
+ - name: "Get profile"
113
+ request:
114
+ url: /me
115
+ expect:
116
+ - status: 200
117
+
118
+ - name: "Update profile"
119
+ request:
120
+ url: /me
121
+ http_verb: PUT
204
122
  json:
205
- id: kind_of.integer
206
- name: variables.username
207
- email: variables.email
208
- role: global.variables.admin_role
209
-
210
- show_user:
211
- path: /users/{id}
212
- query:
213
- id: store.new_user.body.id
214
- expectations:
215
- - expect:
216
- status: 200
217
- json:
218
- id: store.new_user.body.id
219
- name: store.new_user.body.name
220
- email: store.new_user.body.email
221
- role: global.variables.admin_role
123
+ name: "Updated Name"
124
+ expect:
125
+ - status: 200
222
126
  ```
223
127
 
224
- This automatically generates a complete OpenAPI specification with all endpoints, request/response schemas, and examples!
128
+ ## When Not to Use SpecForge
129
+
130
+ Consider alternatives when you need:
131
+
132
+ 1. **Complex Ruby logic** in tests - custom transformations, calculations, or validation beyond matchers
133
+ 2. **Intricate test setup** - complex database states, multiple service mocks, elaborate fixtures
134
+ 3. **Non-REST APIs** - GraphQL, gRPC, or WebSocket testing may need specialized tools
135
+ 4. **Heavy computational testing** - load testing, performance benchmarks, parallel execution
136
+
137
+ You can use SpecForge alongside traditional RSpec tests. Use SpecForge for standard REST workflows and RSpec for complex scenarios.
225
138
 
226
139
  ## Documentation
227
140
 
228
- For comprehensive documentation, visit the [SpecForge Wiki](https://github.com/itsthedevman/spec_forge/wiki) which includes:
141
+ For comprehensive guides and reference:
142
+
143
+ - **[Getting Started](https://github.com/itsthedevman/spec_forge/wiki/Getting-Started)** - Installation and your first workflow
144
+ - **[Writing Tests](https://github.com/itsthedevman/spec_forge/wiki/Writing-Tests)** - Complete syntax reference
145
+ - **[Configuration](https://github.com/itsthedevman/spec_forge/wiki/Configuration)** - Setup and framework integration
146
+ - **[Running Tests](https://github.com/itsthedevman/spec_forge/wiki/Running-Tests)** - CLI commands and filtering
147
+ - **[Dynamic Features](https://github.com/itsthedevman/spec_forge/wiki/Dynamic-Features)** - Variables, Faker, FactoryBot
148
+ - **[Documentation Generation](https://github.com/itsthedevman/spec_forge/wiki/Documentation-Generation)** - OpenAPI customization
149
+
150
+ **Upgrading from 0.7?** See the **[Migration Guide](https://github.com/itsthedevman/spec_forge/wiki/Migration-Guide)**.
229
151
 
230
- - [Getting Started Guide](https://github.com/itsthedevman/spec_forge/wiki/Getting-Started)
231
- - [Configuration Options](https://github.com/itsthedevman/spec_forge/wiki/Configuration)
232
- - [Writing Tests](https://github.com/itsthedevman/spec_forge/wiki/Writing-Tests)
233
- - [Running Tests](https://github.com/itsthedevman/spec_forge/wiki/Running-Tests)
234
- - [Debugging Guide](https://github.com/itsthedevman/spec_forge/wiki/Debugging)
235
- - [Dynamic Features](https://github.com/itsthedevman/spec_forge/wiki/Dynamic-Features)
236
- - [Factory Support](https://github.com/itsthedevman/spec_forge/wiki/Factory-Support)
237
- - [RSpec Matchers](https://github.com/itsthedevman/spec_forge/wiki/RSpec-Matchers)
152
+ **API Reference:** [itsthedevman.com/docs/spec_forge](https://itsthedevman.com/docs/spec_forge)
238
153
 
239
- Also see the [API Documentation](https://itsthedevman.com/docs/spec_forge).
154
+ ## CLI Reference
240
155
 
241
- ## Future Development
156
+ | Command | Description |
157
+ |---------|-------------|
158
+ | `spec_forge init` | Initialize project structure |
159
+ | `spec_forge new blueprint <name>` | Create a workflow file |
160
+ | `spec_forge new factory <name>` | Create a factory file |
161
+ | `spec_forge run` | Execute workflows |
162
+ | `spec_forge docs` | Generate OpenAPI specs |
163
+ | `spec_forge serve` | Generate and serve documentation |
242
164
 
243
- For the latest development priorities and feature ideas, check out our [Github Project](https://github.com/itsthedevman/spec_forge/projects?query=is%3Aopen). Have a feature request? Open an issue on GitHub!
165
+ Run `spec_forge help <command>` for detailed options.
244
166
 
245
167
  ## Contributing
246
168
 
247
- Contributions are welcome! See the [Contributing Guide](https://github.com/itsthedevman/spec_forge/wiki/Contributing) for details on how to get started.
169
+ Contributions welcome! See the [Contributing Guide](https://github.com/itsthedevman/spec_forge/wiki/Contributing).
248
170
 
249
171
  ## License
250
172
 
251
- The gem is available as open source under the terms of the [MIT License](LICENSE.txt).
173
+ Available as open source under the [MIT License](LICENSE.txt).
252
174
 
253
175
  ## Looking for a Software Engineer?
254
176
 
255
177
  I'm currently looking for opportunities where I can tackle meaningful problems and help build reliable software while mentoring the next generation of developers. If you're looking for a senior engineer with full-stack Rails expertise and a passion for clean, maintainable code, let's talk!
256
178
 
257
- [bryan@itsthedevman.com](mailto:bryan@itsthedevman.com)
179
+ [bryan@itsthedevman.com](mailto:bryan@itsthedevman.com)
data/bin/spec_forge CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env ruby
2
2
  # frozen_string_literal: true
3
3
 
4
- require "spec_forge"
4
+ require_relative "../lib/spec_forge"
5
5
  SpecForge::CLI.new.run
data/flake.lock CHANGED
@@ -1,5 +1,21 @@
1
1
  {
2
2
  "nodes": {
3
+ "flake-compat": {
4
+ "flake": false,
5
+ "locked": {
6
+ "lastModified": 1747046372,
7
+ "narHash": "sha256-CIVLLkVgvHYbgI2UpXvIIBJ12HWgX+fjA8Xf8PUmqCY=",
8
+ "owner": "edolstra",
9
+ "repo": "flake-compat",
10
+ "rev": "9100a0f413b0c601e0533d1d94ffd501ce2e7885",
11
+ "type": "github"
12
+ },
13
+ "original": {
14
+ "owner": "edolstra",
15
+ "repo": "flake-compat",
16
+ "type": "github"
17
+ }
18
+ },
3
19
  "flake-utils": {
4
20
  "inputs": {
5
21
  "systems": "systems"
@@ -18,13 +34,31 @@
18
34
  "type": "github"
19
35
  }
20
36
  },
37
+ "flake-utils_2": {
38
+ "inputs": {
39
+ "systems": "systems_2"
40
+ },
41
+ "locked": {
42
+ "lastModified": 1731533236,
43
+ "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
44
+ "owner": "numtide",
45
+ "repo": "flake-utils",
46
+ "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
47
+ "type": "github"
48
+ },
49
+ "original": {
50
+ "owner": "numtide",
51
+ "repo": "flake-utils",
52
+ "type": "github"
53
+ }
54
+ },
21
55
  "nixpkgs": {
22
56
  "locked": {
23
- "lastModified": 1750365781,
24
- "narHash": "sha256-XE/lFNhz5lsriMm/yjXkvSZz5DfvKJLUjsS6pP8EC50=",
57
+ "lastModified": 1767379071,
58
+ "narHash": "sha256-EgE0pxsrW9jp9YFMkHL9JMXxcqi/OoumPJYwf+Okucw=",
25
59
  "owner": "NixOS",
26
60
  "repo": "nixpkgs",
27
- "rev": "08f22084e6085d19bcfb4be30d1ca76ecb96fe54",
61
+ "rev": "fb7944c166a3b630f177938e478f0378e64ce108",
28
62
  "type": "github"
29
63
  },
30
64
  "original": {
@@ -34,10 +68,33 @@
34
68
  "type": "github"
35
69
  }
36
70
  },
71
+ "nixpkgs-ruby": {
72
+ "inputs": {
73
+ "flake-compat": "flake-compat",
74
+ "flake-utils": "flake-utils_2",
75
+ "nixpkgs": [
76
+ "nixpkgs"
77
+ ]
78
+ },
79
+ "locked": {
80
+ "lastModified": 1766728475,
81
+ "narHash": "sha256-9y9WBiQONK9TgD4lu8SW6TpcfEaJTxEs1HjhC4s4vnY=",
82
+ "owner": "bobvanderlinden",
83
+ "repo": "nixpkgs-ruby",
84
+ "rev": "f167828eab19c3a7e3faa066a140d92e307f7b16",
85
+ "type": "github"
86
+ },
87
+ "original": {
88
+ "owner": "bobvanderlinden",
89
+ "repo": "nixpkgs-ruby",
90
+ "type": "github"
91
+ }
92
+ },
37
93
  "root": {
38
94
  "inputs": {
39
95
  "flake-utils": "flake-utils",
40
- "nixpkgs": "nixpkgs"
96
+ "nixpkgs": "nixpkgs",
97
+ "nixpkgs-ruby": "nixpkgs-ruby"
41
98
  }
42
99
  },
43
100
  "systems": {
@@ -54,6 +111,21 @@
54
111
  "repo": "default",
55
112
  "type": "github"
56
113
  }
114
+ },
115
+ "systems_2": {
116
+ "locked": {
117
+ "lastModified": 1681028828,
118
+ "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
119
+ "owner": "nix-systems",
120
+ "repo": "default",
121
+ "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
122
+ "type": "github"
123
+ },
124
+ "original": {
125
+ "owner": "nix-systems",
126
+ "repo": "default",
127
+ "type": "github"
128
+ }
57
129
  }
58
130
  },
59
131
  "root": "root",
data/flake.nix CHANGED
@@ -4,6 +4,8 @@
4
4
  inputs = {
5
5
  nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
6
6
  flake-utils.url = "github:numtide/flake-utils";
7
+ nixpkgs-ruby.url = "github:bobvanderlinden/nixpkgs-ruby";
8
+ nixpkgs-ruby.inputs.nixpkgs.follows = "nixpkgs";
7
9
  };
8
10
 
9
11
  outputs =
@@ -11,19 +13,18 @@
11
13
  self,
12
14
  nixpkgs,
13
15
  flake-utils,
16
+ nixpkgs-ruby,
14
17
  }:
15
18
  flake-utils.lib.eachDefaultSystem (
16
19
  system:
17
20
  let
18
21
  pkgs = nixpkgs.legacyPackages.${system};
22
+ ruby = nixpkgs-ruby.packages.${system}."ruby-3.2.9";
19
23
  in
20
24
  {
21
25
  devShells.default = pkgs.mkShell {
22
26
  buildInputs = with pkgs; [
23
- (ruby_3_2.override {
24
- jemallocSupport = false;
25
- docSupport = false;
26
- })
27
+ ruby
27
28
 
28
29
  # Dependencies for native gems
29
30
  pkg-config