hotdog 0.6.3 → 0.6.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/lib/hotdog/application.rb +40 -38
- data/lib/hotdog/commands/help.rb +23 -2
- data/lib/hotdog/commands/pssh.rb +10 -115
- data/lib/hotdog/commands/search.rb +1 -5
- data/lib/hotdog/commands/ssh.rb +144 -55
- data/lib/hotdog/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f1b8937e6ed17779e09622476dae786c9f7e04a4
|
4
|
+
data.tar.gz: 59d5cf9204f2b3cf7a272734ca62253f09b01347
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c763c88d2083cb10007195b7962edd980a47f0145a613081b1a5c9713da91ffed3350daa7bdd1317f7e9d00b928141f69a5005e6fa2026deb127a6e6a1b71173
|
7
|
+
data.tar.gz: 796c96d4b2c954690fc9bbf97339d8ebe4213fc7c3c92fafc5c5a67b90914c208ad4eea7c3a2b21f5c871dc4562c002ff561b443321d949c24038b3491743caf
|
data/lib/hotdog/application.rb
CHANGED
@@ -53,44 +53,47 @@ module Hotdog
|
|
53
53
|
args = @optparse.order(argv)
|
54
54
|
|
55
55
|
begin
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
end
|
64
|
-
|
65
|
-
unless options[:application_key]
|
66
|
-
raise("DATADOG_APPLICATION_KEY is not set")
|
67
|
-
end
|
68
|
-
|
69
|
-
if options[:format] == "ltsv"
|
70
|
-
options[:headers] = true
|
71
|
-
end
|
72
|
-
|
73
|
-
options[:formatter] = get_formatter(options[:format])
|
74
|
-
|
75
|
-
if options[:debug] or options[:verbose]
|
76
|
-
options[:logger].level = Logger::DEBUG
|
77
|
-
else
|
78
|
-
options[:logger].level = Logger::INFO
|
79
|
-
end
|
80
|
-
|
81
|
-
cmd.run(args, @options)
|
56
|
+
command_name = ( args.shift || "help" )
|
57
|
+
begin
|
58
|
+
command = get_command(command_name)
|
59
|
+
rescue NameError
|
60
|
+
STDERR.puts("hotdog: '#{command_name}' is not a hotdog command.")
|
61
|
+
get_command("help").parse_options(@optparse, ["commands"])
|
62
|
+
exit(1)
|
82
63
|
end
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
64
|
+
|
65
|
+
@optparse.banner = "Usage: hotdog #{command_name} [options]"
|
66
|
+
command.define_options(@optparse, @options)
|
67
|
+
|
68
|
+
begin
|
69
|
+
args = command.parse_options(@optparse, args)
|
70
|
+
rescue OptionParser::ParseError => error
|
71
|
+
STDERR.puts("hotdog: #{error.message}")
|
72
|
+
command.parse_options(@optparse, ["--help"])
|
73
|
+
exit(1)
|
74
|
+
end
|
75
|
+
|
76
|
+
unless options[:api_key]
|
77
|
+
raise("DATADOG_API_KEY is not set")
|
92
78
|
end
|
93
|
-
|
79
|
+
|
80
|
+
unless options[:application_key]
|
81
|
+
raise("DATADOG_APPLICATION_KEY is not set")
|
82
|
+
end
|
83
|
+
|
84
|
+
if options[:format] == "ltsv"
|
85
|
+
options[:headers] = true
|
86
|
+
end
|
87
|
+
|
88
|
+
options[:formatter] = get_formatter(options[:format])
|
89
|
+
|
90
|
+
if options[:debug] or options[:verbose]
|
91
|
+
options[:logger].level = Logger::DEBUG
|
92
|
+
else
|
93
|
+
options[:logger].level = Logger::INFO
|
94
|
+
end
|
95
|
+
|
96
|
+
command.run(args, @options)
|
94
97
|
rescue Errno::EPIPE
|
95
98
|
# nop
|
96
99
|
end
|
@@ -174,8 +177,7 @@ module Hotdog
|
|
174
177
|
load library
|
175
178
|
klass = Hotdog::Commands.const_get(const_name(File.basename(library, ".rb")))
|
176
179
|
else
|
177
|
-
|
178
|
-
klass = Hotdog::Commands::Help
|
180
|
+
raise(NameError.new("unknown command: #{name}"))
|
179
181
|
end
|
180
182
|
end
|
181
183
|
klass.new(self)
|
data/lib/hotdog/commands/help.rb
CHANGED
@@ -6,8 +6,29 @@ module Hotdog
|
|
6
6
|
module Commands
|
7
7
|
class Help < BaseCommand
|
8
8
|
def run(args=[], options={})
|
9
|
-
|
10
|
-
|
9
|
+
commands = command_files.map { |file| File.basename(file, ".rb") }.sort.uniq
|
10
|
+
if "commands" == args.first
|
11
|
+
STDOUT.puts("hotdog commands are:")
|
12
|
+
commands.each do |command|
|
13
|
+
STDOUT.puts("- #{command}")
|
14
|
+
end
|
15
|
+
else
|
16
|
+
ruby = File.join(RbConfig::CONFIG["bindir"], RbConfig::CONFIG["ruby_install_name"])
|
17
|
+
if commands.include?(args.first)
|
18
|
+
exit(system(ruby, $0, args.first, "--help") ? 0 : 1)
|
19
|
+
else
|
20
|
+
exit(system(ruby, $0, "--help") ? 0 : 1)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
def load_path()
|
27
|
+
$LOAD_PATH.map { |path| File.join(path, "hotdog/commands") }.select { |path| File.directory?(path) }
|
28
|
+
end
|
29
|
+
|
30
|
+
def command_files()
|
31
|
+
load_path.flat_map { |path| Dir.glob(File.join(path, "*.rb")) }.select { |file| File.file?(file) }
|
11
32
|
end
|
12
33
|
end
|
13
34
|
end
|
data/lib/hotdog/commands/pssh.rb
CHANGED
@@ -1,130 +1,25 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
3
|
require "json"
|
4
|
+
require "parallel"
|
4
5
|
require "parslet"
|
5
|
-
require "hotdog/commands/search"
|
6
6
|
require "shellwords"
|
7
|
-
require "
|
7
|
+
require "hotdog/commands/ssh"
|
8
8
|
|
9
9
|
module Hotdog
|
10
10
|
module Commands
|
11
|
-
class Pssh <
|
12
|
-
def define_options(optparse, options={})
|
13
|
-
options[:options] = []
|
14
|
-
options[:user] = nil
|
15
|
-
options[:port] = nil
|
16
|
-
options[:identity_file] = nil
|
17
|
-
options[:forward_agent] = false
|
18
|
-
options[:max_parallelism] = nil
|
19
|
-
options[:color] = :auto
|
20
|
-
|
21
|
-
optparse.on("-o SSH_OPTION", "Passes this string to ssh command through shell. This option may be given multiple times") do |option|
|
22
|
-
options[:options] += [option]
|
23
|
-
end
|
24
|
-
optparse.on("-i SSH_IDENTITY_FILE", "SSH identity file path") do |path|
|
25
|
-
options[:identity_file] = path
|
26
|
-
end
|
27
|
-
optparse.on("-A", "Enable agent forwarding", TrueClass) do |b|
|
28
|
-
options[:forward_agent] = b
|
29
|
-
end
|
30
|
-
optparse.on("-p PORT", "Port of the remote host", Integer) do |port|
|
31
|
-
options[:port] = port
|
32
|
-
end
|
33
|
-
optparse.on("-u SSH_USER", "SSH login user name") do |user|
|
34
|
-
options[:user] = user
|
35
|
-
end
|
36
|
-
optparse.on("-P PARALLELISM", "Max parallelism", Integer) do |n|
|
37
|
-
options[:max_parallelism] = n
|
38
|
-
end
|
39
|
-
optparse.on("-v", "--verbose", "Enable verbose ode") do |v|
|
40
|
-
options[:verbose] = v
|
41
|
-
end
|
42
|
-
optparse.on("--color=WHEN", "--colour=WHEN", "Enable colors") do |color|
|
43
|
-
options[:color] = color
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
def run(args=[], options={})
|
48
|
-
expression = args.join(" ").strip
|
49
|
-
if expression.empty?
|
50
|
-
# return everything if given expression is empty
|
51
|
-
expression = "*"
|
52
|
-
end
|
53
|
-
|
54
|
-
begin
|
55
|
-
node = parse(expression)
|
56
|
-
rescue Parslet::ParseFailed => error
|
57
|
-
STDERR.puts("syntax error: " + error.cause.ascii_tree)
|
58
|
-
exit(1)
|
59
|
-
end
|
60
|
-
|
61
|
-
result0 = evaluate(node, self)
|
62
|
-
if 0 < result0.length
|
63
|
-
exec_command(result0, options)
|
64
|
-
else
|
65
|
-
STDERR.puts("no match found: #{expression}")
|
66
|
-
exit(1)
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
11
|
+
class Pssh < SshAlike
|
70
12
|
private
|
71
|
-
def
|
72
|
-
result, fields = get_hosts(result0)
|
73
|
-
hosts = result.flatten
|
74
|
-
threads = options[:max_parallelism] || hosts.size
|
13
|
+
def run_main(hosts, options={})
|
75
14
|
use_color_p = use_color?
|
76
|
-
stats = Parallel.map(hosts
|
77
|
-
cmdline = build_command_string(host, options)
|
78
|
-
|
79
|
-
IO.popen(cmdline, in: :close, err: [:child, :out]) do |io|
|
80
|
-
io.each_with_index do |s, i|
|
81
|
-
STDOUT.write("\e[0;36m") if use_color_p
|
82
|
-
STDOUT.write("#{name}:#{i}:")
|
83
|
-
STDOUT.write("\e[0m") if use_color_p
|
84
|
-
STDOUT.write(s)
|
85
|
-
end
|
86
|
-
end
|
87
|
-
$?.success? # $? is thread-local variable
|
15
|
+
stats = Parallel.map(hosts, in_threads: parallelism(hosts)) { |host|
|
16
|
+
cmdline = build_command_string(host, @remote_command, options)
|
17
|
+
exec_command(host, cmdline, true, use_color_p)
|
88
18
|
}
|
89
|
-
|
90
|
-
exit(
|
91
|
-
end
|
92
|
-
end
|
93
|
-
|
94
|
-
def build_command_string(host, options={})
|
95
|
-
# build ssh command
|
96
|
-
base_cmdline = ["ssh"]
|
97
|
-
if options[:forward_agent]
|
98
|
-
base_cmdline << "-A"
|
99
|
-
end
|
100
|
-
if options[:identity_file]
|
101
|
-
base_cmdline << "-i" << options[:identity_file]
|
102
|
-
end
|
103
|
-
if options[:user]
|
104
|
-
base_cmdline << "-l" << options[:user]
|
105
|
-
end
|
106
|
-
base_cmdline << "-o" << "BatchMode=yes"
|
107
|
-
if options[:options]
|
108
|
-
base_cmdline += options[:options].flat_map { |option| ["-o", option] }
|
109
|
-
end
|
110
|
-
if options[:port]
|
111
|
-
base_cmdline << "-p" << options[:port].to_s
|
112
|
-
end
|
113
|
-
cmdline = base_cmdline + [host]
|
114
|
-
if @remote_command
|
115
|
-
cmdline << "--" << @remote_command
|
116
|
-
end
|
117
|
-
Shellwords.join(cmdline)
|
118
|
-
end
|
119
|
-
|
120
|
-
def use_color?
|
121
|
-
case options[:color]
|
122
|
-
when :always
|
123
|
-
true
|
124
|
-
when :never
|
125
|
-
false
|
19
|
+
if stats.all?
|
20
|
+
exit(0)
|
126
21
|
else
|
127
|
-
|
22
|
+
exit(1)
|
128
23
|
end
|
129
24
|
end
|
130
25
|
end
|
@@ -742,11 +742,7 @@ module Hotdog
|
|
742
742
|
def evaluate(environment, options={})
|
743
743
|
values = environment.execute(@query, @values).map { |row| row.first }
|
744
744
|
if values.empty? and @fallback
|
745
|
-
@fallback.evaluate(environment, options)
|
746
|
-
if values.empty?
|
747
|
-
environment.logger.info("no result: #{self.dump.inspect}")
|
748
|
-
end
|
749
|
-
end
|
745
|
+
@fallback.evaluate(environment, options)
|
750
746
|
else
|
751
747
|
values
|
752
748
|
end
|
data/lib/hotdog/commands/ssh.rb
CHANGED
@@ -2,29 +2,21 @@
|
|
2
2
|
|
3
3
|
require "json"
|
4
4
|
require "parslet"
|
5
|
-
require "hotdog/commands/search"
|
6
5
|
require "shellwords"
|
6
|
+
require "hotdog/commands/search"
|
7
7
|
|
8
8
|
module Hotdog
|
9
9
|
module Commands
|
10
|
-
class
|
10
|
+
class SshAlike < Search
|
11
11
|
def define_options(optparse, options={})
|
12
|
-
options[:index] = nil
|
13
12
|
options[:options] = []
|
14
13
|
options[:user] = nil
|
15
14
|
options[:port] = nil
|
16
15
|
options[:identity_file] = nil
|
17
16
|
options[:forward_agent] = false
|
17
|
+
options[:color] = :auto
|
18
|
+
options[:max_parallelism] = nil
|
18
19
|
|
19
|
-
optparse.on("-D BIND_ADDRESS", "Specifies a local \"dynamic\" application-level port forwarding") do |bind_address|
|
20
|
-
options[:dynamic_port_forward] = bind_address
|
21
|
-
end
|
22
|
-
optparse.on("-L BIND_ADDRESS", "Specifies that the given port on the local (client) host is to be forwarded to the given host and port on the remote side") do |bind_address|
|
23
|
-
options[:port_forward] = bind_address
|
24
|
-
end
|
25
|
-
optparse.on("-n", "--index INDEX", "Use this index of host if multiple servers are found", Integer) do |index|
|
26
|
-
options[:index] = index
|
27
|
-
end
|
28
20
|
optparse.on("-o SSH_OPTION", "Passes this string to ssh command through shell. This option may be given multiple times") do |option|
|
29
21
|
options[:options] += [option]
|
30
22
|
end
|
@@ -43,6 +35,15 @@ module Hotdog
|
|
43
35
|
optparse.on("-v", "--verbose", "Enable verbose ode") do |v|
|
44
36
|
options[:verbose] = v
|
45
37
|
end
|
38
|
+
optparse.on("--filter=COMMAND", "Command to filter search result.") do |command|
|
39
|
+
options[:filter_command] = command
|
40
|
+
end
|
41
|
+
optparse.on("-P PARALLELISM", "Max parallelism", Integer) do |n|
|
42
|
+
options[:max_parallelism] = n
|
43
|
+
end
|
44
|
+
optparse.on("--color=WHEN", "--colour=WHEN", "Enable colors") do |color|
|
45
|
+
options[:color] = color
|
46
|
+
end
|
46
47
|
end
|
47
48
|
|
48
49
|
def run(args=[], options={})
|
@@ -60,73 +61,161 @@ module Hotdog
|
|
60
61
|
end
|
61
62
|
|
62
63
|
result0 = evaluate(node, self)
|
63
|
-
|
64
|
-
|
65
|
-
|
64
|
+
result, fields = get_hosts_with_search_tags(result0, node)
|
65
|
+
hosts = filter_hosts(result.flatten)
|
66
|
+
validate_hosts!(hosts)
|
67
|
+
run_main(hosts, options)
|
68
|
+
end
|
69
|
+
|
70
|
+
private
|
71
|
+
def parallelism(hosts)
|
72
|
+
options[:max_parallelism] || hosts.size
|
73
|
+
end
|
74
|
+
|
75
|
+
def filter_hosts(hosts)
|
76
|
+
if options[:filter_command]
|
77
|
+
use_color_p = use_color?
|
78
|
+
filtered_hosts = Parallel.map(hosts, in_threads: parallelism(hosts)) { |host|
|
79
|
+
cmdline = build_command_string(host, options[:filter_command], options)
|
80
|
+
[host, exec_command(host, cmdline, false, use_color_p)]
|
81
|
+
}.select { |host, stat|
|
82
|
+
stat
|
83
|
+
}.map { |host, stat|
|
84
|
+
host
|
85
|
+
}
|
86
|
+
if hosts == filtered_hosts
|
87
|
+
hosts
|
66
88
|
else
|
67
|
-
|
68
|
-
|
69
|
-
else
|
70
|
-
result, fields = get_hosts_with_search_tags(result0, node)
|
71
|
-
|
72
|
-
# add "index" field
|
73
|
-
result = result.each_with_index.map { |host, i| [i] + host }
|
74
|
-
fields = ["index"] + fields
|
75
|
-
|
76
|
-
STDERR.print(format(result, fields: fields))
|
77
|
-
logger.info("found %d host(s)." % result.length)
|
78
|
-
exit(1)
|
79
|
-
end
|
89
|
+
logger.info("filtered host(s): #{(hosts - filtered_hosts).inspect}")
|
90
|
+
filtered_hosts
|
80
91
|
end
|
81
92
|
else
|
82
|
-
|
93
|
+
hosts
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def validate_hosts!(hosts)
|
98
|
+
if hosts.length < 1
|
99
|
+
STDERR.puts("no match found")
|
83
100
|
exit(1)
|
84
101
|
end
|
85
|
-
exit(127)
|
86
102
|
end
|
87
103
|
|
88
|
-
|
89
|
-
|
90
|
-
result, fields = get_hosts(result0)
|
91
|
-
hosts = result.flatten
|
92
|
-
cmdline = build_command_string(hosts.first, options)
|
93
|
-
logger.debug("execute: #{cmdline}")
|
94
|
-
exec(cmdline)
|
104
|
+
def run_main(hosts, options={})
|
105
|
+
raise(NotImplementedError)
|
95
106
|
end
|
96
107
|
|
97
|
-
def
|
98
|
-
|
99
|
-
base_cmdline = ["ssh"]
|
108
|
+
def build_command_options(options={})
|
109
|
+
cmdline = []
|
100
110
|
if options[:forward_agent]
|
101
|
-
|
102
|
-
end
|
103
|
-
if options[:dynamic_port_forward]
|
104
|
-
base_cmdline << "-D" << options[:dynamic_port_forward]
|
105
|
-
end
|
106
|
-
if options[:port_forward]
|
107
|
-
base_cmdline << "-L" << options[:port_forward]
|
111
|
+
cmdline << "-A"
|
108
112
|
end
|
109
113
|
if options[:identity_file]
|
110
|
-
|
114
|
+
cmdline << "-i" << options[:identity_file]
|
111
115
|
end
|
112
116
|
if options[:user]
|
113
|
-
|
117
|
+
cmdline << "-l" << options[:user]
|
114
118
|
end
|
115
119
|
if options[:options]
|
116
|
-
|
120
|
+
cmdline += options[:options].flat_map { |option| ["-o", option] }
|
117
121
|
end
|
118
122
|
if options[:port]
|
119
|
-
|
123
|
+
cmdline << "-p" << options[:port].to_s
|
120
124
|
end
|
121
125
|
if options[:verbose]
|
122
|
-
|
126
|
+
cmdline << "-v"
|
123
127
|
end
|
124
|
-
cmdline
|
125
|
-
|
126
|
-
|
128
|
+
cmdline
|
129
|
+
end
|
130
|
+
|
131
|
+
def build_command_string(host, command=nil, options={})
|
132
|
+
# build ssh command
|
133
|
+
cmdline = ["ssh"] + build_command_options(options) + [host]
|
134
|
+
if command
|
135
|
+
cmdline << "--" << command
|
127
136
|
end
|
128
137
|
Shellwords.join(cmdline)
|
129
138
|
end
|
139
|
+
|
140
|
+
def use_color?
|
141
|
+
case options[:color]
|
142
|
+
when :always
|
143
|
+
true
|
144
|
+
when :never
|
145
|
+
false
|
146
|
+
else
|
147
|
+
STDOUT.tty?
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
def exec_command(identifier, cmdline, output=true, colorize=false)
|
152
|
+
logger.debug("execute: #{cmdline}")
|
153
|
+
IO.popen(cmdline, in: :close, err: [:child, :out]) do |io|
|
154
|
+
io.each_with_index do |s, i|
|
155
|
+
if output
|
156
|
+
STDOUT.write("\e[0;36m") if colorize
|
157
|
+
STDOUT.write("#{identifier}:#{i}:")
|
158
|
+
STDOUT.write("\e[0m") if colorize
|
159
|
+
STDOUT.write(s)
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
163
|
+
$?.success? # $? is thread-local variable
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
class Ssh < SshAlike
|
168
|
+
def define_options(optparse, options={})
|
169
|
+
super
|
170
|
+
options[:index] = nil
|
171
|
+
optparse.on("-D BIND_ADDRESS", "Specifies a local \"dynamic\" application-level port forwarding") do |bind_address|
|
172
|
+
options[:dynamic_port_forward] = bind_address
|
173
|
+
end
|
174
|
+
optparse.on("-L BIND_ADDRESS", "Specifies that the given port on the local (client) host is to be forwarded to the given host and port on the remote side") do |bind_address|
|
175
|
+
options[:port_forward] = bind_address
|
176
|
+
end
|
177
|
+
optparse.on("-n", "--index INDEX", "Use this index of host if multiple servers are found", Integer) do |index|
|
178
|
+
options[:index] = index
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
private
|
183
|
+
def filter_hosts(hosts)
|
184
|
+
hosts = super
|
185
|
+
if options[:index] and options[:index] < hosts.length
|
186
|
+
[hosts[options[:index]]]
|
187
|
+
else
|
188
|
+
hosts
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
def validate_hosts!(hosts)
|
193
|
+
super
|
194
|
+
if hosts.length != 1
|
195
|
+
result = hosts.each_with_index.map { |host, i| [i, host] }
|
196
|
+
STDERR.print(format(result, fields: ["index", "host"]))
|
197
|
+
logger.error("found %d hosts." % result.length)
|
198
|
+
exit(1)
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
def run_main(hosts, options={})
|
203
|
+
cmdline = build_command_string(hosts.first, @remote_command, options)
|
204
|
+
logger.debug("execute: #{cmdline}")
|
205
|
+
exec(cmdline)
|
206
|
+
exit(127)
|
207
|
+
end
|
208
|
+
|
209
|
+
def build_command_options(options={})
|
210
|
+
arguments = super
|
211
|
+
if options[:dynamic_port_forward]
|
212
|
+
arguments << "-D" << options[:dynamic_port_forward]
|
213
|
+
end
|
214
|
+
if options[:port_forward]
|
215
|
+
arguments << "-L" << options[:port_forward]
|
216
|
+
end
|
217
|
+
arguments
|
218
|
+
end
|
130
219
|
end
|
131
220
|
end
|
132
221
|
end
|
data/lib/hotdog/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hotdog
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.6.
|
4
|
+
version: 0.6.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Yamashita Yuu
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-10-
|
11
|
+
date: 2015-10-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|