dekiru 0.1.3 → 0.1.8

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: 8c0bb6ed019dee9b851e2f68be25d4bb213a96c7d482fe9a1025ff89534809f2
4
- data.tar.gz: 71ab7770a0b3d111f1fb62668bfff4a3bf3e23a548c1217a1d15da40edc74169
3
+ metadata.gz: 5ae4d2f88bf4f0db1e61e84464ea24df21523043c039f5b06fabf1a81d6a5f7d
4
+ data.tar.gz: a329f3991c66e86f0f76d859770291ce9d0a4b32391e7554a48183fde335445c
5
5
  SHA512:
6
- metadata.gz: 8930b878569914b971c14d5521091060ecf2079deec914a96e5d9ef9461e067df7b44d2d877988dbb40df15e94114dc05dda361c81985062427d4d7366d688fd
7
- data.tar.gz: e30b62a917913f8abfaaa2aadf9b4d56c584d24e107401f4cd855e089aa0d440a5eca0bacdba7d812d3feb8a911c2b9cae8679607191af938deb1d53bc6a15f2
6
+ metadata.gz: a5c8ff8add10ef86b6d165bb8ac9805cfd83bff5e3feca41b1d0237fcfefdcd81b9922b893d5f9f86f1408edb45c14903efafd3178b2fa8b66057d3bc8f2c057
7
+ data.tar.gz: 1f3724e621a879d91f43787c8b0a08cfd33a3b97b00069574753074337aab4abc1e18fd72a687017c54f3659fe5e88461335e381230342177c66a373de9907b9
@@ -1 +1 @@
1
- 2.5.1
1
+ 2.7.1
@@ -1,7 +1,8 @@
1
1
  rvm:
2
- - 2.3.3
3
- - 2.4.4
4
- - 2.5.1
2
+ - 2.4.6
3
+ - 2.5.5
4
+ - 2.6.3
5
+ - 2.7.1
5
6
 
6
7
  # NOTE: https://github.com/travis-ci/travis-ci/issues/8978
7
8
  before_install:
data/README.md CHANGED
@@ -109,6 +109,65 @@ Rails.application.load_tasks
109
109
  Rake::Task['db:migrate'].enhance(['db:migrate:check_conflict']) if Rails.env.development?
110
110
  ```
111
111
 
112
+ ## Mail Security Hook
113
+
114
+ 以下の設定をすると、宛先を指定しないメールを配信しようとした時に`Dekiru::MailSecurityInterceptor::NoToAdreessError`例外を発生させる。
115
+
116
+ ※ to に空文字や空配列を指定してメールを配信しようとすると、bcc 内のアドレスが to に転記されるといった問題がある。これを未然に防ぐことができる。
117
+
118
+ ```ruby
119
+ # config/initializer/dekiru.rb
120
+ Dekiru.configure do |config|
121
+ config.mail_security_hook = true # default: false
122
+ end
123
+ ```
124
+
125
+ ## Data Migration Operator
126
+
127
+ 実行しながら進捗を表示したり、処理の最後に実行の確認をしたりといった、データ移行作業をするときに必要な処理を以下のような script を作成することで、実現できるようになります。
128
+
129
+ ```ruby
130
+ # scripts/demo.rb
131
+ Dekiru::DataMigrationOperator.execute('Demo migration') do
132
+ targets = User.where("email LIKE '%sonicgarden%'")
133
+
134
+ log "all targets count: #{targets.count}"
135
+ find_each_with_progress(targets) do |user|
136
+ user.update(admin: true)
137
+ end
138
+
139
+ log "updated user count: #{User.where("email LIKE '%sonicgarden%'").where(admin: true).count}"
140
+ end
141
+ ```
142
+
143
+ ```
144
+ $ bin/rails r scripts/demo.rb
145
+ Start: Demo migration at 2019-05-24 18:29:57 +0900
146
+
147
+ all targets count: 30
148
+ Time: 00:00:00 |=================>>| 100% Progress
149
+ updated user count: 30
150
+
151
+ Are you sure to commit? (yes/no) > yes
152
+
153
+ Finished successfully: Demo migration
154
+ Total time: 6.35 sec
155
+ ```
156
+
157
+ ## Refinements
158
+
159
+ ### Dekiru::CamelizeHash
160
+
161
+ ```ruby
162
+ using Dekiru::CamelizeHash
163
+
164
+ { dekiru_rails: true }.camelize_keys(:lower)
165
+ # => { dekiruRails: true }
166
+
167
+ { dekiru_rails: { dekiru_rails: true } }.deep_camelize_keys(:lower)
168
+ # => { dekiruRails: { dekiruRails: true } }
169
+ ```
170
+
112
171
  ## Contributing
113
172
 
114
173
  1. Fork it
@@ -15,8 +15,11 @@ Gem::Specification.new do |gem|
15
15
  gem.require_paths = ["lib"]
16
16
  gem.version = Dekiru::VERSION
17
17
 
18
+ gem.required_ruby_version = '>= 2.4.0'
19
+
18
20
  gem.add_dependency 'http_accept_language', [">= 2.0.0"]
19
21
  gem.add_dependency 'rails'
22
+ gem.add_dependency 'ruby-progressbar'
20
23
  gem.add_development_dependency 'rake', [">= 0"]
21
24
  gem.add_development_dependency 'rspec'
22
25
  gem.add_development_dependency 'rubocop'
@@ -3,9 +3,29 @@ require 'dekiru/railtie' if defined?(::Rails)
3
3
  require 'dekiru/helper'
4
4
  require 'dekiru/controller_additions'
5
5
  require 'dekiru/validators/existence'
6
+ require 'dekiru/data_migration_operator'
7
+ require 'dekiru/mail_security_interceptor'
8
+ require 'dekiru/camelize_hash'
6
9
 
7
10
  require 'active_support'
8
11
  require 'active_support/all'
9
12
 
10
13
  module Dekiru
14
+ class << self
15
+ def configure
16
+ yield(configuration)
17
+ end
18
+
19
+ def configuration
20
+ @configuration ||= Configuration.new
21
+ end
22
+ end
23
+
24
+ class Configuration
25
+ attr_accessor :mail_security_hook
26
+
27
+ def initialize
28
+ @mail_security_hook = false # default
29
+ end
30
+ end
11
31
  end
@@ -0,0 +1,25 @@
1
+ module Dekiru
2
+ module CamelizeHash
3
+ refine ::Hash do
4
+ def camelize_keys(first_letter = :upper)
5
+ transform_keys do |k|
6
+ if k.is_a?(Symbol)
7
+ k.to_s.camelize(first_letter).to_sym
8
+ else
9
+ k.camelize(first_letter)
10
+ end
11
+ end
12
+ end
13
+
14
+ def deep_camelize_keys(first_letter = :upper)
15
+ deep_transform_keys do |k|
16
+ if k.is_a?(Symbol)
17
+ k.to_s.camelize(first_letter).to_sym
18
+ else
19
+ k.camelize(first_letter)
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -2,14 +2,14 @@ module Dekiru
2
2
  module Capybara
3
3
  module Matchers
4
4
  class JsNoErrorMatcher
5
- def matches?(page)
6
- errors = page.driver.browser.manage.logs.get(:browser)
7
- errors.find_all { |error| error.level == 'WARNING' }.each do |error|
5
+ def matches?(page_or_logs)
6
+ logs = page_or_logs.respond_to?(:driver) ? page_or_logs.driver.browser.manage.logs.get(:browser) : page_or_logs
7
+ logs.find_all { |log| log.level == 'WARNING' }.each do |log|
8
8
  STDERR.puts 'WARN: javascript warning'
9
- STDERR.puts error.message
9
+ STDERR.puts log.message
10
10
  end
11
11
 
12
- @severe_errors = errors.find_all { |error| error.level == 'SEVERE' }
12
+ @severe_errors = logs.find_all { |log| log.level == 'SEVERE' }
13
13
  @severe_errors.empty?
14
14
  end
15
15
 
@@ -0,0 +1,82 @@
1
+ require 'ruby-progressbar'
2
+
3
+ module Dekiru
4
+ class DataMigrationOperator
5
+ attr_reader :title, :stream, :result, :canceled, :started_at, :ended_at, :error
6
+
7
+ def self.execute(title, options = {}, &block)
8
+ self.new(title, options).execute(&block)
9
+ end
10
+
11
+ def initialize(title, options = {})
12
+ @title = title
13
+ @stream = options[:output] || $stdout
14
+ end
15
+
16
+ def log(message)
17
+ stream.puts(message)
18
+ end
19
+
20
+ def execute(&block)
21
+ @started_at = Time.current
22
+ log "Start: #{title} at #{started_at}\n\n"
23
+ @result = ActiveRecord::Base.transaction(requires_new: true, joinable: false) do
24
+ instance_eval(&block)
25
+ confirm?("\nAre you sure to commit?")
26
+ end
27
+ log "Finished successfully: #{title}" if @result == true
28
+ rescue => e
29
+ @error = e
30
+ @result = false
31
+ ensure
32
+ @ended_at = Time.current
33
+ log "Total time: #{self.duration.round(2)} sec"
34
+
35
+ raise error if error
36
+
37
+ return @result
38
+ end
39
+
40
+ def duration
41
+ ((self.ended_at || Time.current) - self.started_at)
42
+ end
43
+
44
+ def find_each_with_progress(target_scope, options = {})
45
+ opt = {
46
+ format: '%a |%b>>%i| %p%% %t',
47
+ }.merge(options).merge(
48
+ total: target_scope.count,
49
+ output: stream
50
+ )
51
+ pb = ::ProgressBar.create(opt)
52
+ target_scope.find_each do |target|
53
+ yield target
54
+ pb.increment
55
+ end
56
+ pb.finish
57
+ end
58
+
59
+ def confirm?(message = 'Are you sure?')
60
+ loop do
61
+ stream.print "#{message} (yes/no) > "
62
+ case STDIN.gets.strip
63
+ when 'yes'
64
+ newline
65
+ return true
66
+ when 'no'
67
+ newline
68
+ cancel!
69
+ end
70
+ end
71
+ end
72
+
73
+ def newline
74
+ log ''
75
+ end
76
+
77
+ def cancel!
78
+ log "Canceled: #{title}"
79
+ raise ActiveRecord::Rollback
80
+ end
81
+ end
82
+ end
@@ -19,8 +19,8 @@ module Dekiru
19
19
  end
20
20
  end
21
21
 
22
- def null_check_localization(*args)
23
- localize(*args) if args.try(:first).present?
22
+ def null_check_localization(object, **options)
23
+ localize(object, **options) if object.present?
24
24
  end
25
25
  alias nl null_check_localization
26
26
 
@@ -0,0 +1,11 @@
1
+ module Dekiru
2
+ class MailSecurityInterceptor
3
+
4
+ class Dekiru::MailSecurityInterceptor::NoToAdreessError < StandardError ; end
5
+ def delivering_email(mail)
6
+ if mail.to.blank?
7
+ raise Dekiru::MailSecurityInterceptor::NoToAdreessError
8
+ end
9
+ end
10
+ end
11
+ end
@@ -10,6 +10,14 @@ module Dekiru
10
10
  end
11
11
  end
12
12
 
13
+ config.after_initialize do
14
+ if Dekiru.configuration.mail_security_hook
15
+ Rails.logger.info '[dekiru] mail_security_hook enabled'
16
+ interceptor = Dekiru::MailSecurityInterceptor.new
17
+ ActionMailer::Base.register_interceptor(interceptor)
18
+ end
19
+ end
20
+
13
21
  rake_tasks do
14
22
  load 'dekiru/tasks/smtp_check.rake'
15
23
  load 'dekiru/tasks/db.rake'
@@ -1,3 +1,3 @@
1
1
  module Dekiru
2
- VERSION = '0.1.3'
2
+ VERSION = '0.1.8'
3
3
  end
@@ -0,0 +1,64 @@
1
+ require "spec_helper"
2
+
3
+ describe Dekiru::CamelizeHash do
4
+ using Dekiru::CamelizeHash
5
+
6
+ let(:hash) do
7
+ hash = {
8
+ dekiru_rails: {
9
+ dekiru_rails: 'dekiru'
10
+ },
11
+ 'dekiru_ruby' => {
12
+ 'dekiru_ruby' => 'dekiru'
13
+ }
14
+ }
15
+ end
16
+
17
+ describe '#camelize_keys' do
18
+ it '一階層目のキーがキャメルケースに変換される' do
19
+ expect(hash.camelize_keys(:lower)).to match({
20
+ dekiruRails: {
21
+ dekiru_rails: 'dekiru'
22
+ },
23
+ 'dekiruRuby' => {
24
+ 'dekiru_ruby' => 'dekiru'
25
+ }
26
+ })
27
+ end
28
+
29
+ it '一階層目のキーがアッパーキャメルケースに変換される' do
30
+ expect(hash.camelize_keys).to match({
31
+ DekiruRails: {
32
+ dekiru_rails: 'dekiru'
33
+ },
34
+ 'DekiruRuby' => {
35
+ 'dekiru_ruby' => 'dekiru'
36
+ }
37
+ })
38
+ end
39
+ end
40
+
41
+ describe '#deep_camelize_keys' do
42
+ it '2階層目以降のキーもキャメルケースに変換される' do
43
+ expect(hash.deep_camelize_keys(:lower)).to match({
44
+ dekiruRails: {
45
+ dekiruRails: 'dekiru'
46
+ },
47
+ 'dekiruRuby' => {
48
+ 'dekiruRuby' => 'dekiru'
49
+ }
50
+ })
51
+ end
52
+
53
+ it '2階層目以降のキーもアッパーキャメルケースに変換される' do
54
+ expect(hash.deep_camelize_keys).to match({
55
+ DekiruRails: {
56
+ DekiruRails: 'dekiru'
57
+ },
58
+ 'DekiruRuby' => {
59
+ 'DekiruRuby' => 'dekiru'
60
+ }
61
+ })
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,113 @@
1
+ require "spec_helper"
2
+
3
+ describe Dekiru::DataMigrationOperator do
4
+ let(:dummy_stream) do
5
+ class Dekiru::DummyStream
6
+ attr_reader :out
7
+
8
+ def initialize
9
+ @out = ''
10
+ end
11
+
12
+ def puts(text)
13
+ @out = out << "#{text}\n"
14
+ end
15
+
16
+ def print(text)
17
+ @out = out << text
18
+ end
19
+
20
+ def tty?
21
+ false
22
+ end
23
+
24
+ def flush
25
+ end
26
+ end
27
+ Dekiru::DummyStream.new
28
+ end
29
+ let(:operator) { Dekiru::DataMigrationOperator.new('dummy', output: dummy_stream) }
30
+
31
+ describe '#execute' do
32
+ it 'confirm で yes' do
33
+ allow(STDIN).to receive(:gets) do
34
+ "yes\n"
35
+ end
36
+
37
+ expect do
38
+ operator.execute { log 'processing'; sleep 1.0 }
39
+ end.not_to raise_error
40
+
41
+ expect(operator.result).to eq(true)
42
+ expect(operator.duration).to be_within(0.1).of(1.0)
43
+ expect(operator.error).to eq(nil)
44
+ expect(operator.stream.out).to include('Are you sure to commit?')
45
+ expect(operator.stream.out).to include('Finished successfully:')
46
+ expect(operator.stream.out).to include('Total time:')
47
+ end
48
+
49
+ it 'confirm で no' do
50
+ allow(STDIN).to receive(:gets) do
51
+ "no\n"
52
+ end
53
+
54
+ expect do
55
+ operator.execute { log 'processing'; sleep 1.0 }
56
+ end.to raise_error(ActiveRecord::Rollback)
57
+
58
+ expect(operator.result).to eq(false)
59
+ expect(operator.duration).to be_within(0.1).of(1.0)
60
+ expect(operator.error.class).to eq(ActiveRecord::Rollback)
61
+ expect(operator.stream.out).to include('Are you sure to commit?')
62
+ expect(operator.stream.out).to include('Canceled:')
63
+ expect(operator.stream.out).to include('Total time:')
64
+ end
65
+
66
+ it '処理中に例外' do
67
+ expect do
68
+ operator.execute { raise ArgumentError }
69
+ end.to raise_error(ArgumentError)
70
+
71
+ expect(operator.result).to eq(false)
72
+ expect(operator.error.class).to eq(ArgumentError)
73
+ expect(operator.stream.out).not_to include('Are you sure to commit?')
74
+ expect(operator.stream.out).not_to include('Canceled:')
75
+ expect(operator.stream.out).to include('Total time:')
76
+ end
77
+ end
78
+
79
+ describe '#find_each_with_progress' do
80
+ it '進捗が表示される' do
81
+ class Dekiru::DummyRecord
82
+ def self.count
83
+ 10
84
+ end
85
+
86
+ def self.find_each
87
+ (0...count).to_a.each do |num|
88
+ yield(num)
89
+ end
90
+ end
91
+ end
92
+
93
+ allow(STDIN).to receive(:gets) do
94
+ "yes\n"
95
+ end
96
+
97
+ sum = 0
98
+ operator.execute do
99
+ find_each_with_progress(Dekiru::DummyRecord, title: 'count up number') do |num|
100
+ sum += num
101
+ end
102
+ end
103
+
104
+ expect(sum).to eq(45)
105
+ expect(operator.result).to eq(true)
106
+ expect(operator.error).to eq(nil)
107
+ expect(operator.stream.out).to include('Are you sure to commit?')
108
+ expect(operator.stream.out).to include('count up number:')
109
+ expect(operator.stream.out).to include('Finished successfully:')
110
+ expect(operator.stream.out).to include('Total time:')
111
+ end
112
+ end
113
+ end
@@ -0,0 +1,47 @@
1
+ require 'spec_helper'
2
+
3
+ class TestMailer < ActionMailer::Base
4
+ default from: 'no-reply@dekiru.test'
5
+
6
+ def test(to)
7
+ mail to: to, subject: 'test', body: 'test'
8
+ end
9
+ end
10
+
11
+ describe Dekiru::MailSecurityInterceptor do
12
+ before do
13
+ interceptor = Dekiru::MailSecurityInterceptor.new
14
+ ActionMailer::Base.register_interceptor(interceptor)
15
+ end
16
+
17
+ context '宛先(to)が空配列の場合' do
18
+ let(:to_address) { [] }
19
+ it '例外が発生すること' do
20
+ expect { TestMailer.test(to_address).deliver_now }.to raise_error(Dekiru::MailSecurityInterceptor::NoToAdreessError)
21
+ end
22
+ end
23
+ context '宛先(to)が空文字の場合' do
24
+ let(:to_address) { '' }
25
+ it '例外が発生すること' do
26
+ expect { TestMailer.test(to_address).deliver_now }.to raise_error(Dekiru::MailSecurityInterceptor::NoToAdreessError)
27
+ end
28
+ end
29
+ context '宛先(to)がnilの場合' do
30
+ let(:to_address) { nil }
31
+ it '例外が発生すること' do
32
+ expect { TestMailer.test(to_address).deliver_now }.to raise_error(Dekiru::MailSecurityInterceptor::NoToAdreessError)
33
+ end
34
+ end
35
+ context '宛先(to)が文字列の場合' do
36
+ let(:to_address) { 'test@dekiru.test' }
37
+ it '例外が発生しないこと' do
38
+ expect { TestMailer.test(to_address).deliver_now }.not_to raise_error
39
+ end
40
+ end
41
+ context '宛先(to)が配列の場合' do
42
+ let(:to_address) { ['test@dekiru.test'] }
43
+ it '例外が発生しないこと' do
44
+ expect { TestMailer.test(to_address).deliver_now }.not_to raise_error
45
+ end
46
+ end
47
+ end
@@ -8,16 +8,14 @@ require 'active_support/core_ext/object'
8
8
  require "active_record"
9
9
  require "action_view"
10
10
  require "action_view/helpers"
11
+ require 'action_mailer'
11
12
 
12
13
  PROJECT_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
13
14
 
14
15
  $LOAD_PATH << File.join(PROJECT_ROOT, 'lib')
15
16
 
16
17
  require 'dekiru'
17
-
18
- Dir.glob(File.join(PROJECT_ROOT, 'spec', 'support', '**', '*.rb')).each do |file|
19
- require(file)
20
- end
18
+ Dir.glob(File.join(PROJECT_ROOT, 'spec/supports/**/*.rb')).each { |f| require f }
21
19
 
22
20
  RSpec.configure do |config|
23
21
  end
@@ -0,0 +1 @@
1
+ ActionMailer::Base.delivery_method = :test
@@ -0,0 +1,5 @@
1
+ class ActiveRecord::Base
2
+ def self.transaction(*args)
3
+ yield(*args)
4
+ end
5
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dekiru
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.3
4
+ version: 0.1.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Akihiro Matsumura
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-05-29 00:00:00.000000000 Z
11
+ date: 2020-11-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: http_accept_language
@@ -38,6 +38,20 @@ dependencies:
38
38
  - - ">="
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: ruby-progressbar
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
41
55
  - !ruby/object:Gem::Dependency
42
56
  name: rake
43
57
  requirement: !ruby/object:Gem::Requirement
@@ -110,10 +124,13 @@ files:
110
124
  - Rakefile
111
125
  - dekiru.gemspec
112
126
  - lib/dekiru.rb
127
+ - lib/dekiru/camelize_hash.rb
113
128
  - lib/dekiru/capybara/helpers.rb
114
129
  - lib/dekiru/capybara/matchers.rb
115
130
  - lib/dekiru/controller_additions.rb
131
+ - lib/dekiru/data_migration_operator.rb
116
132
  - lib/dekiru/helper.rb
133
+ - lib/dekiru/mail_security_interceptor.rb
117
134
  - lib/dekiru/railtie.rb
118
135
  - lib/dekiru/smtp_check_mailer.rb
119
136
  - lib/dekiru/task_with_logger.rb
@@ -121,9 +138,14 @@ files:
121
138
  - lib/dekiru/tasks/smtp_check.rake
122
139
  - lib/dekiru/validators/existence.rb
123
140
  - lib/dekiru/version.rb
141
+ - spec/dekiru/camelize_hash_spec.rb
142
+ - spec/dekiru/data_migration_operator_spec.rb
124
143
  - spec/dekiru/helper_spec.rb
144
+ - spec/dekiru/mail_security_interceptor_spec.rb
125
145
  - spec/dekiru/validators/existence_spec.rb
126
146
  - spec/spec_helper.rb
147
+ - spec/supports/action_mailer.rb
148
+ - spec/supports/mock_active_record.rb
127
149
  homepage: ''
128
150
  licenses: []
129
151
  metadata: {}
@@ -135,19 +157,23 @@ required_ruby_version: !ruby/object:Gem::Requirement
135
157
  requirements:
136
158
  - - ">="
137
159
  - !ruby/object:Gem::Version
138
- version: '0'
160
+ version: 2.4.0
139
161
  required_rubygems_version: !ruby/object:Gem::Requirement
140
162
  requirements:
141
163
  - - ">="
142
164
  - !ruby/object:Gem::Version
143
165
  version: '0'
144
166
  requirements: []
145
- rubyforge_project:
146
- rubygems_version: 2.7.6
167
+ rubygems_version: 3.1.2
147
168
  signing_key:
148
169
  specification_version: 4
149
170
  summary: Usefull helper methods for Ruby on Rails
150
171
  test_files:
172
+ - spec/dekiru/camelize_hash_spec.rb
173
+ - spec/dekiru/data_migration_operator_spec.rb
151
174
  - spec/dekiru/helper_spec.rb
175
+ - spec/dekiru/mail_security_interceptor_spec.rb
152
176
  - spec/dekiru/validators/existence_spec.rb
153
177
  - spec/spec_helper.rb
178
+ - spec/supports/action_mailer.rb
179
+ - spec/supports/mock_active_record.rb