irb 1.0.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.
Files changed (54) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +9 -0
  3. data/.travis.yml +6 -0
  4. data/Gemfile +5 -0
  5. data/LICENSE.txt +22 -0
  6. data/README.md +55 -0
  7. data/Rakefile +10 -0
  8. data/bin/console +6 -0
  9. data/bin/setup +6 -0
  10. data/exe/irb +11 -0
  11. data/irb.gemspec +26 -0
  12. data/lib/irb.rb +798 -0
  13. data/lib/irb/cmd/chws.rb +34 -0
  14. data/lib/irb/cmd/fork.rb +39 -0
  15. data/lib/irb/cmd/help.rb +42 -0
  16. data/lib/irb/cmd/load.rb +67 -0
  17. data/lib/irb/cmd/nop.rb +39 -0
  18. data/lib/irb/cmd/pushws.rb +41 -0
  19. data/lib/irb/cmd/subirb.rb +43 -0
  20. data/lib/irb/completion.rb +244 -0
  21. data/lib/irb/context.rb +425 -0
  22. data/lib/irb/ext/change-ws.rb +46 -0
  23. data/lib/irb/ext/history.rb +119 -0
  24. data/lib/irb/ext/loader.rb +129 -0
  25. data/lib/irb/ext/multi-irb.rb +265 -0
  26. data/lib/irb/ext/save-history.rb +105 -0
  27. data/lib/irb/ext/tracer.rb +72 -0
  28. data/lib/irb/ext/use-loader.rb +74 -0
  29. data/lib/irb/ext/workspaces.rb +67 -0
  30. data/lib/irb/extend-command.rb +306 -0
  31. data/lib/irb/frame.rb +81 -0
  32. data/lib/irb/help.rb +37 -0
  33. data/lib/irb/init.rb +302 -0
  34. data/lib/irb/input-method.rb +192 -0
  35. data/lib/irb/inspector.rb +132 -0
  36. data/lib/irb/lc/.document +4 -0
  37. data/lib/irb/lc/error.rb +32 -0
  38. data/lib/irb/lc/help-message +49 -0
  39. data/lib/irb/lc/ja/encoding_aliases.rb +11 -0
  40. data/lib/irb/lc/ja/error.rb +31 -0
  41. data/lib/irb/lc/ja/help-message +52 -0
  42. data/lib/irb/locale.rb +182 -0
  43. data/lib/irb/magic-file.rb +38 -0
  44. data/lib/irb/notifier.rb +232 -0
  45. data/lib/irb/output-method.rb +92 -0
  46. data/lib/irb/ruby-lex.rb +1180 -0
  47. data/lib/irb/ruby-token.rb +267 -0
  48. data/lib/irb/slex.rb +282 -0
  49. data/lib/irb/src_encoding.rb +7 -0
  50. data/lib/irb/version.rb +17 -0
  51. data/lib/irb/workspace.rb +143 -0
  52. data/lib/irb/ws-for-case-2.rb +15 -0
  53. data/lib/irb/xmp.rb +170 -0
  54. metadata +125 -0
@@ -0,0 +1,105 @@
1
+ # frozen_string_literal: false
2
+ # save-history.rb -
3
+ # $Release Version: 0.9.6$
4
+ # $Revision$
5
+ # by Keiju ISHITSUKA(keiju@ruby-lang.org)
6
+ #
7
+ # --
8
+ #
9
+ #
10
+ #
11
+
12
+ require "readline"
13
+
14
+ module IRB
15
+ module HistorySavingAbility # :nodoc:
16
+ end
17
+
18
+ class Context
19
+ def init_save_history# :nodoc:
20
+ unless (class<<@io;self;end).include?(HistorySavingAbility)
21
+ @io.extend(HistorySavingAbility)
22
+ end
23
+ end
24
+
25
+ # A copy of the default <code>IRB.conf[:SAVE_HISTORY]</code>
26
+ def save_history
27
+ IRB.conf[:SAVE_HISTORY]
28
+ end
29
+
30
+ remove_method :save_history= if respond_to?(:save_history=)
31
+ # Sets <code>IRB.conf[:SAVE_HISTORY]</code> to the given +val+ and calls
32
+ # #init_save_history with this context.
33
+ #
34
+ # Will store the number of +val+ entries of history in the #history_file
35
+ #
36
+ # Add the following to your +.irbrc+ to change the number of history
37
+ # entries stored to 1000:
38
+ #
39
+ # IRB.conf[:SAVE_HISTORY] = 1000
40
+ def save_history=(val)
41
+ IRB.conf[:SAVE_HISTORY] = val
42
+ if val
43
+ main_context = IRB.conf[:MAIN_CONTEXT]
44
+ main_context = self unless main_context
45
+ main_context.init_save_history
46
+ end
47
+ end
48
+
49
+ # A copy of the default <code>IRB.conf[:HISTORY_FILE]</code>
50
+ def history_file
51
+ IRB.conf[:HISTORY_FILE]
52
+ end
53
+
54
+ # Set <code>IRB.conf[:HISTORY_FILE]</code> to the given +hist+.
55
+ def history_file=(hist)
56
+ IRB.conf[:HISTORY_FILE] = hist
57
+ end
58
+ end
59
+
60
+ module HistorySavingAbility # :nodoc:
61
+ include Readline
62
+
63
+ def HistorySavingAbility.extended(obj)
64
+ IRB.conf[:AT_EXIT].push proc{obj.save_history}
65
+ obj.load_history
66
+ obj
67
+ end
68
+
69
+ def load_history
70
+ if history_file = IRB.conf[:HISTORY_FILE]
71
+ history_file = File.expand_path(history_file)
72
+ end
73
+ history_file = IRB.rc_file("_history") unless history_file
74
+ if File.exist?(history_file)
75
+ open(history_file) do |f|
76
+ f.each {|l| HISTORY << l.chomp}
77
+ end
78
+ end
79
+ end
80
+
81
+ def save_history
82
+ if num = IRB.conf[:SAVE_HISTORY] and (num = num.to_i) > 0
83
+ if history_file = IRB.conf[:HISTORY_FILE]
84
+ history_file = File.expand_path(history_file)
85
+ end
86
+ history_file = IRB.rc_file("_history") unless history_file
87
+
88
+ # Change the permission of a file that already exists[BUG #7694]
89
+ begin
90
+ if File.stat(history_file).mode & 066 != 0
91
+ File.chmod(0600, history_file)
92
+ end
93
+ rescue Errno::ENOENT
94
+ rescue
95
+ raise
96
+ end
97
+
98
+ open(history_file, 'w', 0600 ) do |f|
99
+ hist = HISTORY.to_a
100
+ f.puts(hist[-num..-1] || hist)
101
+ end
102
+ end
103
+ end
104
+ end
105
+ end
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: false
2
+ #
3
+ # irb/lib/tracer.rb -
4
+ # $Release Version: 0.9.6$
5
+ # $Revision$
6
+ # by Keiju ISHITSUKA(keiju@ruby-lang.org)
7
+ #
8
+ # --
9
+ #
10
+ #
11
+ #
12
+ require "tracer"
13
+
14
+ module IRB
15
+
16
+ # initialize tracing function
17
+ def IRB.initialize_tracer
18
+ Tracer.verbose = false
19
+ Tracer.add_filter {
20
+ |event, file, line, id, binding, *rests|
21
+ /^#{Regexp.quote(@CONF[:IRB_LIB_PATH])}/ !~ file and
22
+ File::basename(file) != "irb.rb"
23
+ }
24
+ end
25
+
26
+ class Context
27
+ # Whether Tracer is used when evaluating statements in this context.
28
+ #
29
+ # See +lib/tracer.rb+ for more information.
30
+ attr_reader :use_tracer
31
+ alias use_tracer? use_tracer
32
+
33
+ # Sets whether or not to use the Tracer library when evaluating statements
34
+ # in this context.
35
+ #
36
+ # See +lib/tracer.rb+ for more information.
37
+ def use_tracer=(opt)
38
+ if opt
39
+ Tracer.set_get_line_procs(@irb_path) {
40
+ |line_no, *rests|
41
+ @io.line(line_no)
42
+ }
43
+ elsif !opt && @use_tracer
44
+ Tracer.off
45
+ end
46
+ @use_tracer=opt
47
+ end
48
+ end
49
+
50
+ class WorkSpace
51
+ alias __evaluate__ evaluate
52
+ # Evaluate the context of this workspace and use the Tracer library to
53
+ # output the exact lines of code are being executed in chronological order.
54
+ #
55
+ # See +lib/tracer.rb+ for more information.
56
+ def evaluate(context, statements, file = nil, line = nil)
57
+ if context.use_tracer? && file != nil && line != nil
58
+ Tracer.on
59
+ begin
60
+ __evaluate__(context, statements, file, line)
61
+ ensure
62
+ Tracer.off
63
+ end
64
+ else
65
+ __evaluate__(context, statements, file || __FILE__, line || __LINE__)
66
+ end
67
+ end
68
+ end
69
+
70
+ IRB.initialize_tracer
71
+ end
72
+
@@ -0,0 +1,74 @@
1
+ # frozen_string_literal: false
2
+ #
3
+ # use-loader.rb -
4
+ # $Release Version: 0.9.6$
5
+ # $Revision$
6
+ # by Keiju ISHITSUKA(keiju@ruby-lang.org)
7
+ #
8
+ # --
9
+ #
10
+ #
11
+ #
12
+
13
+ require_relative "../cmd/load"
14
+ require_relative "loader"
15
+
16
+ class Object
17
+ alias __original__load__IRB_use_loader__ load
18
+ alias __original__require__IRB_use_loader__ require
19
+ end
20
+
21
+ module IRB
22
+ module ExtendCommandBundle
23
+ # Loads the given file similarly to Kernel#load, see IrbLoader#irb_load
24
+ def irb_load(*opts, &b)
25
+ ExtendCommand::Load.execute(irb_context, *opts, &b)
26
+ end
27
+ # Loads the given file similarly to Kernel#require
28
+ def irb_require(*opts, &b)
29
+ ExtendCommand::Require.execute(irb_context, *opts, &b)
30
+ end
31
+ end
32
+
33
+ class Context
34
+
35
+ IRB.conf[:USE_LOADER] = false
36
+
37
+ # Returns whether +irb+'s own file reader method is used by
38
+ # +load+/+require+ or not.
39
+ #
40
+ # This mode is globally affected (irb-wide).
41
+ def use_loader
42
+ IRB.conf[:USE_LOADER]
43
+ end
44
+
45
+ alias use_loader? use_loader
46
+
47
+ # Sets IRB.conf[:USE_LOADER]
48
+ #
49
+ # See #use_loader for more information.
50
+ def use_loader=(opt)
51
+
52
+ if IRB.conf[:USE_LOADER] != opt
53
+ IRB.conf[:USE_LOADER] = opt
54
+ if opt
55
+ if !$".include?("irb/cmd/load")
56
+ end
57
+ (class<<@workspace.main;self;end).instance_eval {
58
+ alias_method :load, :irb_load
59
+ alias_method :require, :irb_require
60
+ }
61
+ else
62
+ (class<<@workspace.main;self;end).instance_eval {
63
+ alias_method :load, :__original__load__IRB_use_loader__
64
+ alias_method :require, :__original__require__IRB_use_loader__
65
+ }
66
+ end
67
+ end
68
+ print "Switch to load/require#{unless use_loader; ' non';end} trace mode.\n" if verbose?
69
+ opt
70
+ end
71
+ end
72
+ end
73
+
74
+
@@ -0,0 +1,67 @@
1
+ # frozen_string_literal: false
2
+ #
3
+ # push-ws.rb -
4
+ # $Release Version: 0.9.6$
5
+ # $Revision$
6
+ # by Keiju ISHITSUKA(keiju@ruby-lang.org)
7
+ #
8
+ # --
9
+ #
10
+ #
11
+ #
12
+
13
+ module IRB # :nodoc:
14
+ class Context
15
+
16
+ # Size of the current WorkSpace stack
17
+ def irb_level
18
+ workspace_stack.size
19
+ end
20
+
21
+ # WorkSpaces in the current stack
22
+ def workspaces
23
+ if defined? @workspaces
24
+ @workspaces
25
+ else
26
+ @workspaces = []
27
+ end
28
+ end
29
+
30
+ # Creates a new workspace with the given object or binding, and appends it
31
+ # onto the current #workspaces stack.
32
+ #
33
+ # See IRB::Context#change_workspace and IRB::WorkSpace.new for more
34
+ # information.
35
+ def push_workspace(*_main)
36
+ if _main.empty?
37
+ if workspaces.empty?
38
+ print "No other workspace\n"
39
+ return nil
40
+ end
41
+ ws = workspaces.pop
42
+ workspaces.push @workspace
43
+ @workspace = ws
44
+ return workspaces
45
+ end
46
+
47
+ workspaces.push @workspace
48
+ @workspace = WorkSpace.new(@workspace.binding, _main[0])
49
+ if !(class<<main;ancestors;end).include?(ExtendCommandBundle)
50
+ main.extend ExtendCommandBundle
51
+ end
52
+ end
53
+
54
+ # Removes the last element from the current #workspaces stack and returns
55
+ # it, or +nil+ if the current workspace stack is empty.
56
+ #
57
+ # Also, see #push_workspace.
58
+ def pop_workspace
59
+ if workspaces.empty?
60
+ print "workspace stack empty\n"
61
+ return
62
+ end
63
+ @workspace = workspaces.pop
64
+ end
65
+ end
66
+ end
67
+
@@ -0,0 +1,306 @@
1
+ # frozen_string_literal: false
2
+ #
3
+ # irb/extend-command.rb - irb extend command
4
+ # $Release Version: 0.9.6$
5
+ # $Revision$
6
+ # by Keiju ISHITSUKA(keiju@ruby-lang.org)
7
+ #
8
+ # --
9
+ #
10
+ #
11
+ #
12
+ module IRB # :nodoc:
13
+ # Installs the default irb extensions command bundle.
14
+ module ExtendCommandBundle
15
+ EXCB = ExtendCommandBundle # :nodoc:
16
+
17
+ # See #install_alias_method.
18
+ NO_OVERRIDE = 0
19
+ # See #install_alias_method.
20
+ OVERRIDE_PRIVATE_ONLY = 0x01
21
+ # See #install_alias_method.
22
+ OVERRIDE_ALL = 0x02
23
+
24
+ # Quits the current irb context
25
+ #
26
+ # +ret+ is the optional signal or message to send to Context#exit
27
+ #
28
+ # Same as <code>IRB.CurrentContext.exit</code>.
29
+ def irb_exit(ret = 0)
30
+ irb_context.exit(ret)
31
+ end
32
+
33
+ # Displays current configuration.
34
+ #
35
+ # Modifing the configuration is achieved by sending a message to IRB.conf.
36
+ def irb_context
37
+ IRB.CurrentContext
38
+ end
39
+
40
+ @ALIASES = [
41
+ [:context, :irb_context, NO_OVERRIDE],
42
+ [:conf, :irb_context, NO_OVERRIDE],
43
+ [:irb_quit, :irb_exit, OVERRIDE_PRIVATE_ONLY],
44
+ [:exit, :irb_exit, OVERRIDE_PRIVATE_ONLY],
45
+ [:quit, :irb_exit, OVERRIDE_PRIVATE_ONLY],
46
+ ]
47
+
48
+ @EXTEND_COMMANDS = [
49
+ [:irb_current_working_workspace, :CurrentWorkingWorkspace, "irb/cmd/chws",
50
+ [:irb_print_working_workspace, OVERRIDE_ALL],
51
+ [:irb_cwws, OVERRIDE_ALL],
52
+ [:irb_pwws, OVERRIDE_ALL],
53
+ [:cwws, NO_OVERRIDE],
54
+ [:pwws, NO_OVERRIDE],
55
+ [:irb_current_working_binding, OVERRIDE_ALL],
56
+ [:irb_print_working_binding, OVERRIDE_ALL],
57
+ [:irb_cwb, OVERRIDE_ALL],
58
+ [:irb_pwb, OVERRIDE_ALL],
59
+ ],
60
+ [:irb_change_workspace, :ChangeWorkspace, "irb/cmd/chws",
61
+ [:irb_chws, OVERRIDE_ALL],
62
+ [:irb_cws, OVERRIDE_ALL],
63
+ [:chws, NO_OVERRIDE],
64
+ [:cws, NO_OVERRIDE],
65
+ [:irb_change_binding, OVERRIDE_ALL],
66
+ [:irb_cb, OVERRIDE_ALL],
67
+ [:cb, NO_OVERRIDE]],
68
+
69
+ [:irb_workspaces, :Workspaces, "irb/cmd/pushws",
70
+ [:workspaces, NO_OVERRIDE],
71
+ [:irb_bindings, OVERRIDE_ALL],
72
+ [:bindings, NO_OVERRIDE]],
73
+ [:irb_push_workspace, :PushWorkspace, "irb/cmd/pushws",
74
+ [:irb_pushws, OVERRIDE_ALL],
75
+ [:pushws, NO_OVERRIDE],
76
+ [:irb_push_binding, OVERRIDE_ALL],
77
+ [:irb_pushb, OVERRIDE_ALL],
78
+ [:pushb, NO_OVERRIDE]],
79
+ [:irb_pop_workspace, :PopWorkspace, "irb/cmd/pushws",
80
+ [:irb_popws, OVERRIDE_ALL],
81
+ [:popws, NO_OVERRIDE],
82
+ [:irb_pop_binding, OVERRIDE_ALL],
83
+ [:irb_popb, OVERRIDE_ALL],
84
+ [:popb, NO_OVERRIDE]],
85
+
86
+ [:irb_load, :Load, "irb/cmd/load"],
87
+ [:irb_require, :Require, "irb/cmd/load"],
88
+ [:irb_source, :Source, "irb/cmd/load",
89
+ [:source, NO_OVERRIDE]],
90
+
91
+ [:irb, :IrbCommand, "irb/cmd/subirb"],
92
+ [:irb_jobs, :Jobs, "irb/cmd/subirb",
93
+ [:jobs, NO_OVERRIDE]],
94
+ [:irb_fg, :Foreground, "irb/cmd/subirb",
95
+ [:fg, NO_OVERRIDE]],
96
+ [:irb_kill, :Kill, "irb/cmd/subirb",
97
+ [:kill, OVERRIDE_PRIVATE_ONLY]],
98
+
99
+ [:irb_help, :Help, "irb/cmd/help",
100
+ [:help, NO_OVERRIDE]],
101
+
102
+ ]
103
+
104
+ # Installs the default irb commands:
105
+ #
106
+ # +irb_current_working_workspace+:: Context#main
107
+ # +irb_change_workspace+:: Context#change_workspace
108
+ # +irb_workspaces+:: Context#workspaces
109
+ # +irb_push_workspace+:: Context#push_workspace
110
+ # +irb_pop_workspace+:: Context#pop_workspace
111
+ # +irb_load+:: #irb_load
112
+ # +irb_require+:: #irb_require
113
+ # +irb_source+:: IrbLoader#source_file
114
+ # +irb+:: IRB.irb
115
+ # +irb_jobs+:: JobManager
116
+ # +irb_fg+:: JobManager#switch
117
+ # +irb_kill+:: JobManager#kill
118
+ # +irb_help+:: IRB@Command+line+options
119
+ def self.install_extend_commands
120
+ for args in @EXTEND_COMMANDS
121
+ def_extend_command(*args)
122
+ end
123
+ end
124
+
125
+ # Evaluate the given +cmd_name+ on the given +cmd_class+ Class.
126
+ #
127
+ # Will also define any given +aliases+ for the method.
128
+ #
129
+ # The optional +load_file+ parameter will be required within the method
130
+ # definition.
131
+ def self.def_extend_command(cmd_name, cmd_class, load_file = nil, *aliases)
132
+ case cmd_class
133
+ when Symbol
134
+ cmd_class = cmd_class.id2name
135
+ when String
136
+ when Class
137
+ cmd_class = cmd_class.name
138
+ end
139
+
140
+ if load_file
141
+ line = __LINE__; eval %[
142
+ def #{cmd_name}(*opts, &b)
143
+ require "#{load_file}"
144
+ arity = ExtendCommand::#{cmd_class}.instance_method(:execute).arity
145
+ args = (1..(arity < 0 ? ~arity : arity)).map {|i| "arg" + i.to_s }
146
+ args << "*opts" if arity < 0
147
+ args << "&block"
148
+ args = args.join(", ")
149
+ line = __LINE__; eval %[
150
+ def #{cmd_name}(\#{args})
151
+ ExtendCommand::#{cmd_class}.execute(irb_context, \#{args})
152
+ end
153
+ ], nil, __FILE__, line
154
+ send :#{cmd_name}, *opts, &b
155
+ end
156
+ ], nil, __FILE__, line
157
+ else
158
+ line = __LINE__; eval %[
159
+ def #{cmd_name}(*opts, &b)
160
+ ExtendCommand::#{cmd_class}.execute(irb_context, *opts, &b)
161
+ end
162
+ ], nil, __FILE__, line
163
+ end
164
+
165
+ for ali, flag in aliases
166
+ @ALIASES.push [ali, cmd_name, flag]
167
+ end
168
+ end
169
+
170
+ # Installs alias methods for the default irb commands, see
171
+ # ::install_extend_commands.
172
+ def install_alias_method(to, from, override = NO_OVERRIDE)
173
+ to = to.id2name unless to.kind_of?(String)
174
+ from = from.id2name unless from.kind_of?(String)
175
+
176
+ if override == OVERRIDE_ALL or
177
+ (override == OVERRIDE_PRIVATE_ONLY) && !respond_to?(to) or
178
+ (override == NO_OVERRIDE) && !respond_to?(to, true)
179
+ target = self
180
+ (class << self; self; end).instance_eval{
181
+ if target.respond_to?(to, true) &&
182
+ !target.respond_to?(EXCB.irb_original_method_name(to), true)
183
+ alias_method(EXCB.irb_original_method_name(to), to)
184
+ end
185
+ alias_method to, from
186
+ }
187
+ else
188
+ print "irb: warn: can't alias #{to} from #{from}.\n"
189
+ end
190
+ end
191
+
192
+ def self.irb_original_method_name(method_name) # :nodoc:
193
+ "irb_" + method_name + "_org"
194
+ end
195
+
196
+ # Installs alias methods for the default irb commands on the given object
197
+ # using #install_alias_method.
198
+ def self.extend_object(obj)
199
+ unless (class << obj; ancestors; end).include?(EXCB)
200
+ super
201
+ for ali, com, flg in @ALIASES
202
+ obj.install_alias_method(ali, com, flg)
203
+ end
204
+ end
205
+ end
206
+
207
+ install_extend_commands
208
+ end
209
+
210
+ # Extends methods for the Context module
211
+ module ContextExtender
212
+ CE = ContextExtender # :nodoc:
213
+
214
+ @EXTEND_COMMANDS = [
215
+ [:eval_history=, "irb/ext/history.rb"],
216
+ [:use_tracer=, "irb/ext/tracer.rb"],
217
+ [:use_loader=, "irb/ext/use-loader.rb"],
218
+ [:save_history=, "irb/ext/save-history.rb"],
219
+ ]
220
+
221
+ # Installs the default context extensions as irb commands:
222
+ #
223
+ # Context#eval_history=:: +irb/ext/history.rb+
224
+ # Context#use_tracer=:: +irb/ext/tracer.rb+
225
+ # Context#use_loader=:: +irb/ext/use-loader.rb+
226
+ # Context#save_history=:: +irb/ext/save-history.rb+
227
+ def self.install_extend_commands
228
+ for args in @EXTEND_COMMANDS
229
+ def_extend_command(*args)
230
+ end
231
+ end
232
+
233
+ # Evaluate the given +command+ from the given +load_file+ on the Context
234
+ # module.
235
+ #
236
+ # Will also define any given +aliases+ for the method.
237
+ def self.def_extend_command(cmd_name, load_file, *aliases)
238
+ line = __LINE__; Context.module_eval %[
239
+ def #{cmd_name}(*opts, &b)
240
+ Context.module_eval {remove_method(:#{cmd_name})}
241
+ require "#{load_file}"
242
+ send :#{cmd_name}, *opts, &b
243
+ end
244
+ for ali in aliases
245
+ alias_method ali, cmd_name
246
+ end
247
+ ], __FILE__, line
248
+ end
249
+
250
+ CE.install_extend_commands
251
+ end
252
+
253
+ # A convenience module for extending Ruby methods.
254
+ module MethodExtender
255
+ # Extends the given +base_method+ with a prefix call to the given
256
+ # +extend_method+.
257
+ def def_pre_proc(base_method, extend_method)
258
+ base_method = base_method.to_s
259
+ extend_method = extend_method.to_s
260
+
261
+ alias_name = new_alias_name(base_method)
262
+ module_eval %[
263
+ alias_method alias_name, base_method
264
+ def #{base_method}(*opts)
265
+ send :#{extend_method}, *opts
266
+ send :#{alias_name}, *opts
267
+ end
268
+ ]
269
+ end
270
+
271
+ # Extends the given +base_method+ with a postfix call to the given
272
+ # +extend_method+.
273
+ def def_post_proc(base_method, extend_method)
274
+ base_method = base_method.to_s
275
+ extend_method = extend_method.to_s
276
+
277
+ alias_name = new_alias_name(base_method)
278
+ module_eval %[
279
+ alias_method alias_name, base_method
280
+ def #{base_method}(*opts)
281
+ send :#{alias_name}, *opts
282
+ send :#{extend_method}, *opts
283
+ end
284
+ ]
285
+ end
286
+
287
+ # Returns a unique method name to use as an alias for the given +name+.
288
+ #
289
+ # Usually returns <code>#{prefix}#{name}#{postfix}<num></code>, example:
290
+ #
291
+ # new_alias_name('foo') #=> __alias_of__foo__
292
+ # def bar; end
293
+ # new_alias_name('bar') #=> __alias_of__bar__2
294
+ def new_alias_name(name, prefix = "__alias_of__", postfix = "__")
295
+ base_name = "#{prefix}#{name}#{postfix}"
296
+ all_methods = instance_methods(true) + private_instance_methods(true)
297
+ same_methods = all_methods.grep(/^#{Regexp.quote(base_name)}[0-9]*$/)
298
+ return base_name if same_methods.empty?
299
+ no = same_methods.size
300
+ while !same_methods.include?(alias_name = base_name + no)
301
+ no += 1
302
+ end
303
+ alias_name
304
+ end
305
+ end
306
+ end