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
@@ -2,133 +2,263 @@
2
2
 
3
3
  module SpecForge
4
4
  #
5
- # Configuration container for SpecForge settings
6
- # Defines default values and validation for all configuration options
5
+ # Holds configuration options for SpecForge
7
6
  #
8
- class Configuration < Struct.new(:base_url, :headers, :query, :factories, :on_debug_proc)
9
- #
10
- # Manages factory configuration settings
11
- # Controls auto-discovery behavior and custom factory paths
7
+ # Configuration is typically set in forge_helper.rb using the configure block.
8
+ # It controls base URL, global variables, factory settings, callbacks, and more.
9
+ #
10
+ # @example Basic configuration
11
+ # SpecForge.configure do |config|
12
+ # config.base_url = "http://localhost:3000"
13
+ # config.global_variables = {api_version: "v1"}
14
+ # end
15
+ #
16
+ class Configuration
12
17
  #
13
- # @example
14
- # config.factories.auto_discover = false
15
- # config.factories.paths += ["lib/factories"]
18
+ # Configuration for FactoryBot factory loading
16
19
  #
17
20
  class Factories < Struct.new(:auto_discover, :paths)
18
- #
19
- # Creates reader methods that return boolean values
20
- # Allows for checking configuration with predicate methods
21
- #
22
- attr_predicate :auto_discover, :paths
23
-
24
- #
25
- # Initializes a new Factories configuration
26
- # Sets default values for auto-discovery and paths
27
- #
28
- # @param auto_discover [Boolean] Whether to auto-discover factories (default: true)
29
- # @param paths [Array<String>] Additional paths to look for factories (default: [])
30
- #
31
- # @return [Factories] A new factories configuration instance
32
- #
21
+ # @return [Boolean] Whether auto-discovery is enabled
22
+ attr_predicate :auto_discover
23
+
24
+ # @return [Array<String>] Factory file paths
25
+ attr_predicate :paths
26
+
33
27
  def initialize(auto_discover: true, paths: []) = super
34
28
  end
35
29
 
30
+ # @return [String] Base URL for HTTP requests
31
+ attr_accessor :base_url
32
+
33
+ # @return [Hash] Global variables available to all blueprints
34
+ attr_accessor :global_variables
35
+
36
+ # @return [Factories] Factory configuration
37
+ attr_reader :factories
38
+
39
+ # @return [Proc, nil] Debug handler proc
40
+ attr_reader :on_debug_proc
41
+
42
+ # @return [Hash{Symbol => Proc}] Registered callbacks
43
+ attr_reader :callbacks
44
+
45
+ # @return [Hash{Symbol => Array}] Global lifecycle hooks for forge, blueprint, and step events
46
+ attr_reader :hooks
47
+
36
48
  #
37
- # Initializes a new Configuration with default values
38
- # Sets up the configuration structure including factory settings and debug proxy
49
+ # Creates a new Configuration with default values
39
50
  #
40
- # @return [Configuration] A new configuration instance with defaults
51
+ # @return [Configuration] A new configuration instance
41
52
  #
42
53
  def initialize
43
- config = Normalizer.default(:configuration)
54
+ # Validated
55
+ @base_url = "http://localhost:3000"
56
+ @factories = Factories.new
57
+ @global_variables = {}
44
58
 
45
- config[:base_url] = "http://localhost:3000"
46
- config[:factories] = Factories.new
47
- config[:on_debug_proc] = Runner::DebugProxy.default
48
-
49
- super(**config)
59
+ # Internal
60
+ @on_debug_proc = nil
61
+ @callbacks = {}
62
+ @hooks = {
63
+ before_forge: [],
64
+ before_blueprint: [],
65
+ before_step: [],
66
+ after_step: [],
67
+ after_blueprint: [],
68
+ after_forge: []
69
+ }
50
70
  end
51
71
 
52
72
  #
53
- # Validates the configuration and applies normalization
54
- # Ensures all required fields have values and applies defaults when needed
73
+ # Validates the configuration and normalizes values
55
74
  #
56
- # @return [self] Returns self for method chaining
75
+ # @return [Configuration] self
57
76
  #
58
- # @api private
77
+ # @raise [Error::InvalidStructureError] If configuration is invalid
59
78
  #
60
79
  def validate
61
- output = Normalizer.normalize!(to_h, using: :configuration)
80
+ output = Normalizer.normalize!(
81
+ {
82
+ base_url: @base_url,
83
+ factories: @factories.to_h,
84
+ global_variables: @global_variables
85
+ },
86
+ using: :configuration
87
+ )
62
88
 
63
89
  # In case any value was set to `nil`
64
- self.base_url = output[:base_url] if base_url.blank?
65
- self.query = output[:query] if query.blank?
66
- self.headers = output[:headers] if headers.blank?
90
+ @global_variables = output[:global_variables] if @global_variables.blank?
91
+ @global_variables.symbolize_keys!
67
92
 
68
93
  self
69
94
  end
70
95
 
96
+ #
97
+ # Sets a debug handler block to be called when a step has debug: true
98
+ #
99
+ # @yield [context] Block called when debug is triggered
100
+ # @yieldparam context [Forge::Context] The current execution context
101
+ #
102
+ # @example
103
+ # config.on_debug { binding.pry }
104
+ #
71
105
  def on_debug(&block)
72
- self.on_debug_proc = block
106
+ @on_debug_proc = block
73
107
  end
74
108
 
75
- def on_debug=(block)
76
- warn("SpecForge::Configuration#on_debug= is deprecated. Use #on_debug instead")
77
- self.on_debug_proc = block
109
+ #
110
+ # Returns RSpec's configuration for customization
111
+ #
112
+ # @return [RSpec::Core::Configuration] RSpec configuration
113
+ #
114
+ def rspec
115
+ RSpec.configuration
78
116
  end
79
117
 
80
118
  #
81
- # Recursively converts the configuration to a hash representation
119
+ # Registers a callback that can be invoked from blueprints using call:
82
120
  #
83
- # @return [Hash] Hash representation of the configuration
121
+ # @param name [String, Symbol] The callback name to register
84
122
  #
85
- def to_h
86
- hash = super
87
- hash[:factories] = hash[:factories].to_h
88
- hash
123
+ # @yield [context, *args] Block to execute when callback is called
124
+ # @yieldparam context [Forge::Context] The current execution context
125
+ #
126
+ # @example Simple callback
127
+ # config.register_callback("seed_data") do |context|
128
+ # User.create!(name: "Test")
129
+ # end
130
+ #
131
+ # @example Callback with arguments
132
+ # config.register_callback("create_users") do |context, count:|
133
+ # count.times { User.create! }
134
+ # end
135
+ #
136
+ def register_callback(name, &block)
137
+ @callbacks[name.to_sym] = block
89
138
  end
90
139
 
91
140
  #
92
- # Returns the RSpec configuration object
93
- # Provides access to RSpec's internal configuration for test customization
141
+ # Removes a registered callback and detaches it from all lifecycle hooks
94
142
  #
95
- # @return [RSpec::Core::Configuration] RSpec's configuration object
143
+ # @param name [String, Symbol] The callback name to remove
96
144
  #
97
- # @example Setting formatter options
98
- # SpecForge.configure do |config|
99
- # config.specs.formatter = :documentation
100
- # end
145
+ # @return [Proc, nil] The removed callback proc, or nil if not found
101
146
  #
102
- def specs
103
- RSpec.configuration
147
+ # @example Remove a callback
148
+ # config.register_callback(:my_hook) { |context| puts "hook" }
149
+ # config.before(:step, :my_hook)
150
+ # config.deregister_callback(:my_hook) # Removes from callbacks and hooks
151
+ #
152
+ def deregister_callback(name)
153
+ name = name.to_sym
154
+
155
+ callback = @callbacks.delete(name)
156
+ @hooks.each_value { |a| a.delete(name) }
157
+
158
+ callback
104
159
  end
105
160
 
106
- alias_method :rspec, :specs
161
+ #
162
+ # Attaches a callback to a before lifecycle event
163
+ #
164
+ # Global hooks run for all blueprints and execute in registration order.
165
+ # Can either reference a pre-registered callback by name, or accept a block
166
+ # to register and attach a callback in one step (like RSpec's before hooks).
167
+ #
168
+ # @param event [Symbol] The lifecycle event (:forge, :blueprint, or :step)
169
+ # @param callback_name [String, Symbol, nil] The name of a registered callback
170
+ # (optional if block is provided)
171
+ #
172
+ # @yield [context] Block to execute (registers callback automatically)
173
+ # @yieldparam context [Forge::Context] The current execution context
174
+ #
175
+ # @return [String, Symbol] The callback name (auto-generated if block provided)
176
+ #
177
+ # @raise [ArgumentError] If the event is invalid
178
+ # @raise [ArgumentError] If the callback is not registered (when using name)
179
+ #
180
+ # @example Attach a pre-registered callback
181
+ # config.register_callback(:setup) { |context| Database.seed }
182
+ # config.before(:forge, :setup)
183
+ #
184
+ # @example Register and attach with a block (like RSpec)
185
+ # config.before(:step) { |context| Logger.info("Starting step") }
186
+ # config.before(:blueprint) { |context| Database.clean }
187
+ #
188
+ # @example Store the callback name for later deregistration
189
+ # callback_name = config.before(:step) { |context| puts "hook" }
190
+ # config.deregister_callback(callback_name)
191
+ #
192
+ def before(event, callback_name = nil, &block)
193
+ if block
194
+ callback_name = "__sf_cb_#{SecureRandom.uuid.tr("-", "")}"
195
+ register_callback(callback_name, &block)
196
+ end
197
+
198
+ register_hook("before", event, callback_name)
199
+
200
+ callback_name
201
+ end
107
202
 
108
203
  #
109
- # Registers a callback for a specific test lifecycle event
110
- # Allows custom code execution at specific points during test execution
204
+ # Attaches a callback to an after lifecycle event
111
205
  #
112
- # @param name [Symbol, String] The callback point to register for
113
- # (:before_file, :after_expectation, etc.)
114
- # @yield A block to execute when the callback is triggered
115
- # @yieldparam context [Object] An object containing context-specific state data, depending
116
- # on which hook the callback is triggered from.
206
+ # Global hooks run for all blueprints and execute in registration order.
207
+ # Can either reference a pre-registered callback by name, or accept a block
208
+ # to register and attach a callback in one step (like RSpec's after hooks).
117
209
  #
118
- # @return [Proc] The registered callback
210
+ # @param event [Symbol] The lifecycle event (:forge, :blueprint, or :step)
211
+ # @param callback_name [String, Symbol, nil] The name of a registered callback
212
+ # (optional if block is provided)
119
213
  #
120
- # @example Cleaning database after each test
121
- # SpecForge.configure do |config|
122
- # config.register_callback(:after_expectation) do
123
- # DatabaseCleaner.clean
124
- # end
125
- # end
214
+ # @yield [context] Block to execute (registers callback automatically)
215
+ # @yieldparam context [Forge::Context] The current execution context
216
+ #
217
+ # @return [String, Symbol] The callback name (auto-generated if block provided)
218
+ #
219
+ # @raise [ArgumentError] If the event is invalid
220
+ # @raise [ArgumentError] If the callback is not registered (when using name)
221
+ #
222
+ # @example Attach a pre-registered callback
223
+ # config.register_callback(:cleanup) { |context| Database.clean }
224
+ # config.after(:forge, :cleanup)
225
+ #
226
+ # @example Register and attach with a block (like RSpec)
227
+ # config.after(:step) { |context| Logger.info("Step complete") }
228
+ # config.after(:blueprint) { |context| Database.rollback }
229
+ #
230
+ # @example Store the callback name for later deregistration
231
+ # callback_name = config.after(:step) { |context| puts "done" }
232
+ # config.deregister_callback(callback_name)
126
233
  #
127
- def register_callback(name, &)
128
- Callbacks.register(name, &)
234
+ def after(event, callback_name = nil, &block)
235
+ if block
236
+ callback_name = "__sf_cb_#{SecureRandom.uuid.tr("-", "")}"
237
+ register_callback(callback_name, &block)
238
+ end
239
+
240
+ register_hook("after", event, callback_name)
241
+
242
+ callback_name
129
243
  end
130
244
 
131
- alias_method :define_callback, :register_callback
132
- alias_method :callback, :register_callback
245
+ private
246
+
247
+ def register_hook(timing, event, callback_name)
248
+ hook = :"#{timing}_#{event}"
249
+ callback_name = callback_name.to_sym
250
+
251
+ if !@hooks.key?(hook)
252
+ keys = @hooks.keys.select { |k| k.to_s.start_with?(timing) }.map(&:in_quotes)
253
+ raise ArgumentError, "Invalid event #{hook.in_quotes}. Expected one of #{keys.to_or_sentence}"
254
+ end
255
+
256
+ if !@callbacks.key?(callback_name)
257
+ keys = @callbacks.keys.map(&:in_quotes)
258
+ raise ArgumentError, "Invalid callback #{callback_name.in_quotes}. Expected one of #{keys.to_or_sentence}"
259
+ end
260
+
261
+ @hooks[hook] << callback_name
262
+ end
133
263
  end
134
264
  end
@@ -2,20 +2,23 @@
2
2
 
3
3
  module SpecForge
4
4
  module Documentation
5
- class Loader
5
+ class Builder
6
6
  #
7
- # Manages caching of test execution data for documentation generation
7
+ # Manages caching of endpoint data to avoid re-running blueprints
8
8
  #
9
- # Provides caching of endpoint data extracted from tests,
10
- # checking file modification times to determine cache validity and
11
- # avoiding unnecessary test re-execution when specs haven't changed.
9
+ # The Cache stores extracted endpoint data and tracks blueprint file
10
+ # modification times. When blueprints haven't changed, cached data
11
+ # can be reused to speed up documentation generation.
12
+ #
13
+ # Cache files are stored in the OpenAPI generated directory under
14
+ # a .cache subdirectory.
12
15
  #
13
16
  # @example Using the cache
14
17
  # cache = Cache.new
15
18
  # if cache.valid?
16
19
  # endpoints = cache.read
17
20
  # else
18
- # endpoints = run_tests_and_extract_data
21
+ # endpoints = extract_from_blueprints
19
22
  # cache.create(endpoints)
20
23
  # end
21
24
  #
@@ -23,41 +26,41 @@ module SpecForge
23
26
  #
24
27
  # Creates a new cache manager
25
28
  #
26
- # Sets up file paths for endpoint and spec caches in the OpenAPI
29
+ # Sets up file paths for endpoint and blueprint caches in the OpenAPI
27
30
  # generated directory structure.
28
31
  #
29
32
  # @return [Cache] A new cache instance
30
33
  #
31
34
  def initialize
32
35
  @endpoint_cache = SpecForge.openapi_path.join("generated", ".cache", "endpoints.yml")
33
- @spec_cache = SpecForge.openapi_path.join("generated", ".cache", "specs.yml")
36
+ @blueprint_cache = SpecForge.openapi_path.join("generated", ".cache", "blueprints.yml")
34
37
  end
35
38
 
36
39
  #
37
40
  # Checks if the cache is valid and can be used
38
41
  #
39
42
  # Determines cache validity by checking if endpoint cache exists
40
- # and whether any spec files have been modified since the cache
43
+ # and whether any blueprint files have been modified since the cache
41
44
  # was created.
42
45
  #
43
46
  # @return [Boolean] true if cache is valid and can be used
44
47
  #
45
48
  def valid?
46
- endpoint_cache? && !specs_updated?
49
+ endpoint_cache? && !blueprints_updated?
47
50
  end
48
51
 
49
52
  #
50
- # Creates a cache entry with endpoint data and spec file metadata
53
+ # Creates a cache entry with endpoint data and blueprint file metadata
51
54
  #
52
- # Writes both the endpoint data and current spec file modification times
53
- # to enable cache invalidation when specs change.
55
+ # Writes both the endpoint data and current blueprint file modification times
56
+ # to enable cache invalidation when blueprints change.
54
57
  #
55
58
  # @param endpoints [Array<Hash>] Endpoint data to cache
56
59
  #
57
60
  # @return [void]
58
61
  #
59
62
  def create(endpoints)
60
- write_spec_cache
63
+ write_blueprint_cache
61
64
  write(endpoints)
62
65
  end
63
66
 
@@ -93,11 +96,11 @@ module SpecForge
93
96
  YAML.safe_load_file(path, symbolize_names: true, permitted_classes: [Symbol, Time])
94
97
  end
95
98
 
96
- def specs_updated?
97
- return true if !File.exist?(@spec_cache)
99
+ def blueprints_updated?
100
+ return true if !File.exist?(@blueprint_cache)
98
101
 
99
- cache = read_from_file(@spec_cache)
100
- new_cache = generate_spec_cache
102
+ cache = read_from_file(@blueprint_cache)
103
+ new_cache = generate_blueprint_cache
101
104
 
102
105
  different?(cache, new_cache)
103
106
  end
@@ -106,17 +109,17 @@ module SpecForge
106
109
  File.exist?(@endpoint_cache)
107
110
  end
108
111
 
109
- def generate_spec_cache
110
- paths = SpecForge.forge_path.join("specs", "**", "*.{yml,yaml}")
112
+ def generate_blueprint_cache
113
+ paths = SpecForge.forge_path.join("blueprints", "**", "*.{yml,yaml}")
111
114
 
112
115
  Dir[paths].each_with_object({}) do |path, hash|
113
116
  hash[path.to_sym] = File.mtime(path)
114
117
  end
115
118
  end
116
119
 
117
- def write_spec_cache
118
- data = generate_spec_cache
119
- write_to_file(data, @spec_cache)
120
+ def write_blueprint_cache
121
+ data = generate_blueprint_cache
122
+ write_to_file(data, @blueprint_cache)
120
123
  end
121
124
 
122
125
  def different?(cache_left, cache_right)