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

**URL:** <https://www.ruby-forum.com/t/re-qaprototype-91-updated-solution-with-bells-and-whis/65750>\
**Category:** Ruby\
**Created:** [August 21, 2006, 3:45am UTC](https://www.ruby-forum.com/t/re-qaprototype-91-updated-solution-with-bells-and-whis/65750 "2006-08-21T03:45:54Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![rykkers](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/r/e5b9ba/32.png) [@rykkers](https://www.ruby-forum.com/u/rykkers)\
**Post date:** [August 21, 2006, 3:45am UTC](https://www.ruby-forum.com/t/re-qaprototype-91-updated-solution-with-bells-and-whis/65750/1 "2006-08-21T03:45:54Z")

</div>

On 8/20/06, Rick DeNatale [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) 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/](http://talklikeaduck.denhaven2.com/)

---

<div class="post-metadata">

**Author:** ![rykkers](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/r/e5b9ba/32.png) [@rykkers](https://www.ruby-forum.com/u/rykkers)\
**Post date:** [August 21, 2006, 9:14am UTC](https://www.ruby-forum.com/t/re-qaprototype-91-updated-solution-with-bells-and-whis/65750/2 "2006-08-21T09:14:33Z")

</div>

On 8/20/06, Rick DeNatale [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) 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.

---

<div class="post-metadata">

**Author:** ![rykkers](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/r/e5b9ba/32.png) [@rykkers](https://www.ruby-forum.com/u/rykkers)\
**Post date:** [August 21, 2006, 11:02am UTC](https://www.ruby-forum.com/t/re-qaprototype-91-updated-solution-with-bells-and-whis/65750/3 "2006-08-21T11:02:42Z")

</div>

quoth the Rick DeNatale:

> On 8/20/06, Rick DeNatale [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) 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

---

<div class="post-metadata">

**Author:** ![rykkers](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/r/e5b9ba/32.png) [@rykkers](https://www.ruby-forum.com/u/rykkers)\
**Post date:** [August 21, 2006, 6:37pm UTC](https://www.ruby-forum.com/t/re-qaprototype-91-updated-solution-with-bells-and-whis/65750/4 "2006-08-21T18:37:59Z")

</div>

On 8/21/06, darren kirby [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) 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/](http://talklikeaduck.denhaven2.com/)
