gems cleverness?

G

Giles Bowkett

Is there an easy way to find out all the gems you're running in a
particular codebase? (It's a Rails app but I'd imagine the technique
has general usefulness?)
 
D

Devin Mullins

Giles said:
Is there an easy way to find out all the gems you're running in a
particular codebase? (It's a Rails app but I'd imagine the technique
has general usefulness?)

Cheap hack:
$:.map{|s|s=~Regexp.new(Regexp.escape(Config::CONFIG['libdir']+'/ruby/gems/1.8/gems/')+'(.*)/lib$');$1}.compact
(or http://preview.tinyurl.com/ya4en4 in Firefox)

I'm sure if you dig through the RubyGems code, you'll find a better way
of specifying that directory.

Devin
 
G

Giles Bowkett

Giles said:
Is there an easy way to find out all the gems you're running in a
particular codebase? (It's a Rails app but I'd imagine the technique
has general usefulness?)

Cheap hack:
$:.map{|s|s=~Regexp.new(Regexp.escape(Config::CONFIG['libdir']+'/ruby/gems/1.8/gems/')+'(.*)/lib$');$1}.compact
(or http://preview.tinyurl.com/ya4en4 in Firefox)

I'm sure if you dig through the RubyGems code, you'll find a better way
of specifying that directory.

I hate to admit it, because digging through the RubyGems code is
probably much more worthwhile in the long term, but cheap hacks are
totally what I need right now.

Is it the Perl-y $: thing that gives it its magic special sauce? Also,
couldn't the Regexp part work just as well without the Config stuff,
because of the minimal likelihood of a non-gem having that string in
its path?

Anyway, it works perfectly:

gilesb@a2s8 [~/railsapp]# script/console
Loading development environment.
$:.map{|s|s=~Regexp.new(Regexp.escape(Config::CONFIG['libdir']+'/ruby/gems/1.8/gems/')+'(.*)/lib$');$1}.compact
=> ["net-sftp-1.1.0", "net-ssh-1.0.10", "needle-1.3.0",
"ferret-0.10.13", "rails-1.1.6", "actionwebservice-1.1.6",
"actionmailer-1.2.5", "BlueCloth-1.0.0", "RedCloth-3.0.4",
"actionpack-1.12.5", "activesupport-1.3.1",
"activerecord-1.14.4/lib/../../activesupport", "activerecord-1.14.4",
"rake-0.7.1"]

Thanks!

Actually, wait a minute -- the app also uses ImageMagick, but that
didn't show up here.
 
D

Devin Mullins

Giles said:
Is it the Perl-y $: thing that gives it its magic special sauce?
Yup. $: == $LOAD_PATH == the list of directories Ruby looks in when you
do a require. FWIW, $" == $LOADED_FEATURES == the list of files (ruby
and .so) that have been require'd.
Also,
couldn't the Regexp part work just as well without the Config stuff,
because of the minimal likelihood of a non-gem having that string in
its path?
I was just trying to be a little robust. It just expands to
/usr/local/lib or c:/prog/ruby/lib or whatever. *Very* unlikely that
that path would contain a regex metacharacter that needs escaping, too,
but what the hell. Yeah, you certainly could do:
$:.map{|s|s=~%r{ruby/gems/1.8/gems/([^/]+)/lib$};$1}.compact.uniq
Actually, wait a minute -- the app also uses ImageMagick, but that
didn't show up here.
You might not have triggered the loading of the code that actually
depends on it. ActiveSupport overrides const_missing so you need not
require everything. (At least, for... I blogsumed that the feature is
being deprecated, or at least limited to your own rb files.)

Devin
 
E

Eric Hodel

Is there an easy way to find out all the gems you're running in a
particular codebase? (It's a Rails app but I'd imagine the technique
has general usefulness?)

Gem::SourceIndex.from_installed_gems.search(//).map { |spec|
spec.full_name } # *

You get back an Array of Gem::Specification objects.

(I should fix that search in there.)

* I'm running from SVN, but this should still work.
 
G

Giles Bowkett

I think I should submit this question to Ruby Quiz. your approach is
very complete, but overkill -- it gives me everything on my system,
rather than everything my app is actually using. Devin's solution gave
me everything my app was using at the moment I ran the command, but
missed things which were used in the app but not yet loaded.
 
E

Eric Hodel

I think I should submit this question to Ruby Quiz. your approach is
very complete, but overkill -- it gives me everything on my system,
rather than everything my app is actually using.

Oh, sorry.

require 'rubygems'
require 'inline'

class << Gem; attr_reader :loaded_specs; end

p Gem.loaded_specs.keys

I'll make this cleaner.
Devin's solution gave me everything my app was using at the moment =20
I ran the command, but missed things which were used in the app but =20=
not yet loaded.

I don't see how you could possibly expect to know what files would be =20=

loaded by your program in the future.

--=20
Eric Hodel - (e-mail address removed) - http://blog.segment7.net

A: Yes
Q: Is top-posting bad?
=97 Derek Milhous Zumsteg
 
E

Eric Hodel

Oh, sorry.

require 'rubygems'
require 'inline'

class << Gem; attr_reader :loaded_specs; end

p Gem.loaded_specs.keys

I'll make this cleaner.

Ok, This will be going in once rubygems is up. Same interface.
 
G

Giles Bowkett

Devin's solution gave me everything my app was using at the moment
I don't see how you could possibly expect to know what files would be
loaded by your program in the future.

Well, that's the challenge, isn't it? It's only when you start to hack
time-travel knowledge discovery problems that you discover how truly
astounding Ruby's dynamicity is.

Seriously a human can do it just by looking at the source. There were
image magick things in there, they weren't caught by checking all gems
currently in use. Maybe because the code lives in a plugins dir and
wasn't invoked yet? I don't know.
 
E

Eric Hodel

Well, that's the challenge, isn't it? It's only when you start to hack
time-travel knowledge discovery problems that you discover how truly
astounding Ruby's dynamicity is.

Seriously a human can do it just by looking at the source.

Not accurately. Load path manipulation or require order may cause
files to be loaded or not loaded contrary to your expectations.
Files may have been orphaned by the author, or your code may not need
certain files, so they won't be required.
There were image magick things in there, they weren't caught by
checking all gems
currently in use. Maybe because the code lives in a plugins dir and
wasn't invoked yet? I don't know.

Which is why human inspection doesn't work.
 
A

ara.t.howard

Not accurately. Load path manipulation or require order may cause files to
be loaded or not loaded contrary to your expectations. Files may have been
orphaned by the author, or your code may not need certain files, so they
won't be required.

and, of course, it can be even more pathalogical

require 'find'
Find.find($:[rand($:.size)]{|e| break(require(e)) if rand > 0.42}

nevermind code generation and subsequent inclusion!

;-)

-a
 
D

Devin Mullins

and, of course, it can be even more pathalogical

require 'find'
Find.find($:[rand($:.size)]{|e| break(require(e)) if rand > 0.42}

nevermind code generation and subsequent inclusion!
not to mention:
def require; false end

Devin
(or some screwball impl involving reverse, rot13...)
 
T

Tom Pollard

Not accurately. Load path manipulation or require order may cause
files to be loaded or not loaded contrary to your expectations.
Files may have been orphaned by the author, or your code may not
need certain files, so they won't be required.

Granted, but that's not a good reason to not to do what you can.
Based on a static analysis of the code, you can figure out what most
of the module dependencies are, or even all of the module
dependencies in most cases. Being able to identify the modules a
script loads automatically is a necessary step for tools like
PerlApp, perl2exe, PAR/pp, py2app, py2exe, etc. which produce
executables from Perl and Python scripts by bundling the script, the
interpreter and the dependent modules in a self-extracting,
executable archive. I don't remember what the OP here wanted this
for, but what they're asking for is not impractical or silly, and the
problems people are citing with it are not unique to ruby.

If you're not familiar with the Perl and Python products I mentioned,
here are some references:

PAR http://par.perl.org/wiki/Main_Page
Module::ScanDeps http://search.cpan.org/dist/Module-ScanDeps/
py2app http://svn.pythonmac.org/py2app/py2app/trunk/doc/index.html
PerlApp http://aspn.activestate.com/ASPN/docs/PDK/6.0/
PerlApp_overview.html
py2exe http://www.py2exe.org/

I noticed (while Googling) that there is a similar Ruby project
already. Presumably it already does this sort of dependency analysis
in one form or another.

rubyscript2exe http://www.erikveen.dds.nl/rubyscript2exe/index.html

Cheers,

Tom
 

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
474,220
Messages
2,571,128
Members
47,744
Latest member
FrederickM

Latest Threads

Top