has_state_machine 1.2.0 → 1.2.2
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/README.md +19 -3
- data/Rakefile +2 -2
- data/lib/has_state_machine/core_ext/string.rb +3 -1
- data/lib/has_state_machine/state.rb +46 -25
- data/lib/has_state_machine/version.rb +1 -1
- data/lib/ruby_lsp/has_state_machine/addon.rb +16 -1
- data/lib/ruby_lsp/has_state_machine/definition.rb +47 -8
- data/lib/ruby_lsp/has_state_machine/rails_server_addon.rb +15 -3
- metadata +36 -14
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 4f9619070408aa690d1e8b70c31baf787c91d949c0e28665a42af8b17ff79955
|
|
4
|
+
data.tar.gz: '099784a11f816d49d75b18432a1497688838aac08a775d15fe5d29827eb7ac38'
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 749b711582fc925fd8efbfcb7dcdee7dfb3f9902e945d5cc26e1f7f3737ea77f646087a117ccf9e6675444a858acb2497ae52dba0a3c8b2777628ebae33297af
|
|
7
|
+
data.tar.gz: a8cbe864ada7ab74316c55c14704ea33fa18bae5050d3a728d2f5458cb16b561419643805af0824fd7bdcca10cf42e5023e708d84f88ed1e3478a9b24bad2d43
|
data/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# HasStateMachine
|
|
2
2
|
|
|
3
3
|
[](https://github.com/beehiiv/has_state_machine/actions/workflows/ci.yml)
|
|
4
|
-
[](https://github.com/rubocop/rubocop)
|
|
5
5
|
|
|
6
6
|
HasStateMachine uses ruby classes to make creating a finite state machine for your ActiveRecord models a breeze.
|
|
7
7
|
|
|
@@ -98,8 +98,10 @@ module Workflow
|
|
|
98
98
|
end
|
|
99
99
|
|
|
100
100
|
# after_transition_commit runs only once the transition has been
|
|
101
|
-
# committed
|
|
102
|
-
#
|
|
101
|
+
# committed to the database: after the OUTERMOST database transaction
|
|
102
|
+
# commits, or immediately after the transition when no transaction is
|
|
103
|
+
# open. It never runs if the transition or a surrounding transaction
|
|
104
|
+
# rolls back. (Requires Rails 7.2+; see Advanced Usage below.)
|
|
103
105
|
after_transition_commit do
|
|
104
106
|
MyJob.perform_later(object)
|
|
105
107
|
end
|
|
@@ -232,6 +234,20 @@ module Workflow
|
|
|
232
234
|
end
|
|
233
235
|
```
|
|
234
236
|
|
|
237
|
+
#### `after_transition_commit` Semantics
|
|
238
|
+
|
|
239
|
+
`after_transition_commit` callbacks run after the outermost database transaction commits. In detail:
|
|
240
|
+
|
|
241
|
+
- If no transaction is open when `transition_to` is called, they run immediately after the transition commits.
|
|
242
|
+
- If the transition happens inside an open transaction — an app-level `ActiveRecord::Base.transaction`, or a nested transition triggered from another state's `before_transition`/`after_transition` — they are deferred until that outermost transaction commits.
|
|
243
|
+
- They never run if the transition fails, if `rollback_transition` is raised, or if a surrounding transaction rolls back after the transition. Multiple transitions inside one transaction each fire their callbacks after commit, in transition order.
|
|
244
|
+
|
|
245
|
+
This makes `after_transition_commit` the safe place to enqueue background jobs, call external APIs, etc.: the work only happens once the new state is actually visible to other database connections.
|
|
246
|
+
|
|
247
|
+
**Note on Rails versions:** deferral to an outer transaction requires Rails 7.2+. On older Rails versions the callbacks fire as soon as the transition itself completes, which may be inside an uncommitted outer transaction.
|
|
248
|
+
|
|
249
|
+
**Footgun: `ActiveRecord.after_all_transactions_commit`** does not work as a substitute inside `before_transition`/`after_transition`. Rails skips non-joinable transactions when deciding whether any transaction is open, and transactional transitions run inside the gem's own non-joinable transaction — so the block yields *immediately*, while the transition is still uncommitted. Use `after_transition_commit` instead.
|
|
250
|
+
|
|
235
251
|
#### Transient Transition Variables
|
|
236
252
|
|
|
237
253
|
Sometimes you may may want to pass additional arguments to a state transition for additional context in your transition callbacks. To do this, add the `transients` option to the `state_options` declaration. This allows you to define any additional attributes you want to be able to pass along during a state transition to that state.
|
data/Rakefile
CHANGED
|
@@ -10,7 +10,9 @@ class String
|
|
|
10
10
|
#
|
|
11
11
|
# @example
|
|
12
12
|
# "some random string".transition_to("draft") #=> false
|
|
13
|
-
|
|
13
|
+
# rubocop:disable Naming/PredicateMethod -- mirrors HasStateMachine::State#transition_to API
|
|
14
|
+
def transition_to(_desired_state, **_options)
|
|
14
15
|
false
|
|
15
16
|
end
|
|
17
|
+
# rubocop:enable Naming/PredicateMethod
|
|
16
18
|
end
|
|
@@ -16,8 +16,8 @@ module HasStateMachine
|
|
|
16
16
|
define_model_callbacks :transition, only: %i[before after]
|
|
17
17
|
|
|
18
18
|
##
|
|
19
|
-
# Defines the after_transition_commit callback
|
|
20
|
-
# transition
|
|
19
|
+
# Defines the after_transition_commit callback, which runs once a
|
|
20
|
+
# successful transition is committed to the database.
|
|
21
21
|
define_model_callbacks :transition_commit, only: %i[after]
|
|
22
22
|
|
|
23
23
|
##
|
|
@@ -63,7 +63,7 @@ module HasStateMachine
|
|
|
63
63
|
# @return [Boolean] whether or not the transition took place
|
|
64
64
|
def transition_to(desired_state, **options)
|
|
65
65
|
transitioned = false
|
|
66
|
-
options = options.
|
|
66
|
+
options = options.symbolize_keys
|
|
67
67
|
desired_state_instance = state_instance(desired_state, options)
|
|
68
68
|
|
|
69
69
|
with_transition_options(options) do
|
|
@@ -78,45 +78,66 @@ module HasStateMachine
|
|
|
78
78
|
|
|
79
79
|
transitioned
|
|
80
80
|
ensure
|
|
81
|
-
|
|
81
|
+
desired_state_instance&.errors&.each do |error|
|
|
82
82
|
object.errors.add(error.attribute, error.type)
|
|
83
83
|
end
|
|
84
84
|
end
|
|
85
85
|
|
|
86
86
|
##
|
|
87
87
|
# Makes the actual transition from one state to the next and
|
|
88
|
-
# runs the before and after transition callbacks.
|
|
89
|
-
#
|
|
90
|
-
#
|
|
91
|
-
def perform_transition!
|
|
92
|
-
run_callbacks :
|
|
93
|
-
|
|
94
|
-
object.update("#{object.state_attribute}": state)
|
|
95
|
-
end
|
|
88
|
+
# runs the before and after transition callbacks.
|
|
89
|
+
#
|
|
90
|
+
# @return [Boolean] whether or not the transition succeeded
|
|
91
|
+
def perform_transition! # rubocop:disable Naming/PredicateMethod -- public API
|
|
92
|
+
transitioned = run_callbacks :transition do
|
|
93
|
+
object.update("#{object.state_attribute}": state)
|
|
96
94
|
end
|
|
95
|
+
return false unless transitioned
|
|
96
|
+
|
|
97
|
+
@previous_state = previous_state
|
|
98
|
+
enqueue_transition_commit_callbacks
|
|
99
|
+
true
|
|
97
100
|
end
|
|
98
101
|
|
|
99
102
|
##
|
|
100
|
-
#
|
|
101
|
-
#
|
|
102
|
-
#
|
|
103
|
-
#
|
|
104
|
-
def perform_transactional_transition!
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
rollback_transition unless object.update("#{object.state_attribute}": state)
|
|
109
|
-
end
|
|
103
|
+
# Same as {#perform_transition!}, but wrapped in a transaction so
|
|
104
|
+
# callbacks can roll the transition back.
|
|
105
|
+
#
|
|
106
|
+
# @return [Boolean] whether or not the transition succeeded
|
|
107
|
+
def perform_transactional_transition! # rubocop:disable Naming/PredicateMethod -- public API
|
|
108
|
+
ActiveRecord::Base.transaction(requires_new: true, joinable: false) do
|
|
109
|
+
run_callbacks :transition do
|
|
110
|
+
rollback_transition unless object.update("#{object.state_attribute}": state)
|
|
110
111
|
end
|
|
112
|
+
end
|
|
111
113
|
|
|
112
|
-
|
|
114
|
+
@previous_state = previous_state
|
|
115
|
+
return false unless object.reload.public_send(object.state_attribute) == state
|
|
113
116
|
|
|
114
|
-
|
|
115
|
-
|
|
117
|
+
enqueue_transition_commit_callbacks
|
|
118
|
+
true
|
|
116
119
|
end
|
|
117
120
|
|
|
118
121
|
private
|
|
119
122
|
|
|
123
|
+
##
|
|
124
|
+
# Runs the after_transition_commit callbacks once the outermost open
|
|
125
|
+
# transaction commits, discarding them on rollback.
|
|
126
|
+
#
|
|
127
|
+
# @note Registers on the connection's current transaction because
|
|
128
|
+
# +ActiveRecord.after_all_transactions_commit+ ignores non-joinable
|
|
129
|
+
# transactions (like the gem's own) and would fire immediately.
|
|
130
|
+
# @return [void]
|
|
131
|
+
def enqueue_transition_commit_callbacks
|
|
132
|
+
current_transaction = object.class.connection.current_transaction
|
|
133
|
+
|
|
134
|
+
# Rails < 7.2 has no Transaction#after_commit, so callbacks fire
|
|
135
|
+
# immediately with no deferral. Drop this guard at Rails 7.2+.
|
|
136
|
+
return run_callbacks(:transition_commit) { true } unless current_transaction.respond_to?(:after_commit)
|
|
137
|
+
|
|
138
|
+
current_transaction.after_commit { run_callbacks(:transition_commit) { true } }
|
|
139
|
+
end
|
|
140
|
+
|
|
120
141
|
def rollback_transition
|
|
121
142
|
raise ActiveRecord::Rollback
|
|
122
143
|
end
|
|
@@ -12,12 +12,25 @@ module RubyLsp
|
|
|
12
12
|
class Addon < ::RubyLsp::Addon
|
|
13
13
|
def activate(global_state, outgoing_queue)
|
|
14
14
|
@global_state = global_state
|
|
15
|
+
@model_name_cache = {}
|
|
15
16
|
@rails_client = register_rails_server_addon(outgoing_queue)
|
|
17
|
+
|
|
18
|
+
rails_status = if @rails_client
|
|
19
|
+
"registered"
|
|
20
|
+
else
|
|
21
|
+
"unavailable, using naming convention only"
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
log(
|
|
25
|
+
outgoing_queue,
|
|
26
|
+
"Activating Has State Machine Ruby LSP add-on v#{version} (Rails integration: #{rails_status})"
|
|
27
|
+
)
|
|
16
28
|
end
|
|
17
29
|
|
|
18
30
|
def deactivate
|
|
19
31
|
@global_state = nil
|
|
20
32
|
@rails_client = nil
|
|
33
|
+
@model_name_cache = nil
|
|
21
34
|
end
|
|
22
35
|
|
|
23
36
|
def name
|
|
@@ -35,7 +48,8 @@ module RubyLsp
|
|
|
35
48
|
node_context,
|
|
36
49
|
dispatcher,
|
|
37
50
|
index: @global_state&.index,
|
|
38
|
-
rails_client: @rails_client
|
|
51
|
+
rails_client: @rails_client,
|
|
52
|
+
model_name_cache: @model_name_cache
|
|
39
53
|
)
|
|
40
54
|
end
|
|
41
55
|
|
|
@@ -53,6 +67,7 @@ module RubyLsp
|
|
|
53
67
|
|
|
54
68
|
client = rails_addon.rails_runner_client
|
|
55
69
|
return unless client.respond_to?(:register_server_addon)
|
|
70
|
+
return if client.respond_to?(:connected?) && !client.connected?
|
|
56
71
|
|
|
57
72
|
client.register_server_addon(File.expand_path("rails_server_addon.rb", __dir__))
|
|
58
73
|
client
|
|
@@ -7,25 +7,37 @@ module RubyLsp
|
|
|
7
7
|
class Definition
|
|
8
8
|
SERVER_ADDON_NAME = "has_state_machine"
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
# AR methods that return self, so `object.reload.foo` targets the model
|
|
11
|
+
# just like `object.foo`.
|
|
12
|
+
SELF_RETURNING_METHODS = ["reload"].freeze
|
|
13
|
+
|
|
14
|
+
def initialize(response_builder, _uri, node_context, dispatcher, index: nil, rails_client: nil,
|
|
15
|
+
model_name_cache: nil)
|
|
11
16
|
@response_builder = response_builder
|
|
12
17
|
@node_context = node_context
|
|
13
18
|
@index = index
|
|
14
19
|
@rails_client = rails_client
|
|
20
|
+
@model_name_cache = model_name_cache
|
|
15
21
|
|
|
16
22
|
dispatcher.register(self, :on_call_node_enter)
|
|
17
23
|
end
|
|
18
24
|
|
|
19
25
|
def on_call_node_enter(node)
|
|
20
26
|
return unless current_target?(node)
|
|
21
|
-
return unless resolved_model_name
|
|
22
27
|
|
|
28
|
+
# Check the node shape first: resolving the model name may require a
|
|
29
|
+
# round-trip to the Rails runner, so only pay it for `object` calls.
|
|
23
30
|
if object_call?(node)
|
|
31
|
+
return unless resolved_model_name
|
|
32
|
+
|
|
24
33
|
push_entries(constant_entries(resolved_model_name))
|
|
25
34
|
elsif object_method_call?(node)
|
|
35
|
+
return unless resolved_model_name
|
|
36
|
+
|
|
26
37
|
method_name = message(node)
|
|
27
38
|
entries = method_entries(resolved_model_name, method_name)
|
|
28
39
|
entries = association_entries(resolved_model_name, method_name) if entries.empty?
|
|
40
|
+
entries = constant_entries(resolved_model_name) if entries.empty?
|
|
29
41
|
|
|
30
42
|
push_entries(entries)
|
|
31
43
|
end
|
|
@@ -33,7 +45,7 @@ module RubyLsp
|
|
|
33
45
|
|
|
34
46
|
private
|
|
35
47
|
|
|
36
|
-
attr_reader :index, :node_context, :rails_client, :response_builder
|
|
48
|
+
attr_reader :index, :model_name_cache, :node_context, :rails_client, :response_builder
|
|
37
49
|
|
|
38
50
|
def current_target?(node)
|
|
39
51
|
target = node_context.node if node_context.respond_to?(:node)
|
|
@@ -77,8 +89,20 @@ module RubyLsp
|
|
|
77
89
|
end
|
|
78
90
|
|
|
79
91
|
def model_name_from_rails(workflow_namespace)
|
|
80
|
-
return unless workflow_namespace &&
|
|
92
|
+
return unless workflow_namespace && rails_client_available?
|
|
93
|
+
|
|
94
|
+
# Cache hits and misses for the life of the LSP process; the set of
|
|
95
|
+
# models rarely changes mid-session. Failures raise past the cache
|
|
96
|
+
# write, so a slow-to-boot Rails runner can succeed on a later request.
|
|
97
|
+
cache = model_name_cache.to_h
|
|
98
|
+
cache.fetch(workflow_namespace) do
|
|
99
|
+
cache[workflow_namespace] = request_model_name(workflow_namespace)
|
|
100
|
+
end
|
|
101
|
+
rescue
|
|
102
|
+
nil
|
|
103
|
+
end
|
|
81
104
|
|
|
105
|
+
def request_model_name(workflow_namespace)
|
|
82
106
|
result = rails_client.delegate_request(
|
|
83
107
|
server_addon_name: SERVER_ADDON_NAME,
|
|
84
108
|
request_name: "model_for_workflow_namespace",
|
|
@@ -86,8 +110,6 @@ module RubyLsp
|
|
|
86
110
|
)
|
|
87
111
|
|
|
88
112
|
response_name(result)
|
|
89
|
-
rescue
|
|
90
|
-
nil
|
|
91
113
|
end
|
|
92
114
|
|
|
93
115
|
def association_entries(model_name, association_name)
|
|
@@ -97,8 +119,17 @@ module RubyLsp
|
|
|
97
119
|
constant_entries(association_model_name)
|
|
98
120
|
end
|
|
99
121
|
|
|
122
|
+
# Delegating a request to a disconnected client (ruby-lsp-rails NullClient)
|
|
123
|
+
# never produces a response, so read_response would block forever and the
|
|
124
|
+
# convention fallback would never run.
|
|
125
|
+
def rails_client_available?
|
|
126
|
+
return false unless rails_client
|
|
127
|
+
|
|
128
|
+
!rails_client.respond_to?(:connected?) || rails_client.connected?
|
|
129
|
+
end
|
|
130
|
+
|
|
100
131
|
def association_model_name(model_name, association_name)
|
|
101
|
-
return unless rails_client
|
|
132
|
+
return unless rails_client_available? && rails_client.respond_to?(:association_target)
|
|
102
133
|
|
|
103
134
|
result = rails_client.association_target(model_name: model_name, association_name: association_name)
|
|
104
135
|
response_name(result)
|
|
@@ -154,6 +185,7 @@ module RubyLsp
|
|
|
154
185
|
|
|
155
186
|
def entry_location(entry)
|
|
156
187
|
return entry.location if entry.respond_to?(:location)
|
|
188
|
+
|
|
157
189
|
entry.name_location if entry.respond_to?(:name_location)
|
|
158
190
|
end
|
|
159
191
|
|
|
@@ -171,7 +203,14 @@ module RubyLsp
|
|
|
171
203
|
end
|
|
172
204
|
|
|
173
205
|
def object_method_call?(node)
|
|
174
|
-
message(node) &&
|
|
206
|
+
message(node) && object_chain?(receiver(node))
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
def object_chain?(node)
|
|
210
|
+
return false unless node
|
|
211
|
+
return true if object_call?(node)
|
|
212
|
+
|
|
213
|
+
SELF_RETURNING_METHODS.include?(message(node)) && object_chain?(receiver(node))
|
|
175
214
|
end
|
|
176
215
|
|
|
177
216
|
def object_call?(node)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require "ruby_lsp/ruby_lsp_rails/server"
|
|
3
|
+
require "ruby_lsp/ruby_lsp_rails/server" unless defined?(::RubyLsp::Rails::ServerAddon)
|
|
4
4
|
|
|
5
5
|
module RubyLsp
|
|
6
6
|
module HasStateMachine
|
|
@@ -13,7 +13,7 @@ module RubyLsp
|
|
|
13
13
|
with_request_error_handling(request) do
|
|
14
14
|
case request
|
|
15
15
|
when "model_for_workflow_namespace"
|
|
16
|
-
send_result(model_for_workflow_namespace(params.fetch("workflow_namespace")))
|
|
16
|
+
send_result(model_for_workflow_namespace(params[:workflow_namespace] || params.fetch("workflow_namespace")))
|
|
17
17
|
else
|
|
18
18
|
raise NotImplementedError, "Unknown request: #{request}"
|
|
19
19
|
end
|
|
@@ -23,12 +23,24 @@ module RubyLsp
|
|
|
23
23
|
private
|
|
24
24
|
|
|
25
25
|
def model_for_workflow_namespace(workflow_namespace)
|
|
26
|
-
model = models_by_workflow_namespace[workflow_namespace]
|
|
26
|
+
model = conventional_model_for(workflow_namespace) || models_by_workflow_namespace[workflow_namespace]
|
|
27
27
|
return unless model
|
|
28
28
|
|
|
29
29
|
{name: model.name}
|
|
30
30
|
end
|
|
31
31
|
|
|
32
|
+
##
|
|
33
|
+
# Fast path: for the default "Workflow::<Model>" namespace, autoload just
|
|
34
|
+
# that one constant instead of eager loading the whole application. Only
|
|
35
|
+
# custom workflow_namespace configurations need the full scan below.
|
|
36
|
+
def conventional_model_for(workflow_namespace)
|
|
37
|
+
workflow_namespace = workflow_namespace.to_s
|
|
38
|
+
return unless workflow_namespace.start_with?("Workflow::")
|
|
39
|
+
|
|
40
|
+
model = workflow_namespace.delete_prefix("Workflow::").safe_constantize
|
|
41
|
+
model if model.try(:workflow_namespace) == workflow_namespace
|
|
42
|
+
end
|
|
43
|
+
|
|
32
44
|
def models_by_workflow_namespace
|
|
33
45
|
@models_by_workflow_namespace ||= active_record_models.each_with_object({}) do |model, index|
|
|
34
46
|
next unless model.respond_to?(:workflow_namespace)
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: has_state_machine
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.2.
|
|
4
|
+
version: 1.2.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Benjamin Hargett
|
|
@@ -31,9 +31,6 @@ dependencies:
|
|
|
31
31
|
- - ">="
|
|
32
32
|
- !ruby/object:Gem::Version
|
|
33
33
|
version: '1.5'
|
|
34
|
-
- - "<"
|
|
35
|
-
- !ruby/object:Gem::Version
|
|
36
|
-
version: '2.0'
|
|
37
34
|
type: :development
|
|
38
35
|
prerelease: false
|
|
39
36
|
version_requirements: !ruby/object:Gem::Requirement
|
|
@@ -41,9 +38,6 @@ dependencies:
|
|
|
41
38
|
- - ">="
|
|
42
39
|
- !ruby/object:Gem::Version
|
|
43
40
|
version: '1.5'
|
|
44
|
-
- - "<"
|
|
45
|
-
- !ruby/object:Gem::Version
|
|
46
|
-
version: '2.0'
|
|
47
41
|
- !ruby/object:Gem::Dependency
|
|
48
42
|
name: nokogiri
|
|
49
43
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -87,7 +81,21 @@ dependencies:
|
|
|
87
81
|
- !ruby/object:Gem::Version
|
|
88
82
|
version: '0'
|
|
89
83
|
- !ruby/object:Gem::Dependency
|
|
90
|
-
name:
|
|
84
|
+
name: rubocop
|
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
|
86
|
+
requirements:
|
|
87
|
+
- - "~>"
|
|
88
|
+
- !ruby/object:Gem::Version
|
|
89
|
+
version: '1.74'
|
|
90
|
+
type: :development
|
|
91
|
+
prerelease: false
|
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
93
|
+
requirements:
|
|
94
|
+
- - "~>"
|
|
95
|
+
- !ruby/object:Gem::Version
|
|
96
|
+
version: '1.74'
|
|
97
|
+
- !ruby/object:Gem::Dependency
|
|
98
|
+
name: rubocop-performance
|
|
91
99
|
requirement: !ruby/object:Gem::Requirement
|
|
92
100
|
requirements:
|
|
93
101
|
- - ">="
|
|
@@ -129,19 +137,19 @@ dependencies:
|
|
|
129
137
|
- !ruby/object:Gem::Version
|
|
130
138
|
version: '0'
|
|
131
139
|
- !ruby/object:Gem::Dependency
|
|
132
|
-
name:
|
|
140
|
+
name: rspec-rails
|
|
133
141
|
requirement: !ruby/object:Gem::Requirement
|
|
134
142
|
requirements:
|
|
135
|
-
- - "
|
|
143
|
+
- - ">="
|
|
136
144
|
- !ruby/object:Gem::Version
|
|
137
|
-
version: '
|
|
145
|
+
version: '6.1'
|
|
138
146
|
type: :development
|
|
139
147
|
prerelease: false
|
|
140
148
|
version_requirements: !ruby/object:Gem::Requirement
|
|
141
149
|
requirements:
|
|
142
|
-
- - "
|
|
150
|
+
- - ">="
|
|
143
151
|
- !ruby/object:Gem::Version
|
|
144
|
-
version: '
|
|
152
|
+
version: '6.1'
|
|
145
153
|
- !ruby/object:Gem::Dependency
|
|
146
154
|
name: ruby-lsp
|
|
147
155
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -170,6 +178,20 @@ dependencies:
|
|
|
170
178
|
- - ">="
|
|
171
179
|
- !ruby/object:Gem::Version
|
|
172
180
|
version: 0.3.17
|
|
181
|
+
- !ruby/object:Gem::Dependency
|
|
182
|
+
name: ruby-lsp-rspec
|
|
183
|
+
requirement: !ruby/object:Gem::Requirement
|
|
184
|
+
requirements:
|
|
185
|
+
- - ">="
|
|
186
|
+
- !ruby/object:Gem::Version
|
|
187
|
+
version: '0'
|
|
188
|
+
type: :development
|
|
189
|
+
prerelease: false
|
|
190
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
191
|
+
requirements:
|
|
192
|
+
- - ">="
|
|
193
|
+
- !ruby/object:Gem::Version
|
|
194
|
+
version: '0'
|
|
173
195
|
- !ruby/object:Gem::Dependency
|
|
174
196
|
name: base64
|
|
175
197
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -268,7 +290,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
268
290
|
- !ruby/object:Gem::Version
|
|
269
291
|
version: '0'
|
|
270
292
|
requirements: []
|
|
271
|
-
rubygems_version: 3.6.
|
|
293
|
+
rubygems_version: 3.6.9
|
|
272
294
|
specification_version: 4
|
|
273
295
|
summary: Class based state machine for ActiveRecord models.
|
|
274
296
|
test_files: []
|