dekiru 0.1.3 → 0.1.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 +4 -4
- data/README.md +45 -0
- data/dekiru.gemspec +1 -0
- data/lib/dekiru.rb +19 -0
- data/lib/dekiru/data_migration_operator.rb +82 -0
- data/lib/dekiru/mail_security_interceptor.rb +11 -0
- data/lib/dekiru/railtie.rb +8 -0
- data/lib/dekiru/version.rb +1 -1
- data/spec/dekiru/data_migration_operator_spec.rb +113 -0
- data/spec/dekiru/mail_security_interceptor_spec.rb +47 -0
- data/spec/spec_helper.rb +2 -4
- data/spec/supports/action_mailer.rb +1 -0
- data/spec/supports/mock_active_record.rb +5 -0
- metadata +26 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fa88f3d2cf47df7ed8a071acc0dbb0b86fa20e42c5ad3e72b3f23fb8c6f593b5
|
4
|
+
data.tar.gz: ddabf00fc5c3dfcfb8a22f9103f7a8d90ea5e92b6c158bd2b4ea1936d48ebc81
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 02ed8451df03137d882758e3adb2fb06f7d8aa3b9e240ec84cd0e59a3bf460945f18919717010c44f58f13abbd6f468d39a33d37a29c9ad809334385ecbd6adc
|
7
|
+
data.tar.gz: be1798f99193883c7bb7978f52b9e52e40bcd2e01e1b041159f110c1be6517922b7a6067978a423e3c9315bf9a870bceb465fae1234b2929a318d191d486066c
|
data/README.md
CHANGED
@@ -109,6 +109,51 @@ 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
|
+
|
112
157
|
## Contributing
|
113
158
|
|
114
159
|
1. Fork it
|
data/dekiru.gemspec
CHANGED
@@ -17,6 +17,7 @@ Gem::Specification.new do |gem|
|
|
17
17
|
|
18
18
|
gem.add_dependency 'http_accept_language', [">= 2.0.0"]
|
19
19
|
gem.add_dependency 'rails'
|
20
|
+
gem.add_dependency 'ruby-progressbar'
|
20
21
|
gem.add_development_dependency 'rake', [">= 0"]
|
21
22
|
gem.add_development_dependency 'rspec'
|
22
23
|
gem.add_development_dependency 'rubocop'
|
data/lib/dekiru.rb
CHANGED
@@ -3,9 +3,28 @@ 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'
|
6
8
|
|
7
9
|
require 'active_support'
|
8
10
|
require 'active_support/all'
|
9
11
|
|
10
12
|
module Dekiru
|
13
|
+
class << self
|
14
|
+
def configure
|
15
|
+
yield(configuration)
|
16
|
+
end
|
17
|
+
|
18
|
+
def configuration
|
19
|
+
@configuration ||= Configuration.new
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
class Configuration
|
24
|
+
attr_accessor :mail_security_hook
|
25
|
+
|
26
|
+
def initialize
|
27
|
+
@mail_security_hook = false # default
|
28
|
+
end
|
29
|
+
end
|
11
30
|
end
|
@@ -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) 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
|
@@ -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
|
data/lib/dekiru/railtie.rb
CHANGED
@@ -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'
|
data/lib/dekiru/version.rb
CHANGED
@@ -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
|
data/spec/spec_helper.rb
CHANGED
@@ -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
|
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.
|
4
|
+
version: 0.1.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Akihiro Matsumura
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2019-06-01 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
|
@@ -113,7 +127,9 @@ files:
|
|
113
127
|
- lib/dekiru/capybara/helpers.rb
|
114
128
|
- lib/dekiru/capybara/matchers.rb
|
115
129
|
- lib/dekiru/controller_additions.rb
|
130
|
+
- lib/dekiru/data_migration_operator.rb
|
116
131
|
- lib/dekiru/helper.rb
|
132
|
+
- lib/dekiru/mail_security_interceptor.rb
|
117
133
|
- lib/dekiru/railtie.rb
|
118
134
|
- lib/dekiru/smtp_check_mailer.rb
|
119
135
|
- lib/dekiru/task_with_logger.rb
|
@@ -121,9 +137,13 @@ files:
|
|
121
137
|
- lib/dekiru/tasks/smtp_check.rake
|
122
138
|
- lib/dekiru/validators/existence.rb
|
123
139
|
- lib/dekiru/version.rb
|
140
|
+
- spec/dekiru/data_migration_operator_spec.rb
|
124
141
|
- spec/dekiru/helper_spec.rb
|
142
|
+
- spec/dekiru/mail_security_interceptor_spec.rb
|
125
143
|
- spec/dekiru/validators/existence_spec.rb
|
126
144
|
- spec/spec_helper.rb
|
145
|
+
- spec/supports/action_mailer.rb
|
146
|
+
- spec/supports/mock_active_record.rb
|
127
147
|
homepage: ''
|
128
148
|
licenses: []
|
129
149
|
metadata: {}
|
@@ -148,6 +168,10 @@ signing_key:
|
|
148
168
|
specification_version: 4
|
149
169
|
summary: Usefull helper methods for Ruby on Rails
|
150
170
|
test_files:
|
171
|
+
- spec/dekiru/data_migration_operator_spec.rb
|
151
172
|
- spec/dekiru/helper_spec.rb
|
173
|
+
- spec/dekiru/mail_security_interceptor_spec.rb
|
152
174
|
- spec/dekiru/validators/existence_spec.rb
|
153
175
|
- spec/spec_helper.rb
|
176
|
+
- spec/supports/action_mailer.rb
|
177
|
+
- spec/supports/mock_active_record.rb
|