action_command 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|