gem_info 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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