Skip to content

Commit

Permalink
Initial implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
svoop committed Aug 23, 2023
0 parents commit 198364a
Show file tree
Hide file tree
Showing 26 changed files with 577 additions and 0 deletions.
21 changes: 21 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
name: Test
on: [push, pull_request]
jobs:
test:
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest]
ruby: ['3.0', '3.1', '3.2']
name: test (Ruby ${{ matrix.ruby }} on ${{ matrix.os }})
runs-on: ${{ matrix.os }}
steps:
- name: Check out
uses: actions/checkout@v3
- name: Set up Ruby ${{ matrix.ruby }}
uses: ruby/setup-ruby@v1
with:
ruby-version: ${{ matrix.ruby }}
bundler-cache: true
- name: Run tests
run: bundle exec rake
18 changes: 18 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# macOS
.DS_Store

# direnv
.direnv
.envrc

# Editors
.nova
.vscode
*.sublime*

# Ruby
gems.locked
pkg/*
*.gem
.bundle
.yardoc
1 change: 1 addition & 0 deletions .ruby-version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
3.2
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
## Main

#### Initial Implementation
* Require Ruby 3.0
* Substitution of instance variables
* Substitution of global variables
* Helper for Minitest spec notation
22 changes: 22 additions & 0 deletions LICENSE.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
Copyright (c) 2013 Sven Schwyn

MIT License

Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
145 changes: 145 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
[![Version](https://img.shields.io/gem/v/minitest-substitute.svg?style=flat)](https://rubygems.org/gems/minitest-substitute)
[![Tests](https://img.shields.io/github/actions/workflow/status/svoop/minitest-substitute/test.yml?style=flat&label=tests)](https://github.com/svoop/minitest-substitute/actions?workflow=Test)
[![Code Climate](https://img.shields.io/codeclimate/maintainability/svoop/minitest-substitute.svg?style=flat)](https://codeclimate.com/github/svoop/minitest-substitute/)
[![Donorbox](https://img.shields.io/badge/donate-on_donorbox-yellow.svg)](https://donorbox.org/bitcetera)

# Minitest::Substitute

Simple Minitest helper to replace values such as an instance variable of an object or an environment variable for the duration of a block or a group of tests.

This comes in very handy when you have to derive from default configuration in order to test some aspects of your code.

* [Homepage](https://github.com/svoop/minitest-substitute)
* [API](https://www.rubydoc.info/gems/minitest-substitute)
* Author: [Sven Schwyn - Bitcetera](https://bitcetera.com)

## Install

This gem is [cryptographically signed](https://guides.rubygems.org/security/#using-gems) in order to assure it hasn't been tampered with. Unless already done, please add the author's public key as a trusted certificate now:

```
gem cert --add <(curl -Ls https://raw.github.com/svoop/minitest-substitute/main/certs/svoop.pem)
```

Add the following to the <tt>Gemfile</tt> or <tt>gems.rb</tt> of your [Bundler](https://bundler.io) powered Ruby project:

```ruby
gem 'minitest-substitute'
```

And then install the bundle:

```
bundle install --trust-policy MediumSecurity
```

Finally, require this gem in your `test_helper.rb` or `spec_helper.rb`:

```ruby
require 'minitest/substitute'
```

## Usage

This lightweight gem implements features on a "as needed" basis, as of now:

* substitution of instance variables
* substitution of global variables

Please [create an issue describing your use case](https://github.com/svoop/minitest-substitute/issues) in case you need more features such as the substitution of class variables or substitution via accessor methods.

### Block

To substitute the value of an instance variable for the duration of a block:

```ruby
class Config
def initialize
@version = 1
end
end

Config.instance_variable_get('@version') # => 1
with '@version', 2, on: Config do
Config.instance_variable_get('@version') # => 2
end
Config.instance_variable_get('@version') # => 1
```

Same goes for global variables:

```ruby
$verbose = false # => false
with '$verbose', true do
$verbose # => true
end
$verbose # => false
```

And it works for hashes as well which comes in handy when you have to temporarily override the value of an environment variable:

```ruby
ENV['EDITOR'] # => 'vi'
with "ENV['EDITOR']", 'nano' do
ENV['EDITOR'] # => 'nano'
end
ENV['EDITOR'] # => 'vi'
```

### Group of Tests

When using spec notation, you can change a value for all tests within a `describe` group:

```ruby
class Config
def initialize
@version = 1
end
end

describe Config do
subject do
Config.new
end

describe 'original version' do
it "returns the original version" do
_(subject.instance_variable_get('@version')).must_equal 1
end
end

describe 'sustituted version' do
with '@version', 2, on: Config

it "returns the substituted version" do
_(subject.instance_variable_get('@version')).must_equal 2
end
end
end
```

For consistency with other Minitest helpers, the following alternative does exactly the same:

```ruby
with '@version', on: Config do
2
end
```

(The spec integration is borrowed from [minitest-around](https://rubygems.org/gems/minitest-around) for elegance and compatibility.)

## Development

To install the development dependencies and then run the test suite:

```
bundle install
bundle exec rake # run tests once
bundle exec guard # run tests whenever files are modified
```

You're welcome to [submit issues](https://github.com/svoop/minitest-substitute/issues) and contribute code by [forking the project and submitting pull requests](https://docs.github.com/en/get-started/quickstart/fork-a-repo).

## License

The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
11 changes: 11 additions & 0 deletions bin/console
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#!/usr/bin/env ruby
# frozen_string_literal: true

require "bundler/setup"
require "minitest/substitute"

# You can add fixtures and/or initialization code here to make experimenting
# with your gem easier. You can also use a different console, if you like.

require "irb"
IRB.start(__FILE__)
8 changes: 8 additions & 0 deletions bin/setup
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#!/usr/bin/env bash
set -euo pipefail
IFS=$'\n\t'
set -vx

bundle install

# Do any other automated setup that you need to do here
20 changes: 20 additions & 0 deletions certs/svoop.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
-----BEGIN CERTIFICATE-----
MIIDODCCAiCgAwIBAgIBATANBgkqhkiG9w0BAQsFADAjMSEwHwYDVQQDDBhydWJ5
L0RDPWJpdGNldGVyYS9EQz1jb20wHhcNMjIxMTA2MTIzNjUwWhcNMjMxMTA2MTIz
NjUwWjAjMSEwHwYDVQQDDBhydWJ5L0RDPWJpdGNldGVyYS9EQz1jb20wggEiMA0G
CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDcLg+IHjXYaUlTSU7R235lQKD8ZhEe
KMhoGlSUonZ/zo1OT3KXcqTCP1iMX743xYs6upEGALCWWwq+nxvlDdnWRjF3AAv7
ikC+Z2BEowjyeCCT/0gvn4ohKcR0JOzzRaIlFUVInlGSAHx2QHZ2N8ntf54lu7nd
L8CiDK8rClsY4JBNGOgH9UC81f+m61UUQuTLxyM2CXfAYkj/sGNTvFRJcNX+nfdC
hM9r2kH1+7wsa8yG7wJ2IkrzNACD8v84oE6qVusN8OLEMUI/NaEPVPbw2LUM149H
PVa0i729A4IhroNnFNmw4wOC93ARNbM1+LW36PLMmKjKudf5Exg8VmDVAgMBAAGj
dzB1MAkGA1UdEwQCMAAwCwYDVR0PBAQDAgSwMB0GA1UdDgQWBBSfK8MtR62mQ6oN
yoX/VKJzFjLSVDAdBgNVHREEFjAUgRJydWJ5QGJpdGNldGVyYS5jb20wHQYDVR0S
BBYwFIEScnVieUBiaXRjZXRlcmEuY29tMA0GCSqGSIb3DQEBCwUAA4IBAQAYG2na
ye8OE2DANQIFM/xDos/E4DaPWCJjX5xvFKNKHMCeQYPeZvLICCwyw2paE7Otwk6p
uvbg2Ks5ykXsbk5i6vxDoeeOLvmxCqI6m+tHb8v7VZtmwRJm8so0eSX0WvTaKnIf
CAn1bVUggczVdNoBXw9WAILKyw9bvh3Ft740XZrR74sd+m2pGwjCaM8hzLvrVbGP
DyYhlBeRWyQKQ0WDIsiTSRhzK8HwSTUWjvPwx7SEdIU/HZgyrk0ETObKPakVu6bH
kAyiRqgxF4dJviwtqI7mZIomWL63+kXLgjOjMe1SHxfIPo/0ji6+r1p4KYa7o41v
fwIwU1MKlFBdsjkd
-----END CERTIFICATE-----
1 change: 1 addition & 0 deletions checksums/minitest-flash-0.1.0.gem.sha512
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
c240bed743a19830b5eeeb6682ff03b00944e13dd24ffdbd31810fd2e9f870c9039cfdef37d055053770e9b184508dbd4e80db974512d5018d2384d355871c61
Binary file added doc/green.mp3
Binary file not shown.
Binary file added doc/red.mp3
Binary file not shown.
Binary file added doc/screenshot.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 5 additions & 0 deletions gems.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# frozen_string_literal: true

source "https://rubygems.org"

gemspec
7 changes: 7 additions & 0 deletions guardfile.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
clearing :on

guard :minitest do
watch(%r{^spec/(.+)_spec\.rb})
watch(%r{^lib/(.+)\.rb}) { "spec/lib/#{_1[1]}_spec.rb" }
watch(%r{^spec/spec_helper.rb}) { 'spec' }
end
8 changes: 8 additions & 0 deletions lib/minitest/substitute.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# frozen_string_literal: true

require_relative 'substitute/version'

require_relative 'substitute/with'
require_relative 'substitute/spec'

include Minitest::Substitute::With
47 changes: 47 additions & 0 deletions lib/minitest/substitute/spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# frozen_string_literal: true

require 'minitest/spec'

Minitest::Spec::DSL.class_eval do
class Substitutor
include Minitest::Substitute::With
end

# Substitute the variable value for the duration of the current description
#
# @param variable [String] instance or global variable name
# @param substitute [Object] temporary substitution value
# @param on [Object, nil] substitute in the context of this object
# @yield temporary substitution value (takes precedence over +substitute+ param)
def with(variable, substitute=nil, on: self)
before do
substitute = yield if block_given?
Substitutor.send(:commit_substitution, variable, substitute, on: on)
end
after do
Substitutor.send(:rollback_substitution, variable, on: on)
end
end

# Minitest does not support multiple before/after blocks
remove_method :before
def before(_type=nil, &block)
include(Module.new do
define_method(:setup) do
super()
instance_eval &block
end
end) # .then &:include
end

remove_method :after
def after(_type=nil, &block)
include(Module.new do
define_method(:teardown) do
instance_eval &block
ensure
super()
end
end) #.then &:include
end
end
7 changes: 7 additions & 0 deletions lib/minitest/substitute/version.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# frozen_string_literal: true

module Minitest
module Substitute
VERSION = '0.1.0'
end
end
36 changes: 36 additions & 0 deletions lib/minitest/substitute/with.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# frozen_string_literal: true

module Minitest
module Substitute
module With
class << self
attr_accessor :original
end

# Substitute the variable value for the duration of the given block
#
# @param variable [String] instance or global variable name
# @param substitute [Object] temporary substitution value
# @param on [Object, nil] substitute in the context of this object
# @yield block during which the substitution is made
# @return [Object] return value of the yielded block
def with(variable, substitute, on: self)
commit_substitution(variable, substitute, on: on)
yield.tap do
rollback_substitution(variable, on: on)
end
end

private

def commit_substitution(variable, substitute, on:)
Minitest::Substitute::With.original = on.instance_eval variable.to_s
on.instance_eval "#{variable} = substitute"
end

def rollback_substitution(variable, on:)
on.instance_eval "#{variable} = Minitest::Substitute::With.original"
end
end
end
end
Loading

0 comments on commit 198364a

Please sign in to comment.