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 +5 -0
- data/.gitignore +5 -0
- data/DESCRIPTION +6 -0
- data/LICENSE +20 -0
- data/README.rdoc +55 -0
- data/Rakefile +49 -0
- data/VERSION +1 -0
- data/gem_info.gemspec +70 -0
- data/lib/gem_info/errors.rb +4 -0
- data/lib/gem_info/fuzzy_matcher.rb +53 -0
- data/lib/gem_info/runner.rb +120 -0
- data/lib/gem_info.rb +3 -0
- data/lib/rubygems_plugin.rb +130 -0
- data/spec/fuzzy_matcher_spec.rb +146 -0
- data/spec/runner_spec.rb +249 -0
- data/spec/spec_helper.rb +12 -0
- metadata +112 -0
data/.document
ADDED
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,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,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
|
data/spec/runner_spec.rb
ADDED
@@ -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
|
data/spec/spec_helper.rb
ADDED
@@ -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
|