greener 0.1.0 → 0.2.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
  SHA1:
3
- metadata.gz: 82d715e2bc60c20c81addaf628e6261ce71fe7b3
4
- data.tar.gz: 0a8b92e22438005651b5e3ac73106b784ea9f046
3
+ metadata.gz: 1d98afd17cecb377e1bdc8e8298db1bec22e8376
4
+ data.tar.gz: f60f7de29eb95eee30d8ca8c8553cc789baabd1a
5
5
  SHA512:
6
- metadata.gz: 7fdfa149aa9569cd11b86f02529a2c420b2561d701454eaedc9a24c9a3dba26bba1df53053d086cb0daea573e88814d67a8596af9a636d86a1763a5f6f9c0ccf
7
- data.tar.gz: cc534b77ef04bc747d542cc353fd22bcc9f54d5f9dac3c8d0cf95511d2b51f163b0875a82d56475b54dbb9db6e3d92bae3f32e06cdea36b1390611a9b2a4fc05
6
+ metadata.gz: 96a060c2754ad72b3a6c6e76f05630923f494d94420731f755e22502dafdaa1cf7c0c432e57b94a74033af7b64a92411772c3799c9b0d379d83f3bec6dd924da
7
+ data.tar.gz: 879d811ead5670aa08989db2de52487dfee7dff422fe3c93d7d8a14f7abd8222b1a0676b468e8ec12fd1ddbea0c690b77129cf3274642445b6f25e400b5d6388
data/README.md CHANGED
@@ -1,9 +1,9 @@
1
- greener
1
+ Greener
2
2
  ===
3
3
 
4
- [![Circle CI](https://circleci.com/gh/smoll/greener.svg?style=svg)](https://circleci.com/gh/smoll/greener) [![Code Climate](https://codeclimate.com/github/smoll/greener/badges/gpa.svg)](https://codeclimate.com/github/smoll/greener) [![Coverage Status](https://coveralls.io/repos/smoll/greener/badge.svg?branch=master)](https://coveralls.io/r/smoll/greener?branch=master) [![Gem Version](https://badge.fury.io/rb/greener.svg)](http://badge.fury.io/rb/greener)
4
+ [![Circle CI](https://circleci.com/gh/smoll/greener.svg?style=svg)](https://circleci.com/gh/smoll/greener) [![Code Climate](https://codeclimate.com/github/smoll/greener/badges/gpa.svg)](https://codeclimate.com/github/smoll/greener) [![Coverage Status](https://coveralls.io/repos/smoll/greener/badge.svg?branch=master)](https://coveralls.io/r/smoll/greener?branch=master) [![Gem Version](https://badge.fury.io/rb/greener.svg)](http://badge.fury.io/rb/greener) [![Inline docs](http://inch-ci.org/github/smoll/greener.svg?branch=master)](http://inch-ci.org/github/smoll/greener)
5
5
 
6
- A Gherkin .feature file linter
6
+ Keep your Cucumber and Spinach feature files greener :four_leaf_clover: with this configurable linter
7
7
 
8
8
  **NOTE: This project is still under early-stage development**
9
9
 
@@ -1,8 +1,12 @@
1
- # AllCheckers:
2
- # Include:
3
- # - "**/*.feature"
4
- # Exclude:
5
- # - "**/*_exclusionary_special.feature"
1
+ AllCheckers:
2
+ Formatters:
3
+ # Summary does not need to be added here explicitly
4
+ - Progress
5
+ - SimpleText
6
+ Include:
7
+ - "**/*.feature"
8
+ # Exclude:
9
+ # - "some/excluded/path/*.feature"
6
10
 
7
11
  Style/FeatureName:
8
12
  Enabled: true
@@ -8,6 +8,8 @@ Feature: (checker) feature name
8
8
  When I run `greener`
9
9
  Then the output should contain:
10
10
  """
11
+ F
12
+
11
13
  foo/mismatched_feature_title.feature:1
12
14
  Feature: mismatched feature title LOL
13
15
  ^^^ feature title does not match file name
@@ -21,7 +23,12 @@ Feature: (checker) feature name
21
23
  Feature: Valid Title
22
24
  """
23
25
  When I run `greener`
24
- Then the output should contain exactly "1 file(s) inspected, no offenses detected\n"
26
+ Then the output should contain:
27
+ """
28
+ .
29
+
30
+ 1 file(s) inspected, no offenses detected
31
+ """
25
32
 
26
33
  Scenario: punctuation allowed
27
34
  Given a file named "foo/some_punctuation.feature" with:
@@ -35,7 +42,12 @@ Feature: (checker) feature name
35
42
  AllowPunctuation: true
36
43
  """
37
44
  When I run `greener --config config/punctuation_allowed.yml`
38
- Then the output should contain exactly "1 file(s) inspected, no offenses detected\n"
45
+ Then the output should contain:
46
+ """
47
+ .
48
+
49
+ 1 file(s) inspected, no offenses detected
50
+ """
39
51
 
40
52
  Scenario: title case enforced
41
53
  Given a file named "foo/this_isnt_title_case_yo.feature" with:
@@ -52,6 +64,8 @@ Feature: (checker) feature name
52
64
  When I run `greener --config config/enforce_title_case.yml`
53
65
  Then the output should contain:
54
66
  """
67
+ F
68
+
55
69
  foo/this_isnt_title_case_yo.feature:1
56
70
  Feature: this isn't Title Case, yo!
57
71
  ^^^ feature title is not title case. expected: This Isn't Title Case, Yo!
@@ -13,6 +13,8 @@ Feature: (checker) indentation width
13
13
  When I run `greener`
14
14
  Then the output should contain:
15
15
  """
16
+ F
17
+
16
18
  foo/indentation.feature:5
17
19
  Scenario: poorly indented
18
20
  ^^^ inconsistent indentation detected
@@ -11,7 +11,12 @@ Feature: configuration
11
11
  Enabled: false
12
12
  """
13
13
  When I run `greener --config config/disabled.yml`
14
- Then the output should contain exactly "1 file(s) inspected, no offenses detected\n"
14
+ Then the output should contain:
15
+ """
16
+ .
17
+
18
+ 1 file(s) inspected, no offenses detected
19
+ """
15
20
 
16
21
  Scenario: invalid checker specified in config
17
22
  Given a file named "foo/something.feature" with:
@@ -46,4 +51,9 @@ Feature: configuration
46
51
  Width: 4
47
52
  """
48
53
  When I run `greener --config config/complex.yml`
49
- Then the output should contain exactly "1 file(s) inspected, no offenses detected\n"
54
+ Then the output should contain:
55
+ """
56
+ .
57
+
58
+ 1 file(s) inspected, no offenses detected
59
+ """
@@ -0,0 +1,34 @@
1
+ Feature: (formatter) progress
2
+
3
+ Scenario: happy path
4
+ Given a file named "foo/good.feature" with:
5
+ """
6
+ Feature: good
7
+
8
+ Scenario: correctly indented
9
+
10
+ Scenario: correctly indented
11
+ Then boom
12
+ """
13
+ Given a file named "foo/good_too.feature" with:
14
+ """
15
+ Feature: good too
16
+
17
+ Scenario: correctly indented
18
+
19
+ Scenario: correctly indented
20
+ Then boom
21
+ """
22
+ And a file named "config/good.yml" with:
23
+ """
24
+ AllCheckers:
25
+ Formatters:
26
+ - Progress
27
+ """
28
+ When I run `greener --config config/good.yml`
29
+ Then the output should contain:
30
+ """
31
+ ..
32
+
33
+ 2 file(s) inspected, no offenses detected
34
+ """
@@ -13,6 +13,8 @@ Feature: lint
13
13
  When I run `greener`
14
14
  Then the output should contain:
15
15
  """
16
+ F
17
+
16
18
  foo/multiple_issues.feature:1
17
19
  Feature: multiple issues
18
20
  ^^^ inconsistent indentation detected
@@ -31,8 +31,7 @@ Gem::Specification.new do |spec|
31
31
  spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
32
32
  spec.require_paths = ["lib"]
33
33
 
34
- # TODO: rip this out when gherkin3 has a release
35
- spec.add_dependency "gherkin3-pre-alpha", "~> 3.0.0.alpha.1"
34
+ spec.add_dependency "gherkin", "~> 4.0.0"
36
35
  spec.add_dependency "thor", "~> 0.19.1"
37
36
  spec.add_dependency "titleize", "~> 1.3.0"
38
37
 
@@ -21,7 +21,8 @@ module Greener
21
21
  end
22
22
 
23
23
  def check_every_scenario
24
- feature[:scenarioDefinitions].each do |scenario|
24
+ scenarios = feature[:scenarioDefinitions] || feature[:children]
25
+ scenarios.each do |scenario|
25
26
  scenario[:steps].each { |step| check_a_step(step) }
26
27
 
27
28
  next if scenario[:location][:column] == (1 + configured_indentation_width)
@@ -12,7 +12,6 @@ module Greener
12
12
  def lint
13
13
  linter = Linter.new(options[:config])
14
14
  linter.lint
15
- linter.print_results
16
15
  end
17
16
 
18
17
  default_task :lint
@@ -1,18 +1,23 @@
1
1
  require "yaml"
2
2
 
3
3
  require "greener/utils"
4
- require "greener/custom_error"
4
+ require "greener/error"
5
5
 
6
6
  # Require all checker files here
7
7
  require "greener/checker/style/feature_name"
8
8
  require "greener/checker/style/indentation_width"
9
9
 
10
+ # And formatters
11
+ require "greener/formatter/progress"
12
+ require "greener/formatter/simple_text"
13
+ require "greener/formatter/summary"
14
+
10
15
  module Greener
11
16
  # Read configs from a user-specified greener.yml or fallback to defaults
12
17
  class ConfigStore
13
18
  include Utils
14
19
 
15
- attr_reader :checkers, :files
20
+ attr_reader :checkers, :files, :formatters
16
21
 
17
22
  def initialize(path, default_path = nil)
18
23
  @path = path
@@ -21,16 +26,18 @@ module Greener
21
26
 
22
27
  @checkers = {}
23
28
  @files = []
29
+ @formatters = []
24
30
  end
25
31
 
26
32
  def resolve
27
33
  if @path
28
- fail CustomError, "No config file found at specified path: #{@path}" unless File.exist? @path
34
+ fail Error::Standard, "No config file found at specified path: #{@path}" unless File.exist? @path
29
35
  config = load_yml_file @path
30
36
  end
31
- defaults = load_yml_file @default_path
32
37
 
33
- @all = @path ? defaults.merge(config) : defaults
38
+ config ||= {}
39
+ defaults = load_yml_file @default_path
40
+ @all = merge_hashes(defaults, config)
34
41
 
35
42
  validate
36
43
  self
@@ -47,15 +54,47 @@ module Greener
47
54
 
48
55
  private
49
56
 
57
+ # Deep merge, with a few post-merge checks
58
+ def merge_hashes(default, opt)
59
+ result = deep_merge(default, opt)
60
+ # Change nils to empty hashes/arrays so this class isn't littered with #nil? checks
61
+ result["AllCheckers"]["Exclude"] = [] if result["AllCheckers"]["Exclude"].nil?
62
+
63
+ result
64
+ end
65
+
66
+ def deep_merge(first, second)
67
+ merger = proc { |_key, v1, v2| v1.is_a?(Hash) && v2.is_a?(Hash) ? v1.merge(v2, &merger) : v2 }
68
+ first.merge(second, &merger)
69
+ end
70
+
50
71
  def validate
72
+ set_formatters
51
73
  set_checkers
52
74
  set_files
53
75
 
76
+ @all.delete("AllCheckers") if @all["AllCheckers"] && @all["AllCheckers"].empty?
77
+
54
78
  @all.each do |k, _v|
55
- fail CustomError, "Unknown option in config file: #{k}" # TODO: print warning instead of fail
79
+ fail Error::Standard, "Unknown option in config file: #{k}" # TODO: print warning instead of fail
56
80
  end
57
81
  end
58
82
 
83
+ def set_formatters
84
+ formatters = @all["AllCheckers"]["Formatters"].uniq.compact
85
+ # Ensure "Summary" formatter is in last position
86
+ if formatters.include?("Summary")
87
+ formatters << formatters.delete("Summary")
88
+ else
89
+ formatters << "Summary"
90
+ end
91
+ formatters.each do |f_string|
92
+ @formatters << formatter_from_string(f_string)
93
+ end
94
+
95
+ @all["AllCheckers"].delete "Formatters"
96
+ end
97
+
59
98
  def set_checkers
60
99
  @all.each do |k, v|
61
100
  next unless %w( Style/ Lint/ ).any? { |prefix| k.start_with?(prefix) }
@@ -66,25 +105,16 @@ module Greener
66
105
  end
67
106
 
68
107
  def set_files
69
- if @all["AllCheckers"].nil?
70
- # Default to all .feature files recursively
71
- return @files = files_matching_glob("**/*.feature")
72
- end
73
-
74
- @all.each do |k, v|
75
- next unless k == "AllCheckers"
76
- discover_files(v)
77
- @all.delete(k)
78
- end
79
- end
80
-
81
- def discover_files(hash)
82
108
  includes = []
83
109
  excludes = []
84
110
 
85
- hash["Include"].each { |glob| includes += files_matching_glob(glob) } if hash["Include"]
86
- hash["Exclude"].each { |glob| excludes += files_matching_glob(glob) } if hash["Exclude"]
87
- @files = (includes - excludes).uniq
111
+ @all["AllCheckers"]["Include"].each { |glob| includes += files_matching_glob(glob) }
112
+ @all["AllCheckers"].delete "Include"
113
+
114
+ @all["AllCheckers"]["Exclude"].each { |glob| excludes += files_matching_glob(glob) }
115
+ @all["AllCheckers"].delete "Exclude"
116
+
117
+ @files = includes.uniq - excludes.uniq
88
118
  end
89
119
 
90
120
  def default_absolute_path
@@ -0,0 +1,7 @@
1
+ module Greener
2
+ module Error
3
+ class Standard < StandardError; end
4
+
5
+ class LintFailed < Standard; end
6
+ end
7
+ end
@@ -0,0 +1,35 @@
1
+ module Greener
2
+ module Formatter
3
+ # Abstract base class for formatter, implements all public API methods.
4
+ #
5
+ # ## Method Invocation Order
6
+ #
7
+ # For example, when Greener inspects 2 files,
8
+ # the invocation order should be like this:
9
+ #
10
+ # * `#initialize`
11
+ # * `#started`
12
+ # * `#file_started`
13
+ # * `#file_finished`
14
+ # * `#file_started`
15
+ # * `#file_finished`
16
+ # * `#finished`
17
+ class BaseFormatter
18
+ def initialize(files)
19
+ @files = files
20
+ end
21
+
22
+ def started
23
+ end
24
+
25
+ def file_started
26
+ end
27
+
28
+ def file_finished(_violations)
29
+ end
30
+
31
+ def finished(_violations)
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,21 @@
1
+ require "greener/formatter/base_formatter"
2
+
3
+ module Greener
4
+ module Formatter
5
+ # Print progress in real-time
6
+ class Progress < BaseFormatter
7
+ def file_finished(violations)
8
+ if violations.empty?
9
+ print "."
10
+ else
11
+ print "F"
12
+ end
13
+ end
14
+
15
+ def finished(_violations)
16
+ puts ""
17
+ puts ""
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,17 @@
1
+ require "greener/formatter/base_formatter"
2
+
3
+ module Greener
4
+ module Formatter
5
+ # Prints violation info that includes file, line number, text of the line, and message
6
+ class SimpleText < BaseFormatter
7
+ def finished(violations)
8
+ violations.each do |violation|
9
+ puts "#{violation[:file]}:#{violation[:line]}"
10
+ puts "#{violation[:text_of_line]}"
11
+ puts "#{' ' * (violation[:column] - 1)}^^^ #{violation[:message]}"
12
+ puts ""
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,16 @@
1
+ require "greener/formatter/base_formatter"
2
+
3
+ module Greener
4
+ module Formatter
5
+ # Prints summary line, e.g. "10 file(s) inspected, no offenses detected"
6
+ class Summary < BaseFormatter
7
+ def finished(violations)
8
+ conclusion = violations.empty? ? "no offenses detected" : "#{violations.count} offense(s) detected"
9
+
10
+ res = "#{@files.count} file(s) inspected, #{conclusion}"
11
+ return puts(res) if violations.empty?
12
+ fail Greener::Error::LintFailed, res
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,20 @@
1
+ module Greener
2
+ # A set of Greener::Formatter::SomeFormatter objects
3
+ class FormatterSet
4
+ def initialize(formatters)
5
+ @formatters = formatters
6
+ end
7
+
8
+ # Note the "d"
9
+ def initialized(*args)
10
+ @formatters = @formatters.map { |formatter| formatter.new(*args) }
11
+ end
12
+
13
+ # All these instance methods have the same method signature as those of the Formatter classes
14
+ [:started, :file_started, :file_finished, :finished].each do |method_name|
15
+ define_method method_name do |*args|
16
+ @formatters.each { |formatter| formatter.send(method_name, *args) }
17
+ end
18
+ end
19
+ end
20
+ end
@@ -1,9 +1,6 @@
1
- require "gherkin3/parser"
2
- require "gherkin3/token_scanner"
3
- require "gherkin3/ast_builder"
4
- require "gherkin3/token_matcher"
5
-
6
1
  require "greener/config_store"
2
+ require "greener/formatter_set"
3
+ require "greener/parser"
7
4
 
8
5
  module Greener
9
6
  # Parse then lint a collection of .feature files for violations
@@ -11,49 +8,42 @@ module Greener
11
8
  def initialize(config_path)
12
9
  @config = ConfigStore.new(config_path).resolve
13
10
  @results = []
11
+ @formatter_set = FormatterSet.new @config.formatters
14
12
  end
15
13
 
16
- # Here we iterate through a list of files, then iterate through the list of
17
- # desired checkers, passing each one the filename & parsed AST.
18
- # This is fine for now, but to speed this up we could refactor this to do a
19
- # single pass through the file, line-by-line, and flagging violations as
20
- # they are encountered.
21
14
  def lint
22
- @config.files.each { |f| parse_single_file(f) }
23
- end
24
-
25
- def print_results
26
- @results.each do |violation|
27
- puts "#{violation[:file]}:#{violation[:line]}"
28
- puts "#{violation[:text_of_line]}"
29
- puts "#{' ' * (violation[:column] - 1)}^^^ #{violation[:message]}"
30
- puts ""
15
+ @formatter_set.initialized(@config.files)
16
+ @formatter_set.started
17
+
18
+ # Here we iterate through a list of files, then iterate through the list of
19
+ # desired checkers, passing each one the filename & parsed AST.
20
+ # This is fine for now, but to speed this up we could refactor this to do a
21
+ # single pass through the file, line-by-line, and flagging violations as
22
+ # they are encountered.
23
+ @config.files.each do |f|
24
+ process_file(f) # TODO: move this to its own class
31
25
  end
32
26
 
33
- print_final_line
27
+ @formatter_set.finished @results
34
28
  end
35
29
 
36
30
  private
37
31
 
38
- def parse_single_file(fname)
39
- parser = Gherkin3::Parser.new
40
- scanner = Gherkin3::TokenScanner.new(fname)
41
- builder = Gherkin3::AstBuilder.new
42
- ast = parser.parse(scanner, builder, Gherkin3::TokenMatcher.new)
32
+ def process_file(fname)
33
+ @formatter_set.file_started
34
+
35
+ ast = Parser.new(fname).ast
36
+
37
+ violations_in_file = []
43
38
 
44
39
  @config.checkers.each do |sc_klass, sc_opts|
45
40
  checker = sc_klass.new(ast, fname, sc_opts)
46
41
  checker.run
42
+ violations_in_file += checker.violations
47
43
  @results += checker.violations
48
44
  end
49
- end
50
-
51
- def print_final_line
52
- conclusion = @results.empty? ? "no offenses detected" : "#{@results.count} offense(s) detected"
53
45
 
54
- res = "#{@config.files.count} file(s) inspected, #{conclusion}"
55
- return puts(res) if @results.empty?
56
- fail Greener::Error::LintFailed, res
46
+ @formatter_set.file_finished(violations_in_file)
57
47
  end
58
48
  end
59
49
  end
@@ -0,0 +1,35 @@
1
+ require "stringio"
2
+
3
+ module Greener
4
+ # Initialize this class to delay output, https://gist.github.com/macek/596007
5
+ class OutputBuffer
6
+ def initialize
7
+ @buffer = StringIO.new
8
+ activate
9
+ end
10
+
11
+ def activate
12
+ return if @activated
13
+ self.class.original_stdout = $stdout
14
+ $stdout = @buffer
15
+ @activated = true
16
+ end
17
+
18
+ def to_s
19
+ @buffer.rewind
20
+ @buffer.read
21
+ end
22
+
23
+ def stop
24
+ self.class.restore_default
25
+ end
26
+
27
+ class << self
28
+ attr_accessor :original_stdout
29
+
30
+ def restore_default
31
+ $stdout = original_stdout
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,21 @@
1
+ require "gherkin/parser"
2
+ require "gherkin/token_scanner"
3
+
4
+ module Greener
5
+ # Wrapper around Gherkin3's Parser
6
+ class Parser
7
+ def initialize(feature)
8
+ @feature = feature # filepath or String
9
+ end
10
+
11
+ # Return an Abstract Syntax Tree from a feature file
12
+ def ast
13
+ parser = Gherkin::Parser.new
14
+ if @feature.include?("Feature:")
15
+ parser.parse(Gherkin::TokenScanner.new(@feature))
16
+ else
17
+ parser.parse(Gherkin::TokenScanner.new(File.read(@feature)))[:feature]
18
+ end
19
+ end
20
+ end
21
+ end
@@ -30,7 +30,7 @@ module Greener
30
30
 
31
31
  # Thor::Base#start does not have a return value, assume success if no exception is raised.
32
32
  0
33
- rescue Greener::CustomError => e
33
+ rescue Greener::Error::Standard => e
34
34
  @stderr.puts e.message
35
35
  1
36
36
  rescue StandardError => e
@@ -5,7 +5,13 @@ module Greener
5
5
  namespaced = str.gsub("/", "::")
6
6
  constantize "Greener::Checker::#{namespaced}"
7
7
  rescue NameError
8
- raise CustomError, "Unknown checker specified: #{str}" # TODO: print warning instead of failing
8
+ raise Error::Standard, "Unknown checker specified: #{str}" # TODO: print warning instead of failing
9
+ end
10
+
11
+ def formatter_from_string(str)
12
+ constantize "Greener::Formatter::#{str}"
13
+ rescue NameError
14
+ raise Error::Standard, "Unknown formatter specified: #{str}" # TODO: print warning instead of failing
9
15
  end
10
16
 
11
17
  private
@@ -1,4 +1,4 @@
1
1
  # Gem version
2
2
  module Greener
3
- VERSION = "0.1.0"
3
+ VERSION = "0.2.0"
4
4
  end
metadata CHANGED
@@ -1,29 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: greener
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - smoll
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-06-29 00:00:00.000000000 Z
11
+ date: 2018-03-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: gherkin3-pre-alpha
14
+ name: gherkin
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: 3.0.0.alpha.1
19
+ version: 4.0.0
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: 3.0.0.alpha.1
26
+ version: 4.0.0
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: thor
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -181,6 +181,7 @@ files:
181
181
  - features/checker_feature_name.feature
182
182
  - features/checker_indentation_width.feature
183
183
  - features/configuration.feature
184
+ - features/formatter_progress.feature
184
185
  - features/lint.feature
185
186
  - features/support/env.rb
186
187
  - greener.gemspec
@@ -190,8 +191,15 @@ files:
190
191
  - lib/greener/checker/style/indentation_width.rb
191
192
  - lib/greener/cli.rb
192
193
  - lib/greener/config_store.rb
193
- - lib/greener/custom_error.rb
194
+ - lib/greener/error.rb
195
+ - lib/greener/formatter/base_formatter.rb
196
+ - lib/greener/formatter/progress.rb
197
+ - lib/greener/formatter/simple_text.rb
198
+ - lib/greener/formatter/summary.rb
199
+ - lib/greener/formatter_set.rb
194
200
  - lib/greener/linter.rb
201
+ - lib/greener/output_buffer.rb
202
+ - lib/greener/parser.rb
195
203
  - lib/greener/runner.rb
196
204
  - lib/greener/utils.rb
197
205
  - lib/greener/version.rb
@@ -215,7 +223,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
215
223
  version: '0'
216
224
  requirements: []
217
225
  rubyforge_project:
218
- rubygems_version: 2.4.8
226
+ rubygems_version: 2.6.13
219
227
  signing_key:
220
228
  specification_version: 4
221
229
  summary: A Gherkin .feature file linter
@@ -1,7 +0,0 @@
1
- module Greener
2
- class CustomError < StandardError; end
3
-
4
- module Error
5
- class LintFailed < Greener::CustomError; end
6
- end
7
- end