gem_info 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ README.rdoc
2
+ lib/**/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ LICENSE
data/.gitignore ADDED
@@ -0,0 +1,5 @@
1
+ *.sw?
2
+ .DS_Store
3
+ coverage
4
+ rdoc
5
+ pkg
data/DESCRIPTION ADDED
@@ -0,0 +1,6 @@
1
+ A rubygems plugin which adds an `info' command which prints
2
+ information about gems.
3
+
4
+ Unlike the built-in gem commands, it allows fuzzy matching on gem
5
+ names and versions by default, and allows precise formatting of the
6
+ output, making it easy on the command line and in scripts.
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 George Ogata
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,55 @@
1
+ = Gem Info
2
+
3
+ A rubygems plugin which adds an `info' command that prints information
4
+ about installed gems.
5
+
6
+ Unlike the built-in gem commands, it allows fuzzy matching on gem
7
+ names and versions by default, and allows precise formatting of the
8
+ output, making it easy on the command line and in scripts.
9
+
10
+ == Examples
11
+
12
+ View dependencies at a glance:
13
+
14
+ $ gem info -f '%name-%version: %dependencies' act
15
+ activesupport-2.3.3:
16
+ activesupport-2.3.4:
17
+ activeresource-2.3.4: activesupport = 2.3.4
18
+ activerecord-2.3.4: activesupport = 2.3.4
19
+ actionpack-2.3.4: activesupport = 2.3.4, rack ~> 1.0.0
20
+ actionmailer-2.3.4: actionpack = 2.3.4
21
+
22
+ Handy alias to `cd' to a gem directory:
23
+
24
+ function cdrg {
25
+ if [ $# -eq 0 ]; then
26
+ cd `gem env gemdir`/gems
27
+ elif gem info --exactly-one $@ > /dev/null; then
28
+ local dir=`gem info -f '%path' $@`
29
+ if [ -d $dir/lib ]; then
30
+ cd $dir/lib
31
+ else
32
+ cd $dir
33
+ fi
34
+ fi
35
+ }
36
+
37
+ $ cdrg rails # oops!
38
+ 2 matching gems:
39
+ rails 2.3.3
40
+ rails 2.3.4
41
+ $ cdrg rails 4 # only 2.3.4 contains '4'
42
+ $ pwd
43
+ /usr/lib/ruby/gems/1.8/gems/rails-2.3.4/lib
44
+
45
+ == Contributing
46
+
47
+ * Bug reports: http://github.com/oggy/gem_info/issues
48
+ * Source: http://github.com/oggy/gem_info
49
+ * Patches: Fork on Github, send pull request.
50
+ * Ensure patch includes tests.
51
+ * Leave the version alone, or bump it in a separate commit.
52
+
53
+ == Copyright
54
+
55
+ Copyright (c) 2009 George Ogata. See LICENSE for details.
data/Rakefile ADDED
@@ -0,0 +1,49 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "gem_info"
8
+ gem.summary = "Print information about gems."
9
+ gem.description = File.read('DESCRIPTION')
10
+ gem.email = "george.ogata@gmail.com"
11
+ gem.homepage = "http://github.com/oggy/gem_info"
12
+ gem.authors = ["George Ogata"]
13
+ gem.required_rubygems_version = '>= 1.3.2' # 1.3.2 introduced plugins
14
+ gem.add_development_dependency "rspec"
15
+ gem.add_development_dependency "mocha"
16
+ end
17
+ rescue LoadError
18
+ puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
19
+ end
20
+
21
+ require 'spec/rake/spectask'
22
+ Spec::Rake::SpecTask.new(:spec) do |spec|
23
+ spec.libs << 'lib' << 'spec'
24
+ spec.spec_files = FileList['spec/**/*_spec.rb']
25
+ end
26
+
27
+ Spec::Rake::SpecTask.new(:rcov) do |spec|
28
+ spec.libs << 'lib' << 'spec'
29
+ spec.pattern = 'spec/**/*_spec.rb'
30
+ spec.rcov = true
31
+ end
32
+
33
+ task :spec => :check_dependencies
34
+
35
+ task :default => :spec
36
+
37
+ require 'rake/rdoctask'
38
+ Rake::RDocTask.new do |rdoc|
39
+ if File.exist?('VERSION')
40
+ version = File.read('VERSION')
41
+ else
42
+ version = ""
43
+ end
44
+
45
+ rdoc.rdoc_dir = 'rdoc'
46
+ rdoc.title = "gem_info #{version}"
47
+ rdoc.rdoc_files.include('README*')
48
+ rdoc.rdoc_files.include('lib/**/*.rb')
49
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.1
data/gem_info.gemspec ADDED
@@ -0,0 +1,70 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{gem_info}
8
+ s.version = "0.0.1"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 1.3.2") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["George Ogata"]
12
+ s.date = %q{2010-03-17}
13
+ s.description = %q{A rubygems plugin which adds an `info' command which prints
14
+ information about gems.
15
+
16
+ Unlike the built-in gem commands, it allows fuzzy matching on gem
17
+ names and versions by default, and allows precise formatting of the
18
+ output, making it easy on the command line and in scripts.
19
+ }
20
+ s.email = %q{george.ogata@gmail.com}
21
+ s.extra_rdoc_files = [
22
+ "LICENSE",
23
+ "README.rdoc"
24
+ ]
25
+ s.files = [
26
+ ".document",
27
+ ".gitignore",
28
+ "DESCRIPTION",
29
+ "LICENSE",
30
+ "README.rdoc",
31
+ "Rakefile",
32
+ "VERSION",
33
+ "gem_info.gemspec",
34
+ "lib/gem_info.rb",
35
+ "lib/gem_info/errors.rb",
36
+ "lib/gem_info/fuzzy_matcher.rb",
37
+ "lib/gem_info/runner.rb",
38
+ "lib/rubygems_plugin.rb",
39
+ "spec/fuzzy_matcher_spec.rb",
40
+ "spec/runner_spec.rb",
41
+ "spec/spec_helper.rb"
42
+ ]
43
+ s.homepage = %q{http://github.com/oggy/gem_info}
44
+ s.rdoc_options = ["--charset=UTF-8"]
45
+ s.require_paths = ["lib"]
46
+ s.rubygems_version = %q{1.3.6}
47
+ s.summary = %q{Print information about gems.}
48
+ s.test_files = [
49
+ "spec/fuzzy_matcher_spec.rb",
50
+ "spec/runner_spec.rb",
51
+ "spec/spec_helper.rb"
52
+ ]
53
+
54
+ if s.respond_to? :specification_version then
55
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
56
+ s.specification_version = 3
57
+
58
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
59
+ s.add_development_dependency(%q<rspec>, [">= 0"])
60
+ s.add_development_dependency(%q<mocha>, [">= 0"])
61
+ else
62
+ s.add_dependency(%q<rspec>, [">= 0"])
63
+ s.add_dependency(%q<mocha>, [">= 0"])
64
+ end
65
+ else
66
+ s.add_dependency(%q<rspec>, [">= 0"])
67
+ s.add_dependency(%q<mocha>, [">= 0"])
68
+ end
69
+ end
70
+
@@ -0,0 +1,4 @@
1
+ module GemInfo
2
+ Error = Class.new(RuntimeError)
3
+ UsageError = Class.new(Error)
4
+ end
@@ -0,0 +1,53 @@
1
+ module GemInfo
2
+ class FuzzyMatcher
3
+ def initialize(name, version)
4
+ @name = name
5
+ @version = version
6
+ end
7
+
8
+ def all_available_matches
9
+ matches([])
10
+ end
11
+
12
+ def matches(specs)
13
+ specs = matches_for(specs, :name, @name)
14
+ specs = matches_for(specs, :version, @version) if @version
15
+ specs
16
+ end
17
+
18
+ def matches_for(specs, attribute, value)
19
+ [:exact, :substring, :subsequence].each do |type|
20
+ matches = send("#{type}_matches", specs, attribute, value)
21
+ return matches if !matches.empty?
22
+ end
23
+ []
24
+ end
25
+
26
+ private # -------------------------------------------------------
27
+
28
+ def exact_matches(specs, attribute, value)
29
+ specs.select{|spec| spec.send(attribute).to_s == value}
30
+ end
31
+
32
+ def substring_matches(specs, attribute, value)
33
+ specs.select{|spec| spec.send(attribute).to_s.include?(value)}
34
+ end
35
+
36
+ def subsequence_matches(specs, attribute, value)
37
+ specs.select{|spec| include_subsequence?(spec.send(attribute).to_s, value)}
38
+ end
39
+
40
+ def include_subsequence?(string, subsequence)
41
+ string_index = 0
42
+ subsequence_index = 0
43
+ while string_index < string.length
44
+ if string[string_index] == subsequence[subsequence_index]
45
+ subsequence_index += 1
46
+ return true if subsequence_index == subsequence.length
47
+ end
48
+ string_index += 1
49
+ end
50
+ return false
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,120 @@
1
+ module GemInfo
2
+ class Runner
3
+ def self.run(options, *args)
4
+ Runner.new(options, *args).run
5
+ end
6
+
7
+ def initialize(options={}, *args)
8
+ @options = options
9
+ @args = args
10
+ @output = STDOUT
11
+ end
12
+
13
+ attr_accessor :options, :args, :output
14
+
15
+ def run
16
+ parse_args
17
+ parse_options
18
+ matcher = FuzzyMatcher.new(@name, @version)
19
+ specs = matcher.matches(installed_specs)
20
+ validate_exactly_one(specs)
21
+ output_formatted(specs)
22
+ end
23
+
24
+ private # ---------------------------------------------------------
25
+
26
+ def parse_args
27
+ case @args.length
28
+ when 1
29
+ @name, @version = @args.first, nil
30
+ when 2
31
+ @name, @version = *@args
32
+ else
33
+ raise UsageError
34
+ end
35
+ end
36
+
37
+ def parse_options
38
+ @format = options[:format] || "%name %version"
39
+ end
40
+
41
+ def installed_specs
42
+ Gem.source_index.all_gems.values
43
+ end
44
+
45
+ def validate_exactly_one(specs)
46
+ if @options[:exactly_one]
47
+ if specs.empty?
48
+ raise Error, "no gems matching \"#{@name}\" \"#{@version}\""
49
+ elsif specs.length > 1
50
+ message = "#{specs.length} matching gems:\n" +
51
+ specs.map{|spec| " #{spec.name}-#{spec.version}\n"}.join
52
+ raise Error, message
53
+ end
54
+ end
55
+ end
56
+
57
+ def output_formatted(specs)
58
+ specs.each do |spec|
59
+ output.print format(spec)
60
+ output.print "\n" unless options[:no_newlines]
61
+ end
62
+ end
63
+
64
+ def format(spec)
65
+ @format.gsub(format_regexp) do |match|
66
+ if match =~ /\A%date/
67
+ expansion = expand_date(spec, match)
68
+ else
69
+ self.class.expansions[match].call(spec)
70
+ end
71
+ end
72
+ end
73
+
74
+ def expand_date(spec, match)
75
+ date = spec.date
76
+ if match =~ /\[(.*)\]/
77
+ date.strftime($1)
78
+ else
79
+ date.to_s
80
+ end
81
+ end
82
+
83
+ def format_regexp
84
+ @format_regexp ||= Regexp.union(*self.class.expansions.keys)
85
+ end
86
+
87
+ class << self
88
+ def expand(token, &expansion)
89
+ @expansions ||= {}
90
+ expansions[token] = expansion
91
+ end
92
+ attr_reader :expansions
93
+ end
94
+
95
+ expand('%rubygems_version'){|spec| spec.rubygems_version}
96
+ expand('%specification_version'){|spec| spec.specification_version}
97
+ expand('%name'){|spec| spec.name}
98
+ expand('%version'){|spec| spec.version}
99
+ expand(/%date(?:\[.*?\])?/) # handled specially
100
+ expand('%summary'){|spec| spec.summary}
101
+ expand('%email'){|spec| spec.email}
102
+ expand('%homepage'){|spec| spec.homepage}
103
+ expand('%rubyforge_project'){|spec| spec.rubyforge_project}
104
+ expand('%description'){|spec| spec.description}
105
+ expand('%executables'){|spec| spec.executables.join(', ')}
106
+ expand('%bindir'){|spec| spec.bindir}
107
+ expand('%required_ruby_version'){|spec| spec.required_ruby_version}
108
+ expand('%required_rubygems_version'){|spec| spec.required_rubygems_version}
109
+ expand('%platform'){|spec| spec.platform}
110
+ expand('%signing_key'){|spec| spec.signing_key}
111
+ expand('%cert_chain'){|spec| Array(spec.cert_chain).join("\n\n")}
112
+ expand('%post_install_message'){|spec| spec.post_install_message}
113
+ expand('%authors'){|spec| spec.authors.join(', ')}
114
+ expand('%licenses'){|spec| spec.licenses.join(', ')}
115
+ expand('%dependencies'){|spec| spec.dependencies.map{|dep| "#{dep.name} #{dep.version_requirements}"}.join(', ')}
116
+ expand('%path'){|spec| spec.full_gem_path}
117
+ expand('%%'){|spec| '%'}
118
+ expand('%N'){|spec| "\n"}
119
+ end
120
+ end
data/lib/gem_info.rb ADDED
@@ -0,0 +1,3 @@
1
+ require 'gem_info/errors'
2
+ require 'gem_info/fuzzy_matcher'
3
+ require 'gem_info/runner'
@@ -0,0 +1,130 @@
1
+ require 'rubygems/command_manager'
2
+ require 'gem_info'
3
+
4
+ Gem::CommandManager.instance.register_command :info
5
+
6
+ module Gem
7
+ module Commands
8
+ class InfoCommand < Command
9
+ def initialize
10
+ super 'info', "Print information about a gem. Fuzzy matching available."
11
+ add_option('-1', '--exactly-one', "Fail if not exactly 1 match.") do |value, options|
12
+ options[:exactly_one] = true
13
+ end
14
+ add_option('-f', '--format STRING', "Format of output (see below).") do |value, options|
15
+ options[:format] = value
16
+ end
17
+ add_option('-N', '--no-newlines', "Suppress printing of newlines after each gem") do |value, options|
18
+ options[:no_newlines] = true
19
+ end
20
+ end
21
+
22
+ def arguments
23
+ <<-EOS.gsub(/^ *\|/, '')
24
+ |NAME (fuzzy) name of the gem
25
+ |VERSION (fuzzy) version of the gem
26
+ EOS
27
+ end
28
+
29
+ def usage
30
+ "#{program_name} NAME [VERSION]"
31
+ end
32
+
33
+ def default_str
34
+ ''
35
+ end
36
+
37
+ def description
38
+ <<-EOS.gsub(/^ *\|/, '')
39
+ |Print information about matching gems. The NAME and
40
+ |VERSION are fuzzy-matched according to the following
41
+ |algorithm:
42
+ |
43
+ | * Look for gems exactly matching NAME.
44
+ | * If none found, look for gems containing NAME. e.g.,
45
+ | "inf" matches "gem_info"
46
+ | * If none found, look for gems containing the characters
47
+ | of NAME in the same order. e.g, "e_nf" matches
48
+ | "gem_info"
49
+ | * Filter the results above with the version string in the
50
+ | same way.
51
+ |
52
+ |The format string (--format option) has the following
53
+ |escapes available:
54
+ |
55
+ |%rubygems_version
56
+ | Rubygems version that built the gemspec
57
+ |%specification_version
58
+ | Version of the gem's gemspec
59
+ |%name
60
+ | Gem name
61
+ |%version
62
+ | Gem version
63
+ |%date
64
+ |%date[STRFTIME_FORMAT]
65
+ | Date the gem was released. STRFTIME_FORMAT may contain
66
+ | any %-escapes honored by Time#strftime
67
+ |%summary
68
+ | Summary of the gem
69
+ |%email
70
+ | Email address of the gem author
71
+ |%homepage
72
+ | Homepage of the gem
73
+ |%rubyforge_project
74
+ | Name of the rubyforge project
75
+ |%description
76
+ | Gem description
77
+ |%executables
78
+ | List of executables (comma separated)
79
+ |%bindir
80
+ | Directory the gem's executables are installed into
81
+ |%required_ruby_version
82
+ | Ruby version required for the gem
83
+ |%required_rubygems_version
84
+ | Rubygems version required for the gem
85
+ |%platform
86
+ | Platform the gem is built for
87
+ |%signing_key
88
+ | Key which signed the gem
89
+ |%cert_chain
90
+ | Certificate chain used for signing ("\\n\\n" separated)
91
+ |%post_install_message
92
+ | Message displayed upon installation
93
+ |%authors
94
+ | List of author names (comma separated)
95
+ |%licenses
96
+ | List of license names (comma separated)
97
+ |%dependencies
98
+ | List of dependencies (comma separated)
99
+ |%path
100
+ | Path of the installed gem
101
+ |%%
102
+ | A '%' character
103
+ |%N
104
+ | A newline
105
+ EOS
106
+ end
107
+
108
+ def execute
109
+ begin
110
+ GemInfo::Runner.run(options, *options[:args])
111
+ rescue GemInfo::UsageError
112
+ STDERR.puts "USAGE: #{usage}"
113
+ terminate_interaction(1)
114
+ rescue GemInfo::Error => e
115
+ STDERR.puts e.message
116
+ terminate_interaction(1)
117
+ rescue Object => e
118
+ puts "Unexpected error! Debug with DEBUG=1"
119
+ if ENV['DEBUG']
120
+ STDERR.puts "#{exception.class}: #{exception.message}"
121
+ exception.backtrace.each do |line|
122
+ STDERR.puts " #{line}"
123
+ end
124
+ end
125
+ raise
126
+ end
127
+ end
128
+ end
129
+ end
130
+ end
@@ -0,0 +1,146 @@
1
+ require 'spec/spec_helper'
2
+
3
+ describe FuzzyMatcher do
4
+ before do
5
+ @specs = []
6
+ end
7
+
8
+ def spec(name, version='1.2')
9
+ spec = Gem::Specification.new
10
+ spec.name = name
11
+ spec.version = version
12
+ @specs << spec
13
+ spec
14
+ end
15
+
16
+ describe "#matches" do
17
+ describe "when no version is given" do
18
+ before do
19
+ @matcher = FuzzyMatcher.new('name', nil)
20
+ end
21
+
22
+ describe "when there are specs whose name matches the term exactly" do
23
+ before do
24
+ @name1 = spec('name')
25
+ @name2 = spec('name')
26
+ end
27
+
28
+ it "should return the matching specs" do
29
+ @matcher.matches(@specs).should == [@name1, @name2]
30
+ end
31
+
32
+ it "should not return any specs whose name only contains the term" do
33
+ xnamex = spec('xnamex')
34
+ @matcher.matches(@specs).should_not include(xnamex)
35
+ end
36
+ end
37
+
38
+ describe "when there are no specs who name matches the term exactly, but there are specs whose name contains the term" do
39
+ before do
40
+ @aname = spec('aname')
41
+ @nameb = spec('nameb')
42
+ end
43
+
44
+ it "should return any specs whose name contains the term" do
45
+ @matcher.matches(@specs).should == [@aname, @nameb]
46
+ end
47
+
48
+ it "should not return any specs whose name only contains the term as a subsequence" do
49
+ @nxame = spec('nxame')
50
+ @matcher.matches(@specs).should_not include(@nxame)
51
+ end
52
+ end
53
+
54
+ describe "when there are no specs whose name contains the term, but there are specs whose name contains the term as a subsequence" do
55
+ before do
56
+ @nxame = spec('nxame')
57
+ @n_axxme = spec('n-axxme')
58
+ end
59
+
60
+ it "should return any specs whose name contains the term as a subsequence" do
61
+ @matcher.matches(@specs).should == [@nxame, @n_axxme]
62
+ end
63
+
64
+ it "should not return any specs whose name does not contain the term as a subsequence" do
65
+ @zzz = spec('zzz')
66
+ @matcher.matches(@specs).should_not include(@zzz)
67
+ end
68
+ end
69
+
70
+ describe "when there are no specs whose name contains the term as a subsequence" do
71
+ it "should return no results" do
72
+ spec('zzz')
73
+ @matcher.matches(@specs).should == []
74
+ end
75
+ end
76
+ end
77
+
78
+ describe "when a version is given" do
79
+ before do
80
+ @matcher = FuzzyMatcher.new('name', '1.2')
81
+ end
82
+
83
+ describe "when there are specs whose version matches the term exactly" do
84
+ before do
85
+ @name1 = spec('name', '1.2')
86
+ @name2 = spec('name', '1.2')
87
+ end
88
+
89
+ it "should return the matching specs" do
90
+ @matcher.matches(@specs).should == [@name1, @name2]
91
+ end
92
+
93
+ it "should not return any specs whose version only contains the term" do
94
+ v11 = spec('name', '1.2.3')
95
+ @matcher.matches(@specs).should_not include(v11)
96
+ end
97
+ end
98
+
99
+ describe "when there are no specs who version matches the term exactly, but there are specs whose version contains the term" do
100
+ before do
101
+ @v121 = spec('name', '1.2.1')
102
+ @v122 = spec('name', '1.2.2')
103
+ end
104
+
105
+ it "should return any specs whose version contains the term" do
106
+ @matcher.matches(@specs).should == [@v121, @v122]
107
+ end
108
+
109
+ it "should not return any specs whose version only contains the term as a subsequence" do
110
+ v132 = spec('name', '1.3.2')
111
+ @matcher.matches(@specs).should_not include(v132)
112
+ end
113
+ end
114
+
115
+ describe "when there are no specs whose version contains the term, but there are specs whose version contains the term as a subsequence" do
116
+ before do
117
+ @v132 = spec('name', '1.3.2')
118
+ @v142 = spec('name', '1.4.2')
119
+ end
120
+
121
+ it "should return any specs whose version contains the term as a subsequence" do
122
+ @matcher.matches(@specs).should == [@v132, @v142]
123
+ end
124
+
125
+ it "should not return any specs whose version does not contain the term as a subsequence" do
126
+ v45 = spec('name', '4.5')
127
+ @matcher.matches(@specs).should_not include(v45)
128
+ end
129
+ end
130
+
131
+ describe "when there are no specs whose version contains the term as a subsequence" do
132
+ it "should return no results" do
133
+ spec('name', '4.5')
134
+ @matcher.matches(@specs).should == []
135
+ end
136
+ end
137
+
138
+ it "should filter the specs whose name matches with the version" do
139
+ name_only_match = spec('name', '4.5')
140
+ version_only_match = spec('unmatched', '1.2')
141
+ name_and_version_match = spec('name', '1.2')
142
+ @matcher.matches(@specs).should == [name_and_version_match]
143
+ end
144
+ end
145
+ end
146
+ end
@@ -0,0 +1,249 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe Runner do
4
+ before do
5
+ @runner = Runner.new({}, 'name', 'version')
6
+ @runner.output = StringIO.new
7
+ end
8
+
9
+ def make_spec(name='NAME', version='1.2')
10
+ spec = Gem::Specification.new
11
+ spec.name = name
12
+ spec.version = Gem::Version.create(version)
13
+ spec
14
+ end
15
+
16
+ def output
17
+ @runner.run
18
+ @runner.output.string
19
+ end
20
+
21
+ describe "#initialize" do
22
+ it "should raise a UsageError if no non-option arguments are given" do
23
+ @runner.args = []
24
+ lambda{@runner.run}.should raise_error(UsageError)
25
+ end
26
+
27
+ it "should raise a UsageError if more than 2 non-option arguments are given" do
28
+ @runner.args = ['x', 'x', 'x']
29
+ lambda{@runner.run}.should raise_error(UsageError)
30
+ end
31
+ end
32
+
33
+ describe "when exactly one match is required" do
34
+ before do
35
+ @runner.options = {:exactly_one => true}
36
+ end
37
+
38
+ it "should raise an error if no matches are found" do
39
+ FuzzyMatcher.any_instance.stubs(:matches).returns([])
40
+ lambda{@runner.run}.should raise_error(Error)
41
+ end
42
+
43
+ it "should raise an error if more than one match is found" do
44
+ FuzzyMatcher.any_instance.stubs(:matches).returns([make_spec, make_spec])
45
+ lambda{@runner.run}.should raise_error(Error)
46
+ end
47
+
48
+ it "should not raise an error if one match is found" do
49
+ FuzzyMatcher.any_instance.stubs(:matches).returns([make_spec])
50
+ lambda{@runner.run}.should_not raise_error
51
+ end
52
+ end
53
+
54
+ describe "when there are matching gems" do
55
+ before do
56
+ specs = [make_spec('ONE', '1.0'), make_spec('TWO', '2.0')]
57
+ FuzzyMatcher.any_instance.stubs(:matches).returns(specs)
58
+ end
59
+
60
+ it "should print each gem name and version on its own line" do
61
+ output.should == "ONE 1.0\nTWO 2.0\n"
62
+ end
63
+
64
+ describe "when newline printing is suppressed" do
65
+ before do
66
+ @runner.options[:no_newlines] = true
67
+ end
68
+ it "should not print newlines after each gem" do
69
+ output.should == "ONE 1.0TWO 2.0"
70
+ end
71
+ end
72
+ end
73
+
74
+ describe "when exactly one match is not required" do
75
+ it "should not raise an error if no matches are found" do
76
+ FuzzyMatcher.any_instance.stubs(:matches).returns([])
77
+ lambda{@runner.run}.should_not raise_error
78
+ end
79
+ end
80
+
81
+ describe "when a format string is given" do
82
+ def stub_matches(attributes={})
83
+ spec = Gem::Specification.new
84
+ attributes.each do |name, value|
85
+ spec.stubs(name).returns(value)
86
+ end
87
+ FuzzyMatcher.any_instance.stubs(:matches).returns([spec])
88
+ end
89
+
90
+ it "should replace %rubygems_version with the version of rubygems used to create the gem" do
91
+ stub_matches :rubygems_version => '10.0'
92
+ @runner.options[:format] = '%rubygems_version'
93
+ output.should == "10.0\n"
94
+ end
95
+
96
+ it "should replace %specification_version of the gem" do
97
+ stub_matches :specification_version => '10.0'
98
+ @runner.options[:format] = '%specification_version'
99
+ output.should == "10.0\n"
100
+ end
101
+
102
+ it "should replace %name with the gem name" do
103
+ stub_matches :name => 'NAME'
104
+ @runner.options[:format] = '%name'
105
+ output.should == "NAME\n"
106
+ end
107
+
108
+ it "should replace %version with the version" do
109
+ stub_matches :version => Gem::Version.create('1.2.3')
110
+ @runner.options[:format] = '%version'
111
+ output.should == "1.2.3\n"
112
+ end
113
+
114
+ it "should replace %date with the release date in the default time format" do
115
+ time = Time.mktime(2001, 2, 3, 4, 5, 6).utc
116
+ stub_matches :date => time
117
+ @runner.options[:format] = '%date'
118
+ output.should == "#{time}\n"
119
+ end
120
+
121
+ it "should replace %date[%B] with the month of the release date" do
122
+ stub_matches :date => Time.mktime(2001, 2, 3, 4, 5, 6).utc
123
+ @runner.options[:format] = '%date[%B]'
124
+ output.should == "February\n"
125
+ end
126
+
127
+ it "should replace %summary with the summary of the gem" do
128
+ stub_matches :summary => 'SUMMARY'
129
+ @runner.options[:format] = '%summary'
130
+ output.should == "SUMMARY\n"
131
+ end
132
+
133
+ it "should replace %email with the email of the gem author" do
134
+ stub_matches :email => 'EM@I.L'
135
+ @runner.options[:format] = '%email'
136
+ output.should == "EM@I.L\n"
137
+ end
138
+
139
+ it "should replace %homepage with the homepage of the gem" do
140
+ stub_matches :homepage => 'http://example.com'
141
+ @runner.options[:format] = '%homepage'
142
+ output.should == "http://example.com\n"
143
+ end
144
+
145
+ it "should replace %rubyforge_project with the name of the Rubyforge project" do
146
+ stub_matches :rubyforge_project => 'RUBYFORGE_PROJECT'
147
+ @runner.options[:format] = '%rubyforge_project'
148
+ output.should == "RUBYFORGE_PROJECT\n"
149
+ end
150
+
151
+ it "should replace %description with the description of the gem" do
152
+ stub_matches :description => 'DESCRIPTION'
153
+ @runner.options[:format] = '%description'
154
+ output.should == "DESCRIPTION\n"
155
+ end
156
+
157
+ it "should replace %executables with the list of executables in the gem (comma-separated)" do
158
+ stub_matches :executables => ['EXECUTABLE1', 'EXECUTABLE2']
159
+ @runner.options[:format] = '%executables'
160
+ output.should == "EXECUTABLE1, EXECUTABLE2\n"
161
+ end
162
+
163
+ it "should replace %bindir with the path for executable scripts of the gem" do
164
+ stub_matches :bindir => 'BINDIR'
165
+ @runner.options[:format] = '%bindir'
166
+ output.should == "BINDIR\n"
167
+ end
168
+
169
+ it "should replace %required_ruby_version with the required ruby version for the gem" do
170
+ stub_matches :required_ruby_version => '10.0'
171
+ @runner.options[:format] = '%required_ruby_version'
172
+ output.should == "10.0\n"
173
+ end
174
+
175
+ it "should replace %required_rubygems_version with the required rubygems version for the gem" do
176
+ stub_matches :required_rubygems_version => '10.0'
177
+ @runner.options[:format] = '%required_rubygems_version'
178
+ output.should == "10.0\n"
179
+ end
180
+
181
+ it "should replace %platform with the platform the gem runs on" do
182
+ stub_matches :platform => 'ruby'
183
+ @runner.options[:format] = '%platform'
184
+ output.should == "ruby\n"
185
+ end
186
+
187
+ it "should replace %signing_key with the key the gem was signed with" do
188
+ stub_matches :signing_key => 'KEY'
189
+ @runner.options[:format] = '%signing_key'
190
+ output.should == "KEY\n"
191
+ end
192
+
193
+ it "should replace %cert_chain with the certificate chain used to sign the gem" do
194
+ stub_matches :cert_chain => ['CERT_CHAIN']
195
+ @runner.options[:format] = '%cert_chain'
196
+ output.should == "CERT_CHAIN\n"
197
+ end
198
+
199
+ it "should handle specs with a nil cert_chain" do
200
+ stub_matches :cert_chain => nil
201
+ @runner.options[:format] = '%cert_chain'
202
+ output.should == "\n"
203
+ end
204
+
205
+ it "should replace %post_install_message with the message displayed after the gem is installed" do
206
+ stub_matches :post_install_message => 'POST_INSTALL_MESSAGE'
207
+ @runner.options[:format] = '%post_install_message'
208
+ output.should == "POST_INSTALL_MESSAGE\n"
209
+ end
210
+
211
+ it "should replace %authors with the list of gem authors (comma-separated)" do
212
+ stub_matches :authors => ['John Smith', 'Mary Jane']
213
+ @runner.options[:format] = '%authors'
214
+ output.should == "John Smith, Mary Jane\n"
215
+ end
216
+
217
+ it "should replace %licenses with the license names of the gem (comma-separated)" do
218
+ stub_matches :licenses => ['MIT', 'ruby']
219
+ @runner.options[:format] = '%licenses'
220
+ output.should == "MIT, ruby\n"
221
+ end
222
+
223
+ it "should replace %dependencies with the list of dependencies (comma-separated)" do
224
+ dependency1 = Gem::Dependency.new('GEM1', '>= 1.0')
225
+ dependency2 = Gem::Dependency.new('GEM2', '>= 2.0')
226
+ stub_matches :dependencies => [dependency1, dependency2]
227
+ @runner.options[:format] = '%dependencies'
228
+ output.should == "GEM1 >= 1.0, GEM2 >= 2.0\n"
229
+ end
230
+
231
+ it "should replace %path with the path to the gem" do
232
+ stub_matches :full_gem_path => '/path/to/gem'
233
+ @runner.options[:format] = '%path'
234
+ output.should == "/path/to/gem\n"
235
+ end
236
+
237
+ it "should replace %% with a '%'-sign" do
238
+ stub_matches
239
+ @runner.options[:format] = '%%'
240
+ output.should == "%\n"
241
+ end
242
+
243
+ it "should replace %N with a newline" do
244
+ stub_matches
245
+ @runner.options[:format] = '%N'
246
+ output.should == "\n\n"
247
+ end
248
+ end
249
+ end
@@ -0,0 +1,12 @@
1
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
2
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
3
+ require 'gem_info'
4
+ require 'spec'
5
+ require 'spec/autorun'
6
+
7
+ Spec::Runner.configure do |config|
8
+ config.mock_with :mocha
9
+ end
10
+
11
+ # So we don't have to qualify all our classes.
12
+ include GemInfo
metadata ADDED
@@ -0,0 +1,112 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: gem_info
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 0
8
+ - 1
9
+ version: 0.0.1
10
+ platform: ruby
11
+ authors:
12
+ - George Ogata
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-03-17 00:00:00 -04:00
18
+ default_executable:
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: rspec
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ segments:
28
+ - 0
29
+ version: "0"
30
+ type: :development
31
+ version_requirements: *id001
32
+ - !ruby/object:Gem::Dependency
33
+ name: mocha
34
+ prerelease: false
35
+ requirement: &id002 !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ segments:
40
+ - 0
41
+ version: "0"
42
+ type: :development
43
+ version_requirements: *id002
44
+ description: |
45
+ A rubygems plugin which adds an `info' command which prints
46
+ information about gems.
47
+
48
+ Unlike the built-in gem commands, it allows fuzzy matching on gem
49
+ names and versions by default, and allows precise formatting of the
50
+ output, making it easy on the command line and in scripts.
51
+
52
+ email: george.ogata@gmail.com
53
+ executables: []
54
+
55
+ extensions: []
56
+
57
+ extra_rdoc_files:
58
+ - LICENSE
59
+ - README.rdoc
60
+ files:
61
+ - .document
62
+ - .gitignore
63
+ - DESCRIPTION
64
+ - LICENSE
65
+ - README.rdoc
66
+ - Rakefile
67
+ - VERSION
68
+ - gem_info.gemspec
69
+ - lib/gem_info.rb
70
+ - lib/gem_info/errors.rb
71
+ - lib/gem_info/fuzzy_matcher.rb
72
+ - lib/gem_info/runner.rb
73
+ - lib/rubygems_plugin.rb
74
+ - spec/fuzzy_matcher_spec.rb
75
+ - spec/runner_spec.rb
76
+ - spec/spec_helper.rb
77
+ has_rdoc: true
78
+ homepage: http://github.com/oggy/gem_info
79
+ licenses: []
80
+
81
+ post_install_message:
82
+ rdoc_options:
83
+ - --charset=UTF-8
84
+ require_paths:
85
+ - lib
86
+ required_ruby_version: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - ">="
89
+ - !ruby/object:Gem::Version
90
+ segments:
91
+ - 0
92
+ version: "0"
93
+ required_rubygems_version: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - ">="
96
+ - !ruby/object:Gem::Version
97
+ segments:
98
+ - 1
99
+ - 3
100
+ - 2
101
+ version: 1.3.2
102
+ requirements: []
103
+
104
+ rubyforge_project:
105
+ rubygems_version: 1.3.6
106
+ signing_key:
107
+ specification_version: 3
108
+ summary: Print information about gems.
109
+ test_files:
110
+ - spec/fuzzy_matcher_spec.rb
111
+ - spec/runner_spec.rb
112
+ - spec/spec_helper.rb