sidekiq_adhoc_job 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: cbb78def72673141d39f88a5cdd7b3142da526620ce4ec42829cac57cc35f398
4
+ data.tar.gz: ae4d22cb3bcaeef550515011c282368bd6f6ccb75b93a9b6fc397af87cdd9662
5
+ SHA512:
6
+ metadata.gz: 50288dad7f7287ceed184e0327febe69b26eccf994a81f335819aa6b15bc9c8c300e7da3c373dce6ea3de3beb5b4cabf0539c25765dab3659cda63041d97cb9e
7
+ data.tar.gz: e6f3e09e7c731034059bfc6085219a20c401385d65b52fd57d659ab739a0d6d4c41d8a1fd330d47256ebb62b9d5e7c841711383897ed36db0ebfc6ed8988b541
@@ -0,0 +1,32 @@
1
+ module SidekiqAdhocJob
2
+ class ScheduleAdhocJob
3
+
4
+ StringUtil ||= ::SidekiqAdhocJob::Utils::String
5
+
6
+ def initialize(job_name, request_params)
7
+ @request_params = request_params.inject({}) do |acc, (k, v)|
8
+ acc[k.to_sym] = v
9
+ acc
10
+ end
11
+ @worker_klass = WorkerClassesLoader.find_worker_klass(job_name)
12
+ parse_params
13
+ end
14
+
15
+ def call
16
+ worker_klass.perform_async(*worker_params)
17
+ end
18
+
19
+ private
20
+
21
+ attr_reader :request_params, :worker_klass, :allowed_params, :worker_params
22
+
23
+ def parse_params
24
+ @allowed_params = worker_klass.new.method(:perform).parameters.reject { |type, _| type == :rest }.flat_map(&:last)
25
+ @worker_params = allowed_params.map { |key| StringUtil.parse(request_params[key]) }
26
+ if !!request_params[:rest_args] && !request_params[:rest_args].empty?
27
+ @worker_params += request_params[:rest_args].split(',').map { |arg| StringUtil.parse(arg.strip) }
28
+ end
29
+ end
30
+
31
+ end
32
+ end
@@ -0,0 +1,108 @@
1
+ # References: https://github.com/hanami/utils/blob/master/lib/hanami/utils/string.rb
2
+ module SidekiqAdhocJob
3
+ module Utils
4
+ class String
5
+
6
+ EMPTY_STRING ||= ''.freeze
7
+ CLASSIFY_SEPARATOR ||= '_'.freeze
8
+ NAMESPACE_SEPARATOR ||= '::'.freeze
9
+ UNDERSCORE_SEPARATOR ||= '/'.freeze
10
+ UNDERSCORE_DIVISION_TARGET ||= '\1_\2'.freeze
11
+ DASHERIZE_SEPARATOR ||= '-'.freeze
12
+ CLASSIFY_WORD_SEPARATOR ||= /#{CLASSIFY_SEPARATOR}|#{NAMESPACE_SEPARATOR}|#{UNDERSCORE_SEPARATOR}|#{DASHERIZE_SEPARATOR}/.freeze
13
+
14
+ # Return a CamelCase version of the string
15
+ # If the given string is a file name, it will convert each file directory into a CamelCase namespace
16
+ #
17
+ # @see https://github.com/hanami/utils/blob/92ef4464f7ae3e5acba4b8fadc1c8225a81b9b76/lib/hanami/utils/string.rb#L223
18
+ #
19
+ # @param input [::String] the input
20
+ #
21
+ # @return [::String] the transformed string
22
+ #
23
+ # @since 0.1.0
24
+ #
25
+ # @example
26
+ # require 'sidekiq_adhoc_job/utils/string'
27
+ #
28
+ # SidekiqAdhocJob::Utils::String.classify('sidekiq_adhoc_job') # => 'SidekiqAdhocJob'
29
+ # SidekiqAdhocJob::Utils::String.classify('sidekiq_adhoc_job/utils/string') # => 'SidekiqAdhocJob::Utils::String'
30
+ def self.classify(input)
31
+ string = ::String.new(input.to_s)
32
+ words = underscore(string).split(CLASSIFY_WORD_SEPARATOR).map!(&:capitalize)
33
+ delimiters = underscore(string).scan(CLASSIFY_WORD_SEPARATOR)
34
+
35
+ delimiters.map! do |delimiter|
36
+ delimiter == CLASSIFY_SEPARATOR ? EMPTY_STRING : NAMESPACE_SEPARATOR
37
+ end
38
+
39
+ words.zip(delimiters).join
40
+ end
41
+
42
+ # Return a downcased and underscore separated version of the string
43
+ # If the given string is a namespaced class name, it will convert the namespace separator :: into a file path separator /
44
+ #
45
+ # @see https://github.com/hanami/utils/blob/92ef4464f7ae3e5acba4b8fadc1c8225a81b9b76/lib/hanami/utils/string.rb#L250
46
+ #
47
+ # @param input [::String] the input
48
+ #
49
+ # @return [::String] the transformed string
50
+ #
51
+ # @since 0.1.0
52
+ #
53
+ # @example
54
+ # require 'sidekiq_adhoc_job/utils/string'
55
+ #
56
+ # SidekiqAdhocJob::Utils::String.underscore('SidekiqAdhocJob') # => 'sidekiq_adhoc_job'
57
+ # SidekiqAdhocJob::Utils::String.underscore('SidekiqAdhocJob::Utils::String') # => 'sidekiq_adhoc_job/utils/string'
58
+ def self.underscore(input)
59
+ string = ::String.new(input.to_s)
60
+ string.gsub!(NAMESPACE_SEPARATOR, UNDERSCORE_SEPARATOR)
61
+ string.gsub!(/([A-Z\d]+)([A-Z][a-z])/, UNDERSCORE_DIVISION_TARGET)
62
+ string.gsub!(/([a-z\d])([A-Z])/, UNDERSCORE_DIVISION_TARGET)
63
+ string.gsub!(/[[:space:]]|\-/, UNDERSCORE_DIVISION_TARGET)
64
+ string.downcase
65
+ end
66
+
67
+ def self.constantize(input)
68
+ names = input.split('::')
69
+ names.shift if names.empty? || names.first.empty?
70
+
71
+ constant = Object
72
+ names.each do |name|
73
+ constant = constant.const_defined?(name) ? constant.const_get(name) : constant.const_missing(name)
74
+ end
75
+ constant
76
+ end
77
+
78
+ def self.parse(input)
79
+ return unless input
80
+
81
+ if input == 'true'
82
+ true
83
+ elsif input == 'false'
84
+ false
85
+ elsif (i = parse_integer(input))
86
+ i
87
+ elsif (f = parse_float(input))
88
+ f
89
+ else
90
+ input
91
+ end
92
+ end
93
+
94
+ def self.parse_integer(input)
95
+ Integer(input)
96
+ rescue ArgumentError => _e
97
+ nil
98
+ end
99
+
100
+ def self.parse_float(input)
101
+ Float(input)
102
+ rescue ArgumentError => _e
103
+ nil
104
+ end
105
+
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,3 @@
1
+ module SidekiqAdhocJob
2
+ VERSION = '0.1.2'.freeze
3
+ end
@@ -0,0 +1,56 @@
1
+ # References: https://github.com/moove-it/sidekiq-scheduler/blob/master/lib/sidekiq-scheduler/job_presenter.rb
2
+ module SidekiqAdhocJob
3
+ module Web
4
+ class JobPresenter
5
+ include Sidekiq::WebHelpers
6
+
7
+ attr_reader :name, :path_name, :queue, :required_args, :optional_args, :has_rest_args, :args
8
+
9
+ StringUtil ||= ::SidekiqAdhocJob::Utils::String
10
+
11
+ # args: { req: [], opt: [] }
12
+ def initialize(name, path_name, queue, args)
13
+ @name = name
14
+ @path_name = path_name
15
+ @queue = queue
16
+ @required_args = args[:req] || []
17
+ @optional_args = args[:opt] || []
18
+ @has_rest_args = !!args[:rest]
19
+ @args = @required_args + @optional_args
20
+ end
21
+
22
+ # Builds the presenter instances for the schedule hash
23
+ #
24
+ # @param
25
+ # @return [Array<JobPresenter>] an array with the instances of presenters
26
+ def self.build_collection
27
+ WorkerClassesLoader.worker_klasses.map do |path_name, worker_klass|
28
+ convert_klass_name_to_presenter(path_name, worker_klass)
29
+ end
30
+ end
31
+
32
+ def self.find(path_name)
33
+ klass_name = WorkerClassesLoader.find_worker_klass(path_name)
34
+
35
+ return unless klass_name
36
+
37
+ convert_klass_name_to_presenter(path_name, klass_name)
38
+ end
39
+
40
+ def self.convert_klass_name_to_presenter(path_name, klass_name)
41
+ klass_obj = klass_name.new
42
+ queue = klass_name.sidekiq_options['queue']
43
+ args = klass_obj
44
+ .method(:perform)
45
+ .parameters
46
+ .group_by { |type, _| type }
47
+ .inject({}) do |acc, (type, params)|
48
+ acc[type] = params.map(&:last)
49
+ acc
50
+ end
51
+ new(klass_name, path_name, queue, args)
52
+ end
53
+
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,11 @@
1
+ en:
2
+ adhoc_jobs: Adhoc Jobs
3
+ adhoc_jobs_actions: Actions
4
+ adhoc_jobs_go_back: Go Back
5
+ adhoc_jobs_has_rest_arguments: Has Rest Arguments
6
+ adhoc_jobs_name: Job Name
7
+ adhoc_jobs_optional_arguments: Optional Arguments
8
+ adhoc_jobs_queue: Job Queue
9
+ adhoc_jobs_required_arguments: Required Arguments
10
+ adhoc_jobs_run_job: Run Job
11
+ adhoc_jobs_view_job: View Job
@@ -0,0 +1,17 @@
1
+ module SidekiqAdhocJob
2
+ module Web
3
+ module Jobs
4
+ class Index
5
+
6
+ def self.register(app)
7
+ app.get '/adhoc-jobs' do
8
+ @presented_jobs = SidekiqAdhocJob::Web::JobPresenter.build_collection
9
+
10
+ erb File.read(File.join(VIEW_PATH, 'jobs/index.html.erb'))
11
+ end
12
+ end
13
+
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,16 @@
1
+ module SidekiqAdhocJob
2
+ module Web
3
+ module Jobs
4
+ class Schedule
5
+
6
+ def self.register(app)
7
+ app.post '/adhoc-jobs/:name/schedule' do
8
+ SidekiqAdhocJob::ScheduleAdhocJob.new(params[:name], request.params).call
9
+ redirect "#{root_path}adhoc-jobs"
10
+ end
11
+ end
12
+
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,21 @@
1
+ module SidekiqAdhocJob
2
+ module Web
3
+ module Jobs
4
+ class Show
5
+
6
+ def self.register(app)
7
+ app.get '/adhoc-jobs/:name' do
8
+ @csrf_token = env['rack.session'][:csrf]
9
+ @presented_job = SidekiqAdhocJob::Web::JobPresenter.find(params[:name])
10
+ if @presented_job
11
+ erb File.read(File.join(VIEW_PATH, 'jobs/show.html.erb'))
12
+ else
13
+ redirect "#{root_path}adhoc-jobs"
14
+ end
15
+ end
16
+ end
17
+
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,33 @@
1
+ <h3><%= t('adhoc_jobs') %></h3>
2
+
3
+ <div class="table_container">
4
+ <table class="table table-hover table-bordered table-striped table-white">
5
+ <thead>
6
+ <tr>
7
+ <th><%= t('adhoc_jobs_name') %></th>
8
+ <th><%= t('adhoc_jobs_queue') %></th>
9
+ <th><%= t('adhoc_jobs_required_arguments') %></th>
10
+ <th><%= t('adhoc_jobs_optional_arguments') %></th>
11
+ <th><%= t('adhoc_jobs_has_rest_arguments') %></th>
12
+ <th><%= t('adhoc_jobs_actions') %></th>
13
+ </tr>
14
+ </thead>
15
+
16
+ <tbody>
17
+ <% @presented_jobs.each do |job| %>
18
+ <tr>
19
+ <td><%= job.name %></td>
20
+ <td><%= job.queue %></td>
21
+ <td><%= job.required_args.join(', ') %></td>
22
+ <td><%= job.optional_args.join(', ') %></td>
23
+ <td><%= job.has_rest_args %></td>
24
+ <td class="text-center">
25
+ <a class="btn btn-warn btn-xs" href="<%= root_path %>adhoc-jobs/<%= URI.escape(job.path_name) %>">
26
+ <%= t('adhoc_jobs_view_job') %>
27
+ </a>
28
+ </td>
29
+ </tr>
30
+ <% end %>
31
+ </tbody>
32
+ </table>
33
+ </div>
@@ -0,0 +1,39 @@
1
+ <h3><%= t('adhoc_jobs') %></h3>
2
+
3
+ <form method="POST" action="<%= root_path %>adhoc-jobs/<%= URI.escape(@presented_job.path_name) %>/schedule">
4
+ <input type="hidden" name="authenticity_token" value="<%= @csrf_token %>" />
5
+ <% if @presented_job.args.empty? && !@presented_job.has_rest_args %>
6
+ <p>No job arguments</p>
7
+ <% else %>
8
+ <% @presented_job.required_args.each do |arg| %>
9
+ <div class="form-group row">
10
+ <label class="col-sm-2 col-form-label" for="<%= arg %>">*<%= arg %>:</label>
11
+ <div class="col-sm-4">
12
+ <input class="form-control" type="text" name="<%= arg %>" id="<%= arg %>" required/>
13
+ </div>
14
+ </div>
15
+ <% end %>
16
+ <% @presented_job.optional_args.each do |arg| %>
17
+ <div class="form-group row">
18
+ <label class="col-sm-2 col-form-label" for="<%= arg %>"><%= arg %>:</label>
19
+ <div class="col-sm-4">
20
+ <input class="form-control" type="text" name="<%= arg %>" id="<%= arg %>"/>
21
+ </div>
22
+ </div>
23
+ <% end %>
24
+ <% if @presented_job.has_rest_args %>
25
+ <div class="form-group row">
26
+ <label class="col-sm-2 col-form-label" for="rest_args">*Rest arguments (please separate each argument by comma):</label>
27
+ <div class="col-sm-4">
28
+ <input class="form-control" type="text" name="rest_args" id="rest_args" required/>
29
+ </div>
30
+ </div>
31
+ <% end %>
32
+ <% end %>
33
+ <div class="form-group row">
34
+ <div class="col-sm-4">
35
+ <button type="submit" class="btn btn-danger"><%= t('adhoc_jobs_run_job') %></button>
36
+ <a class="btn" href="<%= root_path %>adhoc-jobs"><%= t('adhoc_jobs_go_back') %></a>
37
+ </div>
38
+ </div>
39
+ </form>
@@ -0,0 +1,26 @@
1
+ require 'pathname'
2
+
3
+ ROUTE_PATH ||= File.expand_path('web/routes', __dir__)
4
+
5
+ module SidekiqAdhocJob
6
+ module Web
7
+ VIEW_PATH ||= File.expand_path('web/templates', __dir__)
8
+
9
+ StringUtil ||= ::SidekiqAdhocJob::Utils::String
10
+
11
+ def self.registered(app)
12
+ Dir[File.join(ROUTE_PATH, '**/*.rb')].each do |file_name|
13
+ relative_path = ::Pathname.new(file_name).relative_path_from(ROUTE_PATH)
14
+ module_name = StringUtil.classify(File.dirname(relative_path))
15
+ klass_name = StringUtil.classify(File.basename(relative_path, '.rb'))
16
+ namespaced_klass_name = StringUtil.constantize("SidekiqAdhocJob::Web::#{module_name}::#{klass_name}")
17
+ namespaced_klass_name.register(app)
18
+ end
19
+ end
20
+
21
+ end
22
+ end
23
+
24
+ Dir[File.join(ROUTE_PATH, '**/*.rb')].each do |file_name|
25
+ require_relative file_name
26
+ end
@@ -0,0 +1,52 @@
1
+ module SidekiqAdhocJob
2
+ class WorkerClassesLoader
3
+
4
+ VALID_QUALIFIED_CLASS_NAME ||= /\A(([A-Z]{1}[a-z]+)(::)*)+\z/
5
+ VALID_WORKER_CLASS_NAME ||= /^.+[^(::)]+Worker$/
6
+
7
+ StringUtil ||= Utils::String
8
+
9
+ @_worker_klasses = {}
10
+
11
+ def self.load(module_names)
12
+ module_consts = module_names.map { |name| StringUtil.constantize(name.to_s) }
13
+ module_consts.each do |module_const|
14
+ module_const.constants.each do |sub_module_const_sym|
15
+ load_workers(module_const, sub_module_const_sym, @_worker_klasses)
16
+ end
17
+ end
18
+ end
19
+
20
+ def self.worker_klasses
21
+ @_worker_klasses
22
+ end
23
+
24
+ def self.find_worker_klass(path_name)
25
+ @_worker_klasses[path_name]
26
+ end
27
+
28
+ def self.load_workers(parent_module_const, module_sym, workers)
29
+ qualified_name = module_sym.to_s
30
+ return unless VALID_QUALIFIED_CLASS_NAME.match?(qualified_name)
31
+
32
+ module_const = begin
33
+ StringUtil.constantize(qualified_name)
34
+ rescue NameError => _e
35
+ qualified_name = [parent_module_const, module_sym].compact.join('::')
36
+ begin
37
+ StringUtil.constantize(qualified_name)
38
+ rescue NameError => _e
39
+ nil
40
+ end
41
+ end
42
+ return unless module_const && module_const.is_a?(Class)
43
+
44
+ if VALID_WORKER_CLASS_NAME.match?(qualified_name)
45
+ path_name = StringUtil.underscore(qualified_name).gsub('/', '_')
46
+ workers[path_name] = module_const
47
+ return
48
+ end
49
+ end
50
+
51
+ end
52
+ end
@@ -0,0 +1,45 @@
1
+ require 'sidekiq'
2
+ require 'sidekiq/web'
3
+
4
+ require 'sidekiq_adhoc_job/utils/string'
5
+ require 'sidekiq_adhoc_job/worker_classes_loader'
6
+ require 'sidekiq_adhoc_job/web/job_presenter'
7
+ require 'sidekiq_adhoc_job/services/schedule_adhoc_job'
8
+ require 'sidekiq_adhoc_job/web'
9
+
10
+ module SidekiqAdhocJob
11
+
12
+ InvalidConfigurationError ||= Class.new(RuntimeError)
13
+
14
+ def self.configure
15
+ @_config = Configuration.new
16
+ yield @_config
17
+ end
18
+
19
+ def self.config
20
+ @_config
21
+ end
22
+
23
+ def self.init
24
+ raise InvalidConfigurationError, 'Must configure before init' unless @_config&.configured?
25
+
26
+ SidekiqAdhocJob::WorkerClassesLoader.load(@_config.module_names)
27
+
28
+ Sidekiq::Web.register(SidekiqAdhocJob::Web)
29
+ Sidekiq::Web.tabs['adhoc_jobs'] = 'adhoc-jobs'
30
+ Sidekiq::Web.locales << File.expand_path('sidekiq_adhoc_job/web/locales', __dir__)
31
+ end
32
+
33
+ class Configuration
34
+ attr_accessor :module_names
35
+
36
+ def initialize
37
+ @module_names = []
38
+ end
39
+
40
+ def configured?
41
+ !@module_names.empty?
42
+ end
43
+ end
44
+
45
+ end
metadata ADDED
@@ -0,0 +1,156 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sidekiq_adhoc_job
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.2
5
+ platform: ruby
6
+ authors:
7
+ - Goh Khoon Hiang
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2019-06-06 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: pry
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: 2.0.1
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 2.0.1
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: 12.3.2
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: 12.3.2
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: 3.8.0
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: 3.8.0
69
+ - !ruby/object:Gem::Dependency
70
+ name: rack-test
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: 1.1.0
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: 1.1.0
83
+ - !ruby/object:Gem::Dependency
84
+ name: mock_redis
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: 0.20.0
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: 0.20.0
97
+ - !ruby/object:Gem::Dependency
98
+ name: sidekiq
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: 5.2.7
104
+ type: :runtime
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: 5.2.7
111
+ description: Trigger jobs adhoc from Sidekiq web admin
112
+ email:
113
+ - gohkhoonhiang@gmail.com
114
+ executables: []
115
+ extensions: []
116
+ extra_rdoc_files: []
117
+ files:
118
+ - lib/sidekiq_adhoc_job.rb
119
+ - lib/sidekiq_adhoc_job/services/schedule_adhoc_job.rb
120
+ - lib/sidekiq_adhoc_job/utils/string.rb
121
+ - lib/sidekiq_adhoc_job/version.rb
122
+ - lib/sidekiq_adhoc_job/web.rb
123
+ - lib/sidekiq_adhoc_job/web/job_presenter.rb
124
+ - lib/sidekiq_adhoc_job/web/locales/en.yml
125
+ - lib/sidekiq_adhoc_job/web/routes/jobs/index.rb
126
+ - lib/sidekiq_adhoc_job/web/routes/jobs/schedule.rb
127
+ - lib/sidekiq_adhoc_job/web/routes/jobs/show.rb
128
+ - lib/sidekiq_adhoc_job/web/templates/jobs/index.html.erb
129
+ - lib/sidekiq_adhoc_job/web/templates/jobs/show.html.erb
130
+ - lib/sidekiq_adhoc_job/worker_classes_loader.rb
131
+ homepage: https://github.com/gohkhoonhiang/sidekiq_adhoc_job
132
+ licenses:
133
+ - MIT
134
+ metadata:
135
+ allowed_push_host: https://rubygems.org
136
+ post_install_message:
137
+ rdoc_options: []
138
+ require_paths:
139
+ - lib/sidekiq_adhoc_job
140
+ - lib
141
+ required_ruby_version: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - ">="
144
+ - !ruby/object:Gem::Version
145
+ version: 2.6.0
146
+ required_rubygems_version: !ruby/object:Gem::Requirement
147
+ requirements:
148
+ - - ">="
149
+ - !ruby/object:Gem::Version
150
+ version: '0'
151
+ requirements: []
152
+ rubygems_version: 3.0.3
153
+ signing_key:
154
+ specification_version: 4
155
+ summary: Trigger jobs adhoc from Sidekiq web admin
156
+ test_files: []