mini-clean-kit 0.0.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/mini-clean-kit.gemspec +12 -0
- data/spring-4.7.0/LICENSE.txt +23 -0
- data/spring-4.7.0/README.md +467 -0
- data/spring-4.7.0/bin/spring +49 -0
- data/spring-4.7.0/lib/spring/application/boot.rb +25 -0
- data/spring-4.7.0/lib/spring/application.rb +449 -0
- data/spring-4.7.0/lib/spring/application_manager.rb +145 -0
- data/spring-4.7.0/lib/spring/binstub.rb +13 -0
- data/spring-4.7.0/lib/spring/boot.rb +10 -0
- data/spring-4.7.0/lib/spring/client/binstub.rb +190 -0
- data/spring-4.7.0/lib/spring/client/command.rb +18 -0
- data/spring-4.7.0/lib/spring/client/help.rb +62 -0
- data/spring-4.7.0/lib/spring/client/rails.rb +34 -0
- data/spring-4.7.0/lib/spring/client/run.rb +297 -0
- data/spring-4.7.0/lib/spring/client/server.rb +18 -0
- data/spring-4.7.0/lib/spring/client/status.rb +30 -0
- data/spring-4.7.0/lib/spring/client/stop.rb +22 -0
- data/spring-4.7.0/lib/spring/client/version.rb +11 -0
- data/spring-4.7.0/lib/spring/client.rb +48 -0
- data/spring-4.7.0/lib/spring/command_wrapper.rb +82 -0
- data/spring-4.7.0/lib/spring/commands/rails.rb +112 -0
- data/spring-4.7.0/lib/spring/commands/rake.rb +30 -0
- data/spring-4.7.0/lib/spring/commands.rb +57 -0
- data/spring-4.7.0/lib/spring/configuration.rb +99 -0
- data/spring-4.7.0/lib/spring/env.rb +115 -0
- data/spring-4.7.0/lib/spring/errors.rb +36 -0
- data/spring-4.7.0/lib/spring/failsafe_thread.rb +14 -0
- data/spring-4.7.0/lib/spring/json.rb +623 -0
- data/spring-4.7.0/lib/spring/process_title_updater.rb +65 -0
- data/spring-4.7.0/lib/spring/server.rb +162 -0
- data/spring-4.7.0/lib/spring/version.rb +3 -0
- data/spring-4.7.0/lib/spring/watcher/abstract.rb +117 -0
- data/spring-4.7.0/lib/spring/watcher/polling.rb +98 -0
- data/spring-4.7.0/lib/spring/watcher.rb +30 -0
- metadata +75 -0
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
module Spring
|
|
2
|
+
ORIGINAL_ENV = ENV.to_hash
|
|
3
|
+
end
|
|
4
|
+
|
|
5
|
+
require "spring/boot"
|
|
6
|
+
require "spring/application_manager"
|
|
7
|
+
|
|
8
|
+
# Must be last, as it requires bundler/setup, which alters the load path
|
|
9
|
+
require "spring/commands"
|
|
10
|
+
|
|
11
|
+
module Spring
|
|
12
|
+
class Server
|
|
13
|
+
def self.boot(options = {})
|
|
14
|
+
new(options).boot
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
attr_reader :env
|
|
18
|
+
|
|
19
|
+
def initialize(options = {})
|
|
20
|
+
@foreground = options.fetch(:foreground, false)
|
|
21
|
+
@env = options[:env] || default_env
|
|
22
|
+
@applications = Hash.new do |hash, key|
|
|
23
|
+
hash[key] = ApplicationManager.new(*key, env)
|
|
24
|
+
end
|
|
25
|
+
@pidfile = env.pidfile_path.open('a')
|
|
26
|
+
@mutex = Mutex.new
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def foreground?
|
|
30
|
+
@foreground
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def log(message)
|
|
34
|
+
env.log "[server] #{message}"
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def boot
|
|
38
|
+
Spring.verify_environment
|
|
39
|
+
|
|
40
|
+
write_pidfile
|
|
41
|
+
set_pgid unless foreground?
|
|
42
|
+
ignore_signals unless foreground?
|
|
43
|
+
set_exit_hook
|
|
44
|
+
set_process_title
|
|
45
|
+
start_server
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def start_server
|
|
49
|
+
server = UNIXServer.open(env.socket_name)
|
|
50
|
+
log "started on #{env.socket_name}"
|
|
51
|
+
loop { serve server.accept }
|
|
52
|
+
rescue Interrupt
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def serve(client)
|
|
56
|
+
log "accepted client"
|
|
57
|
+
client.puts env.version
|
|
58
|
+
|
|
59
|
+
app_client = client.recv_io
|
|
60
|
+
command = JSON.load(client.read(client.gets.to_i))
|
|
61
|
+
|
|
62
|
+
args, default_rails_env, spawn_env, reset_env = command.values_at('args', 'default_rails_env', 'spawn_env', 'reset_env')
|
|
63
|
+
|
|
64
|
+
if Spring.command?(args.first)
|
|
65
|
+
application = @applications[rails_env_for(args, default_rails_env, spawn_env)]
|
|
66
|
+
reset_if_env_changed(application, reset_env)
|
|
67
|
+
|
|
68
|
+
log "running command #{args.first}"
|
|
69
|
+
client.puts
|
|
70
|
+
client.puts application.run(app_client)
|
|
71
|
+
else
|
|
72
|
+
log "command not found #{args.first}"
|
|
73
|
+
client.close
|
|
74
|
+
end
|
|
75
|
+
rescue SocketError => e
|
|
76
|
+
raise e unless client.eof?
|
|
77
|
+
rescue Errno::EPIPE => e
|
|
78
|
+
log "client disconnected with error #{e.message}, ignoring command"
|
|
79
|
+
ensure
|
|
80
|
+
redirect_output
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def rails_env_for(args, default_rails_env, spawn_env)
|
|
84
|
+
[Spring.command(args.first).env(args.drop(1)) || default_rails_env, spawn_env]
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
# Boot the server into the process group of the current session.
|
|
88
|
+
# This will cause it to be automatically killed once the session
|
|
89
|
+
# ends (i.e. when the user closes their terminal).
|
|
90
|
+
def set_pgid
|
|
91
|
+
pgid = Process.getpgid(Process.getsid)
|
|
92
|
+
Process.setpgid(0, pgid)
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
# Ignore SIGINT and SIGQUIT otherwise the user typing ^C or ^\ on the command line
|
|
96
|
+
# will kill the server/application.
|
|
97
|
+
def ignore_signals
|
|
98
|
+
IGNORE_SIGNALS.each { |sig| trap(sig, "IGNORE") }
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def set_exit_hook
|
|
102
|
+
server_pid = Process.pid
|
|
103
|
+
|
|
104
|
+
# We don't want this hook to run in any forks of the current process
|
|
105
|
+
at_exit { shutdown if Process.pid == server_pid }
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def shutdown
|
|
109
|
+
log "shutting down"
|
|
110
|
+
|
|
111
|
+
[env.socket_path, env.pidfile_path].each do |path|
|
|
112
|
+
if path.exist?
|
|
113
|
+
path.unlink rescue nil
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
@applications.values.map { |a| Spring.failsafe_thread { a.stop } }.map(&:join)
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def write_pidfile
|
|
121
|
+
if @pidfile.flock(File::LOCK_EX | File::LOCK_NB)
|
|
122
|
+
@pidfile.truncate(0)
|
|
123
|
+
@pidfile.write("#{Process.pid}\n")
|
|
124
|
+
@pidfile.fsync
|
|
125
|
+
else
|
|
126
|
+
exit 1
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
# We need to redirect STDOUT and STDERR, otherwise the server will
|
|
131
|
+
# keep the original FDs open which would break piping. (e.g.
|
|
132
|
+
# `spring rake -T | grep db` would hang forever because the server
|
|
133
|
+
# would keep the stdout FD open.)
|
|
134
|
+
def redirect_output
|
|
135
|
+
[STDOUT, STDERR].each { |stream| stream.reopen(env.log_file) }
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
def set_process_title
|
|
139
|
+
ProcessTitleUpdater.run { |distance|
|
|
140
|
+
"spring server | #{env.app_name} | started #{distance} ago"
|
|
141
|
+
}
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
private
|
|
145
|
+
|
|
146
|
+
def reset_if_env_changed(application, reset_env)
|
|
147
|
+
application.stop if ENV.slice(*reset_env.keys) != reset_env
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
def default_env
|
|
151
|
+
Env.new(log_file: default_log_file)
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
def default_log_file
|
|
155
|
+
if foreground? && !ENV["SPRING_LOG"]
|
|
156
|
+
$stdout
|
|
157
|
+
else
|
|
158
|
+
nil
|
|
159
|
+
end
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
end
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
require "pathname"
|
|
2
|
+
|
|
3
|
+
module Spring
|
|
4
|
+
module Watcher
|
|
5
|
+
# A user of a watcher can use IO.select to wait for changes:
|
|
6
|
+
#
|
|
7
|
+
# watcher = MyWatcher.new(root, latency)
|
|
8
|
+
# IO.select([watcher]) # watcher is running in background
|
|
9
|
+
# watcher.stale? # => true
|
|
10
|
+
class Abstract
|
|
11
|
+
attr_reader :files, :directories, :root, :latency
|
|
12
|
+
|
|
13
|
+
def initialize(root, latency)
|
|
14
|
+
@mutex = Mutex.new
|
|
15
|
+
@root = File.realpath(root)
|
|
16
|
+
@latency = latency
|
|
17
|
+
@files = {}
|
|
18
|
+
@directories = {}
|
|
19
|
+
@stale = false
|
|
20
|
+
@listeners = []
|
|
21
|
+
|
|
22
|
+
@on_debug = nil
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def synchronize(&block)
|
|
26
|
+
# Used by some gems.
|
|
27
|
+
@mutex.synchronize(&block)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def on_debug(&block)
|
|
31
|
+
@on_debug = block
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def debug
|
|
35
|
+
@on_debug.call(yield) if @on_debug
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def add(*items)
|
|
39
|
+
debug { "watcher: add: #{items.inspect}" }
|
|
40
|
+
|
|
41
|
+
items = items.flatten.map do |item|
|
|
42
|
+
item = Pathname.new(item)
|
|
43
|
+
|
|
44
|
+
if item.relative?
|
|
45
|
+
Pathname.new("#{root}/#{item}")
|
|
46
|
+
else
|
|
47
|
+
item
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
items = items.select do |item|
|
|
52
|
+
if item.symlink?
|
|
53
|
+
item.readlink.exist?.tap do |exists|
|
|
54
|
+
if !exists
|
|
55
|
+
debug { "add: ignoring dangling symlink: #{item.inspect} -> #{item.readlink.inspect}" }
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
else
|
|
59
|
+
item.exist?
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
@mutex.synchronize do
|
|
64
|
+
items.each do |item|
|
|
65
|
+
if item.directory?
|
|
66
|
+
directories[item.realpath.to_s] = true
|
|
67
|
+
else
|
|
68
|
+
begin
|
|
69
|
+
files[item.realpath.to_s] = true
|
|
70
|
+
rescue Errno::ENOENT
|
|
71
|
+
# Race condition. Ignore symlinks whose target was removed
|
|
72
|
+
# since the check above, or are deeply chained.
|
|
73
|
+
debug { "add: ignoring now-dangling symlink: #{item.inspect} -> #{item.readlink.inspect}" }
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
subjects_changed
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def stale?
|
|
83
|
+
@stale
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def on_stale(&block)
|
|
87
|
+
debug { "added listener: #{block.inspect}" }
|
|
88
|
+
@listeners << block
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def mark_stale
|
|
92
|
+
return if stale?
|
|
93
|
+
@stale = true
|
|
94
|
+
debug { "marked stale, calling listeners: listeners=#{@listeners.inspect}" }
|
|
95
|
+
@listeners.each(&:call)
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def restart
|
|
99
|
+
debug { "restarting" }
|
|
100
|
+
stop
|
|
101
|
+
start
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def start
|
|
105
|
+
raise NotImplementedError
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def stop
|
|
109
|
+
raise NotImplementedError
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def subjects_changed
|
|
113
|
+
raise NotImplementedError
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
end
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
require "spring/watcher/abstract"
|
|
2
|
+
|
|
3
|
+
module Spring
|
|
4
|
+
module Watcher
|
|
5
|
+
class Polling < Abstract
|
|
6
|
+
attr_reader :mtime
|
|
7
|
+
|
|
8
|
+
def initialize(root, latency)
|
|
9
|
+
super
|
|
10
|
+
@mtime = 0
|
|
11
|
+
@poller = nil
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def check_stale
|
|
15
|
+
@mutex.synchronize do
|
|
16
|
+
computed = compute_mtime
|
|
17
|
+
if mtime < computed
|
|
18
|
+
debug { "check_stale: mtime=#{mtime.inspect} < computed=#{computed.inspect}" }
|
|
19
|
+
mark_stale
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def add(*)
|
|
25
|
+
check_stale if @poller
|
|
26
|
+
super
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def start
|
|
30
|
+
debug { "start: poller=#{@poller.inspect}" }
|
|
31
|
+
unless @poller
|
|
32
|
+
@poller = Thread.new {
|
|
33
|
+
Thread.current.abort_on_exception = true
|
|
34
|
+
|
|
35
|
+
begin
|
|
36
|
+
until stale?
|
|
37
|
+
Kernel.sleep latency
|
|
38
|
+
check_stale
|
|
39
|
+
end
|
|
40
|
+
rescue Exception => e
|
|
41
|
+
debug do
|
|
42
|
+
"poller: aborted: #{e.class}: #{e}\n #{e.backtrace.join("\n ")}"
|
|
43
|
+
end
|
|
44
|
+
raise
|
|
45
|
+
ensure
|
|
46
|
+
@poller = nil
|
|
47
|
+
end
|
|
48
|
+
}
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def stop
|
|
53
|
+
debug { "stopping poller: #{@poller.inspect}" }
|
|
54
|
+
if @poller
|
|
55
|
+
@poller.kill
|
|
56
|
+
@poller = nil
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def running?
|
|
61
|
+
@poller && @poller.alive?
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def subjects_changed
|
|
65
|
+
computed = compute_mtime
|
|
66
|
+
debug { "subjects_changed: mtime #{@mtime} -> #{computed}" }
|
|
67
|
+
@mtime = computed
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
private
|
|
71
|
+
|
|
72
|
+
def compute_mtime
|
|
73
|
+
expanded_files.map do |f|
|
|
74
|
+
# Get the mtime of symlink targets. Ignore dangling symlinks.
|
|
75
|
+
if File.symlink?(f)
|
|
76
|
+
begin
|
|
77
|
+
File.mtime(f)
|
|
78
|
+
rescue Errno::ENOENT
|
|
79
|
+
0
|
|
80
|
+
end
|
|
81
|
+
# If a file no longer exists, treat it as changed.
|
|
82
|
+
else
|
|
83
|
+
begin
|
|
84
|
+
File.mtime(f)
|
|
85
|
+
rescue Errno::ENOENT
|
|
86
|
+
debug { "compute_mtime: no longer exists: #{f}" }
|
|
87
|
+
Float::MAX
|
|
88
|
+
end
|
|
89
|
+
end.to_f
|
|
90
|
+
end.max || 0
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def expanded_files
|
|
94
|
+
(files.keys + Dir["{#{directories.keys.map { |d| "#{d}/**/*" }.join(",")}}"]).uniq
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
require "spring/watcher/abstract"
|
|
2
|
+
require "spring/configuration"
|
|
3
|
+
|
|
4
|
+
module Spring
|
|
5
|
+
class << self
|
|
6
|
+
attr_accessor :watch_interval
|
|
7
|
+
attr_writer :watcher
|
|
8
|
+
attr_reader :watch_method
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def self.watch_method=(method)
|
|
12
|
+
if method.is_a?(Class)
|
|
13
|
+
@watch_method = method
|
|
14
|
+
else
|
|
15
|
+
require "spring/watcher/#{method}"
|
|
16
|
+
@watch_method = Watcher.const_get(method.to_s.gsub(/(^.|_.)/) { $1[-1].upcase })
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
self.watch_interval = 0.2
|
|
21
|
+
self.watch_method = :polling
|
|
22
|
+
|
|
23
|
+
def self.watcher
|
|
24
|
+
@watcher ||= watch_method.new(Spring.application_root_path, watch_interval)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def self.watch(*items)
|
|
28
|
+
watcher.add(*items)
|
|
29
|
+
end
|
|
30
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: mini-clean-kit
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.0.1
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Andrey78
|
|
8
|
+
bindir: bin
|
|
9
|
+
cert_chain: []
|
|
10
|
+
date: 2026-07-06 00:00:00.000000000 Z
|
|
11
|
+
dependencies: []
|
|
12
|
+
description: University research based on spring
|
|
13
|
+
email:
|
|
14
|
+
- cakoc614@gmail.com
|
|
15
|
+
executables: []
|
|
16
|
+
extensions: []
|
|
17
|
+
extra_rdoc_files: []
|
|
18
|
+
files:
|
|
19
|
+
- mini-clean-kit.gemspec
|
|
20
|
+
- spring-4.7.0/LICENSE.txt
|
|
21
|
+
- spring-4.7.0/README.md
|
|
22
|
+
- spring-4.7.0/bin/spring
|
|
23
|
+
- spring-4.7.0/lib/spring/application.rb
|
|
24
|
+
- spring-4.7.0/lib/spring/application/boot.rb
|
|
25
|
+
- spring-4.7.0/lib/spring/application_manager.rb
|
|
26
|
+
- spring-4.7.0/lib/spring/binstub.rb
|
|
27
|
+
- spring-4.7.0/lib/spring/boot.rb
|
|
28
|
+
- spring-4.7.0/lib/spring/client.rb
|
|
29
|
+
- spring-4.7.0/lib/spring/client/binstub.rb
|
|
30
|
+
- spring-4.7.0/lib/spring/client/command.rb
|
|
31
|
+
- spring-4.7.0/lib/spring/client/help.rb
|
|
32
|
+
- spring-4.7.0/lib/spring/client/rails.rb
|
|
33
|
+
- spring-4.7.0/lib/spring/client/run.rb
|
|
34
|
+
- spring-4.7.0/lib/spring/client/server.rb
|
|
35
|
+
- spring-4.7.0/lib/spring/client/status.rb
|
|
36
|
+
- spring-4.7.0/lib/spring/client/stop.rb
|
|
37
|
+
- spring-4.7.0/lib/spring/client/version.rb
|
|
38
|
+
- spring-4.7.0/lib/spring/command_wrapper.rb
|
|
39
|
+
- spring-4.7.0/lib/spring/commands.rb
|
|
40
|
+
- spring-4.7.0/lib/spring/commands/rails.rb
|
|
41
|
+
- spring-4.7.0/lib/spring/commands/rake.rb
|
|
42
|
+
- spring-4.7.0/lib/spring/configuration.rb
|
|
43
|
+
- spring-4.7.0/lib/spring/env.rb
|
|
44
|
+
- spring-4.7.0/lib/spring/errors.rb
|
|
45
|
+
- spring-4.7.0/lib/spring/failsafe_thread.rb
|
|
46
|
+
- spring-4.7.0/lib/spring/json.rb
|
|
47
|
+
- spring-4.7.0/lib/spring/process_title_updater.rb
|
|
48
|
+
- spring-4.7.0/lib/spring/server.rb
|
|
49
|
+
- spring-4.7.0/lib/spring/version.rb
|
|
50
|
+
- spring-4.7.0/lib/spring/watcher.rb
|
|
51
|
+
- spring-4.7.0/lib/spring/watcher/abstract.rb
|
|
52
|
+
- spring-4.7.0/lib/spring/watcher/polling.rb
|
|
53
|
+
homepage: https://rubygems.org/profiles/Andrey78
|
|
54
|
+
licenses:
|
|
55
|
+
- MIT
|
|
56
|
+
metadata:
|
|
57
|
+
source_code_uri: https://github.com/Andrey78/mini-clean-kit
|
|
58
|
+
rdoc_options: []
|
|
59
|
+
require_paths:
|
|
60
|
+
- lib
|
|
61
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
62
|
+
requirements:
|
|
63
|
+
- - ">="
|
|
64
|
+
- !ruby/object:Gem::Version
|
|
65
|
+
version: '0'
|
|
66
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
67
|
+
requirements:
|
|
68
|
+
- - ">="
|
|
69
|
+
- !ruby/object:Gem::Version
|
|
70
|
+
version: '0'
|
|
71
|
+
requirements: []
|
|
72
|
+
rubygems_version: 3.6.2
|
|
73
|
+
specification_version: 4
|
|
74
|
+
summary: Research test
|
|
75
|
+
test_files: []
|