berkeley_library-util 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. checksums.yaml +7 -0
  2. data/.github/workflows/build.yml +18 -0
  3. data/.gitignore +240 -0
  4. data/.idea/.gitignore +8 -0
  5. data/.idea/inspectionProfiles/Project_Default.xml +21 -0
  6. data/.idea/misc.xml +6 -0
  7. data/.idea/modules.xml +8 -0
  8. data/.idea/util.iml +123 -0
  9. data/.idea/vcs.xml +6 -0
  10. data/.rubocop.yml +334 -0
  11. data/.ruby-version +1 -0
  12. data/.simplecov +8 -0
  13. data/.yardopts +1 -0
  14. data/CHANGES.md +3 -0
  15. data/Gemfile +3 -0
  16. data/LICENSE.md +21 -0
  17. data/README.md +21 -0
  18. data/Rakefile +20 -0
  19. data/berkeley_library-util.gemspec +42 -0
  20. data/lib/berkeley_library/util/arrays.rb +178 -0
  21. data/lib/berkeley_library/util/module_info.rb +16 -0
  22. data/lib/berkeley_library/util/paths.rb +111 -0
  23. data/lib/berkeley_library/util/stringios.rb +30 -0
  24. data/lib/berkeley_library/util/strings.rb +42 -0
  25. data/lib/berkeley_library/util/sys_exits.rb +15 -0
  26. data/lib/berkeley_library/util/times.rb +22 -0
  27. data/lib/berkeley_library/util/uris/appender.rb +162 -0
  28. data/lib/berkeley_library/util/uris/requester.rb +62 -0
  29. data/lib/berkeley_library/util/uris/validator.rb +32 -0
  30. data/lib/berkeley_library/util/uris.rb +44 -0
  31. data/lib/berkeley_library/util.rb +1 -0
  32. data/rakelib/bundle.rake +8 -0
  33. data/rakelib/coverage.rake +11 -0
  34. data/rakelib/gem.rake +54 -0
  35. data/rakelib/rubocop.rake +18 -0
  36. data/rakelib/spec.rake +2 -0
  37. data/spec/.rubocop.yml +40 -0
  38. data/spec/berkeley_library/util/arrays_spec.rb +340 -0
  39. data/spec/berkeley_library/util/paths_spec.rb +90 -0
  40. data/spec/berkeley_library/util/stringios_spec.rb +34 -0
  41. data/spec/berkeley_library/util/strings_spec.rb +59 -0
  42. data/spec/berkeley_library/util/times_spec.rb +39 -0
  43. data/spec/berkeley_library/util/uris/requester_spec.rb +75 -0
  44. data/spec/berkeley_library/util/uris/validator_spec.rb +51 -0
  45. data/spec/berkeley_library/util/uris_spec.rb +133 -0
  46. data/spec/spec_helper.rb +30 -0
  47. metadata +321 -0
@@ -0,0 +1,111 @@
1
+ require 'berkeley_library/util/stringios'
2
+
3
+ module BerkeleyLibrary
4
+ module Util
5
+ # This module, modeled on the {https://golang.org/pkg/path/ Go `path` package},
6
+ # provides utility routines for modifying paths separated by forward slashes,
7
+ # such as URL paths. For system-dependent file paths, use
8
+ # {https://ruby-doc.org/stdlib-2.7.0/libdoc/pathname/rdoc/Pathname.html `Pathname`}
9
+ # instead.
10
+ module Paths
11
+ include BerkeleyLibrary::Util::StringIOs
12
+
13
+ class << self
14
+ include Paths
15
+ end
16
+
17
+ # Returns the shortest path name equivalent to `path` by purely lexical
18
+ # processing by:
19
+ #
20
+ # 1. replacing runs of multiple `/` with a single `/`
21
+ # 2. eliminating all `.` (current directory) elements
22
+ # 3. eliminating all `<child>/..` in favor of directly
23
+ # referencing the parent directory
24
+ # 4. replaing all `/..` at the beginning of the path
25
+ # with a single leading `/`
26
+ #
27
+ # The returned path ends in a slash only if it is the root `/`.
28
+ # @see https://9p.io/sys/doc/lexnames.html Rob Pike, "Lexical File Names in Plan 9 or Getting Dot-Dot Right"
29
+ #
30
+ # @param path [String, nil] the path to clean
31
+ # @return [String, nil] the cleaned path, or `nil` for a nil path.
32
+ def clean(path)
33
+ return unless path
34
+ return '.' if ['', '.'].include?(path)
35
+
36
+ StringIO.new.tap do |out|
37
+ out << '/' if path[0] == '/'
38
+ dotdot = (r = out.size)
39
+ r, dotdot = process_next(r, dotdot, path, out) while r < path.size
40
+ out << '.' if out.pos == 0
41
+ end.string
42
+ end
43
+
44
+ # Joins any number of path elements into a single path, separating
45
+ # them with slashes, ignoring empty elements and passing the result
46
+ # to {Paths#clean}.
47
+ #
48
+ # @param elements [Array<String>] the elements to join
49
+ # @return [String] the joined path
50
+ def join(*elements)
51
+ elements = elements.reject { |e| [nil, ''].include?(e) }
52
+ joined_raw = elements.join('/')
53
+ return '' if joined_raw == ''
54
+
55
+ clean(joined_raw)
56
+ end
57
+
58
+ private
59
+
60
+ def process_next(r, dotdot, path, out)
61
+ # empty path element, or .
62
+ return r + 1, dotdot if empty_or_dot?(r, path)
63
+ # .. element: remove to last /
64
+ return handle_dotdot(r, dotdot, path, out) if dotdot?(r, path)
65
+
66
+ # real path element
67
+ [append_from(r, path, out), dotdot]
68
+ end
69
+
70
+ def handle_dotdot(r, dotdot, path, out)
71
+ if out.pos > dotdot
72
+ backtrack_to_dotdot(out, dotdot)
73
+ elsif path[0] != '/'
74
+ dotdot = append_dotdot(out)
75
+ end
76
+
77
+ [r + 2, dotdot]
78
+ end
79
+
80
+ def dotdot?(r, path)
81
+ path[r] == '.' && (r + 2 == path.size || path[r + 2] == '/')
82
+ end
83
+
84
+ def empty_or_dot?(r, path)
85
+ path[r] == '/' || (path[r] == '.' && (r + 1 == path.size || path[r + 1] == '/'))
86
+ end
87
+
88
+ def append_from(r, path, out)
89
+ out << '/' if (path[0] == '/' && out.pos != 1) || (path[0] != '/' && out.pos != 0)
90
+ while r < path.size && path[r] != '/'
91
+ out << path[r]
92
+ r += 1
93
+ end
94
+ r
95
+ end
96
+
97
+ def append_dotdot(out)
98
+ out << '/' if out.pos > 1
99
+ out << '..'
100
+ out.pos
101
+ end
102
+
103
+ def backtrack_to_dotdot(out, dotdot)
104
+ out.seek(-1, IO::SEEK_CUR)
105
+ out.seek(-1, IO::SEEK_CUR) while out.pos > dotdot && getbyte(out, out.pos) != 47 # '/' is ASCII 37
106
+ out.truncate(out.pos)
107
+ end
108
+
109
+ end
110
+ end
111
+ end
@@ -0,0 +1,30 @@
1
+ require 'stringio'
2
+
3
+ module BerkeleyLibrary
4
+ module Util
5
+ module StringIOs
6
+ class << self
7
+ include StringIOs
8
+ end
9
+
10
+ # Returns the byte (**not** character) at the specified byte index
11
+ # in the specified `StringIO`.
12
+ #
13
+ # @param s [StringIO] the StringIO to search in
14
+ # @param i [Integer] the byte index
15
+ # @return [Integer, nil] the byte, or nil if the byte index is invalid.
16
+ def getbyte(s, i)
17
+ return if i >= s.size
18
+ return if s.size + i < 0
19
+
20
+ pos_orig = s.pos
21
+ begin
22
+ s.seek(i >= 0 ? i : s.size + i)
23
+ s.getbyte
24
+ ensure
25
+ s.seek(pos_orig)
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,42 @@
1
+ module BerkeleyLibrary
2
+ module Util
3
+ module Strings
4
+
5
+ ASCII_0 = '0'.ord
6
+ ASCII_9 = '9'.ord
7
+
8
+ def ascii_numeric?(s)
9
+ s.chars.all? do |c|
10
+ ord = c.ord
11
+ ord >= ASCII_0 && ord <= ASCII_9
12
+ end
13
+ end
14
+
15
+ # Locates the point at which two strings differ
16
+ #
17
+ # @return [Integer, nil] the index of the first character in either string
18
+ # that differs from the other, or `nil` if the strings are identical,
19
+ # or are not strings
20
+ def diff_index(s1, s2)
21
+ return unless string_like?(s1, s2)
22
+
23
+ shorter, longer = s1.size > s2.size ? [s2, s1] : [s1, s2]
24
+ shorter.chars.each_with_index do |c, i|
25
+ return i if c != longer[i]
26
+ end
27
+ shorter.length if shorter.length < longer.length # otherwise they're equal
28
+ end
29
+
30
+ class << self
31
+ include Strings
32
+ end
33
+
34
+ private
35
+
36
+ def string_like?(*strs)
37
+ strs.all? { |s| s.respond_to?(:chars) && s.respond_to?(:size) }
38
+ end
39
+
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,15 @@
1
+ module BerkeleyLibrary
2
+ module Util
3
+ # cf. BSD sysexits.h https://cgit.freebsd.org/src/tree/include/sysexits.h?h=releng/2.0
4
+ module SysExits
5
+ # successful termination
6
+ EX_OK = 0
7
+
8
+ # command line usage error
9
+ EX_USAGE = 64
10
+
11
+ # internal software error
12
+ EX_SOFTWARE = 70 # command line usage error
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,22 @@
1
+ require 'time'
2
+
3
+ module BerkeleyLibrary
4
+ module Util
5
+ module Times
6
+ class << self
7
+ include Times
8
+ end
9
+
10
+ # @param time [Time, Date] the time
11
+ # @return the UTC time corresponding to `time`
12
+ def ensure_utc(time)
13
+ return unless time
14
+ return time if time.respond_to?(:utc?) && time.utc?
15
+ return time.getutc if time.respond_to?(:getutc)
16
+ return time.to_time.getutc if time.respond_to?(:to_time)
17
+
18
+ raise ArgumentError, "Not a date or time: #{time.inspect}"
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,162 @@
1
+ require 'berkeley_library/util/paths'
2
+ require 'uri'
3
+ require 'typesafe_enum'
4
+
5
+ module BerkeleyLibrary
6
+ module Util
7
+ module URIs
8
+
9
+ # Appends the specified paths to the path of the specified URI, removing any extraneous slashes,
10
+ # and builds a new URI with that path and the same scheme, host, query, fragment, etc.
11
+ # as the original.
12
+ class Appender
13
+ attr_reader :original_uri, :elements
14
+
15
+ # Creates and invokes a new {Appender}.
16
+ #
17
+ # @param uri [URI, String] the original URI
18
+ # @param elements [Array<String, Symbol>] the URI elements to join.
19
+ # @raise URI::InvalidComponentError if appending the specified elements would create an invalid URI
20
+ def initialize(uri, *elements)
21
+ raise ArgumentError, 'uri cannot be nil' unless (@original_uri = URIs.uri_or_nil(uri))
22
+
23
+ @elements = elements.map(&:to_s)
24
+ @elements.each_with_index do |element, elem_index|
25
+ next start_query_at(elem_index) if element.include?('?')
26
+ next start_fragment_at(elem_index) if element.include?('#')
27
+
28
+ add_element(element)
29
+ end
30
+ end
31
+
32
+ # Returns the new URI.
33
+ #
34
+ # @return [URI] a new URI appending the joined path elements.
35
+ # @raise URI::InvalidComponentError if appending the specified elements would create an invalid URI
36
+ def to_uri
37
+ original_uri.dup.tap do |new_uri|
38
+ new_uri.path = Paths.join(original_uri.path, *path_elements)
39
+ new_uri.query = query unless query_elements.empty?
40
+ new_uri.fragment = fragment unless fragment_elements.empty?
41
+ end
42
+ end
43
+
44
+ private
45
+
46
+ def state
47
+ @state ||= :path
48
+ end
49
+
50
+ def in_query?
51
+ state == :query
52
+ end
53
+
54
+ def in_fragment?
55
+ state == :fragment
56
+ end
57
+
58
+ def query
59
+ query_elements.join
60
+ end
61
+
62
+ def fragment
63
+ fragment_elements.join
64
+ end
65
+
66
+ def path_elements
67
+ @path_elements ||= []
68
+ end
69
+
70
+ def query_elements
71
+ @query_elements ||= [].tap { |e| e << original_uri.query if original_uri.query }
72
+ end
73
+
74
+ def fragment_elements
75
+ @fragment_elements ||= [].tap { |e| e << original_uri.fragment if original_uri.fragment }
76
+ end
77
+
78
+ def start_query_at(elem_index)
79
+ raise URI::InvalidComponentError, err_query_after_fragment(elem_index) if in_fragment?
80
+ raise URI::InvalidComponentError, err_too_many_queries(elem_index) unless query_elements.empty?
81
+
82
+ handle_query_start(elem_index)
83
+ @state = :query
84
+ end
85
+
86
+ def start_fragment_at(elem_index)
87
+ raise URI::InvalidComponentError, err_too_many_fragments(elem_index) unless fragment_elements.empty?
88
+ raise URI::InvalidComponentError, err_query_after_fragment(elem_index) if query_after_fragment?(elem_index)
89
+
90
+ handle_fragment_start(elem_index)
91
+ @state = :fragment
92
+ end
93
+
94
+ def query_after_fragment?(elem_index)
95
+ e = elements[elem_index]
96
+ e.index('?', e.index('#'))
97
+ end
98
+
99
+ def add_element(e)
100
+ return fragment_elements << e if in_fragment?
101
+ return query_elements << e if in_query? || (e.include?('&') && !query_elements.empty?)
102
+
103
+ path_elements << e
104
+ end
105
+
106
+ def handle_query_start(elem_index)
107
+ element = elements[elem_index]
108
+
109
+ # if there's anything before the '?', we treat that excess as a path element
110
+ excess, q_start = split_around(element, element.index('?'))
111
+ q_start = push_fragment_start(elem_index, q_start)
112
+
113
+ query_elements << q_start
114
+ path_elements << excess
115
+ end
116
+
117
+ # if the fragment starts in the middle of this element, we keep the part before
118
+ # the fragment delimiter '#', and push the rest (w/'#') back onto the next element
119
+ # to be parsed in the next iteration
120
+ def push_fragment_start(elem_index, q_start)
121
+ return q_start unless (f_index = q_start.index('#'))
122
+
123
+ next_index = elem_index + 1
124
+ q_start, q_next = split_around(q_start, f_index) # NOTE: this doesn't return the '#'
125
+ elements[next_index] = "##{q_next}#{elements[next_index]}" # so we prepend one here
126
+ q_start
127
+ end
128
+
129
+ def handle_fragment_start(elem_index)
130
+ element = elements[elem_index]
131
+
132
+ # if there's anything before the '#', we treat that excess as a path element,
133
+ # or as a query element if there's a query
134
+ excess, f_start = split_around(element, element.index('#'))
135
+
136
+ fragment_elements << f_start
137
+ if in_query?
138
+ query_elements << excess
139
+ else
140
+ path_elements << excess
141
+ end
142
+ end
143
+
144
+ def split_around(s, i)
145
+ [s[0...i], s[(i + 1)..]]
146
+ end
147
+
148
+ def err_too_many_queries(elem_index)
149
+ "#{elements[elem_index].inspect}: URI already has a query string: #{query.inspect}"
150
+ end
151
+
152
+ def err_query_after_fragment(elem_index)
153
+ "#{elements[elem_index].inspect}: Query delimiter '?' cannot follow fragment delimeter '#'"
154
+ end
155
+
156
+ def err_too_many_fragments(elem_index)
157
+ "#{elements[elem_index].inspect}: URI already has a fragment: #{fragment.inspect}"
158
+ end
159
+ end
160
+ end
161
+ end
162
+ end
@@ -0,0 +1,62 @@
1
+ require 'rest-client'
2
+ require 'berkeley_library/util/uris/appender'
3
+ require 'berkeley_library/util/uris/validator'
4
+ require 'berkeley_library/logging'
5
+
6
+ module BerkeleyLibrary
7
+ module Util
8
+ module URIs
9
+ module Requester
10
+ class << self
11
+ include BerkeleyLibrary::Logging
12
+
13
+ # Performs a GET request.
14
+ #
15
+ # @param uri [URI, String] the URI to GET
16
+ # @param params [Hash] the query parameters to add to the URI. (Note that the URI may already include query parameters.)
17
+ # @param headers [Hash] the request headers.
18
+ # @return [String] the body as a string.
19
+ # @raise [RestClient::Exception] in the event of an error.
20
+ def get(uri, params: {}, headers: {})
21
+ url_str = url_str_with_params(uri, params)
22
+ resp = get_or_raise(url_str, headers)
23
+ resp.body
24
+ end
25
+
26
+ private
27
+
28
+ def url_str_with_params(uri, params)
29
+ raise ArgumentError, 'uri cannot be nil' unless (url_str = Validator.url_str_or_nil(uri))
30
+
31
+ elements = [].tap do |ee|
32
+ ee << url_str
33
+ ee << '?' unless url_str.include?('?')
34
+ ee << URI.encode_www_form(params)
35
+ end
36
+
37
+ uri = Appender.new(*elements).to_uri
38
+ uri.to_s
39
+ end
40
+
41
+ def get_or_raise(url_str, headers)
42
+ resp = RestClient.get(url_str, headers)
43
+ begin
44
+ return resp if (status = resp.code) == 200
45
+
46
+ raise(exception_for(resp, status))
47
+ ensure
48
+ logger.info("GET #{url_str} returned #{status}")
49
+ end
50
+ end
51
+
52
+ def exception_for(resp, status)
53
+ RestClient::RequestFailed.new(resp, status).tap do |ex|
54
+ status_message = RestClient::STATUSES[status] || '(Unknown)'
55
+ ex.message = "#{status} #{status_message}"
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,32 @@
1
+ require 'uri'
2
+
3
+ module BerkeleyLibrary
4
+ module Util
5
+ module URIs
6
+ module Validator
7
+ class << self
8
+
9
+ # Returns the specified URL as a URI.
10
+ # @param url [String, URI] the URL.
11
+ # @return [URI] the URI.
12
+ # @raise [URI::InvalidURIError] if `url` cannot be parsed as a URI.
13
+ def uri_or_nil(url)
14
+ return unless url
15
+
16
+ # noinspection RubyMismatchedReturnType
17
+ url.is_a?(URI) ? url : URI.parse(url.to_s)
18
+ end
19
+
20
+ # Returns the specified URL as a string.
21
+ # @param url [String, URI] the URL.
22
+ # @return [String] the URL.
23
+ # @raise [URI::InvalidURIError] if `url` cannot be parsed as a URI.
24
+ def url_str_or_nil(url)
25
+ uri = Validator.uri_or_nil(url)
26
+ uri.to_s if uri
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,44 @@
1
+ require 'berkeley_library/util/uris/appender'
2
+ require 'berkeley_library/util/uris/requester'
3
+ require 'berkeley_library/util/uris/validator'
4
+
5
+ module BerkeleyLibrary
6
+ module Util
7
+ module URIs
8
+ class << self
9
+ include URIs
10
+ end
11
+
12
+ # Appends the specified paths to the path of the specified URI, removing any extraneous slashes
13
+ # and merging additional query parameters, and returns a new URI with that path and the same scheme,
14
+ # host, query, fragment, etc. as the original.
15
+ #
16
+ # @param uri [URI, String] the original URI
17
+ # @param elements [Array<String, Symbol>] the URI elements to join.
18
+ # @return [URI] a new URI appending the joined path elements.
19
+ # @raise URI::InvalidComponentError if appending the specified elements would create an invalid URI
20
+ def append(uri, *elements)
21
+ Appender.new(uri, *elements).to_uri
22
+ end
23
+
24
+ # Performs a GET request.
25
+ #
26
+ # @param uri [URI, String] the URI to GET
27
+ # @param params [Hash] the query parameters to add to the URI. (Note that the URI may already include query parameters.)
28
+ # @param headers [Hash] the request headers.
29
+ # @return [String] the body as a string.
30
+ # @raise [RestClient::Exception] in the event of an error.
31
+ def get(uri, params: {}, headers: {})
32
+ Requester.get(uri, params: params, headers: headers)
33
+ end
34
+
35
+ # Returns the specified URL as a URI.
36
+ # @param url [String, URI] the URL.
37
+ # @return [URI] the URI.
38
+ # @raise [URI::InvalidURIError] if `url` cannot be parsed as a URI.
39
+ def uri_or_nil(url)
40
+ Validator.uri_or_nil(url)
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1 @@
1
+ Dir.glob(File.expand_path('util/*.rb', __dir__)).sort.each(&method(:require))
@@ -0,0 +1,8 @@
1
+ namespace :bundle do
2
+ desc 'Updates the ruby-advisory-db then runs bundle-audit'
3
+ task :audit do
4
+ require 'bundler/audit/cli'
5
+ Bundler::Audit::CLI.start ['update']
6
+ Bundler::Audit::CLI.start %w[check --ignore CVE-2015-9284]
7
+ end
8
+ end
@@ -0,0 +1,11 @@
1
+ require 'ci/reporter/rake/rspec'
2
+
3
+ # Configure CI::Reporter report generation
4
+ ENV['GENERATE_REPORTS'] ||= 'true'
5
+ ENV['CI_REPORTS'] = 'artifacts/rspec'
6
+
7
+ desc 'Run all specs in spec directory, with coverage'
8
+ task coverage: ['ci:setup:rspec'] do
9
+ ENV['COVERAGE'] ||= 'true'
10
+ Rake::Task[:spec].invoke
11
+ end
data/rakelib/gem.rake ADDED
@@ -0,0 +1,54 @@
1
+ require 'rubygems/gem_runner'
2
+ require 'berkeley_library/util/module_info'
3
+
4
+ gem_root_module = BerkeleyLibrary::Util
5
+
6
+ class << gem_root_module
7
+ def project_root
8
+ @project_root ||= File.expand_path('..', __dir__)
9
+ end
10
+
11
+ def artifacts_dir
12
+ return project_root unless ENV['CI']
13
+
14
+ @artifacts_dir ||= File.join(project_root, 'artifacts')
15
+ end
16
+
17
+ def gemspec_file
18
+ @gemspec_file ||= begin
19
+ gemspec_files = Dir.glob(File.expand_path('*.gemspec', project_root))
20
+ raise ArgumentError, "Too many .gemspecs: #{gemspec_files.join(', ')}" if gemspec_files.size > 1
21
+ raise ArgumentError, 'No .gemspec file found' if gemspec_files.empty?
22
+
23
+ gemspec_files[0]
24
+ end
25
+ end
26
+
27
+ def gemspec_basename
28
+ File.basename(gemspec_file)
29
+ end
30
+
31
+ def output_file
32
+ @output_file ||= begin
33
+ gem_name = File.basename(gemspec_file, '.*')
34
+ version = self::ModuleInfo::VERSION
35
+ basename = "#{gem_name}-#{version}.gem"
36
+ File.join(artifacts_dir, basename)
37
+ end
38
+ end
39
+
40
+ def output_file_relative
41
+ return File.basename(output_file) unless ENV['CI']
42
+
43
+ @output_file_relative ||= begin
44
+ artifacts_dir_relative = File.basename(artifacts_dir)
45
+ File.join(artifacts_dir_relative, File.basename(output_file))
46
+ end
47
+ end
48
+ end
49
+
50
+ desc "Build #{gem_root_module.gemspec_basename} as #{gem_root_module.output_file_relative}"
51
+ task :gem do
52
+ args = ['build', gem_root_module.gemspec_file, "--output=#{gem_root_module.output_file}"]
53
+ Gem::GemRunner.new.run(args)
54
+ end
@@ -0,0 +1,18 @@
1
+ require 'rubocop'
2
+ require 'rubocop/rake_task'
3
+
4
+ desc 'Run rubocop with HTML output'
5
+ RuboCop::RakeTask.new(:rubocop) do |cop|
6
+ output = ENV['RUBOCOP_OUTPUT'] || 'artifacts/rubocop/index.html'
7
+ puts "Writing RuboCop inspection report to #{output}"
8
+
9
+ cop.verbose = false
10
+ cop.formatters = ['html']
11
+ cop.options = ['--out', output]
12
+ end
13
+
14
+ desc 'Run RuboCop with auto-correct, and output results to console'
15
+ task :ra do
16
+ # b/c we want console output, we can't just use `rubocop:auto_correct`
17
+ RuboCop::CLI.new.run(['--safe-auto-correct'])
18
+ end
data/rakelib/spec.rake ADDED
@@ -0,0 +1,2 @@
1
+ require 'rspec/core/rake_task'
2
+ RSpec::Core::RakeTask.new(:spec)
data/spec/.rubocop.yml ADDED
@@ -0,0 +1,40 @@
1
+ inherit_from: ../.rubocop.yml
2
+
3
+ AllCops:
4
+ # Exclude generated files
5
+ Exclude:
6
+ - 'suite/**/*'
7
+
8
+ Style/ClassAndModuleChildren:
9
+ Enabled: false
10
+
11
+ Style/MultilineBlockChain:
12
+ Enabled: false
13
+
14
+ Style/ParallelAssignment:
15
+ Enabled: false
16
+
17
+ Layout/LineLength:
18
+ Enabled: false
19
+
20
+ Metrics/AbcSize:
21
+ Enabled: false
22
+
23
+ Metrics/BlockLength:
24
+ Enabled: false
25
+
26
+ Metrics/ClassLength:
27
+ Enabled: false
28
+
29
+ Metrics/ModuleLength:
30
+ Enabled: false
31
+
32
+ Metrics/MethodLength:
33
+ Enabled: false
34
+
35
+ ############################################################
36
+ # Added in Rubocop 0.89
37
+
38
+ # Sometimes we're testing the operator
39
+ Lint/BinaryOperatorWithIdenticalOperands:
40
+ Enabled: false