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.
@@ -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
+ &mdash; 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> &raquo;
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,4 @@
1
+ module ActionCommand
2
+ # Version of this Gem
3
+ VERSION = '0.1.0'.freeze
4
+ end
@@ -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