loga 2.5.2 → 2.6.1

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
  SHA256:
3
- metadata.gz: 346f092fca3d84834d02408f3307462e0ec017f9634bf08396355e46a1681ec2
4
- data.tar.gz: 93949c198f5a4a697ca261bc6d13eabdbd3349c2ab2d57e845abbd5289279095
3
+ metadata.gz: 1c431f4c2be4360f29975cc8434c86647c77cf8a375bcd8fa6e6a0b47bb8a2e8
4
+ data.tar.gz: 2ec1e76ed48281e99acca8bdc3dd55b3fb6068dee599dd5c4bf92008e1af6eb0
5
5
  SHA512:
6
- metadata.gz: c64276706dd59404d3dc19370dc5b85a8390b60d80f6c781826d6417db086c445051b28ce9b85511da071da4d1c5172f7c4703e2782298f09a2e271399ee7a3f
7
- data.tar.gz: 19c9919c468fd33bcabf84877b429e631ffdffa1fe3e8b2cbf3319d8b894ffdf3e3db830549f5fa39a57b8745aa9d37d6f691fd9feeb0f4cc2a0a2538f6b5d24
6
+ metadata.gz: 5c09402cb2b8f7e90bb53ccba07df43c759a9d4cea9cd5a19f8fbfcf332b0ce7914dca1d3c085cd43d9d081e40cc2c4d18452bd5c6b44d10e1df2771c7a88146
7
+ data.tar.gz: f9f937d8e0a600c05ca50e60c05b084d6756b76158f2b4dcfc7a070ee30ad535ef2df6f0c10d6f61a99152ec2fa2cdb1815b450ce600e4be72e51e797d1165b6
data/.circleci/config.yml CHANGED
@@ -1,7 +1,7 @@
1
1
  basic_build: &basic_build
2
2
  working_directory: ~/loga
3
3
  docker:
4
- - image: circleci/ruby:2.5.1
4
+ - image: cimg/ruby:2.7.5
5
5
 
6
6
  test_build: &test_build
7
7
  working_directory: ~/loga
@@ -25,43 +25,11 @@ test_build: &test_build
25
25
  at: ./tmp
26
26
  - run: RACK_ENV=development bundle exec appraisal rspec
27
27
  - run: RACK_ENV=production bundle exec appraisal rspec
28
- - run: ./tmp/cc-test-reporter format-coverage -t simplecov -o $(ruby -e 'puts "tmp/codeclimate.#{RUBY_VERSION}.json"') coverage/.resultset.json
29
- - persist_to_workspace:
30
- root: tmp
31
- paths:
32
- - codeclimate.*.json
33
28
  - store_artifacts:
34
29
  path: coverage
35
30
 
36
31
  version: 2
37
32
  jobs:
38
- build:
39
- <<: *basic_build
40
- steps:
41
- - run:
42
- name: Download cc-test-reporter
43
- command: |
44
- mkdir -p tmp/
45
- curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./tmp/cc-test-reporter
46
- chmod +x ./tmp/cc-test-reporter
47
- - persist_to_workspace:
48
- root: ./tmp
49
- paths:
50
- - cc-test-reporter
51
- upload-coverage:
52
- <<: *basic_build
53
- steps:
54
- - attach_workspace:
55
- at: ./tmp
56
- - run:
57
- name: Upload coverage results to Code Climate
58
- command: |
59
- ./tmp/cc-test-reporter sum-coverage tmp/codeclimate.*.json -o tmp/codeclimate.total.json
60
- ./tmp/cc-test-reporter upload-coverage -i tmp/codeclimate.total.json -r $CODECLIMATE_REPO_TOKEN
61
- ruby-2.3:
62
- docker:
63
- - image: circleci/ruby:2.3
64
- <<: *test_build
65
33
  ruby-2.4:
66
34
  docker:
67
35
  - image: circleci/ruby:2.4
@@ -74,6 +42,14 @@ jobs:
74
42
  docker:
75
43
  - image: circleci/ruby:2.6
76
44
  <<: *test_build
45
+ ruby-2.7:
46
+ docker:
47
+ - image: cimg/ruby:2.7
48
+ <<: *test_build
49
+ ruby-3.0:
50
+ docker:
51
+ - image: cimg/ruby:3.0
52
+ <<: *test_build
77
53
  rubocop:
78
54
  <<: *basic_build
79
55
  steps:
@@ -103,48 +79,32 @@ workflows:
103
79
  version: 2
104
80
  test-then-push-gem:
105
81
  jobs:
106
- - build:
107
- filters:
108
- tags:
109
- only: /.*/
110
82
  - rubocop:
111
83
  filters:
112
84
  tags:
113
85
  only: /.*/
114
- - ruby-2.3:
115
- filters:
116
- tags:
117
- only: /.*/
118
- requires:
119
- - build
120
86
  - ruby-2.4:
121
87
  filters:
122
88
  tags:
123
89
  only: /.*/
124
- requires:
125
- - build
126
90
  - ruby-2.5:
127
91
  filters:
128
92
  tags:
129
93
  only: /.*/
130
- requires:
131
- - build
132
94
  - ruby-2.6:
133
95
  filters:
134
96
  tags:
135
97
  only: /.*/
136
- requires:
137
- - build
138
- - upload-coverage:
98
+ - ruby-2.7:
99
+ filters:
100
+ tags:
101
+ only: /.*/
102
+ - ruby-3.0:
139
103
  filters:
140
104
  tags:
141
105
  only: /.*/
142
- requires:
143
- - ruby-2.3
144
- - ruby-2.4
145
- - ruby-2.5
146
- - ruby-2.6
147
106
  - push-to-rubygems:
107
+ context: org-rubygems
148
108
  filters:
149
109
  tags:
150
110
  only: /^v\d.+/
@@ -152,7 +112,8 @@ workflows:
152
112
  ignore: /.*/
153
113
  requires:
154
114
  - rubocop
155
- - ruby-2.3
156
115
  - ruby-2.4
157
116
  - ruby-2.5
158
117
  - ruby-2.6
118
+ - ruby-2.7
119
+ - ruby-3.0
data/Appraisals CHANGED
@@ -8,20 +8,22 @@ if Gem::Version.new(RUBY_VERSION) < Gem::Version.new('2.4.0')
8
8
  end
9
9
  end
10
10
 
11
- appraise 'rails42' do
12
- gem 'rails', '~> 4.2.0'
13
- end
11
+ if Gem::Version.new(RUBY_VERSION) < Gem::Version.new('2.7.0')
12
+ appraise 'rails42' do
13
+ gem 'rails', '~> 4.2.0'
14
+ end
14
15
 
15
- appraise 'sinatra14' do
16
- gem 'sinatra', '~> 1.4.0'
17
- end
16
+ appraise 'rails50' do
17
+ gem 'rails', '~> 5.0.0'
18
+ end
18
19
 
19
- appraise 'rails50' do
20
- gem 'rails', '~> 5.0.0'
20
+ appraise 'rails52' do
21
+ gem 'rails', '~> 5.2.0'
22
+ end
21
23
  end
22
24
 
23
- appraise 'rails52' do
24
- gem 'rails', '~> 5.2.0'
25
+ appraise 'sinatra14' do
26
+ gem 'sinatra', '~> 1.4.0'
25
27
  end
26
28
 
27
29
  if Gem::Version.new(RUBY_VERSION) > Gem::Version.new('2.5.0')
@@ -32,6 +34,20 @@ if Gem::Version.new(RUBY_VERSION) > Gem::Version.new('2.5.0')
32
34
  appraise 'sidekiq6' do
33
35
  gem 'sidekiq', '~> 6.0'
34
36
  end
37
+
38
+ appraise 'sidekiq61' do
39
+ gem 'sidekiq', '~> 6.1.0'
40
+ end
41
+ end
42
+
43
+ if Gem::Version.new(RUBY_VERSION) > Gem::Version.new('2.7.0')
44
+ appraise 'rails61' do
45
+ gem 'rails', '~> 6.1.4.4'
46
+ end
47
+
48
+ appraise 'rails70' do
49
+ gem 'rails', '~> 7.0.0'
50
+ end
35
51
  end
36
52
 
37
53
  appraise 'sidekiq51' do
data/CHANGELOG.md CHANGED
@@ -4,6 +4,26 @@ All notable changes to this project will be documented in this file.
4
4
  The format is based on [Keep a Changelog](http://keepachangelog.com/)
5
5
  and this project adheres to [Semantic Versioning](http://semver.org/).
6
6
 
7
+ ## [2.6.1] - 2022-02-22
8
+ ### Fixed
9
+ - Fix compatibility with sidekiq 6.4.1
10
+
11
+ ## [2.6.0] - 2021-12-22
12
+ ### Added
13
+ - Allow using the gem with rails 7
14
+ - Add a build for ruby 3.0
15
+
16
+ ### Removed
17
+ - Remove build for ruby 2.3
18
+
19
+ ## [2.5.4] - 2021-03-24
20
+ ### Fixed
21
+ - Remove state from Rack middleware, to prevent race conditions where one request would overwrite the state of another
22
+
23
+ ## [2.5.3] - 2020-10-27
24
+ ### Fixed
25
+ - Support for sidekiq 6 - previous versions were causing sidekiq to crash with `Internal exception!`
26
+
7
27
  ## [2.5.2] - 2020-10-21
8
28
  ### Fixed
9
29
  - Support for sidekiq 6
data/Guardfile CHANGED
@@ -15,7 +15,7 @@ end
15
15
 
16
16
  group :rails do
17
17
  %w[production development].each do |env|
18
- %w[rails32 rails40 rails50 rails52].each do |appraisal|
18
+ %w[rails52 rails61 rails70].each do |appraisal|
19
19
  cmd = "RACK_ENV=#{env} bundle exec appraisal #{appraisal} rspec"
20
20
 
21
21
  guard :rspec, all_on_start: true, cmd: cmd do
data/README.md CHANGED
@@ -4,7 +4,7 @@
4
4
  [![Build Status](https://circleci.com/gh/FundingCircle/loga/tree/master.svg?style=shield&circle-token=9b81c3cf8468a8c3dc760f4c0398cf8914cb27d4)](https://circleci.com/gh/FundingCircle/loga/tree/master)
5
5
  [![Code Quality](https://codeclimate.com/repos/5563694f6956805723005d2f/badges/8eecb9144730614fb39e/gpa.svg)](https://codeclimate.com/repos/5563694f6956805723005d2f/feed)
6
6
  [![Test Coverage](https://codeclimate.com/repos/5563694f6956805723005d2f/badges/8eecb9144730614fb39e/coverage.svg)](https://codeclimate.com/repos/5563694f6956805723005d2f/coverage)
7
- [![Dependency Status](https://gemnasium.com/badges/github.com/FundingCircle/loga.svg)](https://gemnasium.com/github.com/FundingCircle/loga)
7
+ [![Dependency Status](https://img.shields.io/librariesio/release/rubygems/loga)](https://libraries.io/rubygems/loga)
8
8
 
9
9
  ## Description
10
10
 
@@ -5,7 +5,7 @@ source "https://rubygems.org"
5
5
  gem "rails", "~> 6.0.0"
6
6
 
7
7
  group :test do
8
- gem "simplecov"
8
+ gem "simplecov", "~> 0.17.0"
9
9
  end
10
10
 
11
11
  gemspec path: "../"
@@ -0,0 +1,11 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "rails", "~> 6.1.4.4"
6
+
7
+ group :test do
8
+ gem "simplecov", "~> 0.17.0"
9
+ end
10
+
11
+ gemspec path: "../"
@@ -0,0 +1,11 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "rails", "~> 7.0.0"
6
+
7
+ group :test do
8
+ gem "simplecov", "~> 0.17.0"
9
+ end
10
+
11
+ gemspec path: "../"
@@ -5,7 +5,7 @@ source "https://rubygems.org"
5
5
  gem "sidekiq", "~> 5.1.0"
6
6
 
7
7
  group :test do
8
- gem "simplecov"
8
+ gem "simplecov", "~> 0.17.0"
9
9
  end
10
10
 
11
11
  gemspec path: "../"
@@ -5,7 +5,7 @@ source "https://rubygems.org"
5
5
  gem "sidekiq", "~> 6.0"
6
6
 
7
7
  group :test do
8
- gem "simplecov"
8
+ gem "simplecov", "~> 0.17.0"
9
9
  end
10
10
 
11
11
  gemspec path: "../"
@@ -0,0 +1,11 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "sidekiq", "~> 6.1.0"
6
+
7
+ group :test do
8
+ gem "simplecov", "~> 0.17.0"
9
+ end
10
+
11
+ gemspec path: "../"
@@ -5,7 +5,7 @@ source "https://rubygems.org"
5
5
  gem "sinatra", "~> 1.4.0"
6
6
 
7
7
  group :test do
8
- gem "simplecov"
8
+ gem "simplecov", "~> 0.17.0"
9
9
  end
10
10
 
11
11
  gemspec path: "../"
@@ -3,7 +3,7 @@
3
3
  source "https://rubygems.org"
4
4
 
5
5
  group :test do
6
- gem "simplecov"
6
+ gem "simplecov", "~> 0.17.0"
7
7
  end
8
8
 
9
9
  gemspec path: "../"
@@ -79,6 +79,7 @@ module Loga
79
79
  { format: ENV['LOGA_FORMAT'].presence }.reject { |_, v| v.nil? }
80
80
  end
81
81
 
82
+ # Note: sidekiq 6 will extend the logger -> https://github.com/mperham/sidekiq/blob/v6.1.2/lib/sidekiq.rb#L210
82
83
  def initialize_logger
83
84
  device.sync = sync
84
85
  logger = Logger.new(device)
@@ -47,7 +47,8 @@ module Loga
47
47
  end
48
48
 
49
49
  event.timestamp ||= time
50
- event.data ||= {}
50
+ # Overwrite sidekiq_context data anything manually specified
51
+ event.data = sidekiq_context.merge!(event.data || {})
51
52
  event.data.tap do |hash|
52
53
  hash.merge! compute_exception(event.exception)
53
54
  hash.merge! compute_type(event.type)
@@ -101,6 +102,20 @@ module Loga
101
102
  tags: current_tags.join(' '),
102
103
  }
103
104
  end
105
+
106
+ def sidekiq_context
107
+ return {} unless defined?(::Sidekiq::Context)
108
+
109
+ c = ::Sidekiq::Context.current
110
+
111
+ # The context usually holds :class and :jid. :elapsed is added when the job ends
112
+ data = c.dup
113
+ if data.key?(:elapsed)
114
+ data[:duration] = data[:elapsed].to_f
115
+ data.delete(:elapsed)
116
+ end
117
+ data
118
+ end
104
119
  end
105
120
  end
106
121
  end
@@ -7,65 +7,57 @@ module Loga
7
7
  @app = app
8
8
  end
9
9
 
10
- def call(env)
10
+ def call(env, started_at = Time.now)
11
11
  request = Loga::Rack::Request.new(env)
12
12
  env['loga.request.original_path'] = request.path
13
13
 
14
14
  if logger.respond_to?(:tagged)
15
- logger.tagged(compute_tags(request)) { call_app(request, env) }
15
+ logger.tagged(compute_tags(request)) { call_app(request, env, started_at) }
16
16
  else
17
- call_app(request, env)
17
+ call_app(request, env, started_at)
18
18
  end
19
19
  end
20
20
 
21
21
  private
22
22
 
23
- attr_reader :data, :env, :request, :started_at
24
-
25
- def call_app(request, env)
26
- @data = {}
27
- @env = env
28
- @request = request
29
- @started_at = Time.now
30
-
31
- @app.call(env).tap { |status, _headers, _body| data['status'] = status.to_i }
23
+ def call_app(request, env, started_at)
24
+ status, _headers, _body = @app.call(env)
32
25
  ensure
33
- set_data
34
- send_message
35
- end
26
+ data = generate_data(request, status, started_at)
36
27
 
37
- # rubocop:disable Metrics/LineLength
38
- def set_data
39
- data['method'] = request.request_method
40
- data['path'] = request.original_path
41
- data['params'] = request.filtered_parameters
42
- data['request_id'] = request.uuid
43
- data['request_ip'] = request.ip
44
- data['user_agent'] = request.user_agent
45
- data['controller'] = request.controller_action_name if request.controller_action_name
46
- data['duration'] = duration_in_ms(started_at, Time.now)
47
-
48
- # If data['status'] is nil we assume an exception was raised when calling the application
49
- data['status'] ||= 500
50
- end
51
- # rubocop:enable Metrics/LineLength
28
+ exception = compute_exception(env)
52
29
 
53
- def send_message
54
30
  event = Loga::Event.new(
55
31
  data: { request: data },
56
- exception: compute_exception,
57
- message: compute_message,
32
+ exception: exception,
33
+ message: compute_message(request, data),
58
34
  timestamp: started_at,
59
35
  type: 'request',
60
36
  )
61
- logger.public_send(compute_level, event)
37
+
38
+ exception ? logger.error(event) : logger.info(event)
39
+ end
40
+
41
+ def generate_data(request, status, started_at)
42
+ controller = request.controller_action_name
43
+ status ||= 500
44
+ {
45
+ 'method' => request.request_method,
46
+ 'path' => request.original_path,
47
+ 'params' => request.filtered_parameters,
48
+ 'request_id' => request.uuid,
49
+ 'request_ip' => request.ip,
50
+ 'user_agent' => request.user_agent,
51
+ 'duration' => duration_in_ms(started_at, Time.now),
52
+ 'status' => status.to_i,
53
+ }.tap { |d| d['controller'] = controller if controller }
62
54
  end
63
55
 
64
56
  def logger
65
57
  Loga.logger
66
58
  end
67
59
 
68
- def compute_message
60
+ def compute_message(request, data)
69
61
  '%<method>s %<filtered_full_path>s %<status>d in %<duration>dms' % {
70
62
  method: request.request_method,
71
63
  filtered_full_path: request.filtered_full_path,
@@ -74,19 +66,14 @@ module Loga
74
66
  }
75
67
  end
76
68
 
77
- def compute_level
78
- compute_exception ? :error : :info
79
- end
69
+ def compute_exception(env)
70
+ exception =
71
+ env['loga.exception'] || env['action_dispatch.exception'] ||
72
+ env['sinatra.error'] || env['rack.exception']
80
73
 
81
- def compute_exception
82
74
  filter_exceptions.include?(exception.class.to_s) ? nil : exception
83
75
  end
84
76
 
85
- def exception
86
- env['loga.exception'] || env['action_dispatch.exception'] ||
87
- env['sinatra.error'] || env['rack.exception']
88
- end
89
-
90
77
  def filter_exceptions
91
78
  Loga.configuration.filter_exceptions
92
79
  end
data/lib/loga/railtie.rb CHANGED
@@ -125,7 +125,7 @@ module Loga
125
125
  def silence_rails_rack_logger
126
126
  case Rails::VERSION::MAJOR
127
127
  when 3 then require 'loga/ext/rails/rack/logger3.rb'
128
- when 4..6 then require 'loga/ext/rails/rack/logger.rb'
128
+ when 4..7 then require 'loga/ext/rails/rack/logger.rb'
129
129
  else
130
130
  raise Loga::ConfigurationError,
131
131
  "Rails #{Rails::VERSION::MAJOR} is unsupported"
data/lib/loga/sidekiq.rb CHANGED
@@ -1,13 +1,21 @@
1
- require 'loga/sidekiq/job_logger'
2
-
3
1
  module Loga
4
2
  module Sidekiq
5
3
  def self.configure_logging
6
4
  return unless defined?(::Sidekiq)
7
5
  return if Gem::Version.new(::Sidekiq::VERSION) < Gem::Version.new('5.0')
8
6
 
9
- ::Sidekiq.configure_server do |config|
10
- config.options[:job_logger] = Loga::Sidekiq::JobLogger
7
+ if Gem::Version.new(::Sidekiq::VERSION) < Gem::Version.new('6.0')
8
+ require 'loga/sidekiq5/job_logger'
9
+
10
+ ::Sidekiq.configure_server do |config|
11
+ config.options[:job_logger] = Loga::Sidekiq5::JobLogger
12
+ end
13
+ elsif Gem::Version.new(::Sidekiq::VERSION) < Gem::Version.new('7.0')
14
+ require 'loga/sidekiq6/job_logger'
15
+
16
+ ::Sidekiq.configure_server do |config|
17
+ config.options[:job_logger] = Loga::Sidekiq6::JobLogger
18
+ end
11
19
  end
12
20
 
13
21
  ::Sidekiq.logger = Loga.configuration.logger
@@ -1,9 +1,7 @@
1
1
  module Loga
2
- module Sidekiq
2
+ module Sidekiq5
3
3
  # The approach of using a custom job logger in sidekiq was introduced
4
4
  # in v5.0: https://github.com/mperham/sidekiq/pull/3235
5
- # This job logger does not support logging for Sidekiq versions
6
- # that are before 5.0
7
5
  class JobLogger
8
6
  include Loga::Utilities
9
7
 
@@ -0,0 +1,55 @@
1
+ require 'sidekiq/job_logger'
2
+
3
+ module Loga
4
+ module Sidekiq6
5
+ class JobLogger < ::Sidekiq::JobLogger
6
+ EVENT_TYPE = 'sidekiq'.freeze
7
+
8
+ def call(item, _queue)
9
+ start = ::Process.clock_gettime(::Process::CLOCK_MONOTONIC)
10
+
11
+ yield
12
+
13
+ ::Sidekiq::Context.current[:elapsed] = elapsed(start)
14
+
15
+ loga_log(message: "#{item['class']} with jid: '#{item['jid']}' done", item: item)
16
+ rescue Exception => e # rubocop:disable Lint/RescueException
17
+ ::Sidekiq::Context.current[:elapsed] = elapsed(start)
18
+
19
+ loga_log(
20
+ message: "#{item['class']} with jid: '#{item['jid']}' fail", item: item,
21
+ exception: e
22
+ )
23
+
24
+ raise
25
+ end
26
+
27
+ def prepare(job_hash, &block)
28
+ super
29
+ ensure
30
+ # For sidekiq version < 6.4
31
+ Thread.current[:sidekiq_context] = nil
32
+ end
33
+
34
+ private
35
+
36
+ def loga_log(message:, item:, exception: nil)
37
+ data = {
38
+ 'created_at' => item['created_at'],
39
+ 'enqueued_at' => item['enqueued_at'],
40
+ 'jid' => item['jid'],
41
+ 'queue' => item['queue'],
42
+ 'retry' => item['retry'],
43
+ 'params' => item['args'],
44
+ 'class' => item['class'],
45
+ }
46
+ if exception
47
+ data['exception'] = exception
48
+ @logger.warn(Event.new(type: EVENT_TYPE, message: message, data: data))
49
+ else
50
+ @logger.info(Event.new(type: EVENT_TYPE, message: message, data: data))
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
data/lib/loga/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Loga
2
- VERSION = '2.5.2'.freeze
2
+ VERSION = '2.6.1'.freeze
3
3
  end
data/loga.gemspec CHANGED
@@ -21,17 +21,17 @@ Gem::Specification.new do |spec|
21
21
  spec.add_dependency 'activesupport', '>= 2.3.8'
22
22
  spec.add_dependency 'rack'
23
23
 
24
- spec.add_development_dependency 'appraisal', '~> 2.2.0'
25
- spec.add_development_dependency 'bundler', '~> 1.6'
24
+ spec.add_development_dependency 'appraisal', '~> 2.4'
25
+ spec.add_development_dependency 'bundler', '>= 1.6'
26
26
  spec.add_development_dependency 'byebug'
27
27
  spec.add_development_dependency 'guard', '~> 2.13'
28
- spec.add_development_dependency 'guard-rspec', '~> 4.7.3'
28
+ spec.add_development_dependency 'guard-rspec', '~> 4.7'
29
29
  spec.add_development_dependency 'guard-rubocop', '~> 1.2'
30
30
  spec.add_development_dependency 'pry'
31
31
  spec.add_development_dependency 'rack-test'
32
32
  spec.add_development_dependency 'rake'
33
33
  spec.add_development_dependency 'fakeredis'
34
- spec.add_development_dependency 'rspec', '~> 3.7.0'
34
+ spec.add_development_dependency 'rspec', '~> 3.7'
35
35
  spec.add_development_dependency 'rubocop', '~> 0.57.0'
36
36
  spec.add_development_dependency 'rubocop-rspec'
37
37
  spec.add_development_dependency 'timecop'