Finding Libraries by Querying Gem Respositories
Problem
You want to find new gems to install on your system, or see which gems you already have installed.
Solution
From the command line, use gems query command:
$ gem query *** LOCAL GEMS *** sources (0.0.1) This package provides download sources for remote gem installation $ gem query --remote *** REMOTE GEMS *** actionmailer (1.1.1, 1.0.1, 1.0.0, 0.9.1, 0.9.0, 0.8.1, …) Service layer for easy email delivery and testing. actionpack (1.10.1, 1.9.1, 1.9.0, 1.8.1, 1.8.0, 1.7.0, …) Web-flow and rendering framework putting the VC in MVC. [… Much more output omitted ….]
From Ruby code, use Gem::cache to query your locally installed gems, and Gem::RemoteInstaller#search to query the gems on some other site. Gem::cache can be treated as an Enumerable full of tasty Gem::Specification objects. Gem::Remote-Installer#search returns an Array containing an Array of Gem::Specification objects for every remote source it searched. Usually there will only be one remote sourcethe main gem repository on rubyforge.org.
This Ruby code iterates over the locally installed gems:
require ubygems Gem::cache.each do |name, gem| puts %{"#{gem.name}" gem version #{gem.version} is installed.} end # "sources" gem version 0.0.1 is installed
The format_gems method defined below gives a convenient way of looking at a large set of Gem::Specification objects. It groups the gems by name and version, then prints a formatted list:
require ubygems/remote_installer require yaml def format_gems(gems) gem_versions = gems.inject({}) { |h, gem| (h[gem.name] ||= []) << gem; h} gem_versions.keys.sort.each do |name| versions = gem_versions[name].collect { |gem| gem.version.to_s } puts "#{name} is available in these versions: #{versions.join(, )}" end end
Here it is being run on the gems available from RubyForge:
format_gems(Gem::RemoteInstaller.new.search(/.*/).flatten) # Asami is available in these versions: 0.04 # Bangkok is available in these versions: 0.1.0 # Bloglines4R is available in these versions: 0.1.0 # BlueCloth is available in these versions: 0.0.2, 0.0.3, 0.0.4, 1.0.0 # …
Discussion
Not only are Ruby gems a convenient packaging mechanism, they e an excellent way to find out about new pieces of Ruby code. The gem repository at rubyforge.org is the canonical location for Ruby libraries, so youve got one place to find new code.
You can query the gems library for gems whose names match a certain regular expression:
$ gem query --remote --name-matches "test" ** REMOTE GEMS *** lazytest (0.1.0) Testing and benchmarking for lazy people test-unit-mock (0.30) Test::Unit::Mock is a class for conveniently building mock objects in Test::Unit test cases. testunitxml (0.1.4, 0.1.3) Unit test suite for XML documents ZenTest (3.1.0, 3.0.0) == FEATURES/PROBLEMS
Or, from Ruby code:
format_ gems(Gem::RemoteInstaller.new.search(/test/i).flatten) # ZenTest is available in these versions: 3.0.0, 3.1.0 # lazytest is available in these versions: 0.1.0 # test-unit-mock is available in these versions: 0.30 # testunitxml is available in these versions: 0.1.3, 0.1.4
This method finds gems that are newer than a certain date. It has to keep around both a Date and a Time object for comparisons, because RubyForge stores some gems dates as Date objects, some as Time objects, and some as string representations of dates.[1]
[1] This is because of differences in the underlying gem specification files. Different people build their gemspecs in different ways.
require date def gems_newer_than(date, query=/.*/) time = Time.local(date.year, date.month, date.day, 0, 0, 0) gems = Gem::RemoteInstaller.new.search(query).flatten gems.reject do |gem| gem_date = gem.date gem_date = DateTime.parse(gem_date) if gem_date.respond_to? :to_str gem_date < (gem_date.is_a?(Date) ? date : time) end end todays_gems = gems_newer_than(Date.today-1) todays_gems.size #=> 7 format_gems(todays_gems) # filament is available in these versions: 0.3.0 # mechanize is available in these versions: 0.4.1 # mongrel is available in these versions: 0.3.12.1, 0.3.12.1 # rake is available in these versions: 0.7.1 # rspec is available in these versions: 0.5.0 # tzinfo is available in these versions: 0.2.0
By default, remote queries look only at the main gem repository on rubyforge.org:
Gem::RemoteInstaller.new.sources # => ["http://gems.rubyforge.org"]
To query a gem repository other than rubyforge.org, pass in the URL to the repository as the --source argument from the command line. This code starts a gem server on the local machine (it can serve all of your installed gems to other machines), and queries it:
$ gem_server & $ gem query --remote --source http://localhost:8808 # *** REMOTE GEMS *** # Updating Gem source index for: http://localhost:8808 # sources (0.0.1) # This package provides download sources for remote gem installation
From Ruby code, modify the Gem.sources variable to retrieve gems from another source:
Gem.sources.replace([http://localhost:8808]) format_ gems(Gem::RemoteInstaller.new.search(/.*/).flatten) # sources is available in these versions: 0.0.1
See Also
- Recipe 18.7, "Distributing Your Gems," for more on hosting your own gem repository
- The Ruby Application Archive is a companion to rubyforge.org: rather than hosting Ruby projects, it links to Ruby packages hosted all around the Web; you e more likely to see projects on the RAA that aren packaged as gems (see Recipe 18.8 for tips on installing them)
Категории