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.5.17"

Class Method Summary collapse

Class Method Details

.actions(action, *args) ⇒ Object



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

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.



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

def self.clear_current
  store :current, nil
end

.clear_expectationsObject

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



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

def self.clear_expectations
  store :expectations, false
end

.clear_modesObject

Clears all registered modes.



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

def self.clear_modes
  store :modes, []
end

.currentObject

Returns the toplevel ContextState.



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

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.



323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
# File 'lib/mspec/runner/mspec.rb', line 323

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.



344
345
346
347
# File 'lib/mspec/runner/mspec.rb', line 344

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

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



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

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



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

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

.enable_feature(feature) ⇒ Object



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

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

.exit_codeObject

Retrieves the stored exit code.



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

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

.expectationObject

Records that an expectation has been encountered in an example.



243
244
245
# File 'lib/mspec/runner/mspec.rb', line 243

def self.expectation
  store :expectations, true
end

.expectation?Boolean

Returns true if an expectation has been encountered

Returns:

  • (Boolean)


248
249
250
# File 'lib/mspec/runner/mspec.rb', line 248

def self.expectation?
  retrieve :expectations
end

.feature_enabled?(feature) ⇒ Boolean

Returns:

  • (Boolean)


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

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

.filesObject



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

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.



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

def self.guard
  @guarded << true
end

.guarded?Boolean

Returns:

  • (Boolean)


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

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)


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

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

.processObject



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

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

.protect(location, &block) ⇒ Object



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

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



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

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

.randomize?Boolean

Returns:

  • (Boolean)


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

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")



277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
# File 'lib/mspec/runner/mspec.rb', line 277

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


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

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.



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

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

.register_exit(code) ⇒ Object

Stores the exit code used by the runner scripts.



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

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

.register_files(files) ⇒ Object

Stores the list of files to be evaluated.



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

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


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

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.



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

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.



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

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

.retrieve(symbol) ⇒ Object



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

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

.retrieve_shared(desc) ⇒ Object

Returns the shared ContextState matching description.



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

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

.shuffle(ary) ⇒ Object



232
233
234
235
236
237
238
239
240
# File 'lib/mspec/runner/mspec.rb', line 232

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



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

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.



267
268
269
270
271
272
273
# File 'lib/mspec/runner/mspec.rb', line 267

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



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

def self.unguard
  @guarded.pop
end

.unregister(symbol, action) ⇒ Object



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

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.



306
307
308
309
310
311
312
313
314
315
316
317
318
# File 'lib/mspec/runner/mspec.rb', line 306

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.



295
296
297
298
299
300
301
302
# File 'lib/mspec/runner/mspec.rb', line 295

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