unified_matchers 0.1.5.0

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.
@@ -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