1 require 'mspec/runner/context'
2 require 'mspec/runner/exception'
3 require 'mspec/runner/tag'
28 def self.describe(mod, options=nil, &block)
29 state = ContextState.new mod, options
30 state.parent = current
32 MSpec.register_current state
33 state.describe(&block)
35 state.process unless state.shared? or current
45 return unless files = retrieve(:files)
47 shuffle files if randomize?
54 protect("loading #{file}") { Kernel.load file }
59 def self.actions(action, *args)
60 actions = retrieve(action)
61 actions.each { |obj| obj.send action, *args } if actions
64 def self.protect(location, &block)
66 @env.instance_eval(&block)
70 rescue Exception => exc
72 actions :exception, ExceptionState.new(current && current.state, location, exc)
77 # Sets the toplevel ContextState to +state+.
78 def self.register_current(state)
82 # Sets the toplevel ContextState to +nil+.
83 def self.clear_current
87 # Returns the toplevel ContextState.
92 # Stores the shared ContextState keyed by description.
93 def self.register_shared(state)
94 @shared[state.to_s] = state
97 # Returns the shared ContextState matching description.
98 def self.retrieve_shared(desc)
102 # Stores the exit code used by the runner scripts.
103 def self.register_exit(code)
107 # Retrieves the stored exit code.
112 # Stores the list of files to be evaluated.
113 def self.register_files(files)
117 # Stores one or more substitution patterns for transforming
118 # a spec filename into a tags filename, where each pattern
123 # See also +tags_file+.
124 def self.register_tags_patterns(patterns)
125 store :tags_patterns, patterns
128 def self.register_mode(mode)
132 def self.retrieve(symbol)
133 instance_variable_get :"@#{symbol}"
136 def self.store(symbol, value)
137 instance_variable_set :"@#{symbol}", value
140 # This method is used for registering actions that are
141 # run at particular points in the spec cycle:
142 # :start before any specs are run
143 # :load before a spec file is loaded
144 # :enter before a describe block is run
145 # :before before a single spec is run
146 # :expectation before a 'should', 'should_receive', etc.
147 # :example after an example block is run, passed the block
148 # :exception after an exception is rescued
149 # :after after a single spec is run
150 # :leave after a describe block is run
151 # :unload after a spec file is run
152 # :finish after all specs are run
154 # Objects registered as actions above should respond to
155 # a method of the same name. For example, if an object
156 # is registered as a :start action, it should respond to
157 # a #start method call.
159 # Additionally, there are two "action" lists for
161 # :include return true if the spec should be run
162 # :exclude return true if the spec should NOT be run
164 def self.register(symbol, action)
165 unless value = retrieve(symbol)
166 value = store symbol, []
168 value << action unless value.include? action
171 def self.unregister(symbol, action)
172 if value = retrieve(symbol)
177 def self.verify_mode?
181 def self.report_mode?
185 def self.pretend_mode?
189 def self.randomize(flag=true)
197 def self.shuffle(ary)
202 r = rand(size - i - 1)
203 ary[i], ary[r] = ary[r], ary[i]
207 # Records that an expectation has been encountered in an example.
209 store :expectations, true
212 # Returns true if an expectation has been encountered
213 def self.expectation?
214 retrieve :expectations
217 # Resets the flag that an expectation has been encountered in an example.
218 def self.clear_expectations
219 store :expectations, false
222 # Transforms a spec filename into a tags filename by applying each
223 # substitution pattern in :tags_pattern. The default patterns are:
225 # [%r(/spec/), '/spec/tags/'], [/_spec.rb$/, '_tags.txt']
227 # which will perform the following transformation:
229 # path/to/spec/class/method_spec.rb => path/to/spec/tags/class/method_tags.txt
231 # See also +register_tags_patterns+.
233 patterns = retrieve(:tags_patterns) ||
234 [[%r(spec/), 'spec/tags/'], [/_spec.rb$/, '_tags.txt']]
235 patterns.inject(retrieve(:file).dup) do |file, pattern|
240 def self.read_tags(*keys)
244 File.open(file, "r") do |f|
245 f.each_line do |line|
246 tag = SpecTag.new line.chomp
247 tags << tag if keys.include? tag.tag
254 def self.write_tag(tag)
257 path = File.dirname file
258 FileUtils.mkdir_p(path) unless File.exist?(path)
260 File.open(file, "r") do |f|
261 f.each_line { |line| return false if line.chomp == string }
264 File.open(file, "a") { |f| f.puts string }
268 def self.delete_tag(tag)
270 pattern = /#{tag.tag}.*#{Regexp.escape tag.description}/
273 lines = IO.readlines(file)
274 File.open(file, "w") do |f|
276 unless pattern =~ line.chomp
283 File.delete file unless File.size? file