transition_through 1.0.0.pre.beta.1
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 +7 -0
- data/CHANGELOG.md +7 -0
- data/CONTRIBUTING.md +33 -0
- data/LICENSE +20 -0
- data/README.md +64 -0
- data/SECURITY.md +8 -0
- data/lib/transition_through/expression.rb +39 -0
- data/lib/transition_through/matcher.rb +77 -0
- data/lib/transition_through/methods.rb +10 -0
- data/lib/transition_through/version.rb +5 -0
- data/lib/transition_through.rb +10 -0
- metadata +125 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 245765e994574db116dd542c12e40bd84fe6487f130f647761fc542a19745b45
|
4
|
+
data.tar.gz: fd51b8b84f3c552abb310b6e8912c657449474b80e481f05d4f08b5eb8bca266
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 9b671d76bcece48f74db7248870a0182b841dc52484007802128d727a5ea2d5d075f66b202953450c19207527d99a88d70d0ebf481d0e999c99d049e0d8f3007
|
7
|
+
data.tar.gz: ca866a6ef2d58f7ca14c9b4a46218e445dd205c3df0f42f7170044127fb8de43cf4818edf1bb1bd68b1fb57dbcd4f72699c7ce4c52a7eb1fb0ca242114ffda77
|
data/CHANGELOG.md
ADDED
data/CONTRIBUTING.md
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
## Security issues
|
2
|
+
|
3
|
+
If you have found a security related issue, please do not file an issue on
|
4
|
+
GitHub or send a PR addressing the issue. Contact [Keygen](mailto:security@keygen.sh)
|
5
|
+
directly. You will be given public credit for your disclosure.
|
6
|
+
|
7
|
+
## Reporting issues
|
8
|
+
|
9
|
+
Please try to answer the following questions in your bug report:
|
10
|
+
|
11
|
+
- What did you do?
|
12
|
+
- What did you expect to happen?
|
13
|
+
- What happened instead?
|
14
|
+
|
15
|
+
Make sure to include as much relevant information as possible. Ruby version,
|
16
|
+
Rails version, `transition_through` version, OS version and any stack traces
|
17
|
+
you have are very valuable.
|
18
|
+
|
19
|
+
## Pull Requests
|
20
|
+
|
21
|
+
- **Add tests!** Your patch won't be accepted if it doesn't have tests.
|
22
|
+
|
23
|
+
- **Document any change in behaviour**. Make sure the README and any other
|
24
|
+
relevant documentation are kept up-to-date.
|
25
|
+
|
26
|
+
- **Create topic branches**. Please don't ask us to pull from your master branch.
|
27
|
+
|
28
|
+
- **One pull request per feature**. If you want to do more than one thing, send
|
29
|
+
multiple pull requests.
|
30
|
+
|
31
|
+
- **Send coherent history**. Make sure each individual commit in your pull
|
32
|
+
request is meaningful. If you had to make multiple intermediate commits while
|
33
|
+
developing, please squash them before sending them to us.
|
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright 2024 Keygen LLC
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
# transition_through
|
2
|
+
|
3
|
+
[](https://github.com/keygen-sh/transition_through/actions)
|
4
|
+
[](https://badge.fury.io/rb/transition_through)
|
5
|
+
|
6
|
+
Assert state changes in sequence. Like `change { ... }`, but for asserting
|
7
|
+
multiple changes in RSpec.
|
8
|
+
|
9
|
+
Sponsored by:
|
10
|
+
|
11
|
+
<a href="https://keygen.sh?ref=transition_through">
|
12
|
+
<div>
|
13
|
+
<img src="https://keygen.sh/images/logo-pill.png" width="200" alt="Keygen">
|
14
|
+
</div>
|
15
|
+
</a>
|
16
|
+
|
17
|
+
_A fair source software licensing and distribution API._
|
18
|
+
|
19
|
+
## Installation
|
20
|
+
|
21
|
+
Add this line to your application's `Gemfile`:
|
22
|
+
|
23
|
+
```ruby
|
24
|
+
gem 'transition_through'
|
25
|
+
```
|
26
|
+
|
27
|
+
And then execute:
|
28
|
+
|
29
|
+
```bash
|
30
|
+
$ bundle
|
31
|
+
```
|
32
|
+
|
33
|
+
Or install it yourself as:
|
34
|
+
|
35
|
+
```bash
|
36
|
+
$ gem install transition_through
|
37
|
+
```
|
38
|
+
|
39
|
+
## Usage
|
40
|
+
|
41
|
+
```ruby
|
42
|
+
it 'should transition through' do
|
43
|
+
expect { counter.increment(3) }.to transition { counter.count }.through 0..3
|
44
|
+
end
|
45
|
+
```
|
46
|
+
|
47
|
+
## Supported Rubies
|
48
|
+
|
49
|
+
**`transition_through` supports Ruby 3.1 and above.** We encourage you to upgrade
|
50
|
+
if you're on an older version. Ruby 3 provides a lot of great features, like
|
51
|
+
better pattern matching and a new shorthand hash syntax.
|
52
|
+
|
53
|
+
## Is it any good?
|
54
|
+
|
55
|
+
Yes.
|
56
|
+
|
57
|
+
## Contributing
|
58
|
+
|
59
|
+
If you have an idea, or have discovered a bug, please open an issue or create a
|
60
|
+
pull request.
|
61
|
+
|
62
|
+
## License
|
63
|
+
|
64
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/SECURITY.md
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'prism'
|
4
|
+
|
5
|
+
module TransitionThrough
|
6
|
+
##
|
7
|
+
# TransitionExpression walks a Prism AST until we find a transition expression, e.g.:
|
8
|
+
#
|
9
|
+
# expect { ... }.to transition { ... }.through [...]
|
10
|
+
#
|
11
|
+
# Returns the transition state in the transition block as a Result.
|
12
|
+
class Expression < Prism::Visitor
|
13
|
+
attr_reader :at, :result
|
14
|
+
|
15
|
+
def initialize(at:) = @at = at
|
16
|
+
|
17
|
+
# FIXME(ezekg) right now this only supports simple expressions, e.g. object.foo not object.foo(1).bar.
|
18
|
+
def visit_call_node(node)
|
19
|
+
case node
|
20
|
+
in name: :transition, block: Prism::BlockNode(body: Prism::Node(body: [Prism::CallNode(receiver:, name: method_name)]), location:) if location.start_line == at
|
21
|
+
@result = Result.new(receiver:, method_name:)
|
22
|
+
else
|
23
|
+
super
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
class Result
|
30
|
+
attr_reader :receiver, :method_name
|
31
|
+
|
32
|
+
def initialize(receiver:, method_name:)
|
33
|
+
@receiver = receiver
|
34
|
+
@method_name = method_name
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
@@ -0,0 +1,77 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rspec'
|
4
|
+
require 'rspec/mocks/standalone'
|
5
|
+
|
6
|
+
require_relative 'expression'
|
7
|
+
|
8
|
+
module TransitionThrough
|
9
|
+
class Matcher
|
10
|
+
include RSpec::Matchers, RSpec::Matchers::Composable, RSpec::Mocks::ExampleMethods
|
11
|
+
|
12
|
+
attr_reader :state_block
|
13
|
+
|
14
|
+
def initialize(state_block)
|
15
|
+
@state_block = state_block
|
16
|
+
@expected_states = []
|
17
|
+
@actual_states = []
|
18
|
+
end
|
19
|
+
|
20
|
+
def supports_block_expectations? = true
|
21
|
+
def matches?(expect_block)
|
22
|
+
path, start_line = state_block.source_location
|
23
|
+
|
24
|
+
# walk the ast until we find our transition expression
|
25
|
+
exp = Expression.new(at: start_line)
|
26
|
+
ast = Prism.parse_file(path)
|
27
|
+
|
28
|
+
ast.value.accept(exp)
|
29
|
+
|
30
|
+
# raise if the expression is empty
|
31
|
+
raise InvalidExpressionError if
|
32
|
+
exp.result.nil? || exp.result.receiver.nil? || exp.result.method_name.nil?
|
33
|
+
|
34
|
+
# get the actual transitioning object from the state block's binding
|
35
|
+
receiver = state_block.binding.eval(exp.result.receiver.name.to_s)
|
36
|
+
|
37
|
+
raise InvalidExpressionError unless
|
38
|
+
receiver.respond_to?(:"#{exp.result.method_name}=") &&
|
39
|
+
receiver.respond_to?(exp.result.method_name)
|
40
|
+
|
41
|
+
# get the receiver's methods for stubbing
|
42
|
+
setter = receiver.method(:"#{exp.result.method_name}=")
|
43
|
+
getter = receiver.method(exp.result.method_name)
|
44
|
+
|
45
|
+
# record initial state via getter
|
46
|
+
@expected_states = @actual_states = [getter.call]
|
47
|
+
|
48
|
+
# stub the setter so that we can track state transitions
|
49
|
+
allow(receiver).to receive(setter.name) do |value|
|
50
|
+
@actual_states << value
|
51
|
+
|
52
|
+
setter.call(value)
|
53
|
+
end
|
54
|
+
|
55
|
+
# call the expect block
|
56
|
+
expect_block.call
|
57
|
+
|
58
|
+
# assert states match
|
59
|
+
@actual_states == @expected_states
|
60
|
+
end
|
61
|
+
|
62
|
+
def through(*values)
|
63
|
+
@expected_states = values.flatten(1)
|
64
|
+
|
65
|
+
self
|
66
|
+
end
|
67
|
+
|
68
|
+
def failure_message
|
69
|
+
"expected block to transition through #{@expected_states.inspect} but it transitioned through #{@actual_states.inspect}"
|
70
|
+
end
|
71
|
+
|
72
|
+
def failure_message_when_negated
|
73
|
+
"expected block not to transition through #{@expected_states.inspect} but it did"
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
@@ -0,0 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'transition_through/version'
|
4
|
+
require_relative 'transition_through/expression'
|
5
|
+
require_relative 'transition_through/matcher'
|
6
|
+
require_relative 'transition_through/methods'
|
7
|
+
|
8
|
+
module TransitionThrough
|
9
|
+
class InvalidExpressionError < StandardError; end
|
10
|
+
end
|
metadata
ADDED
@@ -0,0 +1,125 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: transition_through
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0.pre.beta.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Zeke Gabrielse
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2024-08-14 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rails
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '6.0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '6.0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rspec-rails
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: temporary_tables
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '1.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '1.0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: sqlite3
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '1.4'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '1.4'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: prism
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
description: Assert state changes through multiple values for an object, enabling
|
84
|
+
you to test complex state transitions in sequence.
|
85
|
+
email:
|
86
|
+
- oss@keygen.sh
|
87
|
+
executables: []
|
88
|
+
extensions: []
|
89
|
+
extra_rdoc_files: []
|
90
|
+
files:
|
91
|
+
- CHANGELOG.md
|
92
|
+
- CONTRIBUTING.md
|
93
|
+
- LICENSE
|
94
|
+
- README.md
|
95
|
+
- SECURITY.md
|
96
|
+
- lib/transition_through.rb
|
97
|
+
- lib/transition_through/expression.rb
|
98
|
+
- lib/transition_through/matcher.rb
|
99
|
+
- lib/transition_through/methods.rb
|
100
|
+
- lib/transition_through/version.rb
|
101
|
+
homepage: https://github.com/keygen-sh/transition_through
|
102
|
+
licenses:
|
103
|
+
- MIT
|
104
|
+
metadata: {}
|
105
|
+
post_install_message:
|
106
|
+
rdoc_options: []
|
107
|
+
require_paths:
|
108
|
+
- lib
|
109
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
110
|
+
requirements:
|
111
|
+
- - ">="
|
112
|
+
- !ruby/object:Gem::Version
|
113
|
+
version: '3.1'
|
114
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
115
|
+
requirements:
|
116
|
+
- - ">"
|
117
|
+
- !ruby/object:Gem::Version
|
118
|
+
version: 1.3.1
|
119
|
+
requirements: []
|
120
|
+
rubygems_version: 3.4.13
|
121
|
+
signing_key:
|
122
|
+
specification_version: 4
|
123
|
+
summary: Assert state changes in sequence. Like change{}, but for asserting multiple
|
124
|
+
changes in RSpec.
|
125
|
+
test_files: []
|