[Rubygems-developers] Design notes for RubyGems 2

Gavin Sinclair gsinclair at soyabean.com.au
Tue Jun 8 19:15:26 EDT 2004


On Wednesday, June 9, 2004, 4:15:52 AM, Curt wrote:

> Chad Fowler wrote:
>>
>> On Wed, 9 Jun 2004, Gavin Sinclair wrote:
>>
>> # The reality is that RubyGems is pretty simple.  I want an interface to
>> # the main thing in the system - the collection of gems - that is also
>> # simple.  Tell it want you want and you get it.  Obviously that needs
>> # to be codified somewhat.  But the current system is more like
>> # low-level scratching than high-level ease.
>> #
>>
>> Agreed on the simplicity comment.  To me, the interface you're talking
>> about looks something like this:
>>
>> Gem::Cache.from_installed_gems.each do |gemspec|
>>    Gem::DocManager.new(gemspec).generate_rdoc
>> end
>>
>> There might be some things lacking, but I'd like to see them built based
>> on a concrete need for them.

> Why not:

>   repo = new Repository(LOCALHOST)
>   repo.each_installed_gem do |gem|
>     gem.generate_rdoc
>   end

> (Of course, the first two lines could be written as one line.)

I'll go you halfway.  Generating RDoc is a process, so I'd use
Tools::RDocGenerator to implement that process.  Now you don't
actually need a Gem for that; you need a directory (that's where turn
'rdoc' loose) and the gemspec (giving you RDoc options, etc.).

   # We don't create Repositories often; they are long-living objects
   # that know about all local and remote gems.  So we just use the
   # 'repo' object that's available to us.

   installed_gems = repo.gem_report(:installed)
    # -> [ GemResource<rake, 0.3.2, :installed, /usr/lib/ruby/gems/1.8>,
           GemResource<pqa,  0.6,   :installed, /usr/lib/ruby/gems/1.8>,
           ... ]

   installed_gems.each do |gem_resource|
     Tools::RDocGenerator.generate(gem_resource)
   end

In Chad's example, "Gem::DocManager.new(gemspec).generate_rdoc" has no
way of knowing *where* the gem is installed.  Not even Cache can tell
it.

In Curt's example, a Gem object (if that's what 'gem' is) knows how to
generate RDoc, which is an inappropriate abstraction, I believe.
    
> A GUI gems browser is going to want to have a navigation tree control that
> can enumerate known repositories (local and remote) and the gems within each
> repository. Once enumerated and displayed, if the user selects an item in
> the GUI tree, it needs to know what that corresponds to.

In my design, as demonstrated above, the Repository gives you
GemResource objects.  Given a random GemResource object 'gr', you can:

  gr.name               -> rake
  gr.version            -> 0.3.2
  gr.installed?         -> false
  gr.cellared?          -> false
  gr.remote?            -> true
  gr.location_category  -> :remote
  gr.source             -> 'http://raa.ruby-lang.org/gems'

You want to retrieve this gem?

  gem = repo.get_gem(gr)

  gem.name              -> rake
  gem.version           -> 0.3.2
  gem.fullname          -> rake-0.3.2
  gem.spec              -> Gem::Specification<...>
  gem.data              -> "..." (raw data)
  gem.extract("README") -> "..."
  gem.extract_all do |path, data|
    # Hey, installation is pretty easy with this!
  end

Now we can cellar it:

  Tools::Cellar.cellar(gem, base_dir)
    # Rough implementation:
    #
    #   cellar_dir = Directories.cellar(base_dir)
    #   cellar_path = File.join(cellar_dir, gem.fullname + '.gem')
    #   File.write(cellar_path, gem.data)

Or install it:

  Tools::Installer.install(gem, base_dir, repo)
    # Rough implementation
    #
    #     # Deal with dependencies.
    #   gem.spec.dependencies.each do |name, version_req|
    #     unless repo.installed?(name, version_req)
    #         # Communicate with app somehow to confirm installation.
    #       dep_gem = repo.get_gem(name, version_req)
    #         Installer.install(dep_gem, base_dir, repo)
    #       end
    #     end
    #   end
    #
    #     # Now deal with the gem at hand.
    #   install_dir = Directories.installation(base_dir, gem)
    #   FileUtils.mkdir(install_dir)
    #   Dir.chdir(install_dir) do
    #     gem.extract_all do |path, data|
    #       FileUtils.mkdir_p(File.dirname(path))
    #       File.write(path, data)
    #     end
    #   end

Or if we have an _installed_ GemResource and we want to uninstall it:

  gr.installed?                -> true
  gr.source                    -> '/usr/lib/uby/gems/1.8'

  Tools::Uninstaller.uninstall(gr)
    # Rough implementation.
    #
    #   return unless gr.installed?
    #   base_dir = gr.source
    #   install_dir = Directories.installation(base_dir)
    #   FileUtils.rm_f(install_dir)


I hope that gives I decent idea of the API I had in mind.  All of that
is off the top of my head, so there could be inconsistencies or room
for improvement in there.

Cheers,
Gavin





More information about the Rubygems-developers mailing list