betterobject 0.1.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.
- checksums.yaml +7 -0
- data/.gitignore +9 -0
- data/.rspec +2 -0
- data/.travis.yml +4 -0
- data/CODE_OF_CONDUCT.md +49 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +584 -0
- data/Rakefile +6 -0
- data/betterobject.gemspec +36 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/lib/betterobject/version.rb +3 -0
- data/lib/betterobject.rb +246 -0
- data/lib/generators.rb +325 -0
- metadata +123 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 17e2da8e7bbc0099c4d397ac0ecbc619ce9ba46c
|
4
|
+
data.tar.gz: 7b0350db719f6ba417e65e197032262a4507ce14
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: aa69cb58b0152b7f729cb0a66f66eb737b2b701c5e6dd477f462fe313d18e157801ddd3024cf31582a1e1780005dae396c56539c56476611f28b90780c6453fe
|
7
|
+
data.tar.gz: 6fc1f62ef608d31bff14911771aa19d96f74d7bd741c732503a5f8c2d5c4d3414c29404a839cf9be9cb7443086a95de73dbc9a8e9145028caaff50d4888a4929
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
data/CODE_OF_CONDUCT.md
ADDED
@@ -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
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,584 @@
|
|
1
|
+
# Betterobject
|
2
|
+
|
3
|
+
This gem installs several class methods to Object which in turn generates both class and instance methods but only when you are ready.
|
4
|
+
In order to prevent name pollution, you have the ability to manage the generators to pick alternate names if you prefer.
|
5
|
+
After scouring the RubyGems site, some of the better Class upgrades are included here as well as some of my own.
|
6
|
+
The gem creates the backbone upon which future upgrades should be forthcoming.
|
7
|
+
As a teaser, some of the generators presently include: obj.local_methods, obj.inherited_methods, obj.in?, COBJ.comes_from?, COBJ.derives_from?, COBJ.define_presence_of, obj.find_def. This first release installs 14 generators.
|
8
|
+
Calling `Object.better_install_all` will install all of the generators.
|
9
|
+
You can also generate a subset by calling `Object.better_install :generator_name` or `Object.better_install array_of_gen_names`.
|
10
|
+
The generator names are also the method names which can be renamed by calling `Object.better_rename(old_name, new_name)`;
|
11
|
+
this must be done before you generate the method.
|
12
|
+
|
13
|
+
## Installation
|
14
|
+
|
15
|
+
Add this line to your application's Gemfile:
|
16
|
+
|
17
|
+
```ruby
|
18
|
+
gem 'betterobject'
|
19
|
+
```
|
20
|
+
|
21
|
+
And then execute:
|
22
|
+
|
23
|
+
$ bundle
|
24
|
+
|
25
|
+
Or install it yourself as:
|
26
|
+
|
27
|
+
$ gem install betterobject
|
28
|
+
|
29
|
+
Or as a stand-alone:
|
30
|
+
|
31
|
+
$ require "betterobject"
|
32
|
+
|
33
|
+
## Usage
|
34
|
+
|
35
|
+
The class methods installed on Object must be called before something useful will happen.
|
36
|
+
Somewhere in the installation, you will need to run the generators. If you open `irb`, you can try this:
|
37
|
+
|
38
|
+
```ruby
|
39
|
+
require "betterobject" # load gem
|
40
|
+
|
41
|
+
Object.better_install_all # install all generators
|
42
|
+
5.in? 1..9 # true ...
|
43
|
+
class Fred
|
44
|
+
def a
|
45
|
+
end
|
46
|
+
end
|
47
|
+
fred = Fred.new
|
48
|
+
fred.local_methods # [:a]
|
49
|
+
fred.inherited_methods # [bunch of stuff not including :a]
|
50
|
+
String.derives_from? Comparable # true
|
51
|
+
String.derives_from? String # false
|
52
|
+
String.comes_from? Comparable # true
|
53
|
+
String.comes_from? String # true
|
54
|
+
|
55
|
+
String.define_presence_of :i_am_a_string? # updates Object and String
|
56
|
+
"hello".i_am_a_string? # true
|
57
|
+
1234.i_am_a_string? # false
|
58
|
+
Arrray.define_presence_of(:i_am_not_an_array?, false)
|
59
|
+
[1,2,3].i_am_not_an_array? # false
|
60
|
+
"".i_am_not_an_array? # true
|
61
|
+
```
|
62
|
+
|
63
|
+
You can see the motivation. In the event that one of these generators conflicts with some other method, you can elect to not execute that generator.
|
64
|
+
Or if you really need the functionality, you can rename the generator. First close the `irb` then reopen it, then try this:
|
65
|
+
|
66
|
+
```ruby
|
67
|
+
require "betterobject"
|
68
|
+
|
69
|
+
Object.better_rename(:in?, :in_the_thing_to_the_right?)
|
70
|
+
Object.better_rename(:local_methods, :methods_by_me)
|
71
|
+
Object.better_install [:in_the_thing_to_the_right?, :methods_by_me] # or better_install_all
|
72
|
+
5.in? 1..9 # undefined method ...
|
73
|
+
5.in_the_thing_to_the_right? 1..9 # true
|
74
|
+
"".local_methods # undefined method ...
|
75
|
+
"".methods_by_me # [...]
|
76
|
+
```
|
77
|
+
|
78
|
+
You can control which methods names get generated. Now let's dive into the other class methods of `betterobject`.
|
79
|
+
|
80
|
+
#### Object class methods created from the `betterobject` gem
|
81
|
+
* `Object.better_installed_instance_methods`
|
82
|
+
* `Object.better_installed_class_methods`
|
83
|
+
* `Object.better_installed`
|
84
|
+
* `Object.better_explain`
|
85
|
+
* `Object.better_source_code`
|
86
|
+
* `Object.better_list`
|
87
|
+
* `Object.better_install`
|
88
|
+
* `Object.better_install_all`
|
89
|
+
* `Object.better_uninstall`
|
90
|
+
* `Object.better_uninstall_all`
|
91
|
+
* `Object.better_skip`
|
92
|
+
* `Object.better_unskip`
|
93
|
+
* `Object.better_skipped`
|
94
|
+
* `Object.better_rename`
|
95
|
+
|
96
|
+
|
97
|
+
Note that there are no instance methods created by this gem until you install a generator.
|
98
|
+
Also, each and every method must be called from Object.
|
99
|
+
|
100
|
+
#### Object.better_install_all
|
101
|
+
|
102
|
+
This will install every defined generator. In the event that a generator is renamed, the new name will be generated, while the old name
|
103
|
+
will no longer exist. This is similar to renaming a file. Note that the generator essence never goes away, as it will exist under some new name.
|
104
|
+
It is simply tucked away until needed. Also, generators marked as skipped will not be installed.
|
105
|
+
|
106
|
+
#### Object.better_skip(gen or [gen1, gen2, ...] or gen1, gen2, ...)
|
107
|
+
|
108
|
+
This is to prevent a generator from installing by adding a skip attribute.
|
109
|
+
Additionally, skipped generators cannot be uninstalled until the skip flag is removed.
|
110
|
+
If a generator is first installed then given this skip attribute, it cannot be uninstalled.
|
111
|
+
This acts as a protection.
|
112
|
+
|
113
|
+
#### Object.better_unskip(gen or [gen1, gen2, ...] or gen1, gen2, ...)
|
114
|
+
|
115
|
+
This removes the skip attribute enabling the generator to be installed or uninstalled.
|
116
|
+
|
117
|
+
#### Object.better_skipped
|
118
|
+
|
119
|
+
This returns an array of skipped generators.
|
120
|
+
|
121
|
+
#### Object.better_install(gen or [gen1, gen2, ...] or gen1, gen2, ...)
|
122
|
+
|
123
|
+
This will install a specific generator.
|
124
|
+
If you rename a generator, the old name no longer exists, so you must use the new name. See below:
|
125
|
+
|
126
|
+
```ruby
|
127
|
+
Object.better_rename(:in?, :is_in?)
|
128
|
+
Object.better_install(:in?) # Error
|
129
|
+
Object.better_install(:is_in?) # true
|
130
|
+
Object.better_install(:is_in?) # false ... already installed
|
131
|
+
|
132
|
+
str = "The cat in the hat is back"
|
133
|
+
'cat'.is_in? str # true
|
134
|
+
```
|
135
|
+
|
136
|
+
#### Object.better_uninstall_all
|
137
|
+
|
138
|
+
This will remove all the generators from Object. Note that some generators spawn additional generators such as `:define_presence_of`.
|
139
|
+
If this generator is ever run, `Object.better_uninstall_all` will not remove these second generation methods.
|
140
|
+
Note that generators marked with the skip flag will not be uninstalled.
|
141
|
+
|
142
|
+
#### Object.better_uninstall(gen or [gen1, gen2, ...] or gen1, gen2, ...)
|
143
|
+
|
144
|
+
This will uninstall a specific generator or a set of generators.
|
145
|
+
This method returns false if the generator is skipped, or already uninstalled; otherwise true is returned.
|
146
|
+
If you installed a generator and wish to rename it, you must first uninstall it before you can rename it.
|
147
|
+
See below:
|
148
|
+
|
149
|
+
```ruby
|
150
|
+
Object.better_install :local_methods
|
151
|
+
"a string".local_methods # [list of local methods]
|
152
|
+
Object.better_rename(:local_methods, :methods_by_me) # Error ... installed methods cannot be renamed
|
153
|
+
Object.better_uninstall :local_methods
|
154
|
+
Object.better_rename(:local_methods, :methods_by_me)
|
155
|
+
Object.better_install :methods_by_me
|
156
|
+
"a string".methods_by_me # [list of local methods]
|
157
|
+
```
|
158
|
+
|
159
|
+
#### Object.better_list(include_skip=false)
|
160
|
+
|
161
|
+
This returns an array of generators that can be installed. Skipped generators can also be listed if you call this method with the value `true`.
|
162
|
+
|
163
|
+
#### Object.better_installed
|
164
|
+
|
165
|
+
This returns a list of installed generators. This does not list what the generators generate.
|
166
|
+
|
167
|
+
#### Object.better_installed_instance_methods
|
168
|
+
|
169
|
+
This gives us a list of generators that created instance methods. This does not list what the generators generate.
|
170
|
+
|
171
|
+
#### Object.better_installed_class_methods
|
172
|
+
|
173
|
+
This give us a list of generators that created class methods. This does not list what the generators generate.
|
174
|
+
|
175
|
+
#### Object.better_rename(old_name, new_name)
|
176
|
+
|
177
|
+
This allows us to rename a generator which in turn (most likely) renames what gets generated.
|
178
|
+
This is an important feature as placing methods at the Object level has the danger of bumping into potential name conflicts.
|
179
|
+
See the example below:
|
180
|
+
|
181
|
+
```ruby
|
182
|
+
Object.better_list.each do |old_name|
|
183
|
+
new_name = ("bjc_" + old_name.to_s).to_sym # my initials
|
184
|
+
Object.better_rename(old_name, new_name)
|
185
|
+
end
|
186
|
+
Object.better_install_all
|
187
|
+
sorted_hash = {zoo:"animals", banana:"fruit"}.bjc_sort! # == {banana:"fruit", zoo:"animals"}
|
188
|
+
sorted_hash.bjc_tag? # false
|
189
|
+
sorted_hash.bjc_tag!
|
190
|
+
sorted_hash.bjc_tag? # true
|
191
|
+
:zoo.bjc_in? hash # true
|
192
|
+
```
|
193
|
+
|
194
|
+
#### Object.better_explain(:generator_name, pts=true)
|
195
|
+
|
196
|
+
Calling this method without a generator name gives us a general list of the generators.
|
197
|
+
Further details are revealed when a generator name is provided. The last default parameter puts the string to STOUT when true; otherwise,
|
198
|
+
a string is returned.
|
199
|
+
See example below:
|
200
|
+
|
201
|
+
```ruby
|
202
|
+
Object.better_explain(:in?) # obj.in?(enum) # ex: 3.in? [3,4,5] == true
|
203
|
+
```
|
204
|
+
|
205
|
+
#### Object.better_source_code(:generator_name, return_string = false, inner_only = false, type=:code)
|
206
|
+
|
207
|
+
This will revel the source code for the generator. You can then copy and paste this in `irb` and experiment with it. See below:
|
208
|
+
|
209
|
+
```ruby
|
210
|
+
Object.better_source_code(:in?)
|
211
|
+
|
212
|
+
class Object
|
213
|
+
def in?(enum)
|
214
|
+
enum.include? self
|
215
|
+
end
|
216
|
+
end
|
217
|
+
```
|
218
|
+
|
219
|
+
The parameter `return_string` will return a string instance when set true.
|
220
|
+
The parameter `inner_only` when set true will remove the `class Object` and enclosing `end` statements.
|
221
|
+
The final parameter is set to either `:code` or `:rm` depending on if you need the creation code or the deletion code.
|
222
|
+
|
223
|
+
#### Object.better_define(meth_name, code, type, doc="*Undocumented*", rm_code=nil)
|
224
|
+
|
225
|
+
This installs a user-defined generator. As an example we will create a `whotheheckami` generator as follows.
|
226
|
+
```ruby
|
227
|
+
doc = "same as .class"
|
228
|
+
type = :both # declares that :class and :instance will both be present
|
229
|
+
meth_name = :whotheheckami
|
230
|
+
code = "
|
231
|
+
def self.BO_METH_NAME
|
232
|
+
self.class
|
233
|
+
end
|
234
|
+
def BO_METH_NAME
|
235
|
+
self.class
|
236
|
+
end
|
237
|
+
"
|
238
|
+
Object.better_define(meth_name, code, type, doc)
|
239
|
+
Object.better_list.include? :whotheheckami # true
|
240
|
+
Object.better_install :whotheheckami
|
241
|
+
"".whotheheckami # String
|
242
|
+
String.whotheheckami # Class
|
243
|
+
```
|
244
|
+
|
245
|
+
Note that we used the identifier name `BO_METH_NAME` instead of `whotheheckami`.
|
246
|
+
This allows our generator to be renamed.
|
247
|
+
Generally speaking, the generator name need not be coupled with the method name, but that is the convention.
|
248
|
+
Also, you can target a foreign object if you wish.
|
249
|
+
The following example demonstrates updating String and also decouples the rename associations.
|
250
|
+
|
251
|
+
```ruby
|
252
|
+
doc = "some cool string methods"
|
253
|
+
type = :instance
|
254
|
+
meth_name = :string_methods
|
255
|
+
code = "
|
256
|
+
String.class_eval do
|
257
|
+
def sort
|
258
|
+
self.split('').sort.join('')
|
259
|
+
end
|
260
|
+
def sort!
|
261
|
+
replace self.split('').sort.join('')
|
262
|
+
end
|
263
|
+
def histogram
|
264
|
+
hash = {}
|
265
|
+
self.split('').sort.each do |ch|
|
266
|
+
hash[ch] = hash[ch].nil? ? 1 : 1 + hash[ch]
|
267
|
+
end
|
268
|
+
return hash
|
269
|
+
end
|
270
|
+
end
|
271
|
+
"
|
272
|
+
rm_code = "
|
273
|
+
String.class_eval do
|
274
|
+
undef sort
|
275
|
+
undef sort!
|
276
|
+
undef histogram
|
277
|
+
end
|
278
|
+
"
|
279
|
+
Object.better_define(meth_name, code, type, doc, rm_code)
|
280
|
+
Object.better_list.include? :string_methods # true
|
281
|
+
Object.better_install :string_methods
|
282
|
+
"".string_methods # Error
|
283
|
+
"everybody".sort # "bdeeorvyy"
|
284
|
+
```
|
285
|
+
|
286
|
+
In this case if you rename `:string_methods` you will only rename the generator.
|
287
|
+
This method was used as a tool to create some of the generators.
|
288
|
+
Note that if you decouple the method name from the generator name, or target a foreign object,
|
289
|
+
you must provide code to remove your methods.
|
290
|
+
|
291
|
+
#### Generator list
|
292
|
+
* `:local_methods`
|
293
|
+
* `:inherited_methods`
|
294
|
+
* `:replaced_methods`
|
295
|
+
* `:derives_from?`
|
296
|
+
* `:comes_from?`
|
297
|
+
* `:define_presence_of`
|
298
|
+
* `:in?`
|
299
|
+
* `:to_literal`
|
300
|
+
* `:pluralize`
|
301
|
+
* `:parent`
|
302
|
+
* `:sort!`
|
303
|
+
* `:find_def`
|
304
|
+
* `:tag`
|
305
|
+
* `:functionize`
|
306
|
+
|
307
|
+
|
308
|
+
#### Generator :local_methods(include_singleton_methods=true)
|
309
|
+
|
310
|
+
This is an instance generator on Object. It is used on all objects that derive from Object (which is pretty much everything).
|
311
|
+
The purpose is to view methods generated by the class of the instance and not the methods inherited by that class.
|
312
|
+
This reduces the clutter considerably while introspecting the methods. See the example below:
|
313
|
+
|
314
|
+
```ruby
|
315
|
+
Object.better_install :local_methods # run the generator
|
316
|
+
|
317
|
+
class Fred < String
|
318
|
+
def a
|
319
|
+
end
|
320
|
+
def b
|
321
|
+
end
|
322
|
+
end
|
323
|
+
|
324
|
+
fred = Fred.new
|
325
|
+
def fred.c; end
|
326
|
+
fred.singleton_methods # [:c]
|
327
|
+
fred.local_methods # [:a, :b, :c]
|
328
|
+
fred.local_methods(false) #[:a, :b]
|
329
|
+
fred.methods # [:a, :b, :dup, :clone, etc ...]
|
330
|
+
```
|
331
|
+
|
332
|
+
#### Generator :inherited_methods
|
333
|
+
|
334
|
+
This is an instance generator on Object. It is similar to `#methods`, except all locally defined methods are excluded.
|
335
|
+
The combination of `#local_methods` and `#inherited_methods` is the same as `#methods`. See below:
|
336
|
+
|
337
|
+
```ruby
|
338
|
+
Object.better_install [:local_methods, :inherited_methods]
|
339
|
+
|
340
|
+
class Fred < String
|
341
|
+
def a
|
342
|
+
end
|
343
|
+
def b
|
344
|
+
end
|
345
|
+
end
|
346
|
+
|
347
|
+
fred = Fred.new
|
348
|
+
fred.methods.sort == [fred.local_methods + fred.inherited_methods].sort # true
|
349
|
+
```
|
350
|
+
|
351
|
+
#### Generator :replaced_methods
|
352
|
+
|
353
|
+
This is an instance generator on Object. This lets us discover which methods have been replaced during inheritance, or replaced due to a singleton method using the same name as an instance method. See the example below:
|
354
|
+
|
355
|
+
```ruby
|
356
|
+
Object.better_install :replaced_methods
|
357
|
+
|
358
|
+
class Fred < String
|
359
|
+
def length
|
360
|
+
end
|
361
|
+
end
|
362
|
+
|
363
|
+
fred = Fred.new
|
364
|
+
def fred.to_s
|
365
|
+
end
|
366
|
+
|
367
|
+
fred.replaced_methods # [:length, :to_s]
|
368
|
+
```
|
369
|
+
|
370
|
+
#### Generators :derives_from? and :comes_from?
|
371
|
+
|
372
|
+
These methods are both class methods on Object. The purpose is to test hierarchy of derived objects.
|
373
|
+
The two class methods once generated are identical except `comes_from?` is more inclusive.
|
374
|
+
See the example below:
|
375
|
+
|
376
|
+
```ruby
|
377
|
+
Object.better_install :derives_from?, :comes_from?
|
378
|
+
|
379
|
+
class Fred < String
|
380
|
+
def a
|
381
|
+
end
|
382
|
+
def b
|
383
|
+
end
|
384
|
+
end
|
385
|
+
|
386
|
+
Fred.derives_from? String # true
|
387
|
+
Fred.derives_from? Fred # false
|
388
|
+
Fred.derives_from? Object # true
|
389
|
+
Fred.comes_from? Fred # true
|
390
|
+
Fred.comes_from? String # true
|
391
|
+
Fred.comes_from? Object # true
|
392
|
+
```
|
393
|
+
|
394
|
+
#### Generators :define_presence_of(:target_method_name, target_default_value = true)
|
395
|
+
|
396
|
+
This generator generates a generator!
|
397
|
+
When installed, a class method is created on Object called `#define_presence_of`.
|
398
|
+
This is called from a derived class such as String or Integer.
|
399
|
+
The intent is to create a test for a certain type.
|
400
|
+
This is a short-hand way of using the `#kind_of(CLASS_NAME)` method.
|
401
|
+
See the example below:
|
402
|
+
|
403
|
+
```ruby
|
404
|
+
|
405
|
+
t1 = "fred"
|
406
|
+
t2 = 123
|
407
|
+
t1.kind_of? String # true ... old way of doing things
|
408
|
+
t2.kind_of? String # false
|
409
|
+
|
410
|
+
Object.better_install :define_presence_of
|
411
|
+
|
412
|
+
String.define_presence_of(:string?)
|
413
|
+
String.define_presence_of(:not_string?, false)
|
414
|
+
Integer.define_presence_of(:int?, true)
|
415
|
+
Integer.define_presence_of(:not_int?, false)
|
416
|
+
|
417
|
+
t1.string? # true
|
418
|
+
t2.not_string? # true
|
419
|
+
t1.int? # false
|
420
|
+
t2.int? # true
|
421
|
+
[4].int? # false ... it is an array
|
422
|
+
```
|
423
|
+
|
424
|
+
As we can see from the above code, we now have a shorter way of doing type checking.
|
425
|
+
The generated generator defines an instance method on Object as well as the descendant class that calls it.
|
426
|
+
Each method returns an opposite result.
|
427
|
+
There are several base class gems (not mine) that force a certain naming convention; this one let's you pick the name!
|
428
|
+
|
429
|
+
#### Generators :in?
|
430
|
+
|
431
|
+
This generator allows us to swap the order of the standard `#include?` method with an improved comprehensive ordering.
|
432
|
+
I saw this in another gem called ("object-in" by Tim Rogers), so I give him credit for the idea. It is included here because
|
433
|
+
it is cool. This is probably the best name, but others (which you could rename to) could be: `:member_of`, `:is_in?`, `:in`, or `:element_of`.
|
434
|
+
See the example below:
|
435
|
+
|
436
|
+
```ruby
|
437
|
+
|
438
|
+
[1,2,3].include? 2 # true ... old way of doing things
|
439
|
+
|
440
|
+
Object.better_install :in?
|
441
|
+
|
442
|
+
2.in? [1,2,3] # true
|
443
|
+
'i'.in? "team" # false
|
444
|
+
```
|
445
|
+
|
446
|
+
#### Generators :pluralize(meth_name, alt=nil)
|
447
|
+
|
448
|
+
This generator installs a generator that mimics another method using a pluralized name.
|
449
|
+
One of my pet peves is poorly named methods that are grammatically incorrect.
|
450
|
+
From the String class, the method named `#start_with` should have been named `#starts_with`.
|
451
|
+
This class method can be called from Object, String, or any class you wish.
|
452
|
+
The pluralization is pretty smart, but if it does not quite work, you can provide the altername name in the second parameter. The new method name is returned. See the example below
|
453
|
+
|
454
|
+
```ruby
|
455
|
+
|
456
|
+
Object.better_install :pluralize # installs the first-level generator
|
457
|
+
Object.pluralize :include? # returns :includes?
|
458
|
+
[1,2,3].includes? 2 # true
|
459
|
+
|
460
|
+
String.pluralize :start_with? # returns :starts_with?
|
461
|
+
"whatever".starts_with? "wh" # true
|
462
|
+
|
463
|
+
Object.pluralize :respond_to? # :responds_to?
|
464
|
+
17.responds_to? :to_s # true
|
465
|
+
```
|
466
|
+
|
467
|
+
#### Generators :parent
|
468
|
+
|
469
|
+
This generator finds the first non-module ancestor of a class.
|
470
|
+
The class Object's parent is always Object.
|
471
|
+
This is a class method installed on Object.
|
472
|
+
|
473
|
+
#### Generators :to_literal
|
474
|
+
|
475
|
+
This is an alias for `#inspect`. In the event inspect fails, `#to_s` is then called.
|
476
|
+
|
477
|
+
#### Generators :tag
|
478
|
+
|
479
|
+
This generator creates a family of instance methods. If unrenamed, you will get: `#tag`, `#tag!`, `#untag`, `#tag?` and `#tag=`.
|
480
|
+
If you rename this generator to :fred, you will get these: `#fred`, `#fred!`, `#unfred`, `#fred?`, `#fred=`.
|
481
|
+
Note that uninstall will remove all five methods even if renamed.
|
482
|
+
This method attaches a property to an instance of an Object or a derivative object.
|
483
|
+
Note that objects that have no constructors such as Integer, Float, NilClass, TrueClass, FalseClass and Symbol cannot be tagged.
|
484
|
+
Also, frozen object instances cannot be tagged.
|
485
|
+
You will need to place such objects either in a wrapper class or a use a container such as Array.
|
486
|
+
A good container system is the gem `primitive_wrapper`.
|
487
|
+
See the example below:
|
488
|
+
|
489
|
+
```ruby
|
490
|
+
Object.better_install :tag
|
491
|
+
|
492
|
+
#tag get current tag value
|
493
|
+
#tag=(val) set tag's value to `val`
|
494
|
+
#tag! set tag's value to true ... same as #tag=true
|
495
|
+
#tag? returns true if tag's value is anything but nil, or false
|
496
|
+
#untag set tag's value to false ... same as #tag=false
|
497
|
+
|
498
|
+
var1 = "Something to remember"
|
499
|
+
var1.tag? # false
|
500
|
+
var1.tag # nil
|
501
|
+
var1.tag! # true
|
502
|
+
var1.tag # true
|
503
|
+
var1.tag? # true
|
504
|
+
var1.untag # false
|
505
|
+
var1.tag? # false
|
506
|
+
var1.tag= "don't forget me!"
|
507
|
+
var1.tag? # true
|
508
|
+
var1.tag # "don't forget me!"
|
509
|
+
var1.untag # false
|
510
|
+
var1.tag? # false
|
511
|
+
var1.tag # false
|
512
|
+
```
|
513
|
+
|
514
|
+
#### Generators :sort!
|
515
|
+
|
516
|
+
This method targets only the Hash class and creates the `#sort!` method.
|
517
|
+
Hash has a method `#sort` that returns a sorted array of key value pairs.
|
518
|
+
Obviously, they omitted the self modifying version because `Arrays` are not `Hashes`.
|
519
|
+
See the example below:
|
520
|
+
|
521
|
+
```ruby
|
522
|
+
hash = {:zoo=>"Animals", :fruit=>"Banana", :better=>"Object"}
|
523
|
+
hash.keys # [:zoo, :fruit, :better]
|
524
|
+
Object.better_install :sort!
|
525
|
+
Hash.respond_to? :sort! # true
|
526
|
+
hash.sort!
|
527
|
+
Hash.keys # [:better, :fruit, :zoo]
|
528
|
+
```
|
529
|
+
|
530
|
+
#### Generators :find_def
|
531
|
+
|
532
|
+
This method locates the owner of either an instance method or a class method.
|
533
|
+
The method expects a symbol representation of the method.
|
534
|
+
The value `nil` is returned in the event that the method is undefined.
|
535
|
+
See the example below:
|
536
|
+
|
537
|
+
```ruby
|
538
|
+
Object.better_install :find_def
|
539
|
+
tst = "".find_def :< # tst = Comparable
|
540
|
+
tst = 7.find_def :< # tst = Fixnum
|
541
|
+
tst = 7.find_def :to_int # tst = Integer
|
542
|
+
tst = 7.find_def :to_c # tst = Numeric
|
543
|
+
tst = Fixnum.find_def :to_s # tst = Module
|
544
|
+
tst = Fixnum.find_def :new # tst = nil
|
545
|
+
tst = "nope".find_def :foo # tst = nil
|
546
|
+
```
|
547
|
+
|
548
|
+
#### Generators :functionize(meth = :new)
|
549
|
+
|
550
|
+
This method makes your class look like a method that you simply call on the class constant.
|
551
|
+
If you examine the `Rational` class, there is no `#new` constructor at all.
|
552
|
+
Instead, you call `Rational(2,3)` which creates the object.
|
553
|
+
On your own class object, the default will call `#new` adding shorter syntax candy.
|
554
|
+
This allows less typing to create the object.
|
555
|
+
You can also provide any class method you wish, but because you only get one, probably best if it were a constructor.
|
556
|
+
See the example below:
|
557
|
+
|
558
|
+
```ruby
|
559
|
+
Object.better_install :functionize
|
560
|
+
class Clown
|
561
|
+
def initialize(prm1, prm2)
|
562
|
+
@prms = [prm1, prm2]
|
563
|
+
end
|
564
|
+
end
|
565
|
+
|
566
|
+
Clown.functionize
|
567
|
+
obj1 = Clown(:one, :two) # fast way
|
568
|
+
obj2 = Clown.new(:three, :four) # slow way
|
569
|
+
```
|
570
|
+
|
571
|
+
## Development
|
572
|
+
|
573
|
+
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.
|
574
|
+
|
575
|
+
To install this gem onto your local machine, run `bundle exec rake install`.
|
576
|
+
|
577
|
+
## Contributing
|
578
|
+
|
579
|
+
I need to control this for the time being.
|
580
|
+
|
581
|
+
## License
|
582
|
+
|
583
|
+
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
584
|
+
|