metadatacop 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.
- checksums.yaml +7 -0
- data/.gitignore +9 -0
- data/.rspec +2 -0
- data/.rubocop.yml +5 -0
- data/.travis.yml +3 -0
- data/Gemfile +6 -0
- data/README.md +33 -0
- data/Rakefile +1 -0
- data/bin/console +14 -0
- data/bin/setup +7 -0
- data/config/mods/default.yml +8 -0
- data/exe/metadatacop +19 -0
- data/lib/metadata_cop.rb +1 -0
- data/lib/metadatacop.rb +22 -0
- data/lib/metadatacop/cli.rb +46 -0
- data/lib/metadatacop/config_loader.rb +42 -0
- data/lib/metadatacop/cop.rb +4 -0
- data/lib/metadatacop/cop/base_cop.rb +23 -0
- data/lib/metadatacop/cop/team.rb +29 -0
- data/lib/metadatacop/cop/xml/lint/schema_valid.rb +29 -0
- data/lib/metadatacop/cop/xml/lint/valid.rb +16 -0
- data/lib/metadatacop/logger.rb +9 -0
- data/lib/metadatacop/offense.rb +17 -0
- data/lib/metadatacop/options.rb +25 -0
- data/lib/metadatacop/runner.rb +47 -0
- data/lib/metadatacop/version.rb +3 -0
- data/metadatacop.gemspec +25 -0
- metadata +126 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 5ee79d74b339b80a9f7053d5c7c5f972c206c7cf
|
4
|
+
data.tar.gz: caca883eb5d399d5e61f78de6d04098c9825dda9
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: d1b3907b800a7bbb4e6924767191432541fac2a543757f72ed5505fa3d41b0b872bbf449718e16607f84e9ee72e205a1a46c81301228a06c282410621d3ab479
|
7
|
+
data.tar.gz: bafc15c1a639085170383eb6668263fb6c9f8299bee680e1c0aae404838baed5843b25e90cfe10cefa54503efdd89b0304c83a68513b5e719dba97022dab8a1a
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.rubocop.yml
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
# MetadataCop
|
2
|
+
|
3
|
+
MetadataCop is a metadata quality analyzer, in the same vein as [RuboCop](https://github.com/bbatsov/rubocop) and other static code analyzers.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
MetadataCop is distributed as a Ruby gem:
|
8
|
+
|
9
|
+
```console
|
10
|
+
$ gem install metadatacop
|
11
|
+
```
|
12
|
+
|
13
|
+
## Basic Usage
|
14
|
+
|
15
|
+
Run MetadataCop against specific files:
|
16
|
+
|
17
|
+
```console
|
18
|
+
$ metadatacop -t mods path/to/my/mods.xml
|
19
|
+
```
|
20
|
+
|
21
|
+
## Development
|
22
|
+
|
23
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `bin/console` for an interactive prompt that will allow you to experiment.
|
24
|
+
|
25
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release` to create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
26
|
+
|
27
|
+
## Contributing
|
28
|
+
|
29
|
+
1. Fork it ( https://github.com/cbeer/metadatacop/fork )
|
30
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
31
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
32
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
33
|
+
5. Create a new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'bundler/gem_tasks'
|
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'bundler/setup'
|
4
|
+
require 'metadatacop'
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require 'irb'
|
14
|
+
IRB.start
|
data/bin/setup
ADDED
data/exe/metadatacop
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
$LOAD_PATH.unshift(File.dirname(File.realpath(__FILE__)) + '/../lib')
|
4
|
+
|
5
|
+
require 'metadatacop'
|
6
|
+
require 'optparse'
|
7
|
+
|
8
|
+
options = MetadataCop::Options.parse(ARGV)
|
9
|
+
|
10
|
+
if options[:type].nil?
|
11
|
+
MetadataCop::Options.parse(['--help'])
|
12
|
+
exit 1
|
13
|
+
end
|
14
|
+
|
15
|
+
cli = MetadataCop::CLI.new options
|
16
|
+
|
17
|
+
exit_code = cli.run ARGV
|
18
|
+
|
19
|
+
exit exit_code
|
data/lib/metadata_cop.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'metadatacop'
|
data/lib/metadatacop.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'metadatacop/version'
|
2
|
+
|
3
|
+
module MetadataCop
|
4
|
+
require 'metadatacop/logger'
|
5
|
+
require 'metadatacop/cli'
|
6
|
+
require 'metadatacop/runner'
|
7
|
+
require 'metadatacop/options'
|
8
|
+
require 'metadatacop/config_loader'
|
9
|
+
require 'metadatacop/offense'
|
10
|
+
|
11
|
+
require 'metadatacop/cop'
|
12
|
+
require 'metadatacop/cop/team'
|
13
|
+
|
14
|
+
require 'active_support/inflector'
|
15
|
+
require 'nokogiri'
|
16
|
+
require 'open-uri'
|
17
|
+
require 'yaml'
|
18
|
+
|
19
|
+
require 'metadatacop/cop/base_cop'
|
20
|
+
require 'metadatacop/cop/xml/lint/valid'
|
21
|
+
require 'metadatacop/cop/xml/lint/schema_valid'
|
22
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module MetadataCop
|
2
|
+
class CLI
|
3
|
+
attr_reader :options
|
4
|
+
|
5
|
+
def initialize(options = {})
|
6
|
+
@options = options
|
7
|
+
end
|
8
|
+
|
9
|
+
def run(*paths)
|
10
|
+
runner = Runner.new(runner_options)
|
11
|
+
runner.run(paths)
|
12
|
+
|
13
|
+
report_offenses(runner.offenses)
|
14
|
+
|
15
|
+
runner.success? ? 0 : 1
|
16
|
+
rescue StandardError => e
|
17
|
+
$stderr.puts e.message
|
18
|
+
$stderr.puts e.backtrace
|
19
|
+
1
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def report_offenses(runner_offenses)
|
25
|
+
return if runner_offenses.empty?
|
26
|
+
|
27
|
+
runner_offenses.each do |file, offenses|
|
28
|
+
offenses.each do |o|
|
29
|
+
puts "#{file}: #{o.message} (#{o.cop})"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def runner_options
|
35
|
+
options.merge(cop_options)
|
36
|
+
end
|
37
|
+
|
38
|
+
def cop_options
|
39
|
+
{ cops: enabled_cops }
|
40
|
+
end
|
41
|
+
|
42
|
+
def enabled_cops
|
43
|
+
ConfigLoader.new(options).cops
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module MetadataCop
|
2
|
+
class ConfigLoader
|
3
|
+
METADATACOP_HOME = File.realpath(File.join(File.dirname(__FILE__), '..', '..'))
|
4
|
+
DEFAULT_PATH = File.join(METADATACOP_HOME, 'config', '%{type}', 'default.yml')
|
5
|
+
|
6
|
+
attr_reader :options
|
7
|
+
|
8
|
+
def initialize(options = {})
|
9
|
+
@options = options
|
10
|
+
end
|
11
|
+
|
12
|
+
def configuration
|
13
|
+
@configuration ||= YAML.load_file(default_path)
|
14
|
+
end
|
15
|
+
|
16
|
+
def cops
|
17
|
+
configuration.select(&method(:cop?)).select(&method(:enabled?)).map do |cop, options|
|
18
|
+
cop_class(cop).new(options)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def cop?(cop, _)
|
25
|
+
cop_class(cop) < MetadataCop::Cop::BaseCop
|
26
|
+
rescue NameError
|
27
|
+
false
|
28
|
+
end
|
29
|
+
|
30
|
+
def cop_class(cop_name)
|
31
|
+
"MetadataCop/Cop/#{cop_name}".classify.constantize
|
32
|
+
end
|
33
|
+
|
34
|
+
def enabled?(_, options)
|
35
|
+
options['Enabled'] == true
|
36
|
+
end
|
37
|
+
|
38
|
+
def default_path
|
39
|
+
self.class::DEFAULT_PATH % options
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module MetadataCop
|
2
|
+
module Cop
|
3
|
+
class BaseCop
|
4
|
+
attr_reader :options
|
5
|
+
|
6
|
+
def initialize(options = {})
|
7
|
+
@options = options
|
8
|
+
end
|
9
|
+
|
10
|
+
def message(params = {})
|
11
|
+
self.class::MSG % params
|
12
|
+
end
|
13
|
+
|
14
|
+
def lint?
|
15
|
+
self.class.to_s =~ /Lint/
|
16
|
+
end
|
17
|
+
|
18
|
+
def offense(message)
|
19
|
+
MetadataCop::Offense.new(cop: self.class, message: message)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module MetadataCop
|
2
|
+
module Cop
|
3
|
+
class Team
|
4
|
+
attr_reader :cops, :options
|
5
|
+
|
6
|
+
def initialize(cops, options = {})
|
7
|
+
@cops = cops
|
8
|
+
@options = options
|
9
|
+
end
|
10
|
+
|
11
|
+
def inspect_file(file)
|
12
|
+
linters, others = @cops.partition(&:lint?)
|
13
|
+
|
14
|
+
result = run_cops(linters, file)
|
15
|
+
|
16
|
+
# if the linters failed, no reason to run the others
|
17
|
+
result += run_cops(others, file) if result.empty?
|
18
|
+
|
19
|
+
result
|
20
|
+
end
|
21
|
+
|
22
|
+
def run_cops(cops, file)
|
23
|
+
cops.inject([]) do |offenses, cop|
|
24
|
+
offenses + cop.investigate(file)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module MetadataCop
|
2
|
+
module Cop
|
3
|
+
module Xml
|
4
|
+
module Lint
|
5
|
+
class SchemaValid < Valid
|
6
|
+
def investigate(file)
|
7
|
+
doc = Nokogiri::XML(File.read(file))
|
8
|
+
|
9
|
+
xsd.validate(doc).map { |m| offense(m) }
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def xsd
|
15
|
+
@schema = Nokogiri::XML::Schema(open(xsd_schema_path).read)
|
16
|
+
end
|
17
|
+
|
18
|
+
def xsd_schema_path
|
19
|
+
options.fetch('EnforcedSchema') { class_schema_path }
|
20
|
+
end
|
21
|
+
|
22
|
+
def class_schema_path
|
23
|
+
self.class::SCHEMA_PATH if defined? self.class::SCHEMA_PATH
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module MetadataCop
|
2
|
+
module Cop
|
3
|
+
module Xml
|
4
|
+
module Lint
|
5
|
+
class Valid < BaseCop
|
6
|
+
def investigate(file)
|
7
|
+
doc = Nokogiri::XML(File.read(file))
|
8
|
+
return if doc.errors.empty?
|
9
|
+
|
10
|
+
doc.errors.map { |m| offense(m) }
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module MetadataCop
|
2
|
+
class Offense
|
3
|
+
attr_reader :options
|
4
|
+
|
5
|
+
def initialize(options = {})
|
6
|
+
@options = options
|
7
|
+
end
|
8
|
+
|
9
|
+
def cop
|
10
|
+
options[:cop].to_s.sub('MetadataCop::Cop::', '').underscore
|
11
|
+
end
|
12
|
+
|
13
|
+
def message
|
14
|
+
options[:message]
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'optparse'
|
2
|
+
|
3
|
+
module MetadataCop
|
4
|
+
class Options
|
5
|
+
def self.parse(args)
|
6
|
+
options = {}
|
7
|
+
|
8
|
+
parser(options).parse!(args)
|
9
|
+
options
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.parser(options)
|
13
|
+
OptionParser.new do |opts|
|
14
|
+
opts.on('-t', '--type [TYPE]', 'Rules to apply') do |t|
|
15
|
+
options[:type] = t
|
16
|
+
end
|
17
|
+
|
18
|
+
opts.on('-h', '--help', 'Prints this help') do
|
19
|
+
puts opts
|
20
|
+
exit
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module MetadataCop
|
2
|
+
class Runner
|
3
|
+
attr_reader :options
|
4
|
+
|
5
|
+
def initialize(options = {})
|
6
|
+
@options = options
|
7
|
+
@ran = false
|
8
|
+
end
|
9
|
+
|
10
|
+
def offenses
|
11
|
+
@offenses ||= {}
|
12
|
+
end
|
13
|
+
|
14
|
+
def run(*paths)
|
15
|
+
paths.flatten.each_with_object(offenses) do |file, h|
|
16
|
+
file_offenses = process_file(file).flatten
|
17
|
+
|
18
|
+
h[file] ||= []
|
19
|
+
h[file] += file_offenses
|
20
|
+
end
|
21
|
+
|
22
|
+
@ran = true
|
23
|
+
|
24
|
+
offenses
|
25
|
+
end
|
26
|
+
|
27
|
+
def success?
|
28
|
+
offenses.empty? && ran?
|
29
|
+
end
|
30
|
+
|
31
|
+
def ran?
|
32
|
+
@ran
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def process_file(file)
|
38
|
+
MetadataCop.logger.debug "Scanning #{file}"
|
39
|
+
|
40
|
+
cop_team.inspect_file(file)
|
41
|
+
end
|
42
|
+
|
43
|
+
def cop_team
|
44
|
+
MetadataCop::Cop::Team.new(options[:cops], options)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
data/metadatacop.gemspec
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'metadatacop/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = 'metadatacop'
|
8
|
+
spec.version = MetadataCop::VERSION
|
9
|
+
spec.authors = ['Chris Beer']
|
10
|
+
spec.email = ['chris@cbeer.info']
|
11
|
+
|
12
|
+
spec.summary = 'Style enforcement for metadata'
|
13
|
+
spec.homepage = 'https://github.com/cbeer/metadatacop'
|
14
|
+
|
15
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
16
|
+
spec.bindir = 'exe'
|
17
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
18
|
+
spec.require_paths = ['lib']
|
19
|
+
|
20
|
+
spec.add_dependency 'activesupport'
|
21
|
+
spec.add_dependency 'nokogiri'
|
22
|
+
|
23
|
+
spec.add_development_dependency 'bundler', '~> 1.9'
|
24
|
+
spec.add_development_dependency 'rake', '~> 10.0'
|
25
|
+
end
|
metadata
ADDED
@@ -0,0 +1,126 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: metadatacop
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Chris Beer
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-06-10 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: activesupport
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: nokogiri
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: bundler
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '1.9'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '1.9'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rake
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '10.0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '10.0'
|
69
|
+
description:
|
70
|
+
email:
|
71
|
+
- chris@cbeer.info
|
72
|
+
executables:
|
73
|
+
- metadatacop
|
74
|
+
extensions: []
|
75
|
+
extra_rdoc_files: []
|
76
|
+
files:
|
77
|
+
- ".gitignore"
|
78
|
+
- ".rspec"
|
79
|
+
- ".rubocop.yml"
|
80
|
+
- ".travis.yml"
|
81
|
+
- Gemfile
|
82
|
+
- README.md
|
83
|
+
- Rakefile
|
84
|
+
- bin/console
|
85
|
+
- bin/setup
|
86
|
+
- config/mods/default.yml
|
87
|
+
- exe/metadatacop
|
88
|
+
- lib/metadata_cop.rb
|
89
|
+
- lib/metadatacop.rb
|
90
|
+
- lib/metadatacop/cli.rb
|
91
|
+
- lib/metadatacop/config_loader.rb
|
92
|
+
- lib/metadatacop/cop.rb
|
93
|
+
- lib/metadatacop/cop/base_cop.rb
|
94
|
+
- lib/metadatacop/cop/team.rb
|
95
|
+
- lib/metadatacop/cop/xml/lint/schema_valid.rb
|
96
|
+
- lib/metadatacop/cop/xml/lint/valid.rb
|
97
|
+
- lib/metadatacop/logger.rb
|
98
|
+
- lib/metadatacop/offense.rb
|
99
|
+
- lib/metadatacop/options.rb
|
100
|
+
- lib/metadatacop/runner.rb
|
101
|
+
- lib/metadatacop/version.rb
|
102
|
+
- metadatacop.gemspec
|
103
|
+
homepage: https://github.com/cbeer/metadatacop
|
104
|
+
licenses: []
|
105
|
+
metadata: {}
|
106
|
+
post_install_message:
|
107
|
+
rdoc_options: []
|
108
|
+
require_paths:
|
109
|
+
- lib
|
110
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
111
|
+
requirements:
|
112
|
+
- - ">="
|
113
|
+
- !ruby/object:Gem::Version
|
114
|
+
version: '0'
|
115
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
116
|
+
requirements:
|
117
|
+
- - ">="
|
118
|
+
- !ruby/object:Gem::Version
|
119
|
+
version: '0'
|
120
|
+
requirements: []
|
121
|
+
rubyforge_project:
|
122
|
+
rubygems_version: 2.4.5
|
123
|
+
signing_key:
|
124
|
+
specification_version: 4
|
125
|
+
summary: Style enforcement for metadata
|
126
|
+
test_files: []
|