unified_matchers 0.1.5.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,71 @@
1
+ # Copyright:: Copyright (c) 2006 Uttk Team. All rights reserved.
2
+ # Author:: Gaelle Champarnaud <gallooo@gmail.com>
3
+ # License:: Gnu General Public License.
4
+ # Revision:: $Id: /w/fey/um/trunk/lib/unified_matchers/matcher_result.rb 23455 2006-05-09T10:59:14.845424Z pouillar $
5
+
6
+ module UnifiedMatchers
7
+
8
+ class MatcherResult
9
+
10
+ attr_reader :name, :data, :ref, :my
11
+
12
+ def initialize name, ref, my, message_ref, message_my, default_message, status, data=nil, message=nil
13
+ if status == true or status == false
14
+ @name = name
15
+ @status = status
16
+ @data = data
17
+ @ref = ref
18
+ @my = my
19
+ @message_ref = message_ref
20
+ @message_my = message_my
21
+ if message.nil?
22
+ message = default_message
23
+ end
24
+ @message_template = message
25
+ else
26
+ raise ArgumentError,
27
+ "The status must be true or false, not #{status}."
28
+ end
29
+ end
30
+
31
+ def success?
32
+ @status
33
+ end
34
+
35
+ def failure?
36
+ ! @status
37
+ end
38
+
39
+ def message
40
+ if defined? @message
41
+ @message
42
+ else
43
+ str = ''
44
+ str << 'not ' if failure?
45
+ str << @message_template
46
+ str.gsub!('%ref', compute_messages(@message_ref))
47
+ str.gsub!('%my', compute_messages(@message_my))
48
+ @message = str
49
+ end
50
+ end
51
+
52
+ def compute_messages message
53
+ x = message.shift.inspect_for_unified_matchers
54
+ message.inject(x) { |accu, y| y.gsub('%x', accu) }
55
+ end
56
+
57
+ def to_s
58
+ if @name.nil?
59
+ message
60
+ else
61
+ "#@name: #{message}"
62
+ end
63
+ end
64
+
65
+ def method_missing *a, &b
66
+ @data.send(*a, &b)
67
+ end
68
+
69
+ end # class MatcherResult
70
+
71
+ end # module UnifiedMatchers
@@ -0,0 +1,46 @@
1
+ # Copyright:: Copyright (c) 2006 Uttk Team. All rights reserved.
2
+ # Author:: Gaelle Champarnaud <gallooo@gmail.com>
3
+ # License:: Gnu General Public License.
4
+ # Revision:: $Id: /w/fey/um/trunk/lib/unified_matchers/matcher_results.rb 23455 2006-05-09T10:59:14.845424Z pouillar $
5
+
6
+ module UnifiedMatchers
7
+
8
+ class MatcherResults
9
+
10
+ def initialize *matcher_results
11
+ @elements = matcher_results.flatten
12
+ end
13
+
14
+ def success?
15
+ @elements.all? { |x| x.success? }
16
+ end
17
+
18
+ def failure?
19
+ @elements.any? { |x| x.failure? }
20
+ end
21
+
22
+ def each &block
23
+ @elements.each(&block)
24
+ end
25
+
26
+ def first
27
+ @elements.first
28
+ end
29
+
30
+ def to_s
31
+ s = ''
32
+ each { |x| s << x.to_s << "\n" }
33
+ s
34
+ end
35
+
36
+ def << result
37
+ if result.respond_to? :each
38
+ result.each { |x| @elements << x }
39
+ else
40
+ @elements << result
41
+ end
42
+ end
43
+
44
+ end # class MatcherResults
45
+
46
+ end # module UnifiedMatchers
@@ -0,0 +1,78 @@
1
+ # Copyright:: Copyright (c) 2005 Uttk Team. All rights reserved.
2
+ # Author:: Nicolas Pouillard <ertai@lrde.epita.fr>.
3
+ # License:: Gnu General Public License.
4
+ # Revision:: $Id: /w/fey/um/trunk/lib/unified_matchers/stream_matcher.rb 23258 2006-04-09T09:46:24.223538Z ertai $
5
+
6
+
7
+ module UnifiedMatchers
8
+
9
+ class StreamMatcher < UnifiedMatcher
10
+ make Concrete
11
+
12
+ rule :open
13
+ rule :io, :all => [ :rewind, :read ], :message => '%x.{rewind ; read}' do
14
+ rewind ; read
15
+ end
16
+ rule :to_s
17
+ final(String, String, :message => '%ref == %my') { |ref, my| ref == my }
18
+ final(Class, Object, :message => '%my.is_a? %ref') { |ref, my| my.is_a?(ref) }
19
+ final Regexp, String, :message => '%ref.match %my' do |ref, my|
20
+ r = ref.match(my) ; [ !! r, r ]
21
+ end
22
+
23
+ end # class StreamMatcher
24
+
25
+
26
+
27
+ test_section __FILE__ do
28
+
29
+ class TestStreamMatchers < ::Test::Unit::TestCase
30
+ include UnifiedMatchers::Assertions
31
+
32
+ def setup
33
+ self.matcher = StreamMatcher.new
34
+ end
35
+
36
+ def teardown
37
+ end
38
+
39
+ def test_stream_matcher
40
+ assert_failure 'a', 'b'
41
+ assert_success(/^a$/, 'a')
42
+ assert_success 'a', 'a'
43
+ assert_failure(/^a$/, /^a$/)
44
+ assert_success "(?-mix:^a$)", /^a$/
45
+ assert_success(/\d/, 4)
46
+ assert_success '42', 42
47
+ assert_success 42, '42'
48
+ s = StringIO.new
49
+ s << 'foo'
50
+ assert_success 'foo', s
51
+ assert_failure 'bar', s
52
+ assert_success 'foo', s
53
+ assert_success Integer, 42
54
+ assert_failure String, 42
55
+ assert_failure 42, Integer
56
+ TempPath.new do |t|
57
+ t.overwrite 'foo'
58
+ assert_success 'foo', t
59
+ assert_success(/fo+/, t.open)
60
+ assert_success t, t
61
+ f = t.open
62
+ assert_success f, f
63
+ end
64
+ end
65
+
66
+ def test_with_a_new_class
67
+ c = Class.new
68
+ assert_success(/^#<#<Class:.*>.*>$/, c.new)
69
+ StreamMatcher.rule(:test_with_a_new_class, c, :before => :to_s) { object_id }
70
+ assert_failure(/^#<#<Class:.*>.*>$/, c.new)
71
+ assert_success(/^\d+$/, c.new)
72
+ end
73
+
74
+ end # class TestStreamMatchers
75
+
76
+ end
77
+
78
+ end # module UnifiedMatchers
@@ -0,0 +1,44 @@
1
+ # Copyright:: Copyright (c) 2005 Uttk Team. All rights reserved.
2
+ # Author:: Nicolas Pouillard <ertai@lrde.epita.fr>.
3
+ # License:: Gnu General Public License.
4
+ # Revision:: $Id: /w/fey/um/trunk/lib/unified_matchers/strict_equality_based_matcher.rb 23258 2006-04-09T09:46:24.223538Z ertai $
5
+
6
+
7
+ module UnifiedMatchers
8
+
9
+ class StrictEqualityBasedMatcher < UnifiedMatcher
10
+ make Concrete
11
+
12
+ final(Object, Object, :message => '%ref.equal? %my') { |ref, my| ref.equal? my }
13
+
14
+ end # class StrictEqualityBasedMatcher
15
+
16
+
17
+
18
+ test_section __FILE__ do
19
+
20
+ class TestStrictEqualityBasedMatcher < ::Test::Unit::TestCase
21
+ include UnifiedMatchers::Assertions
22
+
23
+ def setup
24
+ self.matcher = StrictEqualityBasedMatcher.new
25
+ end
26
+
27
+ def teardown
28
+ end
29
+
30
+ def test_equality_based_matcher
31
+ assert_success 42, 42
32
+ assert_failure 42, 43
33
+ assert_failure '42', '42'
34
+ s = '42'
35
+ assert_success s, s
36
+ assert_failure '42', 42
37
+ assert_failure '42', '43'
38
+ end
39
+
40
+ end # class TestStrictEqualityBasedMatcher
41
+
42
+ end
43
+
44
+ end # module UnifiedMatchers
@@ -0,0 +1,260 @@
1
+ # Copyright:: Copyright (c) 2005 Uttk Team. All rights reserved.
2
+ # Author:: Nicolas Pouillard <ertai@lrde.epita.fr>.
3
+ # License:: Gnu General Public License.
4
+ # Revision:: $Id: /w/fey/um/trunk/lib/unified_matchers/unified_matcher.rb 23455 2006-05-09T10:59:14.845424Z pouillar $
5
+
6
+
7
+ # @UnifiedMatcher@ is an abstract class. It contains the key-definitions:
8
+ # list do
9
+ # * the class @Rule@,
10
+ #
11
+ # * the methods @rule@ and @final@,
12
+ #
13
+ # * the methods @delete_rule@, @delete_final@, @redefine_rule@ and
14
+ # @replace_rule@,
15
+ #
16
+ # * the method @[]@, which is used when the user wants to compare two objects
17
+ # with an operator of UnifiedMatchers. This method first searches the final
18
+ # rule which suits to the class of the first object (@ref@), and eventually
19
+ # applies to this object a change (using the intermediate rules).
20
+ # Then it changes the second object (@my@) until its class is that that the
21
+ # final rule need.
22
+ # The result is an object of class MatcherResults.
23
+ # end
24
+ module UnifiedMatchers
25
+
26
+ class UnifiedMatcher
27
+ make Abstract
28
+
29
+ class_inheritable_hash :rules, :ref_triggers
30
+ class_inheritable_accessor :last_defined_rule, :order
31
+ self.rules = {}
32
+ self.ref_triggers = {}
33
+ self.order = []
34
+
35
+ class Rule
36
+
37
+ attr_reader :name, :message
38
+
39
+ def initialize matcher, name, *args, &block
40
+ unless name.is_a? Symbol
41
+ raise ArgumentError, "The name must be a symbol, not: #{name}"
42
+ end
43
+ @name = name
44
+ @conditions = {}
45
+ @message = nil
46
+ @pos = 0
47
+ for arg in args.flatten do
48
+ setup_arg arg, matcher
49
+ end
50
+ if @conditions.empty?
51
+ @conditions[:respond_to] = @name
52
+ end
53
+ case @pos
54
+ when 0
55
+ update_order name, matcher.last_defined_rule, 1, matcher #after
56
+ when 1
57
+ else raise ArgumentError,
58
+ "Don't define more than one position (:before or :after)"
59
+ end
60
+ if block.nil?
61
+ meth = @conditions[:respond_to]
62
+ @block = lambda { |x| x.send meth }
63
+ @message ||= "%x.#{meth}"
64
+ else
65
+ @block = block
66
+ @message ||= "%x.<rule #@name>"
67
+ end
68
+ matcher.last_defined_rule = name
69
+ matcher.rules = {@name => self}
70
+ end
71
+
72
+ def setup_arg arg, matcher
73
+ case arg
74
+ when Class then @conditions[:is_a] = arg
75
+ when Symbol then @conditions[:respond_to] = arg
76
+ when Hash
77
+ for k,v in arg do
78
+ case k
79
+ when :after
80
+ @pos += 1
81
+ update_order name, v, 1, matcher
82
+ when :before
83
+ @pos += 1
84
+ update_order name, v, 0, matcher
85
+ when :message
86
+ @message = v
87
+ else @conditions[k] = v
88
+ end
89
+ end
90
+ end
91
+ end
92
+ private :setup_arg
93
+
94
+ def update_order new, ref, offset, m
95
+ m.order = m.order - [new]
96
+ i = m.order.index ref
97
+ if i.nil?
98
+ if m.last_defined_rule.nil?
99
+ m.order = [new]
100
+ else
101
+ raise ArgumentError, "Undefined rule: #{ref}"
102
+ end
103
+ else
104
+ m.order = m.order[0..i-1+offset] + [new] + m.order[i+offset..-1]
105
+ end
106
+ end
107
+
108
+ def activable? anObject
109
+ activable_rec @conditions, anObject
110
+ end
111
+
112
+ def activable_rec condition, anObject
113
+ case condition
114
+ when Class then anObject.is_a? condition
115
+ when Symbol then anObject.respond_to? condition
116
+ when Hash
117
+ if condition.size != 1
118
+ raise ArgumentError, "Too much conditions, use :all or :any to" +
119
+ "combine them. (rule: #{name})"
120
+ end
121
+ k,v = condition.to_a.first
122
+ case k
123
+ when :is_a then anObject.is_a? v
124
+ when :respond_to then anObject.respond_to? v
125
+ when :all then v.all? { |x| activable_rec x, anObject }
126
+ when :any then v.any? { |x| activable_rec x, anObject }
127
+ else raise ArgumentError, "Bad key: #{k}"
128
+ end
129
+ else raise ArgumentError, "Bad condition: #{condition}"
130
+ end
131
+ end
132
+
133
+ def activate x
134
+ case @block.arity
135
+ when -1 then x.instance_eval(&@block)
136
+ when 1 then @block[x]
137
+ else raise ArgumentError, "Bad block arity: #{@block.arity}"
138
+ end
139
+ end
140
+
141
+ end # class Rule
142
+
143
+ Rule.new(self, :unified_matchers_first)
144
+
145
+ class << self
146
+
147
+ def rule *args, &block
148
+ Rule.new(self, *args, &block)
149
+ end
150
+
151
+ def final ref_class, my_class, options=nil, &block
152
+ raise ArgumentError, 'Need a block' if block.nil?
153
+ raise ArgumentError, "Need a class, not: #{ref_class}" unless ref_class.is_a? Class
154
+ raise ArgumentError, "Need a class, not: #{my_class}" unless my_class.is_a? Class
155
+ options = {} if options.nil?
156
+ raise ArgumentError, "Need a Hash, not: #{options.inspect}" unless options.is_a? Hash
157
+ options[:message] ||= "#{self}.final(#{ref_class} = %ref, #{my_class} = %my)"
158
+ self.ref_triggers = { ref_class => [my_class, options, block] }
159
+ end
160
+
161
+ def delete_rule aRuleName
162
+ self.last_defined_rule = nil if last_defined_rule == aRuleName
163
+ self.order = order - [aRuleName]
164
+ self.rules = {aRuleName => nil}
165
+ end
166
+
167
+ def delete_final aClass
168
+ self.ref_triggers = {aClass => nil}
169
+ end
170
+
171
+ def replace_rule old_name, new_name, *args, &block
172
+ #FIXME verify that there is no before or after
173
+ i = order.index old_name
174
+ delete_rule old_name
175
+ Rule.new(self, new_name, *args, &block)
176
+ self.order = order - [new_name]
177
+ self.order = order[0..i-1] + [new_name] + order[i..-1]
178
+ end
179
+
180
+ def redefine_rule name, *args, &block
181
+ replace_rule name, name, *args, &block
182
+ end
183
+
184
+ end # class << self
185
+
186
+ def [] ( ref, my, name=nil )
187
+ my_target_class, options, ref_trigger = nil, nil
188
+ message_ref = [ref]
189
+ rule_i = 0
190
+ rule = rules[order[rule_i]]
191
+ first = true
192
+ done = []
193
+ until (rule.nil? and not first) or ref_trigger do
194
+ first = false
195
+ ref_class = ref.class
196
+ ref_class.ancestors.each do |aModule|
197
+ if ref_triggers.has_key? aModule
198
+ my_target_class, options, ref_trigger = ref_triggers[aModule]
199
+ break
200
+ end
201
+ end
202
+ if ref_trigger.nil?
203
+ if rule.activable? ref
204
+ check_done rule, done
205
+ message_ref << rule.message
206
+ ref = rule.activate ref
207
+ rule_i = 0
208
+ else
209
+ rule_i += 1
210
+ end
211
+ rule = rules[order[rule_i]]
212
+ end
213
+ end
214
+ if ref_trigger.nil?
215
+ raise ArgumentError, "No final rule with this class #{ref.class}"
216
+ end
217
+ message_my = [my]
218
+ rule_i = 0
219
+ rule = rules[order[rule_i]]
220
+ done.clear
221
+ until my.class <= my_target_class or rule.nil? do
222
+ if rule.activable? my
223
+ check_done rule, done
224
+ message_my << rule.message
225
+ my = rule.activate my
226
+ rule_i = 0
227
+ else
228
+ rule_i += 1
229
+ end
230
+ rule = rules[order[rule_i]]
231
+ end
232
+ unless my.class <= my_target_class
233
+ raise ArgumentError, "No activable rule for #{my}"
234
+ end
235
+ if ref_trigger.arity == 3
236
+ result = ref_trigger[ref, my, self]
237
+ else
238
+ result = ref_trigger[ref, my]
239
+ end
240
+ case result
241
+ when MatcherResults then return result
242
+ else
243
+ result = [result] unless result.is_a? Array
244
+ m = MatcherResult.new(name, ref, my, message_ref, message_my,
245
+ options[:message], *result)
246
+ return MatcherResults.new(m)
247
+ end
248
+ end # def []
249
+
250
+ def check_done rule, done
251
+ if done.include? rule
252
+ raise RuntimeError, "Possibly infinite rule activation" +
253
+ " (#{rule.name}). Perhaps you should use :before or :after."
254
+ end
255
+ done << rule
256
+ end
257
+
258
+ end # class UnifiedMatcher
259
+
260
+ end # module UnifiedMatchers
@@ -0,0 +1,10 @@
1
+ # Copyright:: Copyright (c) 2006 Nicolas Pouillard. All rights reserved.
2
+ # Author:: Nicolas Pouillard <nicolas.pouillard@gmail.com>.
3
+ # License:: Gnu General Public License.
4
+ # Revision:: $Id: /w/fey/um/trunk/lib/unified_matchers/version_id.rb 53948 2007-01-14T14:04:05.765192Z ertai $
5
+
6
+ module UnifiedMatchers
7
+
8
+ VersionId = Version.parse("dev-ruby/unified_matchers-0.1")
9
+
10
+ end # module UnifiedMatchers
@@ -0,0 +1,41 @@
1
+ # Copyright:: Copyright (c) 2005 Uttk Team. All rights reserved.
2
+ # Author:: Nicolas Pouillard <ertai@lrde.epita.fr>.
3
+ # License:: Gnu General Public License.
4
+ # Revision:: $Id: /w/fey/um/trunk/lib/unified_matchers.rb 24390 2006-07-09T20:59:27.061458Z ertai $
5
+
6
+ require 'pathname'
7
+
8
+ lib = Pathname.new(__FILE__).dirname
9
+ vendor = lib.parent + 'vendor'
10
+ unless defined? CoreEx
11
+ $CORE_EX_VENDORS ||= []
12
+ $CORE_EX_VENDORS << vendor
13
+ file = vendor + 'core_ex' + 'lib' + 'core_ex'
14
+ if file.exist?
15
+ require file.to_s
16
+ else
17
+ require 'rubygems' unless ENV['NO_GEM']
18
+ require_gem 'core_ex'
19
+ require 'core_ex'
20
+ end
21
+ end
22
+ lib.load_path!
23
+ suppress(LoadError) { require 'diff/lcs' }
24
+
25
+ unless defined? RubyEx
26
+ module Abstract
27
+ end
28
+ module Concrete
29
+ end
30
+ end
31
+
32
+ module UnifiedMatchers
33
+
34
+ mattr_accessor :dir, :fixtures
35
+
36
+ end # module UnifiedMatchers
37
+
38
+ UM = UnifiedMatchers unless defined? UM
39
+ UnifiedMatchers.dir = lib
40
+ UnifiedMatchers.fixtures = lib.parent/'test'/'fixtures'
41
+ UnifiedMatchers::Helpers.import!
@@ -0,0 +1,14 @@
1
+ ---
2
+
3
+ # Run this suite with -S 'url: scheme://the/url/to/the/ruby_ex/package'
4
+ UnifiedMatchers Package Test Suite: !S::Suite
5
+ contents:
6
+
7
+ - Checkout: !S::Checkout
8
+ url: <<url>>
9
+ fatal: true
10
+ weight: 0
11
+
12
+ - Check the package: !S::Import
13
+ import: <<checkout_dir>>/test/check.yml
14
+
data/test/check.yml ADDED
@@ -0,0 +1,8 @@
1
+ ---
2
+
3
+ UnifiedMatchers test suite: !S::Iterate
4
+ over: !pathlist <<pwd>>/(*-suite).yml
5
+ iter: [it_file, it_name]
6
+ test:
7
+ Run the <<it_name>> test suite: !S::Import
8
+ import: !path <<it_file>>
@@ -0,0 +1 @@
1
+ bird
@@ -0,0 +1 @@
1
+ birds
@@ -0,0 +1 @@
1
+ foo/bar
@@ -0,0 +1,17 @@
1
+ #! /usr/bin/env ruby
2
+
3
+ def main()
4
+ if (ARGV.length == 0)
5
+ word = STDIN.gets.chomp
6
+ else
7
+ word = ARGV[0]
8
+ end
9
+ if word =~ /\d/
10
+ STDERR.puts "bad word: #{word}"
11
+ exit 1
12
+ else
13
+ puts word + "s"
14
+ end
15
+ end
16
+
17
+ main
@@ -0,0 +1,62 @@
1
+ ---
2
+
3
+ UnifiedMatchers Sanity Multiple Requires Test Suite: !S::Suite
4
+
5
+ attributes: !S::Cmd
6
+ command: <<ruby>>
7
+ exit: 0
8
+ error: ""
9
+ output: !re 0 failures, 0 errors$
10
+ args: -I<<pwd>>/../../lib
11
+
12
+ contents:
13
+ - require:
14
+ input: |
15
+ require 'unified_matchers'
16
+ Dependencies.mechanism = :require
17
+ require 'test/unit'
18
+ class TC_ < Test::Unit::TestCase
19
+ def test_definitions
20
+ path_list = PathList['<<pwd>>/../../lib/(**/*).rb']
21
+ path_list.each do |_, path|
22
+ require path
23
+ path += '.rb'
24
+ assert($LOADED_FEATURES.include?(path),
25
+ "#{path} not in $LOADED_FEATURES #{$LOADED_FEATURES.inspect}")
26
+ end
27
+ end
28
+ end
29
+
30
+ - require dependency:
31
+ input: |
32
+ require 'unified_matchers'
33
+ require 'test/unit'
34
+ class TC_ < Test::Unit::TestCase
35
+ def test_definitions
36
+ lib_dir = '<<pwd>>/../../lib'.to_path
37
+ lib_dir.load_path!
38
+ path_list = PathList[lib_dir/'(**/*).rb']
39
+ path_list.each do |_, path|
40
+ require_dependency path
41
+ assert(Dependencies.loaded.include?(path),
42
+ "#{path} not in Dependencies.loaded #{Dependencies.loaded.inspect}")
43
+ end
44
+ end
45
+ end
46
+
47
+ - lazy loading:
48
+ input: |
49
+ require 'unified_matchers'
50
+ require 'test/unit'
51
+ class TC_ < Test::Unit::TestCase
52
+ def test_definitions
53
+ PathList['<<pwd>>/../../lib/(**/*).rb'].each do |path, name|
54
+ assert_nothing_raised("cannot camelize #{name}") do
55
+ @camel = name.camelize
56
+ end
57
+ assert_nothing_raised("#@camel not defined?") do
58
+ @camel.constantize
59
+ end
60
+ end
61
+ end
62
+ end