qed 2.4.0 → 2.5.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,3 +1,5 @@
1
+ require 'facets/dir/ascend'
2
+
1
3
  class Object
2
4
 
3
5
  unless method_defined?(:instance_exec) # 1.9
data/lib/qed/demo.rb CHANGED
@@ -1,35 +1,31 @@
1
1
  module QED
2
- require 'yaml'
3
2
 
4
- require 'facets/dir/ascend'
3
+ require 'yaml'
5
4
 
5
+ require 'qed/core_ext'
6
6
  require 'qed/parser'
7
7
  require 'qed/evaluator'
8
+ require 'qed/applique'
8
9
 
9
- # = Demo
10
+ # The Demo class ecapsulates a demonstration document.
10
11
  #
11
12
  class Demo
12
13
 
13
- #
14
- attr :applique
15
-
16
14
  # Demonstrandum file.
17
15
  attr :file
18
16
 
19
- #
17
+ # Parser mode.
20
18
  attr :mode
21
19
 
22
- #
20
+ # Scope to run demonstration within. (Known as a "World" in Cucumber.)
23
21
  attr :scope
24
22
 
25
23
  # New Script
26
- def initialize(file, applique, options={})
24
+ def initialize(file, options={})
27
25
  @file = file
28
- @applique = applique.dup # localize copy of applique
29
26
  @scope = options[:scope] || Scope.new(applique, file)
30
27
  @mode = options[:mode]
31
28
  @binding = @scope.__binding__
32
- #@loadlist = []
33
29
  #apply_environment
34
30
  end
35
31
 
@@ -38,17 +34,6 @@ module QED
38
34
  @binding #||= @scope.__binding__
39
35
  end
40
36
 
41
- # TODO: demo advice vs. applique advice
42
- def advice
43
- #@scope.__advice__
44
- @applique.__advice__
45
- end
46
-
47
- #
48
- def advise(signal, *args)
49
- advice.call(@scope, signal, *args)
50
- end
51
-
52
37
  # Expanded dirname of +file+.
53
38
  def directory
54
39
  @directory ||= File.expand_path(File.dirname(file))
@@ -65,6 +50,48 @@ module QED
65
50
  #@scope.module_eval(section.text, @file, section.line)
66
51
  end
67
52
 
53
+ # Returns a cached Array of Applique modules.
54
+ def applique
55
+ @applique ||= (
56
+ list = [Applique.new]
57
+ applique_locations.each do |location|
58
+ Dir[location + '/**/*.rb'].each do |file|
59
+ list << Applique.new(file)
60
+ end
61
+ end
62
+ list
63
+ )
64
+ end
65
+
66
+ # Returns a list of applique directories to be used by this
67
+ # demonstrastion.
68
+ def applique_locations
69
+ @applique_locations ||= (
70
+ locations = []
71
+ Dir.ascend(File.dirname(file)) do |path|
72
+ break if path == Dir.pwd
73
+ dir = File.join(path, 'applique')
74
+ if File.directory?(dir)
75
+ locations << dir
76
+ end
77
+ end
78
+ locations
79
+ )
80
+ end
81
+
82
+ # Parse demonstration script.
83
+ #
84
+ # Returns an abstract syntax tree.
85
+ def parse
86
+ Parser.new(file, :mode=>mode).parse
87
+ end
88
+
89
+ #
90
+ def run(*observers)
91
+ evaluator = Evaluator.new(self, *observers)
92
+ evaluator.run
93
+ end
94
+
68
95
  #
69
96
  #def source
70
97
  # @source ||= (
@@ -78,18 +105,6 @@ module QED
78
105
  # )
79
106
  #end
80
107
 
81
- # Parse script.
82
- # Retruns an abstract syntax tree.
83
- def parse
84
- Parser.new(file, :mode=>mode).parse
85
- end
86
-
87
- #
88
- def run(*observers)
89
- evaluator = Evaluator.new(self, *observers)
90
- evaluator.run
91
- end
92
-
93
108
  end
94
109
 
95
110
  end
data/lib/qed/evaluator.rb CHANGED
@@ -98,6 +98,7 @@ module QED
98
98
  end
99
99
 
100
100
  # TODO: Not sure how to handle loading links in --comment runner mode.
101
+ # TODO: Do not think Scope should be reuseud by imported demo.
101
102
  def evaluate_links(step)
102
103
  step.text.scan(/\[qed:\/\/(.*?)\]/) do |match|
103
104
  file = $1
@@ -110,7 +111,7 @@ module QED
110
111
  when '.rb'
111
112
  import!(file)
112
113
  else
113
- Demo.new(file, @script.applique, :scope=>@script.scope).run
114
+ Demo.new(file, :scope=>@script.scope).run
114
115
  end
115
116
  end
116
117
  end
@@ -142,7 +143,14 @@ module QED
142
143
  # Dispatch event to observers and advice.
143
144
  def advise!(signal, *args)
144
145
  @observers.each{ |o| o.update(signal, *args) }
145
- @script.advise(signal, *args)
146
+
147
+ #@script.advise(signal, *args)
148
+ case signal
149
+ when :when
150
+ call_matchers(*args)
151
+ else
152
+ call_signals(signal, *args)
153
+ end
146
154
  end
147
155
 
148
156
  #
@@ -150,6 +158,106 @@ module QED
150
158
  # @advice.call_when(match)
151
159
  #end
152
160
 
161
+ # React to an event.
162
+ #
163
+ # TODO: Should events short circuit on finding first match?
164
+ # In other words, should there be only one of each type of signal
165
+ # ragardless of how many applique layers?
166
+ def call_signals(type, *args)
167
+ @script.applique.each do |a|
168
+ signals = a.__signals__
169
+ proc = signals[type.to_sym]
170
+ #signals.each do |set|
171
+ #proc = set[type.to_sym]
172
+ #proc.call(*args) if proc
173
+ @script.scope.instance_exec(*args, &proc) if proc
174
+ #end
175
+ end
176
+
177
+ #@script.applique.each do |a|
178
+ # signals = a.__signals__
179
+ # proc = signals[type.to_sym]
180
+ # if proc
181
+ # @script.scope.instance_exec(*args, &proc)
182
+ # break
183
+ # end
184
+ #end
185
+
186
+ #meth = "qed_#{type}"
187
+ #if @script.scope.respond_to?(meth)
188
+ # meth = @script.scope.method(meth)
189
+ # if meth.arity == 0
190
+ # meth.call
191
+ # else
192
+ # meth.call(*args)
193
+ # end
194
+ #end
195
+
196
+ #@script.scope.__send__(meth, *args)
197
+ end
198
+
199
+ #
200
+ def call_matchers(section)
201
+ match = section.text
202
+ args = section.arguments
203
+ @script.applique.each do |a|
204
+ matchers = a.__matchers__
205
+ matchers.each do |(patterns, proc)|
206
+ compare = match
207
+ matched = true
208
+ params = []
209
+ patterns.each do |pattern|
210
+ case pattern
211
+ when Regexp
212
+ regex = pattern
213
+ else
214
+ regex = match_string_to_regexp(pattern)
215
+ end
216
+ if md = regex.match(compare)
217
+ params.concat(md[1..-1])
218
+ compare = md.post_match
219
+ else
220
+ matched = false
221
+ break
222
+ end
223
+ end
224
+ if matched
225
+ params += args
226
+ #proc.call(*params)
227
+ @script.scope.instance_exec(*params, &proc)
228
+ end
229
+ end
230
+ end
231
+ end
232
+
233
+ # Convert matching string into a regular expression. If the string
234
+ # contains double parenthesis, such as ((.*?)), then the text within
235
+ # them is treated as in regular expression and kept verbatium.
236
+ #
237
+ # TODO: Better way to isolate regexp. Maybe ?:(.*?) or /(.*?)/.
238
+ #
239
+ # TODO: Now that we can use multi-patterns, do we still need this?
240
+ #
241
+ def match_string_to_regexp(str)
242
+ str = str.split(/(\(\(.*?\)\))(?!\))/).map{ |x|
243
+ x =~ /\A\(\((.*)\)\)\Z/ ? $1 : Regexp.escape(x)
244
+ }.join
245
+ str = str.gsub(/\\\s+/, '\s+')
246
+ Regexp.new(str, Regexp::IGNORECASE)
247
+
248
+ #rexps = []
249
+ #str = str.gsub(/\(\((.*?)\)\)/) do |m|
250
+ # rexps << '(' + $1 + ')'
251
+ # "\0"
252
+ #end
253
+ #str = Regexp.escape(str)
254
+ #rexps.each do |r|
255
+ # str = str.sub("\0", r)
256
+ #end
257
+ #str = str.gsub(/(\\\ )+/, '\s+')
258
+ #Regexp.new(str, Regexp::IGNORECASE)
259
+ end
260
+
153
261
  ##
154
262
  #def method_missing(s, *a)
155
263
  # super(s, *a) unless /^tag/ =~ s.to_s
@@ -158,4 +266,3 @@ module QED
158
266
  end
159
267
 
160
268
  end
161
-
@@ -0,0 +1,35 @@
1
+ module QED
2
+
3
+ # This extension provides a simple means for creatind file-system fixtures.
4
+ # Include this in your applique, to have a
5
+ module FileFixtures
6
+
7
+ #
8
+ def self.included(base)
9
+ require 'erb'
10
+ end
11
+
12
+ #
13
+ def copy_fixture(name, tmpdir=nil)
14
+ tmpdir ||= 'tmp' # self.tmpdir
15
+ FileUtils.mkdir(tmpdir) unless File.directory?(tmpdir)
16
+ srcdir = File.join(demo_directory, 'fixtures', name)
17
+ paths = Dir.glob(File.join(srcdir, '**', '*'), File::FNM_DOTMATCH)
18
+ paths.each do |path|
19
+ basename = File.basename(path)
20
+ next if basename == '.'
21
+ next if basename == '..'
22
+ dest = File.join(tmpdir, path.sub(srcdir+'/', ''))
23
+ if File.directory?(path)
24
+ FileUtils.mkdir(dest)
25
+ else
26
+ text = ERB.new(File.read(path)).result
27
+ File.open(dest, 'w'){ |f| f << text }
28
+ end
29
+ end
30
+ end
31
+
32
+ end
33
+
34
+ end
35
+
File without changes
data/lib/qed/meta/data.rb CHANGED
@@ -1,29 +1,27 @@
1
- Object.__send__(:remove_const, :VERSION) if Object.const_defined?(:VERSION) # becuase Ruby 1.8~ gets in the way
2
-
3
1
  module QED
4
2
 
5
- def self.__DIR__
6
- File.dirname(__FILE__)
7
- end
3
+ DIRECTORY = File.dirname(__FILE__)
8
4
 
9
- def self.gemfile
10
- @gemfile ||= (
5
+ def self.package
6
+ @package ||= (
11
7
  require 'yaml'
12
- YAML.load(File.new(__DIR__ + '/gemfile'))
8
+ YAML.load(File.new(DIRECTORY + '/package'))
13
9
  )
14
10
  end
15
11
 
16
12
  def self.profile
17
13
  @profile ||= (
18
14
  require 'yaml'
19
- YAML.load(File.new(__DIR__ + '/profile'))
15
+ YAML.load(File.new(DIRECTORY + '/profile'))
20
16
  )
21
17
  end
22
18
 
23
19
  def self.const_missing(name)
24
20
  key = name.to_s.downcase
25
- gemfile[key] || profile[key] || super(name)
21
+ package[key] || profile[key] || super(name)
26
22
  end
27
23
 
28
24
  end
29
25
 
26
+ # becuase Ruby 1.8~ gets in the way
27
+ Object.__send__(:remove_const, :VERSION) if Object.const_defined?(:VERSION)
@@ -1,10 +1,10 @@
1
1
  name: qed
2
- version: 2.4.0
3
- date: 2010-09-02
2
+ date: 2010-11-07
3
+ version: 2.5.0
4
4
 
5
5
  requires:
6
6
  - ansi
7
7
  - facets
8
- - ae (test)
8
+ - ae
9
9
  - syckle (build)
10
10
 
@@ -237,8 +237,12 @@ module Reporter
237
237
  end
238
238
 
239
239
  def print_tally
240
+ assert_count = Assertion.count
241
+ assert_fails = Assertion.fails
242
+ assert_delta = assert_count - assert_fails
243
+
240
244
  mask = "%s demos, %s steps: %s failures, %s errors (%s/%s assertions)"
241
- vars = [demos.size, steps.size, fails.size, errors.size, $assertions-$failures, $assertions] #, @pass.size ]
245
+ vars = [demos.size, steps.size, fails.size, errors.size, assert_delta, assert_count] #, @pass.size ]
242
246
 
243
247
  io.puts mask % vars
244
248
  end
@@ -46,9 +46,9 @@ module Reporter #:nodoc:
46
46
  tab = step.text.index(/\S/)
47
47
  io.print "#{txt}\n\n".ansi(:red)
48
48
  msg = []
49
- #msg << ANSI::Code.bold(ANSI::Code.red("FAIL: ")) + error.to_str
49
+ #msg << ANSI::Code.bold(ANSI::Code.red("FAIL: ")) + error.message
50
50
  #msg << ANSI::Code.bold(clean_backtrace(error.backtrace[0]))
51
- msg << "FAIL: ".ansi(:bold, :red) + error.to_str
51
+ msg << "FAIL: ".ansi(:bold, :red) + error.message #to_str
52
52
  msg << clean_backtrace(error.backtrace[0]).ansi(:bold)
53
53
  io.puts msg.join("\n").tabto(tab||2)
54
54
  io.puts
@@ -62,7 +62,7 @@ module Reporter #:nodoc:
62
62
  tab = step.text.index(/\S/)
63
63
  io.print "#{txt}\n\n".ansi(:red)
64
64
  msg = []
65
- msg << "ERROR: #{error.class} ".ansi(:bold,:red) + error.to_str #.sub(/for QED::Context.*?$/,'')
65
+ msg << "ERROR: #{error.class} ".ansi(:bold,:red) + error.message #.sub(/for QED::Context.*?$/,'')
66
66
  msg << clean_backtrace(error.backtrace[0]).ansi(:bold)
67
67
  #msg = msg.ansi(:red)
68
68
  io.puts msg.join("\n").tabto(tab||2)
data/lib/qed/scope.rb CHANGED
@@ -6,26 +6,30 @@ module QED
6
6
  #
7
7
  class Scope < Module
8
8
 
9
- #
10
- def self.new(applique, file)
11
- @_applique = applique
12
- super(applique, file)
13
- end
9
+ # Location of `qed/scope.rb`.
10
+ DIRECTORY = File.dirname(__FILE__)
14
11
 
15
12
  #
16
- def self.const_missing(name)
17
- @_applique.const_get(name)
18
- end
13
+ # def self.new(applique, file)
14
+ # @_applique = applique
15
+ # super(applique, file)
16
+ # end
17
+
18
+ # #
19
+ # def self.const_missing(name)
20
+ # @_applique.const_get(name)
21
+ # end
19
22
 
20
23
  #
21
24
  def initialize(applique, file=nil)
22
25
  super()
23
26
  @_applique = applique
24
27
  @_file = file
28
+ #@loadlist = []
25
29
 
30
+ include *applique
26
31
  extend self
27
- extend applique # TODO: extend or include applique or none ?
28
- include applique
32
+ #extend applique # TODO: extend or include applique or none ?
29
33
  #extend DSLi
30
34
 
31
35
  # TODO: custom extends?
@@ -45,20 +49,51 @@ module QED
45
49
  }
46
50
  end
47
51
 
52
+ #
53
+ def include(*modules)
54
+ super(*modules)
55
+ extend self
56
+ end
57
+
48
58
  # Expanded dirname of +file+.
49
59
  def demo_directory
50
60
  @_demo_directory ||= File.expand_path(File.dirname(@_file))
51
61
  end
52
62
 
53
63
  # Evaluate code in the context of the scope's special binding.
54
- def eval(code, binding=nil)
64
+ def eval(code, binding=nil, file=nil)
55
65
  super(code, binding || __binding__, @_file)
56
66
  end
57
67
 
68
+
69
+
70
+ # Utilize is like #require, but will evaluate the script in the context
71
+ # of the current scope.
72
+ #--
73
+ # TODO: Alternative to Plugin gem?
74
+ #
75
+ # TODO: Should work like require so same file isn't loaded twice.
76
+ #++
77
+ def utilize(file)
78
+ file = Dir[DIRECTORY + "/helpers/#{file}"].first
79
+ if !file
80
+ require 'plugin'
81
+ file = Plugin.find("#{file}{,.rb}", :directory=>nil)
82
+ end
83
+ if file
84
+ code = File.read(file)
85
+ eval(code, nil, file)
86
+ else
87
+ raise LoadError, "no such file -- #{file}"
88
+ end
89
+ end
90
+
91
+
92
+
58
93
  # Define "when" advice.
59
94
  def When(*patterns, &procedure)
60
95
  patterns = patterns.map{ |pat| pat == :text ? :desc : pat }
61
- @_applique.When(*patterns, &procedure)
96
+ @_applique.first.When(*patterns, &procedure)
62
97
  end
63
98
 
64
99
  # Define "before" advice. Default type is :each, which
@@ -66,7 +101,7 @@ module QED
66
101
  def Before(type=:each, &procedure)
67
102
  type = :step if type == :each
68
103
  type = :demo if type == :all
69
- @_applique.Before(type, &procedure)
104
+ @_applique.first.Before(type, &procedure)
70
105
  end
71
106
 
72
107
  # Define "after" advice. Default type is :each, which
@@ -74,9 +109,11 @@ module QED
74
109
  def After(type=:each, &procedure)
75
110
  type = :step if type == :each
76
111
  type = :demo if type == :all
77
- @_applique.After(type, &procedure)
112
+ @_applique.first.After(type, &procedure)
78
113
  end
79
114
 
115
+
116
+
80
117
  # TODO: Should Table and Data be extensions that can be loaded if desired?
81
118
 
82
119
  # Use sample table to run steps. The table file will be
@@ -128,6 +165,11 @@ module QED
128
165
  #end
129
166
  end
130
167
 
168
+ #
169
+ def const_missing(const)
170
+ Object.const_get(const)
171
+ end
172
+
131
173
  end#class Scope
132
174
 
133
175
  end#module QED