MonoForge

btakita / mspec

mspec

Public

RSpec-syntax compatible framework for RubySpecs

157 filesupdated Jun 18, 2026

README

= Overview

MSpec is a specialized framework that is syntax-compatible with RSpec for basic things like +describe+, +it+ blocks and +before+, +after+ actions. MSpec contains additional features that assist in writing the RubySpecs used by multiple Ruby implementations.

MSpec attempts to use the simplest Ruby language features so that beginning Ruby implementations can run the Ruby specs. So, for example, there is not great concern given to constant clashes. Namespacing (or module scoping) is not used because implementing this correctly took a significant amount of work in Rubinius and it is likely that other implementations would also face difficulties.

MSpec is not intended as a replacement for RSpec. MSpec attempts to provide a subset of RSpec's features in some cases and a superset in others. It does not provide all the matchers, for instance. However, MSpec provides several extensions to facilitate writing the Ruby specs in a manner compatible with multiple Ruby implementations.

First, MSpec offers a set of guards to control execution of the specs. These guards not only enable or disable execution but also annotate the specs with additional information about why they are run or not run. Second, MSpec provides a different shared spec implementation specifically designed to ease writing specs for the numerous aliased methods in Ruby. The MSpec shared spec implementation should not conflict with RSpec's own shared behavior facility. Third, MSpec provides various helper methods to simplify some specs, for example, creating temporary file names. Finally, MSpec has several specialized runner scripts that includes a configuration facility with a default project file and user-specific overrides.

Caveats:

  • Use RSpec to run the MSpec specs. There are no plans currently to make the MSpec specs runnable by MSpec.
  • Don't mock the #hash method as MSpec's Mock implementation uses Hash internally. This can be replaced if necessary, but at this point there is no compelling need to do so.

== Architecture

== Matchers

Matchers are additional aids for the verification process. The default is of course to #should or #should_not using the #== operator and its friends but the matchers add a new set of 'operators' to help in the task. They reside in mspec/matchers/. There are two broad categories, those that apply to an individual object and those that apply to a block:

=== Object

  • base implements the standard #==, #< #<= #>= #> and #=~ with their normal semantics for the objects that you invoke them on.

  • be_ancestor_of is equivalent to checking obj.ancestors.include?.

  • be_close is a "delta" for floating-point math. Due to the very nature of it, floating-point comparisons should never be treated as exact. By default the tolerance is 0.00003 but it can be altered if so desired. So 0.23154.should be_close(0.23157) would succeed (which is usually close enough for floating point unless you are doing some scientific computing.)

  • be_empty checks obj.empty?

  • be_kind_of is equivalent to obj.kind_of?

  • include is obj.include?

=== Block

All of these should be applied to a block created with lambda or proc:

  • complain is probably clearer stated as lambda {...}.should complain; it checks that the block issues a warning. The message can be checked against either a String or a Regexp.

  • output checks that the block produces the given output (stdout as well as stderr, in that order) matched either to a String or a Regexp. This one uses overrides so if that is a problem (for e.g. speccing Readline or something) see below.

  • output_to_fd is a lower-level version and actually verifies that output to a certain file descriptor is correct whether from an in-/output stream or an actual file. Also can check with either a String or a Regexp.

  • raise_error verifies the exception type (if any) raised by the block it is associated with. The exception class can be given for finer-grained control (inheritance works normally so Exception would catch everything.)

== Guards

== Helpers

== Runners