[前][次][番号順一覧][スレッド一覧]

ruby-changes:31689

From: drbrain <ko1@a...>
Date: Fri, 22 Nov 2013 08:27:42 +0900 (JST)
Subject: [ruby-changes:31689] drbrain:r43767 (trunk): * lib/rubygems: Update to RubyGems master 50a8210. Important changes

drbrain	2013-11-22 08:27:30 +0900 (Fri, 22 Nov 2013)

  New Revision: 43767

  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=43767

  Log:
    * lib/rubygems:  Update to RubyGems master 50a8210.  Important changes
      in this commit:
    
      RubyGems now automatically checks for gem.deps.rb or Gemfile when
      running ruby executables.  This behavior is similar to `bundle exec
      rake`.  This change may be reverted before Ruby 2.1.0 if too many bugs
      are found.
    
    * test/rubygems:  ditto.

  Modified files:
    trunk/ChangeLog
    trunk/lib/rubygems/doctor.rb
    trunk/lib/rubygems/exceptions.rb
    trunk/lib/rubygems/request_set/gem_dependency_api.rb
    trunk/lib/rubygems/request_set.rb
    trunk/lib/rubygems/resolver/api_set.rb
    trunk/lib/rubygems/resolver/api_specification.rb
    trunk/lib/rubygems/resolver/composed_set.rb
    trunk/lib/rubygems/resolver/conflict.rb
    trunk/lib/rubygems/resolver/git_set.rb
    trunk/lib/rubygems/resolver/requirement_list.rb
    trunk/lib/rubygems/resolver.rb
    trunk/lib/rubygems/source/git.rb
    trunk/lib/rubygems/source.rb
    trunk/lib/rubygems/specification.rb
    trunk/lib/rubygems/test_case.rb
    trunk/lib/rubygems/util.rb
    trunk/lib/rubygems.rb
    trunk/test/rubygems/test_gem.rb
    trunk/test/rubygems/test_gem_impossible_dependencies_error.rb
    trunk/test/rubygems/test_gem_request_set.rb
    trunk/test/rubygems/test_gem_request_set_gem_dependency_api.rb
    trunk/test/rubygems/test_gem_resolver.rb
    trunk/test/rubygems/test_gem_resolver_api_set.rb
    trunk/test/rubygems/test_gem_resolver_api_specification.rb
    trunk/test/rubygems/test_gem_resolver_conflict.rb
    trunk/test/rubygems/test_gem_resolver_git_set.rb
    trunk/test/rubygems/test_gem_source_git.rb
    trunk/test/rubygems/test_gem_specification.rb
    trunk/test/rubygems/test_gem_util.rb
Index: ChangeLog
===================================================================
--- ChangeLog	(revision 43766)
+++ ChangeLog	(revision 43767)
@@ -1,3 +1,15 @@ https://github.com/ruby/ruby/blob/trunk/ChangeLog#L1
+Fri Nov 22 08:27:13 2013  Eric Hodel  <drbrain@s...>
+
+	* lib/rubygems:  Update to RubyGems master 50a8210.  Important changes
+	  in this commit:
+
+	  RubyGems now automatically checks for gem.deps.rb or Gemfile when
+	  running ruby executables.  This behavior is similar to `bundle exec
+	  rake`.  This change may be reverted before Ruby 2.1.0 if too many bugs
+	  are found.
+
+	* test/rubygems:  ditto.
+
 Thu Nov 21 22:33:59 2013  Koichi Sasada  <ko1@a...>
 
 	* gc.c: RGENGC_CHECK_MODE should be 0.
Index: lib/rubygems/request_set.rb
===================================================================
--- lib/rubygems/request_set.rb	(revision 43766)
+++ lib/rubygems/request_set.rb	(revision 43767)
@@ -2,6 +2,7 @@ require 'rubygems' https://github.com/ruby/ruby/blob/trunk/lib/rubygems/request_set.rb#L2
 require 'rubygems/dependency'
 require 'rubygems/dependency_list'
 require 'rubygems/installer'
+require 'rubygems/resolver'
 require 'tsort'
 
 ##
@@ -146,7 +147,15 @@ class Gem::RequestSet https://github.com/ruby/ruby/blob/trunk/lib/rubygems/request_set.rb#L147
 
     resolve
 
-    install options, &block
+    if options[:explain]
+      puts "Gems to install:"
+
+      specs.map { |s| s.full_name }.sort.each do |s|
+        puts "  #{s}"
+      end
+    else
+      install options, &block
+    end
   end
 
   def install_into dir, force = true, options = {}
@@ -201,7 +210,7 @@ class Gem::RequestSet https://github.com/ruby/ruby/blob/trunk/lib/rubygems/request_set.rb#L210
   # Resolve the requested dependencies and return an Array of Specification
   # objects to be activated.
 
-  def resolve set = Gem::Resolver::IndexSet.new
+  def resolve set = Gem::Resolver::BestSet.new
     @sets << set
     @sets << @git_set
     @sets << @vendor_set
@@ -253,7 +262,7 @@ class Gem::RequestSet https://github.com/ruby/ruby/blob/trunk/lib/rubygems/request_set.rb#L262
         end
       else
         unless @soft_missing
-          raise Gem::DependencyError, "Unresolved depedency found during sorting - #{dep}"
+          raise Gem::DependencyError, "Unresolved dependency found during sorting - #{dep} (requested by #{node.spec.full_name})"
         end
       end
     end
Index: lib/rubygems/specification.rb
===================================================================
--- lib/rubygems/specification.rb	(revision 43766)
+++ lib/rubygems/specification.rb	(revision 43767)
@@ -27,6 +27,7 @@ class Date; end https://github.com/ruby/ruby/blob/trunk/lib/rubygems/specification.rb#L27
 #   Gem::Specification.new do |s|
 #     s.name        = 'example'
 #     s.version     = '0.1.0'
+#     s.licenses    = ['MIT']
 #     s.summary     = "This is an example!"
 #     s.description = "Much longer explanation of the example!"
 #     s.authors     = ["Ruby Coder"]
@@ -530,6 +531,7 @@ class Gem::Specification < Gem::BasicSpe https://github.com/ruby/ruby/blob/trunk/lib/rubygems/specification.rb#L531
   end
 
   ##
+  # :category: Recommended gemspec attributes
   # The license for this gem.
   #
   # The license must be a short name, no more than 64 characters.
@@ -538,7 +540,12 @@ class Gem::Specification < Gem::BasicSpe https://github.com/ruby/ruby/blob/trunk/lib/rubygems/specification.rb#L540
   # text of the license should be inside of the gem when you build it.
   #
   # See http://opensource.org/licenses/alphabetical for a list of licenses and
-  # their abbreviations (or short names).
+  # their abbreviations (or short names).  GitHub also provides a
+  # license picker at http://choosealicense.com/
+  #
+  #  According to copyright law, not having an OSI-approved open source license
+  #  means you have no rights to use the code for any purpose-- in other words,
+  #  "all rights reserved".
   #
   # You can set multiple licenses with #licenses=
   #
@@ -550,6 +557,7 @@ class Gem::Specification < Gem::BasicSpe https://github.com/ruby/ruby/blob/trunk/lib/rubygems/specification.rb#L557
   end
 
   ##
+  # :category: Recommended gemspec attributes
   # The license(s) for the library.
   #
   # Each license must be a short name, no more than 64 characters.
@@ -2526,8 +2534,8 @@ class Gem::Specification < Gem::BasicSpe https://github.com/ruby/ruby/blob/trunk/lib/rubygems/specification.rb#L2534
     }
 
     warning <<-warning if licenses.empty?
-licenses is empty.  Use a license abbreviation from:
-  http://opensource.org/licenses/alphabetical
+licenses is empty, but is recommended.  Use a license abbreviation from:
+http://opensource.org/licenses/alphabetical
     warning
 
     validate_permissions
Index: lib/rubygems/exceptions.rb
===================================================================
--- lib/rubygems/exceptions.rb	(revision 43766)
+++ lib/rubygems/exceptions.rb	(revision 43767)
@@ -223,7 +223,7 @@ class Gem::UnsatisfiableDependencyError https://github.com/ruby/ruby/blob/trunk/lib/rubygems/exceptions.rb#L223
   attr_reader :dependency
 
   ##
-  # Creates a new UnsatisfiableDepedencyError for the unsatisfiable
+  # Creates a new UnsatisfiableDependencyError for the unsatisfiable
   # Gem::Resolver::DependencyRequest +dep+
 
   def initialize dep, platform_mismatch=nil
Index: lib/rubygems/source/git.rb
===================================================================
--- lib/rubygems/source/git.rb	(revision 43766)
+++ lib/rubygems/source/git.rb	(revision 43767)
@@ -36,9 +36,11 @@ class Gem::Source::Git < Gem::Source https://github.com/ruby/ruby/blob/trunk/lib/rubygems/source/git.rb#L36
   attr_reader :need_submodules
 
   ##
-  # Creates a new git gem source for a gem with the given +name+ that will be
-  # loaded from +reference+ in +repository+.  If +submodules+ is true,
-  # submodules will be checked out when the gem is installed.
+  # Creates a new git gem source for a gems from loaded from +repository+ at
+  # the given +reference+.  The +name+ is only used to track the repository
+  # back to a gem dependencies file, it has no real significance as a git
+  # repository may contain multiple gems.  If +submodules+ is true, submodules
+  # will be checked out when the gem is installed.
 
   def initialize name, repository, reference, submodules = false
     super(nil)
@@ -126,34 +128,6 @@ class Gem::Source::Git < Gem::Source https://github.com/ruby/ruby/blob/trunk/lib/rubygems/source/git.rb#L128
   end
 
   ##
-  # Loads a Gem::Specification for +name+ from this git repository.
-
-  def load_spec name
-    cache
-
-    gemspec_reference = "#{@reference}:#{name}.gemspec"
-
-    Dir.chdir repo_cache_dir do
-      source = Gem::Util.popen @git, 'show', gemspec_reference
-
-      source.force_encoding Encoding::UTF_8 if Object.const_defined? :Encoding
-      source.untaint
-
-      begin
-        spec = eval source, binding, gemspec_reference
-
-        return spec if Gem::Specification === spec
-
-        warn "git gem specification for #{@repository} #{gemspec_reference} is not a Gem::Specification (#{spec.class} instead)."
-      rescue SignalException, SystemExit
-        raise
-      rescue SyntaxError, Exception
-        warn "invalid git gem specification for #{@repository} #{gemspec_reference}"
-      end
-    end
-  end
-
-  ##
   # The directory where the git gem's repository will be cached.
 
   def repo_cache_dir # :nodoc:
@@ -164,12 +138,29 @@ class Gem::Source::Git < Gem::Source https://github.com/ruby/ruby/blob/trunk/lib/rubygems/source/git.rb#L138
   # Converts the git reference for the repository into a commit hash.
 
   def rev_parse # :nodoc:
-    # HACK no safe equivalent of ` exists on 1.8.7
     Dir.chdir repo_cache_dir do
       Gem::Util.popen(@git, 'rev-parse', @reference).strip
     end
   end
 
+  ##
+  # Loads all gemspecs in the repository
+
+  def specs
+    checkout
+
+    Dir.chdir install_dir do
+      Dir['{,*,*/*}.gemspec'].map do |spec_file|
+        directory = File.dirname spec_file
+        file      = File.basename spec_file
+
+        Dir.chdir directory do
+          Gem::Specification.load file
+        end
+      end.compact
+    end
+  end
+
   ##
   # A hash for the git gem based on the git repository URI.
 
Index: lib/rubygems/util.rb
===================================================================
--- lib/rubygems/util.rb	(revision 43766)
+++ lib/rubygems/util.rb	(revision 43767)
@@ -40,27 +40,24 @@ module Gem::Util https://github.com/ruby/ruby/blob/trunk/lib/rubygems/util.rb#L40
   # for a command.
 
   def self.popen *command
-    begin
-      r, = IO.popen command, &:read
-    rescue TypeError # ruby 1.8 only supports string command
-      r, w = IO.pipe
-
-      pid = fork do
-        STDIN.close
-        STDOUT.reopen w
-
-        exec(*command)
-      end
-
-      w.close
-
-      begin
-        return r.read
-      ensure
-        Process.wait pid
-      end
+    IO.popen command, &:read
+  rescue TypeError # ruby 1.8 only supports string command
+    r, w = IO.pipe
+
+    pid = fork do
+      STDIN.close
+      STDOUT.reopen w
+
+      exec(*command)
     end
 
+    w.close
+
+    begin
+      return r.read
+    ensure
+      Process.wait pid
+    end
   end
 
 end
Index: lib/rubygems/source.rb
===================================================================
--- lib/rubygems/source.rb	(revision 43766)
+++ lib/rubygems/source.rb	(revision 43767)
@@ -1,13 +1,30 @@ https://github.com/ruby/ruby/blob/trunk/lib/rubygems/source.rb#L1
 require 'uri'
 require 'fileutils'
 
+##
+# A Source knows how to list and fetch gems from a RubyGems marshal index.
+#
+# There are other Source subclasses for installed gems, local gems, the
+# bundler dependency API and so-forth.
+
 class Gem::Source
-  FILES = {
+
+  include Comparable
+
+  FILES = { # :nodoc:
     :released   => 'specs',
     :latest     => 'latest_specs',
     :prerelease => 'prerelease_specs',
   }
 
+  ##
+  # The URI this source will fetch gems from.
+
+  attr_reader :uri
+
+  ##
+  # Creates a new Source which will use the index located at +uri+.
+
   def initialize(uri)
     unless uri.kind_of? URI
       uri = URI.parse(uri.to_s)
@@ -17,13 +34,17 @@ class Gem::Source https://github.com/ruby/ruby/blob/trunk/lib/rubygems/source.rb#L34
     @api_uri = nil
   end
 
-  attr_reader :uri
+  ##
+  # Use an SRV record on the host to look up the true endpoint for the index.
 
-  def api_uri
+  def api_uri # :nodoc:
     require 'rubygems/remote_fetcher'
     @api_uri ||= Gem::RemoteFetcher.fetcher.api_endpoint uri
   end
 
+  ##
+  # Sources are ordered by installation preference.
+
   def <=>(other)
     case other
     when Gem::Source::Installed,
@@ -46,13 +67,11 @@ class Gem::Source https://github.com/ruby/ruby/blob/trunk/lib/rubygems/source.rb#L67
     end
   end
 
-  include Comparable
-
-  def ==(other)
+  def == other # :nodoc:
     self.class === other and @uri == other.uri
   end
 
-  alias_method :eql?, :==
+  alias_method :eql?, :== # :nodoc:
 
   ##
   # Returns a Set that can fetch specifications from this source.
@@ -70,7 +89,7 @@ class Gem::Source https://github.com/ruby/ruby/blob/trunk/lib/rubygems/source.rb#L89
     end
   end
 
-  def hash
+  def hash # :nodoc:
     @uri.hash
   end
 
@@ -83,6 +102,9 @@ class Gem::Source https://github.com/ruby/ruby/blob/trunk/lib/rubygems/source.rb#L102
     File.join Gem.spec_cache_dir, "#{uri.host}%#{uri.port}", File.dirname(escaped_path)
   end
 
+  ##
+  # Returns true when it is possible and safe to update the cache directory.
+
   def update_cache?
     @update_cache ||=
       begin
@@ -166,6 +188,10 @@ class Gem::Source https://github.com/ruby/ruby/blob/trunk/lib/rubygems/source.rb#L188
     end
   end
 
+  ##
+  # Downloads +spec+ and writes it to +dir+.  See also
+  # Gem::RemoteFetcher#download.
+
   def download(spec, dir=Dir.pwd)
     fetcher = Gem::RemoteFetcher.fetcher
     fetcher.download spec, api_uri.to_s, dir
@@ -176,7 +202,7 @@ class Gem::Source https://github.com/ruby/ruby/blob/trunk/lib/rubygems/source.rb#L202
       q.breakable
       q.text @uri.to_s
       if api = api_uri
-        g.text api
+        q.text api.to_s
       end
     end
   end
Index: lib/rubygems/request_set/gem_dependency_api.rb
===================================================================
--- lib/rubygems/request_set/gem_dependency_api.rb	(revision 43766)
+++ lib/rubygems/request_set/gem_dependency_api.rb	(revision 43767)
@@ -115,7 +115,7 @@ class Gem::RequestSet::GemDependencyAPI https://github.com/ruby/ruby/blob/trunk/lib/rubygems/request_set/gem_dependency_api.rb#L115
   ##
   # A Hash containing gem names and files to require from those gems.
 
-  attr_reader :requires
+  attr_reader :requires # :nodoc:
 
   ##
   # A set of gems that are loaded via the +:path+ option to #gem
@@ -125,7 +125,7 @@ class Gem::RequestSet::GemDependencyAPI https://github.com/ruby/ruby/blob/trunk/lib/rubygems/request_set/gem_dependency_api.rb#L125
   ##
   # The groups of gems to exclude from installation
 
-  attr_accessor :without_groups
+  attr_accessor :without_groups # :nodoc:
 
   ##
   # Creates a new GemDependencyAPI that will add dependencies to the
@@ -282,6 +282,8 @@ class Gem::RequestSet::GemDependencyAPI https://github.com/ruby/ruby/blob/trunk/lib/rubygems/request_set/gem_dependency_api.rb#L282
     true
   end
 
+  private :gem_github
+
   ##
   # Handles the :group and :groups +options+ for the gem with the given
   # +name+.
@@ -361,7 +363,7 @@ class Gem::RequestSet::GemDependencyAPI https://github.com/ruby/ruby/blob/trunk/lib/rubygems/request_set/gem_dependency_api.rb#L363
   def gem_requires name, options # :nodoc:
     if options.include? :require then
       if requires = options.delete(:require) then
-        @requires[name].concat requires
+        @requires[name].concat Array requires
       end
     else
       @requires[name] << name
@@ -370,6 +372,11 @@ class Gem::RequestSet::GemDependencyAPI https://github.com/ruby/ruby/blob/trunk/lib/rubygems/request_set/gem_dependency_api.rb#L372
 
   private :gem_requires
 
+  ##
+  # :category: Gem Dependencies DSL
+  #
+  # Block form for specifying gems from a git +repository+.
+
   def git repository
     @current_repository = repository
 
@@ -424,6 +431,8 @@ class Gem::RequestSet::GemDependencyAPI https://github.com/ruby/ruby/blob/trunk/lib/rubygems/request_set/gem_dependency_api.rb#L431
 
   ##
   # :category: Gem Dependencies DSL
+  #
+  # Block form for restricting gems to a particular platform.
 
   def platform what
     @current_platform = what
@@ -436,6 +445,8 @@ class Gem::RequestSet::GemDependencyAPI https://github.com/ruby/ruby/blob/trunk/lib/rubygems/request_set/gem_dependency_api.rb#L445
 
   ##
   # :category: Gem Dependencies DSL
+  #
+  # Block form for restricting gems to a particular platform.
 
   alias :platforms :platform
 
Index: lib/rubygems/doctor.rb
===================================================================
--- lib/rubygems/doctor.rb	(revision 43766)
+++ lib/rubygems/doctor.rb	(revision 43767)
@@ -27,10 +27,13 @@ class Gem::Doctor https://github.com/ruby/ruby/blob/trunk/lib/rubygems/doctor.rb#L27
     ['gems',           ''],
   ]
 
-  raise 'Update REPOSITORY_EXTENSION_MAP' unless
-    Gem::REPOSITORY_SUBDIRECTORIES.sort ==
+  missing =
+    Gem::REPOSITORY_SUBDIRECTORIES.sort -
       REPOSITORY_EXTENSION_MAP.map { |(k,_)| k }.sort
 
+  raise "Update REPOSITORY_EXTENSION_MAP, missing: #{missing.join ', '}" unless
+    missing.empty?
+
   ##
   # Creates a new Gem::Doctor that will clean up +gem_repository+.  Only one
   # gem repository may be cleaned at a time.
Index: lib/rubygems/resolver/api_set.rb
===================================================================
--- lib/rubygems/resolver/api_set.rb	(revision 43766)
+++ lib/rubygems/resolver/api_set.rb	(revision 43767)
@@ -10,13 +10,28 @@ class Gem::Resolver::APISet < Gem::Resol https://github.com/ruby/ruby/blob/trunk/lib/rubygems/resolver/api_set.rb#L10
   attr_reader :dep_uri # :nodoc:
 
   ##
+  # The Gem::Source that gems are fetched from
+
+  attr_reader :source
+
+  ##
+  # The corresponding place to fetch gems.
+
+  attr_reader :uri
+
+  ##
   # Creates a new APISet that will retrieve gems from +uri+ using the RubyGems
-  # API described at http://guides.rubygems.org/rubygems-org-api
+  # API URL +dep_uri+ which is described at
+  # http://guides.rubygems.org/rubygems-org-api
+
+  def initialize dep_uri = 'https://rubygems.org/api/v1/dependencies'
+    dep_uri = URI dep_uri unless URI === dep_uri # for ruby 1.8
+
+    @dep_uri = dep_uri
+    @uri     = dep_uri + '../../..'
 
-  def initialize uri = 'https://rubygems.org/api/v1/dependencies'
-    uri = URI uri unless URI === uri # for ruby 1.8
-    @data = Hash.new { |h,k| h[k] = [] }
-    @dep_uri = uri
+    @data   = Hash.new { |h,k| h[k] = [] }
+    @source = Gem::Source.new @uri
   end
 
   ##
@@ -41,15 +56,35 @@ class Gem::Resolver::APISet < Gem::Resol https://github.com/ruby/ruby/blob/trunk/lib/rubygems/resolver/api_set.rb#L56
 
   def prefetch reqs
     names = reqs.map { |r| r.dependency.name }
-    needed = names.find_all { |d| !@data.key?(d) }
+    needed = names - @data.keys
 
     return if needed.empty?
 
     uri = @dep_uri + "?gems=#{needed.sort.join ','}"
     str = Gem::RemoteFetcher.fetcher.fetch_path uri
 
+    loaded = []
+
     Marshal.load(str).each do |ver|
-      @data[ver[:name]] << ver
+      name = ver[:name]
+
+      @data[name] << ver
+      loaded << name
+    end
+
+    (needed - loaded).each do |missing|
+      @data[missing] = []
+    end
+  end
+
+  def pretty_print q # :nodoc:
+    q.group 2, '[APISet', ']' do
+      q.breakable
+      q.text "URI: #{@dep_uri}"
+
+      q.breakable
+      q.text 'gem names:'
+      q.pp @data.keys
     end
   end
 
Index: lib/rubygems/resolver/composed_set.rb
===================================================================
--- lib/rubygems/resolver/composed_set.rb	(revision 43766)
+++ lib/rubygems/resolver/composed_set.rb	(revision 43767)
@@ -1,17 +1,36 @@ https://github.com/ruby/ruby/blob/trunk/lib/rubygems/resolver/composed_set.rb#L1
+##
+# A ComposedSet allows multiple sets to be queried like a single set.
+#
+# To create a composed set with any number of sets use:
+#
+#   Gem::Resolver.compose_sets set1, set2
+#
+# This method will eliminate nesting of composed sets.
+
 class Gem::Resolver::ComposedSet < Gem::Resolver::Set
 
   attr_reader :sets # :nodoc:
 
+  ##
+  # Creates a new ComposedSet containing +sets+.  Use
+  # Gem::Resolver::compose_sets instead.
+
   def initialize *sets
     @sets = sets
   end
 
+  ##
+  # Finds all specs matching +req+ in all sets.
+
   def find_all req
     res = []
     @sets.each { |s| res += s.find_all(req) }
     res
   end
 
+  ##
+  # Prefetches +reqs+ in all sets.
+
   def prefetch reqs
     @sets.each { |s| s.prefetch(reqs) }
   end
Index: lib/rubygems/resolver/requirement_list.rb
===================================================================
--- lib/rubygems/resolver/requirement_list.rb	(revision 43766)
+++ lib/rubygems/resolver/requirement_list.rb	(revision 43767)
@@ -37,4 +37,8 @@ class Gem::Resolver::RequirementList https://github.com/ruby/ruby/blob/trunk/lib/rubygems/resolver/requirement_list.rb#L37
   def remove
     @list.shift
   end
+
+  def next5
+    @list[0,5]
+  end
 end
Index: lib/rubygems/resolver/git_set.rb
===================================================================
--- lib/rubygems/resolver/git_set.rb	(revision 43766)
+++ lib/rubygems/resolver/git_set.rb	(revision 43767)
@@ -42,38 +42,27 @@ class Gem::Resolver::GitSet < Gem::Resol https://github.com/ruby/ruby/blob/trunk/lib/rubygems/resolver/git_set.rb#L42
   # Finds all git gems matching +req+
 
   def find_all req
-    @repositories.keys.select do |name|
-      name == req.name
-    end.map do |name|
-      @specs[name] || load_spec(name)
-    e (... truncated)

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]