xcop 0.6.1 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f94025e78c2d5baff1d8ad8e43dc9ccf2daec6f0f408ed1a558e0608db601371
4
- data.tar.gz: 752298a36ba76dcbd2c216fa3611d7922235a65428b6c453d731e8a86e7c0eec
3
+ metadata.gz: 94e8fcd3843e72e2e95cc964a20acd22527734574d2da826e58b0b51fd50ead1
4
+ data.tar.gz: f454cfb06eecd4700b92c86c815bc4207d7554c455db2fba2d17a46f6c5cbc49
5
5
  SHA512:
6
- metadata.gz: 52bf482faa953e3d364836851d50e2c5d1fde84c6ae5cb86a49e9bddecab3ea3afc19dc31b2a020c5b3e71eab7e542c8a641c08616e1290489826be27361e4f9
7
- data.tar.gz: 786b9f4b6ac31dbf36befc363aecc6dc75d9b7cdc2a00b074754e1edb9ce57950c56f84be3c656b5b4405f7af7395a7368afd33d2d4926237c13d77cc46d162a
6
+ metadata.gz: 644e0b11601e49a0c8b1faf884d44d6d588d314c34e232497c9e690df6330769e3a20c0ffd975b83f9d08949599ca6c7420e0987505ddcf97b5cbdf5ff836921
7
+ data.tar.gz: 8ffdfd91e26107945987fd0914fa1debc15ab628e7020819b52d421ed21b14ca6c4a77cf12d18f614fe297d4002d2fdb7053bb94f7778a829421d3feffdad112
@@ -0,0 +1,23 @@
1
+ ---
2
+ name: rake
3
+ on:
4
+ push:
5
+ branches:
6
+ - master
7
+ pull_request:
8
+ branches:
9
+ - master
10
+ jobs:
11
+ test:
12
+ strategy:
13
+ matrix:
14
+ os: [ubuntu-latest, macos-latest]
15
+ ruby: ['2.7', '3.0']
16
+ runs-on: ${{ matrix.os }}
17
+ steps:
18
+ - uses: actions/checkout@v2
19
+ - uses: ruby/setup-ruby@v1
20
+ with:
21
+ ruby-version: ${{ matrix.ruby }}
22
+ - run: bundle update
23
+ - run: bundle exec rake
data/.rubocop.yml CHANGED
@@ -4,14 +4,20 @@ AllCops:
4
4
  - 'assets/**/*'
5
5
  DisplayCopNames: true
6
6
  TargetRubyVersion: 2.2
7
+ NewCops: enable
8
+ SuggestExtensions: false
7
9
 
8
10
  Metrics/CyclomaticComplexity:
9
11
  Max: 10
10
12
  Metrics/MethodLength:
11
13
  Enabled: false
12
- Style/MultilineMethodCallIndentation:
14
+ Layout/MultilineMethodCallIndentation:
13
15
  Enabled: false
14
16
  Metrics/AbcSize:
15
17
  Enabled: false
16
18
  Metrics/BlockLength:
17
19
  Max: 50
20
+ Layout/EmptyLineAfterGuardClause:
21
+ Enabled: false
22
+ Style/ClassAndModuleChildren:
23
+ Enabled: false
data/.rultor.yml CHANGED
@@ -1,17 +1,13 @@
1
1
  assets:
2
2
  rubygems.yml: yegor256/home#assets/rubygems.yml
3
3
  install: |
4
- export GEM_HOME=~/.ruby
5
- export GEM_PATH=$GEM_HOME:$GEM_PATH
6
- sudo apt-get -y update
7
- sudo gem install pdd -v 0.20.5
8
- bundle install
4
+ pdd -f /dev/null
5
+ sudo bundle install --no-color "--gemfile=$(pwd)/Gemfile"
9
6
  release:
10
7
  script: |-
11
8
  bundle exec rake
12
- pdd -f /dev/null
13
9
  rm -rf *.gem
14
- sed -i "s/1\.0\.snapshot/${tag}/g" lib/xcop/version.rb
10
+ sed -i "s/0\.0\.0/${tag}/g" lib/xcop/version.rb
15
11
  git add lib/xcop/version.rb
16
12
  git commit -m "version set to ${tag}"
17
13
  gem build xcop.gemspec
@@ -20,7 +16,6 @@ release:
20
16
  merge:
21
17
  script: |-
22
18
  bundle exec rake
23
- pdd -f /dev/null
24
19
  deploy:
25
20
  script: |-
26
21
  echo "There is nothing to deploy"
data/.simplecov CHANGED
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2017-2020 Yegor Bugayenko
1
+ # Copyright (c) 2017-2022 Yegor Bugayenko
2
2
  #
3
3
  # Permission is hereby granted, free of charge, to any person obtaining a copy
4
4
  # of this software and associated documentation files (the 'Software'), to deal
@@ -18,21 +18,21 @@
18
18
  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19
19
  # SOFTWARE.
20
20
 
21
- if Gem.win_platform? then
21
+ if Gem.win_platform?
22
22
  SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
23
23
  SimpleCov::Formatter::HTMLFormatter
24
24
  ]
25
25
  SimpleCov.start do
26
- add_filter "/test/"
27
- add_filter "/features/"
26
+ add_filter '/test/'
27
+ add_filter '/features/'
28
28
  end
29
29
  else
30
30
  SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter.new(
31
31
  [SimpleCov::Formatter::HTMLFormatter]
32
32
  )
33
33
  SimpleCov.start do
34
- add_filter "/test/"
35
- add_filter "/features/"
34
+ add_filter '/test/'
35
+ add_filter '/features/'
36
36
  minimum_coverage 80
37
37
  end
38
38
  end
data/Gemfile CHANGED
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2017-2020 Yegor Bugayenko
1
+ # Copyright (c) 2017-2022 Yegor Bugayenko
2
2
  #
3
3
  # Permission is hereby granted, free of charge, to any person obtaining a copy
4
4
  # of this software and associated documentation files (the 'Software'), to deal
data/LICENSE.txt CHANGED
@@ -1,6 +1,6 @@
1
1
  (The MIT License)
2
2
 
3
- Copyright (c) 2017-2020 Yegor Bugayenko
3
+ Copyright (c) 2017-2022 Yegor Bugayenko
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the 'Software'), to deal
data/README.md CHANGED
@@ -1,30 +1,31 @@
1
- <img src="/logo.svg" width="64px"/>
1
+ <img alt="XCOP logo" src="/logo.svg" width="64px"/>
2
2
 
3
3
  [![EO principles respected here](https://www.elegantobjects.org/badge.svg)](https://www.elegantobjects.org)
4
4
  [![Managed by Zerocracy](https://www.0crat.com/badge/C3RFVLU72.svg)](https://www.0crat.com/p/C3RFVLU72)
5
5
  [![DevOps By Rultor.com](http://www.rultor.com/b/yegor256/xcop)](http://www.rultor.com/p/yegor256/xcop)
6
6
  [![We recommend RubyMine](https://www.elegantobjects.org/rubymine.svg)](https://www.jetbrains.com/ruby/)
7
7
 
8
- [![Build Status](https://travis-ci.org/yegor256/xcop.svg)](https://travis-ci.org/yegor256/xcop)
9
- [![Build status](https://ci.appveyor.com/api/projects/status/orvfo2qgmd1d7a2i?svg=true)](https://ci.appveyor.com/project/yegor256/xcop)
8
+ [![rake](https://github.com/yegor256/xcop/actions/workflows/rake.yml/badge.svg)](https://github.com/yegor256/xcop/actions/workflows/rake.yml)
10
9
  [![PDD status](http://www.0pdd.com/svg?name=yegor256/xcop)](http://www.0pdd.com/p?name=yegor256/xcop)
11
10
  [![Gem Version](https://badge.fury.io/rb/xcop.svg)](http://badge.fury.io/rb/xcop)
12
11
  [![License](https://img.shields.io/badge/license-MIT-green.svg)](https://github.com/yegor256/xcop/blob/master/LICENSE.txt)
13
12
 
14
13
  [![Maintainability](https://api.codeclimate.com/v1/badges/396ec0584e0a84adc723/maintainability)](https://codeclimate.com/github/yegor256/xcop/maintainability)
15
14
  [![Test Coverage](https://img.shields.io/codecov/c/github/yegor256/xcop.svg)](https://codecov.io/github/yegor256/xcop?branch=master)
15
+ ![Lines of code](https://img.shields.io/tokei/lines/github/yegor256/xcop)
16
16
  [![Hits-of-Code](https://hitsofcode.com/github/yegor256/xcop)](https://hitsofcode.com/view/github/yegor256/xcop)
17
17
 
18
18
  This command line tool validates your XML files for proper formatting.
19
19
  If they are not formatted correctly, it prints the difference and
20
- returns with an error. You can use it two ways: 1) to fail your build
21
- if any X-like files (XML, XSD, XSL, XHTML) are not formatted correctly,
22
- and 2) to format them correctly.
20
+ exits with an error. You can use it two ways: 1) to fail your build
21
+ if any XML-ish files (for example, XML, XSD, XSL, or XHTML) are not formatted correctly,
22
+ and 2) to format them correctly using `--fix` option.
23
23
 
24
- Read this blog post of mine first:
24
+ Read this blog post first:
25
25
  [_XCOP—XML Style Checker_](https://www.yegor256.com/2017/08/29/xcop.html).
26
26
 
27
- Install it first (read below if you can't install it):
27
+ Make sure you have [Ruby installed](https://www.ruby-lang.org/en/documentation/installation/)
28
+ and then install the tool:
28
29
 
29
30
  ```bash
30
31
  $ gem install xcop
@@ -57,6 +58,24 @@ To fix all files in the directory you can do
57
58
  $ xcop --fix $(find . -name '*.xml')
58
59
  ```
59
60
 
61
+ ## Defaults
62
+
63
+ You can put command line options into `.xcop` file in the directory
64
+ where you start `xcop`. Each option should take a single line in the file.
65
+ They all will be _added_ to the list of options you specify. For example:
66
+
67
+ ```
68
+ --license LICENSE.txt
69
+ --nocolor
70
+ --quiet
71
+ --include **/*
72
+ --exclude **/*.xsl
73
+ --exclude **/*.html
74
+ ```
75
+
76
+ You can also create `~/.xcop` file (in your personal home directory), which
77
+ will also be read and _added_ to the command line options.
78
+
60
79
  ## How to use in `Rakefile`?
61
80
 
62
81
  This is what you need there:
@@ -75,6 +94,7 @@ end
75
94
  ## How to use as GitHub action?
76
95
 
77
96
  Create new workflow file in repository under `.github/workflows/xcop.yml`:
97
+
78
98
  ```yaml
79
99
  ---
80
100
  name: XCOP
@@ -85,7 +105,7 @@ name: XCOP
85
105
  - master
86
106
  # run on pull requests to master
87
107
  pull_request:
88
- brranches:
108
+ branches:
89
109
  - master
90
110
  jobs:
91
111
  build:
@@ -94,7 +114,9 @@ jobs:
94
114
  - uses: actions/checkout@v2
95
115
  - uses: g4s8/xcop-action@master
96
116
  ```
117
+
97
118
  To customize license location or files pattern use action inputs `license` and `files`:
119
+
98
120
  ```yaml
99
121
  - uses: g4s8/xcop-action@master
100
122
  with:
data/Rakefile CHANGED
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2017-2020 Yegor Bugayenko
1
+ # Copyright (c) 2017-2022 Yegor Bugayenko
2
2
  #
3
3
  # Permission is hereby granted, free of charge, to any person obtaining a copy
4
4
  # of this software and associated documentation files (the 'Software'), to deal
@@ -56,6 +56,7 @@ desc 'Run RuboCop on all directories'
56
56
  RuboCop::RakeTask.new(:rubocop) do |task|
57
57
  task.fail_on_error = true
58
58
  task.requires << 'rubocop-rspec'
59
+ task.options = ['--display-cop-names']
59
60
  end
60
61
 
61
62
  require 'cucumber/rake/task'
data/bin/xcop CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env ruby
2
- # Copyright (c) 2017-2020 Yegor Bugayenko
2
+ # Copyright (c) 2017-2022 Yegor Bugayenko
3
3
  #
4
4
  # Permission is hereby granted, free of charge, to any person obtaining a copy
5
5
  # of this software and associated documentation files (the 'Software'), to deal
@@ -23,21 +23,24 @@ STDOUT.sync = true
23
23
 
24
24
  require 'slop'
25
25
  require 'nokogiri'
26
- require_relative '../lib/xcop'
26
+ require 'set'
27
+ require_relative '../lib/xcop/cli'
27
28
  require_relative '../lib/xcop/version'
28
29
 
29
30
  if Gem::Version.new(Nokogiri::VERSION) < Gem::Version.new('1.8')
30
31
  puts "Nokogiri version #{Nokogiri::VERSION} is too old, 1.8+ is required"
31
32
  end
32
33
 
33
- file_cfg = []
34
- if File.exist?('.xcop')
35
- file_cfg += File.open('.xcop').read.gsub(/\s+/, " ").strip.split(/\s/)
34
+ def config(path)
35
+ f = File.expand_path(path)
36
+ args = []
37
+ args += File.readlines(f).map(&:strip) if File.exist?(f)
38
+ args
36
39
  end
37
40
 
38
- merged = ARGV + file_cfg
41
+ args = config('~/.xcop') + config('.xcop') + ARGV
39
42
 
40
- opts = Slop.parse(merged, strict: true, help: true) do |o|
43
+ opts = Slop.parse(args, strict: true, help: true) do |o|
41
44
  o.banner = "Usage (#{Xcop::VERSION}): xcop [options] [files...]"
42
45
  o.bool '-h', '--help', 'Show these instructions'
43
46
  o.bool '-q', '--quiet', 'Don\'t print anything if there are no errors'
@@ -45,6 +48,8 @@ opts = Slop.parse(merged, strict: true, help: true) do |o|
45
48
  o.bool '--fix', 'Fix all files instead of reporting their problems'
46
49
  o.bool '--nocolor', 'Suppress colored output'
47
50
  o.string '--license', 'File name of the boilerplate head license'
51
+ o.array '--include', 'Glob pattern(s) to include'
52
+ o.array '--exclude', 'Glob pattern(s) to exclude'
48
53
  end
49
54
 
50
55
  if opts.help?
@@ -60,15 +65,38 @@ end
60
65
  Encoding.default_external = Encoding::UTF_8
61
66
  Encoding.default_internal = Encoding::UTF_8
62
67
 
63
- license = opts.license? ? File.read(opts[:license]) : ''
68
+ license = ''
69
+ if opts.license?
70
+ unless File.exist?(opts[:license])
71
+ puts "License file is absent: #{opts[:license]}"
72
+ exit -1
73
+ end
74
+ license = File.read(opts[:license])
75
+ end
76
+
77
+ files = Set.new
78
+
79
+ if opts[:include]
80
+ opts[:include].each do |glob|
81
+ files += Dir.glob(glob).map { |f| File.expand_path(f) }
82
+ end
83
+ end
84
+
85
+ files += opts.arguments.map { |f| File.expand_path(f) }
86
+
87
+ if opts[:exclude]
88
+ opts[:exclude].each do |glob|
89
+ files -= Dir.glob(glob).map { |f| File.expand_path(f) }
90
+ end
91
+ end
64
92
 
65
93
  if opts.fix?
66
- Xcop::CLI.new(opts.arguments, license).fix do |f|
94
+ Xcop::CLI.new(files, license).fix do |f|
67
95
  puts "#{f} fixed" unless opts.quiet?
68
96
  end
69
97
  else
70
98
  begin
71
- Xcop::CLI.new(opts.arguments, license, opts.nocolor?).run do |f|
99
+ Xcop::CLI.new(files, license, nocolor: opts.nocolor?).run do |f|
72
100
  puts "#{f} looks good" unless opts.quiet?
73
101
  end
74
102
  rescue StandardError => e
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2017-2020 Yegor Bugayenko
1
+ # Copyright (c) 2017-2022 Yegor Bugayenko
2
2
  #
3
3
  # Permission is hereby granted, free of charge, to any person obtaining a copy
4
4
  # of this software and associated documentation files (the 'Software'), to deal
@@ -22,7 +22,6 @@ require 'nokogiri'
22
22
  require 'tmpdir'
23
23
  require 'slop'
24
24
  require 'English'
25
- require_relative '../../lib/xcop'
26
25
 
27
26
  Before do
28
27
  @cwd = Dir.pwd
@@ -42,9 +41,7 @@ end
42
41
 
43
42
  Given(/^I have a "([^"]*)" file with content:$/) do |file, text|
44
43
  FileUtils.mkdir_p(File.dirname(file)) unless File.exist?(file)
45
- File.open(file, 'w') do |f|
46
- f.write(text.gsub(/\\xFF/, 0xFF.chr))
47
- end
44
+ File.write(file, text.gsub(/\\xFF/, 0xFF.chr))
48
45
  end
49
46
 
50
47
  When(%r{^I run bin/xcop with "([^"]*)"$}) do |arg|
@@ -54,9 +51,7 @@ When(%r{^I run bin/xcop with "([^"]*)"$}) do |arg|
54
51
  end
55
52
 
56
53
  Then(/^Stdout contains "([^"]*)"$/) do |txt|
57
- unless @stdout.include?(txt)
58
- raise "STDOUT doesn't contain '#{txt}':\n#{@stdout}"
59
- end
54
+ raise "STDOUT doesn't contain '#{txt}':\n#{@stdout}" unless @stdout.include?(txt)
60
55
  end
61
56
 
62
57
  Then(/^Stdout is empty$/) do
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2017-2020 Yegor Bugayenko
1
+ # Copyright (c) 2017-2022 Yegor Bugayenko
2
2
  #
3
3
  # Permission is hereby granted, free of charge, to any person obtaining a copy
4
4
  # of this software and associated documentation files (the 'Software'), to deal
@@ -19,4 +19,3 @@
19
19
  # SOFTWARE.
20
20
 
21
21
  require 'simplecov'
22
- require_relative '../../lib/xcop'
data/lib/xcop/cli.rb ADDED
@@ -0,0 +1,64 @@
1
+ # Copyright (c) 2017-2022 Yegor Bugayenko
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ # of this software and associated documentation files (the 'Software'), to deal
5
+ # in the Software without restriction, including without limitation the rights
6
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ # copies of the Software, and to permit persons to whom the Software is
8
+ # furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in all
11
+ # copies or substantial portions of the Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFINGEMENT. IN NO EVENT SHALL THE
16
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19
+ # SOFTWARE.
20
+
21
+ require 'nokogiri'
22
+ require 'differ'
23
+ require 'rainbow'
24
+ require_relative 'version'
25
+ require_relative 'document'
26
+
27
+ # Command line interface.
28
+ # Author:: Yegor Bugayenko (yegor256@gmail.com)
29
+ # Copyright:: Copyright (c) 2017-2022 Yegor Bugayenko
30
+ # License:: MIT
31
+ class Xcop::CLI
32
+ def initialize(files, license, nocolor: false)
33
+ @files = files
34
+ @license = license
35
+ @nocolor = nocolor
36
+ end
37
+
38
+ def run
39
+ @files.each do |f|
40
+ doc = Xcop::Document.new(f)
41
+ diff = doc.diff(nocolor: @nocolor)
42
+ unless diff.empty?
43
+ puts diff
44
+ raise "Invalid XML formatting in #{f}"
45
+ end
46
+ unless @license.empty?
47
+ ldiff = doc.ldiff(@license)
48
+ unless ldiff.empty?
49
+ puts ldiff
50
+ raise "Broken license in #{f}"
51
+ end
52
+ end
53
+ yield(f) if block_given?
54
+ end
55
+ end
56
+
57
+ # Fix them all.
58
+ def fix
59
+ @files.each do |f|
60
+ Xcop::Document.new(f).fix(@license)
61
+ yield(f) if block_given?
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,82 @@
1
+ # Copyright (c) 2017-2022 Yegor Bugayenko
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ # of this software and associated documentation files (the 'Software'), to deal
5
+ # in the Software without restriction, including without limitation the rights
6
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ # copies of the Software, and to permit persons to whom the Software is
8
+ # furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in all
11
+ # copies or substantial portions of the Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFINGEMENT. IN NO EVENT SHALL THE
16
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19
+ # SOFTWARE.
20
+
21
+ require 'nokogiri'
22
+ require 'differ'
23
+ require 'rainbow'
24
+ require_relative 'version'
25
+
26
+ # One document.
27
+ # Author:: Yegor Bugayenko (yegor256@gmail.com)
28
+ # Copyright:: Copyright (c) 2017-2022 Yegor Bugayenko
29
+ # License:: MIT
30
+ class Xcop::Document
31
+ # Ctor.
32
+ # +path+:: Path of it
33
+ def initialize(path)
34
+ @path = path
35
+ end
36
+
37
+ # Return the difference, if any (empty string if everything is clean).
38
+ def diff(nocolor: false)
39
+ xml = Nokogiri::XML(File.open(@path), &:noblanks)
40
+ ideal = xml.to_xml(indent: 2)
41
+ now = File.read(@path)
42
+ differ(ideal, now, nocolor: nocolor)
43
+ end
44
+
45
+ # Return the difference for the license.
46
+ def ldiff(license)
47
+ xml = Nokogiri::XML(File.open(@path), &:noblanks)
48
+ comment = xml.xpath('/comment()')[0]
49
+ now = comment.nil? ? '' : comment.text.to_s.strip
50
+ ideal = license.strip
51
+ differ(ideal, now)
52
+ end
53
+
54
+ # Fixes the document.
55
+ def fix(license = '')
56
+ xml = Nokogiri::XML(File.open(@path), &:noblanks)
57
+ unless license.empty?
58
+ xml.xpath('/comment()').remove
59
+ xml.children.before(
60
+ Nokogiri::XML::Comment.new(xml, "\n#{license.strip}\n")
61
+ )
62
+ end
63
+ ideal = xml.to_xml(indent: 2)
64
+ File.write(@path, ideal)
65
+ end
66
+
67
+ private
68
+
69
+ def differ(ideal, fact, nocolor: false)
70
+ return '' if ideal == fact
71
+ if nocolor
72
+ Differ.diff_by_line(ideal, fact).to_s
73
+ else
74
+ Differ.format = :color
75
+ Differ.diff_by_line(schars(ideal), schars(fact)).to_s
76
+ end
77
+ end
78
+
79
+ def schars(text)
80
+ text.gsub(/\n/, "\\n\n")
81
+ end
82
+ end
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2017-2020 Yegor Bugayenko
1
+ # Copyright (c) 2017-2022 Yegor Bugayenko
2
2
  #
3
3
  # Permission is hereby granted, free of charge, to any person obtaining a copy
4
4
  # of this software and associated documentation files (the 'Software'), to deal
@@ -20,59 +20,51 @@
20
20
 
21
21
  require 'rake'
22
22
  require 'rake/tasklib'
23
- require_relative '../xcop'
23
+ require_relative '../xcop/cli'
24
24
 
25
25
  # Xcop rake task.
26
26
  # Author:: Yegor Bugayenko (yegor256@gmail.com)
27
- # Copyright:: Copyright (c) 2017-2020 Yegor Bugayenko
27
+ # Copyright:: Copyright (c) 2017-2022 Yegor Bugayenko
28
28
  # License:: MIT
29
- module Xcop
30
- # Rake task.
31
- class RakeTask < Rake::TaskLib
32
- attr_accessor :name
33
- attr_accessor :fail_on_error
34
- attr_accessor :excludes
35
- attr_accessor :includes
36
- attr_accessor :license
37
- attr_accessor :quiet
29
+ class Xcop::RakeTask < Rake::TaskLib
30
+ attr_accessor :name, :fail_on_error, :excludes, :includes, :license, :quiet
38
31
 
39
- def initialize(*args, &task_block)
40
- @name = args.shift || :xcop
41
- @includes = %w[xml xsd xhtml xsl html].map { |e| "**/*.#{e}" }
42
- @excludes = []
43
- @license = nil
44
- @quiet = false
45
- desc 'Run Xcop' unless ::Rake.application.last_description
46
- task(name, *args) do |_, task_args|
47
- RakeFileUtils.send(:verbose, true) do
48
- yield(*[self, task_args].slice(0, task_block.arity)) if block_given?
49
- run
50
- end
32
+ def initialize(*args, &task_block)
33
+ super()
34
+ @name = args.shift || :xcop
35
+ @includes = %w[xml xsd xhtml xsl html].map { |e| "**/*.#{e}" }
36
+ @excludes = []
37
+ @license = nil
38
+ @quiet = false
39
+ desc 'Run Xcop' unless ::Rake.application.last_description
40
+ task(name, *args) do |_, task_args|
41
+ RakeFileUtils.send(:verbose, true) do
42
+ yield(*[self, task_args].slice(0, task_block.arity)) if block_given?
43
+ run
51
44
  end
52
45
  end
46
+ end
53
47
 
54
- private
48
+ private
55
49
 
56
- def run
57
- require 'xcop'
58
- puts 'Running xcop...' unless @quiet
59
- bad = Dir.glob(@excludes)
60
- good = Dir.glob(@includes).reject { |f| bad.include?(f) }
61
- puts "Inspecting #{pluralize(good.length, 'file')}..." unless @quiet
62
- begin
63
- Xcop::CLI.new(good, @license.nil? ? '' : File.read(@license)).run do
64
- print Rainbow('.').green unless @quiet
65
- end
66
- rescue StandardError => e
67
- abort(e.message)
50
+ def run
51
+ puts 'Running xcop...' unless @quiet
52
+ bad = Dir.glob(@excludes)
53
+ good = Dir.glob(@includes).reject { |f| bad.include?(f) }
54
+ puts "Inspecting #{pluralize(good.length, 'file')}..." unless @quiet
55
+ begin
56
+ Xcop::CLI.new(good, @license.nil? ? '' : File.read(@license)).run do
57
+ print Rainbow('.').green unless @quiet
68
58
  end
69
- return if @quiet
70
- puts "\n#{pluralize(good.length, 'file')} checked, \
71
- everything looks #{Rainbow('pretty').green}"
59
+ rescue StandardError => e
60
+ abort(e.message)
72
61
  end
62
+ return if @quiet
63
+ puts "\n#{pluralize(good.length, 'file')} checked, \
64
+ everything looks #{Rainbow('pretty').green}"
65
+ end
73
66
 
74
- def pluralize(num, text)
75
- "#{num} #{num == 1 ? text : text + 's'}"
76
- end
67
+ def pluralize(num, text)
68
+ "#{num} #{num == 1 ? text : "#{text}s"}"
77
69
  end
78
70
  end
data/lib/xcop/version.rb CHANGED
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2017-2020 Yegor Bugayenko
1
+ # Copyright (c) 2017-2022 Yegor Bugayenko
2
2
  #
3
3
  # Permission is hereby granted, free of charge, to any person obtaining a copy
4
4
  # of this software and associated documentation files (the 'Software'), to deal
@@ -20,8 +20,8 @@
20
20
 
21
21
  # Xcop main module.
22
22
  # Author:: Yegor Bugayenko (yegor256@gmail.com)
23
- # Copyright:: Copyright (c) 2017-2020 Yegor Bugayenko
23
+ # Copyright:: Copyright (c) 2017-2022 Yegor Bugayenko
24
24
  # License:: MIT
25
25
  module Xcop
26
- VERSION = '0.6.1'.freeze
26
+ VERSION = '0.7.0'.freeze
27
27
  end
data/test/test__helper.rb CHANGED
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2017-2020 Yegor Bugayenko
1
+ # Copyright (c) 2017-2022 Yegor Bugayenko
2
2
  #
3
3
  # Permission is hereby granted, free of charge, to any person obtaining a copy
4
4
  # of this software and associated documentation files (the 'Software'), to deal
@@ -18,7 +18,7 @@
18
18
  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19
19
  # SOFTWARE.
20
20
 
21
- STDOUT.sync = true
21
+ $stdout.sync = true
22
22
 
23
23
  require 'simplecov'
24
24
  SimpleCov.start
@@ -28,4 +28,3 @@ if ENV['CI'] == 'true'
28
28
  end
29
29
 
30
30
  require 'minitest/autorun'
31
- require_relative '../lib/xcop'
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2017-2020 Yegor Bugayenko
1
+ # Copyright (c) 2017-2022 Yegor Bugayenko
2
2
  #
3
3
  # Permission is hereby granted, free of charge, to any person obtaining a copy
4
4
  # of this software and associated documentation files (the 'Software'), to deal
@@ -22,11 +22,11 @@ require 'minitest/autorun'
22
22
  require 'nokogiri'
23
23
  require 'tmpdir'
24
24
  require 'slop'
25
- require_relative '../lib/xcop'
25
+ require_relative '../lib/xcop/document'
26
26
 
27
- # Xcop main module test.
27
+ # Test for Document class.
28
28
  # Author:: Yegor Bugayenko (yegor256@gmail.com)
29
- # Copyright:: Copyright (c) 2017-2020 Yegor Bugayenko
29
+ # Copyright:: Copyright (c) 2017-2022 Yegor Bugayenko
30
30
  # License:: MIT
31
31
  class TestXcop < Minitest::Test
32
32
  def test_basic
@@ -34,6 +34,7 @@ class TestXcop < Minitest::Test
34
34
  f = File.join(dir, 'a.xml')
35
35
  File.write(f, "<?xml version=\"1.0\"?>\n<hello>Dude!</hello>\n")
36
36
  assert_equal(Xcop::Document.new(f).diff, '')
37
+ File.delete(f)
37
38
  end
38
39
  end
39
40
 
@@ -42,6 +43,7 @@ class TestXcop < Minitest::Test
42
43
  f = File.join(dir, 'no-eol.xml')
43
44
  File.write(f, "<?xml version=\"1.0\"?>\n<x/>")
44
45
  assert(Xcop::Document.new(f).diff != '')
46
+ File.delete(f)
45
47
  end
46
48
  end
47
49
 
@@ -62,6 +64,7 @@ class TestXcop < Minitest::Test
62
64
  ].join("\n")
63
65
  )
64
66
  assert_equal(Xcop::Document.new(f).ldiff(license), '')
67
+ File.delete(f)
65
68
  end
66
69
  end
67
70
 
@@ -78,6 +81,7 @@ class TestXcop < Minitest::Test
78
81
  ].join("\n")
79
82
  )
80
83
  assert(Xcop::Document.new(f).ldiff(license) != '')
84
+ File.delete(f)
81
85
  end
82
86
  end
83
87
 
@@ -89,6 +93,7 @@ class TestXcop < Minitest::Test
89
93
  Xcop::Document.new(f).fix(license)
90
94
  assert_equal(Xcop::Document.new(f).diff, '')
91
95
  assert_equal(Xcop::Document.new(f).ldiff(license), '')
96
+ File.delete(f)
92
97
  end
93
98
  end
94
99
 
@@ -100,6 +105,7 @@ class TestXcop < Minitest::Test
100
105
  Xcop::Document.new(f).fix(license)
101
106
  Xcop::Document.new(f).fix(license)
102
107
  assert_equal(Nokogiri::XML(File.read(f)).xpath('/comment()').length, 1)
108
+ File.delete(f)
103
109
  end
104
110
  end
105
111
  end
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2017-2020 Yegor Bugayenko
1
+ # Copyright (c) 2017-2022 Yegor Bugayenko
2
2
  #
3
3
  # Permission is hereby granted, free of charge, to any person obtaining a copy
4
4
  # of this software and associated documentation files (the 'Software'), to deal
@@ -25,31 +25,35 @@ require_relative '../lib/xcop/rake_task'
25
25
 
26
26
  # Xcop rake task.
27
27
  # Author:: Yegor Bugayenko (yegor256@gmail.com)
28
- # Copyright:: Copyright (c) 2017-2020 Yegor Bugayenko
28
+ # Copyright:: Copyright (c) 2017-2022 Yegor Bugayenko
29
29
  # License:: MIT
30
30
  class TestRakeTask < Minitest::Test
31
31
  def test_basic
32
32
  Dir.mktmpdir 'test' do |dir|
33
33
  Dir.chdir(dir)
34
- File.write('a.xml', "<?xml version=\"1.0\"?>\n<x/>\n")
34
+ f = File.join(dir, 'a.xml')
35
+ File.write(f, "<?xml version=\"1.0\"?>\n<x/>\n")
35
36
  Xcop::RakeTask.new(:xcop1) do |task|
36
37
  task.quiet = true
37
38
  # task.license = 'LICENSE.txt'
38
39
  end
39
40
  Rake::Task['xcop1'].invoke
41
+ File.delete(f)
40
42
  end
41
43
  end
42
44
 
43
45
  def test_with_broken_xml
44
46
  Dir.mktmpdir 'test' do |dir|
45
47
  Dir.chdir(dir)
46
- File.write('broken.xml', "<z><a><b></b></a>\n\n</z>")
48
+ f = File.join(dir, 'broken.xml')
49
+ File.write(f, "<z><a><b></b></a>\n\n</z>")
47
50
  Xcop::RakeTask.new(:xcop2) do |task|
48
51
  task.excludes = ['test/**/*']
49
52
  end
50
53
  assert_raises SystemExit do
51
54
  Rake::Task['xcop2'].invoke
52
55
  end
56
+ File.delete(f)
53
57
  end
54
58
  end
55
59
  end
data/xcop.gemspec CHANGED
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2017-2020 Yegor Bugayenko
1
+ # Copyright (c) 2017-2022 Yegor Bugayenko
2
2
  #
3
3
  # Permission is hereby granted, free of charge, to any person obtaining a copy
4
4
  # of this software and associated documentation files (the 'Software'), to deal
@@ -20,20 +20,19 @@
20
20
 
21
21
  require 'English'
22
22
 
23
- lib = File.expand_path('../lib', __FILE__)
23
+ lib = File.expand_path('lib', __dir__)
24
24
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
25
25
  require_relative 'lib/xcop/version'
26
26
 
27
27
  Gem::Specification.new do |s|
28
28
  s.specification_version = 2 if s.respond_to? :specification_version=
29
- if s.respond_to? :required_rubygems_version=
30
- s.required_rubygems_version = Gem::Requirement.new('>= 0')
31
- end
29
+ s.required_rubygems_version = Gem::Requirement.new('>= 0') if s.respond_to? :required_rubygems_version=
32
30
  s.rubygems_version = '2.2'
33
31
  s.required_ruby_version = '>= 2.2'
34
32
  s.name = 'xcop'
35
33
  s.version = Xcop::VERSION
36
34
  s.license = 'MIT'
35
+ s.metadata = { 'rubygems_mfa_required' => 'true' }
37
36
  s.summary = 'XML Formatting Static Validator'
38
37
  s.description = 'Validates XML-like documents for proper formatting'
39
38
  s.authors = ['Yegor Bugayenko']
@@ -41,18 +40,17 @@ Gem::Specification.new do |s|
41
40
  s.homepage = 'http://github.com/yegor256/xcop'
42
41
  s.files = `git ls-files`.split($RS)
43
42
  s.executables = s.files.grep(%r{^bin/}) { |f| File.basename(f) }
44
- s.test_files = s.files.grep(%r{^(test|spec|features)/})
45
43
  s.rdoc_options = ['--charset=UTF-8']
46
44
  s.extra_rdoc_files = ['README.md', 'LICENSE.txt']
47
45
  s.add_runtime_dependency 'differ', '~>0.1.2'
48
- s.add_runtime_dependency 'nokogiri', '~>1.10.9'
46
+ s.add_runtime_dependency 'nokogiri', '~>1.10'
49
47
  s.add_runtime_dependency 'rainbow', '~>3.0'
50
48
  s.add_runtime_dependency 'slop', '~>4.4'
51
- s.add_development_dependency 'codecov', '0.1.10'
52
- s.add_development_dependency 'cucumber', '1.3.17'
53
- s.add_development_dependency 'minitest', '5.5.0'
54
- s.add_development_dependency 'rake', '12.3.3'
55
- s.add_development_dependency 'rdoc', '4.2.0'
56
- s.add_development_dependency 'rubocop', '0.52.0'
57
- s.add_development_dependency 'rubocop-rspec', '1.5.1'
49
+ s.add_development_dependency 'codecov', '0.6.0'
50
+ s.add_development_dependency 'cucumber', '8.0.0'
51
+ s.add_development_dependency 'minitest', '5.15.0'
52
+ s.add_development_dependency 'rake', '13.0.6'
53
+ s.add_development_dependency 'rdoc', '6.4.0'
54
+ s.add_development_dependency 'rubocop', '1.30.1'
55
+ s.add_development_dependency 'rubocop-rspec', '2.11.1'
58
56
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: xcop
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.1
4
+ version: 0.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yegor Bugayenko
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-08-05 00:00:00.000000000 Z
11
+ date: 2022-06-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: differ
@@ -30,14 +30,14 @@ dependencies:
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: 1.10.9
33
+ version: '1.10'
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: 1.10.9
40
+ version: '1.10'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: rainbow
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -72,98 +72,98 @@ dependencies:
72
72
  requirements:
73
73
  - - '='
74
74
  - !ruby/object:Gem::Version
75
- version: 0.1.10
75
+ version: 0.6.0
76
76
  type: :development
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
80
  - - '='
81
81
  - !ruby/object:Gem::Version
82
- version: 0.1.10
82
+ version: 0.6.0
83
83
  - !ruby/object:Gem::Dependency
84
84
  name: cucumber
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
87
  - - '='
88
88
  - !ruby/object:Gem::Version
89
- version: 1.3.17
89
+ version: 8.0.0
90
90
  type: :development
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
94
  - - '='
95
95
  - !ruby/object:Gem::Version
96
- version: 1.3.17
96
+ version: 8.0.0
97
97
  - !ruby/object:Gem::Dependency
98
98
  name: minitest
99
99
  requirement: !ruby/object:Gem::Requirement
100
100
  requirements:
101
101
  - - '='
102
102
  - !ruby/object:Gem::Version
103
- version: 5.5.0
103
+ version: 5.15.0
104
104
  type: :development
105
105
  prerelease: false
106
106
  version_requirements: !ruby/object:Gem::Requirement
107
107
  requirements:
108
108
  - - '='
109
109
  - !ruby/object:Gem::Version
110
- version: 5.5.0
110
+ version: 5.15.0
111
111
  - !ruby/object:Gem::Dependency
112
112
  name: rake
113
113
  requirement: !ruby/object:Gem::Requirement
114
114
  requirements:
115
115
  - - '='
116
116
  - !ruby/object:Gem::Version
117
- version: 12.3.3
117
+ version: 13.0.6
118
118
  type: :development
119
119
  prerelease: false
120
120
  version_requirements: !ruby/object:Gem::Requirement
121
121
  requirements:
122
122
  - - '='
123
123
  - !ruby/object:Gem::Version
124
- version: 12.3.3
124
+ version: 13.0.6
125
125
  - !ruby/object:Gem::Dependency
126
126
  name: rdoc
127
127
  requirement: !ruby/object:Gem::Requirement
128
128
  requirements:
129
129
  - - '='
130
130
  - !ruby/object:Gem::Version
131
- version: 4.2.0
131
+ version: 6.4.0
132
132
  type: :development
133
133
  prerelease: false
134
134
  version_requirements: !ruby/object:Gem::Requirement
135
135
  requirements:
136
136
  - - '='
137
137
  - !ruby/object:Gem::Version
138
- version: 4.2.0
138
+ version: 6.4.0
139
139
  - !ruby/object:Gem::Dependency
140
140
  name: rubocop
141
141
  requirement: !ruby/object:Gem::Requirement
142
142
  requirements:
143
143
  - - '='
144
144
  - !ruby/object:Gem::Version
145
- version: 0.52.0
145
+ version: 1.30.1
146
146
  type: :development
147
147
  prerelease: false
148
148
  version_requirements: !ruby/object:Gem::Requirement
149
149
  requirements:
150
150
  - - '='
151
151
  - !ruby/object:Gem::Version
152
- version: 0.52.0
152
+ version: 1.30.1
153
153
  - !ruby/object:Gem::Dependency
154
154
  name: rubocop-rspec
155
155
  requirement: !ruby/object:Gem::Requirement
156
156
  requirements:
157
157
  - - '='
158
158
  - !ruby/object:Gem::Version
159
- version: 1.5.1
159
+ version: 2.11.1
160
160
  type: :development
161
161
  prerelease: false
162
162
  version_requirements: !ruby/object:Gem::Requirement
163
163
  requirements:
164
164
  - - '='
165
165
  - !ruby/object:Gem::Version
166
- version: 1.5.1
166
+ version: 2.11.1
167
167
  description: Validates XML-like documents for proper formatting
168
168
  email: yegor256@gmail.com
169
169
  executables:
@@ -177,17 +177,16 @@ files:
177
177
  - ".gitattributes"
178
178
  - ".github/ISSUE_TEMPLATE.md"
179
179
  - ".github/PULL_REQUEST_TEMPLATE.md"
180
+ - ".github/workflows/rake.yml"
180
181
  - ".gitignore"
181
182
  - ".pdd"
182
183
  - ".rubocop.yml"
183
184
  - ".rultor.yml"
184
185
  - ".simplecov"
185
- - ".travis.yml"
186
186
  - Gemfile
187
187
  - LICENSE.txt
188
188
  - README.md
189
189
  - Rakefile
190
- - appveyor.yml
191
190
  - bin/xcop
192
191
  - cucumber.yml
193
192
  - features/cli.feature
@@ -195,18 +194,20 @@ files:
195
194
  - features/rake.feature
196
195
  - features/step_definitions/steps.rb
197
196
  - features/support/env.rb
198
- - lib/xcop.rb
197
+ - lib/xcop/cli.rb
198
+ - lib/xcop/document.rb
199
199
  - lib/xcop/rake_task.rb
200
200
  - lib/xcop/version.rb
201
201
  - logo.svg
202
202
  - test/test__helper.rb
203
+ - test/test_document.rb
203
204
  - test/test_rake_task.rb
204
- - test/test_xcop.rb
205
205
  - xcop.gemspec
206
206
  homepage: http://github.com/yegor256/xcop
207
207
  licenses:
208
208
  - MIT
209
- metadata: {}
209
+ metadata:
210
+ rubygems_mfa_required: 'true'
210
211
  post_install_message:
211
212
  rdoc_options:
212
213
  - "--charset=UTF-8"
@@ -223,16 +224,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
223
224
  - !ruby/object:Gem::Version
224
225
  version: '0'
225
226
  requirements: []
226
- rubygems_version: 3.0.1
227
+ rubygems_version: 3.1.2
227
228
  signing_key:
228
229
  specification_version: 2
229
230
  summary: XML Formatting Static Validator
230
- test_files:
231
- - features/cli.feature
232
- - features/gem_package.feature
233
- - features/rake.feature
234
- - features/step_definitions/steps.rb
235
- - features/support/env.rb
236
- - test/test__helper.rb
237
- - test/test_rake_task.rb
238
- - test/test_xcop.rb
231
+ test_files: []
data/.travis.yml DELETED
@@ -1,13 +0,0 @@
1
- language: ruby
2
- rvm:
3
- - 2.2.2
4
- cache: bundler
5
- branches:
6
- only:
7
- - master
8
- install:
9
- - travis_retry bundle update
10
- script:
11
- - bundle exec rake
12
- after_success:
13
- - "bash <(curl -s https://codecov.io/bash)"
data/appveyor.yml DELETED
@@ -1,21 +0,0 @@
1
- version: '{build}'
2
- skip_tags: true
3
- clone_depth: 10
4
- branches:
5
- only:
6
- - master
7
- except:
8
- - gh-pages
9
- os: Windows Server 2012
10
- install:
11
- - cmd: SET PATH=C:\Ruby23-x64\bin;%PATH%
12
- - cmd: ruby --version
13
- - cmd: git --version
14
- build_script:
15
- - bundle update
16
- - bundle install
17
- test_script:
18
- - rake
19
- cache:
20
- - C:\Ruby200\bin -> xcop.gemspec
21
- - C:\Ruby200\lib\ruby\gems\2.0.0 -> xcop.gemspec
data/lib/xcop.rb DELETED
@@ -1,121 +0,0 @@
1
- # Copyright (c) 2017-2020 Yegor Bugayenko
2
- #
3
- # Permission is hereby granted, free of charge, to any person obtaining a copy
4
- # of this software and associated documentation files (the 'Software'), to deal
5
- # in the Software without restriction, including without limitation the rights
6
- # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
- # copies of the Software, and to permit persons to whom the Software is
8
- # furnished to do so, subject to the following conditions:
9
- #
10
- # The above copyright notice and this permission notice shall be included in all
11
- # copies or substantial portions of the Software.
12
- #
13
- # THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
- # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
- # FITNESS FOR A PARTICULAR PURPOSE AND NONINFINGEMENT. IN NO EVENT SHALL THE
16
- # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
- # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
- # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19
- # SOFTWARE.
20
-
21
- require 'nokogiri'
22
- require 'differ'
23
- require 'rainbow'
24
- require_relative 'xcop/version'
25
-
26
- # Xcop main module.
27
- # Author:: Yegor Bugayenko (yegor256@gmail.com)
28
- # Copyright:: Copyright (c) 2017-2020 Yegor Bugayenko
29
- # License:: MIT
30
- module Xcop
31
- # Command line interface.
32
- class CLI
33
- def initialize(files, license, nocolor = false)
34
- @files = files
35
- @license = license
36
- @nocolor = nocolor
37
- end
38
-
39
- def run
40
- @files.each do |f|
41
- doc = Document.new(f)
42
- diff = doc.diff(@nocolor)
43
- unless diff.empty?
44
- puts diff
45
- raise "Invalid XML formatting in #{f}"
46
- end
47
- unless @license.empty?
48
- ldiff = doc.ldiff(@license)
49
- unless ldiff.empty?
50
- puts ldiff
51
- raise "Broken license in #{f}"
52
- end
53
- end
54
- yield(f) if block_given?
55
- end
56
- end
57
-
58
- # Fix them all.
59
- def fix
60
- @files.each do |f|
61
- Document.new(f).fix(@license)
62
- yield(f) if block_given?
63
- end
64
- end
65
- end
66
-
67
- # One document.
68
- class Document
69
- # Ctor.
70
- # +path+:: Path of it
71
- def initialize(path)
72
- @path = path
73
- end
74
-
75
- # Return the difference, if any (empty string if everything is clean).
76
- def diff(nocolor = false)
77
- xml = Nokogiri::XML(File.open(@path), &:noblanks)
78
- ideal = xml.to_xml(indent: 2)
79
- now = File.read(@path)
80
- differ(ideal, now, nocolor)
81
- end
82
-
83
- # Return the difference for the license.
84
- def ldiff(license)
85
- xml = Nokogiri::XML(File.open(@path), &:noblanks)
86
- comment = xml.xpath('/comment()')[0]
87
- now = comment.nil? ? '' : comment.text.to_s.strip
88
- ideal = license.strip
89
- differ(ideal, now)
90
- end
91
-
92
- # Fixes the document.
93
- def fix(license = '')
94
- xml = Nokogiri::XML(File.open(@path), &:noblanks)
95
- unless license.empty?
96
- xml.xpath('/comment()').remove
97
- xml.children.before(
98
- Nokogiri::XML::Comment.new(xml, "\n#{license.strip}\n")
99
- )
100
- end
101
- ideal = xml.to_xml(indent: 2)
102
- File.write(@path, ideal)
103
- end
104
-
105
- private
106
-
107
- def differ(ideal, fact, nocolor = false)
108
- return '' if ideal == fact
109
- if nocolor
110
- Differ.diff_by_line(ideal, fact).to_s
111
- else
112
- Differ.format = :color
113
- Differ.diff_by_line(schars(ideal), schars(fact)).to_s
114
- end
115
- end
116
-
117
- def schars(text)
118
- text.gsub(/\n/, "\\n\n")
119
- end
120
- end
121
- end