ridgepole 3.0.1 → 3.0.4

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: cccf60348e4baf7ac0988edb6e68bc14b0cbb945a167e4a2e6d9ef71d5e35c8a
4
- data.tar.gz: 9ff98ff1c8a823fe988129816db0bcc4dac1c9f1a5c565faa47ef8aa3852507b
3
+ metadata.gz: 931a6b90df6d277ffd72a272342058290e4fcc8b793ffc0b94f2719a9fc6de4e
4
+ data.tar.gz: '01879ec62757730657f0197c052f2601fe74561286cef3fc4d7c9e82bc329764'
5
5
  SHA512:
6
- metadata.gz: f0dc88f6715d8500bb4edfa106140ea7ca6cd1c207edd51cf65d12a76453ed2eb3d575ee8b73d7d96a0e386c4dec3e34ff985bf81bcc7a8026529946c3b40f74
7
- data.tar.gz: 750a855f189b49cafbc35db15d227b2b2cbf8f2a545075b46a390697f768b3b9c606d9c6403c74c3491fdc76a408944aba2a3a2f7781dd475d096b82ec6f330a
6
+ metadata.gz: ada25e648306fce2dbb1755c5746e2bcaf6a7e4413fada585ce278f4750f7b28493b2e156139b17cacdb5b95d70073771dc174c11ce32986033bfa80a8cc3bf9
7
+ data.tar.gz: 61e689542f00d014065941fab911c0c11a6cbd1f41ef0f293cce18ffb4f71de37f9499985f9a6c4241699fe796c7a7bc2721979834a3882ad52bb2fcbfac0011
data/CHANGELOG.md CHANGED
@@ -2,6 +2,19 @@
2
2
 
3
3
  ## 3.0
4
4
 
5
+ ### 3.0.4 (2025/08/31)
6
+
7
+ - Fix checking foreign key without index [pull#571](https://github.com/ridgepole/ridgepole/pull/571)
8
+ - Use `change_column_comment` for comment-only column changes [pull#567](https://github.com/ridgepole/ridgepole/pull/567)
9
+
10
+ ### 3.0.3 (2025/07/23)
11
+
12
+ - Fix for index `algorithm` option [pull#555](https://github.com/ridgepole/ridgepole/pull/555)
13
+
14
+ ### 3.0.2 (2025/06/22)
15
+
16
+ - Faster table definition comparisons [pull#549](https://github.com/ridgepole/ridgepole/pull/549)
17
+
5
18
  ### 3.0.1 (2025/01/12)
6
19
 
7
20
  - Normalize `check_constraint` [pull#512](https://github.com/ridgepole/ridgepole/pull/512)
data/README.md CHANGED
@@ -329,6 +329,42 @@ Apply `Schemafile`
329
329
  ...
330
330
  ```
331
331
 
332
+ ## Define a partial index in PostgreSQL
333
+
334
+ Partial indexes in PostgreSQL are normalized so differences are always detected.
335
+
336
+ ```ruby
337
+ create_table "users", id: :serial, force: :cascade do |t|
338
+ t.text "email"
339
+ t.text "name"
340
+ t.index ["email"], name: "idx_users_email", unique: true, where: "email is not null"
341
+ end
342
+ ```
343
+
344
+ ```sh
345
+ % ridgepole -a -c database.yml --dry-run --verbose
346
+ Apply `Schemafile` (dry-run)
347
+ # Parse DSL
348
+ # ...
349
+ # Compare definitions
350
+ # users
351
+ :options=>
352
+ {:name=>"idx_users_email",
353
+ :unique=>true,
354
+ - :where=>"(email IS NOT NULL)"}}},
355
+ + :where=>"email is not null"}}},
356
+ :options=>{:id=>:serial}}
357
+ ```
358
+
359
+ Use a normalized WHERE clause to avoid detecting differences.
360
+
361
+ ```ruby
362
+ #t.index ["email"], name: "idx_users_email", unique: true, where: "email is not null"
363
+ t.index ["email"], name: "idx_users_email", unique: true, where: "(email IS NOT NULL)"
364
+ ```
365
+
366
+ see https://github.com/ridgepole/ridgepole/issues/568
367
+
332
368
  ## Run tests
333
369
 
334
370
 
@@ -271,7 +271,7 @@ create_table(#{table_name.inspect}, #{inspect_options_include_default_proc(optio
271
271
  end
272
272
  RUBY
273
273
 
274
- if !(@options[:create_table_with_index]) && !indices.empty?
274
+ if !@options[:create_table_with_index] && !indices.empty?
275
275
  append_change_table(table_name, buf) do
276
276
  indices.each do |index_name, index_attrs|
277
277
  append_add_index(table_name, index_name, index_attrs, buf)
@@ -344,6 +344,7 @@ execute "ALTER TABLE #{ActiveRecord::Base.connection.quote_table_name(table_name
344
344
  table_charset = attrs[:table_charset]
345
345
  table_collation = attrs[:table_collation]
346
346
  table_comment = attrs[:table_comment]
347
+ column_comments = attrs[:column_comments] || {}
347
348
 
348
349
  if !definition.empty? || !indices.empty? || !primary_key_definition.empty?
349
350
  append_change_table(table_name, buf) do
@@ -365,12 +366,21 @@ execute "ALTER TABLE #{ActiveRecord::Base.connection.quote_table_name(table_name
365
366
  end
366
367
 
367
368
  append_change_table_comment(table_name, table_comment, buf) if table_comment
369
+ append_change_column_comments(table_name, column_comments, buf) unless column_comments.empty?
368
370
 
369
371
  buf.puts
370
372
  pre_buf_for_fk.puts
371
373
  post_buf_for_fk.puts
372
374
  end
373
375
 
376
+ def append_change_column_comments(table_name, column_comments, buf)
377
+ column_comments.each do |column_name, comment|
378
+ buf.puts(<<-RUBY)
379
+ change_column_comment(#{table_name.inspect}, #{column_name.inspect}, #{comment.inspect})
380
+ RUBY
381
+ end
382
+ end
383
+
374
384
  def append_change_table(table_name, buf)
375
385
  buf.puts "change_table(#{table_name.inspect}, bulk: true) do |t|" if @options[:bulk_change]
376
386
  yield
@@ -30,8 +30,9 @@ module Ridgepole
30
30
  @logger.verbose_info("# #{table_name}")
31
31
 
32
32
  unless @options[:drop_table_only]
33
- unless (attrs_delta = diff_inspect(from_attrs, to_attrs)).empty?
34
- @logger.verbose_info(attrs_delta)
33
+ unless hash_deep_equal?(from_attrs, to_attrs)
34
+ attrs_delta = diff_inspect(from_attrs, to_attrs)
35
+ @logger.verbose_info(attrs_delta) unless attrs_delta.empty?
35
36
  end
36
37
 
37
38
  scan_change(table_name, from_attrs, to_attrs, delta)
@@ -233,6 +234,7 @@ module Ridgepole
233
234
  from = (from || {}).dup
234
235
  to = (to || {}).dup
235
236
  definition_delta = {}
237
+ column_comments = {}
236
238
 
237
239
  scan_column_rename(from, to, definition_delta)
238
240
 
@@ -248,10 +250,14 @@ module Ridgepole
248
250
  next if ignore_column
249
251
 
250
252
  if from_attrs
251
- to_attrs = build_attrs_if_changed(to_attrs, from_attrs)
252
- if to_attrs
253
- definition_delta[:change] ||= {}
254
- definition_delta[:change][column_name] = to_attrs
253
+ changed_attrs = build_attrs_if_changed(to_attrs, from_attrs)
254
+ if changed_attrs
255
+ if comment_only_change?(from_attrs, to_attrs)
256
+ column_comments[column_name] = to_attrs[:options][:comment]
257
+ else
258
+ definition_delta[:change] ||= {}
259
+ definition_delta[:change][column_name] = changed_attrs
260
+ end
255
261
  end
256
262
  else
257
263
  definition_delta[:add] ||= {}
@@ -306,6 +312,7 @@ module Ridgepole
306
312
  end
307
313
 
308
314
  table_delta[:definition] = definition_delta unless definition_delta.empty?
315
+ table_delta[:column_comments] = column_comments unless column_comments.empty?
309
316
  end
310
317
 
311
318
  def scan_column_rename(from, to, definition_delta)
@@ -414,7 +421,7 @@ module Ridgepole
414
421
  end
415
422
  end
416
423
 
417
- if opts[:size] && (attrs[:type] == :text || attrs[:type] == :blob || attrs[:type] == :binary)
424
+ if opts[:size] && %i[text blob binary].include?(attrs[:type])
418
425
  case opts.delete(:size)
419
426
  when :tiny
420
427
  attrs[:type] = :blob if attrs[:type] == :binary
@@ -432,6 +439,9 @@ module Ridgepole
432
439
  # XXX: MySQL only?
433
440
  opts[:using] = :btree unless opts.key?(:using)
434
441
  opts[:unique] = false unless opts.key?(:unique)
442
+
443
+ # 'algorithm: concurrently' is required for index creation but not stored in PostgreSQL DB metadata, so remove 'algorithm' to prevent diff
444
+ opts.delete(:algorithm)
435
445
  end
436
446
 
437
447
  def columns_all_include?(expected_columns, actual_columns, table_options)
@@ -622,6 +632,19 @@ module Ridgepole
622
632
  attrs1 == attrs2
623
633
  end
624
634
 
635
+ def comment_only_change?(attrs1, attrs2)
636
+ return false if @options[:skip_column_comment_change]
637
+
638
+ attrs1 = attrs1.merge(options: attrs1.fetch(:options, {}).dup)
639
+ attrs2 = attrs2.merge(options: attrs2.fetch(:options, {}).dup)
640
+ normalize_default_proc_options!(attrs1[:options], attrs2[:options])
641
+
642
+ comment1 = attrs1.fetch(:options).delete(:comment)
643
+ comment2 = attrs2.fetch(:options).delete(:comment)
644
+
645
+ attrs1 == attrs2 && comment1 != comment2
646
+ end
647
+
625
648
  def normalize_default_proc_options!(opts1, opts2)
626
649
  if opts1[:default].is_a?(Proc) && opts2[:default].is_a?(Proc)
627
650
  opts1[:default] = opts1[:default].call
@@ -732,5 +755,16 @@ module Ridgepole
732
755
  @logger.warn "[WARNING] '#{table_name}' definition is not found" unless definition.key?(table_name)
733
756
  end
734
757
  end
758
+
759
+ def hash_deep_equal?(hash1, hash2)
760
+ return false unless hash1.is_a?(Hash) && hash2.is_a?(Hash)
761
+ return false if hash1.keys.to_set != hash2.keys.to_set
762
+
763
+ hash1.each do |k, v|
764
+ return false unless hash2.key?(k) && v == hash2[k]
765
+ end
766
+
767
+ true
768
+ end
735
769
  end
736
770
  end
@@ -23,16 +23,17 @@ module Ridgepole
23
23
  end
24
24
 
25
25
  def check_orphan_index(table_name, attrs)
26
- raise "Table `#{table_name}` to create the index is not defined: #{attrs[:indices].keys.join(',')}" if attrs[:indices] && !(attrs[:definition])
26
+ raise "Table `#{table_name}` to create the index is not defined: #{attrs[:indices].keys.join(',')}" if attrs[:indices] && !attrs[:definition]
27
27
  end
28
28
 
29
29
  def check_orphan_foreign_key(table_name, attrs)
30
- raise "Table `#{table_name}` to create the foreign key is not defined: #{attrs[:foreign_keys].keys.join(',')}" if attrs[:foreign_keys] && !(attrs[:definition])
30
+ raise "Table `#{table_name}` to create the foreign key is not defined: #{attrs[:foreign_keys].keys.join(',')}" if attrs[:foreign_keys] && !attrs[:definition]
31
31
  end
32
32
 
33
33
  def check_foreign_key_without_index(table_name, attrs)
34
+ return if Ridgepole::ConnectionAdapters.postgresql?
34
35
  return unless attrs[:foreign_keys]
35
- return unless attrs[:options][:options]&.include?('ENGINE=InnoDB')
36
+ return unless innodb_table?(attrs)
36
37
 
37
38
  attrs[:foreign_keys].each_value do |foreign_key_attrs|
38
39
  fk_index = foreign_key_attrs[:options][:column] || "#{foreign_key_attrs[:to_table].singularize}_id"
@@ -53,5 +54,10 @@ module Ridgepole
53
54
  Array(index_column_name).first == fk_index
54
55
  end
55
56
  end
57
+
58
+ def innodb_table?(attrs)
59
+ engine = attrs[:options][:options]&.match(/ENGINE=([^ ]+)/) && Regexp.last_match(1)
60
+ engine.nil? || engine == 'InnoDB'
61
+ end
56
62
  end
57
63
  end
@@ -85,7 +85,7 @@ module Ridgepole
85
85
  end
86
86
 
87
87
  def target?(table_name)
88
- !(@options[:tables]) || @options[:tables].include?(table_name)
88
+ !@options[:tables] || @options[:tables].include?(table_name)
89
89
  end
90
90
 
91
91
  def dump_from(conn)
@@ -3,6 +3,7 @@
3
3
  module Ridgepole
4
4
  class Logger < ::Logger
5
5
  include Singleton
6
+
6
7
  cattr_accessor :verbose
7
8
 
8
9
  def initialize
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Ridgepole
4
- VERSION = '3.0.1'
4
+ VERSION = '3.0.4'
5
5
  end
data/lib/ridgepole.rb CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  require 'logger'
4
4
  require 'open3'
5
- require 'pp' # rubocop:disable Lint/RedundantRequireStatement
5
+ require 'pp'
6
6
  require 'shellwords'
7
7
  require 'singleton'
8
8
  require 'stringio'
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ridgepole
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.1
4
+ version: 3.0.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Genki Sugawara
8
8
  bindir: bin
9
9
  cert_chain: []
10
- date: 2025-01-12 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: activerecord
@@ -231,14 +231,14 @@ dependencies:
231
231
  requirements:
232
232
  - - '='
233
233
  - !ruby/object:Gem::Version
234
- version: 1.69.2
234
+ version: 1.80.0
235
235
  type: :development
236
236
  prerelease: false
237
237
  version_requirements: !ruby/object:Gem::Requirement
238
238
  requirements:
239
239
  - - '='
240
240
  - !ruby/object:Gem::Version
241
- version: 1.69.2
241
+ version: 1.80.0
242
242
  - !ruby/object:Gem::Dependency
243
243
  name: rubocop-rake
244
244
  requirement: !ruby/object:Gem::Requirement
@@ -318,22 +318,10 @@ executables:
318
318
  extensions: []
319
319
  extra_rdoc_files: []
320
320
  files:
321
- - ".rspec"
322
- - ".rubocop.yml"
323
- - ".simplecov"
324
- - Appraisals
325
321
  - CHANGELOG.md
326
- - Gemfile
327
322
  - LICENSE.txt
328
323
  - README.md
329
- - Rakefile
330
324
  - bin/ridgepole
331
- - compose.yml
332
- - gemfiles/activerecord_6.1.gemfile
333
- - gemfiles/activerecord_7.0.gemfile
334
- - gemfiles/activerecord_7.1.gemfile
335
- - gemfiles/activerecord_7.2.gemfile
336
- - gemfiles/activerecord_8.0.gemfile
337
325
  - lib/ridgepole.rb
338
326
  - lib/ridgepole/cli/config.rb
339
327
  - lib/ridgepole/client.rb
@@ -356,7 +344,6 @@ files:
356
344
  - lib/ridgepole/schema_dumper_ext.rb
357
345
  - lib/ridgepole/schema_statements_ext.rb
358
346
  - lib/ridgepole/version.rb
359
- - ridgepole.gemspec
360
347
  homepage: https://github.com/ridgepole/ridgepole
361
348
  licenses:
362
349
  - MIT
@@ -376,7 +363,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
376
363
  - !ruby/object:Gem::Version
377
364
  version: '0'
378
365
  requirements: []
379
- rubygems_version: 3.6.2
366
+ rubygems_version: 3.6.7
380
367
  specification_version: 4
381
368
  summary: Ridgepole is a tool to manage DB schema.
382
369
  test_files: []
data/.rspec DELETED
@@ -1,3 +0,0 @@
1
- --color
2
- --require spec_helper
3
- --format HidePendingFormatter
data/.rubocop.yml DELETED
@@ -1,62 +0,0 @@
1
- AllCops:
2
- Exclude:
3
- - "gemfiles/**/*"
4
- - "omnibus-ridgepole/**/*"
5
- - "vendor/bundle/**/*"
6
- - "Schemafile"
7
- - "**/*.schema"
8
- TargetRubyVersion: 2.7
9
- NewCops: enable
10
- SuggestExtensions: false
11
- Bundler/OrderedGems:
12
- Include:
13
- - "Appraisals"
14
- Layout/HeredocIndentation:
15
- Enabled: false
16
- Metrics/AbcSize:
17
- Enabled: false
18
- Metrics/BlockLength:
19
- Enabled: false
20
- Metrics/BlockNesting:
21
- Enabled: false
22
- Metrics/ClassLength:
23
- Enabled: false
24
- Metrics/CyclomaticComplexity:
25
- Enabled: false
26
- Layout/LineLength:
27
- Max: 200
28
- Metrics/MethodLength:
29
- Enabled: false
30
- Metrics/ModuleLength:
31
- Max: 106
32
- Metrics/ParameterLists:
33
- Enabled: false
34
- Metrics/PerceivedComplexity:
35
- Enabled: false
36
- Style/Documentation:
37
- Enabled: false
38
- Style/GuardClause:
39
- Enabled: false
40
- Style/MixinUsage:
41
- Exclude:
42
- - "spec/**/*"
43
- Style/TrailingCommaInHashLiteral:
44
- EnforcedStyleForMultiline: consistent_comma
45
- Layout/ClosingHeredocIndentation:
46
- Enabled: false
47
- Style/NumericPredicate:
48
- Enabled: false
49
- Lint/MissingSuper:
50
- Enabled: false
51
- Style/StringConcatenation:
52
- Enabled: false
53
- Style/SoleNestedConditional:
54
- Enabled: false
55
- Lint/DuplicateBranch:
56
- Enabled: false
57
- Style/OptionalBooleanParameter:
58
- Enabled: false
59
- Gemspec/DevelopmentDependencies:
60
- Enabled: false
61
- Lint/LiteralInInterpolation:
62
- Enabled: false
data/.simplecov DELETED
@@ -1,6 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- SimpleCov.configure do
4
- # exclude directories and files
5
- add_filter '/spec/'
6
- end
data/Appraisals DELETED
@@ -1,21 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- appraise 'activerecord-6.1' do
4
- gem 'activerecord', '~> 6.1.7'
5
- end
6
-
7
- appraise 'activerecord-7.0' do
8
- gem 'activerecord', '~> 7.0.4'
9
- end
10
-
11
- appraise 'activerecord-7.1' do
12
- gem 'activerecord', '~> 7.1.0'
13
- end
14
-
15
- appraise 'activerecord-7.2' do
16
- gem 'activerecord', '~> 7.2.0'
17
- end
18
-
19
- appraise 'activerecord-8.0' do
20
- gem 'activerecord', '~> 8.0.0'
21
- end
data/Gemfile DELETED
@@ -1,6 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- source 'https://rubygems.org'
4
-
5
- # Specify your gem's dependencies in ridgepole.gemspec
6
- gemspec
data/Rakefile DELETED
@@ -1,13 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'bundler/gem_tasks'
4
- require 'rspec/core/rake_task'
5
- require 'rubocop/rake_task'
6
-
7
- RSpec::Core::RakeTask.new('spec')
8
-
9
- RuboCop::RakeTask.new do |task|
10
- task.options = %w[-c .rubocop.yml]
11
- end
12
-
13
- task default: %i[rubocop spec]
data/compose.yml DELETED
@@ -1,20 +0,0 @@
1
- services:
2
- mysql57:
3
- image: "mysql:5.7"
4
- platform: linux/amd64
5
- ports:
6
- - "13316:3306"
7
- environment:
8
- MYSQL_ROOT_PASSWORD: password
9
- mysql80:
10
- image: "mysql:8.0"
11
- ports:
12
- - "13318:3306"
13
- environment:
14
- MYSQL_ROOT_PASSWORD: password
15
- postgres:
16
- image: "postgres:14"
17
- ports:
18
- - "15442:5432"
19
- environment:
20
- POSTGRES_PASSWORD: password
@@ -1,7 +0,0 @@
1
- # This file was generated by Appraisal
2
-
3
- source "https://rubygems.org"
4
-
5
- gem "activerecord", "~> 6.1.7"
6
-
7
- gemspec path: "../"
@@ -1,7 +0,0 @@
1
- # This file was generated by Appraisal
2
-
3
- source "https://rubygems.org"
4
-
5
- gem "activerecord", "~> 7.0.4"
6
-
7
- gemspec path: "../"
@@ -1,7 +0,0 @@
1
- # This file was generated by Appraisal
2
-
3
- source "https://rubygems.org"
4
-
5
- gem "activerecord", "~> 7.1.0"
6
-
7
- gemspec path: "../"
@@ -1,7 +0,0 @@
1
- # This file was generated by Appraisal
2
-
3
- source "https://rubygems.org"
4
-
5
- gem "activerecord", "~> 7.2.0"
6
-
7
- gemspec path: "../"
@@ -1,7 +0,0 @@
1
- # This file was generated by Appraisal
2
-
3
- source "https://rubygems.org"
4
-
5
- gem "activerecord", "~> 8.0.0"
6
-
7
- gemspec path: "../"
data/ridgepole.gemspec DELETED
@@ -1,50 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- lib = File.expand_path('lib', __dir__)
4
- $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
- require 'ridgepole/version'
6
-
7
- Gem::Specification.new do |spec|
8
- spec.name = 'ridgepole'
9
- spec.version = Ridgepole::VERSION
10
- spec.authors = ['Genki Sugawara']
11
- spec.email = ['sugawara@winebarrel.jp']
12
- spec.summary = 'Ridgepole is a tool to manage DB schema.'
13
- spec.description = 'Ridgepole is a tool to manage DB schema. It defines DB schema using Rails DSL, and updates DB schema according to DSL.'
14
- spec.homepage = 'https://github.com/ridgepole/ridgepole'
15
- spec.license = 'MIT'
16
-
17
- spec.files = Dir.chdir(File.expand_path(__dir__)) do
18
- `git ls-files -z`.split("\x0").reject do |f|
19
- f.match(%r{\A(?:(?:test|spec|features)/|\.(?:git|travis|circleci)|appveyor)})
20
- end
21
- end
22
- spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
23
- spec.require_paths = ['lib']
24
-
25
- spec.required_ruby_version = Gem::Requirement.new('>= 2.7')
26
-
27
- spec.add_dependency 'activerecord', '>= 6.1', '< 8.1'
28
- spec.add_dependency 'diffy'
29
- spec.add_dependency 'logger'
30
-
31
- spec.add_development_dependency 'appraisal', '>= 2.2.0'
32
- spec.add_development_dependency 'bigdecimal'
33
- spec.add_development_dependency 'bundler'
34
- spec.add_development_dependency 'erbh', '>= 0.2.1'
35
- spec.add_development_dependency 'hash_modern_inspect', '>= 0.1.1'
36
- spec.add_development_dependency 'hash_order_helper', '>= 0.1.6'
37
- spec.add_development_dependency 'mysql2'
38
- spec.add_development_dependency 'pg'
39
- spec.add_development_dependency 'rake'
40
- spec.add_development_dependency 'rspec', '>= 3.0.0'
41
- spec.add_development_dependency 'rspec-match_fuzzy', '>= 0.2.0'
42
- spec.add_development_dependency 'rspec-match_ruby', '>= 0.1.3'
43
- spec.add_development_dependency 'rubocop', '1.69.2'
44
- spec.add_development_dependency 'rubocop-rake', '>= 0.5.1'
45
- spec.add_development_dependency 'rubocop-rspec', '>= 2.1.0'
46
- spec.add_development_dependency 'simplecov'
47
- spec.add_development_dependency 'simplecov-lcov'
48
- spec.add_development_dependency 'trilogy'
49
- spec.metadata['rubygems_mfa_required'] = 'true'
50
- end