qed 2.2.1 → 2.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
-