action_command 0.1.0
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/.codeclimate.yml +26 -0
- data/.gitignore +36 -0
- data/.rspec +2 -0
- data/.rubocop.yml +11 -0
- data/.travis.yml +21 -0
- data/CODE_OF_CONDUCT.md +49 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +112 -0
- data/Guardfile +75 -0
- data/LICENSE +21 -0
- data/LICENSE.txt +21 -0
- data/README.md +44 -0
- data/Rakefile +18 -0
- data/action_command.gemspec +36 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/doc/ActionCommand/Executable.html +625 -0
- data/doc/ActionCommand/InputOutput.html +876 -0
- data/doc/ActionCommand/Result.html +589 -0
- data/doc/ActionCommand.html +982 -0
- data/doc/_index.html +155 -0
- data/doc/class_list.html +58 -0
- data/doc/css/common.css +1 -0
- data/doc/css/full_list.css +57 -0
- data/doc/css/style.css +339 -0
- data/doc/file.README.html +137 -0
- data/doc/file_list.html +60 -0
- data/doc/frames.html +26 -0
- data/doc/index.html +137 -0
- data/doc/js/app.js +219 -0
- data/doc/js/full_list.js +181 -0
- data/doc/js/jquery.js +4 -0
- data/doc/method_list.html +219 -0
- data/doc/top-level-namespace.html +112 -0
- data/lib/action_command/version.rb +4 -0
- data/lib/action_command.rb +277 -0
- metadata +264 -0
@@ -0,0 +1,219 @@
|
|
1
|
+
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
2
|
+
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
3
|
+
<html>
|
4
|
+
<head>
|
5
|
+
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
6
|
+
|
7
|
+
<link rel="stylesheet" href="css/full_list.css" type="text/css" media="screen" charset="utf-8" />
|
8
|
+
|
9
|
+
<link rel="stylesheet" href="css/common.css" type="text/css" media="screen" charset="utf-8" />
|
10
|
+
|
11
|
+
|
12
|
+
|
13
|
+
<script type="text/javascript" charset="utf-8" src="js/jquery.js"></script>
|
14
|
+
|
15
|
+
<script type="text/javascript" charset="utf-8" src="js/full_list.js"></script>
|
16
|
+
|
17
|
+
|
18
|
+
<title>Method List</title>
|
19
|
+
<base id="base_target" target="_parent" />
|
20
|
+
</head>
|
21
|
+
<body>
|
22
|
+
<script type="text/javascript" charset="utf-8">
|
23
|
+
var hasFrames = false;
|
24
|
+
try {
|
25
|
+
hasFrames = window.top.frames.main ? true : false;
|
26
|
+
} catch (e) { }
|
27
|
+
if (hasFrames) {
|
28
|
+
document.getElementById('base_target').target = 'main';
|
29
|
+
document.body.className = 'frames';
|
30
|
+
}
|
31
|
+
</script>
|
32
|
+
<div id="content">
|
33
|
+
<h1 id="full_list_header">Method List</h1>
|
34
|
+
<div id="nav">
|
35
|
+
|
36
|
+
<span><a target="_self" href="class_list.html">
|
37
|
+
Classes
|
38
|
+
</a></span>
|
39
|
+
|
40
|
+
<span><a target="_self" href="method_list.html">
|
41
|
+
Methods
|
42
|
+
</a></span>
|
43
|
+
|
44
|
+
<span><a target="_self" href="file_list.html">
|
45
|
+
Files
|
46
|
+
</a></span>
|
47
|
+
|
48
|
+
</div>
|
49
|
+
<div id="search">Search: <input type="text" /></div>
|
50
|
+
|
51
|
+
<ul id="full_list" class="method">
|
52
|
+
|
53
|
+
|
54
|
+
<li class="r1 ">
|
55
|
+
<span class='object_link'><a href="ActionCommand/Result.html#%5B%5D-instance_method" title="ActionCommand::Result#[] (method)">#[]</a></span>
|
56
|
+
<small>ActionCommand::Result</small>
|
57
|
+
</li>
|
58
|
+
|
59
|
+
|
60
|
+
<li class="r2 ">
|
61
|
+
<span class='object_link'><a href="ActionCommand/Result.html#%5B%5D%3D-instance_method" title="ActionCommand::Result#[]= (method)">#[]=</a></span>
|
62
|
+
<small>ActionCommand::Result</small>
|
63
|
+
</li>
|
64
|
+
|
65
|
+
|
66
|
+
<li class="r1 ">
|
67
|
+
<span class='object_link'><a href="ActionCommand/InputOutput.html#assign_args-instance_method" title="ActionCommand::InputOutput#assign_args (method)">#assign_args</a></span>
|
68
|
+
<small>ActionCommand::InputOutput</small>
|
69
|
+
</li>
|
70
|
+
|
71
|
+
|
72
|
+
<li class="r2 ">
|
73
|
+
<span class='object_link'><a href="ActionCommand.html#create_and_execute-class_method" title="ActionCommand.create_and_execute (method)">create_and_execute</a></span>
|
74
|
+
<small>ActionCommand</small>
|
75
|
+
</li>
|
76
|
+
|
77
|
+
|
78
|
+
<li class="r1 ">
|
79
|
+
<span class='object_link'><a href="ActionCommand.html#create_result-class_method" title="ActionCommand.create_result (method)">create_result</a></span>
|
80
|
+
<small>ActionCommand</small>
|
81
|
+
</li>
|
82
|
+
|
83
|
+
|
84
|
+
<li class="r2 ">
|
85
|
+
<span class='object_link'><a href="ActionCommand.html#describe_io-class_method" title="ActionCommand.describe_io (method)">describe_io</a></span>
|
86
|
+
<small>ActionCommand</small>
|
87
|
+
</li>
|
88
|
+
|
89
|
+
|
90
|
+
<li class="r1 ">
|
91
|
+
<span class='object_link'><a href="ActionCommand/InputOutput.html#description-instance_method" title="ActionCommand::InputOutput#description (method)">#description</a></span>
|
92
|
+
<small>ActionCommand::InputOutput</small>
|
93
|
+
</li>
|
94
|
+
|
95
|
+
|
96
|
+
<li class="r2 ">
|
97
|
+
<span class='object_link'><a href="ActionCommand/Executable.html#execute-instance_method" title="ActionCommand::Executable#execute (method)">#execute</a></span>
|
98
|
+
<small>ActionCommand::Executable</small>
|
99
|
+
</li>
|
100
|
+
|
101
|
+
|
102
|
+
<li class="r1 ">
|
103
|
+
<span class='object_link'><a href="ActionCommand/Executable.html#execute_internal-instance_method" title="ActionCommand::Executable#execute_internal (method)">#execute_internal</a></span>
|
104
|
+
<small>ActionCommand::Executable</small>
|
105
|
+
</li>
|
106
|
+
|
107
|
+
|
108
|
+
<li class="r2 ">
|
109
|
+
<span class='object_link'><a href="ActionCommand.html#execute_rails-class_method" title="ActionCommand.execute_rails (method)">execute_rails</a></span>
|
110
|
+
<small>ActionCommand</small>
|
111
|
+
</li>
|
112
|
+
|
113
|
+
|
114
|
+
<li class="r1 ">
|
115
|
+
<span class='object_link'><a href="ActionCommand.html#execute_rake-class_method" title="ActionCommand.execute_rake (method)">execute_rake</a></span>
|
116
|
+
<small>ActionCommand</small>
|
117
|
+
</li>
|
118
|
+
|
119
|
+
|
120
|
+
<li class="r2 ">
|
121
|
+
<span class='object_link'><a href="ActionCommand.html#execute_test-class_method" title="ActionCommand.execute_test (method)">execute_test</a></span>
|
122
|
+
<small>ActionCommand</small>
|
123
|
+
</li>
|
124
|
+
|
125
|
+
|
126
|
+
<li class="r1 ">
|
127
|
+
<span class='object_link'><a href="ActionCommand/Result.html#failed-instance_method" title="ActionCommand::Result#failed (method)">#failed</a></span>
|
128
|
+
<small>ActionCommand::Result</small>
|
129
|
+
</li>
|
130
|
+
|
131
|
+
|
132
|
+
<li class="r2 ">
|
133
|
+
<span class='object_link'><a href="ActionCommand/InputOutput.html#help%3F-instance_method" title="ActionCommand::InputOutput#help? (method)">#help?</a></span>
|
134
|
+
<small>ActionCommand::InputOutput</small>
|
135
|
+
</li>
|
136
|
+
|
137
|
+
|
138
|
+
<li class="r1 ">
|
139
|
+
<span class='object_link'><a href="ActionCommand/Result.html#info-instance_method" title="ActionCommand::Result#info (method)">#info</a></span>
|
140
|
+
<small>ActionCommand::Result</small>
|
141
|
+
</li>
|
142
|
+
|
143
|
+
|
144
|
+
<li class="r2 ">
|
145
|
+
<span class='object_link'><a href="ActionCommand/Executable.html#initialize-instance_method" title="ActionCommand::Executable#initialize (method)">#initialize</a></span>
|
146
|
+
<small>ActionCommand::Executable</small>
|
147
|
+
</li>
|
148
|
+
|
149
|
+
|
150
|
+
<li class="r1 ">
|
151
|
+
<span class='object_link'><a href="ActionCommand/Result.html#initialize-instance_method" title="ActionCommand::Result#initialize (method)">#initialize</a></span>
|
152
|
+
<small>ActionCommand::Result</small>
|
153
|
+
</li>
|
154
|
+
|
155
|
+
|
156
|
+
<li class="r2 ">
|
157
|
+
<span class='object_link'><a href="ActionCommand/InputOutput.html#initialize-instance_method" title="ActionCommand::InputOutput#initialize (method)">#initialize</a></span>
|
158
|
+
<small>ActionCommand::InputOutput</small>
|
159
|
+
</li>
|
160
|
+
|
161
|
+
|
162
|
+
<li class="r1 ">
|
163
|
+
<span class='object_link'><a href="ActionCommand/InputOutput.html#input-instance_method" title="ActionCommand::InputOutput#input (method)">#input</a></span>
|
164
|
+
<small>ActionCommand::InputOutput</small>
|
165
|
+
</li>
|
166
|
+
|
167
|
+
|
168
|
+
<li class="r2 ">
|
169
|
+
<span class='object_link'><a href="ActionCommand/InputOutput.html#keys-instance_method" title="ActionCommand::InputOutput#keys (method)">#keys</a></span>
|
170
|
+
<small>ActionCommand::InputOutput</small>
|
171
|
+
</li>
|
172
|
+
|
173
|
+
|
174
|
+
<li class="r1 ">
|
175
|
+
<span class='object_link'><a href="ActionCommand.html#logger%3D-class_method" title="ActionCommand.logger= (method)">logger=</a></span>
|
176
|
+
<small>ActionCommand</small>
|
177
|
+
</li>
|
178
|
+
|
179
|
+
|
180
|
+
<li class="r2 ">
|
181
|
+
<span class='object_link'><a href="ActionCommand/Result.html#ok%3F-instance_method" title="ActionCommand::Result#ok? (method)">#ok?</a></span>
|
182
|
+
<small>ActionCommand::Result</small>
|
183
|
+
</li>
|
184
|
+
|
185
|
+
|
186
|
+
<li class="r1 ">
|
187
|
+
<span class='object_link'><a href="ActionCommand/Executable.html#parent-instance_method" title="ActionCommand::Executable#parent (method)">#parent</a></span>
|
188
|
+
<small>ActionCommand::Executable</small>
|
189
|
+
</li>
|
190
|
+
|
191
|
+
|
192
|
+
<li class="r2 ">
|
193
|
+
<span class='object_link'><a href="ActionCommand/InputOutput.html#show_help-instance_method" title="ActionCommand::InputOutput#show_help (method)">#show_help</a></span>
|
194
|
+
<small>ActionCommand::InputOutput</small>
|
195
|
+
</li>
|
196
|
+
|
197
|
+
|
198
|
+
<li class="r1 ">
|
199
|
+
<span class='object_link'><a href="ActionCommand/Executable.html#test-instance_method" title="ActionCommand::Executable#test (method)">#test</a></span>
|
200
|
+
<small>ActionCommand::Executable</small>
|
201
|
+
</li>
|
202
|
+
|
203
|
+
|
204
|
+
<li class="r2 ">
|
205
|
+
<span class='object_link'><a href="ActionCommand/Executable.html#testing-instance_method" title="ActionCommand::Executable#testing (method)">#testing</a></span>
|
206
|
+
<small>ActionCommand::Executable</small>
|
207
|
+
</li>
|
208
|
+
|
209
|
+
|
210
|
+
<li class="r1 ">
|
211
|
+
<span class='object_link'><a href="ActionCommand/InputOutput.html#validate-instance_method" title="ActionCommand::InputOutput#validate (method)">#validate</a></span>
|
212
|
+
<small>ActionCommand::InputOutput</small>
|
213
|
+
</li>
|
214
|
+
|
215
|
+
|
216
|
+
</ul>
|
217
|
+
</div>
|
218
|
+
</body>
|
219
|
+
</html>
|
@@ -0,0 +1,112 @@
|
|
1
|
+
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
2
|
+
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
3
|
+
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
4
|
+
<head>
|
5
|
+
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
6
|
+
<title>
|
7
|
+
Top Level Namespace
|
8
|
+
|
9
|
+
— Documentation by YARD 0.8.7.6
|
10
|
+
|
11
|
+
</title>
|
12
|
+
|
13
|
+
<link rel="stylesheet" href="css/style.css" type="text/css" charset="utf-8" />
|
14
|
+
|
15
|
+
<link rel="stylesheet" href="css/common.css" type="text/css" charset="utf-8" />
|
16
|
+
|
17
|
+
<script type="text/javascript" charset="utf-8">
|
18
|
+
hasFrames = window.top.frames.main ? true : false;
|
19
|
+
relpath = '';
|
20
|
+
framesUrl = "frames.html#!top-level-namespace.html";
|
21
|
+
</script>
|
22
|
+
|
23
|
+
|
24
|
+
<script type="text/javascript" charset="utf-8" src="js/jquery.js"></script>
|
25
|
+
|
26
|
+
<script type="text/javascript" charset="utf-8" src="js/app.js"></script>
|
27
|
+
|
28
|
+
|
29
|
+
</head>
|
30
|
+
<body>
|
31
|
+
<div id="header">
|
32
|
+
<div id="menu">
|
33
|
+
|
34
|
+
<a href="_index.html">Index</a> »
|
35
|
+
|
36
|
+
|
37
|
+
<span class="title">Top Level Namespace</span>
|
38
|
+
|
39
|
+
|
40
|
+
<div class="noframes"><span class="title">(</span><a href="." target="_top">no frames</a><span class="title">)</span></div>
|
41
|
+
</div>
|
42
|
+
|
43
|
+
<div id="search">
|
44
|
+
|
45
|
+
<a class="full_list_link" id="class_list_link"
|
46
|
+
href="class_list.html">
|
47
|
+
Class List
|
48
|
+
</a>
|
49
|
+
|
50
|
+
<a class="full_list_link" id="method_list_link"
|
51
|
+
href="method_list.html">
|
52
|
+
Method List
|
53
|
+
</a>
|
54
|
+
|
55
|
+
<a class="full_list_link" id="file_list_link"
|
56
|
+
href="file_list.html">
|
57
|
+
File List
|
58
|
+
</a>
|
59
|
+
|
60
|
+
</div>
|
61
|
+
<div class="clear"></div>
|
62
|
+
</div>
|
63
|
+
|
64
|
+
<iframe id="search_frame"></iframe>
|
65
|
+
|
66
|
+
<div id="content"><h1>Top Level Namespace
|
67
|
+
|
68
|
+
|
69
|
+
|
70
|
+
</h1>
|
71
|
+
|
72
|
+
<dl class="box">
|
73
|
+
|
74
|
+
|
75
|
+
|
76
|
+
|
77
|
+
|
78
|
+
|
79
|
+
|
80
|
+
|
81
|
+
</dl>
|
82
|
+
<div class="clear"></div>
|
83
|
+
|
84
|
+
<h2>Defined Under Namespace</h2>
|
85
|
+
<p class="children">
|
86
|
+
|
87
|
+
|
88
|
+
<strong class="modules">Modules:</strong> <span class='object_link'><a href="ActionCommand.html" title="ActionCommand (module)">ActionCommand</a></span>
|
89
|
+
|
90
|
+
|
91
|
+
|
92
|
+
|
93
|
+
</p>
|
94
|
+
|
95
|
+
|
96
|
+
|
97
|
+
|
98
|
+
|
99
|
+
|
100
|
+
|
101
|
+
|
102
|
+
|
103
|
+
</div>
|
104
|
+
|
105
|
+
<div id="footer">
|
106
|
+
Generated on Sat Feb 13 10:16:47 2016 by
|
107
|
+
<a href="http://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
|
108
|
+
0.8.7.6 (ruby-2.2.3).
|
109
|
+
</div>
|
110
|
+
|
111
|
+
</body>
|
112
|
+
</html>
|
@@ -0,0 +1,277 @@
|
|
1
|
+
require 'action_command/version'
|
2
|
+
|
3
|
+
# To use action command, create subclasses of ActionCommand::Executable
|
4
|
+
# and run them using the ActionCommand.execute_... variants.
|
5
|
+
module ActionCommand
|
6
|
+
# Used as root parent of command if we are in a testing context.
|
7
|
+
CONTEXT_TEST = :test
|
8
|
+
|
9
|
+
# Used as root parent of command if we are in a rake task
|
10
|
+
CONTEXT_RAKE = :rake
|
11
|
+
|
12
|
+
# Used as root parent of command if we are executing it from rails (a controller, etc)
|
13
|
+
CONTEXT_RAILS = :rails
|
14
|
+
|
15
|
+
@@logger = nil # rubocop:disable Style/ClassVars
|
16
|
+
@@params = {} # rubocop:disable Style/ClassVars
|
17
|
+
|
18
|
+
# Set a logger to be used when creating commands.
|
19
|
+
# @param logger Any object that implements .error and .info
|
20
|
+
def self.logger=(logger)
|
21
|
+
@@logger = logger # rubocop:disable Style/ClassVars
|
22
|
+
end
|
23
|
+
|
24
|
+
# @return a new, valid, empty result.
|
25
|
+
def self.create_result
|
26
|
+
return ActionCommand::Result.new(@@logger)
|
27
|
+
end
|
28
|
+
|
29
|
+
# Execute a command at the root level of a testing context
|
30
|
+
#
|
31
|
+
# @param rspec pass in 'self' in an rspec example if you want to
|
32
|
+
# perform internal validations. See {Executable#testing} to embed
|
33
|
+
# test code within commands.
|
34
|
+
# @param cls [ActionCommand::Executable] the class of an Executable subclass
|
35
|
+
# @param params [Hash] parameters used by the command.
|
36
|
+
# @return [ActionCommand::Result]
|
37
|
+
def self.execute_test(rspec, cls, params = {})
|
38
|
+
params[:test] = rspec
|
39
|
+
result = create_result
|
40
|
+
return ActionCommand.create_and_execute(cls, params, CONTEXT_TEST, result)
|
41
|
+
end
|
42
|
+
|
43
|
+
# Execute a command at the root level of a rake task context.
|
44
|
+
# @param cls [ActionCommand::Executable] The class of an Executable subclass
|
45
|
+
# @param args [Hash] parameters used by the command.
|
46
|
+
# @return [ActionCommand::Result]
|
47
|
+
def self.execute_rake(cls, args = {})
|
48
|
+
io = cls.describe_io
|
49
|
+
if io.help? args
|
50
|
+
io.show_help
|
51
|
+
return
|
52
|
+
end
|
53
|
+
|
54
|
+
return unless io.validate(args)
|
55
|
+
|
56
|
+
result = create_result
|
57
|
+
return ActionCommand.create_and_execute(cls, args, CONTEXT_RAKE, result)
|
58
|
+
end
|
59
|
+
|
60
|
+
# Execute a command at the root level of a rails context
|
61
|
+
# @param cls [ActionCommand::Executable] The class of an Executable subclass
|
62
|
+
# @param params [Hash] parameters used by the command.
|
63
|
+
# @return [ActionCommand::Result]
|
64
|
+
def self.execute_rails(cls, params = {})
|
65
|
+
result = create_result
|
66
|
+
return ActionCommand.create_and_execute(cls, params, CONTEXT_RAILS, result)
|
67
|
+
end
|
68
|
+
|
69
|
+
|
70
|
+
# Create a global description of the inputs and outputs of a command. Should
|
71
|
+
# usually be called within an ActionCommand::Executable subclass in its
|
72
|
+
# self.describe_io method
|
73
|
+
def self.describe_io(cmd_cls, desc)
|
74
|
+
name = cmd_cls.name
|
75
|
+
params = @@params[name]
|
76
|
+
unless params
|
77
|
+
params = InputOutput.new(cmd_cls, desc)
|
78
|
+
@@params[name] = params
|
79
|
+
yield params
|
80
|
+
end
|
81
|
+
return params
|
82
|
+
end
|
83
|
+
|
84
|
+
# Used internally, not for general purpose use.
|
85
|
+
def self.create_and_execute(cls, params, parent, result)
|
86
|
+
raise ArgumentError, 'Expected params to be a Hash' unless params.is_a? Hash
|
87
|
+
|
88
|
+
unless cls.is_a?(Class) && cls.ancestors.include?(ActionCommand::Executable)
|
89
|
+
raise ArgumentError, 'Expected an ActionCommand::Executable as class'
|
90
|
+
end
|
91
|
+
|
92
|
+
params[:parent] = parent
|
93
|
+
action = cls.new(params)
|
94
|
+
return action.execute(result)
|
95
|
+
end
|
96
|
+
|
97
|
+
# The result of one or more commands being executed.
|
98
|
+
class Result
|
99
|
+
|
100
|
+
# By default, a command is ok?
|
101
|
+
def initialize(logger)
|
102
|
+
@ok = true
|
103
|
+
@values = {}
|
104
|
+
@logger = logger
|
105
|
+
end
|
106
|
+
|
107
|
+
# Call this if your command implementation fails. Sets
|
108
|
+
# ok? to false on the result.
|
109
|
+
# @param msg [String] message describing the failure.
|
110
|
+
def failed(msg)
|
111
|
+
@ok = false
|
112
|
+
error(msg)
|
113
|
+
end
|
114
|
+
|
115
|
+
# @return [Boolean] true, up until failed has been called at least once.
|
116
|
+
def ok?
|
117
|
+
return @ok
|
118
|
+
end
|
119
|
+
|
120
|
+
# Assign some kind of a return value for use by the caller.
|
121
|
+
def []=(key, val)
|
122
|
+
@values[key] = val
|
123
|
+
end
|
124
|
+
|
125
|
+
# Return a value return by the command
|
126
|
+
def [](key)
|
127
|
+
return @values[key]
|
128
|
+
end
|
129
|
+
|
130
|
+
# display an informational message to the logger, if there is one.
|
131
|
+
def info(msg)
|
132
|
+
@logger.info(msg) if @logger
|
133
|
+
end
|
134
|
+
|
135
|
+
protected
|
136
|
+
|
137
|
+
# display an error message to the logger, if there is one.
|
138
|
+
def error(msg)
|
139
|
+
@logger.error(msg) if @logger
|
140
|
+
end
|
141
|
+
|
142
|
+
end
|
143
|
+
|
144
|
+
# A static description of the input and output from a given command. Although
|
145
|
+
# adding this adds a bunch of documentation and validation, it is not required.
|
146
|
+
# If you don't want to specify your input and output, you can just access the hash
|
147
|
+
# you passed into the command as @params
|
148
|
+
class InputOutput
|
149
|
+
# shorthand to indicate the parameter is optional.
|
150
|
+
OPTIONAL = { optional: true }.freeze
|
151
|
+
|
152
|
+
# Do not use this. Instead, implment self.describe_io in your command subclass, and
|
153
|
+
# call the method ActionCommand#self.describe_io from within it, returning its result.
|
154
|
+
def initialize(action, desc)
|
155
|
+
@action = action
|
156
|
+
@desc = desc
|
157
|
+
@params = []
|
158
|
+
|
159
|
+
# universal parameters.
|
160
|
+
input(:help, 'Help on this command', OPTIONAL)
|
161
|
+
input(:test,
|
162
|
+
'Optional rspec context for performing validations via rspec_validate',
|
163
|
+
OPTIONAL)
|
164
|
+
input(:parent, 'Reference to the parent of this command, a symbol at the root', OPTIONAL)
|
165
|
+
end
|
166
|
+
|
167
|
+
# Validates that the specified parameters are valid for this input description.
|
168
|
+
# @param args [Hash] the arguments to validate
|
169
|
+
def validate(args)
|
170
|
+
@params.each do |p|
|
171
|
+
val = args[p[:symbol]]
|
172
|
+
|
173
|
+
# if the argument has a value, no need to test whether it is optional.
|
174
|
+
next unless !val || val == '*' || val == ''
|
175
|
+
|
176
|
+
opts = p[:opts]
|
177
|
+
unless opts[:optional]
|
178
|
+
raise ArgumentError, "You must specify the required input #{p[:symbol]}"
|
179
|
+
end
|
180
|
+
end
|
181
|
+
return true
|
182
|
+
end
|
183
|
+
|
184
|
+
# Goes through, and assigns the value for each declared parameter to an accessor
|
185
|
+
# with the same name.
|
186
|
+
def assign_args(dest, args)
|
187
|
+
# handle aliasing
|
188
|
+
if validate(args)
|
189
|
+
@params.each do |param|
|
190
|
+
sym = param[:symbol]
|
191
|
+
if args.key? sym
|
192
|
+
sym_assign = "#{sym}=".to_sym
|
193
|
+
dest.send(sym_assign, args[sym])
|
194
|
+
end
|
195
|
+
end
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
# Returns the description for this command.
|
200
|
+
def description
|
201
|
+
@desc
|
202
|
+
end
|
203
|
+
|
204
|
+
|
205
|
+
def help?(args)
|
206
|
+
first_arg_sym = @params.first[:symbol]
|
207
|
+
first_arg_val = args[first_arg_sym]
|
208
|
+
return first_arg_val == 'help'
|
209
|
+
end
|
210
|
+
|
211
|
+
# displays the help for this command
|
212
|
+
def show_help
|
213
|
+
puts "#{@action.name}: #{description}"
|
214
|
+
@params.each do |p|
|
215
|
+
puts " #{p[:symbol]}: #{p[:desc]}"
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
# Defines input for a command
|
220
|
+
# @param sym [Symbol] symbol identifying the parameter
|
221
|
+
# @param desc [String] description for use by internal developers, or on a rake task with
|
222
|
+
# rake your_task_name[help]
|
223
|
+
# @param opts Optional arguments.
|
224
|
+
def input(sym, desc, opts = {})
|
225
|
+
@params.insert(0, symbol: sym, desc: desc, opts: opts)
|
226
|
+
end
|
227
|
+
|
228
|
+
# @return an array with the set of parameter symbols this command accepts.
|
229
|
+
def keys
|
230
|
+
@params.collect { |p| p[:symbol] }
|
231
|
+
end
|
232
|
+
end
|
233
|
+
|
234
|
+
|
235
|
+
# Root class for action commands that can be executed by this library.
|
236
|
+
# Override execute_internal to implement one, call one of the variants
|
237
|
+
# of ActionCommand.execute_... to execute one.
|
238
|
+
class Executable
|
239
|
+
|
240
|
+
attr_accessor :parent, :test
|
241
|
+
|
242
|
+
# Do not call new directly, instead use ActionCommand#execute_... variants.
|
243
|
+
def initialize(args)
|
244
|
+
self.class.describe_io.assign_args(self, args)
|
245
|
+
end
|
246
|
+
|
247
|
+
# Execute the logic of a command. Should not usually be called
|
248
|
+
# directly. Command executors should call one of the ActionCommand.execute_...
|
249
|
+
# variants. Command implementors should override
|
250
|
+
# execute_internal.
|
251
|
+
# @return [ActionCommand::Result]
|
252
|
+
def execute(result)
|
253
|
+
execute_internal(result)
|
254
|
+
return result
|
255
|
+
end
|
256
|
+
|
257
|
+
# Call this within a commands execution if you'd like to perform validations
|
258
|
+
# within the testing context.
|
259
|
+
# @yield [context] Yields back the testing context that you
|
260
|
+
# passed in to ActionCommand#execute_test.
|
261
|
+
def testing
|
262
|
+
yield @test if @test
|
263
|
+
end
|
264
|
+
|
265
|
+
protected
|
266
|
+
|
267
|
+
# @!visibility public
|
268
|
+
# Override this method to implement the logic of your command
|
269
|
+
# @param result [ActionCommand::Result] a result object where you can store
|
270
|
+
# the results of your logic, or indicate that the command failed.
|
271
|
+
def execute_internal(result)
|
272
|
+
|
273
|
+
end
|
274
|
+
|
275
|
+
end
|
276
|
+
|
277
|
+
end
|