IHelp bugreport and extension

C

Csaba Henk

First, the bugreport.

Array.help just gives the following garbage:

---------------------------------------------- Class: TSortArray < Array
(no description...)
------------------------------------------------------------------------

Now the fun part...

By overriding ri's io routines by more flexible (but by default
backward-compatible) version, and adjusting IHelp accordingly, one, if
wants, can get the rendered ri output as string (w/o doing io).

It works as follows:

require 'ihelp-dump'
# Default behaviour is the same, but then...

IHelp.set_dump true
IHelp.dump? # => true
5.help :size # => (the help as a string)
5.help :size, :to => $> # prints the help
5.help :size, :times # => (the concatenation of the two helps)
IHelp.set_dump false # everything works again as it used to

Note that the first help atfer a #set_dump will take some time as IHelp
is re-initialized then.

It's also possible to pass ri options to #set_dump:

IHelp.set_dump true, %w(-f html) # don't use "-T", that's handled by \
IHelp.set_dump false, %w(-f ansi) # #set_dump

And finally, some candy:

IHelp.set_dump true, %w(-f ansi)
open("|less -R","w") { |f| Module.helpall f }

IHelp.set_dump true, %w(-f html)
open("|w3m -T text/html","w") { |f| Module.allhelp f } # #allhelp is the \
# same as #helpall

I guess you can guess what it does...

Note that the latter, dumping all docs in html, can also be done easily
via Ilmari's html renderer as well.

Csaba

Ps. So the code:


require 'ihelp'
require 'rdoc/ri/ri_formatter'

class RI::TextFormatter
@@io = $>

def self.io
@@io
end

def self.io= io
@@io = io
end

def print *a
a.each{|e| @@io << e }
nil
end

def printf *a
@@io << sprintf(*a)
nil
end

def puts *a
a.empty? and a << ""
a.each {|e| @@io << e.chomp + "\n"}
nil
end
end

module IHelp

def self.set_dump boo, args=nil
setargs = proc { args and IHelp::RI_ARGS.clear.concat args }
case boo
when true
@use_stdout.nil? and @use_stdout = ((%w(--no-pager -T) - IHelp::RI_ARGS).size < 2)
setargs[]
IHelp::RI_ARGS << "-T"
@dump=true
when false
unless @use_stdout
%w(--no-pager -T).each {|o| IHelp::RI_ARGS.delete o }
RI::Options.instance.use_stdout = false
end
@use_stdout = nil
setargs[]
RI::TextFormatter.io = $>
@dump = false
else raise ArgumentError, "please give `true' or `false' for first argument"
end
IHelp::RI_ARGS.uniq!
@ri_driver = nil
end

instance_methods.include? "__help" or alias_method :__help, :help

def self.dump?
@dump
end

def help(*args,&b)
if IHelp.dump?
optsa, names = args.partition { |e| e.is_a? Hash }
opts = {}
optsa.each {|h| opts.merge! h}
to = opts[:to] || ""
RI::TextFormatter.io = to
names.empty? and names << nil
names.each {|n| __help n }
to
else __help(*args,&b)
end
end

def self.dumpcheck
@dump or raise "do an `IHelp.setdump true', and then you can come back again"
end
private_class_method :dumpcheck

def allhelp to = ""
IHelp.send :dumpcheck
mod = self
self.is_a? Module or mod = self.class
mhd = mod.help_description
help({:to => to},nil,*((mhd.class_methods + mhd.instance_methods).map { |h|h.name}))
end
alias helpall allhelp

end
 
C

Csaba Henk

Now the fun part...

By overriding ri's io routines by more flexible (but by default
backward-compatible) version, and adjusting IHelp accordingly, one, if
wants, can get the rendered ri output as string (w/o doing io).

A much more polished version... No need of doing #set_dump true/false
switches, and RI is not hacked, only IHelp.

It just enriches IHelp#help, and adds the following methods:

IHelp.reset, IHelp#helpall, IHelp#allhelp (these latter two are the
same), IHelp#allhelp_html

(and a couple more, which are not that important for the user).

* IHelp#help: if a hash argument of the form { :to => something }
is given, the help information is written to that something.
Passing more than one argument automatically enables { :to => $> }
Example:

File.help :stat, :size, :to => ""

* IHelp.reset : you can pass ri options to this, and IHelp is
re-initialized accordingly. Like:

IHelp.reset %w(-f html)
IHelp.reset "-f", "ansi"

* IHelp#helpall, IHelp#allhelp: prints out all help info of the given
module/class (or the class of the receiver, if it's not a class). If an
argument is passed, the help info written there. Example:

open("|less -R","w") { |f| Thread.allhelp f }

* IHelp#allhelp_html: does the same as the above, but outputs html
regardless of the formatter's settings. Uses Ilmari's html renderer.
Eg.:

open("|w3m -T text/html","w") { |f| Thread.allhelp_html f }

Csaba

PS. The code:


require 'ihelp'

module IHelp

def self.formatter
@ri_driver.instance_variable_get:)@display).instance_variable_get:)@formatter)
end

def self.io
return unless formatter.respond_to? :io
formatter.io
end

def self.io= val
ri_driver unless formatter
unless formatter.respond_to? :io=
class << formatter
attr_accessor :io

def print *a
a.each{|e| @io << e }
nil
end

def printf *a
@io << sprintf(*a)
nil
end

def puts *a
a.empty? and a << ""
a.each {|e| @io << e.chomp + "\n"}
nil
end
end
end
formatter.io = val
end

def self.reset *args
IHelp::RI_ARGS.clear.concat args.flatten
@ri_driver = nil
ri_driver
nil
end

def self.use_stdout
RI::Options.instance.use_stdout
end

def self.use_stdout= val
RI::Options.instance.use_stdout= val
end

instance_methods.include? "__help" or alias_method :__help, :help

def help(*args,&b)
optsa, names = args.partition { |e| e.is_a? Hash }
opts = {}
optsa.each {|h| opts.merge! h}
if opts[:to] or names.size > 1
begin
orig_io = IHelp.io || $>
orig_use_stdout = IHelp.use_stdout
IHelp.use_stdout = true
IHelp.io = opts[:to] || $>
names.empty? and names << nil
names.each {|n| __help n }
IHelp.io
ensure
IHelp.io = orig_io
IHelp.use_stdout = orig_use_stdout
end
else
__help args[0]
end
end

def __allhelp_backend
mod = self
self.is_a? Module or mod = self.class
mhd = mod.help_description
[nil] + (mhd.class_methods + mhd.instance_methods).map {|h| h.name}
end
private :__allhelp_backend

def allhelp to = $>
help({:to => to},*__allhelp_backend)
end
alias helpall allhelp

def allhelp_html to = $>
__allhelp_backend.each {|t|
begin
to << help_html(t).to_s
rescue NoMethodError => err
warn "Warning: at `#{t}' an error #{err} occurred"
end
}
to
end

end
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,982
Messages
2,570,190
Members
46,736
Latest member
zacharyharris

Latest Threads

Top