test_tube 3.0.0 → 4.0.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 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