test_tube 3.0.0 → 4.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3a1dbc9ba1ec31cf75bfc230ce4eecd83b8fdaa948b0dbaa0787579d659ad7ba
4
- data.tar.gz: f007123f4496bec8617bbc12be65b8b436c61afbead33d9a1f410dd906fdf6ae
3
+ metadata.gz: 62d9c394fa982a2c1465cfb2300ae0c00064abcd81a7fab01cc01997042bedfa
4
+ data.tar.gz: 21b3fa066f82dc567aace21b80a90d84cff94811db6cc81a56036ad3aa3b832b
5
5
  SHA512:
6
- metadata.gz: e95aa4c56a4d7f4de41056584c76f3734068f406a19991cef9b03da1f256e3e743db4a2fe4651241778686f916f206190ccae29fa93bc6a74b48f0adc3a85481
7
- data.tar.gz: 815b44987f0e28b5930a27930d1b089218b33b33bc32d7e66d4dce147d159699584986f979c1ed218b449da4d5d07e4ffe812d3edacd44c03f01d8dd6fe08170
6
+ metadata.gz: 9d2a2e6a4fdef3582048f3b864f7ea07463dbc62c16be1bc4d686a4ca959196137a07a4fd7180c413e60b6411970d931f96dab3de8653f82aec88825de02cc4e
7
+ data.tar.gz: a732a5e445fc21525dc230b6ed190c12d27bfd7df1e80a3a7022326f18382ae82e9e308c251826193874402d5c729711ff2492cb9c501fbec02cc3b1586c02cf
data/LICENSE.md CHANGED
@@ -1,6 +1,6 @@
1
1
  The MIT License (MIT)
2
2
 
3
- Copyright (c) 2021-2024 Cyril Kato
3
+ Copyright (c) 2021-2025 Cyril Kato
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
data/README.md CHANGED
@@ -2,11 +2,15 @@
2
2
 
3
3
  [![Version](https://img.shields.io/github/v/tag/fixrb/test_tube?label=Version&logo=github)](https://github.com/fixrb/test_tube/tags)
4
4
  [![Yard documentation](https://img.shields.io/badge/Yard-documentation-blue.svg?logo=github)](https://rubydoc.info/github/fixrb/test_tube/main)
5
- [![Ruby](https://github.com/fixrb/test_tube/workflows/Ruby/badge.svg?branch=main)](https://github.com/fixrb/test_tube/actions?query=workflow%3Aruby+branch%3Amain)
6
- [![RuboCop](https://github.com/fixrb/test_tube/workflows/RuboCop/badge.svg?branch=main)](https://github.com/fixrb/test_tube/actions?query=workflow%3Arubocop+branch%3Amain)
7
5
  [![License](https://img.shields.io/github/license/fixrb/test_tube?label=License&logo=github)](https://github.com/fixrb/test_tube/raw/main/LICENSE.md)
8
6
 
9
- > A test tube to conduct software experiments 🧪
7
+ > A test tube to conduct software experiments safely 🧪
8
+
9
+ TestTube is a Ruby library designed to safely execute and evaluate code experiments. It provides:
10
+ - Complete exception handling (including SystemExit and other system-level exceptions)
11
+ - A flexible matcher-based testing approach
12
+ - Two distinct testing methods: code execution (`invoke`) and value testing (`pass`)
13
+ - Clear experiment results with actual values, errors, and matcher results
10
14
 
11
15
  ![A researcher experimenting with Ruby code](https://github.com/fixrb/test_tube/raw/main/img/social-media-preview.png)
12
16
 
@@ -32,55 +36,55 @@ gem install test_tube
32
36
 
33
37
  ## Usage
34
38
 
35
- To make __TestTube__ available:
39
+ ### Basic Usage
40
+
41
+ First, make TestTube available:
36
42
 
37
43
  ```ruby
38
44
  require "test_tube"
39
45
  ```
40
46
 
41
- Assuming we'd like to experiment on the answer to the Ultimate Question of Life,
42
- the Universe, and Everything with the following matcher:
47
+ TestTube provides two main ways to conduct experiments:
48
+
49
+ 1. **Execute and test code** with `invoke`:
50
+ - Safely executes blocks of code
51
+ - Catches ALL exceptions, including system-level ones
52
+ - Perfect for testing potentially dangerous operations
53
+
54
+ 2. **Test direct values** with `pass`:
55
+ - Tests pre-computed values
56
+ - Simpler and more direct approach
57
+ - Ideal when you already have the value to test
58
+
59
+ ### Simple Example
60
+
61
+ Let's test if a value equals 42 using a custom matcher:
43
62
 
44
63
  ```ruby
45
64
  class BeTheAnswer
46
- def matches?
65
+ def match?
47
66
  42.equal?(yield)
48
67
  end
49
68
  end
50
- ```
51
-
52
- One possibility would be to `invoke` a whole block of code:
53
-
54
- ```ruby
55
- block_of_code = -> { "101010".to_i(2) }
56
-
57
- experiment = TestTube.invoke(matcher: BeTheAnswer.new, negate: false, &block_of_code)
58
- # => <TestTube actual=42 error=nil got=true>
59
69
 
70
+ # Using invoke to execute code
71
+ experiment = TestTube.invoke(matcher: BeTheAnswer.new, negate: false) do
72
+ "101010".to_i(2) # Converting binary to decimal
73
+ end
74
+ experiment.got # => true
60
75
  experiment.actual # => 42
61
76
  experiment.error # => nil
62
- experiment.got # => true
63
- ```
64
-
65
- An alternative would be to `pass` directly the actual value as a parameter:
66
-
67
- ```ruby
68
- actual_value = "101010".to_i(2)
69
-
70
- experiment = TestTube.pass(actual_value, matcher: BeTheAnswer.new, negate: false)
71
- # => <TestTube actual=42 error=nil got=true>
72
77
 
78
+ # Or using pass with a direct value
79
+ experiment = TestTube.pass(42, matcher: BeTheAnswer.new, negate: false)
80
+ experiment.got # => true
73
81
  experiment.actual # => 42
74
82
  experiment.error # => nil
75
- experiment.got # => true
76
83
  ```
77
84
 
78
- ### __Matchi__ matchers
85
+ ### Integration with Matchi
79
86
 
80
- To facilitate the addition of matchers, a collection is available via the
81
- [__Matchi__ project](https://github.com/fixrb/matchi/).
82
-
83
- Let's use a built-in __Matchi__ matcher:
87
+ TestTube works seamlessly with the [Matchi](https://github.com/fixrb/matchi/) matcher library:
84
88
 
85
89
  ```sh
86
90
  gem install matchi
@@ -88,50 +92,41 @@ gem install matchi
88
92
 
89
93
  ```ruby
90
94
  require "matchi"
91
- ```
92
-
93
- An example of successful experience:
94
95
 
95
- ```ruby
96
+ # Testing for exceptions
96
97
  experiment = TestTube.invoke(
97
98
  matcher: Matchi::RaiseException.new(:NoMethodError),
98
99
  negate: false
99
100
  ) { "foo".blank? }
100
- # => <TestTube actual=#<NoMethodError: undefined method `blank?' for "foo":String> error=nil got=true>
101
-
102
- experiment.actual # => #<NoMethodError: undefined method `blank?' for "foo":String>
103
- experiment.error # => nil
104
101
  experiment.got # => true
105
- ```
106
-
107
- Another example of an experiment that fails:
102
+ experiment.actual # => #<NoMethodError: undefined method `blank?' for "foo":String>
108
103
 
109
- ```ruby
104
+ # Testing floating-point arithmetic
110
105
  experiment = TestTube.invoke(
111
106
  matcher: Matchi::Be.new(0.3),
112
- negate: false,
113
- &-> { 0.1 + 0.2 }
114
- ) # => <TestTube actual=0.30000000000000004 error=nil got=false>
115
-
116
- experiment.actual # => 0.30000000000000004
117
- experiment.error # => nil
107
+ negate: false
108
+ ) { 0.1 + 0.2 }
118
109
  experiment.got # => false
119
- ```
120
-
121
- Finally, an experiment which causes an error:
110
+ experiment.actual # => 0.30000000000000004
122
111
 
123
- ```ruby
112
+ # Handling errors gracefully
124
113
  experiment = TestTube.invoke(
125
114
  matcher: Matchi::Match.new(/^foo$/),
126
115
  negate: false
127
116
  ) { BOOM }
128
- # => <TestTube actual=nil error=#<NameError: uninitialized constant BOOM> got=nil>
129
-
130
- experiment.actual # => nil
131
- experiment.error # => #<NameError: uninitialized constant BOOM>
132
117
  experiment.got # => nil
118
+ experiment.error # => #<NameError: uninitialized constant BOOM>
119
+ experiment.actual # => nil
133
120
  ```
134
121
 
122
+ ## Key Features
123
+
124
+ - **Safe Execution**: Catches all exceptions, including system-level ones
125
+ - **Flexible Testing**: Support for custom matchers and the Matchi library
126
+ - **Clear Results**: Easy access to actual values, errors, and test results
127
+ - **Two Testing Modes**: Choose between code execution and direct value testing
128
+ - **Framework Friendly**: Perfect for building testing frameworks and tools
129
+
135
130
  ## Contact
136
131
 
137
132
  * Source code: https://github.com/fixrb/test_tube
@@ -140,17 +135,12 @@ experiment.got # => nil
140
135
 
141
136
  ## Versioning
142
137
 
143
- __Test Tube__ follows [Semantic Versioning 2.0](https://semver.org/).
138
+ Test Tube follows [Semantic Versioning 2.0](https://semver.org/).
144
139
 
145
140
  ## License
146
141
 
147
142
  The [gem](https://rubygems.org/gems/test_tube) is available as open source under the terms of the [MIT License](https://github.com/fixrb/test_tube/raw/main/LICENSE.md).
148
143
 
149
- ---
144
+ ## Sponsors
150
145
 
151
- <p>
152
- This project is sponsored by:<br />
153
- <a href="https://sashite.com/"><img
154
- src="https://github.com/fixrb/test_tube/raw/main/img/sashite.png"
155
- alt="Sashité" /></a>
156
- </p>
146
+ This project is sponsored by [Sashité](https://sashite.com/)
@@ -0,0 +1,91 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TestTube
4
+ # Abstract class representing the state and result of a test experiment.
5
+ # This class inherits from BasicObject to provide a minimal interface
6
+ # and avoid any method conflicts with the objects being tested.
7
+ #
8
+ # It provides three main attributes:
9
+ # - actual: The value being tested
10
+ # - error: Any error that occurred during the test
11
+ # - got: The boolean result of the matcher
12
+ #
13
+ # @example Examining a test result
14
+ # experiment = TestTube.invoke(matcher: SomeMatcher.new, negate: false) { 42 }
15
+ # experiment.actual # => 42
16
+ # experiment.error # => nil
17
+ # experiment.got # => true
18
+ #
19
+ # @api private
20
+ class Experiment < ::BasicObject
21
+ # Expectation's actual value.
22
+ # This represents the value that was actually produced during the test,
23
+ # whether it came from a direct value (Passer) or a block execution (Invoker).
24
+ #
25
+ # @return [Object] The actual value being tested
26
+ # @return [nil] If an error occurred during the test
27
+ #
28
+ # @api public
29
+ attr_reader :actual
30
+
31
+ # Expectation's raised error.
32
+ # Stores any exception that occurred during the test execution,
33
+ # including system-level exceptions (SystemExit, SignalException, etc.)
34
+ # when using Invoker.
35
+ #
36
+ # @return [Exception, nil] Any error that occurred during the test
37
+ #
38
+ # @api public
39
+ attr_reader :error
40
+
41
+ # Expectation's returned boolean value.
42
+ # The result of applying the matcher to the actual value.
43
+ # Will be nil if an error occurred during the test.
44
+ #
45
+ # @return [Boolean] true if the matcher matched (considering negate)
46
+ # @return [nil] if an error occurred during the test
47
+ #
48
+ # @api public
49
+ attr_reader :got
50
+
51
+ # A string containing a human-readable representation of the experiment.
52
+ # Useful for debugging and logging test results.
53
+ #
54
+ # @example
55
+ # experiment.inspect
56
+ # # => "<TestTube actual=42 error=nil got=true>"
57
+ #
58
+ # @return [String] Human-readable representation of the experiment
59
+ #
60
+ # @api public
61
+ def inspect
62
+ "<TestTube actual=#{actual.inspect} error=#{error.inspect} got=#{got.inspect}>"
63
+ end
64
+
65
+ alias to_s inspect
66
+
67
+ private
68
+
69
+ # Validates that the provided matcher responds to match?.
70
+ # This is crucial as the matcher is the core of the testing mechanism.
71
+ #
72
+ # @param matcher [Object] The matcher to validate
73
+ # @raise [ArgumentError] If the matcher doesn't respond to match?
74
+ #
75
+ # @api private
76
+ def validate_matcher(matcher)
77
+ raise ::ArgumentError, "Matcher must respond to match?" unless matcher.respond_to?(:match?)
78
+ end
79
+
80
+ # Validates that the negate parameter is strictly boolean.
81
+ # This ensures predictable test behavior.
82
+ #
83
+ # @param negate [Object] The value to validate
84
+ # @raise [ArgumentError] If the value isn't true or false
85
+ #
86
+ # @api private
87
+ def validate_negate(negate)
88
+ raise ::ArgumentError, "negate must be boolean" unless [true, false].include?(negate)
89
+ end
90
+ end
91
+ end
@@ -2,40 +2,78 @@
2
2
 
3
3
  require "defi/method"
4
4
 
5
- require_relative "base"
5
+ require_relative "experiment"
6
6
 
7
7
  module TestTube
8
8
  # Evaluate an actual value invoking it with #call method.
9
+ # This class is designed to handle ALL possible exceptions during test execution,
10
+ # including system-level exceptions. This is crucial for testing frameworks to:
11
+ # - Capture system exceptions (SystemExit, SignalException, etc.)
12
+ # - Prevent test suite interruption through exit calls
13
+ # - Ensure complete control over the test execution flow
14
+ # - Allow proper reporting of all types of failures
15
+ #
16
+ # @example Handling a system exit
17
+ # TestTube.invoke(matcher: SomeExitMatcher.new, negate: false) do
18
+ # exit(true) # Will be caught and handled properly
19
+ # end
9
20
  #
10
21
  # @api private
11
- class Invoker < Base
12
- # rubocop:disable Lint/RescueException
13
-
22
+ class Invoker < Experiment
14
23
  # Class initializer.
15
24
  #
16
- # @param matcher [#matches?] A matcher.
17
- # @param negate [Boolean] Invert the matcher or not.
18
- # @param input [Proc] The callable object to test.
25
+ # @param matcher [#match?] The matcher to evaluate the result
26
+ # @param negate [Boolean] Whether to invert the matcher result
27
+ # @param input [Proc] The callable object to test
28
+ # @raise [ArgumentError] If the matcher doesn't respond to match?
19
29
  def initialize(matcher:, negate:, &input)
30
+ validate_matcher(matcher)
31
+ validate_negate(negate)
20
32
  super()
33
+ perform_experiment(matcher, negate, input)
34
+ end
35
+
36
+ private
37
+
38
+ # Executes the experiment and handles any exceptions.
39
+ # Deliberately catches ALL exceptions (including system exceptions) to ensure
40
+ # complete control over the test execution flow.
41
+ #
42
+ # @param matcher [#match?] The matcher to evaluate the result
43
+ # @param negate [Boolean] Whether to invert the matcher result
44
+ # @param input [Proc] The code block to execute
45
+ def perform_experiment(matcher, negate, input)
46
+ @got = evaluate_match(matcher, negate, input)
47
+ rescue ::Exception => e # rubocop:disable Lint/RescueException
48
+ handle_exception(e)
49
+ end
21
50
 
22
- @got = negate ^ matcher.matches? do
51
+ # Evaluates the match result and handles the actual execution of the test code.
52
+ #
53
+ # @param matcher [#match?] The matcher to evaluate the result
54
+ # @param negate [Boolean] Whether to invert the matcher result
55
+ # @param input [Proc] The code block to execute
56
+ # @return [Boolean] The result of the matcher evaluation
57
+ def evaluate_match(matcher, negate, input)
58
+ negate ^ matcher.match? do
23
59
  value = send_call.to(input)
24
60
  @actual = value.object
25
61
  value.call
26
62
  end
27
- rescue ::Exception => e
28
- @actual = nil
29
- @error = e
30
63
  end
31
64
 
32
- # rubocop:enable Lint/RescueException
33
-
34
- private
65
+ # Handles any exception that occurs during the experiment execution.
66
+ # Sets the actual value to nil and stores the exception.
67
+ #
68
+ # @param error [Exception] The exception that was raised
69
+ def handle_exception(error)
70
+ @actual = nil
71
+ @error = error
72
+ end
35
73
 
36
74
  # @return [::Defi::Method] The challenge for the callable object.
37
75
  #
38
- # @see https://github.com/fixrb/defi/blob/v3.0.0/lib/defi/method.rb
76
+ # @see https://github.com/fixrb/defi/blob/v3.0.1/lib/defi/method.rb
39
77
  def send_call
40
78
  ::Defi::Method.new(:call)
41
79
  end
@@ -1,22 +1,35 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "base"
3
+ require_relative "experiment"
4
4
 
5
5
  module TestTube
6
6
  # Evaluate an actual value passed in parameter.
7
+ # Unlike Invoker, this class handles direct value testing without executing a block,
8
+ # making it safer when you already have the value to test.
9
+ #
10
+ # @example Testing a direct value
11
+ # TestTube.pass("101010".to_i(2),
12
+ # matcher: BeTheAnswer.new,
13
+ # negate: false
14
+ # )
7
15
  #
8
16
  # @api private
9
- class Passer < Base
17
+ class Passer < Experiment
10
18
  # Class initializer.
19
+ # Validates the matcher and negate parameter before performing the test.
20
+ # Since no code block is executed, this approach is immune to system-level
21
+ # exceptions that might occur during value computation.
11
22
  #
12
- # @param input [#object_id] The actual value to test.
13
- # @param matcher [#matches?] A matcher.
14
- # @param negate [Boolean] Invert the matcher or not.
23
+ # @param input [Object] The actual value to test
24
+ # @param matcher [#match?] The matcher to evaluate the result
25
+ # @param negate [Boolean] Whether to invert the matcher result
26
+ # @raise [ArgumentError] If the matcher doesn't respond to match?
15
27
  def initialize(input, matcher:, negate:)
28
+ validate_matcher(matcher)
29
+ validate_negate(negate)
16
30
  super()
17
-
18
31
  @actual = input
19
- @got = negate ^ matcher.matches? { input }
32
+ @got = negate ^ matcher.match? { input }
20
33
  end
21
34
  end
22
35
  end
data/lib/test_tube.rb CHANGED
@@ -4,51 +4,82 @@ require_relative File.join("test_tube", "invoker")
4
4
  require_relative File.join("test_tube", "passer")
5
5
 
6
6
  # Namespace for the TestTube library.
7
+ # This library provides two main methods for conducting software experiments:
8
+ # - invoke: For testing blocks of code, with full exception handling
9
+ # - pass: For testing direct values, with a simpler and safer approach
10
+ #
11
+ # @example Using with a testing framework
12
+ # require "test_tube"
13
+ # require "matchi"
14
+ #
15
+ # # Testing for exceptions
16
+ # TestTube.invoke(matcher: Matchi::RaiseException.new(SystemExit), negate: false) do
17
+ # exit(true) # Safely catches the SystemExit
18
+ # end
19
+ #
20
+ # # Testing direct values
21
+ # TestTube.pass(42, matcher: Matchi::EqualTo.new(42), negate: false)
7
22
  #
8
23
  # @api public
9
24
  module TestTube
10
- # @param matcher [#matches?] A matcher.
11
- # @param negate [Boolean] Invert the matcher or not.
12
- # @param input [Proc] The callable object to test.
25
+ # Invokes a block for testing.
26
+ # This method should be used when you need to:
27
+ # - Execute and test a block of code
28
+ # - Catch all possible exceptions (including SystemExit)
29
+ # - Handle potentially dangerous operations safely
30
+ #
31
+ # @see TestTube::Invoker#initialize for parameter details
13
32
  #
14
- # @example
33
+ # @example Testing computation result
15
34
  # require "test_tube"
16
35
  #
17
36
  # class BeTheAnswer
18
- # def matches?
37
+ # def match?
19
38
  # 42.equal?(yield)
20
39
  # end
21
40
  # end
22
41
  #
23
- # TestTube.invoke(matcher: BeTheAnswer.new, negate: false) do
42
+ # experiment = TestTube.invoke(matcher: BeTheAnswer.new, negate: false) do
24
43
  # "101010".to_i(2)
25
44
  # end
26
45
  #
27
- # @return [Invoker] A software experiment.
28
- def self.invoke(matcher:, negate:, &input)
29
- Invoker.new(matcher:, negate:, &input)
46
+ # experiment.actual # => 42
47
+ # experiment.error # => nil
48
+ # experiment.got # => true
49
+ #
50
+ # @return [TestTube::Invoker] A software experiment capturing execution results and any errors
51
+ def self.invoke(...)
52
+ Invoker.new(...)
30
53
  end
31
54
 
32
- # @param input [#object_id] The actual value to test.
33
- # @param matcher [#matches?] A matcher.
34
- # @param negate [Boolean] Invert the matcher or not.
55
+ # Tests a value directly.
56
+ # This method should be used when you:
57
+ # - Already have the value to test
58
+ # - Don't need to execute potentially dangerous code
59
+ # - Want a simpler and more direct testing approach
60
+ #
61
+ # @see TestTube::Passer#initialize for parameter details
35
62
  #
36
- # @example
63
+ # @example Testing a direct value
37
64
  # require "test_tube"
38
65
  #
39
66
  # class BeTheAnswer
40
- # def matches?
67
+ # def match?
41
68
  # 42.equal?(yield)
42
69
  # end
43
70
  # end
44
71
  #
45
- # TestTube.pass("101010".to_i(2),
72
+ # experiment = TestTube.pass("101010".to_i(2),
46
73
  # matcher: BeTheAnswer.new,
47
74
  # negate: false
48
75
  # )
49
76
  #
50
- # @return [Passer] A software experiment.
51
- def self.pass(input, matcher:, negate:)
52
- Passer.new(input, matcher:, negate:)
77
+ # experiment.actual # => 42
78
+ # experiment.error # => nil
79
+ # experiment.got # => true
80
+ #
81
+ # @return [TestTube::Passer] A software experiment representing the test result
82
+ def self.pass(...)
83
+ Passer.new(...)
53
84
  end
54
85
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: test_tube
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.0
4
+ version: 4.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Cyril Kato
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-01-25 00:00:00.000000000 Z
11
+ date: 2024-12-31 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: defi
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: 3.0.0
19
+ version: 3.0.1
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: 3.0.0
26
+ version: 3.0.1
27
27
  description: "A test tube to conduct software experiments \U0001F9EA"
28
28
  email: contact@cyril.email
29
29
  executables: []
@@ -33,7 +33,7 @@ files:
33
33
  - LICENSE.md
34
34
  - README.md
35
35
  - lib/test_tube.rb
36
- - lib/test_tube/base.rb
36
+ - lib/test_tube/experiment.rb
37
37
  - lib/test_tube/invoker.rb
38
38
  - lib/test_tube/passer.rb
39
39
  homepage: https://github.com/fixrb/test_tube
@@ -41,7 +41,7 @@ licenses:
41
41
  - MIT
42
42
  metadata:
43
43
  rubygems_mfa_required: 'true'
44
- post_install_message:
44
+ post_install_message:
45
45
  rdoc_options: []
46
46
  require_paths:
47
47
  - lib
@@ -49,15 +49,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
49
49
  requirements:
50
50
  - - ">="
51
51
  - !ruby/object:Gem::Version
52
- version: 3.2.0
52
+ version: 3.1.0
53
53
  required_rubygems_version: !ruby/object:Gem::Requirement
54
54
  requirements:
55
55
  - - ">="
56
56
  - !ruby/object:Gem::Version
57
57
  version: '0'
58
58
  requirements: []
59
- rubygems_version: 3.4.19
60
- signing_key:
59
+ rubygems_version: 3.3.27
60
+ signing_key:
61
61
  specification_version: 4
62
62
  summary: "A test tube to conduct software experiments \U0001F9EA"
63
63
  test_files: []
@@ -1,40 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module TestTube
4
- # Abstract class representing the state of an experiment.
5
- #
6
- # @api private
7
- class Base < ::BasicObject
8
- # Expectation's actual value.
9
- #
10
- # @return [#object_id] The actual value.
11
- #
12
- # @api public
13
- attr_reader :actual
14
-
15
- # Expectation's raised error.
16
- #
17
- # @return [Exception, nil] The raised error.
18
- #
19
- # @api public
20
- attr_reader :error
21
-
22
- # Expectation's returned boolean value.
23
- #
24
- # @return [Boolean, nil] The returned boolean value.
25
- #
26
- # @api public
27
- attr_reader :got
28
-
29
- # A string containing a human-readable representation of the experiment.
30
- #
31
- # @return [String] The human-readable representation of the experiment.
32
- #
33
- # @api public
34
- def inspect
35
- "<TestTube actual=#{actual.inspect} error=#{error.inspect} got=#{got.inspect}>"
36
- end
37
-
38
- alias to_s inspect
39
- end
40
- end