Module: MSpec

Defined in:
lib/mspec/matchers/include.rb,
lib/mspec/version.rb,
lib/mspec/runner/mspec.rb

Overview

Cannot override #include at the toplevel in MRI

Constant Summary collapse

VERSION =
SpecVersion.new "1.6.0"

Class Method Summary collapse

Class Method Details

.actions(action, *args) ⇒ Object



62
63
64
65
# File 'lib/mspec/runner/mspec.rb', line 62

def self.actions(action, *args)
  actions = retrieve(action)
  actions.each { |obj| obj.send action, *args } if actions
end

.clear_currentObject

Sets the toplevel ContextState to nil.



100
101
102
# File 'lib/mspec/runner/mspec.rb', line 100

def self.clear_current
  store :current, nil
end

.clear_expectationsObject

Resets the flag that an expectation has been encountered in an example.



264
265
266
# File 'lib/mspec/runner/mspec.rb', line 264

def self.clear_expectations
  store :expectations, false
end

.clear_modesObject

Clears all registered modes.



158
159
160
# File 'lib/mspec/runner/mspec.rb', line 158

def self.clear_modes
  store :modes, []
end

.currentObject

Returns the toplevel ContextState.



105
106
107
# File 'lib/mspec/runner/mspec.rb', line 105

def self.current
  retrieve :current
end

.delete_tag(tag) ⇒ Object

Deletes tag from the tag file if it exists. Returns true if the tag is deleted, false otherwise. Deletes the tag file if it is empty.



334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
# File 'lib/mspec/runner/mspec.rb', line 334

def self.delete_tag(tag)
  deleted = false
  pattern = /#{tag.tag}.*#{Regexp.escape(tag.escape(tag.description))}/
  file = tags_file
  if File.exist? file
    lines = IO.readlines(file)
    File.open(file, "wb") do |f|
      lines.each do |line|
        unless pattern =~ line.chomp
          f.puts line unless line.empty?
        else
          deleted = true
        end
      end
    end
    File.delete file unless File.size? file
  end
  return deleted
end

.delete_tagsObject

Removes the tag file associated with a spec file.



355
356
357
358
# File 'lib/mspec/runner/mspec.rb', line 355

def self.delete_tags
  file = tags_file
  File.delete file if File.exist? file
end

.describe(mod, options = nil, &block) ⇒ Object



31
32
33
34
35
36
37
38
39
# File 'lib/mspec/runner/mspec.rb', line 31

def self.describe(mod, options=nil, &block)
  state = ContextState.new mod, options
  state.parent = current

  MSpec.register_current state
  state.describe(&block)

  state.process unless state.shared? or current
end

.disable_feature(feature) ⇒ Object



171
172
173
# File 'lib/mspec/runner/mspec.rb', line 171

def self.disable_feature(feature)
  retrieve(:features)[feature] = false
end

.enable_feature(feature) ⇒ Object



167
168
169
# File 'lib/mspec/runner/mspec.rb', line 167

def self.enable_feature(feature)
  retrieve(:features)[feature] = true
end

.exit_codeObject

Retrieves the stored exit code.



125
126
127
# File 'lib/mspec/runner/mspec.rb', line 125

def self.exit_code
  retrieve(:exit).to_i
end

.expectationObject

Records that an expectation has been encountered in an example.



254
255
256
# File 'lib/mspec/runner/mspec.rb', line 254

def self.expectation
  store :expectations, true
end

.expectation?Boolean

Returns true if an expectation has been encountered

Returns:

  • (Boolean)


259
260
261
# File 'lib/mspec/runner/mspec.rb', line 259

def self.expectation?
  retrieve :expectations
end

.feature_enabled?(feature) ⇒ Boolean

Returns:

  • (Boolean)


175
176
177
# File 'lib/mspec/runner/mspec.rb', line 175

def self.feature_enabled?(feature)
  retrieve(:features)[feature] || false
end

.filesObject



47
48
49
50
51
52
53
54
55
56
57
58
59
60
# File 'lib/mspec/runner/mspec.rb', line 47

def self.files
  return unless files = retrieve(:files)

  shuffle files if randomize?
  files.each do |file|
    @env = Object.new
    @env.extend MSpec

    store :file, file
    actions :load
    protect("loading #{file}") { Kernel.load file }
    actions :unload
  end
end

.guardObject

Guards can be nested, so a stack is necessary to know when we have exited the toplevel guard.



82
83
84
# File 'lib/mspec/runner/mspec.rb', line 82

def self.guard
  @guarded << true
end

.guarded?Boolean

Returns:

  • (Boolean)


90
91
92
# File 'lib/mspec/runner/mspec.rb', line 90

def self.guarded?
  not @guarded.empty?
end

.include(*expected) ⇒ Object



28
29
30
# File 'lib/mspec/matchers/include.rb', line 28

def include(*expected)
  IncludeMatcher.new(*expected)
end

.mode?(mode) ⇒ Boolean

Returns true if mode is registered.

Returns:

  • (Boolean)


163
164
165
# File 'lib/mspec/runner/mspec.rb', line 163

def self.mode?(mode)
  retrieve(:modes).include? mode
end

.processObject



41
42
43
44
45
# File 'lib/mspec/runner/mspec.rb', line 41

def self.process
  actions :start
  files
  actions :finish
end

.protect(location, &block) ⇒ Object



67
68
69
70
71
72
73
74
75
76
77
78
# File 'lib/mspec/runner/mspec.rb', line 67

def self.protect(location, &block)
  begin
    @env.instance_eval(&block)
    return true
  rescue SystemExit
    raise
  rescue Exception => exc
    register_exit 1
    actions :exception, ExceptionState.new(current && current.state, location, exc)
    return false
  end
end

.randomize(flag = true) ⇒ Object



225
226
227
# File 'lib/mspec/runner/mspec.rb', line 225

def self.randomize(flag=true)
  @randomize = flag
end

.randomize?Boolean

Returns:

  • (Boolean)


229
230
231
# File 'lib/mspec/runner/mspec.rb', line 229

def self.randomize?
  @randomize == true
end

.read_tags(keys) ⇒ Object

Returns a list of tags matching any tag string in keys based on the return value of keys.include?("tag_name")



288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
# File 'lib/mspec/runner/mspec.rb', line 288

def self.read_tags(keys)
  tags = []
  file = tags_file
  if File.exist? file
    File.open(file, "rb") do |f|
      f.each_line do |line|
        line.chomp!
        next if line.empty?
        tag = SpecTag.new line.chomp
        tags << tag if keys.include? tag.tag
      end
    end
  end
  tags
end

.register(symbol, action) ⇒ Object

This method is used for registering actions that are run at particular points in the spec cycle:

:start        before any specs are run
:load         before a spec file is loaded
:enter        before a describe block is run
:before       before a single spec is run
:add          while a describe block is adding examples to run later
:expectation  before a 'should', 'should_receive', etc.
:example      after an example block is run, passed the block
:exception    after an exception is rescued
:after        after a single spec is run
:leave        after a describe block is run
:unload       after a spec file is run
:finish       after all specs are run

Objects registered as actions above should respond to a method of the same name. For example, if an object is registered as a :start action, it should respond to a #start method call.

Additionally, there are two “action” lists for filtering specs:

:include  return true if the spec should be run
:exclude  return true if the spec should NOT be run


212
213
214
215
216
217
# File 'lib/mspec/runner/mspec.rb', line 212

def self.register(symbol, action)
  unless value = retrieve(symbol)
    value = store symbol, []
  end
  value << action unless value.include? action
end

.register_current(state) ⇒ Object

Sets the toplevel ContextState to state.



95
96
97
# File 'lib/mspec/runner/mspec.rb', line 95

def self.register_current(state)
  store :current, state
end

.register_exit(code) ⇒ Object

Stores the exit code used by the runner scripts.



120
121
122
# File 'lib/mspec/runner/mspec.rb', line 120

def self.register_exit(code)
  store :exit, code
end

.register_files(files) ⇒ Object

Stores the list of files to be evaluated.



130
131
132
# File 'lib/mspec/runner/mspec.rb', line 130

def self.register_files(files)
  store :files, files
end

.register_mode(mode) ⇒ Object

Registers an operating mode. Modes recognized by MSpec:

:pretend - actions execute but specs are not run
:verify - specs are run despite guards and the result is
          verified to match the expectation of the guard
:report - specs that are guarded are reported
:unguarded - all guards are forced off


152
153
154
155
# File 'lib/mspec/runner/mspec.rb', line 152

def self.register_mode(mode)
  modes = retrieve :modes
  modes << mode unless modes.include? mode
end

.register_shared(state) ⇒ Object

Stores the shared ContextState keyed by description.



110
111
112
# File 'lib/mspec/runner/mspec.rb', line 110

def self.register_shared(state)
  @shared[state.to_s] = state
end

.register_tags_patterns(patterns) ⇒ Object

Stores one or more substitution patterns for transforming a spec filename into a tags filename, where each pattern has the form:

[Regexp, String]

See also tags_file.



141
142
143
# File 'lib/mspec/runner/mspec.rb', line 141

def self.register_tags_patterns(patterns)
  store :tags_patterns, patterns
end

.repeatObject



237
238
239
240
241
# File 'lib/mspec/runner/mspec.rb', line 237

def self.repeat
  (@repeat || 1).times do
    yield
  end
end

.repeat=(times) ⇒ Object



233
234
235
# File 'lib/mspec/runner/mspec.rb', line 233

def self.repeat=(times)
  @repeat = times
end

.retrieve(symbol) ⇒ Object



179
180
181
# File 'lib/mspec/runner/mspec.rb', line 179

def self.retrieve(symbol)
  instance_variable_get :"@#{symbol}"
end

.retrieve_shared(desc) ⇒ Object

Returns the shared ContextState matching description.



115
116
117
# File 'lib/mspec/runner/mspec.rb', line 115

def self.retrieve_shared(desc)
  @shared[desc.to_s]
end

.shuffle(ary) ⇒ Object



243
244
245
246
247
248
249
250
251
# File 'lib/mspec/runner/mspec.rb', line 243

def self.shuffle(ary)
  return if ary.empty?

  size = ary.size
  size.times do |i|
    r = rand(size - i - 1)
    ary[i], ary[r] = ary[r], ary[i]
  end
end

.store(symbol, value) ⇒ Object



183
184
185
# File 'lib/mspec/runner/mspec.rb', line 183

def self.store(symbol, value)
  instance_variable_set :"@#{symbol}", value
end

.tags_fileObject

Transforms a spec filename into a tags filename by applying each substitution pattern in :tags_pattern. The default patterns are:

[%r(/spec/), '/spec/tags/'], [/_spec.rb$/, '_tags.txt']

which will perform the following transformation:

path/to/spec/class/method_spec.rb => path/to/spec/tags/class/method_tags.txt

See also register_tags_patterns.



278
279
280
281
282
283
284
# File 'lib/mspec/runner/mspec.rb', line 278

def self.tags_file
  patterns = retrieve(:tags_patterns) ||
             [[%r(spec/), 'spec/tags/'], [/_spec.rb$/, '_tags.txt']]
  patterns.inject(retrieve(:file).dup) do |file, pattern|
    file.gsub(*pattern)
  end
end

.unguardObject



86
87
88
# File 'lib/mspec/runner/mspec.rb', line 86

def self.unguard
  @guarded.pop
end

.unregister(symbol, action) ⇒ Object



219
220
221
222
223
# File 'lib/mspec/runner/mspec.rb', line 219

def self.unregister(symbol, action)
  if value = retrieve(symbol)
    value.delete action
  end
end

.write_tag(tag) ⇒ Object

Writes tag to the tag file if it does not already exist. Returns true if the tag is written, false otherwise.



317
318
319
320
321
322
323
324
325
326
327
328
329
# File 'lib/mspec/runner/mspec.rb', line 317

def self.write_tag(tag)
  string = tag.to_s
  file = tags_file
  path = File.dirname file
  FileUtils.mkdir_p path unless File.exist? path
  if File.exist? file
    File.open(file, "rb") do |f|
      f.each_line { |line| return false if line.chomp == string }
    end
  end
  File.open(file, "ab") { |f| f.puts string }
  return true
end

.write_tags(tags) ⇒ Object

Writes each tag in tags to the tag file. Overwrites the tag file if it exists.



306
307
308
309
310
311
312
313
# File 'lib/mspec/runner/mspec.rb', line 306

def self.write_tags(tags)
  file = tags_file
  path = File.dirname file
  FileUtils.mkdir_p path unless File.exist? path
  File.open(file, "wb") do |f|
    tags.each { |t| f.puts t }
  end
end