vop 0.3.5 → 0.3.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.github/workflows/ci.yml +39 -0
- data/.ruby-version +1 -0
- data/Gemfile.lock +34 -47
- data/README.md +118 -16
- data/bin/sidekiq.sh +10 -0
- data/exe/vop +2 -2
- data/lib/core/cache/cache.plugin +0 -0
- data/lib/core/cache/commands/invalidate_cache.rb +9 -0
- data/lib/core/{structure → meta}/commands/list_commands.rb +2 -1
- data/lib/core/meta/commands/list_filters.rb +3 -0
- data/lib/core/meta/commands/list_plugins.rb +3 -0
- data/lib/core/meta/commands/new_plugin.rb +3 -7
- data/lib/core/shell/commands/detail.rb +21 -0
- data/lib/core/shell/commands/edit.rb +5 -2
- data/lib/core/shell/commands/help.rb +1 -1
- data/lib/core/shell/commands/source.rb +10 -4
- data/lib/core/structure/commands/collect_contributions.rb +8 -2
- data/lib/core/structure/commands/generate_entity_commands.rb +19 -10
- data/lib/core/structure/commands/generate_invalidation_commands.rb +19 -9
- data/lib/core/structure/commands/list_contribution_targets.rb +9 -0
- data/lib/core/structure/commands/list_contributors.rb +1 -1
- data/lib/core/structure/structure.plugin +1 -1
- data/lib/vop/objects/chain.rb +6 -3
- data/lib/vop/objects/command.rb +14 -5
- data/lib/vop/objects/command_param.rb +22 -0
- data/lib/vop/objects/entities.rb +8 -8
- data/lib/vop/objects/entity.rb +57 -16
- data/lib/vop/objects/entity_definition.rb +22 -0
- data/lib/vop/objects/plugin.rb +46 -4
- data/lib/vop/objects/request.rb +9 -5
- data/lib/vop/parts/dependency_resolver.rb +0 -4
- data/lib/vop/parts/entity_loader.rb +0 -3
- data/lib/vop/parts/executor.rb +33 -8
- data/lib/vop/parts/plugin_finder.rb +6 -16
- data/lib/vop/search_path.rb +12 -0
- data/lib/vop/shell/shell.rb +134 -87
- data/lib/vop/shell/shell_formatter.rb +32 -17
- data/lib/vop/shell/shell_input_readline.rb +3 -0
- data/lib/vop/shell/shell_input_testable.rb +9 -3
- data/lib/vop/syntax/command_syntax.rb +22 -17
- data/lib/vop/syntax/entity_syntax.rb +21 -6
- data/lib/vop/syntax/plugin_syntax.rb +6 -0
- data/lib/vop/util/pluralizer.rb +9 -1
- data/lib/vop/version.rb +1 -1
- data/lib/vop/vop.rb +70 -44
- data/lib/vop.rb +11 -1
- data/vop.gemspec +8 -6
- metadata +103 -28
- data/lib/core/meta/commands/search_gems_for_plugins.rb +0 -38
- data/lib/core/meta/commands/search_path.rb +0 -6
- data/lib/core/structure/commands/list_plugins.rb +0 -3
- data/lib/vop/util/worker.rb +0 -24
data/lib/vop/shell/shell.rb
CHANGED
@@ -1,4 +1,3 @@
|
|
1
|
-
require "readline"
|
2
1
|
require_relative "shell_formatter"
|
3
2
|
require_relative "shell_input"
|
4
3
|
require_relative "shell_input_readline"
|
@@ -8,6 +7,7 @@ module Vop
|
|
8
7
|
class Shell
|
9
8
|
|
10
9
|
attr_reader :context
|
10
|
+
attr_reader :last_response
|
11
11
|
|
12
12
|
def initialize(op, input = nil)
|
13
13
|
@op = op
|
@@ -15,7 +15,7 @@ module Vop
|
|
15
15
|
|
16
16
|
@formatter = ShellFormatter.new
|
17
17
|
|
18
|
-
#
|
18
|
+
# override for testing
|
19
19
|
if input.nil?
|
20
20
|
input = ShellInputReadline.new(method(:tab_completion))
|
21
21
|
end
|
@@ -45,43 +45,48 @@ module Vop
|
|
45
45
|
puts
|
46
46
|
print @prompt
|
47
47
|
else
|
48
|
-
puts "\
|
48
|
+
puts "\n"
|
49
49
|
exit
|
50
50
|
end
|
51
51
|
end
|
52
52
|
|
53
|
-
def mix_arguments_and_context
|
54
|
-
result = @arguments
|
53
|
+
def mix_arguments_and_context(command = nil, arguments = nil)
|
54
|
+
result = arguments || @arguments
|
55
55
|
@context.each do |k,v|
|
56
|
-
|
57
|
-
if
|
58
|
-
|
56
|
+
cmd = command || @command
|
57
|
+
if cmd
|
58
|
+
param = (cmd).param(k)
|
59
|
+
if param && param.wants_context
|
60
|
+
result[k] = @context[k]
|
61
|
+
end
|
59
62
|
end
|
60
63
|
end
|
61
64
|
result
|
62
65
|
end
|
63
66
|
|
64
|
-
def
|
65
|
-
|
66
|
-
|
67
|
-
missing_mandatory_params = @command.mandatory_params.delete_if do |param|
|
68
|
-
@arguments.keys.include?(param.name) ||
|
67
|
+
def missing_mandatory_params(command = @command, arguments = @arguments)
|
68
|
+
command.mandatory_params.delete_if do |param|
|
69
|
+
arguments.keys.include?(param.name) ||
|
69
70
|
(@context.keys.include?(param.name) && param.wants_context)
|
70
71
|
end
|
72
|
+
end
|
71
73
|
|
72
|
-
|
73
|
-
$logger.debug "missing params : #{missing_mandatory_params.map(&:name)}"
|
74
|
-
end
|
75
|
-
|
74
|
+
def maybe_execute
|
76
75
|
if missing_mandatory_params.size > 0
|
77
76
|
@missing_params = missing_mandatory_params
|
78
77
|
@prompt = "#{@command.short_name}.#{@missing_params.first.name} ? "
|
79
78
|
else
|
80
79
|
begin
|
81
|
-
request =
|
80
|
+
request = @op.prepare_request(@command.short_name, @arguments, @context, @command.short_name)
|
82
81
|
request.shell = self
|
83
82
|
response = @op.execute_request(request)
|
84
83
|
|
84
|
+
# log the last response for the "detail" command
|
85
|
+
unless @command.short_name == "detail"
|
86
|
+
@last_response = response
|
87
|
+
end
|
88
|
+
|
89
|
+
# mix context changes from the response into the local context
|
85
90
|
@context.merge! response.context
|
86
91
|
|
87
92
|
display_type = @formatter.analyze(request, response)
|
@@ -95,65 +100,92 @@ module Vop
|
|
95
100
|
end
|
96
101
|
|
97
102
|
def accept_param(line)
|
98
|
-
|
99
|
-
|
100
|
-
|
103
|
+
unless line.nil?
|
104
|
+
current_param = @missing_params.shift
|
105
|
+
$logger.debug "value for param #{current_param.name} : #{line}"
|
106
|
+
@arguments[current_param.name] = line
|
101
107
|
|
102
|
-
|
108
|
+
maybe_execute
|
109
|
+
end
|
103
110
|
end
|
104
111
|
|
105
|
-
def
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
112
|
+
def is_special?(command)
|
113
|
+
command.start_with?('$') || command.start_with?('@') || command.end_with?('?')
|
114
|
+
end
|
115
|
+
|
116
|
+
def handle_special(command)
|
117
|
+
if command.start_with?('$')
|
118
|
+
if command.start_with?('$vop')
|
119
|
+
puts "executing #{command}"
|
120
|
+
puts eval command
|
121
|
+
else
|
122
|
+
puts "unknown $-command #{command} - try '$vop' maybe?"
|
123
|
+
end
|
124
|
+
elsif command.start_with?('@')
|
125
|
+
if command.start_with?('@op')
|
126
|
+
puts "executing #{command}"
|
127
|
+
puts eval command
|
128
|
+
else
|
129
|
+
puts "unknown @-command #{command} - try '@op' maybe?"
|
118
130
|
end
|
119
131
|
end
|
120
|
-
result
|
121
132
|
end
|
122
133
|
|
123
|
-
def
|
134
|
+
def parse(command_line)
|
124
135
|
(command, *args) = command_line.split
|
125
136
|
|
137
|
+
arguments = {}
|
126
138
|
if command
|
127
139
|
$logger.debug "command : #{command}, args : #{args}"
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
140
|
+
|
141
|
+
if command.end_with?("??")
|
142
|
+
target_command = command[0..-3]
|
143
|
+
command = "source"
|
144
|
+
arguments["name"] = target_command
|
145
|
+
elsif command.end_with?("?")
|
146
|
+
target_command = command[0..-2]
|
147
|
+
command = "help"
|
148
|
+
arguments["name"] = target_command
|
149
|
+
end
|
150
|
+
|
151
|
+
known_commands = @op.commands.keys
|
152
|
+
if known_commands.include? command
|
153
|
+
cmd = @op.commands[command]
|
154
|
+
|
155
|
+
unless args.empty? || is_special?(command)
|
156
|
+
args.each do |token|
|
157
|
+
if token.include? "="
|
158
|
+
(key, value) = token.split("=")
|
159
|
+
arguments[key] = value
|
160
|
+
else
|
161
|
+
default_param = cmd.default_param(mix_arguments_and_context)
|
162
|
+
if default_param
|
163
|
+
arguments[default_param.name] = args
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
141
167
|
end
|
168
|
+
[command, cmd, arguments]
|
142
169
|
else
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
end
|
170
|
+
[command, nil, arguments]
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
148
174
|
|
175
|
+
def parse_and_execute(command_line)
|
176
|
+
command, cmd, arguments = parse(command_line)
|
177
|
+
|
178
|
+
if command
|
179
|
+
$logger.debug "command : #{command}, args : #{arguments}"
|
180
|
+
if is_special?(command)
|
181
|
+
handle_special(command_line)
|
182
|
+
else
|
149
183
|
if command == "exit"
|
150
184
|
@input.exit
|
151
185
|
else
|
152
|
-
|
153
|
-
|
154
|
-
@
|
155
|
-
@arguments = parse_command_line(args)
|
156
|
-
|
186
|
+
if cmd
|
187
|
+
@command = cmd
|
188
|
+
@arguments = arguments
|
157
189
|
maybe_execute
|
158
190
|
else
|
159
191
|
puts "unknown command '#{command}'"
|
@@ -161,47 +193,62 @@ module Vop
|
|
161
193
|
end
|
162
194
|
end
|
163
195
|
end
|
164
|
-
|
165
196
|
end
|
166
197
|
|
167
|
-
def
|
168
|
-
|
198
|
+
def complete_for_command(s)
|
199
|
+
current_param = @missing_params.first
|
200
|
+
if current_param && current_param.options.has_key?(:lookup)
|
201
|
+
begin
|
202
|
+
lookup_block = current_param.options[:lookup]
|
169
203
|
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
# the lookup block might want the previously collected params as input
|
177
|
-
lookups = if lookup_block.arity > 0
|
178
|
-
params_for_lookup = mix_arguments_and_context
|
179
|
-
lookup_block.call(params_for_lookup)
|
180
|
-
else
|
181
|
-
lookup_block.call()
|
182
|
-
end
|
183
|
-
rescue => detail
|
184
|
-
$logger.error "problem loading lookup values for #{current_param.name} : #{detail.message}"
|
204
|
+
# the lookup block might want the previously collected params as input
|
205
|
+
lookups = if lookup_block&.arity > 0
|
206
|
+
params_for_lookup = mix_arguments_and_context
|
207
|
+
lookup_block.call(params_for_lookup)
|
208
|
+
else
|
209
|
+
lookup_block.call()
|
185
210
|
end
|
211
|
+
lookups.grep /^#{Regexp.escape(s)}/
|
212
|
+
rescue => detail
|
213
|
+
$logger.error "problem loading lookup values for #{current_param.name} : #{detail.message}"
|
214
|
+
end
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
def complete_command_line(s)
|
219
|
+
potential_command, potential_cmd, potential_args = parse(s)
|
220
|
+
#$logger.debug "? >>#{potential_cmd}<< (#{potential_args}) [#{Readline.line_buffer}]"
|
221
|
+
if potential_cmd
|
222
|
+
default_param = potential_cmd.default_param
|
223
|
+
if default_param
|
224
|
+
lookups = default_param.lookup(mix_arguments_and_context)
|
225
|
+
lookups
|
226
|
+
.grep(/^#{Regexp.escape(s.split.last)}/)
|
227
|
+
.map do |lookup|
|
228
|
+
"#{potential_command} #{lookup}"
|
229
|
+
end
|
186
230
|
end
|
187
231
|
else
|
188
|
-
lookups = @op.commands.keys.sort
|
232
|
+
lookups = @op.commands.keys.sort.grep /^#{Regexp.escape(s)}/
|
189
233
|
end
|
190
234
|
|
191
|
-
lookups.grep /^#{Regexp.escape(s)}/
|
192
235
|
end
|
193
236
|
|
194
|
-
def
|
195
|
-
|
196
|
-
|
237
|
+
def tab_completion(s)
|
238
|
+
if @command
|
239
|
+
complete_for_command(s)
|
240
|
+
else
|
241
|
+
complete_command_line(s)
|
242
|
+
end
|
243
|
+
end
|
197
244
|
|
198
|
-
|
245
|
+
def do_it(command_line = nil)
|
246
|
+
if command_line && command_line != ""
|
199
247
|
parse_and_execute(command_line)
|
200
248
|
else
|
201
249
|
while line = @input.read(@prompt)
|
202
|
-
#while line = Readline.readline(@prompt, true)
|
203
250
|
if @command
|
204
|
-
# if a command has already been selected,
|
251
|
+
# if a command has already been selected, ask for missing params
|
205
252
|
accept_param(line)
|
206
253
|
else
|
207
254
|
# otherwise input is treated as regular command line (command + args)
|
@@ -213,7 +260,7 @@ module Vop
|
|
213
260
|
|
214
261
|
def self.run(op = nil, command_line = nil)
|
215
262
|
if op.nil?
|
216
|
-
op = Vop.new
|
263
|
+
op = Vop.new(origin: "shell:#{Process.pid}@#{`hostname`.strip}")
|
217
264
|
end
|
218
265
|
self.new(op).do_it(command_line)
|
219
266
|
end
|
@@ -35,10 +35,11 @@ module Vop
|
|
35
35
|
command = request.command
|
36
36
|
show_options = command.show_options
|
37
37
|
|
38
|
-
|
38
|
+
case display_type
|
39
39
|
when :table
|
40
40
|
columns_to_display =
|
41
41
|
if show_options[:columns]
|
42
|
+
# TODO validate all columns exist?
|
42
43
|
show_options[:columns]
|
43
44
|
else
|
44
45
|
# TODO this is not optimal - what if the second row has more keys than the first?
|
@@ -54,8 +55,9 @@ module Vop
|
|
54
55
|
data.each do |row|
|
55
56
|
values = [ ]
|
56
57
|
columns_to_display.each do |key|
|
57
|
-
|
58
|
-
|
58
|
+
potential_value = row[key.to_s] || row[key.to_sym]
|
59
|
+
values << potential_value
|
60
|
+
end unless row.nil?
|
59
61
|
rearranged << values
|
60
62
|
end
|
61
63
|
|
@@ -79,18 +81,33 @@ module Vop
|
|
79
81
|
"#{k} : #{v}"
|
80
82
|
end.join("\n")
|
81
83
|
when :entity_list
|
82
|
-
data.sort_by { |e| e.id }
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
84
|
+
sorted = data.sort_by { |e| e.id }
|
85
|
+
|
86
|
+
columns = if show_options[:columns]
|
87
|
+
show_options[:columns]
|
88
|
+
else
|
89
|
+
blacklisted_keys = %w|name params plugin_name|
|
90
|
+
all_keys = sorted.map { |x| x.data.keys }.flatten.uniq
|
91
|
+
all_keys.delete_if { |x| blacklisted_keys.include? x }
|
92
|
+
end
|
93
|
+
|
94
|
+
headers = [ sorted.first.key ] + columns
|
95
|
+
|
96
|
+
rows = sorted.map do |entity|
|
97
|
+
row = [ entity.id ]
|
98
|
+
|
99
|
+
columns.each do |column|
|
100
|
+
value = entity.data[column] || ""
|
101
|
+
row << (value.respond_to?(to_s) ? value.to_s[0..49] : value)
|
102
|
+
end
|
103
|
+
|
104
|
+
row
|
105
|
+
end
|
106
|
+
|
107
|
+
Terminal::Table.new(
|
108
|
+
rows: rows,
|
109
|
+
headings: headers
|
110
|
+
)
|
94
111
|
when :entity
|
95
112
|
entity = data
|
96
113
|
"[#{entity.type}] #{entity.id}"
|
@@ -101,8 +118,6 @@ module Vop
|
|
101
118
|
else
|
102
119
|
raise "unknown display type #{display_type}"
|
103
120
|
end
|
104
|
-
|
105
|
-
result
|
106
121
|
end
|
107
122
|
|
108
123
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require "readline"
|
2
|
+
|
1
3
|
module Vop
|
2
4
|
|
3
5
|
class ShellInputReadline
|
@@ -5,6 +7,7 @@ module Vop
|
|
5
7
|
def initialize(completion_method)
|
6
8
|
Readline.completion_append_character = ""
|
7
9
|
Readline.completion_proc = completion_method
|
10
|
+
Readline.completer_word_break_characters = "\t\n\"\\'\`@$><=;|&{(" # default, but without space
|
8
11
|
end
|
9
12
|
|
10
13
|
def read(prompt)
|
@@ -3,17 +3,23 @@ module Vop
|
|
3
3
|
class TestableShellInput
|
4
4
|
|
5
5
|
attr_accessor :answers
|
6
|
-
attr_reader :exit
|
6
|
+
attr_reader :exit, :prompt
|
7
|
+
attr_accessor :fail_if_out_of_answers
|
7
8
|
|
8
9
|
def initialize
|
9
10
|
@answers = []
|
10
11
|
@exit = false
|
12
|
+
@prompt = nil
|
13
|
+
@fail_if_out_of_answers = true
|
11
14
|
end
|
12
15
|
|
13
16
|
def read(prompt)
|
17
|
+
@prompt = prompt
|
14
18
|
answer = @answers.shift
|
15
|
-
if answer.nil?
|
16
|
-
|
19
|
+
if answer.nil? && @fail_if_out_of_answers
|
20
|
+
unless @exit
|
21
|
+
raise "no more pre-defined answers (asked for '#{prompt}')"
|
22
|
+
end
|
17
23
|
end
|
18
24
|
answer
|
19
25
|
end
|
@@ -2,24 +2,17 @@ module Vop
|
|
2
2
|
|
3
3
|
module CommandSyntax
|
4
4
|
|
5
|
-
def run(&block)
|
6
|
-
@command.block = block
|
7
|
-
end
|
8
|
-
|
9
5
|
def description(s)
|
10
6
|
@command.description = s
|
11
7
|
end
|
12
8
|
|
13
|
-
def
|
14
|
-
|
15
|
-
options = {
|
16
|
-
description: options
|
17
|
-
}
|
18
|
-
end
|
19
|
-
options
|
9
|
+
def run(&block)
|
10
|
+
@command.block = block
|
20
11
|
end
|
21
12
|
|
22
|
-
def param(name, options = {})
|
13
|
+
def param(name, options = {}, more_options = {})
|
14
|
+
options = resolve_options_string(options).merge(more_options)
|
15
|
+
|
23
16
|
if name.is_a? Symbol
|
24
17
|
key = "name" # default for select_machine
|
25
18
|
entity = @op.entities.values.select { |x| x.short_name == name.to_s }.first
|
@@ -38,18 +31,15 @@ module Vop
|
|
38
31
|
name = name.to_s
|
39
32
|
end
|
40
33
|
|
41
|
-
options = resolve_options_string(options)
|
42
|
-
|
43
34
|
@command.add_param(name, options)
|
44
35
|
end
|
45
36
|
|
46
|
-
def param!(name, options = {})
|
47
|
-
options = resolve_options_string(options)
|
37
|
+
def param!(name, options = {}, more_options = {})
|
38
|
+
options = resolve_options_string(options).merge(more_options)
|
48
39
|
options.merge! mandatory: true
|
49
40
|
param(name, options)
|
50
41
|
end
|
51
42
|
|
52
|
-
# TODO does not really work yet
|
53
43
|
def block_param(name = "block", options = {})
|
54
44
|
options.merge! block: true
|
55
45
|
param(name, options)
|
@@ -69,6 +59,10 @@ module Vop
|
|
69
59
|
@command.allows_extra = true
|
70
60
|
end
|
71
61
|
|
62
|
+
def dont_log
|
63
|
+
@command.dont_log = true
|
64
|
+
end
|
65
|
+
|
72
66
|
def show(options = {})
|
73
67
|
@command.show_options[:columns] = options.delete(:columns)
|
74
68
|
@command.show_options[:display_type] = options.delete(:display_type)
|
@@ -89,6 +83,17 @@ module Vop
|
|
89
83
|
@command.invalidation_block = block
|
90
84
|
end
|
91
85
|
|
86
|
+
private
|
87
|
+
|
88
|
+
def resolve_options_string(options)
|
89
|
+
if options.is_a? String
|
90
|
+
options = {
|
91
|
+
description: options
|
92
|
+
}
|
93
|
+
end
|
94
|
+
options
|
95
|
+
end
|
96
|
+
|
92
97
|
end
|
93
98
|
|
94
99
|
end
|
@@ -2,18 +2,20 @@ module Vop
|
|
2
2
|
|
3
3
|
module EntitySyntax
|
4
4
|
|
5
|
+
def description(s)
|
6
|
+
@entity.description = s
|
7
|
+
end
|
8
|
+
|
5
9
|
def key(key)
|
6
10
|
@entity.key = key
|
7
11
|
end
|
8
12
|
|
9
13
|
def entity(options = { key: "name" }, &block)
|
10
|
-
|
11
|
-
run(&block)
|
12
|
-
end
|
14
|
+
run(&block)
|
13
15
|
end
|
14
16
|
|
15
17
|
def run(&block)
|
16
|
-
@entity.block = block
|
18
|
+
@entity.block = block if block
|
17
19
|
end
|
18
20
|
|
19
21
|
def on(other_entity)
|
@@ -26,8 +28,21 @@ module Vop
|
|
26
28
|
|
27
29
|
raise "unknown keyword #{options.keys.first}" if options.keys.length > 0
|
28
30
|
|
29
|
-
@entity.show_options[:columns] = column_options
|
30
|
-
@entity.show_options[:display_type] = display_type
|
31
|
+
@entity.show_options[:columns] = column_options if column_options
|
32
|
+
@entity.show_options[:display_type] = display_type if display_type
|
33
|
+
end
|
34
|
+
|
35
|
+
def invalidate(&block)
|
36
|
+
@entity.invalidation_block = block
|
37
|
+
end
|
38
|
+
|
39
|
+
def contribute(options, &block)
|
40
|
+
raise "missing option 'to'" unless options.has_key?(:to)
|
41
|
+
@op.register_contributor(
|
42
|
+
command_name: options[:to],
|
43
|
+
contributor: @entity.name.to_s.carefully_pluralize
|
44
|
+
)
|
45
|
+
run(&block)
|
31
46
|
end
|
32
47
|
|
33
48
|
end
|
@@ -42,6 +42,12 @@ module Vop
|
|
42
42
|
end
|
43
43
|
end
|
44
44
|
|
45
|
+
# TODO: support version requirements
|
46
|
+
def depends_on_gem(gem, **options)
|
47
|
+
$logger.debug "plugin #{@plugin.name} depends on gem #{gem}"
|
48
|
+
@plugin.external_dependencies[:gem] << [gem, options]
|
49
|
+
end
|
50
|
+
|
45
51
|
def on(hook_sym, &block)
|
46
52
|
@plugin.hook(hook_sym, &block)
|
47
53
|
end
|
data/lib/vop/util/pluralizer.rb
CHANGED
@@ -2,7 +2,7 @@ begin
|
|
2
2
|
require "active_support/inflector"
|
3
3
|
rescue Exception => e
|
4
4
|
message = "active_support inflector cannot be loaded - pluralization results may deviate : #{e.message}"
|
5
|
-
puts message
|
5
|
+
#puts message
|
6
6
|
end
|
7
7
|
|
8
8
|
module Vop
|
@@ -19,6 +19,14 @@ module Vop
|
|
19
19
|
end
|
20
20
|
end
|
21
21
|
|
22
|
+
def carefully_singularize
|
23
|
+
begin
|
24
|
+
self.singularize
|
25
|
+
rescue
|
26
|
+
"#{self[0..-2]}"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
22
30
|
end
|
23
31
|
|
24
32
|
end
|
data/lib/vop/version.rb
CHANGED