radius-spec 0.4.0 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +28 -0
- data/.github/workflows/reviewdog.yml +21 -0
- data/.rubocop.yml +9 -5
- data/.yardopts +1 -0
- data/CHANGELOG.md +111 -1
- data/Gemfile +3 -4
- data/README.md +335 -37
- data/benchmarks/bm_setup.rb +1 -0
- data/benchmarks/call_vs_yield.rb +33 -2
- data/benchmarks/casecmp_vs_downcase.rb +488 -0
- data/benchmarks/cover_vs_include.rb +2 -2
- data/benchmarks/format_string.rb +3 -3
- data/benchmarks/hash_each.rb +305 -0
- data/benchmarks/hash_merge.rb +1 -1
- data/benchmarks/hash_transform.rb +455 -0
- data/benchmarks/unfreeze_string.rb +0 -2
- data/bin/ci +1 -1
- data/common_rubocop.yml +168 -41
- data/common_rubocop_rails.yml +107 -21
- data/lib/radius/spec/model_factory.rb +35 -24
- data/lib/radius/spec/rails.rb +1 -1
- data/lib/radius/spec/rspec/negated_matchers.rb +19 -0
- data/lib/radius/spec/rspec.rb +20 -0
- data/lib/radius/spec/tempfile.rb +162 -0
- data/lib/radius/spec/vcr.rb +98 -0
- data/lib/radius/spec/version.rb +1 -1
- data/radius-spec.gemspec +8 -7
- metadata +44 -20
- data/.travis.yml +0 -17
- data/bin/ci-code-review +0 -28
- data/bin/travis +0 -29
@@ -268,6 +268,7 @@ module Radius
|
|
268
268
|
def safe_transform(value)
|
269
269
|
return value.call if value.is_a?(Proc)
|
270
270
|
return value if value.frozen?
|
271
|
+
|
271
272
|
value.dup
|
272
273
|
end
|
273
274
|
|
@@ -426,53 +427,63 @@ module Radius
|
|
426
427
|
|
427
428
|
# Convenience wrapper for building, and persisting, a model template.
|
428
429
|
#
|
429
|
-
# This is a thin wrapper around
|
430
|
-
# persistence message `save!` will only be called on objects which
|
431
|
-
# respond to it.
|
432
|
-
#
|
433
|
-
# ### Avoid for New Code
|
430
|
+
# This is a thin wrapper around:
|
434
431
|
#
|
435
|
-
#
|
436
|
-
#
|
437
|
-
#
|
432
|
+
# ```ruby
|
433
|
+
# build(name, attrs, &block).tap(&:save!)
|
434
|
+
# ```
|
438
435
|
#
|
439
|
-
#
|
440
|
-
#
|
436
|
+
# The persistence message `save!` will only be called on objects which
|
437
|
+
# respond to it.
|
441
438
|
#
|
442
|
-
#
|
443
|
-
#
|
439
|
+
# @note It is generally suggested that you avoid using `build!` for new
|
440
|
+
# code. Instead be explicit about when and how objects are persisted.
|
441
|
+
# This allows you to have fine grain control over how your data is
|
442
|
+
# setup.
|
444
443
|
#
|
445
|
-
#
|
446
|
-
#
|
447
|
-
# end
|
448
|
-
# ```
|
444
|
+
# We suggest that you create instances which need to be persisted
|
445
|
+
# before your specs using the following syntax:
|
449
446
|
#
|
450
|
-
#
|
451
|
-
#
|
447
|
+
# ```ruby
|
448
|
+
# let(:an_instance) { build("AnyClass") }
|
452
449
|
#
|
453
|
-
#
|
454
|
-
#
|
455
|
-
#
|
450
|
+
# before do
|
451
|
+
# an_instance.save!
|
452
|
+
# end
|
453
|
+
# ```
|
456
454
|
#
|
457
455
|
# @param (see .build)
|
458
456
|
# @return (see .build)
|
459
457
|
# @raise (see .build)
|
460
458
|
# @see .build
|
461
459
|
# @see .define_factory
|
462
|
-
|
460
|
+
# @since 0.5.0
|
461
|
+
def build!(name, custom_attrs = {}, &block)
|
463
462
|
instance = build(name, custom_attrs, &block)
|
464
463
|
instance.save! if instance.respond_to?(:save!)
|
465
464
|
instance
|
466
465
|
end
|
466
|
+
|
467
|
+
# Legacy helper provided for backwards compatibility support.
|
468
|
+
#
|
469
|
+
# This provides the same behavior as {.build!} and will be removed in a
|
470
|
+
# future release.
|
471
|
+
#
|
472
|
+
# @param (see .build)
|
473
|
+
# @return (see .build)
|
474
|
+
# @raise (see .build)
|
475
|
+
# @see .build
|
476
|
+
# @see .define_factory
|
477
|
+
def create(name, custom_attrs = {}, &block)
|
478
|
+
build!(name, custom_attrs, &block)
|
479
|
+
end
|
467
480
|
end
|
468
481
|
end
|
469
482
|
end
|
470
483
|
|
471
484
|
# Try to load the factories defined for the specs
|
472
|
-
# rubocop:disable Lint/HandleExceptions
|
473
485
|
begin
|
474
486
|
require 'support/model_factories'
|
475
487
|
rescue LoadError
|
476
488
|
# Ignore as this is an optional convenience feature
|
477
489
|
end
|
478
|
-
# rubocop:enable Lint/HandleExceptions
|
data/lib/radius/spec/rails.rb
CHANGED
@@ -7,7 +7,7 @@ require 'rspec/rails'
|
|
7
7
|
|
8
8
|
RSpec.configure do |config|
|
9
9
|
# Remove this line if you're not using ActiveRecord or ActiveRecord fixtures
|
10
|
-
config.fixture_path = ::Rails.root.join("spec", "fixtures")
|
10
|
+
config.fixture_path = ::Rails.root.join("spec", "fixtures").to_path
|
11
11
|
|
12
12
|
# If you're not using ActiveRecord, or you'd prefer not to run each of your
|
13
13
|
# examples within a transaction, remove the following line or assign false
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Define negated matchers for use with composable matchers and compound
|
4
|
+
# expectations.
|
5
|
+
#
|
6
|
+
# @see https://relishapp.com/rspec/rspec-expectations/v/3-8/docs/composing-matchers
|
7
|
+
# @see https://relishapp.com/rspec/rspec-expectations/v/3-8/docs/compound-expectations
|
8
|
+
RSpec::Matchers.define_negated_matcher :exclude, :include
|
9
|
+
RSpec::Matchers.define_negated_matcher :excluding, :including
|
10
|
+
RSpec::Matchers.define_negated_matcher :not_eq, :eq
|
11
|
+
|
12
|
+
# Allows us to check that a block doesn't raise an exception while also
|
13
|
+
# checking for other changes using compound expectations; since you can't chain
|
14
|
+
# a negative (`not_to`) with any other matchers
|
15
|
+
#
|
16
|
+
# @see https://relishapp.com/rspec/rspec-expectations/v/3-8/docs/compound-expectations
|
17
|
+
RSpec::Matchers.define_negated_matcher :not_change, :change
|
18
|
+
RSpec::Matchers.define_negated_matcher :not_raise_error, :raise_error
|
19
|
+
RSpec::Matchers.define_negated_matcher :not_raise_exception, :raise_exception
|
data/lib/radius/spec/rspec.rb
CHANGED
@@ -109,6 +109,11 @@ RSpec.configure do |config|
|
|
109
109
|
config.include Radius::Spec::ModelFactory, :model_factory, :model_factories
|
110
110
|
end
|
111
111
|
|
112
|
+
config.when_first_matching_example_defined(:tempfile, :tmpfile) do
|
113
|
+
require 'radius/spec/tempfile'
|
114
|
+
config.include Radius::Spec::Tempfile, :tempfile, :tmpfile
|
115
|
+
end
|
116
|
+
|
112
117
|
config.when_first_matching_example_defined(type: :controller) do
|
113
118
|
require 'radius/spec/model_factory'
|
114
119
|
config.include Radius::Spec::ModelFactory, type: :controller
|
@@ -124,6 +129,11 @@ RSpec.configure do |config|
|
|
124
129
|
config.include Radius::Spec::ModelFactory, type: :job
|
125
130
|
end
|
126
131
|
|
132
|
+
config.when_first_matching_example_defined(type: :mailer) do
|
133
|
+
require 'radius/spec/model_factory'
|
134
|
+
config.include Radius::Spec::ModelFactory, type: :mailer
|
135
|
+
end
|
136
|
+
|
127
137
|
config.when_first_matching_example_defined(type: :model) do
|
128
138
|
require 'radius/spec/model_factory'
|
129
139
|
config.include Radius::Spec::ModelFactory, type: :model
|
@@ -138,4 +148,14 @@ RSpec.configure do |config|
|
|
138
148
|
require 'radius/spec/model_factory'
|
139
149
|
config.include Radius::Spec::ModelFactory, type: :system
|
140
150
|
end
|
151
|
+
|
152
|
+
config.when_first_matching_example_defined(:webmock) do
|
153
|
+
require 'webmock/rspec'
|
154
|
+
end
|
155
|
+
|
156
|
+
config.when_first_matching_example_defined(:vcr, :vcr_record, :vcr_record_new) do
|
157
|
+
require 'radius/spec/vcr'
|
158
|
+
end
|
141
159
|
end
|
160
|
+
|
161
|
+
require 'radius/spec/rspec/negated_matchers'
|
@@ -0,0 +1,162 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'pathname'
|
4
|
+
require 'tempfile'
|
5
|
+
|
6
|
+
module Radius
|
7
|
+
module Spec
|
8
|
+
# Temporary file helpers
|
9
|
+
#
|
10
|
+
# These helpers are meant to ease the creation of temporary files to either
|
11
|
+
# stub the data out or provide a location for data to be saved then
|
12
|
+
# verified.
|
13
|
+
#
|
14
|
+
# In the case of file stubs, using these helpers allows you to co-locate
|
15
|
+
# the file data with the specs. This makes it easy for someone to read the
|
16
|
+
# spec and understand the test case; instead of having to find a fixture
|
17
|
+
# file and look at its data. This also makes it easy to change the data
|
18
|
+
# between specs, allowing them to focus on just what they need.
|
19
|
+
#
|
20
|
+
# To make these helpers available require them after the gem:
|
21
|
+
#
|
22
|
+
# ```ruby
|
23
|
+
# require 'radius/spec'
|
24
|
+
# require 'radius/spec/tempfile'
|
25
|
+
# ```
|
26
|
+
#
|
27
|
+
# ### Including Helpers in Specs
|
28
|
+
#
|
29
|
+
# There are multiple ways you can use these helpers. Which method you
|
30
|
+
# choose depends on how much perceived magic/syntactic sugar you want:
|
31
|
+
#
|
32
|
+
# - call the helpers directly on the module
|
33
|
+
# - manually include the helper methods in the specs
|
34
|
+
# - use metadata to auto load this feature and include it in the specs
|
35
|
+
#
|
36
|
+
# When using the metadata option you do not need to explicitly require the
|
37
|
+
# module. This gem registers metadata with the RSpec configuration when it
|
38
|
+
# loads and `RSpec` is defined. When the matching metadata is first used it
|
39
|
+
# will automatically require and include the helpers.
|
40
|
+
#
|
41
|
+
# Any of following metadata will include the factory helpers:
|
42
|
+
#
|
43
|
+
# - `:tempfile`
|
44
|
+
# - `:tmpfile`
|
45
|
+
#
|
46
|
+
# @example use a helper directly in specs
|
47
|
+
# require 'radius/spec/tempfile'
|
48
|
+
#
|
49
|
+
# RSpec.describe AnyClass do
|
50
|
+
# it "includes the file helpers" do
|
51
|
+
# Radius::Spec::Tempfile.using_tempfile do |pathname|
|
52
|
+
# code_under_test pathname
|
53
|
+
# expect(pathname.read).to eq "Any written data"
|
54
|
+
# end
|
55
|
+
# end
|
56
|
+
# end
|
57
|
+
# @example manually include the helpers
|
58
|
+
# require 'radius/spec/tempfile'
|
59
|
+
#
|
60
|
+
# RSpec.describe AnyClass do
|
61
|
+
# include Radius::Spec::Tempfile
|
62
|
+
# it "includes the file helpers" do
|
63
|
+
# using_tempfile do |pathname|
|
64
|
+
# code_under_test pathname
|
65
|
+
# expect(pathname.read).to eq "Any written data"
|
66
|
+
# end
|
67
|
+
# end
|
68
|
+
# end
|
69
|
+
# @example use metadata to auto include the helpers
|
70
|
+
# RSpec.describe AnyClass do
|
71
|
+
# it "includes the file helpers", :tempfile do
|
72
|
+
# using_tempfile do |pathname|
|
73
|
+
# code_under_test pathname
|
74
|
+
# expect(pathname.read).to eq "Any written data"
|
75
|
+
# end
|
76
|
+
# end
|
77
|
+
# end
|
78
|
+
# @since 0.5.0
|
79
|
+
module Tempfile
|
80
|
+
module_function
|
81
|
+
|
82
|
+
# Convenience wrapper for managaing temporary files.
|
83
|
+
#
|
84
|
+
# This creates a temporary file and yields its path to the provided
|
85
|
+
# block. When the block returns the temporary file is deleted.
|
86
|
+
#
|
87
|
+
# ### Optional Parameters
|
88
|
+
#
|
89
|
+
# The block is required. All other parameters are optional. All
|
90
|
+
# parameters except `data` are Ruby version dependent and will be
|
91
|
+
# forwarded directly to the stdlib's
|
92
|
+
# {https://ruby-doc.org/stdlib/libdoc/tempfile/rdoc/Tempfile.html#method-c-create
|
93
|
+
# `Tempfile.create`}. The when the `data` parameter is provided it's
|
94
|
+
# contents will be written to the temporary file prior to yielding to the
|
95
|
+
# block.
|
96
|
+
#
|
97
|
+
# @example creating a tempfile to pass to code
|
98
|
+
# def write_hello_world(filepath)
|
99
|
+
# File.write filepath, "Hello World"
|
100
|
+
# end
|
101
|
+
#
|
102
|
+
# Radius::Spec::Tempfile.using_tempfile do |pathname|
|
103
|
+
# write_hello_world pathname
|
104
|
+
# end
|
105
|
+
# @example creating a file stub
|
106
|
+
# stub_data = "Any file stub data text."
|
107
|
+
# Radius::Spec::Tempfile.using_tempfile(data: stub_data) do |stubpath|
|
108
|
+
# # File.read(stubpath)
|
109
|
+
# # => "Any file stub data text."
|
110
|
+
# code_under_test stubpath
|
111
|
+
# end
|
112
|
+
# @example creating a file stub inline
|
113
|
+
# Radius::Spec::Tempfile.using_tempfile(data: <<~TEXT) do |stubpath|
|
114
|
+
# Any file stub data text.
|
115
|
+
# TEXT
|
116
|
+
# # File.read(stubpath)
|
117
|
+
# # => "Any file stub data text.\n"
|
118
|
+
# code_under_test stubpath
|
119
|
+
# end
|
120
|
+
# @example creating a file stub inline without trailing newline
|
121
|
+
# Radius::Spec::Tempfile.using_tempfile(data: <<~TEXT.chomp) do |stubpath|
|
122
|
+
# Any file stub data text.
|
123
|
+
# TEXT
|
124
|
+
# # File.read(stubpath)
|
125
|
+
# # => "Any file stub data text."
|
126
|
+
# code_under_test stubpath
|
127
|
+
# end
|
128
|
+
# @example writing binary data inline
|
129
|
+
# Radius::Spec::Tempfile.using_tempfile(encoding: Encoding::BINARY, data: <<~BIN.chomp) do |binpath|
|
130
|
+
# \xC8\x90\xC5\x9D\xE1\xB9\x95\xC4\x93\xC4\x89
|
131
|
+
# BIN
|
132
|
+
# # File.read(binpath)
|
133
|
+
# # => "Ȑŝṕēĉ"
|
134
|
+
# code_under_test binpath
|
135
|
+
# end
|
136
|
+
# @param args [Object] addition file creation options
|
137
|
+
#
|
138
|
+
# Passed directly to {https://ruby-doc.org/stdlib/libdoc/tempfile/rdoc/Tempfile.html#method-c-create
|
139
|
+
# `Tempfile.create`}; see the stdlib docs for details on available
|
140
|
+
# options.
|
141
|
+
# @param data [String] stub data to write to the file before yielding
|
142
|
+
# @param kwargs [Hash{Symbol => Object}] addition file creation options
|
143
|
+
#
|
144
|
+
# Passed directly to {https://ruby-doc.org/stdlib/libdoc/tempfile/rdoc/Tempfile.html#method-c-create
|
145
|
+
# `Tempfile.create`}; see the stdlib docs for details on available
|
146
|
+
# options.
|
147
|
+
# @yieldparam pathname [Pathname] {https://ruby-doc.org/stdlib/libdoc/pathname/rdoc/Pathname.html path}
|
148
|
+
# of the created temporary file
|
149
|
+
# @note A block must be provided
|
150
|
+
# @see https://ruby-doc.org/stdlib/libdoc/pathname/rdoc/Pathname.html Pathname
|
151
|
+
# @see https://ruby-doc.org/stdlib/libdoc/tempfile/rdoc/Tempfile.html Tempfile
|
152
|
+
def using_tempfile(*args, data: nil, **kwargs)
|
153
|
+
args << 'tmpfile' if args.empty?
|
154
|
+
::Tempfile.create(*args, **kwargs) do |f|
|
155
|
+
f.write(data)
|
156
|
+
f.close
|
157
|
+
yield Pathname(f.path)
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'webmock/rspec'
|
4
|
+
require 'vcr'
|
5
|
+
|
6
|
+
VCR.configure do |config|
|
7
|
+
config.cassette_library_dir = "spec/cassettes"
|
8
|
+
config.hook_into :webmock
|
9
|
+
config.configure_rspec_metadata!
|
10
|
+
config.ignore_localhost = true
|
11
|
+
|
12
|
+
record_mode = case
|
13
|
+
when RSpec.configuration.files_to_run.one?
|
14
|
+
# When developing new features we often run new specs in
|
15
|
+
# isolation as we write the code. This is the time to allow
|
16
|
+
# creating the cassettes.
|
17
|
+
:once
|
18
|
+
when ENV['CI']
|
19
|
+
# Never let CI record
|
20
|
+
:none
|
21
|
+
else
|
22
|
+
# Default to blocking new requests to catch issues
|
23
|
+
:none
|
24
|
+
end
|
25
|
+
config.default_cassette_options = {
|
26
|
+
record: record_mode,
|
27
|
+
|
28
|
+
# Required for working proxy
|
29
|
+
update_content_length_header: true,
|
30
|
+
|
31
|
+
# Raise errors when recorded cassettes no longer match interactions
|
32
|
+
allow_unused_http_interactions: false,
|
33
|
+
}
|
34
|
+
|
35
|
+
# Filter out common sensitive or environment specific data
|
36
|
+
%w[
|
37
|
+
AWS_ACCESS_KEY_ID
|
38
|
+
AWS_SECRET_ACCESS_KEY
|
39
|
+
GOOGLE_CLIENT_ID
|
40
|
+
GOOGLE_CLIENT_SECRET
|
41
|
+
RADIUS_OAUTH_PROVIDER_APP_ID
|
42
|
+
RADIUS_OAUTH_PROVIDER_APP_SECRET
|
43
|
+
RADIUS_OAUTH_PROVIDER_URL
|
44
|
+
].each do |secret|
|
45
|
+
config.filter_sensitive_data("<#{secret}>") { ENV[secret] }
|
46
|
+
|
47
|
+
config.filter_sensitive_data("<#{secret}_FORM>") {
|
48
|
+
URI.encode_www_form_component(ENV[secret]) if ENV[secret]
|
49
|
+
}
|
50
|
+
|
51
|
+
config.filter_sensitive_data("<#{secret}_URI>") {
|
52
|
+
ERB::Util.url_encode(ENV[secret]) if ENV[secret]
|
53
|
+
}
|
54
|
+
|
55
|
+
config.filter_sensitive_data('<AUTHORIZATION_HEADER>') { |interaction|
|
56
|
+
interaction.request.headers['Authorization']&.first
|
57
|
+
}
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
RSpec.configure do |config|
|
62
|
+
{
|
63
|
+
vcr_record: :once,
|
64
|
+
vcr_record_new: :new_episodes,
|
65
|
+
}.each do |tag, record_mode|
|
66
|
+
config.define_derived_metadata(tag) do |metadata|
|
67
|
+
case metadata[:vcr]
|
68
|
+
when nil, true
|
69
|
+
metadata[:vcr] = { record: record_mode }
|
70
|
+
when Hash
|
71
|
+
metadata[:vcr][:record] = record_mode
|
72
|
+
else
|
73
|
+
raise "Unknown VCR metadata value: #{metadata[:vcr].inspect}"
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
config.define_derived_metadata(:focus) do |metadata|
|
79
|
+
# VCR is flagged as falsey
|
80
|
+
next if metadata.key?(:vcr) && !metadata[:vcr]
|
81
|
+
|
82
|
+
case metadata[:vcr]
|
83
|
+
when nil, true
|
84
|
+
metadata[:vcr] = { record: :once }
|
85
|
+
when Hash
|
86
|
+
metadata[:vcr][:record] ||= :once
|
87
|
+
else
|
88
|
+
raise "Unknown VCR metadata value: #{metadata[:vcr].inspect}"
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
# Try to any custom VCR config for the app
|
94
|
+
begin
|
95
|
+
require 'support/vcr'
|
96
|
+
rescue LoadError
|
97
|
+
# Ignore as this is an optional convenience feature
|
98
|
+
end
|
data/lib/radius/spec/version.rb
CHANGED
data/radius-spec.gemspec
CHANGED
@@ -12,7 +12,7 @@ Gem::Specification.new do |spec|
|
|
12
12
|
|
13
13
|
spec.metadata = {
|
14
14
|
"bug_tracker_uri" => "https://github.com/RadiusNetworks/radius-spec/issues",
|
15
|
-
"changelog_uri"
|
15
|
+
"changelog_uri" => "https://github.com/RadiusNetworks/radius-spec/blob/v#{Radius::Spec::VERSION}/CHANGELOG.md",
|
16
16
|
"source_code_uri" => "https://github.com/RadiusNetworks/radius-spec/tree/v#{Radius::Spec::VERSION}",
|
17
17
|
}
|
18
18
|
spec.summary = "Radius Networks RSpec setup and plug-ins"
|
@@ -21,18 +21,19 @@ Gem::Specification.new do |spec|
|
|
21
21
|
spec.homepage = "https://github.com/RadiusNetworks/radius-spec"
|
22
22
|
spec.license = "Apache-2.0"
|
23
23
|
|
24
|
-
spec.files = `git ls-files -z`.split("\x0").reject
|
24
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f|
|
25
25
|
f.match(%r{^(test|spec|features)/})
|
26
|
-
|
26
|
+
}
|
27
27
|
spec.bindir = "exe"
|
28
28
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
29
29
|
spec.require_paths = ["lib"]
|
30
30
|
|
31
|
-
spec.required_ruby_version = ">= 2.5"
|
31
|
+
spec.required_ruby_version = ">= 2.5" # rubocop:disable Gemspec/RequiredRubyVersion
|
32
32
|
|
33
33
|
spec.add_runtime_dependency "rspec", "~> 3.7"
|
34
|
-
spec.add_runtime_dependency "rubocop", "~> 0.
|
34
|
+
spec.add_runtime_dependency "rubocop", "~> 0.82.0"
|
35
|
+
spec.add_runtime_dependency "rubocop-rails", "~> 2.5.2"
|
35
36
|
|
36
|
-
spec.add_development_dependency "bundler", "
|
37
|
-
spec.add_development_dependency "rake", "
|
37
|
+
spec.add_development_dependency "bundler", ">= 2.2.10"
|
38
|
+
spec.add_development_dependency "rake", ">= 12.0", "< 14.0"
|
38
39
|
end
|