command_exec 0.1.3 → 0.2.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.
Files changed (49) hide show
  1. data/Gemfile +6 -2
  2. data/Gemfile.lock +42 -18
  3. data/README.md +707 -72
  4. data/RELEASE_NOTES.md +62 -0
  5. data/Rakefile +40 -9
  6. data/TODO.md +8 -2
  7. data/command_exec.gemspec +3 -2
  8. data/gemfiles/Gemfile.default +28 -0
  9. data/gemfiles/Gemfile.travis +16 -0
  10. data/gemfiles/Gemfile.travis.lock +48 -0
  11. data/lib/command_exec.rb +22 -2
  12. data/lib/command_exec/command.rb +307 -157
  13. data/lib/command_exec/exceptions.rb +16 -6
  14. data/lib/command_exec/field_helper.rb +263 -0
  15. data/lib/command_exec/formatter/array.rb +158 -0
  16. data/lib/command_exec/formatter/hash.rb +78 -0
  17. data/lib/command_exec/formatter/json.rb +22 -0
  18. data/lib/command_exec/formatter/string.rb +22 -0
  19. data/lib/command_exec/formatter/xml.rb +22 -0
  20. data/lib/command_exec/formatter/yaml.rb +22 -0
  21. data/lib/command_exec/logger.rb +9 -0
  22. data/lib/command_exec/process.rb +294 -0
  23. data/lib/command_exec/spec_helper_module.rb +52 -0
  24. data/lib/command_exec/version.rb +1 -1
  25. data/script/console +8 -0
  26. data/spec/command/command_spec.rb +413 -117
  27. data/spec/command/test_data/echo_test +3 -0
  28. data/spec/command/test_data/exit_status_test +2 -0
  29. data/spec/command/test_data/log_file_test +3 -0
  30. data/spec/command/test_data/logger_test +2 -0
  31. data/spec/command/test_data/not_raise_error_test +4 -0
  32. data/spec/command/test_data/not_throw_error_test +4 -0
  33. data/spec/command/test_data/output_test +6 -0
  34. data/spec/command/test_data/raise_error_test +6 -0
  35. data/spec/command/test_data/runner_open3_test +4 -0
  36. data/spec/command/test_data/runner_system_test +4 -0
  37. data/spec/command/test_data/stderr_test +4 -0
  38. data/spec/command/test_data/stdout_multiple_lines_test +4 -0
  39. data/spec/command/test_data/stdout_test +4 -0
  40. data/spec/command/test_data/throw_error_test +6 -0
  41. data/spec/command/test_data/true_test +2 -0
  42. data/spec/formatter/array_spec.rb +215 -0
  43. data/spec/formatter/hash_spec.rb +117 -0
  44. data/spec/formatter/json_spec.rb +21 -0
  45. data/spec/formatter/xml_spec.rb +33 -0
  46. data/spec/formatter/yaml_spec.rb +21 -0
  47. data/spec/process/process_spec.rb +329 -0
  48. data/spec/spec_helper.rb +15 -4
  49. metadata +79 -5
@@ -1,20 +1,30 @@
1
+ # encoding: utf-8
2
+
1
3
  # Main
2
4
  module CommandExec
3
5
  # Classed concerning pdflatex exceptions
4
6
  module Exceptions
5
7
  # Class used to indicate that a command
6
8
  # could not be found in file system
7
- class CommandNotFound < RuntimeError
8
- end
9
+ class CommandNotFound < RuntimeError; end
10
+
11
+ # Class used to indicate that a command
12
+ # is not flagged as executable
13
+ #
14
+ # @example Counter measure for this error
15
+ # chmod +x <executable>
16
+ class CommandNotExecutable < RuntimeError; end
17
+
18
+ # Class used to indicate that a command
19
+ # is not a file
20
+ class CommandIsNotAFile < RuntimeError; end
9
21
 
10
22
  # Class used to indicate that a command run
11
23
  # ended with a failure
12
- class ExecuteCommandFailed < RuntimeError
13
- end
24
+ class CommandExecutionFailed < RuntimeError; end
14
25
 
15
26
  # Class used to indicate that a logfile
16
27
  # could not be found in file system
17
- class LogfileNotFound < RuntimeError
18
- end
28
+ class LogfileNotFound < RuntimeError; end
19
29
  end
20
30
  end
@@ -0,0 +1,263 @@
1
+ #encoding: utf-8
2
+
3
+ #Main
4
+ module CommandExec
5
+ # Shared methods for fields
6
+ module FieldHelper
7
+
8
+ # Initialize helper
9
+ #
10
+ # will be used from array and hash via super call although there's no
11
+ # inheritance.
12
+ # See for more information http://stackoverflow.com/questions/1645398/ruby-include-question
13
+ def initialize
14
+ @end_time = []
15
+ @executable = []
16
+ @log_file = []
17
+ @pid = []
18
+ @reason_for_failure = []
19
+ @return_code = []
20
+ @start_time = []
21
+ @status = []
22
+ @stderr = []
23
+ @stdout = []
24
+ end
25
+
26
+ private
27
+
28
+ # Return the available header names
29
+ #
30
+ # @return [Hash] the names of the headers
31
+ #
32
+ # * :status [String]: 'STATUS'
33
+ # * :return_code [String]: 'RETURN CODE'
34
+ # * :log_file [String]: 'LOG FILE'
35
+ # * :stderr [String]: 'STDERR'
36
+ # * :stdout [String]: 'STDOUT'
37
+ # * :pid [String]: 'PID'
38
+ # * :reason\_for\_failure [String]: 'REASON FOR FAILURE'
39
+ # * :executable [String]: 'EXECUTABLE'
40
+ #
41
+ def header_names
42
+ {
43
+ headers: {
44
+ names: {
45
+ status: 'STATUS',
46
+ return_code: 'RETURN CODE',
47
+ log_file: 'LOG FILE',
48
+ stderr: 'STDERR',
49
+ stdout: 'STDOUT',
50
+ pid: 'PID',
51
+ reason_for_failure: 'REASON FOR FAILURE',
52
+ executable: 'EXECUTABLE',
53
+ start_time: 'START TIME',
54
+ end_time: 'END TIME',
55
+ },
56
+ }
57
+ }
58
+ end
59
+
60
+ # Return the available fields for output
61
+ #
62
+ # @return [Hash] the available fields with the corresponding instance
63
+ # variable
64
+ def available_fields
65
+ {
66
+ :status => @status,
67
+ :return_code => @return_code,
68
+ :stderr => @stderr,
69
+ :stdout => @stdout,
70
+ :log_file => @log_file,
71
+ :pid => @pid,
72
+ :reason_for_failure => @reason_for_failure,
73
+ :executable => @executable,
74
+ :start_time => @start_time,
75
+ :end_time => @end_time,
76
+ }
77
+ end
78
+
79
+ # Return the default fields for output
80
+ #
81
+ # @return [Array] the names of the fields which should be outputted by
82
+ # default
83
+ def default_fields
84
+ [:status,
85
+ :return_code,
86
+ :stderr,
87
+ :stdout,
88
+ :log_file,
89
+ :pid,
90
+ :reason_for_failure,
91
+ :executable,
92
+ :start_time,
93
+ :end_time,
94
+ ]
95
+ end
96
+
97
+ # Set the status of the command
98
+ #
99
+ # @param [String,Symbol] value
100
+ # Set the status of the command based on input.
101
+ #
102
+ # @param [Hash] options
103
+ # Options for status
104
+ #
105
+ # @option options [True,False] :color
106
+ # Should the output be colored
107
+ #
108
+ # @return [Array]
109
+ # the formatted status. It returns `OK` (in bold and green) if status is
110
+ # `:success` and `FAILED` (in bold and red) if status is `:failed`.
111
+ #
112
+ def prepare_status(value,options={})
113
+
114
+ case value.to_s
115
+ when 'success'
116
+ @status[0] = message_success(color: options[:color])
117
+ when 'failed'
118
+ @status[0] = message_failure(color: options[:color])
119
+ else
120
+ @status[0] = message_failure(color: options[:color])
121
+ end
122
+
123
+ @status
124
+ end
125
+
126
+ # Returns the success message
127
+ #
128
+ # @param [Hash] options
129
+ # options
130
+ #
131
+ # @option options [True,False] :color
132
+ # should the message return in color
133
+ #
134
+ # @return [String] the message
135
+ def message_success(options={})
136
+ message = 'OK'
137
+
138
+ if options[:color]
139
+ return message.green.bold
140
+ else
141
+ return message
142
+ end
143
+ end
144
+
145
+ # Returns the failure message
146
+ #
147
+ # @param [Hash] options
148
+ # options
149
+ #
150
+ # @option options [True,False] :color
151
+ # should the message return in color
152
+ #
153
+ # @return [String] the message
154
+ def message_failure(options)
155
+ message = 'FAILED'
156
+
157
+ if options[:color]
158
+ return message.red.bold
159
+ else
160
+ return message
161
+ end
162
+ end
163
+
164
+ public
165
+
166
+ # Set the content of the log file
167
+ #
168
+ # @param content [Array,String]
169
+ # The content of log file
170
+ #
171
+ # @return [Array] the content of the log file
172
+ def log_file(*content)
173
+ @log_file += content.flatten
174
+ end
175
+
176
+ # Set the return code of the command
177
+ #
178
+ # @param value [Number,String]
179
+ # Set the return code(s) of the command.
180
+ #
181
+ # @return [Array] the return code
182
+ def return_code(value)
183
+ @return_code[0] = value.to_s
184
+
185
+ @return_code
186
+ end
187
+
188
+ # Set the content of stdout
189
+ #
190
+ # @param content [Array,String]
191
+ # The content of stdout
192
+ #
193
+ # @return [Array]
194
+ def stdout(*content)
195
+ @stdout += content.flatten
196
+ end
197
+
198
+ # Set the content of stderr
199
+ #
200
+ # @param content [Array,String]
201
+ # The content of stderr
202
+ #
203
+ # @return [Array]
204
+ def stderr(*content)
205
+ @stderr += content.flatten
206
+ end
207
+
208
+ # Set the pid of the command
209
+ #
210
+ # @param value [Number,String]
211
+ # Set the pid of the command.
212
+ #
213
+ # @return [Array]
214
+ def pid(value)
215
+ @pid[0] = value.to_s
216
+
217
+ @pid
218
+ end
219
+
220
+ # Set the reason for failure
221
+ #
222
+ # @param content [Array, String]
223
+ # Set the reason for failure.
224
+ #
225
+ # @return [Array]
226
+ def reason_for_failure(*content)
227
+ @reason_for_failure += content.flatten
228
+ end
229
+
230
+ # Set the path to the executable of the command
231
+ #
232
+ # @param [String] value
233
+ # the path to the executable
234
+ #
235
+ # @return [Array]
236
+ # the executable
237
+ def executable(value)
238
+ @executable[0] = value
239
+ end
240
+
241
+ # Set the start time of command execution
242
+ #
243
+ # @param [Time] value
244
+ # the start time of command execution
245
+ #
246
+ # @return [Array]
247
+ # the start time
248
+ def start_time(value)
249
+ @start_time[0] = value
250
+ end
251
+
252
+ # Set the end time of command execution
253
+ #
254
+ # @param [Time] value
255
+ # the end time of command execution
256
+ #
257
+ # @return [Array]
258
+ # the end time
259
+ def end_time(value)
260
+ @end_time[0] = value
261
+ end
262
+ end
263
+ end
@@ -0,0 +1,158 @@
1
+ # encoding: utf-8
2
+
3
+ #Main
4
+ module CommandExec
5
+ #Formatting output
6
+ module Formatter
7
+ #Style array
8
+ class Array
9
+
10
+ include FieldHelper
11
+
12
+ # @!attribute [r] output
13
+ # return the formatted output
14
+ attr_reader :output
15
+ # @!attribute [w] logger
16
+ # set the logger after object creation
17
+ attr_writer :logger
18
+
19
+ # Create new array formatter
20
+ #
21
+ # @param [Hash] options
22
+ # Options for formatter
23
+ #
24
+ # @option options [Hash] :headers
25
+ # It is used to configure how the headers will be formatted
26
+ #
27
+ # There are several sub-options:
28
+ #
29
+ # * :names [Hash]: What should be output as name for the header (filled via deep_merge and FieldHelper-Module)
30
+ # * :prefix [String]: What is placed before the header ('=' * 5)
31
+ # * :suffix [String]: What is placed after the header ('=' * 5)
32
+ # * :halign [Symbol]: How to align the header: :center [default], :left, :right
33
+ # * :show (Boolean): Should the header be shown (true)
34
+ #
35
+ # @option options [Symbol] :logger
36
+ # Logger to output information. Needs to have the same interface like
37
+ # the ruby `Logger`-class.
38
+ #
39
+ def initialize(options={})
40
+ @options = {
41
+ headers: {
42
+ names: {},
43
+ prefix: '=' * 5,
44
+ suffix: '=' * 5,
45
+ halign: :center,
46
+ show: true,
47
+ },
48
+ logger: Logger.new($stdout),
49
+ }.deep_merge(header_names.deep_merge(options))
50
+
51
+ @headers_options = @options[:headers]
52
+ @logger = @options[:logger]
53
+
54
+ super()
55
+ end
56
+
57
+ def status(value)
58
+ prepare_status(value, color: true)
59
+ end
60
+
61
+ private
62
+
63
+ # Get the maximum length over all headers
64
+ #
65
+ # @return [Number] the maxium header length
66
+ def max_header_length
67
+ @max_header_length ||= @headers_options[:names].values.inject(0) { |max_length, name| max_length < name.length ? name.length : max_length }
68
+ end
69
+
70
+ # Align header names
71
+ #
72
+ # @param [String] name
73
+ # the name which should be aligned
74
+ #
75
+ # @param max_length [Number]
76
+ # the maximum length which is used to align the name
77
+ #
78
+ # @param orientation [Symbol]
79
+ # how to align the header name
80
+ #
81
+ # @return [String] the aligned header name
82
+ def halign(name, max_length, orientation)
83
+
84
+ name = name.to_s
85
+
86
+ case orientation
87
+ when :center
88
+ name.center(max_length)
89
+ when :left
90
+ name.ljust(max_length)
91
+ when :right
92
+ name.rjust(max_length)
93
+ else
94
+ name.center(max_length)
95
+ end
96
+ end
97
+
98
+ # Format header but only if given header is defined.
99
+ #
100
+ # @param [Symbol] header
101
+ # the name of the header. It has to be defined in opts[:names]
102
+ #
103
+ # @param [Hash] options
104
+ # used to change format options like `prefix`, `suffix` etc. after the
105
+ # creation of the `Formatter::Array`-object. Those options defined at the
106
+ # creation of the `Formatter`-object are default and can be overwritten
107
+ # using this `Hash`.
108
+ #
109
+ # @return [String] the formatted header
110
+ def format_header(header,options={})
111
+ opts = @headers_options.deep_merge options
112
+
113
+ output=""
114
+ unless opts[:names][header] == ""
115
+ output += "#{opts[:prefix]} " unless opts[:prefix].blank?
116
+ output += halign(opts[:names][header], max_header_length, opts[:halign])
117
+ output += " #{opts[:suffix]}" unless opts[:suffix].blank?
118
+ end
119
+
120
+ output
121
+ end
122
+
123
+ # Build the data structure for output
124
+ #
125
+ # @param [Array] fields
126
+ # which fields should be outputted
127
+ #
128
+ # @return [Array]
129
+ # the formatted output
130
+ def prepare_output(fields=[])
131
+ out = []
132
+ fields = fields.flatten
133
+
134
+ fields = default_fields if fields.blank?
135
+
136
+ fields.each do |var|
137
+ out << format_header(var,@headers_options) if @headers_options[:show] = true and available_fields.has_key?(var)
138
+ out += available_fields[var] if available_fields.has_key?(var)
139
+ end
140
+
141
+ out
142
+ end
143
+
144
+ public
145
+
146
+ # Output the prepared output
147
+ #
148
+ # @param [Array,Symbol) fields
149
+ # the fields which should be outputted
150
+ #
151
+ # @return [Array]
152
+ # the formatted output
153
+ def output(*fields)
154
+ prepare_output(fields.flatten)
155
+ end
156
+ end
157
+ end
158
+ end