Strategies for writing Ruby applications to be easily distributed with RubyGems

Z

Zev Blut

Hello,

This is mostly a repost of ruby-talk[229723] with some clarifications
and an appeal for ideas.

I have recently attempted to write a RubyGem for the Saikuro project.
Unfortunately, I have learned that there is a mismatch between how I
wrote Saikuro and how RubyGems expects executables to work.

I would like to know is are there any better or commonly followed ways
of writing executables that work with RubyGems and other installation
programs such as setup.rb ?

Below are the differences between how I wrote Saikuro and what
RubyGems does.

1)
Saikuro uses the "if __FILE__ =3D=3D $0" check before doing the
"application work". When RubyGems creates a new gemified saikuro
wrapper to call the real saikuro bin "$0" is the gemified saikuro and
not the real one. Thus, by default nothing happens.

For fun I cheated and commented out the "if __FILE__" check and
replaced it with "if true". Saikuro will work with this change, but I
then ran "saikuro -?" to get a usage message and found the next
problem:


2)
I was reading through the Programming Ruby book and found a part that
showed how to use rdoc to create usage messages. I figured this might
be better than my normal technique so I used it in Saikuro. This has
caused a number of problems actually.

* With the above cheat I get the gem message:
--
/usr/bin/saikuro: invalid option -- ?
This file was generated by RubyGems.

The application 'Saikuro' is installed as part of a gem, and this file
is here to facilitate running it.
--

Which is not the usage message I wanted.


My original goal was to keep Saikuro simple so that as a single file
nothing complicated was needed. But now I suppose that should change.

I am planning to move all logic above and "if __FILE__ =3D=3D $0" block
into a separate library file. Then add a require to this newly made
file and remove the "if __FILE__" check logic to make the insides of
the block automatically run.

Next I will stop using rdoc usage and simply put the usage message in
a method that outputs a String.

Does this sound like a good strategy?

Thanks,
Zev
 
E

Eric Hodel

This is mostly a repost of ruby-talk[229723] with some clarifications
and an appeal for ideas.

I have recently attempted to write a RubyGem for the Saikuro project.
Unfortunately, I have learned that there is a mismatch between how I
wrote Saikuro and how RubyGems expects executables to work.

I would like to know is are there any better or commonly followed ways
of writing executables that work with RubyGems and other installation
programs such as setup.rb ?

My executables typically consist of three lines:

#!/usr/local/bin/ruby -w
require 'some_file'
SomeFile.run

Where SomeFile::run is something like:

class SomeFile
def self.run(args = ARGV)
options = process_args args
new(option[:foo]).run
end
end
2)
I was reading through the Programming Ruby book and found a part that
showed how to use rdoc to create usage messages. I figured this might
be better than my normal technique so I used it in Saikuro. This has
caused a number of problems actually.

What does this technique look like? I'm not familiar with it.
My original goal was to keep Saikuro simple so that as a single file
nothing complicated was needed. But now I suppose that should change.

I am planning to move all logic above and "if __FILE__ == $0" block
into a separate library file. Then add a require to this newly made
file and remove the "if __FILE__" check logic to make the insides of
the block automatically run.

I keep these together, but put the logic that would normally go in
"if __FILE__ == $0" into its own method or methods. That keeps the
executable as simple as possible.
 
Z

Zev Blut

On Dec 18, 2006, at 22:34, Zev Blut wrote:
I would like to know is are there any better or commonly followed way= s
of writing executables that work with RubyGems and other installation=
programs such as setup.rb ?

My executables typically consist of three lines:

#!/usr/local/bin/ruby -w
require 'some_file'
SomeFile.run

Where SomeFile::run is something like:

class SomeFile
def self.run(args =3D ARGV)
options =3D process_args args
new(option[:foo]).run
end
end

Yes that is a good way to solve this problem.
What does this technique look like? I'm not familiar with it.

http://ruby-doc.org/stdlib/libdoc/rdoc/rdoc/classes/RDoc.html#M001338

It is something like this:

-------------
#!/usr/bin/env ruby
# =3D=3D Usage
# Some stuff on how to use a program.
# More stuff

require 'rdoc/usage'

RDoc.usage
 
E

Eric Hodel

On Dec 18, 2006, at 22:34, Zev Blut wrote:
I would like to know is are there any better or commonly followed
ways
of writing executables that work with RubyGems and other
installation
programs such as setup.rb ?

My executables typically consist of three lines:

#!/usr/local/bin/ruby -w
require 'some_file'
SomeFile.run

Where SomeFile::run is something like:

class SomeFile
def self.run(args = ARGV)
options = process_args args
new(option[:foo]).run
end
end

Yes that is a good way to solve this problem.
What does this technique look like? I'm not familiar with it.

http://ruby-doc.org/stdlib/libdoc/rdoc/rdoc/classes/RDoc.html#M001338

It is something like this:

-------------
#!/usr/bin/env ruby
# == Usage
# Some stuff on how to use a program.
# More stuff

require 'rdoc/usage'

RDoc.usage

Since RDoc.usage uses #caller to figure out which file to read you
should be able to combine RDoc.usage with my method above, and the
usage will live in the library file.
 
Z

Zev Blut

=


Since RDoc.usage uses #caller to figure out which file to read you =
should be able to combine RDoc.usage with my method above, and the usa=
ge =
will live in the library file.

I have done a quick refactoring to create something similar to your
suggestions. The bin part works now, but the RDoc.usage still gives a
RubyGems message.

Just in case here is my ruby version
# ruby -v
ruby 1.8.5 (2006-08-25) [i686-linux]

I stuck some debugging puts in the RDoc.usage_no_exit method and this
is what I got:

# saikuro -?
/usr/bin/saikuro: invalid option -- ?
Caller main program file is /usr/bin/saikuro
Caller stack is
/usr/lib/ruby/1.8/rdoc/usage.rb:93:in `usage'
/usr/lib/ruby/gems/1.8/gems/Saikuro-1.0.0/bin/saikuro:175:in `run'
/usr/lib/ruby/gems/1.8/gems/Saikuro-1.0.0/bin/saikuro:200
/usr/bin/saikuro:18:in `load'
/usr/bin/saikuro:18
This file was generated by RubyGems.

The application 'Saikuro' is installed as part of a gem, and this file
is here to facilitate running it.


-----

Here is the specific piece of code in rdoc/usage usage_no_exit

main_program_file =3D caller[-1].sub(/:\d+$/, '')

It appears that it assumes that the last caller on the stack is the
one who has the usage comments. But, in this current RubyGems bin
case the line above should be something like this:

main_program_file =3D caller[1].sub(/:\d+:).*)?$/, '')

If you read the synopsis of RDoc/usage it states that it will always
take the usage from the main program file. This appears to be in
conflict with RubyGems. I suppose one could hack the method to look
at the caller stack and if it sees a RubyGems /bin/ in the caller
stack uses the first instance as the main_program_file ?

Thanks,
Zev
 

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,755
Messages
2,569,534
Members
45,008
Latest member
Rahul737

Latest Threads

Top