safer 0.4.0 → 0.4.1

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.
@@ -1,3 +1,7 @@
1
+ === 0.4.1 / 2011-10-29
2
+
3
+ * Fixed Manifest.txt.
4
+
1
5
  === 0.4.0 / 2011-10-29
2
6
 
3
7
  * Safer::IVar functionality moved into Safer::IVarFactory class.
@@ -5,8 +5,13 @@ README.rdoc
5
5
  Rakefile
6
6
  lib/safer.rb
7
7
  lib/safer/ivar.rb
8
+ lib/safer/ivarfactory.rb
9
+ lib/safer/ivarfactory/dsl.rb
10
+ lib/safer/ivarfactory/prefix.rb
8
11
  lib/safer/protocol.rb
9
12
  lib/safer/hashprotocol.rb
10
13
  test/test_safer_ivar.rb
14
+ test/test_safer_ivar_run.rb
15
+ test/test_safer_ivarfactory.rb
11
16
  test/test_safer_protocol.rb
12
17
  test/test_safer_hashprotocol.rb
@@ -15,5 +15,5 @@
15
15
  class Safer
16
16
  ##
17
17
  # Current release of Safer.
18
- VERSION = "0.4.0"
18
+ VERSION = "0.4.1"
19
19
  end
@@ -0,0 +1,269 @@
1
+ require 'safer'
2
+
3
+ ##
4
+ # Create accessor functions for instance variables, in which the accessor
5
+ # function is prefixed with the name of the class in which the instance
6
+ # variable is defined.
7
+ #
8
+ # ==Usage
9
+ # Create one or more instance variables using instance_variable .
10
+ # For example, the following code:
11
+ # class Outer
12
+ # Safer::IVar.instance_variable(self, :variable)
13
+ # class Inner < Outer
14
+ # Safer::IVar.instance_variable(self, :variable)
15
+ # end
16
+ # end
17
+ # puts(Outer.instance_methods.grep(/__variable/).inspect)
18
+ # puts(Outer::Inner.instance_methods.grep(/__variable/).inspect)
19
+ # produces the following output:
20
+ # ["outer__variable", "outer__variable="]
21
+ # ["outer_inner__variable", "outer_inner__variable=", "outer__variable", "outer__variable="]
22
+ #
23
+ # Accessors for Safer::IVar-defined instance variables can be created using
24
+ # export_reader, export_writer, and export_accessor .
25
+ #
26
+ # ==Rationale
27
+ # Safer::IVar is intended to improve the clarity and consistency of ruby
28
+ # code in at least the following (related) ways:
29
+ #
30
+ # 1. Reducing the probability of instance variable usage errors.
31
+ # 2. Documenting the instance variables attached to a class.
32
+ #
33
+ # ===Error Reduction
34
+ # Safer::IVar should help in reducing errors in at least the following ways:
35
+ #
36
+ # * Encapsulation errors. Traditional ruby instance variables defined by one
37
+ # class are transparently accessible to all subclasses. They are not,
38
+ # however, part of the public interface to a class (unless an accessor is
39
+ # defined), which means they are not generally documented. These two
40
+ # factors create a situation in which it is quite possible that a subclass
41
+ # inadvertantly re-define an instance variable in such a way as to render
42
+ # the subclass unusable. Bugs of this sort can be very difficult to
43
+ # resolve.
44
+ #
45
+ # Because instance variables generated by Safer::IVar are prefixed with a
46
+ # string derived from the class in which the variable is defined, it is much
47
+ # less likely that developers _inadvertantly_ re-define instance variables
48
+ # in sub-classes, dramatically reducing the likelihood of this type of
49
+ # error.
50
+ #
51
+ # * Misspelling errors. For example, suppose you typically write software
52
+ # using the en-us dialect, and have an object with a +@color+ instance
53
+ # variable. A en-uk speaker then submits a patch that sets the default
54
+ # color to green:
55
+ # --- ex1.rb 2010-09-28 06:24:52.000000000 -0400
56
+ # +++ ex2.rb 2010-09-28 06:25:00.000000000 -0400
57
+ # @@ -1,6 +1,7 @@
58
+ # class Foo
59
+ # def initialize
60
+ # @size = 3
61
+ # + @colour = "green"
62
+ # end
63
+ # attr_reader :color
64
+ # end
65
+ # This code will not raise any exceptions, but its behavior does not match
66
+ # developer intent. On the other hand, using Safer::IVar
67
+ # --- ex1-safer.rb 2010-09-28 06:31:51.000000000 -0400
68
+ # +++ ex2-safer.rb 2010-09-28 06:32:08.000000000 -0400
69
+ # @@ -1,7 +1,8 @@
70
+ # class Foo
71
+ # Safer::IVar.instance_variable(self, :size, :color)
72
+ # Safer::IVar.export_reader(self, :color)
73
+ # def initialize
74
+ # self.foo__size = 3
75
+ # + self.foo__colour = "green"
76
+ # end
77
+ # end
78
+ # The new code will raise an exception at the call to Foo.new, making it
79
+ # much less likely that the error will go undetected.
80
+ #
81
+ # ===Documentation
82
+ # Traditional ruby instance variables are defined and used in an <i>ad hoc</i>
83
+ # manner. As such, there is no natural location in which the instance
84
+ # variables defined by a class can be documented, and no obvious way to
85
+ # determine the set of instance variables used in a class. Safer::IVar
86
+ # instance variables will all be associated with a single call to
87
+ # Safer::IVar.instance_variable. This provides both a natural location for
88
+ # documenting an instance variable's interpretation, as well as a string to
89
+ # search for when determining the set of instance variables defined by a
90
+ # class.
91
+ #
92
+ class Safer::IVarFactory
93
+ def initialize(prefix)
94
+ @prefix = prefix
95
+ end
96
+
97
+ ##
98
+ # Given a Class object, derive the prefix string for the accessor functions
99
+ # that instance_variable will create.
100
+ def class_symbol_prefix(klass)
101
+ @prefix.class_symbol_prefix(klass)
102
+ end # Safer::IVarFactory#class_symbol_prefix
103
+
104
+ ##
105
+ # Used internally.
106
+ # [+prefix+] Prefix of generated symbol names.
107
+ # [+nmlist+] Array of +Symbol+ objects.
108
+ # [_return_] Array of +Symbol+ objects. Each element will be the
109
+ # concatenation of the +prefix+, '__', and the corresponding
110
+ # element of +nmlist+
111
+ def _symbol_names_internal(prefix, nmlist)
112
+ nmlist.map do |nm|
113
+ (prefix + '__' + nm.to_s).to_sym
114
+ end
115
+ end
116
+
117
+ ##
118
+ # Used internally.
119
+ # [+klass+] Class object for which to generate a symbol name.
120
+ # [+nmlist+] Array of +Symbol+ objects.
121
+ # [_return_] Array of +Symbol+ objects generated from +klass+ and each
122
+ # element of +nmlist+.
123
+ def _symbol_names(klass, nmlist)
124
+ kname = self.class_symbol_prefix(klass)
125
+ self._symbol_names_internal(kname, nmlist)
126
+ end # Safer::IVarFactory#_symbol_names
127
+
128
+ ##
129
+ # compute accessor routine symbol names, where the symbol name prefix is
130
+ # derived from the class name.
131
+ # [+klass+] Class object for which to generate a symbol name.
132
+ # [+nmlist+] Array of +Symbol+ objects.
133
+ # [_return_] Array of +Symbol+ objects generated from +klass+ and each
134
+ # element of +nmlist+.
135
+ # For example, given the following listing:
136
+ # class OuterClass
137
+ # class InnerClass
138
+ # SYMNM = Safer::IVar.symbol_names(self, :foo)
139
+ # puts(SYMNM.to_s)
140
+ # end
141
+ # end
142
+ # the following output would be produced:
143
+ # outerclass_innerclass__foo
144
+ def symbol_names(klass, *nmlist)
145
+ self._symbol_names(klass, nmlist)
146
+ end # Safer::IVarFactory#symbol_names
147
+
148
+ ##
149
+ # Used internally. See Safer::IVarFactory#instance_variable, and
150
+ # Safer::IVarFactory::Dsl#ivar .
151
+ def _instance_variable_internal(klass, prefix, nmlist)
152
+ self._symbol_names_internal(prefix, nmlist).each do |symnm|
153
+ klass.class_eval do
154
+ attr_accessor symnm
155
+ end
156
+ end
157
+ end
158
+
159
+ ##
160
+ # create accessor routines for an instance variable, with variable name
161
+ # determined by the class in which the instance variable was declared.
162
+ # [+klass+] Class object into which to generate the variable accessor
163
+ # functions.
164
+ # [+nmlist+] List of symbols for which to create accessor routines.
165
+ # Uses Safer::IVar.symbol_names to determine the symbol names of the
166
+ # accessor routines.
167
+ # For example, the listing:
168
+ # class MyClass
169
+ # class SubClass
170
+ # Safer::IVar.instance_variable(self, :foo, :bar)
171
+ # end
172
+ # end
173
+ # is equivalent to the following code:
174
+ # class MyClass
175
+ # class SubClass
176
+ # attr_accessor :myclass_subclass__foo
177
+ # attr_accessor :myclass_subclass__bar
178
+ # end
179
+ # end
180
+ # The name-mangling signals that these instance variables are, for all
181
+ # intents and purposes, private to +klass+.
182
+ def instance_variable(klass, *nmlist)
183
+ self._instance_variable_internal(
184
+ klass, self.class_symbol_prefix(klass), nmlist)
185
+ end # Safer::IVarFactory#instance_variable
186
+
187
+ ##
188
+ # Used internally. See Safer::IVarFactory#export_reader, and
189
+ # Safer::IVarFactory::Dsl#reader .
190
+ def _export_reader_internal(klass, prefix, nmlist)
191
+ symlist = self._symbol_names_internal(prefix, nmlist)
192
+ nmlist.size.times do |index|
193
+ thisnm = nmlist[index]
194
+ thissym = symlist[index]
195
+ klass.class_eval("def #{thisnm} ; self.#{thissym} ; end")
196
+ end
197
+ end
198
+
199
+ ##
200
+ # export the reader routines for instance variables in a safer way.
201
+ # [+klass+] Class object for which to define reader accessors for
202
+ # instance variables defined by Safer::IVar.instance_variable.
203
+ # [+nmlist+] List of symbols for which to define reader accessors.
204
+ # Each symbol in +nmlist+ should have previously been given as
205
+ # an argument to Safer::IVar.instance_variable(+klass+).
206
+ def export_reader(klass, *nmlist)
207
+ self._export_reader_internal(
208
+ klass, self.class_symbol_prefix(klass), nmlist)
209
+ end # Safer::IVarFactory#export_reader
210
+
211
+ ##
212
+ # Used internally. See Safer::IVarFactory#export_writer, and
213
+ # Safer::IVarFactory::Dsl#writer .
214
+ def _export_writer_internal(klass, prefix, nmlist)
215
+ symlist = self._symbol_names_internal(prefix, nmlist)
216
+ nmlist.size.times do |index|
217
+ thisnm = nmlist[index]
218
+ thissym = symlist[index]
219
+ klass.class_eval(
220
+ "def #{thisnm}=(value) ; self.#{thissym} = value ; end"
221
+ )
222
+ end
223
+ end
224
+
225
+ ##
226
+ # export the writer routines for instance variables in a safer way.
227
+ # [+klass+] Class object for which to define writer accessors for
228
+ # instance variables defined by Safer::IVar.instance_variable.
229
+ # [+nmlist+] List of symbols for which to define writer accessors.
230
+ # Each symbol in +nmlist+ should have previously been given as
231
+ # an argument to Safer::IVar.instance_variable(+klass+).
232
+ def export_writer(klass, *nmlist)
233
+ self._export_writer_internal(
234
+ klass, self.class_symbol_prefix(klass), nmlist)
235
+ end # Safer::IVarFactory#export_writer
236
+
237
+ ##
238
+ # Used internally. See Safer::IVarFactory#export_accessor, and
239
+ # Safer::IVarFactory::Dsl#accessor .
240
+ def _export_accessor_internal(klass, prefix, nmlist)
241
+ self._export_reader_internal(klass, prefix, nmlist)
242
+ self._export_writer_internal(klass, prefix, nmlist)
243
+ end
244
+
245
+ ##
246
+ # export both reader and writer routines for instance variables in a
247
+ # safer way.
248
+ # [+klass+] Class object for which to define accessors for
249
+ # instance variables defined by Safer::IVar.instance_variable.
250
+ # [+nmlist+] List of symbols for which to define accessors.
251
+ # Each symbol in +nmlist+ should have previously been given as
252
+ # an argument to Safer::IVar.instance_variable(+klass+).
253
+ def export_accessor(klass, *nmlist)
254
+ self._export_accessor_internal(
255
+ klass, self.class_symbol_prefix(klass), nmlist)
256
+ end # Safer::IVarFactory#export_accessor
257
+
258
+ ##
259
+ # Yield DSL interface for instance variable creation to caller. See
260
+ # Safer::IVarFactory::Dsl for the DSL API.
261
+ # [+klass+] Class object used by DSL interface.
262
+ def run(klass)
263
+ yield(Dsl.new(self, klass))
264
+ end # Safer::IVarFactory#run
265
+
266
+ end # Safer::IVarFactory
267
+
268
+ require 'safer/ivarfactory/dsl.rb'
269
+ require 'safer/ivarfactory/prefix.rb'
@@ -0,0 +1,49 @@
1
+ ##
2
+ # Present a lightweight interface to instance variable creation. An
3
+ # instance of this class is given to the user as an argument to the yield
4
+ # block passed to Safer::IVarFactory#run. For example:
5
+ # class Foo
6
+ # Safer::IVar.run(self) do |ivar|
7
+ # # ivar is an instance of Safer::IVarFactory::Dsl
8
+ # end
9
+ # end
10
+ class Safer::IVarFactory::Dsl
11
+ ##
12
+ # Initialize a DSL object.
13
+ # [+factory+] IVarFactory to use for creating instance variables.
14
+ # [+klass+] +klass argument to Safer::IVarFactory#run; create instance
15
+ # variables in this class.
16
+ def initialize(factory, klass)
17
+ @factory = factory
18
+ @klass = klass
19
+ @symbol_prefix = factory.class_symbol_prefix(klass)
20
+ end # Safer::IVarFactory::Dsl#initialize
21
+
22
+ ##
23
+ # Define Safer::IVarFactory instance variables for the class attached to
24
+ # this DSL object. See Safer::IVarFactory#instance_variable
25
+ def ivar(*args)
26
+ @factory._instance_variable_internal(@klass, @symbol_prefix, args)
27
+ end # Safer::IVarFactory::Dsl#ivar
28
+
29
+ ##
30
+ # Export readers for Safer::IVarFactory instance variables in the class
31
+ # attached to this DSL object. See Safer::IVarFactory#export_reader
32
+ def reader(*args)
33
+ @factory._export_reader_internal(@klass, @symbol_prefix, args)
34
+ end # Safer::IVarFactory::Dsl#reader
35
+
36
+ ##
37
+ # Export writers for Safer::IVarFactory instance variables in the class
38
+ # attached to this DSL object. See Safer::IVarFactory#export_reader
39
+ def writer(*args)
40
+ @factory._export_writer_internal(@klass, @symbol_prefix, args)
41
+ end # Safer::IVarFactory::Dsl#writer
42
+
43
+ ##
44
+ # Export accessors for Safer::IVarFactory instance variables in the class
45
+ # attached to this DSL object. See Safer::IVarFactory#export_reader
46
+ def accessor(*args)
47
+ @factory._export_accessor_internal(@klass, @symbol_prefix, args)
48
+ end # Safer::IVarFactory::Dsl#accessor
49
+ end # Safer::IVarFactory::Dsl
@@ -0,0 +1,29 @@
1
+ class Safer::IVarFactory::Prefix
2
+ def self.is_anon(component)
3
+ /^\#<.*>$/.match(component)
4
+ end
5
+
6
+ class Full < Safer::IVarFactory::Prefix
7
+ def self.class_symbol_prefix(klass)
8
+ klass.to_s.split('::').inject(nil) do |memo, el|
9
+ # reset the symbol name when an anonymous class is encountered.
10
+ if self.is_anon(el)
11
+ nil
12
+ elsif memo
13
+ memo + '_' + el.downcase
14
+ else
15
+ el.downcase
16
+ end
17
+ end
18
+ end # Safer::IVarFactory::Prefix::Full#class_symbol_prefix
19
+ end # Safer::IVarFactory::Prefix::Full
20
+
21
+ class Last < Safer::IVarFactory::Prefix
22
+ def self.class_symbol_prefix(klass)
23
+ el = klass.to_s.split('::').reverse.find do |obj|
24
+ ! self.is_anon(obj)
25
+ end
26
+ el.downcase
27
+ end
28
+ end # Safer::IVarFactory::Prefix::Last
29
+ end # Safer::IVarFactory::Prefix
metadata CHANGED
@@ -1,13 +1,12 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: safer
3
3
  version: !ruby/object:Gem::Version
4
- hash: 15
5
4
  prerelease: false
6
5
  segments:
7
6
  - 0
8
7
  - 4
9
- - 0
10
- version: 0.4.0
8
+ - 1
9
+ version: 0.4.1
11
10
  platform: ruby
12
11
  authors:
13
12
  - Aidan Cully
@@ -26,7 +25,6 @@ dependencies:
26
25
  requirements:
27
26
  - - ">="
28
27
  - !ruby/object:Gem::Version
29
- hash: 7
30
28
  segments:
31
29
  - 2
32
30
  - 0
@@ -42,12 +40,11 @@ dependencies:
42
40
  requirements:
43
41
  - - ">="
44
42
  - !ruby/object:Gem::Version
45
- hash: 19
46
43
  segments:
47
44
  - 2
48
- - 6
49
- - 2
50
- version: 2.6.2
45
+ - 7
46
+ - 0
47
+ version: 2.7.0
51
48
  type: :development
52
49
  version_requirements: *id002
53
50
  description: |-
@@ -81,13 +78,16 @@ files:
81
78
  - Rakefile
82
79
  - lib/safer.rb
83
80
  - lib/safer/ivar.rb
81
+ - lib/safer/ivarfactory.rb
82
+ - lib/safer/ivarfactory/dsl.rb
83
+ - lib/safer/ivarfactory/prefix.rb
84
84
  - lib/safer/protocol.rb
85
85
  - lib/safer/hashprotocol.rb
86
86
  - test/test_safer_ivar.rb
87
- - test/test_safer_protocol.rb
88
- - test/test_safer_hashprotocol.rb
89
87
  - test/test_safer_ivar_run.rb
90
88
  - test/test_safer_ivarfactory.rb
89
+ - test/test_safer_protocol.rb
90
+ - test/test_safer_hashprotocol.rb
91
91
  has_rdoc: true
92
92
  homepage: http://safer.rubyforge.org
93
93
  licenses: []
@@ -103,7 +103,6 @@ required_ruby_version: !ruby/object:Gem::Requirement
103
103
  requirements:
104
104
  - - ">="
105
105
  - !ruby/object:Gem::Version
106
- hash: 3
107
106
  segments:
108
107
  - 0
109
108
  version: "0"
@@ -112,7 +111,6 @@ required_rubygems_version: !ruby/object:Gem::Requirement
112
111
  requirements:
113
112
  - - ">="
114
113
  - !ruby/object:Gem::Version
115
- hash: 3
116
114
  segments:
117
115
  - 0
118
116
  version: "0"