goodcheck 0.1.0

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.
@@ -0,0 +1,57 @@
1
+ module Goodcheck
2
+ class Pattern
3
+ attr_reader :source
4
+ attr_reader :regexp
5
+
6
+ def initialize(source:, regexp:)
7
+ @source = source
8
+ @regexp = regexp
9
+ end
10
+
11
+ def self.literal(literal, case_insensitive:)
12
+ new(source: literal, regexp: Regexp.compile(Regexp.escape(literal), case_insensitive))
13
+ end
14
+
15
+ def self.regexp(regexp, case_insensitive:, multiline:)
16
+ options = 0
17
+ options |= Regexp::IGNORECASE if case_insensitive
18
+ options |= Regexp::MULTILINE if multiline
19
+
20
+ new(source: regexp, regexp: Regexp.compile(regexp, options))
21
+ end
22
+
23
+ def self.token(tokens)
24
+ new(source: tokens, regexp: compile_tokens(tokens))
25
+ end
26
+
27
+ def self.compile_tokens(source)
28
+ tokens = []
29
+ s = StringScanner.new(source)
30
+
31
+ until s.eos?
32
+ case
33
+ when s.scan(/\(|\)|\{|\}|\[|\]|\<|\>/)
34
+ tokens << Regexp.escape(s.matched)
35
+ when s.scan(/\s+/)
36
+ tokens << '\s+'
37
+ when s.scan(/(\p{Letter}|\w)+/)
38
+ tokens << Regexp.escape(s.matched)
39
+ when s.scan(%r{[!"#$%&'=\-^~¥\\|`@*:+;/?.,]+})
40
+ tokens << Regexp.escape(s.matched.rstrip)
41
+ when s.scan(/./)
42
+ tokens << Regexp.escape(s.matched)
43
+ end
44
+ end
45
+
46
+ if tokens.first =~ /\A\p{Letter}/
47
+ tokens.first.prepend('\b')
48
+ end
49
+
50
+ if tokens.last =~ /\p{Letter}\Z/
51
+ tokens.last << '\b'
52
+ end
53
+
54
+ Regexp.new(tokens.join('\s*').gsub(/\\s\*(\\s\+\\s\*)+/, '\s+'), Regexp::MULTILINE)
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,50 @@
1
+ module Goodcheck
2
+ module Reporters
3
+ class JSON
4
+ attr_reader :stdout
5
+ attr_reader :stderr
6
+ attr_reader :issues
7
+
8
+ def initialize(stdout:, stderr:)
9
+ @stdout = stdout
10
+ @stderr = stderr
11
+ @issues = []
12
+ end
13
+
14
+ def analysis
15
+ stderr.puts "Starting analysis..."
16
+ yield
17
+
18
+ json = issues.map do |issue|
19
+ {
20
+ rule_id: issue.rule.id,
21
+ path: issue.path,
22
+ location: {
23
+ start_line: issue.location.start_line,
24
+ start_column: issue.location.start_column,
25
+ end_line: issue.location.end_line,
26
+ end_column: issue.location.end_column
27
+ },
28
+ message: issue.rule.message,
29
+ justifications: issue.rule.justifications
30
+ }
31
+ end
32
+ stdout.puts ::JSON.dump(json)
33
+ end
34
+
35
+ def file(path)
36
+ stderr.puts "Checking #{path}..."
37
+ yield
38
+ end
39
+
40
+ def rule(rule)
41
+ stderr.puts " Checking #{rule.id}..."
42
+ yield
43
+ end
44
+
45
+ def issue(issue)
46
+ issues << issue
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,34 @@
1
+ module Goodcheck
2
+ module Reporters
3
+ class Text
4
+ attr_reader :stdout
5
+
6
+ def initialize(stdout:)
7
+ @stdout = stdout
8
+ end
9
+
10
+ def analysis
11
+ yield
12
+ end
13
+
14
+ def file(path)
15
+ yield
16
+ end
17
+
18
+ def rule(rule)
19
+ yield
20
+ end
21
+
22
+ def issue(issue)
23
+ line = issue.buffer.line(issue.location.start_line).chomp
24
+ end_column = if issue.location.start_line == issue.location.end_line
25
+ issue.location.end_column
26
+ else
27
+ line.bytesize
28
+ end
29
+ colored_line = line.byteslice(0, issue.location.start_column) + Rainbow(line.byteslice(issue.location.start_column, end_column - issue.location.start_column)).red + line.byteslice(end_column, line.bytesize - end_column)
30
+ stdout.puts "#{issue.path}:#{issue.location.start_line}:#{colored_line}:\t#{issue.rule.message.lines.first.chomp}"
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,21 @@
1
+ module Goodcheck
2
+ class Rule
3
+ attr_reader :id
4
+ attr_reader :patterns
5
+ attr_reader :message
6
+ attr_reader :justifications
7
+ attr_reader :globs
8
+ attr_reader :passes
9
+ attr_reader :fails
10
+
11
+ def initialize(id:, patterns:, message:, justifications:, globs:, fails:, passes:)
12
+ @id = id
13
+ @patterns = patterns
14
+ @message = message
15
+ @justifications = justifications
16
+ @globs = globs
17
+ @passes = passes
18
+ @fails = fails
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,3 @@
1
+ module Goodcheck
2
+ VERSION = "0.1.0"
3
+ end
data/sample.yml ADDED
@@ -0,0 +1,28 @@
1
+ rules:
2
+ - id: sample.debug_print
3
+ pattern:
4
+ - token: pp
5
+ - token: p
6
+ glob: "**/*.rb"
7
+ message: |
8
+ You should not use debug print
9
+ pass:
10
+ - render "app/views/welcome.html.erb"
11
+ fail:
12
+ - pp("Hello World")
13
+ - id: sample.index_zero
14
+ pattern:
15
+ - token: "[0]"
16
+ glob: "**/*.rb"
17
+ message: |
18
+ You can use #first instead of [0]
19
+ pass: array.first
20
+ fail: array[0]
21
+ - id: sample.closed_range
22
+ pattern:
23
+ - token: ...
24
+ glob: "**/*.rb"
25
+ message: |
26
+ Generally .. is better than ...
27
+ fail: 1...3
28
+ pass: 1..4
metadata ADDED
@@ -0,0 +1,161 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: goodcheck
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Soutaro Matsumoto
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2017-12-20 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.16'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.16'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: minitest
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '5.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '5.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: activesupport
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '5.0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '5.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: strong_json
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: 0.5.0
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: 0.5.0
83
+ - !ruby/object:Gem::Dependency
84
+ name: rainbow
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: 3.0.0
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: 3.0.0
97
+ description: Regexp based customizable linter
98
+ email:
99
+ - matsumoto@soutaro.com
100
+ executables:
101
+ - goodcheck
102
+ extensions: []
103
+ extra_rdoc_files: []
104
+ files:
105
+ - ".gitignore"
106
+ - ".ruby-version"
107
+ - ".travis.yml"
108
+ - Gemfile
109
+ - Gemfile.lock
110
+ - LICENSE
111
+ - README.md
112
+ - Rakefile
113
+ - bin/console
114
+ - bin/setup
115
+ - exe/goodcheck
116
+ - goodcheck.gemspec
117
+ - lib/goodcheck.rb
118
+ - lib/goodcheck/analyzer.rb
119
+ - lib/goodcheck/array_helper.rb
120
+ - lib/goodcheck/buffer.rb
121
+ - lib/goodcheck/cli.rb
122
+ - lib/goodcheck/commands/check.rb
123
+ - lib/goodcheck/commands/config_loading.rb
124
+ - lib/goodcheck/commands/init.rb
125
+ - lib/goodcheck/commands/test.rb
126
+ - lib/goodcheck/config.rb
127
+ - lib/goodcheck/config_loader.rb
128
+ - lib/goodcheck/glob.rb
129
+ - lib/goodcheck/issue.rb
130
+ - lib/goodcheck/location.rb
131
+ - lib/goodcheck/matcher.rb
132
+ - lib/goodcheck/pattern.rb
133
+ - lib/goodcheck/reporters/json.rb
134
+ - lib/goodcheck/reporters/text.rb
135
+ - lib/goodcheck/rule.rb
136
+ - lib/goodcheck/version.rb
137
+ - sample.yml
138
+ homepage: https://github.com/sideci/goodcheck
139
+ licenses: []
140
+ metadata: {}
141
+ post_install_message:
142
+ rdoc_options: []
143
+ require_paths:
144
+ - lib
145
+ required_ruby_version: !ruby/object:Gem::Requirement
146
+ requirements:
147
+ - - ">="
148
+ - !ruby/object:Gem::Version
149
+ version: '0'
150
+ required_rubygems_version: !ruby/object:Gem::Requirement
151
+ requirements:
152
+ - - ">="
153
+ - !ruby/object:Gem::Version
154
+ version: '0'
155
+ requirements: []
156
+ rubyforge_project:
157
+ rubygems_version: 2.6.13
158
+ signing_key:
159
+ specification_version: 4
160
+ summary: Regexp based customizable linter
161
+ test_files: []