qed 2.2.1 → 2.2.2

Sign up to get free protection for your applications and to get access to all the features.
File without changes
@@ -1,18 +1,34 @@
1
1
  = RELEASE HISTORY
2
2
 
3
- == 2.2.1 / 2010-06-21
3
+ == 2.2.2 / 2010-06-21
4
+
5
+ An issue was reported in which the a code block at the very
6
+ top of a demo was being ignored. This release fixes this issue
7
+ by rewriting the parser (much better now thanks!). At the same
8
+ time the Data and Table methods have been polished, both of
9
+ which can now pick up sample data relative to the current demo.
10
+
11
+ Changes:
12
+
13
+ * Rewrite parser and fix top code issue.
14
+ * Data method cannot write data, instead executes block.
15
+ * Data and Table methods look for file relative to demo first.
16
+ * Added -R option to run demos relative to project root.
17
+
18
+
19
+ == 2.2.1 / 2010-06-20
4
20
 
5
21
  Remove dependencies to Tilt and Nokogiri. Should have
6
22
  done this in last release but alas --there is so
7
23
  much to do.
8
24
 
9
- Change:
25
+ Changes:
10
26
 
11
27
  * Removed HTML parsing dependencies.
12
28
  * Reduce Advice to a single class.
13
29
 
14
30
 
15
- == 2.2.0 / 2010-06-20
31
+ == 2.2.0 / 2010-06-19
16
32
 
17
33
  This release returns to a text-based evaluator, rather
18
34
  then use HTML. Processing HTML proved to have too many
data/PROFILE CHANGED
@@ -11,6 +11,6 @@ description:
11
11
 
12
12
  resources:
13
13
  home: http://proutils.github.com/qed
14
- work: http://github.com/protuils/qed
14
+ work: http://github.com/proutils/qed
15
15
  repo: git://github.com/proutils/qed.git
16
16
 
@@ -1,6 +1,6 @@
1
1
  = Ruby Q.E.D.
2
2
 
3
- homepage: http://proutils.rubyforge.org/qed
3
+ homepage: http://proutils.github.com/qed
4
4
  mailing list: http://groups.google.com/group/proutils
5
5
  development: http://github.com/proutils/qed
6
6
 
data/VERSION CHANGED
@@ -1,5 +1,5 @@
1
1
  name : qed
2
2
  major: 2
3
3
  minor: 2
4
- patch: 1
5
- date : 2010-06-20
4
+ patch: 2
5
+ date : 2010-06-21
data/bin/qed CHANGED
@@ -1,4 +1,4 @@
1
1
  #!/usr/bin/env ruby
2
- require 'qed/command'
3
- QED::Command.execute
2
+ require 'qed'
3
+ QED.main(*ARGV)
4
4
 
@@ -114,7 +114,6 @@ So +x+ should now contain these three list samples.
114
114
 
115
115
  x.assert == [ 'SampleA', 'SampleB', 'SampleC' ]
116
116
 
117
-
118
117
  == Pattern Matchers
119
118
 
120
119
  QED also supports comment match triggers. With the +When+ method one can
@@ -0,0 +1,49 @@
1
+ = Test Samples
2
+
3
+ == Flat-file Data
4
+
5
+ When creating testable demonstrations, there are times when sizable
6
+ chunks of data are needed. It is convenient to store such data in
7
+ separate files. The +Data+ method makes is easy to utilize them.
8
+
9
+ Data('demo/samples/data.txt').assert =~ /dolor/
10
+
11
+ The +Data+ method can also take a block which passes the data
12
+ as the block's only argument.
13
+
14
+ Data('demo/samples/data.txt') do |data|
15
+ data.assert =~ /dolor/
16
+ end
17
+
18
+ Files are looked-up relative to the location of the current document.
19
+ If not found then they will be looked-up relative to the current
20
+ working directory.
21
+
22
+ == Tabular Data
23
+
24
+ The +Table+ method is similar to the +Data+ method except that it
25
+ expects a YAML file, and it can take a block to iterate the data over.
26
+ This makes it easy to test tables of examples.
27
+
28
+ The arity of the table block corresponds to the number of columns in
29
+ each row of the table. Each row is assigned in turn and run through
30
+ the coded step. Consider the following example:
31
+
32
+ Every row in the {table.yml table}[table.yml] will be assigned to
33
+ the block parameters and run through the subsequent assertion.
34
+
35
+ Table 'demo/samples/table.yml' do |x, y|
36
+ x.upcase.assert == y
37
+ end
38
+
39
+ Without the block, the +Table+ methods simply returns the sample data.
40
+
41
+ == Considerations
42
+
43
+ Both Data and Table are some what "old fashion" approches to sample
44
+ data. New techinques using plain text blocks are more convenient
45
+ in that the data can be stored directly in the demonstration itself.
46
+ However, for especially large data sets and external file is still
47
+ the better option, and +Data+ and +Table+ make them quite easy to
48
+ access.
49
+
File without changes
File without changes
data/lib/qed.rb CHANGED
@@ -21,5 +21,6 @@ module QED
21
21
  end
22
22
  end
23
23
 
24
+ require 'qed/command'
24
25
  require 'qed/session'
25
26
 
@@ -1,26 +1,39 @@
1
- #!/usr/bin/env ruby
2
-
3
- require 'qed'
4
1
  require 'optparse'
5
2
  require 'shellwords'
6
3
 
7
4
  module QED
8
5
 
6
+ def self.main(*argv)
7
+ Command.main(*argv)
8
+ end
9
+
9
10
  # = QED Commandline Tool
10
11
  #
12
+ # TODO: Merge Command with Session ?
11
13
  class Command
12
14
 
13
- # Configuration directory.
14
- CONFDIR = "{.,}config/qed"
15
+ # Configuration directory `.qed`, `.config/qed` or `config/qed`.
16
+ # In this directory special configuration files can be placed
17
+ # to autmatically effect qed execution. In particular you can
18
+ # add a `profiles.yml` file to setup convenient execution
19
+ # scenarios.
20
+ CONFIG_PATTERN = "{.,.config/,config/}qed"
21
+
22
+ # Default location of demonstrations if no specific files
23
+ # or locations given. This is use in Dir.glob. The default
24
+ # locations are qed/, demo/ or demos/, searched for in that
25
+ # order relative to the root directory.
26
+ DEMO_LOCATION = '{qed,demo,demos}'
27
+
28
+ # Glob pattern used to search for project's root directory.
29
+ ROOT_PATTERN = '{.root,.git,.hg,_darcs}/'
15
30
 
16
- # Default location of demonstrations if no
17
- # specific files or locations given. This
18
- # is use in Dir.glob.
19
- DEFAULT_DEMO_LOCATION = '{demo,demos}'
31
+ # Home directory.
32
+ HOME = File.expand_path('~')
20
33
 
21
- # Initialize and execute.
22
- def self.execute
23
- new.execute
34
+ # Instantiate a new Command object and call #execute.
35
+ def self.main(*argv)
36
+ new.execute(argv)
24
37
  end
25
38
 
26
39
  # Ouput format.
@@ -43,22 +56,25 @@ module QED
43
56
  # Files to be run.
44
57
  attr :files
45
58
 
46
- #
59
+ # Ensure files are in a flat list.
47
60
  def files=(globs)
48
61
  @files = [globs].flatten
49
62
  end
50
63
 
51
- #
64
+ # Paths to be added to $LOAD_PATH.
52
65
  attr_accessor :loadpath
53
66
 
54
- #
67
+ # Libraries to be required.
55
68
  attr_accessor :requires
56
69
 
57
- #
70
+ # ?
58
71
  attr_accessor :extension
59
72
 
60
- # TODO: Should extension and profile have a common reference?
73
+ # Move to root directory?
74
+ attr_accessor :root
61
75
 
76
+ #
77
+ # TODO: Should extension and profile have a common reference?
62
78
  def initialize
63
79
  @format = :dotprogress
64
80
  @extension = :default
@@ -70,7 +86,6 @@ module QED
70
86
  end
71
87
 
72
88
  # Instance of OptionParser
73
-
74
89
  def opts
75
90
  @opts ||= OptionParser.new do |opt|
76
91
 
@@ -84,113 +99,96 @@ module QED
84
99
  end
85
100
 
86
101
  opt.separator("Report Formats (pick one):")
87
-
88
102
  opt.on('--dotprogress', '-d', "use dot-progress reporter [default]") do
89
103
  @options[:format] = :dotprogress
90
104
  end
91
-
92
105
  opt.on('--verbatim', '-v', "use verbatim reporter") do
93
106
  @options[:format] = :verbatim
94
107
  end
95
-
96
108
  opt.on('--bullet', '-b', "use bullet-point reporter") do
97
109
  @options[:format] = :bullet
98
110
  end
99
-
100
111
  opt.on('--html', '-h', "use underlying HTML reporter") do
101
112
  @options[:format] = :html
102
113
  end
103
-
104
114
  opt.on('--format', '-f FORMAT', "use custom reporter") do |format|
105
115
  @options[:format] = format
106
116
  end
107
-
108
117
  #opt.on('--script', "psuedo-reporter") do
109
118
  # @options[:format] = :script # psuedo-reporter
110
119
  #end
111
-
112
120
  opt.separator("Control Options:")
113
-
114
- opt.on('--ext', '-e [NAME]', "runtime extension [default]") do |name|
121
+ opt.on('--root', '-R', "run command from project's root directory") do
122
+ @options[:root] = true
123
+ end
124
+ opt.on('--ext', '-e NAME', "runtime extension [default]") do |name|
115
125
  @options[:extension] = name
116
126
  end
117
-
118
127
  opt.on('--loadpath', "-I PATH", "add paths to $LOAD_PATH") do |arg|
119
128
  @options[:loadpath] ||= []
120
129
  @options[:loadpath].concat(arg.split(/[:;]/).map{ |dir| File.expand_path(dir) })
121
130
  end
122
-
123
131
  opt.on('--require', "-r", "require library") do |arg|
124
132
  @options[:requires] ||= []
125
133
  @options[:requires].concat(arg.split(/[:;]/)) #.map{ |dir| File.expand_path(dir) })
126
134
  end
127
-
128
135
  opt.on('--trace', '-t', "show full backtraces for exceptions") do
129
136
  @options[:trace] = true
130
137
  end
131
-
132
138
  opt.on('--debug', "exit immediately upon raised exception") do
133
139
  $VERBOSE = true # wish this were called $WARN
134
140
  $DEBUG = true
135
141
  end
136
-
137
142
  opt.separator("Optional Commands:")
138
-
139
143
  opt.on_tail('--version', "display version") do
140
144
  puts "QED #{VERSION}"
141
145
  exit
142
146
  end
143
-
144
147
  opt.on_tail('--copyright', "display copyrights") do
145
148
  puts "Copyright (c) 2008, 2009 Thomas Sawyer, GPL License"
146
149
  exit
147
150
  end
148
-
149
151
  opt.on_tail('--help', '-h', "display this help message") do
150
152
  puts opt
151
153
  exit
152
154
  end
153
-
154
155
  end
155
156
  end
156
157
 
157
- #
158
+ # Default recognized demos file types.
159
+ DEMO_TYPES = %w{qed rdoc md markdown}
160
+
161
+ # Returns a list of demo files.
158
162
  def demos
159
- files = self.files
160
- types = %w{qed rdoc md markdown} #Tilt.mappings.keys
161
- if files.empty?
162
- files << DEFAULT_DEMO_LOCATION
163
- end
164
- files = files.map do |pattern|
165
- Dir[pattern]
166
- end.flatten.uniq
167
- files = files.map do |file|
168
- if File.directory?(file)
169
- Dir[File.join(file,'**','*.{' + types.join(',') + '}')]
170
- else
171
- file
163
+ @demos ||= (
164
+ files = self.files
165
+ if files.empty?
166
+ files << DEMO_LOCATION
172
167
  end
173
- end
174
- files = files.flatten.uniq.sort
175
- #files = files.select do |file|
176
- # %w{.yml .yaml .rb}.include?(File.extname(file))
177
- #end
178
- files
168
+ files = files.map{|pattern| Dir[pattern]}.flatten.uniq
169
+ files = files.map do |file|
170
+ if File.directory?(file)
171
+ Dir[File.join(file,'**','*.{' + DEMO_TYPES.join(',') + '}')]
172
+ else
173
+ file
174
+ end
175
+ end
176
+ files = files.flatten.uniq
177
+ files.map{|f| File.expand_path(f) }.sort
178
+ )
179
179
  end
180
180
 
181
181
  # Session instance.
182
-
183
182
  def session
184
183
  @session ||= Session.new(demos, :format=>format, :trace=>trace)
185
184
  end
186
185
 
187
186
  # Parse command-line options along with profile options.
188
-
189
- def parse
190
- @files = []
191
- argv = ARGV.dup
192
- opts.parse!(argv)
193
- @files.concat(argv)
187
+ def parse(argv)
188
+ #@files = []
189
+ opts.parse!(argv ||= ARGV.dup)
190
+ #@files.concat(argv)
191
+ @files = argv
194
192
 
195
193
  #if profile
196
194
  if args = profiles[profile]
@@ -206,75 +204,116 @@ module QED
206
204
  end
207
205
 
208
206
  # Run demonstrations.
207
+ def execute(argv)
208
+ parse(argv)
209
209
 
210
- def execute
211
- parse
210
+ jump = @options[:root] ? root_directory : Dir.pwd
212
211
 
213
- abort "No documents." if demos.empty?
212
+ Dir.chdir(jump) do
213
+ abort "No documents." if demos.empty?
214
214
 
215
- prepare_loadpath
215
+ prepare_loadpath
216
216
 
217
- require_libraries
218
- require_profile
217
+ require_libraries
218
+ require_profile
219
219
 
220
- session.run
220
+ session.run
221
+ end
221
222
  end
222
223
 
223
- # Profile configurations.
224
+ # Project's root directory.
225
+ def root_directory
226
+ @root_directory ||= find_root
227
+ end
228
+
229
+ # Project's QED configuation directory.
230
+ def config_directory
231
+ @config_directory ||= find_config #Dir[File.join(root_directory, CONFIG_PATTERN)].first
232
+ end
224
233
 
234
+ # Profile configurations.
225
235
  def profiles
226
236
  @profiles ||= (
227
- file = Dir["#{CONFDIR}/profile{,s}.{yml,yaml}"].first
237
+ file = Dir["#{config_directory}/profile{,s}.{yml,yaml}"].first
228
238
  file ? YAML.load(File.new(file)) : {}
229
239
  )
230
240
  end
231
241
 
232
242
  # Add to load path (from -I option).
233
-
234
243
  def prepare_loadpath
235
244
  loadpath.each{ |dir| $LOAD_PATH.unshift(dir) }
236
245
  end
237
246
 
238
247
  # Require libraries (from -r option).
239
-
240
248
  def require_libraries
241
249
  requires.each{ |file| require(file) }
242
250
  end
243
251
 
244
252
  # Require requirement file (from -e option).
245
-
246
253
  def require_profile
247
- return unless root
248
-
249
- # common environment, always loaded if present.
250
- #if file = Dir["#{root}/#{CONFDIR}/default.rb"].first
251
- # require(file)
252
- #end
253
-
254
- #env = env() || 'default'
255
-
256
- if file = Dir["#{root}/#{CONFDIR}/#{extension}.rb"].first
254
+ return unless config_directory
255
+ if file = Dir["#{config_directory}/#{extension}.rb"].first
257
256
  require(file)
258
257
  end
259
258
  end
260
259
 
260
+ # Locate project's root directory. This is done by searching upward
261
+ # in the file heirarchy for the existence of one of the following
262
+ # path names, each group being tried in turn.
263
+ #
264
+ # * .root/
265
+ # * .git/
266
+ # * .hg/
267
+ # * _darcs/
268
+ #
269
+ # Failing to find any of these locations, resort to the fallback:
270
+ #
271
+ # * lib/
261
272
  #
262
- def root
263
- QED.root
273
+ def find_root(path=nil)
274
+ path = File.expand_path(path || Dir.pwd)
275
+ path = File.dirname(path) unless File.directory?(path)
276
+
277
+ root = lookup(ROOT_PATTERN, path)
278
+ return root if root
279
+
280
+ #root = lookup(path, '{.qed,.config/qed,config/qed}/')
281
+ #return root if root
282
+
283
+ #root = lookup(path, '{qed,demo,demos}/')
284
+ #return root if root
285
+
286
+ root = lookup('lib/', path)
287
+ return root if root
288
+
289
+ abort "Failed to resolve project's root location. Try adding a .root directory."
264
290
  end
265
291
 
266
- end
292
+ # Locate configuration directory by seaching up the
293
+ # file hierachy relative to the working directory
294
+ # for one of the following paths:
295
+ #
296
+ # * .qed/
297
+ # * .config/qed/
298
+ # * config/qed/
299
+ #
300
+ def find_config
301
+ lookup(CONFIG_PATTERN)
302
+ end
267
303
 
268
- # Is there no perfect way to find root directory of a project?
269
- def self.root(path=nil)
270
- path ||= Dir.pwd
271
- path = File.dirname(path) unless File.directory?(path)
272
- until path == File.dirname(path)
273
- mark = Dir[File.join(path, 'README*')].first
274
- return path if mark
275
- path = File.dirname(path)
304
+ # Lookup path +glob+, searching each higher directory
305
+ # in turn until just before the users home directory
306
+ # is reached or just before the system's root directory.
307
+ #
308
+ # TODO: include HOME directory in search?
309
+ def lookup(glob, path=Dir.pwd)
310
+ until path == HOME or path == '/' # until home or root
311
+ mark = Dir.glob(File.join(path,glob), File::FNM_CASEFOLD).first
312
+ return path if mark
313
+ path = File.dirname(path)
314
+ end
276
315
  end
277
- nil
316
+
278
317
  end
279
318
 
280
319
  end
@@ -1,5 +1,5 @@
1
1
  name : qed
2
2
  major: 2
3
3
  minor: 2
4
- patch: 1
5
- date : 2010-06-20
4
+ patch: 2
5
+ date : 2010-06-21
@@ -14,38 +14,51 @@ module QED
14
14
  @ast = []
15
15
  end
16
16
 
17
- #
17
+ # Abstract Syntax Tree
18
18
  attr :ast
19
19
 
20
+ # Parse the demo into an abstract syntax tree.
20
21
  #
22
+ # TODO: I know there has to be a faster way to do this.
21
23
  def parse
22
- state = :text
23
- linein = 0
24
-
25
- text = ''
26
-
24
+ blocks = [[]]
25
+ state = :none
27
26
  @lines.each_with_index do |line, lineno|
28
- if /^\S/ =~ line
29
- if state == :code
30
- add_section(:code, text, linein)
31
- linein = lineno
32
- text = ''
27
+ case line
28
+ when /^$/
29
+ case state
30
+ when :code
31
+ blocks.last << line
32
+ when :blank
33
+ blocks.last << line
34
+ else
35
+ blocks.last << line
36
+ state = :blank
33
37
  end
38
+ when /^\s+/
39
+ blocks << [] if state != :code
40
+ blocks.last << line
41
+ state = :code
42
+ else
43
+ blocks << [] if state != :text
44
+ blocks.last << line
34
45
  state = :text
35
- text << line
46
+ end
47
+ end
48
+ blocks.shift if blocks.first.empty?
49
+
50
+ line_cnt = 1
51
+ blocks.each do |block|
52
+ text = block.join
53
+ case text
54
+ when /\A\s+/
55
+ add_section(:code, text, line_cnt)
36
56
  else
37
- if state == :text
38
- next if text.strip.empty?
39
- add_section(:text, text, linein)
40
- linein = lineno
41
- text = ''
42
- end
43
- state = :code
44
- text << line
57
+ add_section(:text, text, line_cnt)
45
58
  end
59
+ line_cnt += block.size
46
60
  end
47
- add_section(state, text, linein)
48
- @ast.reject!{ |sect| sect.type == :code && sect.text.strip.empty? }
61
+ #@ast.reject!{ |sect| sect.type == :code && sect.text.strip.empty? }
49
62
  return @ast
50
63
  end
51
64
 
@@ -53,7 +66,7 @@ module QED
53
66
  def add_section(state, text, lineno)
54
67
  case state
55
68
  when :code
56
- if ast.last.raw?
69
+ if ast.last && ast.last.cont?
57
70
  @ast.last << text #clean_quote(text)
58
71
  else
59
72
  @ast << CodeSection.new(text, lineno)
@@ -85,23 +98,31 @@ module QED
85
98
 
86
99
  #
87
100
  class TextSection < Section
101
+
88
102
  attr :args
103
+
89
104
  attr :cont
105
+
90
106
  def initialize(text, line, *args)
91
107
  @text = text
92
108
  @line = line
93
109
  @args = args
94
110
  @cont = []
95
111
  end
112
+
113
+ #
96
114
  def <<(text)
97
115
  @cont << clean_continuation(text)
98
116
  @args << block_continuation(text)
99
117
  end
118
+
119
+ #
100
120
  def type
101
121
  :text
102
122
  end
123
+
103
124
  # TODO: Use ':' or '...' ?
104
- def raw?
125
+ def cont?
105
126
  #/\:\s*\Z/m =~ text
106
127
  /\.\.\.\s*\Z/m =~ text
107
128
  end
@@ -11,6 +11,6 @@ description:
11
11
 
12
12
  resources:
13
13
  home: http://proutils.github.com/qed
14
- work: http://github.com/protuils/qed
14
+ work: http://github.com/proutils/qed
15
15
  repo: git://github.com/proutils/qed.git
16
16
 
@@ -13,7 +13,7 @@ module Reporter #:nodoc:
13
13
  def text(step)
14
14
  case step.text
15
15
  when /^\=/
16
- io.puts "#{step.text}".ansi(:bold)
16
+ io.print "#{step.text}".ansi(:bold)
17
17
  else
18
18
  txt = step.text.to_s.strip.tabto(2)
19
19
  txt[0,1] = "*"
@@ -32,8 +32,7 @@ module Reporter #:nodoc:
32
32
  msg << " # " + assertion.to_s
33
33
  msg = msg.ansi(:magenta)
34
34
  io.puts msg
35
- #io.puts
36
- io.puts "#{step.text}".ansi(:red)
35
+ io.print "#{step.text}".ansi(:red)
37
36
  end
38
37
 
39
38
  def error(step, exception)
@@ -44,8 +43,7 @@ module Reporter #:nodoc:
44
43
  msg << " # " + clean_backtrace(exception.backtrace[0])
45
44
  msg = msg.ansi(:magenta)
46
45
  io.puts msg
47
- #io.puts
48
- io.puts "#{step.text}".ansi(:red)
46
+ io.print "#{step.text}".ansi(:red)
49
47
  end
50
48
 
51
49
  #def report(str)
@@ -10,10 +10,10 @@ module Reporter #:nodoc:
10
10
  #
11
11
  def text(section)
12
12
  case section.text
13
- when /^\=/
14
- io.puts "#{section.text}".ansi(:bold)
13
+ when /\A[=#]/
14
+ io.print "#{section.text}".ansi(:bold)
15
15
  else
16
- io.puts(section.text + "\n")
16
+ io.print(section.text)
17
17
  end
18
18
  if !section.cont.empty?
19
19
  section.cont.each do |c|
@@ -27,14 +27,14 @@ module Reporter #:nodoc:
27
27
 
28
28
  #
29
29
  def pass(step)
30
- txt = step.text.rstrip.sub("\n",'')
31
- io.print "#{txt}\n\n".ansi(:green)
30
+ txt = step.text #.rstrip.sub("\n",'')
31
+ io.print "#{txt}".ansi(:green)
32
32
  end
33
33
 
34
34
  #
35
35
  def fail(step, error)
36
36
  txt = step.text.rstrip.sub("\n",'')
37
- tab = step.text.index(/\S/) - 1
37
+ tab = step.text.index(/\S/)
38
38
  io.print "#{txt}\n\n".ansi(:red)
39
39
  msg = []
40
40
  #msg << ANSI::Code.bold(ANSI::Code.red("FAIL: ")) + error.to_str
@@ -49,7 +49,7 @@ module Reporter #:nodoc:
49
49
  def error(step, error)
50
50
  raise error if $DEBUG
51
51
  txt = step.text.rstrip.sub("\n",'')
52
- tab = step.text.index(/\S/) - 1
52
+ tab = step.text.index(/\S/)
53
53
  io.print "#{txt}\n\n".ansi(:red)
54
54
  msg = []
55
55
  msg << "ERROR: #{error.class} ".ansi(:bold,:red) + error.to_str #.sub(/for QED::Context.*?$/,'')
@@ -7,110 +7,109 @@ module QED
7
7
  class Scope < Module
8
8
 
9
9
  #
10
- def self.new(applique)
11
- @applique = applique
12
- super(applique)
10
+ def self.new(applique, file)
11
+ @_applique = applique
12
+ super(applique, file)
13
13
  end
14
14
 
15
15
  #
16
16
  def self.const_missing(name)
17
- @applique.const_get(name)
17
+ @_applique.const_get(name)
18
18
  end
19
19
 
20
20
  #
21
- def initialize(applique)
21
+ def initialize(applique, file=nil)
22
22
  super()
23
- @applique = applique
23
+ @_applique = applique
24
+ @_file = file
25
+
24
26
  extend self
25
27
  extend applique # TODO: extend or include applique or none ?
26
28
  #extend DSLi
27
- create_clean_binding_method
29
+
30
+ # TODO: custom extends?
31
+
32
+ __create_clean_binding_method__
28
33
  end
29
34
 
30
- # This turned out to be the key to proper scoping.
31
- def create_clean_binding_method
35
+ # This turns out to be the key to proper scoping.
36
+ def __create_clean_binding_method__
32
37
  define_method(:__binding__) do
33
38
  @__binding__ ||= binding
34
39
  end
35
40
  end
36
41
 
37
- #module DSLi
42
+ # Evaluate code in the context of the scope's special
43
+ # binding.
44
+ def eval(code)
45
+ super(code, __binding__)
46
+ end
38
47
 
39
- #def initialize
40
- # @__binding__ = binding
41
- #end
48
+ # Define "when" advice.
49
+ def When(*patterns, &procedure)
50
+ @_applique.When(*patterns, &procedure)
51
+ end
42
52
 
43
- #def __binding__
44
- # @__binding__
45
- #end
53
+ # Define "before" advice.
54
+ def Before(type=:code, &procedure)
55
+ @_applique.Before(type, &procedure)
56
+ end
46
57
 
47
- #
48
- #def __binding__
49
- # @__binding__ ||= binding
50
- #end
58
+ # Define "after" advice.
59
+ def After(type=:code, &procedure)
60
+ @_applique.After(type, &procedure)
61
+ end
51
62
 
52
- #
53
- def eval(code)
54
- super(code, __binding__)
55
- end
63
+ # TODO: Should Table and Data be extensions that can be loaded if desired?
56
64
 
57
- #
58
- def When(*patterns, &procedure)
59
- @applique.When(*patterns, &procedure)
60
- end
61
-
62
- #
63
- def Before(type=:code, &procedure)
64
- @applique.Before(type, &procedure)
65
+ # Use sample table to run steps. The table file will be
66
+ # looked for relative to the demo, failing that it will
67
+ # be looked for relative to the working directory.
68
+ #
69
+ # TODO: Cache data for speed ?
70
+ def Table(file=nil) #:yield:
71
+ if file
72
+ file = Dir.glob(File.join(File.dirname(@_file), file)).first || file
73
+ else
74
+ file = @_last_table
65
75
  end
76
+ @_last_table = file
66
77
 
67
- #
68
- def After(type=:code, &procedure)
69
- @applique.After(type, &procedure)
78
+ tbl = YAML.load(File.new(file))
79
+ tbl.each do |set|
80
+ yield(*set)
70
81
  end
82
+ end
71
83
 
72
- # Table-based steps.
73
- #--
74
- # TODO: Look for files relative to script first?
75
- #++
76
- def Table(file=nil, &blk)
77
- file = file || @_tables.last
78
- tbl = YAML.load(File.new(file))
79
- tbl.each do |set|
80
- blk.call(*set)
84
+ # Read a static data sample.
85
+ #
86
+ # TODO: Cache data for speed ?
87
+ def Data(file) #:yield:
88
+ #raise if File.directory?(file)
89
+ #if content
90
+ # FileUtils.mkdir_p(File.dirname(file))
91
+ # case File.extname(file)
92
+ # when '.yml', '.yaml'
93
+ # File.open(file, 'w'){ |f| f << content.call.to_yaml }
94
+ # else
95
+ # File.open(file, 'w'){ |f| f << content.call }
96
+ # end
97
+ #else
98
+ #raise LoadError, "no such fixture file -- #{fname}" unless File.exist?(fname)
99
+ file = Dir.glob(File.join(File.dirname(@_file), file)).first || file
100
+ case File.extname(file)
101
+ when '.yml', '.yaml'
102
+ data = YAML.load(File.new(file))
103
+ else
104
+ data = File.read(file)
81
105
  end
82
- @__tables__ ||= []
83
- @__tables__ << file
84
- end
85
-
86
- # Read/Write a static data fixture.
87
- #--
88
- # TODO: Perhaps #Data would be best as some sort of Kernel extension.
89
- #
90
- # TODO: Look for files relative to script first?
91
- #++
92
- def Data(file, &content)
93
- raise if File.directory?(file)
94
- if content
95
- FileUtils.mkdir_p(File.dirname(fname))
96
- case File.extname(file)
97
- when '.yml', '.yaml'
98
- File.open(file, 'w'){ |f| f << content.call.to_yaml }
99
- else
100
- File.open(file, 'w'){ |f| f << content.call }
101
- end
106
+ if block_given?
107
+ yield(data)
102
108
  else
103
- #raise LoadError, "no such fixture file -- #{fname}" unless File.exist?(fname)
104
- case File.extname(file)
105
- when '.yml', '.yaml'
106
- YAML.load(File.new(file))
107
- else
108
- File.read(file)
109
- end
109
+ data
110
110
  end
111
- end
112
-
113
- #end#module DSL
111
+ #end
112
+ end
114
113
 
115
114
  end#class Scope
116
115
 
@@ -23,7 +23,7 @@ module QED
23
23
  def initialize(applique, file, scope=nil)
24
24
  @applique = applique.dup # localize copy of applique
25
25
  @file = file
26
- @scope = scope || Scope.new(applique)
26
+ @scope = scope || Scope.new(applique, file)
27
27
  @binding = @scope.__binding__
28
28
  #@loadlist = []
29
29
  #apply_environment
@@ -34,7 +34,7 @@ module QED
34
34
  @binding #||= @scope.__binding__
35
35
  end
36
36
 
37
- #
37
+ # TODO: demo advice vs. applique advice
38
38
  def advice
39
39
  #@scope.__advice__
40
40
  @applique.__advice__
@@ -42,7 +42,7 @@ module QED
42
42
  # QED.config
43
43
  #end
44
44
 
45
- # TODO: Ultimately use Plugin library.
45
+ # TODO: Ultimately use Plugin library to support custom reporters?
46
46
  def require_reporters
47
47
  Dir[File.dirname(__FILE__) + '/reporter/*'].each do |file|
48
48
  require file
@@ -94,7 +94,7 @@ module QED
94
94
  # end
95
95
  #end
96
96
 
97
- # TODO: associate scripts to there applique
97
+ # TODO: associate scripts to there applique ?
98
98
  def create_applique
99
99
  applique = Applique.new
100
100
  #eval "include QED::DomainLanguage", TOPLEVEL_BINDING
@@ -1,2 +1,4 @@
1
1
  #!/usr/bin/ruby
2
- system "ruby -Ilib -- bin/qed demo/*.rdoc"
2
+ pass1 = system "ruby -Ilib -- bin/qed demo/*.rdoc"
3
+ pass2 = system "ruby -Ilib -- bin/qed test/integration/*.rdoc"
4
+ exit -1 unless pass1 && pass2
@@ -0,0 +1,8 @@
1
+ x = "Is this running?"
2
+ x.assert == "Is this running?"
3
+
4
+ This demo simply checks to make sure top code is exectued
5
+ like any other code when there is no prior description.
6
+
7
+ x.assert == "Is this running?"
8
+
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: qed
3
3
  version: !ruby/object:Gem::Version
4
- hash: 5
4
+ hash: 3
5
5
  prerelease: false
6
6
  segments:
7
7
  - 2
8
8
  - 2
9
- - 1
10
- version: 2.2.1
9
+ - 2
10
+ version: 2.2.2
11
11
  platform: ruby
12
12
  authors:
13
13
  - Thomas Sawyer <transfire@gmail.com>
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2010-06-20 00:00:00 -04:00
18
+ date: 2010-06-24 00:00:00 -04:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
@@ -89,7 +89,7 @@ files:
89
89
  - demo/01_demos.rdoc
90
90
  - demo/02_advice.rdoc
91
91
  - demo/03_helpers.rdoc
92
- - demo/04_fixtures.rdoc
92
+ - demo/04_samples.rdoc
93
93
  - demo/05_quote.rdoc
94
94
  - demo/07_toplevel.rdoc
95
95
  - demo/08_cross_script.rdoc
@@ -101,14 +101,11 @@ files:
101
101
  - demo/applique/markup.rb
102
102
  - demo/applique/quote.rb
103
103
  - demo/applique/toplevel.rb
104
- - demo/fixtures/data.txt
105
- - demo/fixtures/table.yml
106
104
  - demo/helpers/advice.rb
107
105
  - demo/helpers/sample.rb
108
106
  - demo/helpers/toplevel.rb
109
- - eg/hello_world.rdoc
110
- - eg/view_error.rdoc
111
- - eg/website.rdoc
107
+ - demo/samples/data.txt
108
+ - demo/samples/table.yml
112
109
  - lib/qed/advice.rb
113
110
  - lib/qed/applique.rb
114
111
  - lib/qed/command.rb
@@ -133,13 +130,13 @@ files:
133
130
  - lib/qedoc/document.rb
134
131
  - script/qedoc
135
132
  - script/test
133
+ - test/integration/topcode.rdoc
136
134
  - PROFILE
135
+ - Diary.rdoc
137
136
  - README.rdoc
138
- - HISTORY
139
137
  - REQUIRE
140
- - ROADMAP
141
- - DIARY.rdoc
142
138
  - VERSION
139
+ - History.rdoc
143
140
  - COPYING
144
141
  has_rdoc: true
145
142
  homepage: http://proutils.github.com/qed
data/ROADMAP DELETED
@@ -1,12 +0,0 @@
1
- = ROADMAP
2
-
3
- == 2.2.0
4
-
5
- * Simplify code. I do not think we need both an Evaluator and Scope classes.
6
-
7
- == 2.3.0
8
-
9
- * Add a distributed evaluator, probably using Drb. This will allow the code
10
- portion of documents to run in an isolated process. It will also make it possible
11
- (in the long run) to run tests in parallel acrosss a cluster.
12
-
@@ -1,29 +0,0 @@
1
- = Fixtures
2
-
3
- == Flat-file Data
4
-
5
- When creating testable demonstrations, there are times when sizable
6
- chunks of data are needed. It is convenient to store such data in
7
- separate files. The +Data+ method makes is easy to load such files.
8
-
9
- Data('demo/fixtures/data.txt').assert =~ /dolor/
10
-
11
- All files are found relative to the location of current document.
12
-
13
- == Tabular Data
14
-
15
- The +Table+ method is similar to the +Data+ method except that it
16
- expects a YAML file, and it can take a block to iterate the data over.
17
- This makes it easy to test tables of examples.
18
-
19
- The arity of the table block corresponds to the number of columns in
20
- each row of the table. Each row is assigned in turn and run through
21
- the coded step. Consider the following example:
22
-
23
- Every row in the {table.yml table}[table.yml] will be assigned to
24
- the block parameters and run through the subsequent assertion.
25
-
26
- Table 'demo/fixtures/table.yml' do |x, y|
27
- x.upcase.assert == y
28
- end
29
-
@@ -1,15 +0,0 @@
1
- = Hello World
2
-
3
- Did you know that famous `Hello World` moniker is
4
- eleven characters long?
5
-
6
- "Hello World".size.assert == 11
7
-
8
- To pass a piece of literal text on with a description
9
- we simply need to end it with a ...
10
-
11
- Now this text will appear verbatim.
12
- In the applique arguments.
13
-
14
- That's all.
15
-
@@ -1,21 +0,0 @@
1
- = Examples of Failure
2
-
3
- This document is here simply to demonstrate what
4
- a failed and error raising code steps looks like.
5
-
6
- When run with the -v (verbatim) option, for instance, +qed+
7
- will highlight the following sections in red and give a brief
8
- error message.
9
-
10
- == Failure
11
-
12
- This step demonstrates a failed assertion.
13
-
14
- 1.assert == 2
15
-
16
- == Error
17
-
18
- This step demonstrates a raised error.
19
-
20
- raise "Just because"
21
-
@@ -1,12 +0,0 @@
1
- = Addition
2
-
3
- require 'calculator'
4
- calculator = Caclulater.new
5
-
6
- A Calculator can add two numbers.
7
-
8
- calculator.push 2
9
- calculator.push 2
10
- calculator.add
11
- calculator.output.assert == 4
12
-