easysuite 1.2.1
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 +7 -0
- data/LICENSE.txt +21 -0
- data/exe/easysuite +29 -0
- data/lib/easysuite/config.rb +243 -0
- data/lib/easysuite/lock.rb +135 -0
- data/lib/easysuite/logger.rb +97 -0
- data/lib/easysuite/smtp.rb +178 -0
- data/lib/easysuite/thread.rb +97 -0
- data/lib/easysuite/version.rb +3 -0
- data/lib/easysuite.rb +73 -0
- data/sample/common.rb +3 -0
- data/sample/easytools.rb +57 -0
- data/sample/sample.rb +5 -0
- metadata +55 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: ce68c493c22986c2c08f2443778f6de32c365eeeed0b64e24182a01b162cd295
|
4
|
+
data.tar.gz: ababc499754f35cec1e70a68f577ca172b60a2fcab9112059a8b0b779429581d
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 9030154a5e7c000c3ca1742590b88a4fb02a39b029ea0fae635b48a26978904062530efe8ea8c393c16bce92a3dead707fd16710bc61082ae2c06b9e6ba8037c
|
7
|
+
data.tar.gz: '08f47c288a9f622de954df439c313e417b7fb4760637464aa34582f4e9cc4792f2935807b87d96b14d2edd4802bb263386389b85652caf60549b5e7c2d3dda69'
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2016 Masafumi Kiribayashi
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/exe/easysuite
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'fileutils'
|
3
|
+
|
4
|
+
if (ARGV.size >= 2) && (ARGV[0] == "new")
|
5
|
+
proj = ARGV[1]
|
6
|
+
$stderr.puts("Deploying easytools to '#{proj}'...")
|
7
|
+
|
8
|
+
["app", "config", "lib", "log", "tmp"].each do |dir|
|
9
|
+
unless File.exist?(path = File.join(proj, dir))
|
10
|
+
$stderr.puts("%12s %s" % ["create", path])
|
11
|
+
FileUtils.mkpath(path)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
paths = []
|
16
|
+
paths << File.join(proj, "lib", "easytools.rb")
|
17
|
+
paths << File.join(proj, "app", "common.rb")
|
18
|
+
paths << File.join(proj, "app", "sample.rb")
|
19
|
+
|
20
|
+
paths.each do |path|
|
21
|
+
unless File.exist?(path)
|
22
|
+
$stderr.puts("%12s %s" % ["create", path])
|
23
|
+
src = File.expand_path("../../sample/#{File.basename(path)}", __FILE__)
|
24
|
+
FileUtils.cp(src, path)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
else
|
28
|
+
$stderr.puts("SYNOPSIS: easysuite new [Project]")
|
29
|
+
end
|
@@ -0,0 +1,243 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
3
|
+
module EasySuite
|
4
|
+
#--
|
5
|
+
# Config
|
6
|
+
#++
|
7
|
+
# Class to config easily.
|
8
|
+
class Config
|
9
|
+
class << self
|
10
|
+
#--
|
11
|
+
# load_yaml
|
12
|
+
#++
|
13
|
+
# Load object from YAML file.
|
14
|
+
def load_yaml(path)
|
15
|
+
yaml = binread(path).to_s
|
16
|
+
YAML.respond_to?(:unsafe_load) ? YAML.unsafe_load(yaml) : YAML.load(yaml)
|
17
|
+
end
|
18
|
+
|
19
|
+
alias_method :load, :load_yaml
|
20
|
+
|
21
|
+
#--
|
22
|
+
# dump_yaml
|
23
|
+
#++
|
24
|
+
# Dump object to YAML file.
|
25
|
+
def dump_yaml(path, obj)
|
26
|
+
binwrite(path, YAML.dump(obj))
|
27
|
+
end
|
28
|
+
|
29
|
+
alias_method :dump, :dump_yaml
|
30
|
+
|
31
|
+
#--
|
32
|
+
# read
|
33
|
+
#++
|
34
|
+
# Read string from file.
|
35
|
+
def read(path)
|
36
|
+
IO.read(path) rescue nil
|
37
|
+
end
|
38
|
+
|
39
|
+
#--
|
40
|
+
# write
|
41
|
+
#++
|
42
|
+
# Write string to file.
|
43
|
+
def write(path, str)
|
44
|
+
IO.write(path, str)
|
45
|
+
end
|
46
|
+
|
47
|
+
#--
|
48
|
+
# binread
|
49
|
+
#++
|
50
|
+
# Read string from file.(binary mode)
|
51
|
+
def binread(path)
|
52
|
+
IO.binread(path) rescue nil
|
53
|
+
end
|
54
|
+
|
55
|
+
#--
|
56
|
+
# binwrite
|
57
|
+
#++
|
58
|
+
# Write string to file.(binary mode)
|
59
|
+
def binwrite(path, str)
|
60
|
+
IO.binwrite(path, str)
|
61
|
+
end
|
62
|
+
|
63
|
+
#--
|
64
|
+
# set_values
|
65
|
+
#++
|
66
|
+
# Set values from Hash or YAML file.
|
67
|
+
def set_values(obj, src, *keys)
|
68
|
+
values = case src
|
69
|
+
when Hash
|
70
|
+
src
|
71
|
+
when String
|
72
|
+
load_yaml(src) rescue nil
|
73
|
+
end
|
74
|
+
|
75
|
+
if values.kind_of?(Hash)
|
76
|
+
keys = values.keys if keys.empty?
|
77
|
+
|
78
|
+
keys.each do |key|
|
79
|
+
writer = key.to_s + "="
|
80
|
+
obj.__send__(writer, values[key]) if obj.respond_to?(writer)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
obj
|
85
|
+
end
|
86
|
+
|
87
|
+
#--
|
88
|
+
# encode
|
89
|
+
#++
|
90
|
+
# Encode strings (in Hash and Array).
|
91
|
+
def encode(obj, &proc)
|
92
|
+
proc ||= lambda {|s| s.encode }
|
93
|
+
|
94
|
+
case obj
|
95
|
+
when Hash
|
96
|
+
{}.tap {|x| obj.each {|k, v| x[encode(k, &proc)] = encode(v, &proc) }}
|
97
|
+
when Array
|
98
|
+
[].tap {|x| obj.each {|v| x << encode(v, &proc) }}
|
99
|
+
when String
|
100
|
+
proc.call(obj)
|
101
|
+
when Symbol
|
102
|
+
proc.call(obj.to_s).to_sym
|
103
|
+
else
|
104
|
+
obj
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
#--
|
109
|
+
# keys_to_symbol
|
110
|
+
#++
|
111
|
+
# Convert Hash keys into Symbol from String (in Hash and Array).
|
112
|
+
def keys_to_symbol(obj)
|
113
|
+
keys_to_something(obj) do |x, k, v|
|
114
|
+
if k.kind_of?(String)
|
115
|
+
x[k.to_sym] ||= keys_to_symbol(v)
|
116
|
+
else
|
117
|
+
x[k] = keys_to_symbol(v)
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
#--
|
123
|
+
# keys_to_string
|
124
|
+
#++
|
125
|
+
# Convert Hash keys into String from Symbol (in Hash and Array).
|
126
|
+
def keys_to_string(obj)
|
127
|
+
keys_to_something(obj) do |x, k, v|
|
128
|
+
if k.kind_of?(Symbol)
|
129
|
+
x[k.to_s] ||= keys_to_string(v)
|
130
|
+
else
|
131
|
+
x[k] = keys_to_string(v)
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
private
|
137
|
+
|
138
|
+
#--
|
139
|
+
# keys_to_something
|
140
|
+
#++
|
141
|
+
# Convert Hash keys (in Hash and Array).
|
142
|
+
def keys_to_something(obj, &proc)
|
143
|
+
return obj unless proc
|
144
|
+
|
145
|
+
case obj
|
146
|
+
when Hash
|
147
|
+
{}.tap {|x| obj.each {|k, v| proc.call(x, k, keys_to_something(v, &proc)) }}
|
148
|
+
when Array
|
149
|
+
[].tap {|x| obj.each {|v| x << keys_to_something(v, &proc) }}
|
150
|
+
else
|
151
|
+
obj
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
attr_accessor :config_dir
|
157
|
+
|
158
|
+
#--
|
159
|
+
# initialize
|
160
|
+
#++
|
161
|
+
# [config_dir]
|
162
|
+
# Default directory of instance.
|
163
|
+
def initialize(config_dir = nil)
|
164
|
+
@config_dir = config_dir
|
165
|
+
end
|
166
|
+
|
167
|
+
#--
|
168
|
+
# load_yaml
|
169
|
+
#++
|
170
|
+
# Load object from YAML file.
|
171
|
+
def load_yaml(filename)
|
172
|
+
path = expand_path(filename)
|
173
|
+
Config.load_yaml(path)
|
174
|
+
end
|
175
|
+
|
176
|
+
alias_method :load, :load_yaml
|
177
|
+
|
178
|
+
#--
|
179
|
+
# dump_yaml
|
180
|
+
#++
|
181
|
+
# Dump object to YAML file.
|
182
|
+
def dump_yaml(filename, obj)
|
183
|
+
path = expand_path(filename)
|
184
|
+
Config.dump_yaml(path, obj)
|
185
|
+
end
|
186
|
+
|
187
|
+
alias_method :dump, :dump_yaml
|
188
|
+
|
189
|
+
#--
|
190
|
+
# read
|
191
|
+
#++
|
192
|
+
# Read string from file.
|
193
|
+
def read(filename)
|
194
|
+
path = expand_path(filename)
|
195
|
+
Config.read(path)
|
196
|
+
end
|
197
|
+
|
198
|
+
#--
|
199
|
+
# write
|
200
|
+
#++
|
201
|
+
# Write string to file.
|
202
|
+
def write(filename, str)
|
203
|
+
path = expand_path(filename)
|
204
|
+
Config.write(path, str)
|
205
|
+
end
|
206
|
+
|
207
|
+
#--
|
208
|
+
# binread
|
209
|
+
#++
|
210
|
+
# Read string from file.(binary mode)
|
211
|
+
def binread(filename)
|
212
|
+
path = expand_path(filename)
|
213
|
+
Config.binread(path)
|
214
|
+
end
|
215
|
+
|
216
|
+
#--
|
217
|
+
# binwrite
|
218
|
+
#++
|
219
|
+
# Write string to file.(binary mode)
|
220
|
+
def binwrite(filename, str)
|
221
|
+
path = expand_path(filename)
|
222
|
+
Config.binwrite(path, str)
|
223
|
+
end
|
224
|
+
|
225
|
+
#--
|
226
|
+
# set_values
|
227
|
+
#++
|
228
|
+
# Set values from Hash or YAML file.
|
229
|
+
def set_values(obj, src, *keys)
|
230
|
+
src = expand_path(src) if src.kind_of?(String)
|
231
|
+
Config.set_values(obj, src, *keys)
|
232
|
+
end
|
233
|
+
|
234
|
+
private
|
235
|
+
|
236
|
+
#--
|
237
|
+
# expand_path
|
238
|
+
#++
|
239
|
+
def expand_path(filename)
|
240
|
+
File.expand_path(filename, @config_dir)
|
241
|
+
end
|
242
|
+
end
|
243
|
+
end
|
@@ -0,0 +1,135 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
require 'timeout'
|
3
|
+
|
4
|
+
module EasySuite
|
5
|
+
#--
|
6
|
+
# Lock
|
7
|
+
#++
|
8
|
+
# Class to lock easily.
|
9
|
+
class Lock
|
10
|
+
attr_accessor :lock_dir
|
11
|
+
|
12
|
+
#--
|
13
|
+
# initialize
|
14
|
+
#++
|
15
|
+
# [lock_dir]
|
16
|
+
# This class uses files in the directory.
|
17
|
+
def initialize(lock_dir = nil)
|
18
|
+
@lock_dir = lock_dir
|
19
|
+
end
|
20
|
+
|
21
|
+
#--
|
22
|
+
# lock
|
23
|
+
#++
|
24
|
+
# Make lock file in @lock_dir.
|
25
|
+
def lock(name)
|
26
|
+
result = create_lock_file(name)
|
27
|
+
|
28
|
+
if result && block_given?
|
29
|
+
begin
|
30
|
+
result = yield
|
31
|
+
ensure
|
32
|
+
delete_lock_file(name)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
result
|
37
|
+
end
|
38
|
+
|
39
|
+
#--
|
40
|
+
# wait
|
41
|
+
#++
|
42
|
+
# Make lock file in @lock_dir until success.
|
43
|
+
def wait(name, sec = nil)
|
44
|
+
result = nil
|
45
|
+
|
46
|
+
begin
|
47
|
+
Timeout.timeout(sec) {
|
48
|
+
sleep(1) until result = create_lock_file(name)
|
49
|
+
}
|
50
|
+
rescue Timeout::Error
|
51
|
+
end
|
52
|
+
|
53
|
+
if result && block_given?
|
54
|
+
begin
|
55
|
+
result = yield
|
56
|
+
ensure
|
57
|
+
delete_lock_file(name)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
result
|
62
|
+
end
|
63
|
+
|
64
|
+
#--
|
65
|
+
# unlock
|
66
|
+
#++
|
67
|
+
# Delete lock file in @lock_dir.
|
68
|
+
def unlock(name)
|
69
|
+
delete_lock_file(name)
|
70
|
+
end
|
71
|
+
|
72
|
+
private
|
73
|
+
|
74
|
+
#--
|
75
|
+
# lock_file(name)
|
76
|
+
#++
|
77
|
+
def lock_file(name)
|
78
|
+
File.expand_path("#{name}.lock", @lock_dir.to_s)
|
79
|
+
end
|
80
|
+
|
81
|
+
#--
|
82
|
+
# owner_pid(name)
|
83
|
+
#++
|
84
|
+
def owner_pid(name)
|
85
|
+
IO.read(lock_file(name)).to_i rescue 0
|
86
|
+
end
|
87
|
+
|
88
|
+
#--
|
89
|
+
# is_valid?(name)
|
90
|
+
#++
|
91
|
+
def is_valid?(name)
|
92
|
+
((pid = owner_pid(name)) > 0) && ((Process.kill(0, pid) rescue 0) == 1)
|
93
|
+
end
|
94
|
+
|
95
|
+
#--
|
96
|
+
# create_lock_file
|
97
|
+
#++
|
98
|
+
def create_lock_file(name)
|
99
|
+
return false unless @lock_dir
|
100
|
+
|
101
|
+
if is_valid?(name)
|
102
|
+
return (owner_pid(name) == Process.pid)
|
103
|
+
end
|
104
|
+
|
105
|
+
begin
|
106
|
+
FileUtils.mkpath(@lock_dir)
|
107
|
+
IO.write(lock_file(name), "#{Process.pid}\n")
|
108
|
+
rescue
|
109
|
+
return false
|
110
|
+
end
|
111
|
+
|
112
|
+
true
|
113
|
+
end
|
114
|
+
|
115
|
+
#--
|
116
|
+
# delete_lock_file
|
117
|
+
#++
|
118
|
+
def delete_lock_file(name)
|
119
|
+
return false unless @lock_dir
|
120
|
+
return true unless File.exist?(lock_file(name))
|
121
|
+
|
122
|
+
if is_valid?(name) && (owner_pid(name) != Process.pid)
|
123
|
+
return false
|
124
|
+
end
|
125
|
+
|
126
|
+
begin
|
127
|
+
FileUtils.rm(lock_file(name))
|
128
|
+
rescue
|
129
|
+
return false
|
130
|
+
end
|
131
|
+
|
132
|
+
true
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
require 'easysuite/thread'
|
2
|
+
require 'fileutils'
|
3
|
+
require 'logger'
|
4
|
+
|
5
|
+
module EasySuite
|
6
|
+
#--
|
7
|
+
# Logger
|
8
|
+
#++
|
9
|
+
# Class to log easily.
|
10
|
+
class Logger < ThreadSafe
|
11
|
+
#--
|
12
|
+
# initialize
|
13
|
+
#++
|
14
|
+
def initialize(log_dir = nil, log_file = nil)
|
15
|
+
super()
|
16
|
+
@log_dir = log_dir
|
17
|
+
@log_file = log_file
|
18
|
+
reset
|
19
|
+
end
|
20
|
+
|
21
|
+
#--
|
22
|
+
# log_dir=
|
23
|
+
#++
|
24
|
+
def log_dir=(log_dir)
|
25
|
+
reutrn if (@log_dir == log_dir)
|
26
|
+
@log_dir = log_dir
|
27
|
+
reset
|
28
|
+
end
|
29
|
+
|
30
|
+
#--
|
31
|
+
# log_dir
|
32
|
+
#++
|
33
|
+
def log_dir
|
34
|
+
@log_dir || "."
|
35
|
+
end
|
36
|
+
|
37
|
+
#--
|
38
|
+
# log_file=
|
39
|
+
#++
|
40
|
+
def log_file=(log_file)
|
41
|
+
return if (@log_file == log_file)
|
42
|
+
@log_file = log_file
|
43
|
+
reset
|
44
|
+
end
|
45
|
+
|
46
|
+
#--
|
47
|
+
# log_file
|
48
|
+
#++
|
49
|
+
def log_file
|
50
|
+
s = @log_file || ""
|
51
|
+
s = "common.log" if s.empty?
|
52
|
+
Time.now.strftime(s)
|
53
|
+
end
|
54
|
+
|
55
|
+
#--
|
56
|
+
# puts
|
57
|
+
#++
|
58
|
+
def puts(*args)
|
59
|
+
current = Time.now
|
60
|
+
reset unless @last_time &&
|
61
|
+
(@last_time.yday == current.yday) && (@last_time.year == current.year)
|
62
|
+
@last_time = current
|
63
|
+
prepare
|
64
|
+
args.flatten.each {|arg| arg.to_s.each_line {|l| @logger.debug(l.chomp) }}
|
65
|
+
end
|
66
|
+
|
67
|
+
private
|
68
|
+
|
69
|
+
#--
|
70
|
+
# log_format
|
71
|
+
#++
|
72
|
+
def log_format(severity, datetime, progname, msg)
|
73
|
+
datetime.strftime("[%Y-%m-%d %H:%M:%S] #{msg}\n")
|
74
|
+
end
|
75
|
+
|
76
|
+
#--
|
77
|
+
# reset
|
78
|
+
#++
|
79
|
+
def reset
|
80
|
+
return unless @logger
|
81
|
+
@logger.close
|
82
|
+
@logger = nil
|
83
|
+
end
|
84
|
+
|
85
|
+
#--
|
86
|
+
# prepare
|
87
|
+
#++
|
88
|
+
def prepare
|
89
|
+
return if @logger
|
90
|
+
log_path = File.join(self.log_dir, self.log_file)
|
91
|
+
FileUtils.mkpath(self.log_dir)
|
92
|
+
FileUtils.touch(log_path) unless File.exist?(log_path)
|
93
|
+
@logger = ::Logger.new(log_path)
|
94
|
+
@logger.formatter = method(:log_format)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
@@ -0,0 +1,178 @@
|
|
1
|
+
require 'net/smtp'
|
2
|
+
require 'base64'
|
3
|
+
|
4
|
+
module EasySuite
|
5
|
+
#--
|
6
|
+
# SMTP
|
7
|
+
#++
|
8
|
+
# Class to send mail easily.
|
9
|
+
class SMTP
|
10
|
+
attr_accessor :address, :port, :helo_domain, :account, :password, :authtype,
|
11
|
+
:from, :to, :cc, :bcc
|
12
|
+
|
13
|
+
#--
|
14
|
+
# initialize
|
15
|
+
#++
|
16
|
+
def initialize
|
17
|
+
@port = Net::SMTP.default_port
|
18
|
+
@helo_domain = "localhost"
|
19
|
+
end
|
20
|
+
|
21
|
+
#--
|
22
|
+
# send_mail
|
23
|
+
#++
|
24
|
+
def send_mail(subject, message)
|
25
|
+
smtp = Net::SMTP.new(@address, @port)
|
26
|
+
|
27
|
+
case @port
|
28
|
+
when Net::SMTP.default_port
|
29
|
+
when Net::SMTP.default_tls_port
|
30
|
+
smtp.enable_tls
|
31
|
+
when Net::SMTP.default_submission_port
|
32
|
+
smtp.enable_starttls
|
33
|
+
else
|
34
|
+
raise "Not supported port: #{@port}"
|
35
|
+
end
|
36
|
+
|
37
|
+
body, charset, transfer_encoding = make_body(message)
|
38
|
+
headers = []
|
39
|
+
headers << make_header("From", @from) if @from
|
40
|
+
headers << make_header("To", @to) if @to
|
41
|
+
headers << make_header("Cc", @cc) if @cc
|
42
|
+
headers << make_header("Bcc", @bcc) if @bcc
|
43
|
+
headers << make_header("Subject", subject)
|
44
|
+
headers << make_header("Date", Time.now.strftime("%a, %d %b %Y %X %z"))
|
45
|
+
headers << make_header("Mime-Version", "1.0")
|
46
|
+
headers << make_header("Content-Type", "text/plain; charset=#{charset}")
|
47
|
+
headers << make_header("Content-Transfer-Encoding", transfer_encoding)
|
48
|
+
mailsrc = headers.join("\n")
|
49
|
+
mailsrc += "\n\n#{body}"
|
50
|
+
|
51
|
+
smtp.start(@helo_domain, @account, @password, @authtype) do |smtp|
|
52
|
+
smtp.send_mail(mailsrc, mail_from, rcpt_to)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
#--
|
57
|
+
# mail_from
|
58
|
+
#++
|
59
|
+
def mail_from
|
60
|
+
extract_address(@from)
|
61
|
+
end
|
62
|
+
|
63
|
+
#--
|
64
|
+
# rcpt_to
|
65
|
+
#++
|
66
|
+
def rcpt_to
|
67
|
+
addrs = []
|
68
|
+
|
69
|
+
([@to].flatten + [@cc].flatten + [@bcc].flatten).each do |addr|
|
70
|
+
next unless addr
|
71
|
+
addrs << extract_address(addr)
|
72
|
+
end
|
73
|
+
|
74
|
+
addrs.uniq
|
75
|
+
end
|
76
|
+
|
77
|
+
private
|
78
|
+
|
79
|
+
#--
|
80
|
+
# make_header
|
81
|
+
#++
|
82
|
+
def make_header(key, val)
|
83
|
+
items = []
|
84
|
+
|
85
|
+
encode = lambda {|x|
|
86
|
+
Base64.encode64(x.encode(Encoding::UTF_8)).
|
87
|
+
lines.map {|l| "=?UTF-8?B?#{l.chomp}?=" }.join(" ")
|
88
|
+
}
|
89
|
+
|
90
|
+
# Make 7bit strings.
|
91
|
+
[val].flatten.each do |obj|
|
92
|
+
src = obj.to_s.gsub("\n", "")
|
93
|
+
dst = ""
|
94
|
+
buf = ""
|
95
|
+
space = ""
|
96
|
+
|
97
|
+
loop do
|
98
|
+
a = src.partition(/\s+/)
|
99
|
+
|
100
|
+
if a[0].ascii_only?
|
101
|
+
unless buf.empty?
|
102
|
+
dst += encode.call(buf)
|
103
|
+
buf = ""
|
104
|
+
end
|
105
|
+
|
106
|
+
dst += space
|
107
|
+
dst += a[0]
|
108
|
+
else
|
109
|
+
if buf.empty?
|
110
|
+
dst += space
|
111
|
+
buf = a[0]
|
112
|
+
else
|
113
|
+
buf += space
|
114
|
+
buf += a[0]
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
break if a[1].empty? && a[2].empty?
|
119
|
+
space, src = a[1], a[2]
|
120
|
+
end
|
121
|
+
|
122
|
+
unless buf.empty?
|
123
|
+
dst += encode.call(buf)
|
124
|
+
buf = ""
|
125
|
+
end
|
126
|
+
|
127
|
+
items << dst unless dst.empty?
|
128
|
+
end
|
129
|
+
|
130
|
+
# Each line of characters SHOULD be no more than 78 characters.
|
131
|
+
src = "#{key}: " + items.join(", ")
|
132
|
+
dst = ""
|
133
|
+
buf = ""
|
134
|
+
space = ""
|
135
|
+
|
136
|
+
loop do
|
137
|
+
a = src.partition(/\s+/)
|
138
|
+
|
139
|
+
if (buf.size + space.size + a[0].size > 78)
|
140
|
+
dst += buf + "\n"
|
141
|
+
buf = space + a[0]
|
142
|
+
else
|
143
|
+
buf += space + a[0]
|
144
|
+
end
|
145
|
+
|
146
|
+
break if a[1].empty? && a[2].empty?
|
147
|
+
space, src = a[1], a[2]
|
148
|
+
end
|
149
|
+
|
150
|
+
dst += buf
|
151
|
+
end
|
152
|
+
|
153
|
+
#--
|
154
|
+
# make_body
|
155
|
+
#++
|
156
|
+
def make_body(obj)
|
157
|
+
body = obj.to_s
|
158
|
+
charset = "US-ASCII"
|
159
|
+
transfer_encoding = "7bit"
|
160
|
+
|
161
|
+
unless body.ascii_only?
|
162
|
+
body = Base64.encode64(body.encode(Encoding::UTF_8))
|
163
|
+
charset = "UTF-8"
|
164
|
+
transfer_encoding = "base64"
|
165
|
+
end
|
166
|
+
|
167
|
+
return body, charset, transfer_encoding
|
168
|
+
end
|
169
|
+
|
170
|
+
#--
|
171
|
+
# extract_address
|
172
|
+
#++
|
173
|
+
def extract_address(addr)
|
174
|
+
addr = addr.to_s.strip
|
175
|
+
(addr =~ /<(.+)>$/) ? $1 : addr
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
require 'monitor'
|
2
|
+
|
3
|
+
module EasySuite
|
4
|
+
#--
|
5
|
+
# ThreadPool
|
6
|
+
#++
|
7
|
+
# Class for thread pooling.
|
8
|
+
class ThreadPool
|
9
|
+
#--
|
10
|
+
# initialize
|
11
|
+
#++
|
12
|
+
# [size]
|
13
|
+
# Maximum size of worker threads.
|
14
|
+
# If the value is not positive, there is no limit.
|
15
|
+
def initialize(size)
|
16
|
+
@size = size
|
17
|
+
@queue = Queue.new
|
18
|
+
@workers = []
|
19
|
+
end
|
20
|
+
|
21
|
+
#--
|
22
|
+
# execute
|
23
|
+
#++
|
24
|
+
# Execute block on worker thread.
|
25
|
+
def execute(&block)
|
26
|
+
if (@size > 0)
|
27
|
+
while (@queue.size >= @size)
|
28
|
+
sleep(0.01)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
@queue.push(block)
|
33
|
+
|
34
|
+
if (@size <= 0) || (@workers.size < @size)
|
35
|
+
@workers << create_worker
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
#--
|
40
|
+
# shutdown
|
41
|
+
#++
|
42
|
+
# Wait for active worker threads.
|
43
|
+
def shutdown
|
44
|
+
until @queue.empty? && (@queue.num_waiting == @workers.size)
|
45
|
+
sleep(0.01)
|
46
|
+
end
|
47
|
+
|
48
|
+
@workers.each {|t| t.kill }
|
49
|
+
nil
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
|
54
|
+
#--
|
55
|
+
# create_worker
|
56
|
+
#++
|
57
|
+
# create worker thread.
|
58
|
+
def create_worker
|
59
|
+
Thread.new(@queue) do |q|
|
60
|
+
loop do
|
61
|
+
begin
|
62
|
+
q.pop.call
|
63
|
+
rescue Exception => e
|
64
|
+
$stderr.puts("#{e.backtrace[0]}: #{e.message} (#{e.class.name})")
|
65
|
+
e.backtrace[1..-1].each {|bt| $stderr.puts("\tfrom #{bt}") }
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
#--
|
73
|
+
# ThreadSafe
|
74
|
+
#++
|
75
|
+
# Class for thread safe.
|
76
|
+
class ThreadSafe
|
77
|
+
include MonitorMixin
|
78
|
+
@@thread_safe_instance_methods = []
|
79
|
+
|
80
|
+
private
|
81
|
+
|
82
|
+
def ThreadSafe.method_added(name)
|
83
|
+
fullname = "#{self}##{name}"
|
84
|
+
return if @@thread_safe_instance_methods.include?(fullname)
|
85
|
+
return unless public_method_defined?(name)
|
86
|
+
@@thread_safe_instance_methods << fullname
|
87
|
+
orig_method = instance_method(name)
|
88
|
+
undef_method(name)
|
89
|
+
|
90
|
+
define_method(name) do |*args|
|
91
|
+
synchronize { orig_method.bind(self).call(*args) }
|
92
|
+
end
|
93
|
+
|
94
|
+
public(name)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
data/lib/easysuite.rb
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
raise "REQUIREMENTS: Ruby 1.9.3 or later." if (RUBY_VERSION < '1.9.3')
|
2
|
+
require "easysuite/version"
|
3
|
+
require "easysuite/config"
|
4
|
+
require "easysuite/lock"
|
5
|
+
require "easysuite/logger"
|
6
|
+
require "easysuite/smtp"
|
7
|
+
require "easysuite/thread"
|
8
|
+
|
9
|
+
#--
|
10
|
+
# File
|
11
|
+
#++
|
12
|
+
# Redefine some methods.
|
13
|
+
class File
|
14
|
+
class << self
|
15
|
+
# Replace File::ALT_SEPARATOR to File::SEPARATOR.
|
16
|
+
if ALT_SEPARATOR
|
17
|
+
[:dirname, :join].each do |method|
|
18
|
+
orig_method = instance_method(method)
|
19
|
+
undef_method(method)
|
20
|
+
|
21
|
+
define_method(method) do |*args|
|
22
|
+
orig_method.bind(self).call(*args).gsub(ALT_SEPARATOR, SEPARATOR)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
#--
|
30
|
+
# UseEasyLogger
|
31
|
+
#++
|
32
|
+
# Module to use EasySuite::Logger#puts.
|
33
|
+
module UseEasyLogger
|
34
|
+
#--
|
35
|
+
# puts
|
36
|
+
#++
|
37
|
+
def puts(*args)
|
38
|
+
if @logger.kind_of?(EasySuite::Logger)
|
39
|
+
@logger.puts(*args) rescue nil
|
40
|
+
end
|
41
|
+
|
42
|
+
super
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
#--
|
47
|
+
# Enumerable
|
48
|
+
#++
|
49
|
+
# Add method.
|
50
|
+
module Enumerable
|
51
|
+
#--
|
52
|
+
# peach
|
53
|
+
#++
|
54
|
+
# Parallel each method.
|
55
|
+
# Each block is run on worker threads.
|
56
|
+
#
|
57
|
+
# [pool_size]
|
58
|
+
# Maximum size of worker threads.(default: 2)
|
59
|
+
# If the value is not positive, there is no limit.
|
60
|
+
def peach(pool_size = 2)
|
61
|
+
if block_given?
|
62
|
+
pool = EasySuite::ThreadPool.new(pool_size)
|
63
|
+
|
64
|
+
self.each do |args|
|
65
|
+
pool.execute { yield(args) }
|
66
|
+
end
|
67
|
+
|
68
|
+
pool.shutdown
|
69
|
+
else
|
70
|
+
self.each
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
data/sample/common.rb
ADDED
data/sample/easytools.rb
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'easysuite'
|
2
|
+
|
3
|
+
#
|
4
|
+
# Tools for EasySuite
|
5
|
+
#
|
6
|
+
module EasyTools
|
7
|
+
class << self
|
8
|
+
#
|
9
|
+
# get home directory path
|
10
|
+
#
|
11
|
+
def home_dir
|
12
|
+
@home_dir ||= File.expand_path("../..", __FILE__)
|
13
|
+
end
|
14
|
+
|
15
|
+
#
|
16
|
+
# create instance
|
17
|
+
#
|
18
|
+
def create(key)
|
19
|
+
case(key)
|
20
|
+
when :config
|
21
|
+
EasySuite::Config.new(EasyTools.config_dir)
|
22
|
+
when :lock
|
23
|
+
EasySuite::Lock.new(EasyTools.tmp_dir)
|
24
|
+
when :logger
|
25
|
+
EasySuite::Logger.new(EasyTools.log_dir, "%Y-%m-%d.log")
|
26
|
+
when :smtp
|
27
|
+
EasySuite::SMTP.new
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
#
|
32
|
+
# method_missing
|
33
|
+
#
|
34
|
+
def method_missing(name, *args)
|
35
|
+
# get sub directory path
|
36
|
+
if (name.to_s =~ /^(.+)_dir$/)
|
37
|
+
return File.join(self.home_dir, $1)
|
38
|
+
end
|
39
|
+
|
40
|
+
# default
|
41
|
+
super
|
42
|
+
end
|
43
|
+
|
44
|
+
#
|
45
|
+
# respond_to?
|
46
|
+
#
|
47
|
+
def respond_to?(name, include_private = false)
|
48
|
+
# get sub directory path
|
49
|
+
if (name.to_s =~ /^(.+)_dir$/)
|
50
|
+
return true
|
51
|
+
end
|
52
|
+
|
53
|
+
# default
|
54
|
+
super
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
data/sample/sample.rb
ADDED
metadata
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: easysuite
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.2.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Masafumi Kiribayashi
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2024-07-18 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description:
|
14
|
+
email:
|
15
|
+
executables:
|
16
|
+
- easysuite
|
17
|
+
extensions: []
|
18
|
+
extra_rdoc_files: []
|
19
|
+
files:
|
20
|
+
- LICENSE.txt
|
21
|
+
- exe/easysuite
|
22
|
+
- lib/easysuite.rb
|
23
|
+
- lib/easysuite/config.rb
|
24
|
+
- lib/easysuite/lock.rb
|
25
|
+
- lib/easysuite/logger.rb
|
26
|
+
- lib/easysuite/smtp.rb
|
27
|
+
- lib/easysuite/thread.rb
|
28
|
+
- lib/easysuite/version.rb
|
29
|
+
- sample/common.rb
|
30
|
+
- sample/easytools.rb
|
31
|
+
- sample/sample.rb
|
32
|
+
homepage:
|
33
|
+
licenses:
|
34
|
+
- MIT
|
35
|
+
metadata: {}
|
36
|
+
post_install_message:
|
37
|
+
rdoc_options: []
|
38
|
+
require_paths:
|
39
|
+
- lib
|
40
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
41
|
+
requirements:
|
42
|
+
- - ">="
|
43
|
+
- !ruby/object:Gem::Version
|
44
|
+
version: '0'
|
45
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
46
|
+
requirements:
|
47
|
+
- - ">="
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: '0'
|
50
|
+
requirements: []
|
51
|
+
rubygems_version: 3.3.26
|
52
|
+
signing_key:
|
53
|
+
specification_version: 4
|
54
|
+
summary: Programming for easygoing.
|
55
|
+
test_files: []
|