Skip to content
This repository
Browse code

Imported mpspec 65a5dbf. See http://github.com/rubyspec/mspec/tree/ma…

  • Loading branch information...
commit 002dd4fa8c9d2ff9d571b23a0a28ac37e5d16878 1 parent 3a2a98f
Eloy Durán authored March 11, 2009

Showing 222 changed files with 18,246 additions and 0 deletions. Show diff stats Hide diff stats

  1. 22  mspec/LICENSE
  2. 197  mspec/README
  3. 47  mspec/Rakefile
  4. 7  mspec/bin/mkspec
  5. 1  mspec/bin/mkspec.bat
  6. 7  mspec/bin/mspec
  7. 8  mspec/bin/mspec-ci
  8. 1  mspec/bin/mspec-ci.bat
  9. 8  mspec/bin/mspec-run
  10. 1  mspec/bin/mspec-run.bat
  11. 8  mspec/bin/mspec-tag
  12. 1  mspec/bin/mspec-tag.bat
  13. 1  mspec/bin/mspec.bat
  14. 11  mspec/lib/mspec.rb
  15. 140  mspec/lib/mspec/commands/mkspec.rb
  16. 75  mspec/lib/mspec/commands/mspec-ci.rb
  17. 90  mspec/lib/mspec/commands/mspec-run.rb
  18. 130  mspec/lib/mspec/commands/mspec-tag.rb
  19. 157  mspec/lib/mspec/commands/mspec.rb
  20. 2  mspec/lib/mspec/expectations.rb
  21. 17  mspec/lib/mspec/expectations/expectations.rb
  22. 25  mspec/lib/mspec/expectations/should.rb
  23. 16  mspec/lib/mspec/guards.rb
  24. 21  mspec/lib/mspec/guards/background.rb
  25. 24  mspec/lib/mspec/guards/bug.rb
  26. 37  mspec/lib/mspec/guards/compliance.rb
  27. 18  mspec/lib/mspec/guards/conflict.rb
  28. 44  mspec/lib/mspec/guards/endian.rb
  29. 20  mspec/lib/mspec/guards/extensions.rb
  30. 166  mspec/lib/mspec/guards/guard.rb
  31. 20  mspec/lib/mspec/guards/noncompliance.rb
  32. 43  mspec/lib/mspec/guards/platform.rb
  33. 17  mspec/lib/mspec/guards/quarantine.rb
  34. 34  mspec/lib/mspec/guards/runner.rb
  35. 17  mspec/lib/mspec/guards/superuser.rb
  36. 20  mspec/lib/mspec/guards/support.rb
  37. 20  mspec/lib/mspec/guards/tty.rb
  38. 38  mspec/lib/mspec/guards/version.rb
  39. 11  mspec/lib/mspec/helpers.rb
  40. 43  mspec/lib/mspec/helpers/argv.rb
  41. 5  mspec/lib/mspec/helpers/bignum.rb
  42. 9  mspec/lib/mspec/helpers/const_lookup.rb
  43. 23  mspec/lib/mspec/helpers/environment.rb
  44. 20  mspec/lib/mspec/helpers/fixture.rb
  45. 5  mspec/lib/mspec/helpers/flunk.rb
  46. 17  mspec/lib/mspec/helpers/io.rb
  47. 20  mspec/lib/mspec/helpers/language_version.rb
  48. 123  mspec/lib/mspec/helpers/ruby_exe.rb
  49. 17  mspec/lib/mspec/helpers/scratch.rb
  50. 32  mspec/lib/mspec/helpers/tmp.rb
  51. 23  mspec/lib/mspec/matchers.rb
  52. 95  mspec/lib/mspec/matchers/base.rb
  53. 26  mspec/lib/mspec/matchers/be_an_instance_of.rb
  54. 24  mspec/lib/mspec/matchers/be_ancestor_of.rb
  55. 27  mspec/lib/mspec/matchers/be_close.rb
  56. 20  mspec/lib/mspec/matchers/be_empty.rb
  57. 20  mspec/lib/mspec/matchers/be_false.rb
  58. 24  mspec/lib/mspec/matchers/be_kind_of.rb
  59. 20  mspec/lib/mspec/matchers/be_nil.rb
  60. 20  mspec/lib/mspec/matchers/be_true.rb
  61. 56  mspec/lib/mspec/matchers/complain.rb
  62. 26  mspec/lib/mspec/matchers/eql.rb
  63. 26  mspec/lib/mspec/matchers/equal.rb
  64. 78  mspec/lib/mspec/matchers/equal_element.rb
  65. 34  mspec/lib/mspec/matchers/equal_utf16.rb
  66. 30  mspec/lib/mspec/matchers/have_constant.rb
  67. 24  mspec/lib/mspec/matchers/have_instance_method.rb
  68. 24  mspec/lib/mspec/matchers/have_method.rb
  69. 24  mspec/lib/mspec/matchers/have_private_instance_method.rb
  70. 32  mspec/lib/mspec/matchers/include.rb
  71. 47  mspec/lib/mspec/matchers/match_yaml.rb
  72. 14  mspec/lib/mspec/matchers/method.rb
  73. 67  mspec/lib/mspec/matchers/output.rb
  74. 71  mspec/lib/mspec/matchers/output_to_fd.rb
  75. 48  mspec/lib/mspec/matchers/raise_error.rb
  76. 24  mspec/lib/mspec/matchers/respond_to.rb
  77. 8  mspec/lib/mspec/matchers/stringsymboladapter.rb
  78. 3  mspec/lib/mspec/mocks.rb
  79. 155  mspec/lib/mspec/mocks/mock.rb
  80. 20  mspec/lib/mspec/mocks/object.rb
  81. 136  mspec/lib/mspec/mocks/proxy.rb
  82. 15  mspec/lib/mspec/runner.rb
  83. 8  mspec/lib/mspec/runner/actions.rb
  84. 17  mspec/lib/mspec/runner/actions/debug.rb
  85. 40  mspec/lib/mspec/runner/actions/filter.rb
  86. 17  mspec/lib/mspec/runner/actions/gdb.rb
  87. 133  mspec/lib/mspec/runner/actions/tag.rb
  88. 56  mspec/lib/mspec/runner/actions/taglist.rb
  89. 56  mspec/lib/mspec/runner/actions/tagpurge.rb
  90. 116  mspec/lib/mspec/runner/actions/tally.rb
  91. 22  mspec/lib/mspec/runner/actions/timer.rb
  92. 186  mspec/lib/mspec/runner/context.rb
  93. 34  mspec/lib/mspec/runner/example.rb
  94. 43  mspec/lib/mspec/runner/exception.rb
  95. 4  mspec/lib/mspec/runner/filters.rb
  96. 22  mspec/lib/mspec/runner/filters/match.rb
  97. 54  mspec/lib/mspec/runner/filters/profile.rb
  98. 7  mspec/lib/mspec/runner/filters/regexp.rb
  99. 29  mspec/lib/mspec/runner/filters/tag.rb
  100. 10  mspec/lib/mspec/runner/formatters.rb
  101. 24  mspec/lib/mspec/runner/formatters/describe.rb
  102. 98  mspec/lib/mspec/runner/formatters/dotted.rb
  103. 19  mspec/lib/mspec/runner/formatters/file.rb
  104. 81  mspec/lib/mspec/runner/formatters/html.rb
  105. 93  mspec/lib/mspec/runner/formatters/method.rb
  106. 41  mspec/lib/mspec/runner/formatters/specdoc.rb
  107. 99  mspec/lib/mspec/runner/formatters/spinner.rb
  108. 11  mspec/lib/mspec/runner/formatters/summary.rb
  109. 21  mspec/lib/mspec/runner/formatters/unit.rb
  110. 44  mspec/lib/mspec/runner/formatters/yaml.rb
  111. 335  mspec/lib/mspec/runner/mspec.rb
  112. 24  mspec/lib/mspec/runner/object.rb
  113. 12  mspec/lib/mspec/runner/shared.rb
  114. 32  mspec/lib/mspec/runner/tag.rb
  115. 129  mspec/lib/mspec/utils/name_map.rb
  116. 441  mspec/lib/mspec/utils/options.rb
  117. 8  mspec/lib/mspec/utils/ruby_name.rb
  118. 219  mspec/lib/mspec/utils/script.rb
  119. 53  mspec/lib/mspec/utils/version.rb
  120. 5  mspec/lib/mspec/version.rb
  121. 33  mspec/mspec.gemspec
  122. 0  mspec/spec/commands/fixtures/four.txt
  123. 0  mspec/spec/commands/fixtures/level2/three_spec.rb
  124. 0  mspec/spec/commands/fixtures/one_spec.rb
  125. 0  mspec/spec/commands/fixtures/three.rb
  126. 0  mspec/spec/commands/fixtures/two_spec.rb
  127. 332  mspec/spec/commands/mkspec_spec.rb
  128. 142  mspec/spec/commands/mspec_ci_spec.rb
  129. 178  mspec/spec/commands/mspec_run_spec.rb
  130. 425  mspec/spec/commands/mspec_spec.rb
  131. 410  mspec/spec/commands/mspec_tag_spec.rb
  132. 29  mspec/spec/expectations/expectations_spec.rb
  133. 129  mspec/spec/expectations/should_spec.rb
  134. 36  mspec/spec/guards/background_spec.rb
  135. 140  mspec/spec/guards/bug_spec.rb
  136. 140  mspec/spec/guards/compliance_spec.rb
  137. 39  mspec/spec/guards/conflict_spec.rb
  138. 68  mspec/spec/guards/endian_spec.rb
  139. 69  mspec/spec/guards/extensions_spec.rb
  140. 476  mspec/spec/guards/guard_spec.rb
  141. 69  mspec/spec/guards/noncompliance_spec.rb
  142. 110  mspec/spec/guards/platform_spec.rb
  143. 35  mspec/spec/guards/quarantine_spec.rb
  144. 101  mspec/spec/guards/runner_spec.rb
  145. 35  mspec/spec/guards/superuser_spec.rb
  146. 69  mspec/spec/guards/support_spec.rb
  147. 36  mspec/spec/guards/tty_spec.rb
  148. 130  mspec/spec/guards/version_spec.rb
  149. 26  mspec/spec/helpers/argv_spec.rb
  150. 11  mspec/spec/helpers/bignum_spec.rb
  151. 48  mspec/spec/helpers/const_lookup_spec.rb
  152. 82  mspec/spec/helpers/environment_spec.rb
  153. 18  mspec/spec/helpers/fixture_spec.rb
  154. 19  mspec/spec/helpers/flunk_spec.rb
  155. 38  mspec/spec/helpers/io_spec.rb
  156. 29  mspec/spec/helpers/language_version_spec.rb
  157. 160  mspec/spec/helpers/ruby_exe_spec.rb
  158. 22  mspec/spec/helpers/scratch_spec.rb
  159. 72  mspec/spec/helpers/tmp_spec.rb
  160. 216  mspec/spec/matchers/base_spec.rb
  161. 50  mspec/spec/matchers/be_an_instance_of_spec.rb
  162. 28  mspec/spec/matchers/be_ancestor_of_spec.rb
  163. 46  mspec/spec/matchers/be_close_spec.rb
  164. 26  mspec/spec/matchers/be_empty_spec.rb
  165. 28  mspec/spec/matchers/be_false_spec.rb
  166. 31  mspec/spec/matchers/be_kind_of_spec.rb
  167. 27  mspec/spec/matchers/be_nil_spec.rb
  168. 28  mspec/spec/matchers/be_true_spec.rb
  169. 52  mspec/spec/matchers/complain_spec.rb
  170. 33  mspec/spec/matchers/eql_spec.rb
  171. 75  mspec/spec/matchers/equal_element_spec.rb
  172. 33  mspec/spec/matchers/equal_spec.rb
  173. 47  mspec/spec/matchers/equal_utf16_spec.rb
  174. 37  mspec/spec/matchers/have_constant_spec.rb
  175. 53  mspec/spec/matchers/have_instance_method_spec.rb
  176. 55  mspec/spec/matchers/have_method_spec.rb
  177. 57  mspec/spec/matchers/have_private_instance_method_spec.rb
  178. 37  mspec/spec/matchers/include_spec.rb
  179. 39  mspec/spec/matchers/match_yaml_spec.rb
  180. 74  mspec/spec/matchers/output_spec.rb
  181. 33  mspec/spec/matchers/output_to_fd_spec.rb
  182. 56  mspec/spec/matchers/raise_error_spec.rb
  183. 31  mspec/spec/matchers/respond_to_spec.rb
  184. 40  mspec/spec/matchers/stringsymboladapter_spec.rb
  185. 448  mspec/spec/mocks/mock_spec.rb
  186. 366  mspec/spec/mocks/proxy_spec.rb
  187. 62  mspec/spec/runner/actions/debug_spec.rb
  188. 84  mspec/spec/runner/actions/filter_spec.rb
  189. 61  mspec/spec/runner/actions/gdb_spec.rb
  190. 315  mspec/spec/runner/actions/tag_spec.rb
  191. 152  mspec/spec/runner/actions/taglist_spec.rb
  192. 154  mspec/spec/runner/actions/tagpurge_spec.rb
  193. 347  mspec/spec/runner/actions/tally_spec.rb
  194. 42  mspec/spec/runner/actions/timer_spec.rb
  195. 993  mspec/spec/runner/context_spec.rb
  196. 112  mspec/spec/runner/example_spec.rb
  197. 134  mspec/spec/runner/exception_spec.rb
  198. 4  mspec/spec/runner/filters/a.yaml
  199. 11  mspec/spec/runner/filters/b.yaml
  200. 44  mspec/spec/runner/filters/match_spec.rb
  201. 117  mspec/spec/runner/filters/profile_spec.rb
  202. 13  mspec/spec/runner/filters/regexp_spec.rb
  203. 77  mspec/spec/runner/filters/tag_spec.rb
  204. 67  mspec/spec/runner/formatters/describe_spec.rb
  205. 290  mspec/spec/runner/formatters/dotted_spec.rb
  206. 84  mspec/spec/runner/formatters/file_spec.rb
  207. 216  mspec/spec/runner/formatters/html_spec.rb
  208. 177  mspec/spec/runner/formatters/method_spec.rb
  209. 106  mspec/spec/runner/formatters/specdoc_spec.rb
  210. 85  mspec/spec/runner/formatters/spinner_spec.rb
  211. 26  mspec/spec/runner/formatters/summary_spec.rb
  212. 73  mspec/spec/runner/formatters/unit_spec.rb
  213. 125  mspec/spec/runner/formatters/yaml_spec.rb
  214. 589  mspec/spec/runner/mspec_spec.rb
  215. 27  mspec/spec/runner/shared_spec.rb
  216. 111  mspec/spec/runner/tag_spec.rb
  217. 4  mspec/spec/runner/tags.txt
  218. 43  mspec/spec/spec_helper.rb
  219. 178  mspec/spec/utils/name_map_spec.rb
  220. 1,291  mspec/spec/utils/options_spec.rb
  221. 443  mspec/spec/utils/script_spec.rb
  222. 47  mspec/spec/utils/version_spec.rb
22  mspec/LICENSE
... ...
@@ -0,0 +1,22 @@
  1
+Copyright (c) 2008 Engine Yard, Inc. All rights reserved.
  2
+
  3
+Permission is hereby granted, free of charge, to any person
  4
+obtaining a copy of this software and associated documentation
  5
+files (the "Software"), to deal in the Software without
  6
+restriction, including without limitation the rights to use,
  7
+copy, modify, merge, publish, distribute, sublicense, and/or sell
  8
+copies of the Software, and to permit persons to whom the
  9
+Software is furnished to do so, subject to the following
  10
+conditions:
  11
+
  12
+The above copyright notice and this permission notice shall be
  13
+included in all copies or substantial portions of the Software.
  14
+
  15
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  16
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
  17
+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  18
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
  19
+HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
  20
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  21
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  22
+OTHER DEALINGS IN THE SOFTWARE.
197  mspec/README
... ...
@@ -0,0 +1,197 @@
  1
+= Overview
  2
+
  3
+MSpec is a specialized framework that is syntax-compatible with RSpec for
  4
+basic things like +describe+, +it+ blocks and +before+, +after+ actions. MSpec
  5
+contains additional features that assist in writing the RubySpecs used by
  6
+multiple Ruby implementations.
  7
+
  8
+MSpec attempts to use the simplest Ruby language features so that beginning
  9
+Ruby implementations can run the Ruby specs. So, for example, there is not
  10
+great concern given to constant clashes. Namespacing (or module scoping) is
  11
+not used because implementing this correctly took a significant amount of work
  12
+in Rubinius and it is likely that other implementations would also face
  13
+difficulties.
  14
+
  15
+MSpec is not intended as a replacement for RSpec. MSpec attempts to provide a
  16
+subset of RSpec's features in some cases and a superset in others. It does not
  17
+provide all the matchers, for instance. However, MSpec provides several
  18
+extensions to facilitate writing the Ruby specs in a manner compatible with
  19
+multiple Ruby implementations.
  20
+
  21
+First, MSpec offers a set of guards to control execution of the specs. These
  22
+guards not only enable or disable execution but also annotate the specs with
  23
+additional information about why they are run or not run. Second, MSpec
  24
+provides a different shared spec implementation specifically designed to ease
  25
+writing specs for the numerous aliased methods in Ruby. The MSpec shared spec
  26
+implementation should not conflict with RSpec's own shared behavior facility.
  27
+Third, MSpec provides various helper methods to simplify some specs, for
  28
+example, creating temporary file names. Finally, MSpec has several specialized
  29
+runner scripts that includes a configuration facility with a default project
  30
+file and user-specific overrides.
  31
+
  32
+Caveats:
  33
+
  34
+* Use RSpec to run the MSpec specs. There are no plans currently to make
  35
+  the MSpec specs runnable by MSpec.
  36
+* Don't mock the #hash method as MSpec's Mock implementation uses Hash
  37
+  internally. This can be replaced if necessary, but at this point there is no
  38
+  compelling need to do so.
  39
+
  40
+
  41
+== Architecture
  42
+
  43
+
  44
+== Matchers
  45
+
  46
+Matchers are additional aids for the verification process. The default
  47
+is of course to #should or #should_not using the #== operator and its
  48
+friends but the matchers add a new set of 'operators' to help in the
  49
+task. They reside in `mspec/matchers/`. There are two broad categories,
  50
+those that apply to an individual object and those that apply to a
  51
+block:
  52
+
  53
+=== Object
  54
+
  55
+- `base` implements the standard #==, #< #<= #>= #> and #=~ with their
  56
+  normal semantics for the objects that you invoke them on.
  57
+
  58
+- `be_ancestor_of` is equivalent to checking `obj.ancestors.include?`.
  59
+
  60
+- `be_close` is a "delta" for floating-point math. Due to the very
  61
+  nature of it, floating-point comparisons should never be treated as
  62
+  exact. By default the tolerance is 0.00003 but it can be altered if
  63
+  so desired. So `0.23154.should be_close(0.23157)` would succeed
  64
+  (which is usually close enough for floating point unless you are
  65
+  doing some scientific computing.)
  66
+
  67
+- `be_empty` checks `obj.empty?`
  68
+
  69
+- `be_kind_of` is equivalent to `obj.kind_of?`
  70
+
  71
+- `include` is `obj.include?`
  72
+
  73
+=== Block
  74
+
  75
+All of these should be applied to a block created with `lambda` or `proc`:
  76
+
  77
+- `complain` is probably clearer stated as `lambda {...}.should complain`;
  78
+  it checks that the block issues a warning. The message can be checked
  79
+  against either a String or a Regexp.
  80
+
  81
+- `output` checks that the block produces the given output (stdout as well
  82
+  as stderr, in that order) matched either to a String or a Regexp. This one
  83
+  uses overrides so if that is a problem (for e.g. speccing Readline or
  84
+  something) see below.
  85
+
  86
+- `output_to_fd` is a lower-level version and actually verifies that output
  87
+  to a certain file descriptor is correct whether from an in-/output stream
  88
+  or an actual file. Also can check with either a String or a Regexp.
  89
+
  90
+- `raise_error` verifies the exception type (if any) raised by the block it
  91
+  is associated with. The exception class can be given for finer-grained
  92
+  control (inheritance works normally so Exception would catch everything.)
  93
+
  94
+== Nested 'describe' blocks
  95
+
  96
+MSpec supports nesting one 'describe' block inside another. The examples in
  97
+the nested block are evaluated with all the before/after blocks of all the
  98
+containing 'describe' blocks. The following example illustrates this:
  99
+
  100
+describe "Some#method" do
  101
+  before :each do
  102
+    @obj = 1
  103
+  end
  104
+
  105
+  describe "when passed String" do
  106
+    before :each do
  107
+      @meth = :to_s
  108
+    end
  109
+
  110
+    it "returns false" do
  111
+      # when this example is evaluated, @obj = 1 and @meth = :to_s
  112
+    end
  113
+  end
  114
+end
  115
+
  116
+The output when using the SpecdocFormatter (selected with -fs to the runners)
  117
+will be as follows:
  118
+
  119
+Some#method when passed String
  120
+- returns false
  121
+
  122
+
  123
+== Shared 'describe' blocks
  124
+
  125
+MSpec supports RSpec-style shared 'describe' blocks. MSpec also provides a
  126
+convenience method to assist in writing specs for the numerous aliased methods
  127
+that Ruby provides. The following example illustrates shared blocks:
  128
+
  129
+describe :someclass_some_method, :shared => true do
  130
+  it "does something" do
  131
+  end
  132
+end
  133
+
  134
+describe "SomeClass#some_method" do
  135
+  it_should_behave_like "someclass_some_method"
  136
+end
  137
+
  138
+The first argument to 'describe' for a shared block is an object that
  139
+duck-types as a String. The representation of the object must be unique. This
  140
+example uses a symbol. This was the convention for the previous facility that
  141
+MSpec provided for aliased method (#it_behaves_like). However, this convention
  142
+is not set in stone (but the uniqueness requirement is). Note that the
  143
+argument to the #it_should_behave_like is a String because at this time RSpec
  144
+will not find the shared block by the symbol.
  145
+
  146
+MSpec continues to support the #it_behaves_like convenience method for
  147
+specifying aliased methods. The syntax is as follows:
  148
+
  149
+it_behaves_like :symbol_matching_shared_describe, :method [, :object]
  150
+
  151
+describe :someclass_some_method, :shared => true do
  152
+  it "returns true" do
  153
+    obj.send(@method).should be_true
  154
+  end
  155
+
  156
+  it "returns something else" do
  157
+    @object.send(@method).should be_something_else
  158
+  end
  159
+end
  160
+
  161
+# example #1
  162
+describe "SomeClass#some_method" do
  163
+  it_behaves_like :someclass_some_method, :other_method
  164
+end
  165
+
  166
+# example #2
  167
+describe "SomeOtherClass#some_method" do
  168
+  it_behaves_like :someclass_some_method, :some_method, OtherClass
  169
+end
  170
+
  171
+The first form above (#1) is used for typical aliases. That is, methods with
  172
+different names on the same class that behave identically. The
  173
+#it_behaves_like helper creates a before(:all) block that sets @method to
  174
+:other_method. The form of the first example block in the shared block
  175
+illustrates the typical form of a spec for an aliased method.
  176
+
  177
+The second form above (#2) is used for methods on different classes that are
  178
+essentially aliases, even though Ruby does not provide a syntax for specifying
  179
+such methods as aliases. Examples are the methods on File, FileTest, and
  180
+File::Stat. In this case, the #it_behaves_like helper sets both @method and
  181
+@object in the before(:all) block (@method = :some_method, @object =
  182
+OtherClass in this example).
  183
+
  184
+For shared specs that fall outside of either of these two narrow categories,
  185
+use nested or shared 'describe' blocks as appropriate and use the
  186
+#it_should_behave_like method directly.
  187
+
  188
+== Guards
  189
+
  190
+Since Ruby is not completely isolated from its platform or execution environment, the spec files may contain guards: conditions placed around a spec or a set of specs to enable or disable them. 
  191
+
  192
+You can find an overview of the current guards and their usage in: http://rubyspec.org/wiki/mspec/Guards .
  193
+
  194
+== Helpers
  195
+
  196
+
  197
+== Runners
47  mspec/Rakefile
... ...
@@ -0,0 +1,47 @@
  1
+require 'rubygems'
  2
+require 'spec/rake/spectask'
  3
+require 'rake/gempackagetask'
  4
+
  5
+$:.unshift File.expand_path(File.dirname(__FILE__) + '/lib')
  6
+require 'lib/mspec/version'
  7
+
  8
+Spec::Rake::SpecTask.new
  9
+
  10
+task :default => :spec
  11
+
  12
+
  13
+spec = Gem::Specification.new do |s|
  14
+  s.name                      = %q{mspec}
  15
+  s.version                   = MSpec::VERSION.to_s
  16
+
  17
+  s.specification_version     = 2 if s.respond_to? :specification_version=
  18
+
  19
+  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
  20
+  s.authors                   = ["Brian Ford"]
  21
+  s.date                      = %q{2009-3-1}
  22
+  s.email                     = %q{bford@engineyard.com}
  23
+  s.has_rdoc                  = true
  24
+  s.extra_rdoc_files          = %w[ README LICENSE ]
  25
+  s.executables               = ["mkspec", "mspec", "mspec-ci", "mspec-run", "mspec-tag"]
  26
+  s.files                     = FileList[ '{bin,lib,spec}/**/*.{yaml,txt,rb}', 'Rakefile', *s.extra_rdoc_files ]
  27
+  s.homepage                  = %q{http://rubyspec.org}
  28
+  s.rubyforge_project         = 'http://rubyforge.org/projects/mspec'
  29
+  s.require_paths             = ["lib"]
  30
+  s.rubygems_version          = %q{1.1.1}
  31
+  s.summary                   = <<EOS
  32
+MSpec is a specialized framework that is syntax-compatible
  33
+with RSpec for basic things like describe, it blocks and
  34
+before, after actions.
  35
+
  36
+MSpec contains additional features that assist in writing
  37
+the RubySpecs used by multiple Ruby implementations. Also,
  38
+MSpec attempts to use the simplest Ruby language features
  39
+so that beginning Ruby implementations can run it.
  40
+EOS
  41
+
  42
+  s.rdoc_options << '--title' << 'MSpec Gem' <<
  43
+                   '--main' << 'README' <<
  44
+                   '--line-numbers'
  45
+end
  46
+
  47
+Rake::GemPackageTask.new(spec){ |pkg| pkg.gem_spec = spec }
7  mspec/bin/mkspec
... ...
@@ -0,0 +1,7 @@
  1
+#!/usr/bin/env ruby
  2
+
  3
+$:.unshift File.expand_path(File.dirname(__FILE__) + '/../lib')
  4
+
  5
+require 'mspec/commands/mkspec'
  6
+
  7
+MkSpec.main
1  mspec/bin/mkspec.bat
... ...
@@ -0,0 +1 @@
  1
+@"ruby.exe" "%~dpn0" %*
7  mspec/bin/mspec
... ...
@@ -0,0 +1,7 @@
  1
+#!/usr/bin/env ruby
  2
+
  3
+$:.unshift File.expand_path(File.dirname(__FILE__) + '/../lib')
  4
+
  5
+require 'mspec/commands/mspec'
  6
+
  7
+MSpecMain.main
8  mspec/bin/mspec-ci
... ...
@@ -0,0 +1,8 @@
  1
+#!/usr/bin/env ruby
  2
+
  3
+$:.unshift File.expand_path(File.dirname(__FILE__) + '/../lib')
  4
+
  5
+require 'mspec/commands/mspec-ci'
  6
+require 'mspec'
  7
+
  8
+MSpecCI.main
1  mspec/bin/mspec-ci.bat
... ...
@@ -0,0 +1 @@
  1
+@"ruby.exe" "%~dpn0" %*
8  mspec/bin/mspec-run
... ...
@@ -0,0 +1,8 @@
  1
+#!/usr/bin/env ruby
  2
+
  3
+$:.unshift File.expand_path(File.dirname(__FILE__) + '/../lib')
  4
+
  5
+require 'mspec/commands/mspec-run'
  6
+require 'mspec'
  7
+
  8
+MSpecRun.main
1  mspec/bin/mspec-run.bat
... ...
@@ -0,0 +1 @@
  1
+@"ruby.exe" "%~dpn0" %*
8  mspec/bin/mspec-tag
... ...
@@ -0,0 +1,8 @@
  1
+#!/usr/bin/env ruby
  2
+
  3
+$:.unshift File.expand_path(File.dirname(__FILE__) + '/../lib')
  4
+
  5
+require 'mspec/commands/mspec-tag'
  6
+require 'mspec'
  7
+
  8
+MSpecTag.main
1  mspec/bin/mspec-tag.bat
... ...
@@ -0,0 +1 @@
  1
+@"ruby.exe" "%~dpn0" %*
1  mspec/bin/mspec.bat
... ...
@@ -0,0 +1 @@
  1
+@"ruby.exe" "%~dpn0" %*
11  mspec/lib/mspec.rb
... ...
@@ -0,0 +1,11 @@
  1
+require 'mspec/matchers'
  2
+require 'mspec/expectations'
  3
+require 'mspec/mocks'
  4
+require 'mspec/runner'
  5
+require 'mspec/guards'
  6
+require 'mspec/helpers'
  7
+
  8
+# If the implementation on which the specs are run cannot
  9
+# load pp from the standard library, add a pp.rb file that
  10
+# defines the #pretty_inspect method on Object or Kernel.
  11
+require 'pp'
140  mspec/lib/mspec/commands/mkspec.rb
... ...
@@ -0,0 +1,140 @@
  1
+#! /usr/bin/env ruby
  2
+
  3
+MSPEC_HOME = File.expand_path(File.dirname(__FILE__) + '/../../..')
  4
+
  5
+require 'fileutils'
  6
+require 'rbconfig'
  7
+require 'mspec/version'
  8
+require 'mspec/utils/options'
  9
+require 'mspec/utils/name_map'
  10
+
  11
+
  12
+class MkSpec
  13
+  attr_reader :config
  14
+
  15
+  def initialize
  16
+    @config = {
  17
+      :constants => [],
  18
+      :requires  => [],
  19
+      :base      => "spec/ruby/1.8/core"
  20
+    }
  21
+    @map = NameMap.new
  22
+  end
  23
+
  24
+  def options(argv=ARGV)
  25
+    options = MSpecOptions.new "mkspec [options]"
  26
+
  27
+    options.on("-c", "--constant", "CONSTANT",
  28
+               "Class or Module to generate spec stubs for") do |name|
  29
+      config[:constants] << name
  30
+    end
  31
+    options.on("-b", "--base", "DIR",
  32
+               "Directory to generate specs into") do |directory|
  33
+      config[:base] = File.expand_path directory
  34
+    end
  35
+    options.on("-r", "--require", "LIBRARY",
  36
+               "A library to require") do |file|
  37
+      config[:requires] << file
  38
+    end
  39
+    options.version MSpec::VERSION
  40
+    options.help
  41
+
  42
+    options.doc "\n How might this work in the real world?\n"
  43
+    options.doc "   1. To create spec stubs for every class or module in Object\n"
  44
+    options.doc "     $ mkspec\n"
  45
+    options.doc "   2. To create spec stubs for Fixnum\n"
  46
+    options.doc "     $ mkspec -c Fixnum\n"
  47
+    options.doc "   3. To create spec stubs for Complex in 'superspec/complex'\n"
  48
+    options.doc "     $ mkspec -c Complex -rcomplex -b superspec"
  49
+    options.doc ""
  50
+
  51
+    options.parse argv
  52
+  end
  53
+
  54
+  def create_directory(mod)
  55
+    subdir = @map.dir_name mod, config[:base]
  56
+
  57
+    if File.exist? subdir
  58
+      unless File.directory? subdir
  59
+        puts "#{subdir} already exists and is not a directory."
  60
+        return nil
  61
+      end
  62
+    else
  63
+      FileUtils.mkdir_p subdir
  64
+    end
  65
+
  66
+    subdir
  67
+  end
  68
+
  69
+  def write_requires(dir, file)
  70
+    /\A#{Regexp.escape config[:base]}\/?(.*)/ =~ dir
  71
+    parents = '../' * ($1.split('/').length + 1)
  72
+
  73
+    File.open file, 'w' do |f|
  74
+      f.puts "require File.dirname(__FILE__) + '/#{parents}spec_helper'"
  75
+      config[:requires].each do |lib|
  76
+        f.puts "require '#{lib}'"
  77
+      end
  78
+    end
  79
+  end
  80
+
  81
+  def write_spec(file, meth, exists)
  82
+    if exists
  83
+      out = `#{ruby} #{MSPEC_HOME}/bin/mspec-run --dry-run -fs -e '#{meth}' #{file}`
  84
+      return if out =~ /#{Regexp.escape meth}/
  85
+    end
  86
+
  87
+    File.open file, 'a' do |f|
  88
+      f.puts <<-EOS
  89
+
  90
+describe "#{meth}" do
  91
+  it "needs to be reviewed for spec completeness"
  92
+end
  93
+EOS
  94
+    end
  95
+
  96
+    puts file
  97
+  end
  98
+
  99
+  def create_file(dir, mod, meth, name)
  100
+    file = File.join dir, @map.file_name(meth, mod)
  101
+    exists = File.exist? file
  102
+
  103
+    write_requires dir, file unless exists
  104
+    write_spec file, name, exists
  105
+  end
  106
+
  107
+  def run
  108
+    config[:requires].each { |lib| require lib }
  109
+    constants = config[:constants]
  110
+    constants = @map.filter(Object.constants) if constants.empty?
  111
+
  112
+    @map.map({}, constants).each do |mod, methods|
  113
+      name = mod.chop
  114
+      next unless dir = create_directory(name)
  115
+
  116
+      methods.each { |method| create_file dir, name, method, mod + method }
  117
+    end
  118
+  end
  119
+  
  120
+  ##
  121
+  # Determine and return the path of the ruby executable.
  122
+
  123
+  def ruby
  124
+    ruby = File.join(Config::CONFIG['bindir'],
  125
+                     Config::CONFIG['ruby_install_name'])
  126
+
  127
+    ruby.gsub! File::SEPARATOR, File::ALT_SEPARATOR if File::ALT_SEPARATOR
  128
+
  129
+    return ruby
  130
+  end
  131
+
  132
+  def self.main
  133
+    ENV['MSPEC_RUNNER'] = '1'
  134
+
  135
+    script = new
  136
+    script.options
  137
+    script.run
  138
+  end
  139
+end
  140
+
75  mspec/lib/mspec/commands/mspec-ci.rb
... ...
@@ -0,0 +1,75 @@
  1
+#!/usr/bin/env ruby
  2
+
  3
+$:.unshift File.expand_path(File.dirname(__FILE__) + '/../lib')
  4
+
  5
+require 'mspec/version'
  6
+require 'mspec/utils/options'
  7
+require 'mspec/utils/script'
  8
+
  9
+
  10
+class MSpecCI < MSpecScript
  11
+  def options(argv=ARGV)
  12
+    options = MSpecOptions.new "mspec ci [options] (FILE|DIRECTORY|GLOB)+", 30, config
  13
+
  14
+    options.doc " Ask yourself:"
  15
+    options.doc "  1. How to run the specs?"
  16
+    options.doc "  2. How to modify the guard behavior?"
  17
+    options.doc "  2. How to display the output?"
  18
+    options.doc "  3. What action to perform?"
  19
+    options.doc "  4. When to perform it?"
  20
+
  21
+    options.doc "\n How to run the specs"
  22
+    options.chdir
  23
+    options.prefix
  24
+    options.configure { |f| load f }
  25
+    options.name
  26
+    options.pretend
  27
+    options.background
  28
+    options.interrupt
  29
+
  30
+    options.doc "\n How to modify the guard behavior"
  31
+    options.unguarded
  32
+    options.verify
  33
+
  34
+    options.doc "\n How to display their output"
  35
+    options.formatters
  36
+    options.verbose
  37
+
  38
+    options.doc "\n What action to perform"
  39
+    options.actions
  40
+
  41
+    options.doc "\n When to perform it"
  42
+    options.action_filters
  43
+
  44
+    options.doc "\n Help!"
  45
+    options.version MSpec::VERSION
  46
+    options.help
  47
+
  48
+    options.doc "\n Custom options"
  49
+    custom_options options
  50
+
  51
+    options.doc "\n How might this work in the real world?"
  52
+    options.doc "\n   1. To simply run the known good specs"
  53
+    options.doc "\n     $ mspec ci"
  54
+    options.doc "\n   2. To run a subset of the known good specs"
  55
+    options.doc "\n     $ mspec ci path/to/specs"
  56
+    options.doc "\n   3. To start the debugger before the spec matching 'this crashes'"
  57
+    options.doc "\n     $ mspec ci --spec-debug -S 'this crashes'"
  58
+    options.doc ""
  59
+
  60
+    patterns = options.parse argv
  61
+    patterns = config[:ci_files] if patterns.empty?
  62
+    @files = files patterns
  63
+  end
  64
+
  65
+  def run
  66
+    MSpec.register_tags_patterns config[:tags_patterns]
  67
+    MSpec.register_files @files
  68
+    filter = TagFilter.new(:exclude,
  69
+        "fails", "critical", "unstable", "incomplete", "unsupported")
  70
+    filter.register
  71
+
  72
+    MSpec.process
  73
+    exit MSpec.exit_code
  74
+  end
  75
+end
90  mspec/lib/mspec/commands/mspec-run.rb
... ...
@@ -0,0 +1,90 @@
  1
+#!/usr/bin/env ruby
  2
+
  3
+$:.unshift File.expand_path(File.dirname(__FILE__) + '/../lib')
  4
+
  5
+require 'mspec/version'
  6
+require 'mspec/utils/options'
  7
+require 'mspec/utils/script'
  8
+
  9
+
  10
+class MSpecRun < MSpecScript
  11
+  def initialize
  12
+    super
  13
+
  14
+    config[:files] = []
  15
+  end
  16
+
  17
+  def options(argv=ARGV)
  18
+    options = MSpecOptions.new "mspec run [options] (FILE|DIRECTORY|GLOB)+", 30, config
  19
+
  20
+    options.doc " Ask yourself:"
  21
+    options.doc "  1. What specs to run?"
  22
+    options.doc "  2. How to modify the execution?"
  23
+    options.doc "  3. How to modify the guard behavior?"
  24
+    options.doc "  4. How to display the output?"
  25
+    options.doc "  5. What action to perform?"
  26
+    options.doc "  6. When to perform it?"
  27
+
  28
+    options.doc "\n What specs to run"
  29
+    options.filters
  30
+
  31
+    options.doc "\n How to modify the execution"
  32
+    options.chdir
  33
+    options.prefix
  34
+    options.configure { |f| load f }
  35
+    options.name
  36
+    options.randomize
  37
+    options.pretend
  38
+    options.background
  39
+    options.interrupt
  40
+
  41
+    options.doc "\n How to modify the guard behavior"
  42
+    options.unguarded
  43
+    options.verify
  44
+
  45
+    options.doc "\n How to display their output"
  46
+    options.formatters
  47
+    options.verbose
  48
+
  49
+    options.doc "\n What action to perform"
  50
+    options.actions
  51
+
  52
+    options.doc "\n When to perform it"
  53
+    options.action_filters
  54
+
  55
+    options.doc "\n Help!"
  56
+    options.version MSpec::VERSION
  57
+    options.help
  58
+
  59
+    options.doc "\n Custom options"
  60
+    custom_options options
  61
+
  62
+    options.doc "\n How might this work in the real world?"
  63
+    options.doc "\n   1. To simply run some specs"
  64
+    options.doc "\n     $ mspec path/to/the/specs"
  65
+    options.doc "     mspec path/to/the_file_spec.rb"
  66
+    options.doc "\n   2. To run specs tagged with 'fails'"
  67
+    options.doc "\n     $ mspec -g fails path/to/the_file_spec.rb"
  68
+    options.doc "\n   3. To start the debugger before the spec matching 'this crashes'"
  69
+    options.doc "\n     $ mspec --spec-debug -S 'this crashes' path/to/the_file_spec.rb"
  70
+    options.doc ""
  71
+
  72
+    patterns = options.parse argv
  73
+    patterns = config[:files] if patterns.empty?
  74
+    if patterns.empty?
  75
+      puts options
  76
+      puts "No files specified."
  77
+      exit 1
  78
+    end
  79
+    @files = files patterns
  80
+  end
  81
+
  82
+  def run
  83
+    MSpec.register_tags_patterns config[:tags_patterns]
  84
+    MSpec.register_files @files
  85
+
  86
+    MSpec.process
  87
+    exit MSpec.exit_code
  88
+  end
  89
+end
  90
+
130  mspec/lib/mspec/commands/mspec-tag.rb
... ...
@@ -0,0 +1,130 @@
  1
+#!/usr/bin/env ruby
  2
+
  3
+require 'mspec/version'
  4
+require 'mspec/utils/options'
  5
+require 'mspec/utils/script'
  6
+
  7
+
  8
+class MSpecTag < MSpecScript
  9
+  def initialize
  10
+    super
  11
+
  12
+    config[:tagger]  = :add
  13
+    config[:tag]     = 'fails:'
  14
+    config[:outcome] = :fail
  15
+    config[:ltags]   = []
  16
+  end
  17
+
  18
+  def options(argv=ARGV)
  19
+    options = MSpecOptions.new "mspec tag [options] (FILE|DIRECTORY|GLOB)+", 30, config
  20
+
  21
+    options.doc " Ask yourself:"
  22
+    options.doc "  1. What specs to run?"
  23
+    options.doc "  2. How to modify the execution?"
  24
+    options.doc "  3. How to display the output?"
  25
+    options.doc "  4. What tag action to perform?"
  26
+    options.doc "  5. When to perform it?"
  27
+
  28
+    options.doc "\n What specs to run"
  29
+    options.filters
  30
+
  31
+    options.doc "\n How to modify the execution"
  32
+    options.configure { |f| load f }
  33
+    options.name
  34
+    options.pretend
  35
+    options.unguarded
  36
+    options.interrupt
  37
+
  38
+    options.doc "\n How to display their output"
  39
+    options.formatters
  40
+    options.verbose
  41
+
  42
+    options.doc "\n What action to perform and when to perform it"
  43
+    options.on("-N", "--add", "TAG",
  44
+       "Add TAG with format 'tag' or 'tag(comment)' (see -Q, -F, -L)") do |o|
  45
+      config[:tagger] = :add
  46
+      config[:tag] = "#{o}:"
  47
+    end
  48
+    options.on("-R", "--del", "TAG",
  49
+       "Delete TAG (see -Q, -F, -L)") do |o|
  50
+      config[:tagger] = :del
  51
+      config[:tag] = "#{o}:"
  52
+      config[:outcome] = :pass
  53
+    end
  54
+    options.on("-Q", "--pass", "Apply action to specs that pass (default for --del)") do
  55
+      config[:outcome] = :pass
  56
+    end
  57
+    options.on("-F", "--fail", "Apply action to specs that fail (default for --add)") do
  58
+      config[:outcome] = :fail
  59
+    end
  60
+    options.on("-L", "--all", "Apply action to all specs") do
  61
+      config[:outcome] = :all
  62
+    end
  63
+    options.on("--list", "TAG", "Display descriptions of any specs tagged with TAG") do |t|
  64
+      config[:tagger] = :list
  65
+      config[:ltags] << t
  66
+    end
  67
+    options.on("--list-all", "Display descriptions of any tagged specs") do
  68
+      config[:tagger] = :list_all
  69
+    end
  70
+    options.on("--purge", "Remove all tags not matching any specs") do
  71
+      config[:tagger] = :purge
  72
+    end
  73
+
  74
+    options.doc "\n Help!"
  75
+    options.version MSpec::VERSION
  76
+    options.help
  77
+
  78
+    options.doc "\n Custom options"
  79
+    custom_options options
  80
+
  81
+    options.doc "\n How might this work in the real world?"
  82
+    options.doc "\n   1. To add the 'fails' tag to failing specs"
  83
+    options.doc "\n     $ mspec tag path/to/the_file_spec.rb"
  84
+    options.doc "\n   2. To remove the 'fails' tag from passing specs"
  85
+    options.doc "\n     $ mspec tag --del fails path/to/the_file_spec.rb"
  86
+    options.doc "\n   3. To display the descriptions for all specs tagged with 'fails'"
  87
+    options.doc "\n     $ mspec tag --list fails path/to/the/specs"
  88
+    options.doc ""
  89
+
  90
+    patterns = options.parse argv
  91
+    if patterns.empty?
  92
+      puts options
  93
+      puts "No files specified."
  94
+      exit 1
  95
+    end
  96
+    @files = files patterns
  97
+  end
  98
+
  99
+  def register
  100
+    case config[:tagger]
  101
+    when :add, :del
  102
+      tag = SpecTag.new config[:tag]
  103
+      tagger = TagAction.new(config[:tagger], config[:outcome], tag.tag, tag.comment,
  104
+                             config[:atags], config[:astrings])
  105
+    when :list, :list_all
  106
+      tagger = TagListAction.new config[:tagger] == :list_all ? nil : config[:ltags]
  107
+      MSpec.register_mode :pretend
  108
+      config[:formatter] = false
  109
+    when :purge
  110
+      tagger = TagPurgeAction.new
  111
+      MSpec.register_mode :pretend
  112
+      MSpec.register_mode :unguarded
  113
+      config[:formatter] = false
  114
+    else
  115
+      raise ArgumentError, "No recognized action given"
  116
+    end
  117
+    tagger.register
  118
+
  119
+    super
  120
+  end
  121
+
  122
+  def run
  123
+    MSpec.register_tags_patterns config[:tags_patterns]
  124
+    MSpec.register_files @files
  125
+
  126
+    MSpec.process
  127
+    exit MSpec.exit_code
  128
+  end
  129
+end
  130
+
157  mspec/lib/mspec/commands/mspec.rb
... ...
@@ -0,0 +1,157 @@
  1
+#!/usr/bin/env ruby
  2
+
  3
+MSPEC_HOME = File.expand_path(File.dirname(__FILE__) + '/../../..')
  4
+
  5
+require 'mspec/version'
  6
+require 'mspec/utils/options'
  7
+require 'mspec/utils/script'
  8
+require 'mspec/helpers/tmp'
  9
+require 'mspec/runner/actions/timer'
  10
+
  11
+
  12
+class MSpecMain < MSpecScript
  13
+  def initialize
  14
+    config[:includes] = []
  15
+    config[:requires] = []
  16
+    config[:target]   = ENV['RUBY'] || 'ruby'
  17
+    config[:flags]    = []
  18
+    config[:command]  = nil
  19
+    config[:options]  = []
  20
+  end
  21
+
  22
+  def options(argv=ARGV)
  23
+    config[:command] = argv.shift if ["ci", "run", "tag"].include?(argv[0])
  24
+
  25
+    options = MSpecOptions.new "mspec [COMMAND] [options] (FILE|DIRECTORY|GLOB)+", 30, config
  26
+
  27
+    options.doc " The mspec command sets up and invokes the sub-commands"
  28
+    options.doc " (see below) to enable, for instance, running the specs"
  29
+    options.doc " with different implementations like ruby, jruby, rbx, etc.\n"
  30
+
  31
+    options.configure do |f|
  32
+      load f
  33
+      config[:options] << '-B' << f
  34
+    end
  35
+
  36
+    options.targets
  37
+
  38
+    options.on("-D", "--gdb", "Run under gdb") do
  39
+      config[:flags] << '--gdb'
  40
+    end
  41
+    options.on("-A", "--valgrind", "Run under valgrind") do
  42
+      config[:flags] << '--valgrind'
  43
+    end
  44
+    options.on("--warnings", "Don't supress warnings") do
  45
+      config[:flags] << '-w'
  46
+      ENV['OUTPUT_WARNINGS'] = '1'
  47
+    end
  48
+    options.on("-j", "--multi", "Run multiple (possibly parallel) subprocesses") do
  49
+      config[:multi] = true
  50
+      config[:options] << "-fy"
  51
+    end
  52
+    options.version MSpec::VERSION do
  53
+      if config[:command]
  54
+        config[:options] << "-v"
  55
+      else
  56
+        puts "#{File.basename $0} #{MSpec::VERSION}"
  57
+        exit
  58
+      end
  59
+    end
  60
+    options.help do
  61
+      if config[:command]
  62
+        config[:options] << "-h"
  63
+      else
  64
+        puts options
  65
+        exit 1
  66
+      end
  67
+    end
  68
+
  69
+    options.doc "\n Custom options"
  70
+    custom_options options
  71
+
  72
+    # The rest of the help output
  73
+    options.doc "\n where COMMAND is one of:\n"
  74
+    options.doc "   run - Run the specified specs (default)"
  75
+    options.doc "   ci  - Run the known good specs"
  76
+    options.doc "   tag - Add or remove tags\n"
  77
+    options.doc " mspec COMMAND -h for more options\n"
  78
+
  79
+    options.on_extra { |o| config[:options] << o }
  80
+    config[:options].concat options.parse(argv)
  81
+  end
  82
+
  83
+  def register; end
  84
+
  85
+  def parallel
  86
+    @parallel ||= !(Object.const_defined?(:JRUBY_VERSION) ||
  87
+                  /(mswin|mingw)/ =~ RUBY_PLATFORM)
  88
+  end
  89
+
  90
+  def fork(&block)
  91
+    parallel ? Kernel.fork(&block) : block.call
  92
+  end
  93
+
  94
+  def report(files, timer)
  95
+    require 'yaml'
  96
+
  97
+    exceptions = []
  98
+    tally = Tally.new
  99
+
  100
+    files.each do |file|
  101
+      d = File.open(file, "r") { |f| YAML.load f }
  102
+      File.delete file
  103
+
  104
+      exceptions += Array(d['exceptions'])
  105
+      tally.files!        d['files']
  106
+      tally.examples!     d['examples']
  107
+      tally.expectations! d['expectations']
  108
+      tally.errors!       d['errors']
  109
+      tally.failures!     d['failures']
  110
+    end
  111
+
  112
+    print "\n"
  113
+    exceptions.each_with_index do |exc, index|
  114
+      print "\n#{index+1})\n", exc, "\n"
  115
+    end
  116
+    print "\n#{timer.format}\n\n#{tally.format}\n"
  117
+  end
  118
+
  119
+  def multi_exec(argv)
  120
+    timer = TimerAction.new
  121
+    timer.start
  122
+
  123
+    files = config[:ci_files].inject([]) do |list, item|
  124
+      name = tmp "mspec-ci-multi-#{list.size}"
  125
+
  126
+      rest = argv + ["-o", name, item]
  127
+      fork { system [config[:target], *rest].join(" ") }
  128
+
  129
+      list << name
  130
+    end
  131
+
  132
+    Process.waitall
  133
+    timer.finish
  134
+    report files, timer
  135
+  end
  136
+
  137
+  def run
  138
+    ENV['MSPEC_RUNNER'] = '1'
  139
+    ENV['RUBY_EXE']     = config[:target]
  140
+    ENV['RUBY_FLAGS']   = config[:flags].join " "
  141
+
  142
+    argv = []
  143
+    argv.concat config[:flags]
  144
+    argv.concat config[:includes]
  145
+    argv.concat config[:requires]
  146
+    argv << "-v"
  147
+    argv << "#{MSPEC_HOME}/bin/mspec-#{ config[:command] || "run" }"
  148
+    argv.concat config[:options]
  149
+
  150
+    if config[:multi] and config[:command] == "ci"
  151
+      multi_exec argv
  152
+    else
  153
+      exec config[:target], *argv
  154
+    end
  155
+  end
  156
+end
  157
+
2  mspec/lib/mspec/expectations.rb
... ...
@@ -0,0 +1,2 @@
  1
+require 'mspec/expectations/expectations'
  2
+require 'mspec/expectations/should'
17  mspec/lib/mspec/expectations/expectations.rb
... ...
@@ -0,0 +1,17 @@
  1
+class ExpectationNotMetError < StandardError; end
  2
+class ExpectationNotFoundError < StandardError
  3
+  def message
  4
+    "No behavior expectation was found in the example"
  5
+  end
  6
+end
  7
+
  8
+class Expectation
  9
+  def self.fail_with(expected, actual)
  10
+    if expected.to_s.size + actual.to_s.size > 80
  11
+      message = expected.to_s.chomp + "\n" + actual.to_s
  12
+    else
  13
+      message = expected.to_s + " " + actual.to_s
  14
+    end
  15
+    Kernel.raise ExpectationNotMetError, message
  16
+  end
  17
+end
25  mspec/lib/mspec/expectations/should.rb
... ...
@@ -0,0 +1,25 @@
  1
+class Object
  2
+  def should(matcher=nil)
  3
+    MSpec.expectation
  4
+    MSpec.actions :expectation, MSpec.current.state
  5
+    if matcher
  6
+      unless matcher.matches?(self)
  7
+        Expectation.fail_with(*matcher.failure_message)
  8
+      end
  9
+    else
  10
+      PositiveOperatorMatcher.new(self)
  11
+    end
  12
+  end
  13
+
  14
+  def should_not(matcher=nil)
  15
+    MSpec.expectation
  16
+    MSpec.actions :expectation, MSpec.current.state
  17
+    if matcher
  18
+      if matcher.matches?(self)
  19
+        Expectation.fail_with(*matcher.negative_failure_message)
  20
+      end
  21
+    else
  22
+      NegativeOperatorMatcher.new(self)
  23
+    end
  24
+  end
  25
+end
16  mspec/lib/mspec/guards.rb
... ...
@@ -0,0 +1,16 @@
  1
+require 'mspec/utils/ruby_name'
  2
+require 'mspec/guards/background'
  3
+require 'mspec/guards/bug'
  4
+require 'mspec/guards/compliance'
  5
+require 'mspec/guards/conflict'
  6
+require 'mspec/guards/endian'
  7
+require 'mspec/guards/extensions'
  8
+require 'mspec/guards/guard'
  9
+require 'mspec/guards/noncompliance'
  10
+require 'mspec/guards/platform'
  11
+require 'mspec/guards/quarantine'
  12
+require 'mspec/guards/runner'
  13
+require 'mspec/guards/support'
  14
+require 'mspec/guards/superuser'
  15
+require 'mspec/guards/tty'
  16
+require 'mspec/guards/version'
21  mspec/lib/mspec/guards/background.rb
... ...
@@ -0,0 +1,21 @@
  1
+require 'mspec/guards/guard'
  2
+
  3
+# Some specs, notably those for Readline, will block under certain
  4
+# circumstances when run as background or subprocesses. Use this guard for
  5
+# such specs.
  6
+
  7
+class BackgroundGuard < SpecGuard
  8
+  def match?
  9
+    MSpec.mode? :background
  10
+  end
  11
+end
  12
+
  13
+class Object
  14
+  def process_is_foreground
  15
+    g = BackgroundGuard.new
  16
+    g.name = :process_is_foreground
  17
+    yield if g.yield? true
  18
+  ensure
  19
+    g.unregister
  20
+  end
  21
+end
24  mspec/lib/mspec/guards/bug.rb
... ...
@@ -0,0 +1,24 @@
  1
+require 'mspec/guards/version'
  2
+
  3
+class BugGuard < VersionGuard
  4
+  def initialize(bug, version)
  5
+    @bug = bug
  6
+    @version = SpecVersion.new version, true
  7
+    self.parameters = [@bug, @version]
  8
+  end
  9
+
  10
+  def match?
  11
+    return false if MSpec.mode? :no_ruby_bug
  12
+    standard? && ruby_version <= @version
  13
+  end
  14
+end