Module: MSpec

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

Overview

Cannot override #include at the toplevel in MRI

Class Method Summary collapse

Class Method Details

.actions(action, *args) ⇒ Object



135
136
137
138
# File 'lib/extensions/mspec/mspec/runner/mspec.rb', line 135

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.



222
223
224
# File 'lib/extensions/mspec/mspec/runner/mspec.rb', line 222

def self.clear_current
  store :current, nil
end

.clear_expectationsObject

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



386
387
388
# File 'lib/extensions/mspec/mspec/runner/mspec.rb', line 386

def self.clear_expectations
  store :expectations, false
end

.clear_modesObject

Clears all registered modes.



280
281
282
# File 'lib/extensions/mspec/mspec/runner/mspec.rb', line 280

def self.clear_modes
  store :modes, []
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.



466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
# File 'lib/extensions/mspec/mspec/runner/mspec.rb', line 466

def self.delete_tag(tag)
  deleted = false
  desc = tag.escape(tag.description)
  file = tags_file
  if File.exist? file
    lines = IO.readlines(file)
    File.open(file, "w:utf-8") do |f|
      lines.each do |line|
        line = line.chomp
        if line.start_with?(tag.tag) and line.end_with?(desc)
          deleted = true
        else
          f.puts line unless line.empty?
        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.



488
489
490
491
# File 'lib/extensions/mspec/mspec/runner/mspec.rb', line 488

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

.deprecate(what, replacement) ⇒ Object



2
3
4
5
# File 'lib/extensions/mspec/mspec/utils/deprecate.rb', line 2

def self.deprecate(what, replacement)
  user_caller = caller.find { |line| !line.include?('lib/mspec') }
  $stderr.puts "\n#{what} is deprecated, use #{replacement} instead.\nfrom #{user_caller}"
end

.disable_feature(feature) ⇒ Object



293
294
295
# File 'lib/extensions/mspec/mspec/runner/mspec.rb', line 293

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

.each_file(&block) ⇒ Object



98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
# File 'lib/extensions/mspec/mspec/runner/mspec.rb', line 98

def self.each_file(&block)
  if ENV["MSPEC_MULTI"]
    STDOUT.print "."
    STDOUT.flush
    while (file = STDIN.gets.chomp) != "QUIT"
      yield file
      STDOUT.print "."
      STDOUT.flush
    end
  else
    return unless files = retrieve(:files)
    shuffle files if randomize?
    files.each(&block)
  end
end

.enable_feature(feature) ⇒ Object



289
290
291
# File 'lib/extensions/mspec/mspec/runner/mspec.rb', line 289

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

.exc_locationsObject



49
50
51
# File 'lib/extensions/mspec/mspec/runner/mspec.rb', line 49

def self.exc_locations
  @exc_locations
end

.expectationObject

Records that an expectation has been encountered in an example.



376
377
378
# File 'lib/extensions/mspec/mspec/runner/mspec.rb', line 376

def self.expectation
  store :expectations, true
end

.expectation?Boolean

Returns true if an expectation has been encountered

Returns:

  • (Boolean)


381
382
383
# File 'lib/extensions/mspec/mspec/runner/mspec.rb', line 381

def self.expectation?
  retrieve :expectations
end

.feature_enabled?(feature) ⇒ Boolean

Returns:

  • (Boolean)


297
298
299
# File 'lib/extensions/mspec/mspec/runner/mspec.rb', line 297

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

.filesObject



87
88
89
90
91
92
93
94
95
96
# File 'lib/extensions/mspec/mspec/runner/mspec.rb', line 87

def self.files
  each_file do |file|
    setup_env
    store :file, file
    actions :load
    puts "MSPEC run spec: ["+file.to_s+"]"
    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.



204
205
206
# File 'lib/extensions/mspec/mspec/runner/mspec.rb', line 204

def self.guard
  @guarded << true
end

.guarded?Boolean

Returns:

  • (Boolean)


212
213
214
# File 'lib/extensions/mspec/mspec/runner/mspec.rb', line 212

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

.include(*expected) ⇒ Object



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

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

.make_tag_dir(path) ⇒ Object



426
427
428
429
430
431
432
433
434
435
# File 'lib/extensions/mspec/mspec/runner/mspec.rb', line 426

def self.make_tag_dir(path)
  parent = File.dirname(path)
  return if File.exist? parent
  begin
    Dir.mkdir(parent)
  rescue SystemCallError
    make_tag_dir(parent)
    Dir.mkdir(parent)
  end
end

.mode?(mode) ⇒ Boolean

Returns true if mode is registered.

Returns:

  • (Boolean)


285
286
287
# File 'lib/extensions/mspec/mspec/runner/mspec.rb', line 285

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

.not_supported_countObject



53
54
55
# File 'lib/extensions/mspec/mspec/runner/mspec.rb', line 53

def self.not_supported_count
  @not_supported_count
end

.protect(location, &block) ⇒ Object



140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
# File 'lib/extensions/mspec/mspec/runner/mspec.rb', line 140

def self.protect(location, &block)

  #puts ">>>>>>"
  #puts caller
  #puts "<<<<<<"

  passed = false

  begin
    @env.instance_eval(&block)
    #RHO
    passed = true
    #RHO
    #return true
  rescue SystemExit => e
    raise e
  rescue Exception => exc
    register_exit 1
    actions :exception, ExceptionState.new(current && current.state, location, exc)

      #RHO
      puts "FAIL: #{current} - #{exc.message}\n" + (@backtrace ? exc.backtrace.join("\n") : "")# + " @exc_count[#{@exc_count.to_s}]"

      not_supported = (exc.message=='RHO: not supported')

      info = { 'message' => exc.message, 'backtrace' => exc.backtrace, 'not_supported' => not_supported }

      key = location.to_s
      key = current.state.description if current and current.state and current.state.description
      key = 'unknown' if key.nil?

      if @exc_locations[key].nil?
        @exc_locations[key] = []
      end

      @exc_locations[key] << info

      #@exc_locations << { 'spec' => current, 'message' => exc.message, 'backtrace' => exc.backtrace }
      if not_supported
        @not_supported_count+=1
      else
        @exc_count+=1
      end
      #RHO

    return false
  end

  #RHO
  if passed
      begin
          #if current.to_s.length > 0
              puts "PASSED: #{current.to_s} - OK"# +" @exc_count[#{@exc_count.to_s}]"
          #end
      rescue
      end
  end
  return true
  #RHO

end

.randomize(flag = true) ⇒ Object



347
348
349
# File 'lib/extensions/mspec/mspec/runner/mspec.rb', line 347

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

.randomize?Boolean

Returns:

  • (Boolean)


351
352
353
# File 'lib/extensions/mspec/mspec/runner/mspec.rb', line 351

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



410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
# File 'lib/extensions/mspec/mspec/runner/mspec.rb', line 410

def self.read_tags(keys)
  tags = []
  file = tags_file
  if File.exist? file
    File.open(file, "r:utf-8") do |f|
      f.each_line do |line|
        line.chomp!
        next if line.empty?
        tag = SpecTag.new line
        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


334
335
336
337
338
339
# File 'lib/extensions/mspec/mspec/runner/mspec.rb', line 334

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.



217
218
219
# File 'lib/extensions/mspec/mspec/runner/mspec.rb', line 217

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

.register_exit(code) ⇒ Object

Stores the exit code used by the runner scripts.



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

def self.register_exit(code)
  store :exit, code
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


274
275
276
277
# File 'lib/extensions/mspec/mspec/runner/mspec.rb', line 274

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.



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

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.



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

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

.repeatObject



359
360
361
362
363
# File 'lib/extensions/mspec/mspec/runner/mspec.rb', line 359

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

.repeat=(times) ⇒ Object



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

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

.retrieve(symbol) ⇒ Object



301
302
303
# File 'lib/extensions/mspec/mspec/runner/mspec.rb', line 301

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

.retrieve_shared(desc) ⇒ Object

Returns the shared ContextState matching description.



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

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

.run_spec(file, settings) ⇒ Object

RHO



115
116
117
118
119
120
121
122
123
124
125
126
127
# File 'lib/extensions/mspec/mspec/runner/mspec.rb', line 115

def self.run_spec(file,settings)
 setup_env

 $spec_settings = settings

 store :file, file
 actions :load

 puts "MSPEC run spec: ["+file.to_s+"]"

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

.setup_envObject

RHO



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

def self.setup_env
  @env = Object.new
  @env.extend MSpec
end

.shuffle(ary) ⇒ Object



365
366
367
368
369
370
371
372
373
# File 'lib/extensions/mspec/mspec/runner/mspec.rb', line 365

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



305
306
307
# File 'lib/extensions/mspec/mspec/runner/mspec.rb', line 305

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.



400
401
402
403
404
405
406
# File 'lib/extensions/mspec/mspec/runner/mspec.rb', line 400

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



208
209
210
# File 'lib/extensions/mspec/mspec/runner/mspec.rb', line 208

def self.unguard
  @guarded.pop
end

.unregister(symbol, action) ⇒ Object



341
342
343
344
345
# File 'lib/extensions/mspec/mspec/runner/mspec.rb', line 341

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.



449
450
451
452
453
454
455
456
457
458
459
460
461
# File 'lib/extensions/mspec/mspec/runner/mspec.rb', line 449

def self.write_tag(tag)
  tags = read_tags([tag.tag])
  tags.each do |t|
    if t.tag == tag.tag and t.description == tag.description
      return false
    end
  end

  file = tags_file
  make_tag_dir(file)
  File.open(file, "a:utf-8") { |f| f.puts tag.to_s }
  return true
end

.write_tags(tags) ⇒ Object

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



439
440
441
442
443
444
445
# File 'lib/extensions/mspec/mspec/runner/mspec.rb', line 439

def self.write_tags(tags)
  file = tags_file
  make_tag_dir(file)
  File.open(file, "w:utf-8") do |f|
    tags.each { |t| f.puts t }
  end
end