Re: QAPrototype (#91) - Updated solution with bells and whis

On 8/20/06, Rick DeNatale [email protected] wrote:

I’ve been away from e-mail for a few days. I haven’t looked at anyone
elses solution yet.

Here’s my initial solution which didn’t take long. I expect to refine
this with more function in the next few days.

Okay, I’ve spent a few hours adding things:

  1. First, I added the ability to optionally use the Readline module to
    prompt for method source if it’s available. This allows the history
    in, say irb, to be used. Note the use of class_eval to include the
    module. This allows the code to compile if the module isn’t available.

  2. I added a check to see if the method actually compiles, and loop
    back to reprompt if it doesn’t. This make the saving of the history
    of input using readline worthwhile.

  3. I then added the ability to ‘dump’ any methods created by
    prompting. The Kernel method prompted_methods produces a string which
    could be saved to a file and compiled by ruby.

  4. Finally, it occured to me that you might want to put the method in
    another class (or module) than the class of the receiver. I added a
    prompt allowing the user to select any class or module in the ancestry
    of the receiver, EXCEPT the MethodPrompter module. The idea behind
    this restriction is to keep that module pristine, with nothing but
    method_missing.

The last idea I have is to add a resend of the original message when
the method is defined, and allow the user to remove it if he doesn’t
like the result. I just haven’t gotten around to this yet.

=== method_prompter.rb ===
module MethodPrompter

    class Interactor

            # Try to include the readline library
            # if it's not available define a lower-function method
            begin
                    require 'readline'
                    Interactor.class_eval('include Readline')
            rescue Exception => ex
                    puts ex.to_s
                    warn "The Readline module is not available."
                    def readline(prompt,addHistory)
                            print prompt
                            line = gets
                            # Readline.readline returns empty string 

instead
# of “\n”
line = “” if line == “\n”
line
end
end

            def initialize(target_object)
                    @target_object = target_object
            end

            def prompt_for_body(symbol, *args)
                    puts "Please define what I should do (end with

a newline):"
method_body = []
line_num = 1
while line = readline("#{line_num}: ", true)
break if line.empty?
line_num += 1
method_body << line
end
method_body
end

           def prompt_for_parms(args, block)
                    puts "There were #{args.length} arguments in the 

call."
puts “block = #{block}”
p args if !args.empty?
puts “enter method argument list”
args = readline("arguments: ", false)
args.empty? ? “” : “(#{args})”
end

            def prompt_for_module
                    possibles =

@target_object.class.ancestors.reject { |m| m == MethodPrompter }
result = nil
while result == nil
puts “Possible modules/classes to
implement”
possibles.each_with_index do | mod, i |
puts " #{i}: #{mod.name}"
end
p "Enter
selection(#{@target_object.class.name}): "
result = possibles[gets.to_i]
end
p result
result
end

            def make_method(target_module, symbol, source)
                    target_module.module_eval(source, 'line', 0)
            end

            def method_source(symbol, parms, method_body)
                    "def #{symbol.to_s}#{parms}\n" <<
                         method_body.join("\n") <<
                         "\nend"
            end

            def prompt_for_method(symbol, args, block)
                    puts "#{symbol} is undefined"
                    target_module = prompt_for_module
                    parms = prompt_for_parms(args, block)
                    good_to_go = false
                    until good_to_go
                            method_body = prompt_for_body(symbol)
                            if method_body.empty?
                                    puts "Okay, nothing to do, so

I’ve not defined #{symbol.to_s}"
return
end
begin
source = method_source(symbol,
parms, method_body)
make_method(target_module,
symbol, source)
rescue Exception => ex
puts “#{ex.class}: #{ex}”
ensure
good_to_go =
target_module.method_defined?(symbol)
end
puts “\nThat didn’t work. Empty method
body will give up.” unless good_to_go
end

                    Repository.save_method(target_module, symbol,

parms, method_body)
end

    end

    class Repository

            require 'singleton'
            include Singleton

            def Repository.save_method(target_module, symbol,

parms, method_body )

instance.module_entry(target_module).save_method(symbol,parms,
method_body)
end

            def module_entry(target_module)
                    @modules = @modules || Hash.new {|hash, k|

hash[k] = ModuleEntry.new }
@modules[target_module]
end

            def Repository.list_all
                    instance.list_all
            end

            def list_all
                    return "" unless @modules
                    result = ""
                    @modules.each do | mod, entry |
                         result << (mod.kind_of?(Class) ? "class

": "module ")
result << mod.name << “\n”
result << entry.list_all
result << “end\n”
end
result
end

            def modules
                    @modules
            end
    end

    class ModuleEntry

            def save_method(symbol, parms, method_body)
                    @methods = @methods || Hash.new
                    @methods[symbol] = source_for(symbol, parms,

method_body)
end

            def list_all
                    return "" unless @methods
                    result = ""
                    @methods.each do | symbol, source |
                    result << source << "\n"
                    end
                    result
            end

            private
            def source_for(symbol, parms, method_body)
                    indent = " " * 8
                    source_array = [indent + "def " + symbol.to_s + 

parms ]
method_body.each do | line |
source_array << (indent * 2) + line
end
source_array << indent + ‘end’
source_array.join(“\n”)
end
end

    def method_missing(symbol, *args, &block)
            Interactor.new(self).prompt_for_method(symbol, args, 

block)
end

end

module Kernel
def prompted_methods
MethodPrompter::Repository.list_all
end
end


Rick DeNatale

My blog on Ruby
http://talklikeaduck.denhaven2.com/

On 8/20/06, Rick DeNatale [email protected] wrote:

  1. First, I added the ability to optionally use the Readline module to
    prompt for method source if it’s available. This allows the history
    in, say irb, to be used. Note the use of class_eval to include the
    module. This allows the code to compile if the module isn’t available.

  2. I added a check to see if the method actually compiles, and loop
    back to reprompt if it doesn’t. This make the saving of the history
    of input using readline worthwhile.

I like how you handle getting the source much better. My
implementation has the user just #undo and redefine it… and no
Readline support. I might try to add that in, though. Great ideas,
though.

M.T.

quoth the Rick DeNatale:

On 8/20/06, Rick DeNatale [email protected] wrote:

I’ve been away from e-mail for a few days. I haven’t looked at anyone
elses solution yet.

Here’s my initial solution which didn’t take long. I expect to refine
this with more function in the next few days.

Okay, I’ve spent a few hours adding things:

Your solution is fantastic. The readline support is really the
bees-knees…
I, for one, have permanently installed your module for future use.

Thanks!
-d

On 8/21/06, darren kirby [email protected] wrote:

Your solution is fantastic. The readline support is really the bees-knees…
I, for one, have permanently installed your module for future use.

Ahwww Shucks


Rick DeNatale

My blog on Ruby
http://talklikeaduck.denhaven2.com/