primitive_wrapper 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 9201093aa1a6b289a8daec63a5bb81db853ac54f
4
+ data.tar.gz: eb6ebb33dd2c259832b1678d24f22892b776e13d
5
+ SHA512:
6
+ metadata.gz: 31a190053179c69be065b30386ef83e4d300b39494a04f1cbce428df7f2b2083f21105a2d682ef04ec2a98ec311517f5c9e7130875ab7d431a63f339e52d562c
7
+ data.tar.gz: cd5a4c4a12b8a2bbc53d5050431cb1b6bafd55afc8febb0c914556466f0aeaf091237f4aadb1880e25124305badf3cf2f49a78abc06787ec9cd756ea52f24243
data/.gitignore ADDED
@@ -0,0 +1,9 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
data/.travis.yml ADDED
@@ -0,0 +1,4 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.3.0
4
+ before_install: gem install bundler -v 1.11.2
@@ -0,0 +1,49 @@
1
+ # Contributor Code of Conduct
2
+
3
+ As contributors and maintainers of this project, and in the interest of
4
+ fostering an open and welcoming community, we pledge to respect all people who
5
+ contribute through reporting issues, posting feature requests, updating
6
+ documentation, submitting pull requests or patches, and other activities.
7
+
8
+ We are committed to making participation in this project a harassment-free
9
+ experience for everyone, regardless of level of experience, gender, gender
10
+ identity and expression, sexual orientation, disability, personal appearance,
11
+ body size, race, ethnicity, age, religion, or nationality.
12
+
13
+ Examples of unacceptable behavior by participants include:
14
+
15
+ * The use of sexualized language or imagery
16
+ * Personal attacks
17
+ * Trolling or insulting/derogatory comments
18
+ * Public or private harassment
19
+ * Publishing other's private information, such as physical or electronic
20
+ addresses, without explicit permission
21
+ * Other unethical or unprofessional conduct
22
+
23
+ Project maintainers have the right and responsibility to remove, edit, or
24
+ reject comments, commits, code, wiki edits, issues, and other contributions
25
+ that are not aligned to this Code of Conduct, or to ban temporarily or
26
+ permanently any contributor for other behaviors that they deem inappropriate,
27
+ threatening, offensive, or harmful.
28
+
29
+ By adopting this Code of Conduct, project maintainers commit themselves to
30
+ fairly and consistently applying these principles to every aspect of managing
31
+ this project. Project maintainers who do not follow or enforce the Code of
32
+ Conduct may be permanently removed from the project team.
33
+
34
+ This code of conduct applies both within project spaces and in public spaces
35
+ when an individual is representing the project or its community.
36
+
37
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
38
+ reported by contacting a project maintainer at bryan@bdlsys.com. All
39
+ complaints will be reviewed and investigated and will result in a response that
40
+ is deemed necessary and appropriate to the circumstances. Maintainers are
41
+ obligated to maintain confidentiality with regard to the reporter of an
42
+ incident.
43
+
44
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage],
45
+ version 1.3.0, available at
46
+ [http://contributor-covenant.org/version/1/3/0/][version]
47
+
48
+ [homepage]: http://contributor-covenant.org
49
+ [version]: http://contributor-covenant.org/version/1/3/0/
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in primitive_wrapper.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2017 Bryan Colvin
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,491 @@
1
+ # PrimitiveWrapper
2
+
3
+ This gem creates a thin shell to encapsulate primitive literal types such as integers, floats and symbols.
4
+ There are a family of wrappers which mimic the behavior of what they contain.
5
+ Primitive types have several drawbacks: no constructor to call, can't create instance variables, and can't create singleton methods.
6
+ There is some utility in wrapping a primitive type. You can simulate a call by reference for example.
7
+ You can also simulate mutability, and pointers.
8
+ Some wrappers are dedicated to holding a single type while others may hold a family of types such as the `Number` wrapper.
9
+ What is interesting to note is Number objects do not derive from `Numeric`, but instead derive from `Value` (the wrapper base class);
10
+ but at the same time, `Number` objects mimic the methods of `Fixnum`, `Complex`, `Float`, etc.
11
+ Many of the wrappers can be used in an expression without having to call an access method.
12
+ There are also new types: `Bool` which wraps `true,false` and `Property` which wraps `Hash` types.
13
+ The `Property` object auto-methodizes the key names of the `Hash`.
14
+
15
+ ## Installation
16
+
17
+ Add this line to your application's Gemfile:
18
+
19
+ ```ruby
20
+ gem 'primitive_wrapper'
21
+ ```
22
+
23
+ And then execute:
24
+
25
+ $ bundle
26
+
27
+ Or install it yourself as:
28
+
29
+ $ gem install primitive_wrapper
30
+
31
+ Or try it out inside irb:
32
+
33
+ $ require "primitive_wrapper"
34
+
35
+ ## Usage
36
+
37
+ There are 12 wrapper classes that hold these pesky primitive literal objects.
38
+ Unlike other class objects, these primitives have no constructor and attempt to look the the bottom turtle literals used in compiled languages like C/C++.
39
+ Such primitive literals are completely immutable. The wrappers used in this gem transform these primitive types into mutable objects.
40
+ In fact, these objects cannot be frozen as that would defeat their purpose. The freeze method on these wrapper classes is disabled.
41
+ The wrapped literal now behaves like a true ruby object such as Array, or Hash.
42
+ See the example below:
43
+
44
+ ```ruby
45
+ five = Integer.new(5) # ERROR :: undefined method `new' for Integer:Class
46
+ five = Fixnum.new(5) # ERROR :: undefined method `new' for Fixnum:Class
47
+ five = 5 # ok, this one works!
48
+
49
+ def five.tripple
50
+ self + self + self
51
+ end # ERROR :: TypeError: can't define singleton
52
+
53
+ require "primitive_wrapper"
54
+
55
+ five = Int.new(5) # we now have a wrapped Integer object
56
+ five + 5 + five # 15 ... wrapper has the methods of an Integer object and can be used in an expression
57
+
58
+ def five.tripple
59
+ self + self + self
60
+ end
61
+
62
+ five.tripple # 15
63
+
64
+ five.kind_of? Integer # false
65
+ five.kind_of? Value # true
66
+
67
+ 5.kind_of? Integer # true
68
+ 5.kind_of? Value # false
69
+ ```
70
+
71
+ As we can see from the above code, the Int class does not derive from Integer or anything that would appear numeric.
72
+ Our `Int` class is simply a container which happens to have the methods of `Integer` but does not derive itself from `Integer`.
73
+ All of these container objects derive from the Value class.
74
+
75
+ #### Object methods added
76
+
77
+ There are two new instance methods added to the base Object class necessary to implement this system.
78
+ The most important method is the `#to_wrapper` method.
79
+ When an instance variable calls this method, one of the wrapper containers will generate a new instance.
80
+ The one that gets picked is the one best suited for usability.
81
+ The other method named `#prim_value` will return the inner container value or simply return `self` if it is not a container derived from the `Value` class.
82
+ This is mostly used internally by the container objects. Below shows which objects get mapped to which containers:
83
+
84
+ ```
85
+ nil => Bit
86
+ true, false => Bool
87
+ Integer => Int
88
+ Float => FloatW
89
+ Complex => Number
90
+ Rational => Number
91
+ Symbol => SymbolW
92
+ Hash => Property
93
+ String => Datum
94
+ ```
95
+
96
+ Some examples are as follows:
97
+
98
+ ```ruby
99
+ n = nil.to_wrapper # n.class == Bit
100
+ b = true.to_wrapper # b.class == Bool
101
+ y = 13.to_wrapper # y.class == Int
102
+ t = 3e-9.to_wrapper # t.class == FloatW
103
+ z = (1+6i).to_wrapper # z.class == Number
104
+ str = "yo!".to_wrapper # str.class == Datum
105
+ me = :me.to_wrapper # me.class == SymbolW
106
+ prop = {}.to_wrapper # prop.class == Property
107
+ aw =[1,2,3].to_wrapper # aw.class == Value ... everything else goes inside the Value container
108
+ ```
109
+
110
+ The next sections will detail which objects are allowed to be contained within each container objects.
111
+
112
+ #### Value class container
113
+
114
+ This is the base class for all the containers created by this gem. Any object or primitive type can be held in this container.
115
+ To access the contents, simply call `#val`, `#prim_val`, or `#unwrap`.
116
+ Note that only `Value` derived objects can call `#val` while every object can call `#prim_val`.
117
+ You can also replace the contents with the `#replace` method or the `#val=` method.
118
+ The `Value` container has no restrictions on what it can hold. Other wrappers will raise an exception if the wrong type is added.
119
+ The comparison binary operators `==`, and `!=` are used to compare equality and inequality; this is done on the inner contained element.
120
+ Note that arrays are already containers, so there is little utility in placing it in another container.
121
+ The value container can only contain a single object; it is like an Array object that is only allowed to hold one item.
122
+ See the example code below:
123
+
124
+ ```ruby
125
+ require 'PrimitiveWrapper'
126
+
127
+ # simulation of a pointer
128
+
129
+ a = Value.new(15)
130
+ b = a
131
+ b.val # 15
132
+ a.val # 15
133
+ a.val = 2 # assign new inner value
134
+ b.val # a == 2 ... a,b point to the same data
135
+
136
+ # simulation of pass by reference
137
+
138
+ def pass_by_reference(a, ref)
139
+ ref.val += 15 + a
140
+ return :yes
141
+ end
142
+
143
+ t = pass_by_reference(1, bjc = Value.new(10)) # t==:yes, bjc.val==26
144
+ ```
145
+
146
+ The Value class has the following instance methods:
147
+ ```ruby
148
+ :val, :prim_val, :unwrap, :~ # Returns the internal data object (~ overriden by Int)
149
+ :val=, :replace # Sets the internal data object
150
+ :valid_type(inst) # Returns true if `inst` variable is compatible to wrapper object
151
+ # Child classes override this method
152
+ :freeze # Does nothing ... defined to prevent Object#freeze from being called
153
+ :== # Compares equality of the inner elements
154
+ :!= # Compares inequality of the inner elements
155
+ :inspect # "(Value)==>data" where Value is the class name of the Value derived object, and data is #val.inspect
156
+ :to_s # returns #to_s on contained entity
157
+ ```
158
+
159
+ #### Bool class container
160
+
161
+ The Bool container is allowed to contain only `true` or `false` primitive literals.
162
+ The container adds three binary operators: `&`, `|`, `^` and the prefix operator `!`.
163
+ Equality operators are inherited from the base class `Value`.
164
+ When an operator is called, a new Bool type is created.
165
+ Most of the other wrapper classes will return a standard type in order to make expressions less promblematic.
166
+ You can mix Bool types with `true` and `false` in an expression, but you must make sure the Bool type comes first or unexpected results may occur.
167
+ As with all wrapped containers, left-to-right expressions are owned by the left object. If this cannot be avoided, then calling `#val` will solve the problem.
168
+ This class is derived from Value. See the example below:
169
+
170
+ ```ruby
171
+ aaa = Bool.new(true)
172
+ bbb = Bool.new(false)
173
+
174
+ aaa & !bbb | bbb & !aaa == aaa ^ bbb # definition of XOR
175
+
176
+ t = aaa ^ true # creates a new Bool type with value of false
177
+ t = bbb ^ true # creates a new Bool type with value of true
178
+ t = true ^ aaa # incorrect order returns false ... not a Bool type
179
+ t = true ^ bbb # incorrect order returns false ... not a Bool type
180
+ t = true ^ "?" # false ... any object will return false except nil and false
181
+ t = true ^ 0 # false
182
+ t = true ^ false # true ... this is why Bool must come first when mixing Bool with true or false
183
+ t = true ^ nil # true ... one of the only two primitive types that will provide a true result
184
+
185
+ # other methods
186
+ .to_i # returns 0 if false, 1 if true
187
+ .to_int # returns an Int object wrapper filled with either 0 or 1
188
+ .val # returns true or false
189
+ ```
190
+ Note that the `~` prefix operator returns the primitive value.
191
+ The operator was also added to: Symbol, TrueClass, FalseClass, and NilClass which simply return self;
192
+ these classes previously did not define this operator. Only Integer and Int derived objects define this as being a one's complement operator.
193
+ This `~` prefix operator permits a terse way of getting to the primitive and can be used by Value derived objects or primitives described above.
194
+ This is necessary when using Bool types in conditional statements. Alternatively, you can use the #val method.
195
+
196
+ #### Bit class container
197
+
198
+ The `Bit` container is derived from Bool, but overrides the operators to return primitive values.
199
+ The Bit container also allows `nil` as a valid container entity. Bit objects are therefore thinner than Bool objects
200
+ and are most likely easier to work in expressions. There are also `FixedBit` derived classes called: `Null`, `TrueW`, `FalseW`.
201
+ These are essentially `Bit` objects restricted to a single type. See the example below:
202
+
203
+ ```ruby
204
+ a = Bit.new(nil)
205
+ aa = Null.new # a==aa ... ~a => nil ~aa => nil ~nil => nil
206
+
207
+ b = Bit.new(true)
208
+ bb = TrueW.new # b==bb ... ~b => true ~bb => true ~true => true
209
+
210
+ c = Bit.new(false)
211
+ cc = FalseW.new # c==cc ... ~c => false ~bb => false ~false => false
212
+
213
+ bb ^ b # false
214
+ y = ~b ? 3:4 # y == 3 ... ~b shortcut for b.val
215
+
216
+ FixedBit.new # *** RuntimeError Exception: FixedBit cannot create instance
217
+ aa.val = nil # *** RuntimeError Exception: can't assign primitive type
218
+ ```
219
+
220
+ #### Int class container
221
+
222
+ The `Int` container looks like a duck, quacks and waddles like a duck, swims like a duck, but it ain't a duck! The ancestor chain of `Int` only shares `Value`
223
+ and does not include `Numeric`. With a little meta-magic, the `Int` class mimics the methods of `Integer` so that it can be directly used
224
+ within an expression or without having to call `#val` to get the contained entity. Note that `~` does not get the contained entity, but instead returns the one's complement.
225
+ You can have your cake and eat it too by using two tildes `~~`. This undoes the one's complement and results in the primitive value.
226
+ The `#to_int` method on `Int` returns self, while `#to_i` accesses the primitive value.
227
+ Most of the time if `Integer` does not recognize something it calls coerce on the foreign object (which we grabbed from Integer).
228
+ This means that most expressions should work in whatever order you wish: if not, you will have to convert the Int object into an Integer object.
229
+ Pretty much all expressions with Int will create a primitive Integer.
230
+ See the example below:
231
+
232
+ ```ruby
233
+ aaa = 100.to_wrapper # method added to Object
234
+ bbb = Int.new(200) # standard constructor
235
+
236
+ ttt = aaa + bbb # ttt==300 ... ttt.class == Fixnum
237
+ ~aaa # -101
238
+ ~~aaa # 100
239
+
240
+ aaa.to_int # returns self, an Int object
241
+ aaa.to_i # returns 100
242
+ 100.to_i # returns 100
243
+ 100.to_int # returns 100
244
+ 3 + aaa # returns 103
245
+ aaa + 3 # returns 103
246
+ ```
247
+
248
+ #### FloatW class container
249
+
250
+ The `FloatW` container wraps `Float` types and possesses the thin wrapper similar to how `Int` works.
251
+ This can also be directly used within an expression. Only the `Float` derived objects may be placed inside this container.
252
+ The wrapper is so thin, you might think that you are actually a `Float` type.
253
+ See the example below:
254
+
255
+ ```ruby
256
+ aaa = 3.1415926.to_wrapper
257
+ bbb = FloatW.new(3e0)
258
+
259
+ aaa.to_i # 3
260
+ aaa.to_int #
261
+ aaa ** bbb # 31.006275093569673
262
+ aaa.to_i # 3
263
+ aaa.to_int # (Int==>3)
264
+ ```
265
+
266
+ #### Number class container
267
+
268
+ The `Number` container object can contain any object that is derived from `Numeric`.
269
+ This includes `Float`, `Fixnum`, `Bignum`, `Complex`, `Rational`, or even something that you create yourself so long as it derives from `Numeric`.
270
+ The class generator for `Number` grabs method names from all the standard library of Numeric derived classes.
271
+ This means that there is a possibility that the contained entity will not support some of the method calls.
272
+ This is no different than calling an undefined method. `Int`, `FloatW`, `Number`, `Datum` all derive from `ValueAdd` which is a child of `Value`.
273
+ You can't create an instance of `ValueAdd`, but it is used to store common methods as well as some class construction methods.
274
+ These will be described later on. This will come handy if you have a custom `Numeric` class and wish to import some of the methods defined there.
275
+ This works just like the other specific number wrappers previously described.
276
+
277
+ #### Datum class container
278
+
279
+ The `Datum` container holds everything a `Number` can hold and allows `String` data to be added. This represents things that a human can type into a form as a general data thing.
280
+ The methods of `String` are also added. Errors will occur if you try to call string methods on a `Datum` that is holding a number and visa versa.
281
+
282
+ #### SymbolW class container
283
+
284
+ The `SymbolW` class container holds a `Symbol` primitive. It derives directly from `Value`.
285
+ Although rarely used, `Symbol` types do have some immutable methods that have some string-like behavior.
286
+ The `SymbolW` class implements most of these, and adds some mutating methods as well.
287
+ This makes the SymolW object appear to be completely mutable; however, the inner element remains immutable.
288
+ See below:
289
+
290
+ ```ruby
291
+ # non-mutating methods taken from Symbol:
292
+ # :<, :<=, :>, :>=, :[], :between?, :capitalize, :downcase, :empty?, :length, :next, :size, :succ, :swapcase, :upcase
293
+
294
+ # non-mutating methods taken from String:
295
+ # :append, :include?, :prepend ... actually append renamed from :<<
296
+
297
+ # mutating methods of SymbolW
298
+ # :[]=, :append!, :capitalize!, :downcase!, :next!, :prepend!, :replace, :succ!, :swapcase!, :upcase!
299
+
300
+ # construction:
301
+ wsym = :my_symbol.to_wrapper
302
+ tsym = SymbolW.new(:my_other_symbol)
303
+
304
+ # example:
305
+ wsym[1] = :e # wsym == (SymbolW==>:me_symbol)
306
+ ```
307
+
308
+ #### Property class container
309
+
310
+ The `Property` class container holds a Hash object.
311
+ You can also place a `Hash` object inside the `Value` container, but there are no exposed methods there.
312
+ You can initialize the property class with a Hash instance, or start with a blank slate.
313
+ What is cool about the Property object is the internal hash keys become setters and getters on the instance so long as they obey the rules.
314
+ Additionally the internal hash is the original hash and not a copy;
315
+ so if the contained hash object is changed outside of the Property container,
316
+ new access methods will automatically be generated.
317
+ Hash keys that comprise upper and lowercase characters, underscore, and digits (with the first character not a number)
318
+ will become methods on the `Property` instance.
319
+ Note that these names cannot compete with existing instance method names of Object or Property including private methods.
320
+ Nested hierarchical names are not added: only the first-level names.
321
+ Non-compliant names are still added to the internal `Hash` instance; they just don't have the corresponding method names.
322
+ Another bonus is we have an unmolested `Hash` unlike other competing gems that trash the `Hash` with property getters and setters.
323
+ Most Hash methods except for `:[], :[]=` have not been implemented in order to allow for more property names.
324
+ You can quickly get to the internal Hash by using the `~` tilde prefix operator however.
325
+ See the code below:
326
+
327
+ ```ruby
328
+ abc = Property.new
329
+ xyz = Property.new {:fred => "freddy", :george => "georgey"}
330
+
331
+ abc.seven = 7
332
+ abc.property? :seven # true
333
+ abc.seven # 7
334
+ abc.val # {:seven => 7}
335
+ abc.to_s=15 # this won't create a property because :to_s is reserved
336
+ abc.property? :to_s # false
337
+ abc.deferred? :to_s # true ... internal hash owns this, but no property is created
338
+ abc.to_s # "{:seven=>7, :to_s=>15}"
339
+
340
+ abc.defined_properties! # [:seven]
341
+ xyz.defined_properties! # [:fred, :george]
342
+ abc.deferred_properties! # [:to_s]
343
+ xyz.deferred_properties! # []
344
+
345
+ abc.keys # NoMethodError Exception: undefined method `keys' for (Property==>{...}):Property
346
+ (~abc).keys # [:seven, :to_s] ... Note ~abc.keys does not work as this is interpreted as: ~(abc.keys)
347
+ abc.val.keys # [:seven, :to_s] ... probably best syntax
348
+ hash = ~abc # grab internal Hash object
349
+ hash[:cool] = "yes!"
350
+ abc.cool # "yes!" ... wrapper behavior looks pointer-ish
351
+ abc[:works2] = "yep!"
352
+ abc.works2 # "yep!" ... wrapper supports array access
353
+ abc[:seven] # 7
354
+ abc.sam = {}
355
+ abc.defined_properties! # [:cool, :sam, :seven, :works2]
356
+ abc.val = {}
357
+ abc.defined_properties! # [] ... you just zapped the entire hash after abc.val = {}
358
+
359
+ # Property Instance methods
360
+ # :~ :unwrap :val :prim_value ... returns internal hash
361
+ # :val= :replace ... assigns new hash to wrapper
362
+ # :[] :[]= ... access internal hash element
363
+ # :deferred? key ... true if key in in internal hash but will not create a property access variable
364
+ # :property? key ... true if key is registered as a property access variable
365
+ # :split! ... returns an array of two Hash instances with [valid_property_hash, deferred_hash]
366
+ # :rekey! ... rekeys property and deferred keys ... called internally
367
+ # :valid_type inst_var ... used internally for #replace or #val= ... true if Hash or Property instance
368
+ # :method_missing ... used internally to simulate property methods
369
+ # :import_hash! ext_hash ... merge foreign hash into self
370
+ # :ensure_valid ... used internally ... raises error on type mismatch from :valid_type
371
+ # :deferred_properties! ... returns list of keys that do not have property methods
372
+ # :defined_properties! ... returns list of keys that have property methods
373
+ # :define_properties! [] , dflt ... assignes default properties to a list of property keys
374
+
375
+ # Property Class methods
376
+ # ::good_candidate_name? name ... test to see if name is formatted corectly, and is of type Hash
377
+ # ::good_key? name ... true if properly formatted and not a reserved word
378
+ # ::bad_key? name ... true if wrong type, or reserved word, or not formatted correctly
379
+ # ::reserve_property_names! [] ... adds additional reserved words
380
+ ```
381
+
382
+ #### Customization
383
+
384
+ Things should work out of the box, until they don't. This section will detail what customization is possible with what container.
385
+ First, Property has one method to reserve allowed property key names. This is done as follows:
386
+
387
+ ```ruby
388
+ Property.reserve_property_names! [:Fred, :Wilma, :BamBam, :Barney, :Betty, :Pebbles]
389
+
390
+ bedrock = Property.new
391
+ bedrock.Fred = "Yaba Daba Doo!"
392
+ bedrock.property? :Fred # false
393
+ bedrock.deferred? :Fred # true
394
+ bedrock[:Fred] # "Yaba Daba Doo!"
395
+ bedrock.Fred # *** NoMethodError Exception: undefined method `Fred' for (Property==>{...}):Property
396
+ bedrock.Test = "pass"
397
+ bedrock.Test # "pass"
398
+ ```
399
+
400
+ The containers `Int`, `FloatW`, `Number`, and `Datum` all derive from `ValueAdd` which has two class methods.
401
+ The `ValueAdd` class derives from `Value`, but cannot create an instance. Its purpose is to generate methods
402
+ that belong somewhere else. If we peer into the code we see this:
403
+
404
+ ```ruby
405
+ class ValueAdd < Value
406
+ def valid_type(prm) # must override
407
+ false
408
+ end
409
+ def self.bestow_methods(*args)
410
+ args = args.first if args.first.kind_of? Array
411
+ args.each do |meth|
412
+ define_method meth do |*args, &block|
413
+ @value.send(meth, *args, &block)
414
+ end
415
+ end
416
+ end
417
+ def self.capture_base_methods(type, except=Object)
418
+ add_me = type.instance_methods - except.instance_methods - Value.instance_methods - [:singleton_method_added]
419
+ bestow_methods add_me
420
+ end
421
+ end
422
+ ```
423
+
424
+ If we call `Int.capture_base_methods(Fixnum)`, all of the methods that a Fixnum can do is bestowed to the Int class.
425
+ If you define a new method to Integer called `:do_my_math_thing`, you can teach Int to do it by calling `Int.bestow_methods(:do_my_math_thing)`.
426
+ You should also add it to `Number` and `Datum`. Let's say you have a really cool Matrix class that you would like to teach the Number wrapper.
427
+ Here is how you would do it:
428
+
429
+ ```ruby
430
+ class Number
431
+ capture_base_methods(Matrix, self)
432
+ end
433
+ ```
434
+
435
+ Some of the most extensive customizations involve the SymbolW wrapper class. Only a small subset of `String` methods were added to this wrapper.
436
+ They were chosen to complement the non-mutating `String` like functions already available to Symbols.
437
+ For example, `#upcase!` was added to complement `#upcase`. Note that the Symbol class does not and cannot have a mutating method.
438
+ There are several Class methods on `SymbolW` that capture `Symbol` and `String` methods in several configurable ways.
439
+ If we look under the hood at the source code we will see how they got defined by example:
440
+
441
+ ```ruby
442
+ # ClassW class methods:
443
+ #
444
+ # -- single defines
445
+ # ::bestow_symbol_method(meth_def_name, meth_call_name, mutate_self=false)
446
+ # ::bestow_string_non_mutate_method(meth_def_name, meth_call_name, return_type = SymbolW)
447
+ # ::bestow_string_mutate_method(meth_def_name, meth_call_name)
448
+ #
449
+ # -- group defines
450
+ # ::bestow_string_mutate_methods(meths)
451
+ # ::bestow_string_non_mutate_methods(meths, return_type = SymbolW)
452
+ # ::bestow_symbol_methods(meths, mutate_self=false)
453
+ #
454
+ ```
455
+ The group defines are used when you don't need to rename a method and wish to install a bunch of them.
456
+ As an example `SymbolW.bestow_symbol_methods [:next, :succ, :[], :length, :size, :upcase, :downcase, ...]` was called to install the standard set of methods that exist on `Symbol`.
457
+ The last parameter when set to true will mutate the inner Symbol which means that it gets replaced with the result of the method.
458
+ Some methods that do not return a string like `#length` should not be used as a source for mutating methods.
459
+ Passing `true` as the second parameter will auto-bang the name turning `#upcase` into `#upcase!`. The singular version of the method gives you more control allowing you to completely rename the method.
460
+ The number of Symbol methods is fairly small when compared to the number of String methods.
461
+ It was intentional to leave most of these open as it there are many ways to transform these methods. The self mutating version is the most straight forward as we don't need to worry about the return type.
462
+ See the code below to see how it was used:
463
+
464
+ ```ruby
465
+ SymbolW.bestow_string_mutate_method(:prepend!, :prepend)
466
+ SymbolW.bestow_string_mutate_method(:append!, :<<)
467
+ SymbolW.bestow_string_mutate_method(:[]=, :[]=)
468
+ ```
469
+
470
+ Looking at the code, we see that the `#append!` method is a renamed version of `:<<`. What is interesting to note is that both in the `String` and the `Symbol` classes `#append` is not found.
471
+ Only string implements `:<<` which is a binary operator that does not mutate. Because we are bestowing this self-mutating method to `SymbolW`, we don't need to consider what the return type is as `self` is the only logical choice.
472
+ The non-mutating version must choose what kind of type is returned. We have four choices for return types: (1) force a conversion to `SymbolW`, (2) return `Symbol`, (3) return `String`, or (4) return whatever the string method would otherwise return.
473
+ We would choose the 4th version for any non-string return method such as `#match`. To select this we pass `nil` to the return type which says let the string method decide.
474
+ Now we are left with the head-scratcher on how to decide which is the best return type to give to a string method bestowed upon a wrapped symbol thing.
475
+ This can be mostly a matter of taste, but we can choose custom names that convey this information. Now if you have an extension library such as used by the `gstring` gem, you have an even larger list to choose from.
476
+ So it is left to you to decide.
477
+
478
+ ## Development
479
+
480
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
481
+
482
+ To install this gem onto your local machine, run `bundle exec rake install`.
483
+
484
+ ## Contributing
485
+
486
+ I need to control this for the time being. You are welcome to shoot me an EMAIL if you have any issues or suggestions.
487
+
488
+ ## License
489
+
490
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
491
+