action_command 0.1.0

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