safer 0.2.1 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
data/History.txt CHANGED
@@ -1,6 +1,16 @@
1
- === 0.1.0 / 2010-09-22
1
+ === 0.3.0 / 2010-11-20
2
2
 
3
- * First release
3
+ * Make Safer a Class, instead of a Module, to prevent embedding.
4
+ * Protocol provides match_class and match_instance methods, allowing use of
5
+ case statements to verify protocol conformity.
6
+ * Added HashProtocol suite, to verify that keys of a Hash follow desired
7
+ usage guidelines.
8
+
9
+ === 0.2.1 / 2010-10-17
10
+
11
+ * README.txt still referred to ClassProtocol. Fixed.
12
+ * The Safer module documentation now refers to its submodules.
13
+ * Regularized use of '::' and '.'.
4
14
 
5
15
  === 0.2.0 / 2010-10-10
6
16
 
@@ -8,8 +18,6 @@
8
18
  * Protocol can non-violently check if a class or instance conforms.
9
19
  * Added much documentation.
10
20
 
11
- === 0.2.1 / 2010-10-17
21
+ === 0.1.0 / 2010-09-22
12
22
 
13
- * README.txt still referred to ClassProtocol. Fixed.
14
- * The Safer module documentation now refers to its submodules.
15
- * Regularized use of '::' and '.'.
23
+ * First release
data/Manifest.txt CHANGED
@@ -6,5 +6,7 @@ Rakefile
6
6
  lib/safer.rb
7
7
  lib/safer/ivar.rb
8
8
  lib/safer/protocol.rb
9
+ lib/safer/hashprotocol.rb
9
10
  test/test_safer_ivar.rb
10
11
  test/test_safer_protocol.rb
12
+ test/test_safer_hashprotocol.rb
data/README.txt CHANGED
@@ -5,15 +5,18 @@ http://safer.rubyforge.org
5
5
  == DESCRIPTION:
6
6
 
7
7
  Safer is an umbrella library, with components designed to make it simple to
8
- verify and improve the safety of your ruby code. There are at present two
8
+ verify and improve the safety of your ruby code. There are at present three
9
9
  modules under the safer umbrella:
10
10
 
11
- [<tt>Safer::IVar</tt>] generates specially-named accessor functions
12
- for class instance variables.
13
- [<tt>Safer::Protocol</tt>] is used to provide a ruby analogue to
14
- Objective-C Protocols (which are similar to
15
- Java interfaces, but do not require
16
- inheritance).
11
+ [<tt>Safer::IVar</tt>] generates specially-named accessor functions
12
+ for class instance variables.
13
+ [<tt>Safer::Protocol</tt>] is used to provide a ruby analogue to
14
+ Objective-C Protocols (which are similar to
15
+ Java interfaces, but do not require
16
+ inheritance).
17
+ [<tt>Safer::HashProtocol</tt>] verifies that a Hash keys follow a defined
18
+ format. Intended to help use of Hash objects as
19
+ keyword parameters.
17
20
 
18
21
  == FEATURES/PROBLEMS:
19
22
 
@@ -22,11 +25,13 @@ modules under the safer umbrella:
22
25
  * Define a "Protocol" class, and derive a signature from it. Verify that
23
26
  another class (or an instance of that class) implements the protocol
24
27
  signature.
28
+ * Define a check if a Hash contains a desired combination of keys.
25
29
 
26
30
  == SYNOPSIS:
27
31
 
28
32
  require 'safer/ivar'
29
33
  require 'safer/protocol'
34
+ require 'safer/hashprotocol'
30
35
 
31
36
  module MyModule
32
37
  class MyProtocolClass
@@ -39,11 +44,29 @@ modules under the safer umbrella:
39
44
  class MyClass
40
45
  Safer::IVar.instance_variable(self, :var1, :var2)
41
46
  def initialize(var1, var2)
42
- PROTOCOL.check_instance_conforms(var1)
43
- PROTOCOL.check_instance_conforms(var2)
47
+ PROTOCOL.instance_conforms?(var1)
48
+ PROTOCOL.instance_conforms?(var2)
44
49
  self.mymodule_myclass__var1 = var1
45
50
  self.mymodule_myclass__var2 = var2
46
51
  end
52
+
53
+ SHP = Safer::HashProtocol
54
+ V1Keywords = SHP::HasKey.create(:name, :type)
55
+ V2Keywords = SHP::HasKey.create(:first, :last, :type)
56
+ V1Check = SHP::Only.new(SHP::Any.new(*V1Keywords))
57
+ V2Check = SHP::Only.new(SHP::Any.new(*V2Keywords))
58
+ ValidCheck = SHP::Any.new(V1Check, V2Check)
59
+ def my_fn(h)
60
+ if ! (ValidCheck === h)
61
+ raise ArgumentError, "h should conform to #{ValidCheck.description}"
62
+ end
63
+ case h
64
+ when V1Check
65
+ v1_process(h[:name], h[:type])
66
+ when V2Check
67
+ v2_process(h[:first], h[:last], h[:type])
68
+ end
69
+ end
47
70
  end
48
71
  end
49
72
 
@@ -0,0 +1,304 @@
1
+ require 'safer/ivar'
2
+ require 'safer/protocol'
3
+
4
+ class Safer
5
+ ##
6
+ # Check that the keys in a Hash object follow a set of constraints.
7
+ # ==Usage
8
+ # In this example, we use a Hash to simulate keyword parameters to our
9
+ # function.
10
+ # class YourClass
11
+ # SHP = Safer::HashProtocol
12
+ # # we support two versions of the keyword arguments to our function.
13
+ # # In both versions, the Hash is required to have a :type field.
14
+ # CommonKeywords = SHP::HasKey.create(:type)
15
+ # # In the old version, a person's full name is presented in the :name
16
+ # # keyword.
17
+ # V1Keywords = SHP::HasKey.create(:name)
18
+ # # In the new version, the full name is separated into :familyName
19
+ # # and :givenName.
20
+ # V2Keywords = SHP::HasKey.create(:familyName, :givenName)
21
+ # # Check if the keywords in the Hash match Version1 (that is,
22
+ # # :name and :type fields must be present in the Hash, and no other
23
+ # # fields should be present).
24
+ # V1Check = SHP::Only.new(SHP::All.new(*CommonKeywords + *V1Keywords))
25
+ # # Check if the keywords in the Hash match Version2 (that is,
26
+ # # :familyName, :givenName, and :type fields must be present in the Hash,
27
+ # # and no other fields should be present).
28
+ # V2Check = SHP::Only.new(SHP::All.new(*CommonKeywords + *V2Keywords))
29
+ # # Check if the Hash matches either version 1 or version 2.
30
+ # ValidCheck = SHP::Any.new(V1Check, V2Check)
31
+ # def my_fn(h)
32
+ # if ! (ValidCheck === h)
33
+ # raise ArgumentError, "h should conform to #{ValidCheck.description}"
34
+ # end
35
+ # case h
36
+ # when V1Check
37
+ # v1_process(h[:name], h[:type])
38
+ # when V2Check
39
+ # v2_process(h[:familyName], h[:givenName], h[:type])
40
+ # end
41
+ # end
42
+ # end
43
+ # ==Rationale
44
+ # It is a common design practice in Ruby code to use Hash objects to get an
45
+ # analogue to function keyword arguments in other languages. Among other
46
+ # uses, this practice simplifies the implementation of embedded DSLs within
47
+ # Ruby. When used in this way, the Hash keys are semantically meaningful,
48
+ # and are generally entered by hand. It's important to get these Hashes
49
+ # right. Safer::HashProtocol is intended to help, by simultaneously
50
+ # providing a means of documenting the key combinations required of a Hash,
51
+ # and by detecting when the Hash does not contain a valid set of keys.
52
+ class HashProtocol
53
+ ##
54
+ # Object signature required of HashProtocol objects. Used to derive
55
+ # Safer::HashProtocol::Protocol.
56
+ class ProtocolBase
57
+ ##
58
+ # Retrieve a human-readable description of this HashProtocol object.
59
+ def description
60
+ end
61
+
62
+ ##
63
+ # Check that a Hash (h) follows this object's protocol.
64
+ def ===(h)
65
+ end
66
+
67
+ ##
68
+ # Check that a Hash (h) follows this object's protocol, keeping
69
+ # track of which parts of (h) do not. +remaining+ should only
70
+ # be updated if +h+ matches this object.
71
+ def match(h, remaining)
72
+ end
73
+ end # Safer::HashProtocol::ProtocolBase
74
+ ##
75
+ # Object signature required of HashProtocol objects. Derived from
76
+ # ProtocolBase.
77
+ Protocol = Safer::Protocol.create_from_class(ProtocolBase)
78
+
79
+ ##
80
+ # Base class of all classes exported from Safer::HashProtocol. Implements
81
+ # ProtocolBase#description signature.
82
+ class Base
83
+ Safer::IVar.instance_variable(self, :description)
84
+
85
+ ##
86
+ # :attr_reader: description
87
+ # Human-readable description of this HashProtocol.
88
+ Safer::IVar.export_reader(self, :description)
89
+
90
+ ##
91
+ # Store +description+ into the #description reader attribute.
92
+ def initialize(description)
93
+ self.safer_hashprotocol_base__description = description
94
+ end # Safer::HashProtocol::Base#initialize
95
+ end # Safer::HashProtocol::Base
96
+
97
+ ##
98
+ # Base class of Safer::HashProtocol implementations that provide some
99
+ # derived value from a single "base" implementation.
100
+ class Single < Safer::HashProtocol::Base
101
+ Safer::IVar.instance_variable(self, :base)
102
+
103
+ ##
104
+ # :attr_reader: base
105
+ # Base HashProtocol object from which this object's match operation
106
+ # should be derived.
107
+ Safer::IVar.export_reader(self, :base)
108
+ ##
109
+ # Stores the description and base HashProtocol object in this
110
+ # HashProtocol object. The description is derived from the description
111
+ # of the base object, prepended by +prefix+.
112
+ def initialize(prefix, base)
113
+ Protocol.instance_conforms?(base)
114
+ super("#{prefix}#{base.description}")
115
+ self.safer_hashprotocol_single__base = base
116
+ end # Safer::HashProtocol::Single#initialize
117
+ end # Safer::HashProtocol::Single
118
+
119
+ ##
120
+ # Base class of Safer::HashProtocol implementations that provide some
121
+ # derived value from a set of other HashProtocol implementations.
122
+ class Compound < Safer::HashProtocol::Base
123
+ Safer::IVar.instance_variable(self, :list)
124
+
125
+ ##
126
+ # :attr_reader: list
127
+ # Set of HashProtocol objects from which this object's match operation
128
+ # should be derived.
129
+ Safer::IVar.export_reader(self, :list)
130
+
131
+ ##
132
+ # Stores the description and set of base HashProtocol objects in this
133
+ # HashProtocol object. The description is derived from the description
134
+ # of the base HashProtocol objects, with +sep+ between each element.
135
+ def initialize(sep, *list)
136
+ desc = list.map do |el|
137
+ Protocol.instance_conforms?(el)
138
+ "(#{el.description})"
139
+ end.join(sep)
140
+ super(desc)
141
+ self.safer_hashprotocol_compound__list = list
142
+ end # Safer::HashProtocol::Compound#initialize
143
+ end # Safer::HashProtocol::Compound
144
+
145
+ ##
146
+ # Terminal Safer::HashProtocol implementation, checks that a key exists in
147
+ # a Hash.
148
+ class HasKey < Safer::HashProtocol::Base
149
+ Safer::IVar.instance_variable(self, :key)
150
+ ##
151
+ # The match operation will check that +key+ exists in the Hash.
152
+ # +key.inspect+ is used for the description.
153
+ def initialize(key)
154
+ super(key.inspect)
155
+ self.safer_hashprotocol_haskey__key = key
156
+ end # Safer::HashProtocol::HasKey#initialize
157
+
158
+ ##
159
+ # Check that the +key+ from self.initialize is stored in Hash h.
160
+ def ===(h)
161
+ h.has_key?(self.safer_hashprotocol_haskey__key)
162
+ end # Safer::HashProtocol::HasKey#===
163
+ ##
164
+ # Check that the +key+ from self.initialize is stored in Hash h. If it
165
+ # is, remove that key from +remaining+.
166
+ def match(h, remaining)
167
+ if h.has_key?(self.safer_hashprotocol_haskey__key)
168
+ remaining.delete(self.safer_hashprotocol_haskey__key)
169
+ true
170
+ else
171
+ false
172
+ end
173
+ end # Safer::HashProtocol::HasKey#match
174
+
175
+ ##
176
+ # Convenience function creates a HasKey object for each argument
177
+ # passed in.
178
+ def self.create(*args)
179
+ args.map do |el| self.new(el) end
180
+ end # Safer::HashProtocol::HasKey.create
181
+ end # Safer::HashProtocol::HasKey
182
+
183
+ ##
184
+ # Check that at least one of a set of Safer::HashProtocol objects matches
185
+ # a Hash.
186
+ class Any < Safer::HashProtocol::Compound
187
+ ##
188
+ # The description for this object will be the descriptions for each
189
+ # argument, separated by " OR ".
190
+ def initialize(*list)
191
+ super(" OR ", *list)
192
+ end # Safer::HashProtocol::Any#initialize
193
+
194
+ ##
195
+ # Check if any elements from the +list+ argument to initialize match
196
+ # Hash h.
197
+ def ===(h)
198
+ self.list.any? do |el| el === h end
199
+ end # Safer::HashProtocol::Any#===
200
+
201
+ ##
202
+ # Check if any elements from the +list+ argument to initialize match
203
+ # Hash h, keeping track of which elements from h have not been matched.
204
+ def match(h, remaining)
205
+ self.list.inject(false) do |memo, el|
206
+ if el.match(h, remaining)
207
+ true
208
+ else
209
+ memo
210
+ end
211
+ end
212
+ end # Safer::HashProtocol::Any#match
213
+ end # Safer::HashProtocol::Any
214
+
215
+ ##
216
+ # Check that all of a set of Safer::HashProtocol objects match a Hash.
217
+ class All < Safer::HashProtocol::Compound
218
+ ##
219
+ # The description for this object will be the descriptions for each
220
+ # argument, separated by " AND ".
221
+ def initialize(*list)
222
+ super(" AND ", *list)
223
+ end # Safer::HashProtocol::All#initialize
224
+
225
+ ##
226
+ # Check if all elements from the +list+ argument to initialize match
227
+ # Hash h.
228
+ def ===(h)
229
+ self.list.all? do |el| el === h end
230
+ end # Safer::HashProtocol::All#===
231
+
232
+ ##
233
+ # Check if all elements from the +list+ argument to initialize match
234
+ # Hash h. If they do, +remaining+ will be updated to remove all matching
235
+ # elements from +list+. If not all elements match, +remaining+ will be
236
+ # unmodified.
237
+ def match(h, remaining)
238
+ nremaining = remaining.dup
239
+ rval = self.list.all? do |el| el.match(h, nremaining) end
240
+ if rval
241
+ remaining.update(nremaining)
242
+ end
243
+ rval
244
+ end # Safer::HashProtocol::All#match
245
+ end # Safer::HashProtocol::All
246
+
247
+ ##
248
+ # Check that a base Safer::HashProtocol object does NOT match a Hash.
249
+ # That is, invert the match of a base HashProtocol object.
250
+ class Not < Safer::HashProtocol::Single
251
+ ##
252
+ # The description for this object will be "NOT #{base.description}".
253
+ def initialize(base)
254
+ super("NOT ", base)
255
+ end # Safer::HashProtocol::Not#initialize
256
+
257
+ ##
258
+ # Check that the base object does NOT match the hash.
259
+ def ===(h)
260
+ ! (self.base === h)
261
+ end # Safer::HashProtocol::Not#===
262
+
263
+ ##
264
+ # Check that the base object does NOT match the hash. Does not update
265
+ # +remaining+ under any circumstance.
266
+ def match(h, remaining)
267
+ self === h
268
+ end # Safer::HashProtocol::Not#match
269
+ end # Safer::HashProtocol::Not
270
+
271
+ ##
272
+ # Check that the Hash only contains elements that match the base
273
+ # Safer::HashProtocol object.
274
+ class Only < Safer::HashProtocol::Single
275
+ ##
276
+ # The description for this object will be "ONLY #{base.description}".
277
+ def initialize(base)
278
+ super("ONLY ", base)
279
+ end
280
+ ##
281
+ # Check that all keys in a hash are matched by the base HashProtocol
282
+ # object.
283
+ def ===(h)
284
+ remaining = h.dup
285
+ if self.base.match(h, remaining)
286
+ remaining.empty?
287
+ else
288
+ false
289
+ end
290
+ end
291
+ ##
292
+ # Check that all keys in a hash are matched by the base HashProtocol
293
+ # object. If they are, then empty +remaining+.
294
+ def match(h, remaining)
295
+ if self === h
296
+ remaining.clear
297
+ true
298
+ else
299
+ false
300
+ end
301
+ end
302
+ end # Safer::HashProtocol::Only
303
+ end # Safer::HashProtocol
304
+ end # Safer
data/lib/safer/ivar.rb CHANGED
@@ -1,4 +1,4 @@
1
- module Safer
1
+ class Safer
2
2
  ##
3
3
  # Create accessor functions for instance variables, in which the accessor
4
4
  # function is prefixed with the name of the class in which the instance
@@ -88,7 +88,7 @@ module Safer
88
88
  # search for when determining the set of instance variables defined by a
89
89
  # class.
90
90
  #
91
- module IVar
91
+ class IVar
92
92
 
93
93
  ##
94
94
  # Given a Class object, derive the prefix string for the accessor functions
@@ -1,7 +1,7 @@
1
1
  require 'safer/ivar'
2
2
 
3
- module Safer
4
- ## Safer::Protocol
3
+ class Safer
4
+ ##
5
5
  # Named set of class- and instance- methods, with associated numbers of
6
6
  # arguments. Call +create_from_class+ or +create_from_instance+ to create a
7
7
  # new +Protocol+ object. Call +class_conforms?+ or +instance_conforms?+
@@ -234,7 +234,7 @@ module Safer
234
234
  end # Safer::Protocol::Signature.create
235
235
  end # Safer::Protocol::Signature
236
236
 
237
- ## Safer::Protocol::Error
237
+ ##
238
238
  # Error generated when a class does not conform to a protocol signature.
239
239
  class Error < StandardError
240
240
  Safer::IVar.instance_variable(self, :error_object)
@@ -332,10 +332,38 @@ module Safer
332
332
  end # Safer::Protocol::Error::InstanceError
333
333
  end # Safer::Protocol::Error
334
334
 
335
+ ##
336
+ # Object provides an +===+ operator, which will match when the class
337
+ # conforms to the protocol. Instances are not created directly by clients,
338
+ # but instances can be retrieved through
339
+ # Safer::Protocol#match_class and Safer::Protocol#match_instance.
340
+ class Match
341
+ Safer::IVar.instance_variable(self, :method)
342
+ ##
343
+ # [<tt>method</tt>] Method to call from owning Protocol to verify that
344
+ # an object matches an interface.
345
+ def initialize(method)
346
+ self.safer_protocol_match__method = method
347
+ end # Safer::Protocol::Match#initialize
348
+
349
+ ##
350
+ # Returns true if the object conforms to the protocol, and false if
351
+ # it does not.
352
+ def ===(obj)
353
+ violations = self.safer_protocol_match__method.call(obj)
354
+ if violations
355
+ false
356
+ else
357
+ true
358
+ end
359
+ end # Safer::Protocol::Match#===
360
+ end # Safer::Protocol::Match
335
361
 
336
362
  Safer::IVar.instance_variable(self, :name)
337
363
  Safer::IVar.instance_variable(self, :class_signature)
338
364
  Safer::IVar.instance_variable(self, :instance_signature)
365
+ Safer::IVar.instance_variable(self, :match_class)
366
+ Safer::IVar.instance_variable(self, :match_instance)
339
367
 
340
368
  ##
341
369
  # :attr_reader: name
@@ -352,6 +380,16 @@ module Safer
352
380
  # Signatures of required instance methods for objects implementing this
353
381
  # protocol.
354
382
  Safer::IVar.export_reader(self, :instance_signature)
383
+ ##
384
+ # :attr_reader: match_class
385
+ # Object provides === operation matching when #violations_from_class would
386
+ # return no violations.
387
+ Safer::IVar.export_reader(self, :match_class)
388
+ ##
389
+ # :attr_reader: match_instance
390
+ # Object provides === operation matching when #violations_from_instance
391
+ # would return no violations.
392
+ Safer::IVar.export_reader(self, :match_instance)
355
393
 
356
394
  ##
357
395
  # Create a +Protocol+ object.
@@ -363,6 +401,8 @@ module Safer
363
401
  self.safer_protocol__name = name
364
402
  self.safer_protocol__class_signature = class_signature
365
403
  self.safer_protocol__instance_signature = instance_signature
404
+ self.safer_protocol__match_class = Safer::Protocol::Match.new(self.method(:violations_from_class))
405
+ self.safer_protocol__match_instance = Safer::Protocol::Match.new(self.method(:violations_from_instance))
366
406
  end # Safer::Protocol#initialize
367
407
 
368
408
  ##
data/lib/safer.rb CHANGED
@@ -9,8 +9,8 @@
9
9
  # Objective-C Protocols (which are similar to
10
10
  # Java interfaces, but do not require
11
11
  # inheritance).
12
- module Safer
12
+ class Safer
13
13
  ##
14
14
  # Current release of Safer.
15
- VERSION = "0.2.1"
15
+ VERSION = "0.3.0"
16
16
  end
@@ -0,0 +1,47 @@
1
+ require 'safer/hashprotocol'
2
+ require 'test/unit'
3
+
4
+ class TC_SaferHashProtocol < Test::Unit::TestCase
5
+ SHP = Safer::HashProtocol
6
+ def setup
7
+ @any_hash = { :foo => nil }
8
+ @all_hash = { :foo => nil, :bar => nil, :baz => nil }
9
+ @fail_hash = { :blubby => nil }
10
+ @has_key = SHP::HasKey.create(*@all_hash.keys)
11
+ end
12
+ def teardown
13
+ end
14
+
15
+ def test_any
16
+ any = SHP::Any.new(*@has_key)
17
+ not_any = SHP::Not.new(any)
18
+ assert(any === @any_hash)
19
+ assert(! (not_any === @any_hash))
20
+ assert(any === @all_hash)
21
+ assert(! (not_any === @all_hash))
22
+ assert(! (any === @fail_hash))
23
+ assert(not_any === @fail_hash)
24
+ end
25
+
26
+ def test_all
27
+ all = SHP::All.new(*@has_key)
28
+ not_all = SHP::Not.new(all)
29
+
30
+ assert(! (all === @any_hash))
31
+ assert(not_all === @any_hash)
32
+ assert(all === @all_hash)
33
+ assert(! (not_all === @all_hash))
34
+ assert(! (all === @fail_hash))
35
+ assert(not_all === @fail_hash)
36
+ end
37
+
38
+ def test_only
39
+ any = SHP::Any.new(*@has_key)
40
+ only = SHP::Only.new(any)
41
+ all_plus = @all_hash.merge(@fail_hash)
42
+ assert(only === @all_hash)
43
+ assert(any === @all_hash)
44
+ assert(! (only === all_plus))
45
+ assert(any === all_plus)
46
+ end
47
+ end
@@ -60,6 +60,7 @@ class TC_SaferProtocol < Test::Unit::TestCase
60
60
  :conforms => :instance_conforms?,
61
61
  :violations => :violations_from_instance,
62
62
  :get_object => proc do |obj| obj ; end,
63
+ :match => :match_instance,
63
64
  :error_type => Safer::Protocol::Error::InstanceError
64
65
  }
65
66
  else
@@ -67,6 +68,7 @@ class TC_SaferProtocol < Test::Unit::TestCase
67
68
  :conforms => :class_conforms?,
68
69
  :violations => :violations_from_class,
69
70
  :get_object => proc do |obj| obj.class ; end,
71
+ :match => :match_class,
70
72
  :error_type => Safer::Protocol::Error::ClassError
71
73
  }
72
74
  end
@@ -162,4 +164,30 @@ class TC_SaferProtocol < Test::Unit::TestCase
162
164
  run_classInstanceError(false)
163
165
  run_classInstanceError(true)
164
166
  end
167
+ def run_matchCase(methods, protocol, instance)
168
+ case methods[:get_object].call(instance)
169
+ when protocol.send(methods[:match])
170
+ true
171
+ else
172
+ false
173
+ end
174
+ end
175
+ def run_match(useinstance)
176
+ methods = get_methods(useinstance)
177
+ assert_same(run_matchCase(methods, @class_protocol, @class_instance), true)
178
+ assert_same(run_matchCase(methods, @class_protocol, @instance_instance), false)
179
+ assert_same(run_matchCase(methods, @class_protocol, @both_instance), true)
180
+
181
+ assert_same(run_matchCase(methods, @instance_protocol, @class_instance), false)
182
+ assert_same(run_matchCase(methods, @instance_protocol, @instance_instance), true)
183
+ assert_same(run_matchCase(methods, @instance_protocol, @both_instance), true)
184
+
185
+ assert_same(run_matchCase(methods, @both_protocol, @class_instance), false)
186
+ assert_same(run_matchCase(methods, @both_protocol, @instance_instance), false)
187
+ assert_same(run_matchCase(methods, @both_protocol, @both_instance), true)
188
+ end
189
+ def test_match
190
+ run_match(false)
191
+ run_match(true)
192
+ end
165
193
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: safer
3
3
  version: !ruby/object:Gem::Version
4
- hash: 21
4
+ hash: 19
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
- - 2
9
- - 1
10
- version: 0.2.1
8
+ - 3
9
+ - 0
10
+ version: 0.3.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Aidan Cully
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2010-10-17 00:00:00 -04:00
18
+ date: 2010-11-20 00:00:00 -05:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
@@ -52,15 +52,18 @@ dependencies:
52
52
  version_requirements: *id002
53
53
  description: |-
54
54
  Safer is an umbrella library, with components designed to make it simple to
55
- verify and improve the safety of your ruby code. There are at present two
55
+ verify and improve the safety of your ruby code. There are at present three
56
56
  modules under the safer umbrella:
57
57
 
58
- [<tt>Safer::IVar</tt>] generates specially-named accessor functions
59
- for class instance variables.
60
- [<tt>Safer::Protocol</tt>] is used to provide a ruby analogue to
61
- Objective-C Protocols (which are similar to
62
- Java interfaces, but do not require
63
- inheritance).
58
+ [<tt>Safer::IVar</tt>] generates specially-named accessor functions
59
+ for class instance variables.
60
+ [<tt>Safer::Protocol</tt>] is used to provide a ruby analogue to
61
+ Objective-C Protocols (which are similar to
62
+ Java interfaces, but do not require
63
+ inheritance).
64
+ [<tt>Safer::HashProtocol</tt>] verifies that a Hash keys follow a defined
65
+ format. Intended to help use of Hash objects as
66
+ keyword parameters.
64
67
  email:
65
68
  - aidan@panix.com
66
69
  executables: []
@@ -80,8 +83,10 @@ files:
80
83
  - lib/safer.rb
81
84
  - lib/safer/ivar.rb
82
85
  - lib/safer/protocol.rb
86
+ - lib/safer/hashprotocol.rb
83
87
  - test/test_safer_ivar.rb
84
88
  - test/test_safer_protocol.rb
89
+ - test/test_safer_hashprotocol.rb
85
90
  has_rdoc: true
86
91
  homepage: http://safer.rubyforge.org
87
92
  licenses: []
@@ -118,5 +123,6 @@ signing_key:
118
123
  specification_version: 3
119
124
  summary: Safer is an umbrella library, with components designed to make it simple to verify and improve the safety of your ruby code
120
125
  test_files:
126
+ - test/test_safer_hashprotocol.rb
121
127
  - test/test_safer_ivar.rb
122
128
  - test/test_safer_protocol.rb