dekiru 0.1.3 → 0.1.8

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: 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