lint_trappings 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE.md +21 -0
- data/lib/lint_trappings.rb +17 -0
- data/lib/lint_trappings/application.rb +138 -0
- data/lib/lint_trappings/arguments_parser.rb +145 -0
- data/lib/lint_trappings/cli.rb +61 -0
- data/lib/lint_trappings/command/base.rb +36 -0
- data/lib/lint_trappings/command/display_documentation.rb +65 -0
- data/lib/lint_trappings/command/display_formatters.rb +14 -0
- data/lib/lint_trappings/command/display_help.rb +8 -0
- data/lib/lint_trappings/command/display_linters.rb +24 -0
- data/lib/lint_trappings/command/display_version.rb +14 -0
- data/lib/lint_trappings/command/scan.rb +19 -0
- data/lib/lint_trappings/configuration.rb +94 -0
- data/lib/lint_trappings/configuration_loader.rb +98 -0
- data/lib/lint_trappings/configuration_resolver.rb +49 -0
- data/lib/lint_trappings/document.rb +45 -0
- data/lib/lint_trappings/errors.rb +127 -0
- data/lib/lint_trappings/executable.rb +26 -0
- data/lib/lint_trappings/file_finder.rb +171 -0
- data/lib/lint_trappings/formatter/base.rb +67 -0
- data/lib/lint_trappings/formatter/checkstyle.rb +34 -0
- data/lib/lint_trappings/formatter/default.rb +99 -0
- data/lib/lint_trappings/formatter/json.rb +62 -0
- data/lib/lint_trappings/formatter_forwarder.rb +23 -0
- data/lib/lint_trappings/formatter_loader.rb +45 -0
- data/lib/lint_trappings/lint.rb +37 -0
- data/lib/lint_trappings/linter.rb +182 -0
- data/lib/lint_trappings/linter_configuration_validator.rb +42 -0
- data/lib/lint_trappings/linter_loader.rb +44 -0
- data/lib/lint_trappings/linter_plugin.rb +35 -0
- data/lib/lint_trappings/linter_selector.rb +120 -0
- data/lib/lint_trappings/location.rb +39 -0
- data/lib/lint_trappings/output.rb +118 -0
- data/lib/lint_trappings/preprocessor.rb +41 -0
- data/lib/lint_trappings/rake_task.rb +145 -0
- data/lib/lint_trappings/report.rb +58 -0
- data/lib/lint_trappings/runner.rb +161 -0
- data/lib/lint_trappings/spec.rb +12 -0
- data/lib/lint_trappings/spec/directory_helpers.rb +22 -0
- data/lib/lint_trappings/spec/indentation_helpers.rb +7 -0
- data/lib/lint_trappings/spec/matchers/report_lint_matcher.rb +169 -0
- data/lib/lint_trappings/spec/shared_contexts/linter_shared_context.rb +35 -0
- data/lib/lint_trappings/utils.rb +123 -0
- data/lib/lint_trappings/version.rb +4 -0
- metadata +117 -0
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'lint_trappings'
|
2
|
+
|
3
|
+
# Stub declaration so nested modules can reference it
|
4
|
+
module LintTrappings::Spec; end
|
5
|
+
|
6
|
+
Dir[File.join(File.dirname(__FILE__), 'spec', '**', '*.rb')].each do |file|
|
7
|
+
require file
|
8
|
+
end
|
9
|
+
|
10
|
+
RSpec.configure do |config|
|
11
|
+
config.include LintTrappings::Matchers
|
12
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'tmpdir'
|
2
|
+
|
3
|
+
# Helpers for creating temporary directories for testing.
|
4
|
+
module LintTrappings::Spec::DirectoryHelpers
|
5
|
+
module_function
|
6
|
+
|
7
|
+
# Creates a directory in a temporary directory which will automatically be
|
8
|
+
# destroyed at the end of the spec run. Any block passed to this will be
|
9
|
+
# executed with the created directory as the working directory.
|
10
|
+
#
|
11
|
+
# @return [String] The full path of the directory.
|
12
|
+
def directory(name = 'some-dir', &block)
|
13
|
+
tmpdir = Dir.mktmpdir.tap do |path|
|
14
|
+
Dir.chdir(path) do
|
15
|
+
Dir.mkdir(name)
|
16
|
+
Dir.chdir(name, &block) if block_given?
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
File.join(tmpdir, name)
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,7 @@
|
|
1
|
+
module LintTrappings::Spec::IndentationHelpers
|
2
|
+
# Strips off excess leading indentation from each line so we can use Heredocs
|
3
|
+
# for writing code without having the leading indentation count.
|
4
|
+
def normalize_indent(code)
|
5
|
+
LintTrappings::Utils.normalize_indent(code)
|
6
|
+
end
|
7
|
+
end
|
@@ -0,0 +1,169 @@
|
|
1
|
+
# rubocop:disable Metrics/ClassLength, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity, Metrics/MethodLength, Metrics/LineLength
|
2
|
+
|
3
|
+
module LintTrappings::Matchers
|
4
|
+
# RSpec matcher that returns whether or not a linter reported lints matching
|
5
|
+
# the specified criteria.
|
6
|
+
#
|
7
|
+
# @example
|
8
|
+
#
|
9
|
+
# it { should report_lint line: 2 }
|
10
|
+
class ReportLintMatcher
|
11
|
+
ALLOWED_KEYWORD_ARGUMENTS = %i[line message]
|
12
|
+
|
13
|
+
def initialize(*args, **kwargs)
|
14
|
+
@options = kwargs
|
15
|
+
|
16
|
+
if args.any?
|
17
|
+
raise ArgumentError,
|
18
|
+
'`report_lint` was given more than one argument!' if args.length > 1
|
19
|
+
|
20
|
+
if @options[:line]
|
21
|
+
raise ArgumentError,
|
22
|
+
'`line` keyword argument cannot be specified when Range is given'
|
23
|
+
end
|
24
|
+
|
25
|
+
@range = args.first
|
26
|
+
if @range.is_a?(Array)
|
27
|
+
if @range.length != 2 ||
|
28
|
+
!@range.first.is_a?(Integer) ||
|
29
|
+
!@range.last.is_a?(Integer)
|
30
|
+
raise ArgumentError,
|
31
|
+
'Location tuple must be an Array of two integers ' \
|
32
|
+
"representing line and column, but was #{@range.inspect}"
|
33
|
+
end
|
34
|
+
|
35
|
+
# Convert to an actual range by assuming it spans nothing
|
36
|
+
@range = @range..@range
|
37
|
+
elsif !@range.is_a?(Range)
|
38
|
+
raise ArgumentError, '`report_lint` must be given a Range e.g. [1, 2]..[3, 4]'
|
39
|
+
elsif !(@range.begin.is_a?(Array) && @range.end.is_a?(Array))
|
40
|
+
raise ArgumentError, 'Source range must have Array tuple endpoints'
|
41
|
+
end
|
42
|
+
else
|
43
|
+
# Otherwise no explicit range was specified, so verify the options
|
44
|
+
@options.keys.each do |key|
|
45
|
+
raise ArgumentError,
|
46
|
+
"Unknown keyword argument #{key}" unless ALLOWED_KEYWORD_ARGUMENTS.include?(key)
|
47
|
+
end
|
48
|
+
|
49
|
+
@line = @options[:line]
|
50
|
+
end
|
51
|
+
|
52
|
+
@message = @options[:message] if @options[:message]
|
53
|
+
end
|
54
|
+
|
55
|
+
def matches?(linter)
|
56
|
+
# We're cheating by accessing private values here, but it will allow us to
|
57
|
+
# present more-helpful error messages since we get access to so much more
|
58
|
+
# information by passing the linter instead of just a list of lints.
|
59
|
+
@linter = linter
|
60
|
+
@lints = linter.instance_variable_get(:@lints)
|
61
|
+
|
62
|
+
any_lint_matches?
|
63
|
+
end
|
64
|
+
|
65
|
+
def failure_message
|
66
|
+
output = 'expected that a lint would be reported'
|
67
|
+
|
68
|
+
if !any_range_matches?
|
69
|
+
output <<
|
70
|
+
if @line
|
71
|
+
" on line #{@line}"
|
72
|
+
elsif @range
|
73
|
+
" on #{range_to_str(@range)}"
|
74
|
+
end.to_s
|
75
|
+
|
76
|
+
output <<
|
77
|
+
case @lints.count
|
78
|
+
when 0
|
79
|
+
', but none were'
|
80
|
+
when 1
|
81
|
+
if @line
|
82
|
+
", but was reported on line #{@lints.first.source_range.begin.line}"
|
83
|
+
elsif @range
|
84
|
+
", but was reported on #{range_to_str(@lints.first.source_range)}"
|
85
|
+
end.to_s
|
86
|
+
else
|
87
|
+
if @line
|
88
|
+
", but lints were reported on the following lines instead:\n" +
|
89
|
+
@lints.map { |lint| lint.source_range.line }.sort.join(', ')
|
90
|
+
elsif @range
|
91
|
+
", but lints were reported on the following ranges instead:\n" +
|
92
|
+
@lints.map { |lint| range_to_str(lint.source_range) }.join("\n")
|
93
|
+
end.to_s
|
94
|
+
end
|
95
|
+
elsif @message
|
96
|
+
matching_lints = lints_matching_range
|
97
|
+
output <<
|
98
|
+
if @message.is_a?(Regexp)
|
99
|
+
" with message matching pattern #{@message.inspect} "
|
100
|
+
else
|
101
|
+
" with message #{@message.inspect} "
|
102
|
+
end
|
103
|
+
|
104
|
+
output << "but got:\n" << matching_lints.map(&:message).join("\n")
|
105
|
+
end
|
106
|
+
|
107
|
+
output
|
108
|
+
end
|
109
|
+
|
110
|
+
def failure_message_when_negated
|
111
|
+
'expected that a lint would NOT be reported'
|
112
|
+
end
|
113
|
+
|
114
|
+
def description
|
115
|
+
output = 'report a lint'
|
116
|
+
output <<
|
117
|
+
if @line
|
118
|
+
" on line #{@line}"
|
119
|
+
elsif @range
|
120
|
+
" on #{range_to_str(@range)}"
|
121
|
+
end.to_s
|
122
|
+
|
123
|
+
output
|
124
|
+
end
|
125
|
+
|
126
|
+
private
|
127
|
+
|
128
|
+
def lints_matching_range
|
129
|
+
@lints.select { |lint| range_matches?(lint) }
|
130
|
+
end
|
131
|
+
|
132
|
+
def any_lint_matches?
|
133
|
+
return true if !@line && !@range && @lints.any?
|
134
|
+
lints_matching_range.any? { |lint| message_matches?(lint) }
|
135
|
+
end
|
136
|
+
|
137
|
+
def any_range_matches?
|
138
|
+
@lints.any? do |lint|
|
139
|
+
range_matches?(lint)
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
def range_matches?(lint)
|
144
|
+
if @line
|
145
|
+
lint.source_range.begin.line == @line
|
146
|
+
else
|
147
|
+
lint.source_range == @range
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
def message_matches?(lint)
|
152
|
+
if @message.nil?
|
153
|
+
true
|
154
|
+
elsif @message.is_a?(Regexp)
|
155
|
+
lint.message =~ @message
|
156
|
+
elsif @message.is_a?(String)
|
157
|
+
lint.message == @message
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
def range_to_str(range)
|
162
|
+
"(L#{range.begin.line},C#{range.begin.column})..(L#{range.end.line},C#{range.end.column})"
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
def report_lint(*args, **kwargs)
|
167
|
+
ReportLintMatcher.new(*args, **kwargs)
|
168
|
+
end
|
169
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# Makes writing tests for linters a lot DRYer by taking any `src` variable
|
2
|
+
# defined via `let` and normalizing it (removing indentation that would be
|
3
|
+
# inserted by using Heredocs) and setting up the subject to be the lints
|
4
|
+
# returned by Linter#run.
|
5
|
+
#
|
6
|
+
# Thus a typical test will look like:
|
7
|
+
#
|
8
|
+
# @example
|
9
|
+
# require 'spec_helper'
|
10
|
+
#
|
11
|
+
# RSpec.describe MyApp::Linter::MyLinter do
|
12
|
+
# include_context 'linter'
|
13
|
+
#
|
14
|
+
# context 'when source contains "foo"' do
|
15
|
+
# let(:src) { <<-SRC }
|
16
|
+
# This is some code
|
17
|
+
# with the word "foo" in it.
|
18
|
+
# SRC
|
19
|
+
#
|
20
|
+
# it { should report_lint line: 2 }
|
21
|
+
# end
|
22
|
+
# end
|
23
|
+
shared_context 'linter' do
|
24
|
+
let(:config) do
|
25
|
+
LINT_TRAP_APPLICATION_CLASS.base_configuration.for_linter(described_class)
|
26
|
+
end
|
27
|
+
|
28
|
+
subject do
|
29
|
+
linter = described_class.new(config)
|
30
|
+
document = LINT_TRAP_APPLICATION_CLASS.document_class
|
31
|
+
.new(normalize_indent(src), config)
|
32
|
+
linter.run(document)
|
33
|
+
linter
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,123 @@
|
|
1
|
+
module LintTrappings
|
2
|
+
# Miscellaneus collection of helper functions.
|
3
|
+
module Utils
|
4
|
+
module_function
|
5
|
+
|
6
|
+
# Returns whether a glob pattern (or any of a list of patterns) matches the
|
7
|
+
# specified file.
|
8
|
+
#
|
9
|
+
# This is defined here so our file globbing options are consistent
|
10
|
+
# everywhere we perform globbing.
|
11
|
+
#
|
12
|
+
# @param glob [String, Array]
|
13
|
+
# @param file [String]
|
14
|
+
# @return [Boolean]
|
15
|
+
def any_glob_matches?(globs_or_glob, file)
|
16
|
+
Array(globs_or_glob).any? do |glob|
|
17
|
+
::File.fnmatch?(glob, file,
|
18
|
+
::File::FNM_PATHNAME | # Wildcards don't match path separators
|
19
|
+
::File::FNM_DOTMATCH) # `*` wildcard matches dotfiles
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
# Find all consecutive items satisfying the given block of a minimum size,
|
24
|
+
# yielding each group of consecutive items to the provided block.
|
25
|
+
#
|
26
|
+
# @param items [Array]
|
27
|
+
# @param satisfies [Proc] function that takes an item and returns true/false
|
28
|
+
# @param min_consecutive [Fixnum] minimum number of consecutive items before
|
29
|
+
# yielding the group
|
30
|
+
# @yield Passes list of consecutive items all matching the criteria defined
|
31
|
+
# by the `satisfies` {Proc} to the provided block
|
32
|
+
# @yieldparam group [Array] List of consecutive items
|
33
|
+
# @yieldreturn [Boolean] block should return whether item matches criteria
|
34
|
+
# for inclusion
|
35
|
+
def for_consecutive_items(items, satisfies, min_consecutive = 2)
|
36
|
+
current_index = -1
|
37
|
+
|
38
|
+
while (current_index += 1) < items.count
|
39
|
+
next unless satisfies[items[current_index]]
|
40
|
+
|
41
|
+
count = count_consecutive(items, current_index, &satisfies)
|
42
|
+
next unless count >= min_consecutive
|
43
|
+
|
44
|
+
# Yield the chunk of consecutive items
|
45
|
+
yield items[current_index...(current_index + count)]
|
46
|
+
|
47
|
+
current_index += count # Skip this patch of consecutive items to find more
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
# Count the number of consecutive items satisfying the given {Proc}.
|
52
|
+
#
|
53
|
+
# @param items [Array]
|
54
|
+
# @param offset [Fixnum] index to start searching from
|
55
|
+
# @yield [item] Passes item to the provided block.
|
56
|
+
# @yieldparam item [Object] Item to evaluate as matching criteria for
|
57
|
+
# inclusion
|
58
|
+
# @yieldreturn [Boolean] whether to include the item
|
59
|
+
# @return [Integer]
|
60
|
+
def count_consecutive(items, offset = 0, &block)
|
61
|
+
count = 1
|
62
|
+
count += 1 while (offset + count < items.count) && block.call(items[offset + count])
|
63
|
+
count
|
64
|
+
end
|
65
|
+
|
66
|
+
# Convert a class name or CamelCase string into snake_case.
|
67
|
+
#
|
68
|
+
# @see stackoverflow.com/questions/1509915/converting-camel-case-to-underscore-case-in-ruby
|
69
|
+
#
|
70
|
+
# @param str [String]
|
71
|
+
#
|
72
|
+
# @return [String]
|
73
|
+
def snake_case(str)
|
74
|
+
str.gsub(/::/, '/')
|
75
|
+
.gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
|
76
|
+
.gsub(/([a-z\d])([A-Z])/, '\1_\2')
|
77
|
+
.tr('-', '_')
|
78
|
+
.downcase
|
79
|
+
end
|
80
|
+
|
81
|
+
# Converts a string containing underscores/hyphens/spaces into CamelCase.
|
82
|
+
#
|
83
|
+
# @param str [String]
|
84
|
+
#
|
85
|
+
# @return [String]
|
86
|
+
def camel_case(str)
|
87
|
+
str.split(/_|-| /).map { |part| part.sub(/^\w/, &:upcase) }.join
|
88
|
+
end
|
89
|
+
|
90
|
+
# Returns the plural of the word if necessary based on the given count.
|
91
|
+
#
|
92
|
+
# @param word [String]
|
93
|
+
# @param count [Integer]
|
94
|
+
#
|
95
|
+
# @return [String]
|
96
|
+
def pluralize(word, count)
|
97
|
+
count == 1 ? word : "#{word}s"
|
98
|
+
end
|
99
|
+
|
100
|
+
# Strips off excess leading indentation from each line so we can use Heredocs
|
101
|
+
# for writing code without having the leading indentation count.
|
102
|
+
def normalize_indent(code)
|
103
|
+
leading_indent = code[/^(\s*)/, 1]
|
104
|
+
code.lstrip.gsub(/\n#{leading_indent}/, "\n")
|
105
|
+
end
|
106
|
+
|
107
|
+
# Calls a block of code with a modified set of environment variables,
|
108
|
+
# restoring them once the code has executed.
|
109
|
+
#
|
110
|
+
# @param env [Hash] environment variables to set
|
111
|
+
def with_environment(env)
|
112
|
+
old_env = {}
|
113
|
+
env.each do |var, value|
|
114
|
+
old_env[var] = ENV[var.to_s]
|
115
|
+
ENV[var.to_s] = value
|
116
|
+
end
|
117
|
+
|
118
|
+
yield
|
119
|
+
ensure
|
120
|
+
old_env.each { |var, value| ENV[var.to_s] = value }
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
metadata
ADDED
@@ -0,0 +1,117 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: lint_trappings
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Shane da Silva
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-02-28 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: parallel
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.6'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.6'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: terminal-table
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.4'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.4'
|
41
|
+
description: Framework for writing static analysis tools (a.k.a. linters)
|
42
|
+
email:
|
43
|
+
- shane@dasilva.io
|
44
|
+
executables: []
|
45
|
+
extensions: []
|
46
|
+
extra_rdoc_files: []
|
47
|
+
files:
|
48
|
+
- LICENSE.md
|
49
|
+
- lib/lint_trappings.rb
|
50
|
+
- lib/lint_trappings/application.rb
|
51
|
+
- lib/lint_trappings/arguments_parser.rb
|
52
|
+
- lib/lint_trappings/cli.rb
|
53
|
+
- lib/lint_trappings/command/base.rb
|
54
|
+
- lib/lint_trappings/command/display_documentation.rb
|
55
|
+
- lib/lint_trappings/command/display_formatters.rb
|
56
|
+
- lib/lint_trappings/command/display_help.rb
|
57
|
+
- lib/lint_trappings/command/display_linters.rb
|
58
|
+
- lib/lint_trappings/command/display_version.rb
|
59
|
+
- lib/lint_trappings/command/scan.rb
|
60
|
+
- lib/lint_trappings/configuration.rb
|
61
|
+
- lib/lint_trappings/configuration_loader.rb
|
62
|
+
- lib/lint_trappings/configuration_resolver.rb
|
63
|
+
- lib/lint_trappings/document.rb
|
64
|
+
- lib/lint_trappings/errors.rb
|
65
|
+
- lib/lint_trappings/executable.rb
|
66
|
+
- lib/lint_trappings/file_finder.rb
|
67
|
+
- lib/lint_trappings/formatter/base.rb
|
68
|
+
- lib/lint_trappings/formatter/checkstyle.rb
|
69
|
+
- lib/lint_trappings/formatter/default.rb
|
70
|
+
- lib/lint_trappings/formatter/json.rb
|
71
|
+
- lib/lint_trappings/formatter_forwarder.rb
|
72
|
+
- lib/lint_trappings/formatter_loader.rb
|
73
|
+
- lib/lint_trappings/lint.rb
|
74
|
+
- lib/lint_trappings/linter.rb
|
75
|
+
- lib/lint_trappings/linter_configuration_validator.rb
|
76
|
+
- lib/lint_trappings/linter_loader.rb
|
77
|
+
- lib/lint_trappings/linter_plugin.rb
|
78
|
+
- lib/lint_trappings/linter_selector.rb
|
79
|
+
- lib/lint_trappings/location.rb
|
80
|
+
- lib/lint_trappings/output.rb
|
81
|
+
- lib/lint_trappings/preprocessor.rb
|
82
|
+
- lib/lint_trappings/rake_task.rb
|
83
|
+
- lib/lint_trappings/report.rb
|
84
|
+
- lib/lint_trappings/runner.rb
|
85
|
+
- lib/lint_trappings/spec.rb
|
86
|
+
- lib/lint_trappings/spec/directory_helpers.rb
|
87
|
+
- lib/lint_trappings/spec/indentation_helpers.rb
|
88
|
+
- lib/lint_trappings/spec/matchers/report_lint_matcher.rb
|
89
|
+
- lib/lint_trappings/spec/shared_contexts/linter_shared_context.rb
|
90
|
+
- lib/lint_trappings/utils.rb
|
91
|
+
- lib/lint_trappings/version.rb
|
92
|
+
homepage: https://github.com/sds/lint-trappings
|
93
|
+
licenses:
|
94
|
+
- MIT
|
95
|
+
metadata: {}
|
96
|
+
post_install_message:
|
97
|
+
rdoc_options: []
|
98
|
+
require_paths:
|
99
|
+
- lib
|
100
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
101
|
+
requirements:
|
102
|
+
- - ">="
|
103
|
+
- !ruby/object:Gem::Version
|
104
|
+
version: '2'
|
105
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
106
|
+
requirements:
|
107
|
+
- - ">="
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '0'
|
110
|
+
requirements: []
|
111
|
+
rubyforge_project:
|
112
|
+
rubygems_version: 2.4.5.1
|
113
|
+
signing_key:
|
114
|
+
specification_version: 4
|
115
|
+
summary: Linter framework
|
116
|
+
test_files: []
|
117
|
+
has_rdoc:
|