gem_lint 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/CHANGELOG ADDED
@@ -0,0 +1,2 @@
1
+ v0.0.1 (29th November 2010)
2
+ * initial release
data/README.rdoc ADDED
@@ -0,0 +1,56 @@
1
+ = GemLint
2
+
3
+ Sanity check your rubygems for common issues. Missing readmes, bundled pkg
4
+ directories, encoding issues in the gemspec, etc.
5
+
6
+ Each test is classified as an error or warning. Errors are issues that (by my
7
+ reading) violate the documented gem specs. Warnings are either best practices
8
+ recommended by members of the community or arbitrary things that annoy me
9
+ personally.
10
+
11
+ == Usage
12
+
13
+ gem install gem-lint
14
+ gem lint somefile-0.0.1.gem
15
+
16
+ === API
17
+
18
+ To check a gem programmatically:
19
+
20
+ require "gem_lint"
21
+
22
+ runner = GemLint::Runner.new("widgets-1.0.gem")
23
+ puts runner.name
24
+ puts runner.version
25
+ puts runner.email
26
+ puts runner.tags
27
+
28
+ == Status
29
+
30
+ This a spike. It has few tests and is a proof of concept. Most of it was written at
31
+ a Railscamp and therefore is probably of suspect quality.
32
+
33
+ == Compatability
34
+
35
+ Rubygems 1.3.2 or greater is required, otherwise it's pure ruby should run on most
36
+ ruby VMs.
37
+
38
+ == Developing
39
+
40
+ To add new checks, create a new strategy in lib/gem_lint/strategies with a matching
41
+ spec in spec/strategies.
42
+
43
+ View other strategies for an idea of the required contract. There are existing
44
+ specs to ensure all strategies confirm to the contract, so keep the full spec
45
+ suit (using "rake") green.
46
+
47
+ Full source is on github at https://github.com/yob/gem-lint
48
+
49
+ == Ideas
50
+
51
+ * command for users to display extra info on a tag a gem failed
52
+
53
+ == Further Reading
54
+
55
+ * http://chneukirchen.github.com/rps/
56
+ * http://blog.segment7.net/articles/2010/11/15/how-to-name-gems
@@ -0,0 +1,123 @@
1
+ # coding: utf-8
2
+
3
+ module GemLint
4
+ class Runner
5
+
6
+ attr_reader :tags, :tags_with_level, :email, :name, :version
7
+
8
+ def initialize(filename)
9
+ raise ArgumentError, "'#{filename}' does not exist" unless File.file?(filename.to_s)
10
+
11
+ @filename = filename
12
+ init_vars
13
+ end
14
+
15
+ private
16
+
17
+ def init_vars
18
+ unpack_gem
19
+ @tags = collect_tags
20
+ @tags_with_level = collect_tags_with_level
21
+ @email = spec ? spec.email : nil
22
+ @name = spec ? spec.name : nil
23
+ @version = spec ? spec.version.to_s : nil
24
+ cleanup
25
+ end
26
+
27
+ # returns an array of symbols, each one indicating a test the provided gem
28
+ # failed. Unpacks the gem to a temporary location and cleans up after
29
+ # itself.
30
+ #
31
+ def collect_tags
32
+ if unpack_successful?
33
+ failed_strategies.map { |s|
34
+ s.tag
35
+ }
36
+ else
37
+ ["unpack-failed"]
38
+ end
39
+ end
40
+
41
+ def collect_tags_with_level
42
+ if unpack_successful?
43
+ failed_strategies.map { |s|
44
+ "#{s.level_char}: #{s.tag}"
45
+ }.sort
46
+ else
47
+ ["E: unpack-failed"]
48
+ end
49
+ end
50
+
51
+ def failed_strategies
52
+ if unpack_successful?
53
+ @failed_strategies ||= GemLint.strategies.map { |s|
54
+ s.new(visitor_args)
55
+ }.select { |s|
56
+ s.fail?
57
+ }
58
+ else
59
+ @failed_strategies ||= []
60
+ end
61
+ end
62
+
63
+ def visitor_args
64
+ @visitor_args ||= {
65
+ :filename => @filename,
66
+ :data_path => data_path,
67
+ :metadata_path => metadata_file
68
+ }
69
+ end
70
+
71
+ def unpack_successful?
72
+ File.directory?(data_path) && File.file?(metadata_file)
73
+ end
74
+
75
+ def data_path
76
+ @data_path ||= File.join(unpack_path, "data")
77
+ end
78
+
79
+ def data_file
80
+ @data_file ||= File.join(unpack_path, "data.tar.gz")
81
+ end
82
+
83
+ def metadata_gz_file
84
+ @metadata_gz_file ||= File.join(unpack_path, "metadata.gz")
85
+ end
86
+
87
+ def metadata_file
88
+ @metadata_file ||= File.join(unpack_path, "metadata")
89
+ end
90
+
91
+ def spec
92
+ if @spec || File.file?(metadata_file)
93
+ @spec ||= YAML.load_file(metadata_file)
94
+ else
95
+ nil
96
+ end
97
+ end
98
+
99
+ def unpack_path
100
+ @unpack_path ||= File.join(Dir.tmpdir, rand(100000).to_s)
101
+ end
102
+
103
+ # TODO: update this to use native ruby untar
104
+ def unpack_gem
105
+ Dir.mkdir(unpack_path)
106
+ Dir.mkdir(data_path)
107
+
108
+ `tar -xkC #{unpack_path} -f #{@filename} > /dev/null 2>&1`
109
+ `tar -xzkC #{data_path} -f #{data_file} > /dev/null 2>&1`
110
+ `gunzip #{metadata_file} > /dev/null 2>&1`
111
+
112
+ FileUtils.remove_entry_secure(data_file) if File.file?(data_file)
113
+
114
+ true
115
+ end
116
+
117
+ def cleanup
118
+ return unless File.directory?(unpack_path)
119
+
120
+ FileUtils.remove_entry_secure(unpack_path)
121
+ end
122
+ end
123
+ end
@@ -0,0 +1,40 @@
1
+ # coding: utf-8
2
+
3
+ module GemLint
4
+ module Strategies
5
+ class AbstractStrategy
6
+ attr_reader :filename, :path, :metadata_path
7
+
8
+ def initialize(args = {})
9
+ @filename = args[:filename]
10
+ @path = args[:data_path]
11
+ @metadata_path = args[:metadata_path]
12
+
13
+ raise ArgumentError, "#{@path} is not a directory" unless File.directory?(@path)
14
+ raise ArgumentError, "#{@metadata_path} is not a file" unless File.file?(@metadata_path)
15
+ raise ArgumentError, ":filename must be a filename ending in gem" unless @filename.to_s[-4,4] == ".gem"
16
+ end
17
+
18
+ def level_char
19
+ self.level.to_s[0,1].upcase
20
+ end
21
+
22
+ def description
23
+ raise "this should be implemented by concrete subclasses"
24
+ end
25
+
26
+ def fail?
27
+ raise "this should be implemented by concrete subclasses"
28
+ end
29
+
30
+ def level
31
+ raise "this should be implemented by concrete subclasses"
32
+ end
33
+
34
+ def tag
35
+ raise "this should be implemented by concrete subclasses"
36
+ end
37
+
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,39 @@
1
+ module GemLint
2
+ module Strategies
3
+ class BinEndsWithRbStrategy < AbstractStrategy
4
+
5
+ def description
6
+ "A file in bin/ ends in .rb"
7
+ end
8
+
9
+ def tag
10
+ :"bin-ends-with-rb"
11
+ end
12
+
13
+ def level
14
+ :warning
15
+ end
16
+
17
+ def fail?
18
+ bin_files.any? { |path| path[-3,3] == ".rb" }
19
+ end
20
+
21
+ private
22
+
23
+ def bin_files
24
+ all_files.select { |path|
25
+ path[0,4] == "bin/" && File.file?(self.path + "/" + path)
26
+ }
27
+ end
28
+
29
+ def all_files
30
+ paths = []
31
+ Find.find(self.path) { |path| paths << path }
32
+ paths.map { |path|
33
+ path.gsub(self.path + "/","")
34
+ }
35
+ end
36
+
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,43 @@
1
+ module GemLint
2
+ module Strategies
3
+ class BinWithoutShebangStrategy < AbstractStrategy
4
+
5
+ def description
6
+ "A file in bin/ doesn't have a shebang on the first line"
7
+ end
8
+
9
+ def tag
10
+ :"bin-without-shebang"
11
+ end
12
+
13
+ def level
14
+ :warning
15
+ end
16
+
17
+ def fail?
18
+ bin_files.any? { |path|
19
+ data = File.open(self.path + "/" + path) { |f| f.read }
20
+ first_line = data.split("\n")[0]
21
+ !first_line.to_s.include?("env ruby")
22
+ }
23
+ end
24
+
25
+ private
26
+
27
+ def bin_files
28
+ all_files.select { |path|
29
+ path[0,4] == "bin/" && File.file?(self.path + "/" + path)
30
+ }
31
+ end
32
+
33
+ def all_files
34
+ paths = []
35
+ Find.find(self.path) { |path| paths << path }
36
+ paths.map { |path|
37
+ path.gsub(self.path + "/","")
38
+ }
39
+ end
40
+
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,32 @@
1
+ require 'find'
2
+
3
+ module GemLint
4
+ module Strategies
5
+ class CapitalsInNameStrategy < AbstractStrategy
6
+
7
+ def description
8
+ "It's strongly recommended that your gem name be all lower case"
9
+ end
10
+
11
+ def tag
12
+ :"capitals-in-name"
13
+ end
14
+
15
+ def level
16
+ :warning
17
+ end
18
+
19
+ def fail?
20
+ spec.name.match(/[A-Z]/)
21
+ end
22
+
23
+ private
24
+
25
+ def spec
26
+ @spec ||= YAML.load(File.read(@metadata_path))
27
+ end
28
+
29
+ end
30
+ end
31
+ end
32
+
@@ -0,0 +1,32 @@
1
+ module GemLint
2
+ module Strategies
3
+ class ChangelogStrategy < AbstractStrategy
4
+
5
+ def description
6
+ "Gem contains no changelog or history file"
7
+ end
8
+
9
+ def tag
10
+ :"no-changelog-or-history"
11
+ end
12
+
13
+ def level
14
+ :warning
15
+ end
16
+
17
+ def fail?
18
+ root_files.none? do |filename|
19
+ dfile = filename.downcase
20
+ dfile.include?("changelog") || dfile.include?("history")
21
+ end
22
+ end
23
+
24
+ private
25
+
26
+ def root_files
27
+ Dir.entries(self.path)
28
+ end
29
+
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,31 @@
1
+ module GemLint
2
+ module Strategies
3
+ class ContainsGemFileStrategy < AbstractStrategy
4
+
5
+ def description
6
+ "Gem contains at least 1 other gem file"
7
+ end
8
+
9
+ def tag
10
+ :"contains-gem-file"
11
+ end
12
+
13
+ def level
14
+ :warning
15
+ end
16
+
17
+ def fail?
18
+ spec.files.any? { |filename|
19
+ filename.match(/\A.*\.gem\Z/)
20
+ }
21
+ end
22
+
23
+ private
24
+
25
+ def spec
26
+ @spec ||= YAML.load(File.read(@metadata_path))
27
+ end
28
+
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,30 @@
1
+ module GemLint
2
+ module Strategies
3
+ class CsvAuthorsStrategy < AbstractStrategy
4
+
5
+ def description
6
+ "Authors field in spec uses a comma or semicolon to specify multiple authors instead of an array"
7
+ end
8
+
9
+ def tag
10
+ :"csv-authors"
11
+ end
12
+
13
+ def level
14
+ :error
15
+ end
16
+
17
+ def fail?
18
+ yaml.authors.is_a?(Array) &&
19
+ (yaml.authors.first.include?(",") || yaml.authors.first.include?(";"))
20
+ end
21
+
22
+ private
23
+
24
+ def yaml
25
+ @yaml ||= YAML.load(File.read(@metadata_path))
26
+ end
27
+
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,30 @@
1
+ module GemLint
2
+ module Strategies
3
+ class CsvEmailStrategy < AbstractStrategy
4
+
5
+ def description
6
+ "Email field in spec uses CSV to specify multiple emails instead of an array"
7
+ end
8
+
9
+ def tag
10
+ :"csv-email"
11
+ end
12
+
13
+ def level
14
+ :error
15
+ end
16
+
17
+ def fail?
18
+ (yaml.email.is_a?(String) && (yaml.email.include?(",") || yaml.email.include?(";"))) ||
19
+ (yaml.email.is_a?(Array) && (yaml.email.first.include?(",") || yaml.email.first.include?(";")))
20
+ end
21
+
22
+ private
23
+
24
+ def yaml
25
+ @yaml ||= YAML.load(File.read(@metadata_path))
26
+ end
27
+
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,29 @@
1
+ module GemLint
2
+ module Strategies
3
+ class DuplicateAuthorsStrategy < AbstractStrategy
4
+
5
+ def description
6
+ "Authors field in spec should have no duplicate values"
7
+ end
8
+
9
+ def tag
10
+ :"duplicate-authors"
11
+ end
12
+
13
+ def level
14
+ :warning
15
+ end
16
+
17
+ def fail?
18
+ yaml.authors.is_a?(Array) && yaml.authors.uniq.size != yaml.authors.size
19
+ end
20
+
21
+ private
22
+
23
+ def yaml
24
+ @yaml ||= YAML.load(File.read(@metadata_path))
25
+ end
26
+
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,29 @@
1
+ module GemLint
2
+ module Strategies
3
+ class DuplicateEmailStrategy < AbstractStrategy
4
+
5
+ def description
6
+ "Email field in spec should have no duplicate values"
7
+ end
8
+
9
+ def tag
10
+ :"csv-email"
11
+ end
12
+
13
+ def level
14
+ :warning
15
+ end
16
+
17
+ def fail?
18
+ yaml.email.is_a?(Array) && yaml.email.uniq.size != yaml.email.size
19
+ end
20
+
21
+ private
22
+
23
+ def yaml
24
+ @yaml ||= YAML.load(File.read(@metadata_path))
25
+ end
26
+
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,31 @@
1
+ module GemLint
2
+ module Strategies
3
+ class PkgDirStrategy < AbstractStrategy
4
+
5
+ def description
6
+ "Gem contains a directory in the root called pkg"
7
+ end
8
+
9
+ def tag
10
+ :"pkg-dir"
11
+ end
12
+
13
+ def level
14
+ :warning
15
+ end
16
+
17
+ def fail?
18
+ root_files.any? { |filename|
19
+ filename.match(/pkg.*/)
20
+ }
21
+ end
22
+
23
+ private
24
+
25
+ def root_files
26
+ Dir.entries(self.path)
27
+ end
28
+
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,31 @@
1
+ module GemLint
2
+ module Strategies
3
+ class ReadmeStrategy < AbstractStrategy
4
+
5
+ def description
6
+ "Gem contains no readme file"
7
+ end
8
+
9
+ def tag
10
+ :"no-readme"
11
+ end
12
+
13
+ def level
14
+ :warning
15
+ end
16
+
17
+ def fail?
18
+ root_files.none? do |filename|
19
+ filename.downcase.include?("readme")
20
+ end
21
+ end
22
+
23
+ private
24
+
25
+ def root_files
26
+ Dir.entries(self.path)
27
+ end
28
+
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,42 @@
1
+ require 'find'
2
+
3
+ module GemLint
4
+ module Strategies
5
+ class RequireMatchesGemnameStrategy < AbstractStrategy
6
+
7
+ def description
8
+ "Gem cannot be loaded by require '#{preferred_basename}'"
9
+ end
10
+
11
+ def tag
12
+ :"require-doesnt-match-gemname"
13
+ end
14
+
15
+ def level
16
+ :warning
17
+ end
18
+
19
+ # TODO: does thi need to be beefed up to recognise extensions
20
+ #
21
+ def fail?
22
+ !spec.files.include?(preferred_filename)
23
+ end
24
+
25
+ private
26
+
27
+ def preferred_basename
28
+ "lib/" + spec.name.tr("-","/")
29
+ end
30
+
31
+ def preferred_filename
32
+ preferred_basename + ".rb"
33
+ end
34
+
35
+ def spec
36
+ @spec ||= YAML.load(File.read(@metadata_path))
37
+ end
38
+
39
+ end
40
+ end
41
+ end
42
+
@@ -0,0 +1,38 @@
1
+ require 'find'
2
+
3
+ module GemLint
4
+ module Strategies
5
+ class RubyFileLocationStrategy < AbstractStrategy
6
+
7
+ def description
8
+ "Gem contains ruby files outside of lib, test and spec"
9
+ end
10
+
11
+ def tag
12
+ :"ruby-files-outside-lib-test-spec"
13
+ end
14
+
15
+ def level
16
+ :warning
17
+ end
18
+
19
+ def fail?
20
+ all_files.any? do |filename|
21
+ filename[0,3] != "lib" && filename[0,4] != "spec" &&
22
+ filename[0,4] != "test" && filename[-3,3] == ".rb"
23
+ end
24
+ end
25
+
26
+ private
27
+
28
+ def all_files
29
+ paths = []
30
+ Find.find(self.path) { |path| paths << path }
31
+ paths.map { |path|
32
+ path.gsub(self.path + "/","")
33
+ }
34
+ end
35
+
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,29 @@
1
+ module GemLint
2
+ module Strategies
3
+ class StringEmailStrategy < AbstractStrategy
4
+
5
+ def description
6
+ "Email field in spec is a String instead of an Array"
7
+ end
8
+
9
+ def tag
10
+ :"string-email"
11
+ end
12
+
13
+ def level
14
+ :error
15
+ end
16
+
17
+ def fail?
18
+ yaml.email.is_a?(String)
19
+ end
20
+
21
+ private
22
+
23
+ def yaml
24
+ @yaml ||= YAML.load(File.read(@metadata_path))
25
+ end
26
+
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,37 @@
1
+ require 'find'
2
+
3
+ module GemLint
4
+ module Strategies
5
+ class TestFilesInFilesAttributeStrategy < AbstractStrategy
6
+
7
+ def description
8
+ "Gem metadata includes test files in files attribute. Use test_files instead"
9
+ end
10
+
11
+ def tag
12
+ :"test-files-in-files-attribute"
13
+ end
14
+
15
+ def level
16
+ :warning
17
+ end
18
+
19
+ def fail?
20
+ orig_files.any? { |filename|
21
+ filename[-8,8] == "_spec.rb" || filename[-8,8] == "_test.rb"
22
+ }
23
+ end
24
+
25
+ private
26
+
27
+ def orig_files
28
+ @orig_files ||= yaml.files - yaml.test_files
29
+ end
30
+
31
+ def yaml
32
+ @yaml ||= YAML.load(File.read(@metadata_path))
33
+ end
34
+
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,26 @@
1
+ module GemLint
2
+ module Strategies
3
+ class Utf8MetadataStrategy < AbstractStrategy
4
+
5
+ def description
6
+ "Ensure the gem metadata is all utf8 encoded"
7
+ end
8
+
9
+ def tag
10
+ :"utf8-metadata"
11
+ end
12
+
13
+ def level
14
+ :error
15
+ end
16
+
17
+ def fail?
18
+ File.read(@metadata_path).unpack("U*")
19
+ false
20
+ rescue
21
+ true
22
+ end
23
+
24
+ end
25
+ end
26
+ end
data/lib/gem_lint.rb ADDED
@@ -0,0 +1,25 @@
1
+ # coding: utf-8
2
+
3
+ # stdlib
4
+ require 'tmpdir'
5
+ require 'fileutils'
6
+
7
+ # our own code
8
+ require 'gem_lint/runner'
9
+
10
+ # dynamically load all available strategies
11
+ strategies_path = File.dirname(__FILE__) + "/gem_lint/strategies/**/*.rb"
12
+ Dir[strategies_path].sort.each {|f| require f }
13
+
14
+ module GemLint
15
+
16
+ # return an array of all strategy classes
17
+ #
18
+ def self.strategies
19
+ GemLint::Strategies.constants.sort.select { |class_name|
20
+ class_name != "AbstractStrategy"
21
+ }.map { |class_name|
22
+ GemLint::Strategies.const_get(class_name)
23
+ }
24
+ end
25
+ end
@@ -0,0 +1,35 @@
1
+ require 'rubygems/command'
2
+ require 'gem_lint'
3
+
4
+ class Gem::Commands::LintCommand < Gem::Command
5
+ def description # :nodoc:
6
+ 'Check a gem file for common mistakes and errors'
7
+ end
8
+
9
+ def arguments # :nodoc:
10
+ "GEM built gem to check"
11
+ end
12
+
13
+ def usage # :nodoc:
14
+ "#{program_name} GEM"
15
+ end
16
+
17
+ def initialize
18
+ super 'lint', description
19
+ end
20
+
21
+ def execute
22
+ runner = GemLint::Runner.new(get_one_gem_name)
23
+ if runner.tags.empty?
24
+ puts "No test failures!"
25
+ puts
26
+ else
27
+ runner.tags_with_level.each do |tag|
28
+ puts "- #{tag}"
29
+ end
30
+ puts
31
+ exit 1
32
+ end
33
+ end
34
+
35
+ end
@@ -0,0 +1,3 @@
1
+ require 'rubygems/command_manager'
2
+
3
+ Gem::CommandManager.instance.register_command :lint
metadata ADDED
@@ -0,0 +1,150 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: gem_lint
3
+ version: !ruby/object:Gem::Version
4
+ hash: 29
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 1
10
+ version: 0.0.1
11
+ platform: ruby
12
+ authors:
13
+ - James Healy
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2010-11-29 00:00:00 -08:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: rake
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ hash: 3
30
+ segments:
31
+ - 0
32
+ version: "0"
33
+ type: :development
34
+ version_requirements: *id001
35
+ - !ruby/object:Gem::Dependency
36
+ name: rcov
37
+ prerelease: false
38
+ requirement: &id002 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ hash: 3
44
+ segments:
45
+ - 0
46
+ version: "0"
47
+ type: :development
48
+ version_requirements: *id002
49
+ - !ruby/object:Gem::Dependency
50
+ name: roodi
51
+ prerelease: false
52
+ requirement: &id003 !ruby/object:Gem::Requirement
53
+ none: false
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ hash: 3
58
+ segments:
59
+ - 0
60
+ version: "0"
61
+ type: :development
62
+ version_requirements: *id003
63
+ - !ruby/object:Gem::Dependency
64
+ name: rspec
65
+ prerelease: false
66
+ requirement: &id004 !ruby/object:Gem::Requirement
67
+ none: false
68
+ requirements:
69
+ - - ~>
70
+ - !ruby/object:Gem::Version
71
+ hash: 3
72
+ segments:
73
+ - 2
74
+ - 0
75
+ version: "2.0"
76
+ type: :development
77
+ version_requirements: *id004
78
+ description: Adds a 'lint' command rubygems that will pront a list of possible errors in a gem
79
+ email:
80
+ - james@yob.id.au
81
+ executables: []
82
+
83
+ extensions: []
84
+
85
+ extra_rdoc_files: []
86
+
87
+ files:
88
+ - lib/gem_lint.rb
89
+ - lib/rubygems_plugin.rb
90
+ - lib/rubygems/commands/lint_command.rb
91
+ - lib/gem_lint/runner.rb
92
+ - lib/gem_lint/strategies/require_matches_gemname_strategy.rb
93
+ - lib/gem_lint/strategies/utf8_metadata_strategy.rb
94
+ - lib/gem_lint/strategies/readme_strategy.rb
95
+ - lib/gem_lint/strategies/changelog_strategy.rb
96
+ - lib/gem_lint/strategies/duplicate_authors_strategy.rb
97
+ - lib/gem_lint/strategies/bin_ends_with_rb_strategy.rb
98
+ - lib/gem_lint/strategies/bin_without_shebang_strategy.rb
99
+ - lib/gem_lint/strategies/csv_email_strategy.rb
100
+ - lib/gem_lint/strategies/abstract_strategy.rb
101
+ - lib/gem_lint/strategies/pkg_dir_strategy.rb
102
+ - lib/gem_lint/strategies/capitals_in_name_strategy.rb
103
+ - lib/gem_lint/strategies/test_files_in_files_attribute_strategy.rb
104
+ - lib/gem_lint/strategies/string_email_strategy.rb
105
+ - lib/gem_lint/strategies/contains_gem_file_strategy.rb
106
+ - lib/gem_lint/strategies/ruby_file_location_strategy.rb
107
+ - lib/gem_lint/strategies/duplicate_email_strategy.rb
108
+ - lib/gem_lint/strategies/csv_authors_strategy.rb
109
+ - README.rdoc
110
+ - CHANGELOG
111
+ has_rdoc: true
112
+ homepage: http://github.com/yob/gem-lint
113
+ licenses: []
114
+
115
+ post_install_message:
116
+ rdoc_options:
117
+ - --title
118
+ - Gem Lint
119
+ - --line-numbers
120
+ require_paths:
121
+ - lib
122
+ required_ruby_version: !ruby/object:Gem::Requirement
123
+ none: false
124
+ requirements:
125
+ - - ">="
126
+ - !ruby/object:Gem::Version
127
+ hash: 3
128
+ segments:
129
+ - 0
130
+ version: "0"
131
+ required_rubygems_version: !ruby/object:Gem::Requirement
132
+ none: false
133
+ requirements:
134
+ - - ">="
135
+ - !ruby/object:Gem::Version
136
+ hash: 31
137
+ segments:
138
+ - 1
139
+ - 3
140
+ - 2
141
+ version: 1.3.2
142
+ requirements: []
143
+
144
+ rubyforge_project:
145
+ rubygems_version: 1.3.7
146
+ signing_key:
147
+ specification_version: 3
148
+ summary: Check rubygem files for common mistakes and errors
149
+ test_files: []
150
+