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.
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
@@ -0,0 +1,36 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'betterobject/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "betterobject"
8
+ spec.version = Betterobject::VERSION
9
+ spec.authors = ["Bryan Colvin"]
10
+ spec.email = ["bryan@bdlsys.com"]
11
+
12
+ spec.summary = %q{Object method generator system}
13
+ spec.description = %q{This gem installs several class methods to Object which in turn generates both class and instance methods but only when you are ready.
14
+ In order to prevent name pollution, you have the ability to manage the generators to pick alternate names if you prefer.
15
+ After scouring the RubyGems site, some of the better Class upgrades are included here as well as some of my own.
16
+ The gem creates the backbone upon which future upgrades should be forthcoming.
17
+ 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.
18
+ Calling `Object.better_install_all` will install all of the generators.
19
+ You can also generate a subset by calling `Object.better_install :generator_name` or `Object.better_install array_of_gen_names`.
20
+ The generator names are also the method names which can be renamed by calling `Object.better_rename(old_name, new_name)`;
21
+ this must be done before you generate the method.}
22
+
23
+ spec.license = "MIT"
24
+
25
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
26
+ spec.files.push "lib/generators.rb"
27
+
28
+ spec.bindir = "exe"
29
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
30
+ spec.require_paths = ["lib"]
31
+
32
+ spec.add_development_dependency "bundler", "~> 1.11"
33
+ spec.add_development_dependency "rake", "~> 10.0"
34
+ spec.add_development_dependency "rspec", "~> 3.0"
35
+ spec.add_development_dependency 'byebug', ">= 5.0.0"
36
+ end
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "betterobject"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,3 @@
1
+ module Betterobject
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,246 @@
1
+ require "betterobject/version"
2
+
3
+ unless require "generators.rb"
4
+ require_relative "generators.rb"
5
+ end
6
+
7
+ class Object
8
+ ###
9
+ ### The following are standard class methods
10
+ ###
11
+
12
+ def self.better_be_object
13
+ raise "must call from Object" unless self==Object
14
+ end
15
+
16
+ def self.better_be_defined(sym)
17
+ raise "unknown generator #{sym.inspect}" unless @@better_object_valid_methods.include? sym
18
+ end
19
+
20
+ def better_list(include_skip=false)
21
+ better_be_object
22
+ rtn = []
23
+ # @@better_object_valid_methods.keys.sort
24
+ @@better_object_valid_methods.each_pair do |key,rec|
25
+ rtn.push key unless rec[:skip]
26
+ end
27
+ return rtn.sort
28
+ end
29
+
30
+ def self.better_skip(*sym)
31
+ if sym.first.class == Array
32
+ sym = sym.first
33
+ sym.each { |m| better_skip m }
34
+ return true
35
+ else
36
+ if sym.count==1
37
+ sym = sym.first
38
+ else
39
+ sym.each { |m| better_skip m }
40
+ return true
41
+ end
42
+ end
43
+ better_be_object
44
+ raise "unknown generator #{sym.inspect}" unless @@better_object_valid_methods.include? sym
45
+ @@better_object_valid_methods[sym][:skip]=true
46
+ end
47
+
48
+ def self.better_unskip(*sym)
49
+ if sym.first.class == Array
50
+ sym = sym.first
51
+ sym.each { |m| better_unskip m }
52
+ return true
53
+ else
54
+ sym = sym.first
55
+ end
56
+ better_be_object
57
+ better_be_defined(sym)
58
+ @@better_object_valid_methods[sym][:skip]=false
59
+ end
60
+
61
+ def self.better_skipped()
62
+ better_be_object
63
+ rtn = []
64
+ @@better_object_valid_methods.each_pair do |key,val|
65
+ if val[:skip]
66
+ rtn.push key
67
+ end
68
+ end
69
+ return rtn.sort
70
+ end
71
+
72
+ def self.better_source_code(sym, return_string=false, inner_only = false, kind = :code)
73
+ better_be_object
74
+ better_be_defined(sym)
75
+ raise "expecting (:code, :rm) 4th parameter and got #{kind.inspect}" unless (kind==:code || kind==:rm)
76
+ return nil unless @@better_object_valid_methods[sym][kind]
77
+ str = "\n"
78
+ str += "class Object\n" unless inner_only
79
+ str += @@better_object_valid_methods[sym][kind]
80
+ str += "\n" unless str[-1]=="\n"
81
+ str += "end\n" unless inner_only
82
+ str = str.gsub(/BO_METH_NAME/,sym.to_s)
83
+ return str if return_string
84
+ puts str
85
+ sym
86
+ end
87
+
88
+ def self.better_explain(sym=nil, pts=true)
89
+ better_be_object
90
+ if @@better_object_valid_methods.include? sym
91
+ str = @@better_object_valid_methods[sym][:explain]
92
+ else
93
+ if sym.nil?
94
+ str = "valid parameters to the method are:\n:"
95
+ meths = better_list.join ", :"
96
+ str += meths.to_s
97
+ str += "\n\nUsage:\n\nObject.better_explain(:one_of_the_above)\n"
98
+ else
99
+ str = "Undefined parameter #{sym.inspect}"
100
+ end
101
+ end
102
+ return str unless pts
103
+ puts str
104
+ sym
105
+ end
106
+
107
+ def self.better_installed
108
+ better_be_object
109
+ @@better_installed_methods.keys.sort
110
+ end
111
+
112
+
113
+ def self.better_installed_class_methods
114
+ better_be_object
115
+ rtn = []
116
+ @@better_installed_methods.keys.each do |key|
117
+ rtn.push key if @@better_object_valid_methods[key][:type]==:class
118
+ rtn.push key if @@better_object_valid_methods[key][:type]==:both
119
+ end
120
+ return rtn.sort
121
+ end
122
+
123
+ def self.better_installed_instance_methods
124
+ better_be_object
125
+ rtn = []
126
+ @@better_installed_methods.keys.each do |key|
127
+ rtn.push key if @@better_object_valid_methods[key][:type]==:instance
128
+ rtn.push key if @@better_object_valid_methods[key][:type]==:both
129
+ end
130
+ return rtn.sort
131
+ end
132
+
133
+ def self.better_uninstall_all
134
+ @@better_installed_methods.keys.each {|m| better_uninstall m}
135
+ end
136
+
137
+ def self.better_uninstall(*sym)
138
+ if sym.first.class == Array
139
+ sym = sym.first
140
+ sym.each { |m| better_uninstall m }
141
+ return true
142
+ else
143
+ if sym.count==1
144
+ sym = sym.first
145
+ else
146
+ sym.each { |m| better_uninstall m }
147
+ return true
148
+ end
149
+ end
150
+ better_be_object
151
+ better_be_defined(sym)
152
+ return false unless @@better_installed_methods.include? sym
153
+ return false if @@better_object_valid_methods[sym][:skip]
154
+ obj = @@better_object_valid_methods[sym]
155
+ if obj[:rm]
156
+ code = obj[:rm].gsub(/BO_METH_NAME/,sym.to_s)
157
+ class_eval code
158
+ @@better_installed_methods.delete sym
159
+ return true
160
+ end
161
+ cmd = "undef #{sym}"
162
+ tp = obj[:type]
163
+ if tp==:instance || tp==:both
164
+ eval cmd rescue :never_mind # don't care if already undefined
165
+ end
166
+ if tp==:class || tp==:both
167
+ # This loses the local variable `cmd`
168
+ # class << self
169
+ # eval cmd
170
+ # end
171
+ # this sould do the trick ...
172
+ singleton_class.class_eval do
173
+ eval cmd rescue :never_mind # don't care if already undefined
174
+ end
175
+ end
176
+ @@better_installed_methods.delete sym
177
+ true
178
+ end
179
+
180
+ def self.better_define(meth_name, code, type, doc="*Undocumented*", rm=nil)
181
+ better_be_object
182
+ hash = {}
183
+ hash[:code] = code
184
+ hash[:explain] = doc
185
+ hash[:type] = type
186
+ hash[:rm] = rm unless rm.nil?
187
+ @@better_object_valid_methods[meth_name] = hash
188
+ end
189
+
190
+ def self.better_install_all
191
+ @@better_object_valid_methods.keys.each {|m| better_install m}
192
+ end
193
+
194
+ def self.better_get_definition(sym) # redo this with hash= way
195
+ better_be_object
196
+ better_be_defined(sym)
197
+ rec = @@better_object_valid_methods[sym]
198
+ puts " { :type => :" + rec[:type].to_s + ","
199
+ puts " :explain => " + '"' + rec[:explain] + '",'
200
+ puts " :code =>"
201
+ puts "<<'CODE'"
202
+ term = rec[:rm].nil? ? "" : ","
203
+ puts rec[:code]
204
+ puts "CODE" + term
205
+ unless rec[:rm].nil?
206
+ puts " :rm =>"
207
+ puts "<<'CODE'"
208
+ puts rec[:rm]
209
+ puts "CODE"
210
+ end
211
+ puts "}"
212
+ end
213
+
214
+ def self.better_install(*sym)
215
+ if sym.first.class == Array
216
+ sym = sym.first
217
+ sym.each { |m| better_install m }
218
+ return true
219
+ else
220
+ if sym.count==1
221
+ sym = sym.first
222
+ else
223
+ sym.each { |m| better_install m }
224
+ return true # todo ... they may all be false ...
225
+ end
226
+ end
227
+ better_be_object
228
+ better_be_defined(sym)
229
+ return false if @@better_installed_methods.include? sym
230
+ return false if @@better_object_valid_methods[sym][:skip]
231
+ @@better_installed_methods[sym]=true
232
+ code = @@better_object_valid_methods[sym][:code].gsub(/BO_METH_NAME/,sym.to_s)
233
+ class_eval code
234
+ true
235
+ end
236
+
237
+ def self.better_rename(old_sym, new_sym)
238
+ better_be_object
239
+ better_be_defined(old_sym)
240
+ raise "cannot rename installed generator" if @@better_installed_methods.keys.include? old_sym
241
+ rec = @@better_object_valid_methods[old_sym]
242
+ @@better_object_valid_methods[new_sym] = rec
243
+ @@better_object_valid_methods.delete old_sym
244
+ end
245
+
246
+ end
data/lib/generators.rb ADDED
@@ -0,0 +1,325 @@
1
+ #
2
+ # These are the rather ugly looking generators separated from the main code for clarity
3
+ #
4
+
5
+
6
+ # ::TODO::
7
+ # String.find_method(:new) [:new, Class] or [] if none found
8
+ # "".find_method(:to_s) # finds instance methods or signleton [:to_s, Comparable] [:wow, Singleton]
9
+ #
10
+ # String.local_methods might also be cool!
11
+ # String.inherited_methods as well
12
+ #
13
+ #
14
+ #
15
+
16
+ class Object
17
+ @@better_installed_methods={}
18
+ @@better_object_valid_methods={}
19
+
20
+
21
+ #
22
+ # Generator :find_def
23
+ #
24
+ hash = {}
25
+ hash[:type] = :both
26
+ hash[:explain] = "CLASS_NAME.find_def # locates owner (class name) of defined instance method"
27
+ hash[:code] = "
28
+ def self.BO_METH_NAME(sym)
29
+ return method(sym).owner rescue nil
30
+ end
31
+ def BO_METH_NAME(sym)
32
+ return method(sym).owner rescue nil
33
+ end
34
+ " # does not seem to like the <<'CODE' thing ... not sure why ... works everywhere else
35
+ # so use the "" thing instead
36
+ @@better_object_valid_methods[:find_def] = hash
37
+
38
+
39
+ #
40
+ # Generator :replaced_methods
41
+ #
42
+ hash = {}
43
+ hash[:type] = :instance
44
+ hash[:explain] = "obj.replaced_methods() # similar to methods but only lists methods replaced by inheritance or overridden by singletons"
45
+ hash[:code] = <<'CODE'
46
+ def BO_METH_NAME
47
+ locals = []
48
+ sc = self.class
49
+ methods.each do |item|
50
+ locals.push item if method(item).owner == sc
51
+ end
52
+ outs = []
53
+ singles = singleton_methods
54
+ chain = self.class.ancestors[1..-1]
55
+ chain.each do |item|
56
+ outs += item.instance_methods
57
+ end
58
+ outs_and_locals = outs & locals
59
+ locals_and_singles = locals & singles
60
+ singles_and_outs = outs & singles
61
+ return (outs_and_locals | locals_and_singles | singles_and_outs).sort
62
+ end
63
+ CODE
64
+ @@better_object_valid_methods[:replaced_methods] = hash
65
+
66
+
67
+ #
68
+ # Generator :local_methods
69
+ #
70
+ hash = {}
71
+ hash[:type] = :instance
72
+ hash[:explain] = "obj.inherited_methods() # similar to methods but excludes locally defined methods"
73
+ hash[:code] = <<'CODE'
74
+ def BO_METH_NAME(include_singles=true)
75
+ rtn = []
76
+ sc = self.class
77
+ methods.each do |item|
78
+ rtn.push item if method(item).owner == sc
79
+ end
80
+ rtn += singleton_methods if include_singles
81
+ return rtn.sort
82
+ end
83
+ CODE
84
+ @@better_object_valid_methods[:local_methods] = hash
85
+
86
+
87
+ #
88
+ # Generator :inherited_methods
89
+ #
90
+ hash = {}
91
+ hash[:type] = :instance
92
+ hash[:explain] = "obj.inherited_methods() # similar to methods but excludes locally defined methods"
93
+ hash[:code] = <<'CODE'
94
+ def BO_METH_NAME
95
+ rtn = []
96
+ sc = self.class
97
+ methods.each do |item|
98
+ rtn.push item unless method(item).owner == sc
99
+ end
100
+ rtn -= singleton_methods
101
+ return rtn.sort
102
+ end
103
+ CODE
104
+ @@better_object_valid_methods[:inherited_methods] = hash
105
+
106
+
107
+ #
108
+ # Generator :comes_from?
109
+ #
110
+ hash = {}
111
+ hash[:type] = :class
112
+ hash[:explain] = "CLASS_NAME.comes_from?(Other) # true if CLASS_NAME is or derives from Other"
113
+ hash[:code] = <<'CODE'
114
+ def self.BO_METH_NAME(const)
115
+ ary = ancestors
116
+ rtn = ary.include? const
117
+ return rtn
118
+ end
119
+ CODE
120
+ @@better_object_valid_methods[:comes_from? ] = hash
121
+
122
+
123
+ #
124
+ # Generator :derives_from?
125
+ #
126
+ hash = {}
127
+ hash[:type] = :class
128
+ hash[:explain] = "CLASS_NAME.derives_from?(Other) # true if CLASS_NAME derives from Other"
129
+ hash[:code] = <<'CODE'
130
+ def self.BO_METH_NAME(const)
131
+ ary = ancestors - [self]
132
+ rtn = ary.include? const
133
+ return rtn
134
+ end
135
+ CODE
136
+ @@better_object_valid_methods[:derives_from? ] = hash
137
+
138
+
139
+ #
140
+ # Generator :in?
141
+ #
142
+ hash = {}
143
+ hash[:type] = :instance
144
+ hash[:explain] = "obj.in?(enum) # ex: 3.in? [3,4,5] == true"
145
+ hash[:code] = <<'CODE'
146
+ def BO_METH_NAME(enum)
147
+ enum.include? self
148
+ end
149
+ CODE
150
+ @@better_object_valid_methods[:in? ] = hash
151
+
152
+
153
+ #
154
+ # Generator :define_presence_of
155
+ #
156
+ hash = {}
157
+ hash[:type] = :class
158
+ hash[:explain] = "CLASS_NAME.define_presence_of(:meth_name, val=true)\n # ex: String.define_presence_of :is_string?\n ''.is_string? # true"
159
+ hash[:code] = <<'CODE'
160
+ def self.BO_METH_NAME(method_name, value=true)
161
+ Object.class_eval do
162
+ define_method(method_name) do
163
+ return !value
164
+ end
165
+ end
166
+ class_eval do
167
+ define_method(method_name) do
168
+ return value
169
+ end
170
+ end
171
+ end # def
172
+ CODE
173
+ @@better_object_valid_methods[:define_presence_of] = hash
174
+
175
+
176
+ #
177
+ # Generator :sort!
178
+ #
179
+ hash = {}
180
+ hash[:type] = :instance
181
+ hash[:explain] = "hash_instance.sort! # forces Hash keys to be sorted in ascending order"
182
+ hash[:code] = <<'CODE'
183
+ Hash.class_eval do
184
+ def BO_METH_NAME
185
+ hash = {}
186
+ sort.each do |pair|
187
+ hash[pair.first]=pair.last
188
+ end
189
+ replace hash
190
+ end
191
+ end
192
+ CODE
193
+ hash[:rm] = <<'CODE'
194
+ Hash.class_eval do
195
+ undef BO_METH_NAME rescue :never_mind
196
+ end
197
+ CODE
198
+ @@better_object_valid_methods[:sort!] = hash
199
+
200
+
201
+ #
202
+ # Generator :to_literal
203
+ #
204
+ hash = {}
205
+ hash[:type] = :instance
206
+ hash[:explain] = "obj.to_literal # alias for #inspect"
207
+ hash[:code] = <<'CODE'
208
+ def BO_METH_NAME
209
+ if respond_to? :inspect
210
+ inspect
211
+ else
212
+ to_s
213
+ end
214
+ end
215
+ CODE
216
+ @@better_object_valid_methods[:to_literal] = hash
217
+
218
+
219
+ #
220
+ # Generator :pluralize
221
+ #
222
+ hash = {}
223
+ hash[:type] = :class
224
+ hash[:explain] = "adds plural versions of include, respond_to?, start_with, etc"
225
+ hash[:code] = <<'CODE'
226
+ def self.BO_METH_NAME(prm, alt=nil)
227
+ unless self==Object
228
+ raise "unknown method #{prm.to_sym}" unless instance_methods.include?(prm)
229
+ end
230
+ if alt.nil?
231
+ sprm = prm.to_s
232
+ if (sprm.include? '_')
233
+ ary = sprm.split('_')
234
+ ary[0] += 's'
235
+ ps = ary.join "_"
236
+ else
237
+ if sprm[-1]=='?'
238
+ ps = sprm[0..(-2)] + 's?'
239
+ elsif sprm[-1]=='!'
240
+ ps = sprm[0..(-2)] + 's!'
241
+ else
242
+ ps = sprm + 's'
243
+ end
244
+ end
245
+ else
246
+ ps = alt
247
+ end
248
+ cmd = "def #{ps}(*prms)\n#{sprm}(*prms)\nend"
249
+ class_eval cmd
250
+ ps
251
+ end
252
+ CODE
253
+ @@better_object_valid_methods[:pluralize] = hash
254
+
255
+
256
+ #
257
+ # Generator :parent
258
+ #
259
+ hash = {}
260
+ hash[:type] = :class
261
+ hash[:explain] = "finds the parent class not including modules"
262
+ hash[:code] = <<'CODE'
263
+ def self.BO_METH_NAME
264
+ return Object if self==Object
265
+ ary = ancestors
266
+ ary[1..(-1)].each do |name|
267
+ next if name.class == Module
268
+ return Object if name==Object
269
+ return name
270
+ end
271
+ end
272
+ CODE
273
+ @@better_object_valid_methods[:parent] = hash
274
+
275
+
276
+ #
277
+ # Generator :tag
278
+ #
279
+ hash = {}
280
+ hash[:type] = :instance
281
+ hash[:explain] = "creates :tag, :tag=, :tag?, untag ..."
282
+ hash[:code] = <<'CODE'
283
+ def BO_METH_NAME
284
+ nil || @bo_BO_METH_NAME
285
+ end
286
+ def BO_METH_NAME!
287
+ @bo_BO_METH_NAME = true
288
+ end
289
+ def unBO_METH_NAME
290
+ @bo_BO_METH_NAME = false
291
+ end
292
+ def BO_METH_NAME?
293
+ return nil != (@bo_BO_METH_NAME || nil)
294
+ end
295
+ def BO_METH_NAME=(prm)
296
+ @bo_BO_METH_NAME=prm
297
+ end
298
+ CODE
299
+ hash[:rm] = <<'CODE'
300
+ undef BO_METH_NAME rescue :never_mind
301
+ undef unBO_METH_NAME rescue :never_mind
302
+ undef BO_METH_NAME? rescue :never_mind
303
+ undef BO_METH_NAME! rescue :never_mind
304
+ undef BO_METH_NAME= rescue :never_mind
305
+ CODE
306
+ @@better_object_valid_methods[:tag] = hash
307
+
308
+
309
+ #
310
+ # Generator :functionize
311
+ #
312
+ hash = {}
313
+ hash[:type] = :class
314
+ hash[:explain] = "creates MyClass() on Kernel level as an alternate constructor or some other method"
315
+ hash[:code] = <<'CODE'
316
+ def BO_METH_NAME(meth=:new)
317
+ raise "can't redefine #{self}" if Kernel.methods.include? self.to_s.to_sym
318
+ raise "can't redefine #{self}" if self.respond_to? self.to_s.to_sym
319
+ cmd = "def #{self}(*prms,&block); return #{self}.#{meth.to_s}(*prms,&block);end"
320
+ Kernel.class_eval cmd
321
+ end
322
+ CODE
323
+ @@better_object_valid_methods[:functionize] = hash
324
+
325
+ end