safer 0.2.1 → 0.3.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.
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