goodcheck 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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: []