transition_through 1.0.0.pre.beta.1

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -0,0 +1,7 @@
1
+ # Changelog
2
+
3
+ ## [Unreleased]
4
+
5
+ ## v1.0.0
6
+
7
+ Initial release.
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
+ [![CI](https://github.com/keygen-sh/transition_through/actions/workflows/test.yml/badge.svg)](https://github.com/keygen-sh/transition_through/actions)
4
+ [![Gem Version](https://badge.fury.io/rb/transition_through.svg)](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,8 @@
1
+ # Security Policy
2
+
3
+ ## Reporting a vulnerability
4
+
5
+ If you find a vulnerability in `transition_through`, please contact Keygen via
6
+ [email](mailto:security@keygen.sh).
7
+
8
+ You will be given public credit for your disclosure.
@@ -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 'matcher'
4
+
5
+ module TransitionThrough
6
+ module Methods
7
+ def transition(&block) = Matcher.new(block)
8
+ end
9
+ end
10
+
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TransitionThrough
4
+ VERSION = '1.0.0-beta.1'
5
+ end
@@ -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: []