Class: QED::Session

Inherits:
Object show all
Defined in:
lib/qed/session.rb,
lib/qed/cli/qed.rb

Overview

The Session class encapsulates a set of demonstrations and the procedure for looping through them and running each in turn.

Constant Summary collapse

DEMO_TYPES =

Default recognized demos file types.

%w{qed rdoc md markdown}
CODE_TYPES =
%w{rb}

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(settings = {}) ⇒ Session

New Session


29
30
31
32
33
34
35
36
37
38
# File 'lib/qed/session.rb', line 29

def initialize(settings={})
  require_reporters

  case settings
  when Settings
    @settings = settings
  else
    @settings = Settings.new(settings)
  end
end

Instance Attribute Details

#settingsObject (readonly)

Returns instance of Settings class.


26
27
28
# File 'lib/qed/session.rb', line 26

def settings
  @settings
end

Class Method Details

.cli(*argv) ⇒ Object

Command line interface for running demos.

When running `qed` on the command line tool, QED can use either a automatic configuration file, via the RC library, or setup configuration via an explicitly required file.

Using a master configuraiton file, add a `config :qed` entry. For example:

config :qed, :profile=>:simplecov do
  require 'simplecov'
  SimpleCov.start do
    coverage_dir 'log/coverage'
  end
end

To not use RC, just create a requirable file such as `config/qed-coverage.rb`

QED.configure do |qed|
  require 'simplecov'
  SimpleCov.start do
    coverage_dir 'log/coverage'
  end
end

Then when running qed use:

$ qed -r ./config/qed-coverage.rb

47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
# File 'lib/qed/cli/qed.rb', line 47

def self.cli(*argv)
  require 'optparse'
  require 'shellwords'

  # we are loading this here instead of above so simplecov coverage works better
  # (actually, this is really not a problem anymore, but we'll leave it for now)
  require 'qed/session'

  Utils.load_config

  options = cli_parse(argv)

  settings = Settings.new(options)
  session  = Session.new(settings)
  success  = session.run

  exit -1 unless success
end

.cli_parse(argv) ⇒ Object

Build an instance of OptionParser.


69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
# File 'lib/qed/cli/qed.rb', line 69

def self.cli_parse(argv)
  options = {}

  parser = OptionParser.new do |opt|
    opt.banner = "Usage: qed [options] <files...>"

    opt.separator("Report Formats (pick one):")

    #opt.on('--dotprogress', '-d', "use dot-progress reporter [default]") do
    #  options[:format] = :dotprogress
    #end
    opt.on('--verbatim', '-v', "shortcut for verbatim reporter") do
      options[:format] = :verbatim
    end
    opt.on('--tapy', '-y', "shortcut for TAP-Y reporter") do
      options[:format] = :tapy
    end    #opt.on('--bullet', '-b', "use bullet-point reporter") do
    #  options[:format] = :bullet
    #end
    #opt.on('--html', '-h', "use underlying HTML reporter") do
    #  options[:format] = :html
    #end
    #opt.on('--script', "psuedo-reporter") do
    #  options[:format] = :script  # psuedo-reporter
    #end

    opt.on('--format', '-f FORMAT', "use custom reporter") do |format|
      options[:format] = format.to_sym
    end

    opt.separator("Control Options:")

    opt.on('-p', '--profile NAME', "load runtime profile") do |name|
      options[:profile] = name
    end
    opt.on('--comment', '-c', "run comment code") do
      options[:mode] = :comment
    end
    opt.on('--loadpath', "-I PATH", "add paths to $LOAD_PATH") do |paths|
      options[:loadpath] = paths.split(/[:;]/).map{|d| File.expand_path(d)}
    end
    opt.on('--require', "-r LIB", "require feature (immediately)") do |paths|
      requires = paths.split(/[:;]/)
      requires.each do |file|
        require file
      end
    end
    opt.on('--rooted', '-R', "run from project root instead of temporary directory") do
      options[:rooted] = true
    end
    opt.on('--trace', '-t [COUNT]', "number of backtraces for exceptions (0 for all)") do |cnt|
      #options[:trace] = true
      ENV['trace'] = cnt
    end
    opt.on('--warn', "run with warnings turned on") do
      $VERBOSE = true # wish this were called $WARN!
    end
    opt.on('--debug', "exit immediately upon raised exception") do
      $DEBUG = true
    end

    opt.separator("Optional Commands:")

    opt.on_tail('--version', "display version") do
      puts "QED #{QED::VERSION}"
      exit
    end
    opt.on_tail('--copyright', "display copyrights") do
      puts "Copyright (c) 2008 Thomas Sawyer, Apache 2.0 License"
      exit
    end
    opt.on_tail('--help', '-h', "display this help message") do
      puts opt

      unless settings.profiles.empty?
        puts "Available Profiles:"        #require 'confection'

        QED.profiles.each do |name|
          next if name.strip == ''
          puts "    -p #{name}"
        end
      end

      exit -1
    end
  end

  parser.parse!(argv)

  options[:files] = argv unless argv.empty?

  return options
end

Instance Method Details

#clear_directoryObject

Clear temporary testing directory.


162
163
164
# File 'lib/qed/session.rb', line 162

def clear_directory
  settings.clear_directory
end

#demo_filesObject

Returns a list of demo files. The files returned depends on the files attribute and if none given, then the current run mode.


188
189
190
191
192
193
194
195
196
# File 'lib/qed/session.rb', line 188

def demo_files
  @demo_files ||= (
    if mode == :comment
      demo_files_in_comment_mode
    else
      demo_files_in_normal_mode
    end
  )
end

#demo_files_in_comment_modeObject

Collect default files to process in code comment mode.

TODO: Sure removing applique files is the best approach here?


206
207
208
209
210
# File 'lib/qed/session.rb', line 206

def demo_files_in_comment_mode
  files = demos_gather(CODE_TYPES)
  files = files.reject{ |f| f.index('applique/') }  # don't include applique files ???
  files
end

#demo_files_in_normal_modeObject

Collect default files to process in normal demo mode.


199
200
201
# File 'lib/qed/session.rb', line 199

def demo_files_in_normal_mode
  demos_gather #(DEMO_TYPES)
end

#demosObject

Returns an Array of Demo instances.


115
116
117
# File 'lib/qed/session.rb', line 115

def demos
  @demos ||= demo_files.map{ |file| Demo.new(file, :mode=>mode, :at=>directory) }
end

#demos_gather(extensions = DEMO_TYPES) ⇒ Object

Gather list of demo files. Uses omit to remove certain files based on the name of their parent directory.


214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
# File 'lib/qed/session.rb', line 214

def demos_gather(extensions=DEMO_TYPES)
  files = self.files  #files << default_location if files.empty?

  files = files.map{|pattern| Dir[pattern]}.flatten.uniq
  files = files.map do |file|
    if File.directory?(file)
      Dir[File.join(file,'**','*.{' + extensions.join(',') + '}')]
    else
      file
    end
  end
  files = files.flatten.uniq  #files = files.reject{ |f| f =~ Regexp.new("/\/(#{omit.join('|')})\//") }

  files = files.reject{ |f| omit.any?{ |o| f.index("/#{o}/") } }
  files.map{|f| File.expand_path(f) }.uniq.sort
end

#directoryObject


86
87
88
# File 'lib/qed/session.rb', line 86

def directory
  settings.tmpdir
end

#filesObject

Demonstration files (or globs).


41
42
43
# File 'lib/qed/session.rb', line 41

def files
  settings.files
end

#formatObject

Output format.


51
52
53
# File 'lib/qed/session.rb', line 51

def format
  settings.format
end

#loadpathObject

Paths to be added to $LOAD_PATH.


66
67
68
# File 'lib/qed/session.rb', line 66

def loadpath
  settings.loadpath
end

#modeObject

Parse mode.


61
62
63
# File 'lib/qed/session.rb', line 61

def mode
  settings.mode
end

#observersObject

List of observers to pass to the evaluator. Only includes the reporter instance, by default.


122
123
124
# File 'lib/qed/session.rb', line 122

def observers
  [reporter]
end

#omitObject

File patterns to omit.


46
47
48
# File 'lib/qed/session.rb', line 46

def omit
  settings.omit
end

#prepare_loadpathObject

Add to load path (from -I option).


172
173
174
# File 'lib/qed/session.rb', line 172

def prepare_loadpath
  loadpath.each{ |dir| $LOAD_PATH.unshift(File.expand_path(dir)) }
end

#profileObject

Selected profile.


81
82
83
# File 'lib/qed/session.rb', line 81

def profile
  settings.profile
end

#reporterObject

Instance of selected Reporter subclass.


105
106
107
108
109
110
# File 'lib/qed/session.rb', line 105

def reporter
  @reporter ||= (
    name = Reporter.constants.find{ |c| /#{format}/ =~ c.to_s.downcase }
    Reporter.const_get(name).new(:trace => trace?)
  )
end

#require_librariesObject

Require libraries (from -r option).


177
178
179
# File 'lib/qed/session.rb', line 177

def require_libraries
  requires.each{ |file| require(file) }
end

#require_reportersObject

Require all reporters.


98
99
100
101
102
# File 'lib/qed/session.rb', line 98

def require_reporters
  Dir[File.dirname(__FILE__) + '/reporter/*'].each do |file|
    require file
  end
end

#requiresObject

Libraries to be required.


71
72
73
# File 'lib/qed/session.rb', line 71

def requires
  settings.requires
end

#reset_assertion_countsObject

Set $ASSERTION_COUNTS to zero point.


167
168
169
# File 'lib/qed/session.rb', line 167

def reset_assertion_counts
  $ASSERTION_COUNTS = Hash.new{ |h,k| h[k] = 0 }
end

#rootedObject

Operate from project root?


76
77
78
# File 'lib/qed/session.rb', line 76

def rooted
  settings.rooted
end

#runObject

Run session.


129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
# File 'lib/qed/session.rb', line 129

def run
  abort "No documents." if demo_files.empty?

  clear_directory

  reset_assertion_counts

  #require_profile  # <-- finally runs the profile

  prepare_loadpath
  require_libraries

  Dir.chdir(directory) do
    # pre-parse demos
    demos.each{ |demo| demo.steps }

    # Let's do it.
    observers.each{ |o| o.before_session(self) }
    begin
      demos.each do |demo|
        Evaluator.run(demo, :observers=>observers, :settings=>settings) #demo.run(*observers)
        #pid = fork { demo.run(*observers) }
        #Process.detach(pid)
      end
    ensure
      observers.each{ |o| o.after_session(self) }
    end
  end

  reporter.success?
end

#total_step_countObject

Get the total test count. This method tallies up the number of assertive steps.


241
242
243
244
245
246
247
248
249
# File 'lib/qed/session.rb', line 241

def total_step_count
  count = 0
  demos.each do |demo|
    demo.steps.each do |step|
      count += 1 if step.assertive?
    end
  end
  count
end

#trace?Boolean

Trace execution?


56
57
58
# File 'lib/qed/session.rb', line 56

def trace?
  settings.trace
end