runnable 0.2.4 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (5) hide show
  1. data/README.markdown +41 -36
  2. data/VERSION +1 -1
  3. data/lib/runnable.rb +231 -213
  4. data/runnable.gemspec +4 -3
  5. metadata +61 -22
data/README.markdown CHANGED
@@ -5,10 +5,17 @@ A Ruby gem that allow programmer to control UNIX system commands as a Ruby class
5
5
  All you have to do is to create a class named exactly as command and make it
6
6
  inherit from class Runnable.
7
7
 
8
- class LS < Runnable
8
+ class LS
9
+ include Runnable
9
10
  end
10
11
 
11
12
  That gives you the basics to control the execution of ```ls``` command.
13
+ You can overwrite the name of the command by using the ```executes``` macro:
14
+ class MyLs
15
+ include Runnable
16
+
17
+ executes :ls
18
+ end
12
19
 
13
20
  Now you can create an instance like this:
14
21
 
@@ -23,53 +30,51 @@ for some important information about the command and its process. Entire
23
30
  documentation of this gem can be generated using ```yardoc```. To do this use
24
31
  ```rake doc```.
25
32
 
26
- ## Return values
27
- Runnable has two special methods which are called at the end of a command execution.
28
- ```:finish``` if commands finalized in a correct way and ```:fail``` if an error
29
- ocurred. In case something went wrong and a ```:fail``` method is called, Runnable
30
- also provide an array containing the command return value as the parameter of a
31
- SystemCallError exception and optionally others exceptions ocurred at runtime.
33
+ ## Custom output and exceptions
34
+ Runnable parse a set of user defined regular expresion to set up the command return
35
+ values.
32
36
 
33
37
  This is an example of how we can receive the return value of a command:
34
38
 
35
- class LS < Runnable
39
+ class Nmap
40
+ include Runnable
41
+
42
+ executes :nmap
36
43
 
37
- def finish
38
- puts "Everything went better than expected :)"
39
- end
44
+ define_command( :scan, :blocking => true ) { |ip, subnet| "-sP #{ip}/#{subnet}" }
45
+ scan_processors(
46
+ :exceptions => { /^Illegal netmask value/ => ArgumentError },
47
+ :outputs => { /Nmap scan report for (.*)/ => :ip }
48
+ )
49
+ end
40
50
 
41
- def failed( exceptions )
42
- puts "Something went wrong :("
43
- exceptions.each do |exception|
44
- puts exception.message
45
- end
46
- end
51
+ Nmap.new.scan("192.168.1.1", "24") # should return an array with the ips
47
52
 
48
- end
53
+ Runnable can also raise custom exceptions, using the previously Nmap defined class:
54
+ Nmap.new.scan("192.168.1.1", "1000")
55
+ Will raise an ArgumentError exception.
56
+ Note that Runnable will also raise an exception if the command returned value is not 0.
49
57
 
50
- my_command = LS.new
51
- my_command.run
58
+ ## Background usage
59
+ Runnable can be used with background process:
52
60
 
53
- ## Custom exceptions
54
- As we saw in previous chapter, if a command execution does not ends
55
- succesfully, Runnable fires a ```:fail``` event whit an exceptions array. We can
56
- add exceptions to that array based on the output of command. For example, we
57
- can controll that parameters passed to a command are valids if we know the
58
- command output for an invalid parameters.
61
+ class Ping
62
+ include Runnable
59
63
 
60
- First we have to do is override the method ```exceptions``` defined in runnable
61
- as follows
64
+ define_command( :goping, :blocking => false) { "-c5 www.google.es" }
62
65
 
63
- class LS < Runnable
64
- def exceptions
65
- { /ls: (invalid option.*)/ => ArgumentError }
66
- end
66
+ goping_processors(
67
+ :outputs => { /64 bytes from .* time=(.*) ms/ => :time }
68
+ )
67
69
  end
68
70
 
69
- ```exceptions``` method should return a hash containing a regular expression
70
- which will be match against the command output, and a value which will be the
71
- exception added to exception array. This means that if the command output match
72
- the regular expression, a new exception will be include in ```:fail``` event parameter.
71
+ p = Ping.new
72
+ p.goping
73
+
74
+ while p.running?
75
+ p p.output[:time]
76
+ sleep 1
77
+ end
73
78
 
74
79
  # About
75
80
  Runnable is a gem developed by [NoSoloSoftware](http://nosolosoftware.biz).
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.2.4
1
+ 0.3.0
data/lib/runnable.rb CHANGED
@@ -24,14 +24,97 @@ require 'fileutils'
24
24
  # you are able to start, define params and send signals (like kill, or stop)
25
25
  #
26
26
  # @example Usage:
27
- # class LS < Runnable
27
+ # class LS
28
+ # include Runnable
29
+ #
30
+ # executes :ls
28
31
  # command_style :extended
29
32
  # end
30
33
  #
31
34
  # ls = LS.new
32
35
  # ls.alh
33
36
  # ls.run
34
- class Runnable
37
+ module Runnable
38
+ def self.included(klass)
39
+ klass.extend ClassMethods
40
+ end
41
+
42
+ module ClassMethods
43
+ # Define the command to be executed
44
+ # @return [nil]
45
+ # @param [Symbol] command Command to be executed
46
+ def executes( cmd )
47
+ define_method( :command ) { cmd }
48
+ end
49
+
50
+ # Define the parameter style to be used.
51
+ # @return [nil]
52
+ def command_style( style )
53
+ define_method( :command_style ) { style }
54
+ end
55
+
56
+ # Create a user definde command
57
+ # @return [nil]
58
+ # @param [Symbol] name The user defined command name
59
+ # @param [Hash] options Options.
60
+ # @option options :blocking (false) Describe if the execution is blocking or non-blocking
61
+ # @option options :log_path (false) Path used to store logs # (dont store logs if no path specified)
62
+ def define_command( name, opts = {}, &block )
63
+ blocking = opts[:blocking] || false
64
+ log_path = opts[:log_path] || false
65
+
66
+ commands[name] = { :blocking => blocking }
67
+
68
+ define_method( name ) do |*args|
69
+ run name, block.call(*args), log_path
70
+ join if blocking
71
+ end
72
+ end
73
+
74
+ # Generic command processor. It allows to define generic processors used in all the
75
+ # user defined commands
76
+ # @param [Hash] opts Processing options
77
+ # @option opts :outputs (nil) Output processing Hash (regexp => output)
78
+ # @option opts :exceptions (nil) Exceptions processing Hash (regexp => exception)
79
+ def processors( opts = nil )
80
+ if opts.is_a? Hash
81
+ @processors = opts
82
+ else
83
+ @processors ||= Hash.new
84
+ end
85
+ end
86
+
87
+ # Method missing processing for the command processors
88
+ def method_missing( name, *opts )
89
+ raise NoMethodError.new( name.to_s ) unless name.to_s =~ /([a-z]*)_([a-z]*)/
90
+
91
+ # command_processors
92
+ if $2 == "processors"
93
+ commands[$1.to_sym][:outputs] = opts.first[:outputs]
94
+ commands[$1.to_sym][:exceptions] = opts.first[:exceptions]
95
+ end
96
+ end
97
+
98
+ # @group Accessors for the module class variables
99
+
100
+ # Returns the user defined commands
101
+ # @return [Hash] commands User defined commands
102
+ def commands
103
+ @commands ||= Hash.new
104
+ end
105
+
106
+ # Returns the list of runnable instances by pid
107
+ # @return [Hash] list of runnable instances by pid
108
+ def processes
109
+ @processes ||= Hash.new
110
+ end
111
+
112
+ # Processes writer
113
+ def processes=( value )
114
+ @processes = value
115
+ end
116
+ end
117
+
35
118
  # Process id.
36
119
  attr_reader :pid
37
120
  # Process owner.
@@ -41,137 +124,54 @@ class Runnable
41
124
  # Directory where process was called from.
42
125
  attr_reader :pwd
43
126
 
44
- # Input file
45
- attr_accessor :input
127
+ # Process output
128
+ attr_reader :output
46
129
 
47
- # Set the output file
48
- attr_accessor :output
130
+ # Process options
131
+ attr_accessor :options
132
+ # Process log output
133
+ attr_accessor :log_path
49
134
 
50
135
  # Metaprogramming part of the class
51
-
52
- # Define the parameter style to be used.
53
- # @return [nil]
54
- def self.command_style( style )
55
- define_method( :command_style ) do
56
- style
57
- end
58
- end
59
-
136
+
60
137
  # Parameter style used for the command.
61
138
  # @return [Symbol] Command style.
62
139
  def command_style
63
140
  :gnu
64
141
  end
65
142
 
66
- # List of runnable instances running on the system order by pid.
67
- @@processes = Hash.new
143
+ # Default command to be executed
144
+ # @return [String] Command to be executed
145
+ def command
146
+ self.class.to_s.split( "::" ).last.downcase
147
+ end
68
148
 
69
149
  # Constant to calculate cpu usage.
70
150
  HERTZ = 100
71
151
 
72
- # Create a new instance of a runnable command.
73
- # @param [Hash] option_hash Options.
74
- # @option option_hash :delete_log (true) Delete the log after execution.
75
- # @option option_hash :command_options ("") Command options.
76
- # @option option_hash :log_path ("/var/log/runnable") Path for the log files.
77
- def initialize( option_hash = {} )
78
- # keys :delete_log
79
- # :command_options
80
- # :log_path
81
-
82
- # If we have the command class in a namespace, we need to remove
83
- # the namespace name
84
- @command = self.class.to_s.split( "::" ).last.downcase
85
-
86
- # Set the default command option
87
- # Empty by default
88
- option_hash[:command_options] ||= ""
89
- @options = option_hash[:command_options]
90
-
91
- # Set the log path
92
- # Default path is "/var/log/runnable"
93
- option_hash[:log_path] ||= "/var/log/runnable/"
94
- @log_path = option_hash[:log_path]
95
-
96
- # Set the delete_log option
97
- # true by default
98
- if option_hash[:delete_log] == nil
99
- @delete_log = true
100
- else
101
- @delete_log = option_hash[:delete_log]
102
- end
103
-
104
- # Store input options
105
- @input = String.new
106
-
107
- # Store output options
108
- @output = String.new
109
-
110
- # Standar Outputs
111
- @std_output = {
112
- :out => "",
113
- :err => ""
114
- }
115
-
116
- # @todo: checks that command is in the PATH
117
- # ...
118
-
119
- # we dont set the pid, because we dont know until run
120
- @pid = nil
121
- @excep_array = []
122
-
123
-
124
- # Metaprogramming part
125
- # Create a new instance of the parser class
126
- @command_line_interface = Object.const_get( command_style.to_s.capitalize.to_sym ).new
127
- # End Metaprogramming part
128
-
129
- #End of initialize instance variables
130
-
131
- create_log_directory
132
- end
133
-
134
152
  # Start the execution of the command.
135
153
  # @return [nil]
136
- def run
154
+ def run(name = nil, opts = nil, log_path = nil)
155
+ return false if @pid
137
156
  # Create a new mutex
138
157
  @pid_mutex = Mutex.new
158
+
159
+ # Log path should be an instance variable to avoid a mess
160
+ @log_path = log_path || @log_path
139
161
 
140
162
  # Create pipes to redirect Standar I/O
141
163
  out_rd, out_wr = IO.pipe
142
164
  # Redirect Error I/O
143
165
  err_rd, err_wr = IO.pipe
144
-
166
+
145
167
  # Reset exceptions array to not store exceptions for
146
168
  # past executions
147
- @excep_array = []
148
-
149
- # Set up the command line
150
- command = []
151
- #command << @command
152
- command << @input.to_s
153
- command << @options.to_s
154
- command << @command_line_interface.parse
155
- command << @output.to_s
156
- #command = command.join( " " )
157
- command.flatten!
158
-
159
- command = command.select do |value|
160
- !value.to_s.strip.empty?
161
- end
162
- =begin
163
- # Debugging purpose
164
- puts "I: #{@input}"
165
- puts "OP: #{@options}"
166
- puts "CLI: #{@command_line_interface.parse}"
167
- puts "O: #{@output}"
168
- puts "C: #{command}"
169
- =end
170
- #@pid = Process.spawn( command, { :out => out_wr, :err => err_wr } )
171
- @pid = Process.spawn( @command, *command, { :out => out_wr, :err => err_wr } )
169
+ command_argument = opts ? opts.split(" ") : compose_command
170
+
171
+ @pid = Process.spawn( command.to_s, *command_argument, { :out => out_wr, :err => err_wr } )
172
172
 
173
173
  # Include instance in class variable
174
- @@processes[@pid] = self
174
+ self.class.processes[@pid] = self
175
175
 
176
176
  # Prepare the process info file to be read
177
177
  file_status = File.open( "/proc/#{@pid}/status" ).read.split( "\n" )
@@ -179,46 +179,36 @@ class Runnable
179
179
  @owner = file_status[6].split( " " )[1]
180
180
  # Group: Read the Group owner from /proc/@pid/status
181
181
  @group = file_status[7].split( " " )[1]
182
-
182
+
183
183
  # Set @output_thread with new threads
184
184
  # wich execute the input/ouput loop
185
- create_logs(:out => [out_wr, out_rd], :err => [err_wr, err_rd])
186
-
187
- # Create a new thread to avoid blocked processes
188
- @run_thread = Thread.new do
189
- # Wait to get the pid process even if it has finished
190
- Process.wait( @pid, Process::WUNTRACED )
185
+ stream_info = {
186
+ :out => [out_wr, out_rd],
187
+ :err => [err_wr, err_rd]
188
+ }
189
+
190
+ if name
191
+ cmd_info = self.class.commands[name]
192
+ stream_processors = {
193
+ :outputs => cmd_info[:outputs],
194
+ :exceptions => cmd_info[:exceptions]
195
+ }
196
+ end
191
197
 
192
- # Wait each I/O thread
193
- @output_threads.each { |thread| thread.join }
194
- # Delete log if its necesary
195
- delete_log
198
+ output_threads = process_streams( stream_info, stream_processors )
199
+
200
+ # Create a new thread to avoid blocked processes
201
+ @run_thread = threaded_process(@pid, output_threads)
196
202
 
197
- # Get the exit code from command
198
- exit_status = $?.exitstatus
199
-
200
- # In case of error add an Exception to the @excep_array
201
- @excep_array << SystemCallError.new( exit_status ) if exit_status != 0
202
-
203
- # Call methods according to the exit code
204
- if @excep_array.empty?
205
- finish
206
- else
207
- failed( @excep_array )
208
- end
209
-
210
- # This instance is finished and we remove it
211
- @@processes.delete( @pid )
212
- end
213
-
214
203
  # Satuts Variables
215
204
  # PWD: Current Working Directory get by /proc/@pid/cwd
216
205
  # @rescue If a fast process is runned there isn't time to get
217
206
  # the correct PWD. If the readlink fails, we retry, if the process still alive
218
207
  # until the process finish.
208
+
219
209
  begin
220
- @pwd = File.readlink( "/proc/#{@pid}/cwd" )
221
- rescue
210
+ @pwd ||= File.readlink( "/proc/#{@pid}/cwd" )
211
+ rescue Errno::ENOENT
222
212
  # If cwd is not available rerun @run_thread
223
213
  if @run_thread.alive?
224
214
  #If it is alive, we retry to get cwd
@@ -228,6 +218,8 @@ class Runnable
228
218
  #If process has terminated, we set pwd to current working directory of ruby
229
219
  @pwd = Dir.getwd
230
220
  end
221
+ rescue #Errno::EACCESS
222
+ @pwd = Dir.getwd
231
223
  end
232
224
  end
233
225
 
@@ -257,6 +249,7 @@ class Runnable
257
249
  # @return [nil]
258
250
  def join
259
251
  @run_thread.join if @run_thread.alive?
252
+ @output unless @output.empty?
260
253
  end
261
254
 
262
255
  # Check if prcess is running on the system.
@@ -268,13 +261,25 @@ class Runnable
268
261
  # Standar output of command
269
262
  # @return [String] Standar output
270
263
  def std_out
271
- @std_output[:out]
264
+ @std_out ||= ""
272
265
  end
273
266
 
274
267
  # Standar error output of the command
275
268
  # @return [String] Standar error output
276
269
  def std_err
277
- @std_output[:err]
270
+ @std_err ||= ""
271
+ end
272
+
273
+ # Sets the command input to be passed to the command execution
274
+ # @param [String] opt Command input
275
+ def input=( opt )
276
+ @command_input = opt
277
+ end
278
+
279
+ # Sets the command output to be passed to the command execution
280
+ # @param [String] opt Command output
281
+ def output=( opt )
282
+ @command_output = opt
278
283
  end
279
284
 
280
285
  # Calculate the estimated memory usage in Kb.
@@ -315,7 +320,6 @@ class Runnable
315
320
  # Seconds is Zero!
316
321
  0
317
322
  end
318
-
319
323
  end
320
324
 
321
325
  # Estimated bandwidth in kb/s.
@@ -354,6 +358,8 @@ class Runnable
354
358
  # @param [Block] block Block code in method
355
359
  # @return [nil]
356
360
  def method_missing( method, *params, &block )
361
+ @command_line_interface ||= Object.const_get( command_style.to_s.capitalize.to_sym ).new
362
+
357
363
  if params.length > 1
358
364
  super( method, params, block )
359
365
  else
@@ -363,8 +369,7 @@ class Runnable
363
369
  # @see parse_hash for more information
364
370
  parse_hash( params[0] )
365
371
  else
366
- @command_line_interface.add_param( method.to_s,
367
- params != nil ? params.join(",") : nil )
372
+ @command_line_interface.add_param( method.to_s, params != nil ? params.join(",") : nil )
368
373
  end
369
374
  end
370
375
  end
@@ -375,39 +380,6 @@ class Runnable
375
380
  @@processes
376
381
  end
377
382
 
378
- # @abstract
379
- # Returns a hash of regular expressions and exceptions associated to them.
380
- # Command output is match against those regular expressions, if it does match
381
- # an appropiate exception is included in the return value of execution.
382
- # @note This method should be overwritten in child classes.
383
- # @example Usage:
384
- # class ls < Runnable
385
- # def exceptions
386
- # { /ls: (invalid option.*)/ => ArgumentError }
387
- # end
388
- # end
389
- #
390
- # @return [Hash] Using regular expressions as keys and exceptions that should
391
- # be raised as values.
392
- def exceptions
393
- {}
394
- end
395
-
396
- # @abstract
397
- # Method called when command ends with no erros.
398
- # This method is a hook so it should be overwritten in child classes.
399
- # @return [nil]
400
- def finish
401
- end
402
-
403
- # @abstract
404
- # Method called when command executions fail.
405
- # This method is a hook so it should be overwritten in child classes.
406
- # @param [Array] exceptions Array containing exceptions raised during the command execution.
407
- # @return [nil]
408
- def failed( exceptions )
409
- end
410
-
411
383
  # Send the desired signal to the command.
412
384
  # @param [Symbol] Signal to be send to the command.
413
385
  # @todo raise ESRCH if pid is not in system
@@ -437,50 +409,24 @@ class Runnable
437
409
  end
438
410
 
439
411
  protected
440
- # Redirect command I/O to log files.
412
+ # Process the command I/O.
441
413
  # These files are located in /var/log/runnable.
442
414
  # @param [Hash] Outputs options.
443
415
  # @option outputs stream [Symbol] Stream name.
444
416
  # @option outputs pipes [IO] I/O stream to be redirected.
445
- # @return [nil]
446
- def create_logs( outputs = {} )
447
- # Create an empty file for logging
448
- FileUtils.touch "#{@log_path}#{@command}_#{@pid}.log"
417
+ # @return [Array] output_threads Array containing the output processing threads
418
+ def process_streams( output_streams = {}, stream_processors = nil )
419
+ @output = Hash.new
420
+ @std_output = Hash.new
449
421
 
450
- @output_threads = []
422
+ output_threads = []
451
423
  # for each io stream we create a thread wich read that
452
424
  # stream and write it in a log file
453
- outputs.each do |output_name, pipes|
454
- @output_threads << Thread.new do
455
- pipes[0].close
456
-
457
- @std_output[output_name] = ""
458
-
459
- pipes[1].each_line do |line|
460
- @std_output[output_name] << line
461
-
462
- File.open("#{@log_path}#{@command}_#{@pid}.log", "a") do |log_file|
463
- log_file.puts( "[#{Time.new.inspect} || [STD#{output_name.to_s.upcase} || [#{@pid}]] #{line}" )
464
- end
465
- # Match custom exceptions
466
- # if we get a positive match, add it to the exception array
467
- # in order to inform the user of what had happen
468
- exceptions.each do | reg_expr, value |
469
- @excep_array<< value.new( $1 ) if reg_expr =~ line
470
- end
471
- end
472
- end
425
+ output_streams.collect do |output_name, pipes|
426
+ threaded_output_processor(output_name, pipes, stream_processors)
473
427
  end
474
428
  end
475
429
 
476
- def create_log_directory
477
- Dir.mkdir( @log_path ) unless Dir.exist?( @log_path )
478
- end
479
-
480
- def delete_log
481
- File.delete( "#{@log_path}#{@command}_#{@pid}.log" ) if @delete_log == true
482
- end
483
-
484
430
  # Expand a parameter hash calling each key as method and value as param
485
431
  # forcing method misssing to be called.
486
432
  # @param [Hash] hash Parameters to be expand and included in command execution
@@ -488,10 +434,82 @@ class Runnable
488
434
  def parse_hash( hash )
489
435
  hash.each do |key, value|
490
436
  # Add the param parsed to command_line_interface
491
- @command_line_interface.add_param(
492
- key.to_s,
493
- value != nil ? value.to_s : nil
494
- )
437
+ @command_line_interface.add_param( key.to_s, value != nil ? value.to_s : nil )
495
438
  end
496
439
  end
440
+
441
+ private
442
+
443
+ def save_log(output_name, line)
444
+ Dir.mkdir( @log_path ) unless Dir.exist?( @log_path )
445
+
446
+ File.open("#{@log_path}/#{self.command}_#{@pid}.log", "a") do |log_file|
447
+ log_file.puts( "[#{Time.new.inspect} || [STD#{output_name.to_s.upcase} || [#{@pid}]] #{line}" )
448
+ end
449
+ end
450
+
451
+ def compose_command
452
+ @command_line_interface ||= Object.const_get( command_style.to_s.capitalize.to_sym ).new
453
+
454
+ [ @command_input.to_s,
455
+ @options.to_s,
456
+ @command_line_interface.parse,
457
+ @command_output.to_s
458
+ ].select do |value|
459
+ !value.to_s.strip.empty?
460
+ end.flatten.select{|x| !x.empty?}
461
+ end
462
+
463
+ def threaded_process(pid, output_threads)
464
+ Thread.new do
465
+ # Wait to get the pid process even if it has finished
466
+ Process.wait( pid, Process::WUNTRACED )
467
+
468
+ # Wait each I/O thread
469
+ output_threads.each { |thread| thread.join }
470
+
471
+ # Get the exit code from command
472
+ exit_status = $?.exitstatus
473
+
474
+ # This instance is finished and we remove it
475
+ self.class.processes.delete( pid )
476
+ @pid = nil
477
+
478
+ # In case of error add an Exception to the @excep_array
479
+ raise SystemCallError.new( exit_status ) if exit_status != 0
480
+ end
481
+ end
482
+
483
+ def threaded_output_processor(output_name, pipes, stream_processors)
484
+ exception_processors = stream_processors.is_a?(Hash) ? stream_processors[:exceptions] : {}
485
+ exception_processors.merge!(self.class.processors[:exceptions] || {})
486
+
487
+ output_processors = stream_processors.is_a?(Hash) ? stream_processors[:outputs] : {}
488
+ output_processors.merge!(self.class.processors[:output] || {})
489
+
490
+ Thread.new do
491
+ pipes[0].close
492
+
493
+ pipes[1].each_line do |line|
494
+ ( output_name == :err ? self.std_err : self.std_out ) << line
495
+
496
+ save_log(output_name, line) if @log_path
497
+
498
+ # Match custom exceptions
499
+ # if we get a positive match, raise the exception
500
+ exception_processors.each do | reg_expr, value |
501
+ raise value.new( line ) if reg_expr =~ line
502
+ end
503
+
504
+ # Match custom outputs
505
+ # if we get a positive match, add it to the outputs array
506
+ output_processors.each do | reg_expr, value |
507
+ @output[value] ||= Array.new
508
+ @output[value] << $1 if reg_expr =~ line
509
+ end
510
+
511
+ end
512
+ end
513
+ end
514
+
497
515
  end
data/runnable.gemspec CHANGED
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{runnable}
8
- s.version = "0.2.4"
8
+ s.version = "0.3.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Rafael García", "Luis Ciudad", "Pedro Navajas", "Javier Aranda"]
12
- s.date = %q{2011-10-27}
12
+ s.date = %q{2012-01-17}
13
13
  s.description = %q{Convert a executable command in a Ruby-like class you are able to start, define params and send signals (like kill, or stop)}
14
14
  s.email = ["rgarcia@nosolosoftware.biz", "lciudad@nosolosoftware.biz", "pnavajas@nosolosoftware.biz", "jaranda@nosolosoftware.biz"]
15
15
  s.extra_rdoc_files = [
@@ -28,10 +28,11 @@ Gem::Specification.new do |s|
28
28
  s.homepage = %q{http://github.com/nosolosoftware/runnable}
29
29
  s.licenses = ["GPL-3"]
30
30
  s.require_paths = ["lib"]
31
- s.rubygems_version = %q{1.6.2}
31
+ s.rubygems_version = %q{1.3.7}
32
32
  s.summary = %q{A Ruby gem for execute and control system commands}
33
33
 
34
34
  if s.respond_to? :specification_version then
35
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
35
36
  s.specification_version = 3
36
37
 
37
38
  if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
metadata CHANGED
@@ -1,86 +1,121 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: runnable
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.4
5
- prerelease:
4
+ version: 0.3.0
5
+ segments:
6
+ - 0
7
+ - 3
8
+ - 0
9
+ prerelease: false
10
+ segments_generated: true
6
11
  platform: ruby
7
12
  authors:
8
13
  - Rafael García
9
14
  - Luis Ciudad
10
15
  - Pedro Navajas
11
16
  - Javier Aranda
12
- autorequire:
17
+ autorequire: !!null
13
18
  bindir: bin
14
19
  cert_chain: []
15
- date: 2011-10-27 00:00:00.000000000 +02:00
16
- default_executable:
20
+ date: 2012-01-17 00:00:00.000000000 +01:00
21
+ default_executable: !!null
17
22
  dependencies:
18
23
  - !ruby/object:Gem::Dependency
19
24
  name: rake
20
- requirement: &21080560 !ruby/object:Gem::Requirement
25
+ requirement: &32400380 !ruby/object:Gem::Requirement
21
26
  none: false
22
27
  requirements:
23
28
  - - ! '>='
24
29
  - !ruby/object:Gem::Version
25
30
  version: 0.8.7
31
+ segments:
32
+ - 0
33
+ - 8
34
+ - 7
35
+ segments_generated: true
26
36
  type: :development
27
37
  prerelease: false
28
- version_requirements: *21080560
38
+ version_requirements: *32400380
29
39
  - !ruby/object:Gem::Dependency
30
40
  name: yard
31
- requirement: &21079240 !ruby/object:Gem::Requirement
41
+ requirement: &32398960 !ruby/object:Gem::Requirement
32
42
  none: false
33
43
  requirements:
34
44
  - - ! '>='
35
45
  - !ruby/object:Gem::Version
36
46
  version: 0.6.8
47
+ segments:
48
+ - 0
49
+ - 6
50
+ - 8
51
+ segments_generated: true
37
52
  type: :development
38
53
  prerelease: false
39
- version_requirements: *21079240
54
+ version_requirements: *32398960
40
55
  - !ruby/object:Gem::Dependency
41
56
  name: rspec
42
- requirement: &21076920 !ruby/object:Gem::Requirement
57
+ requirement: &32397820 !ruby/object:Gem::Requirement
43
58
  none: false
44
59
  requirements:
45
60
  - - ! '>='
46
61
  - !ruby/object:Gem::Version
47
62
  version: 2.5.0
63
+ segments:
64
+ - 2
65
+ - 5
66
+ - 0
67
+ segments_generated: true
48
68
  type: :development
49
69
  prerelease: false
50
- version_requirements: *21076920
70
+ version_requirements: *32397820
51
71
  - !ruby/object:Gem::Dependency
52
72
  name: cucumber
53
- requirement: &21075340 !ruby/object:Gem::Requirement
73
+ requirement: &32396420 !ruby/object:Gem::Requirement
54
74
  none: false
55
75
  requirements:
56
76
  - - ! '>='
57
77
  - !ruby/object:Gem::Version
58
78
  version: 0.10.2
79
+ segments:
80
+ - 0
81
+ - 10
82
+ - 2
83
+ segments_generated: true
59
84
  type: :development
60
85
  prerelease: false
61
- version_requirements: *21075340
86
+ version_requirements: *32396420
62
87
  - !ruby/object:Gem::Dependency
63
88
  name: jeweler
64
- requirement: &21070000 !ruby/object:Gem::Requirement
89
+ requirement: &32388060 !ruby/object:Gem::Requirement
65
90
  none: false
66
91
  requirements:
67
92
  - - ! '>='
68
93
  - !ruby/object:Gem::Version
69
94
  version: 1.6.0
95
+ segments:
96
+ - 1
97
+ - 6
98
+ - 0
99
+ segments_generated: true
70
100
  type: :development
71
101
  prerelease: false
72
- version_requirements: *21070000
102
+ version_requirements: *32388060
73
103
  - !ruby/object:Gem::Dependency
74
104
  name: bluecloth
75
- requirement: &21067180 !ruby/object:Gem::Requirement
105
+ requirement: &32386220 !ruby/object:Gem::Requirement
76
106
  none: false
77
107
  requirements:
78
108
  - - ! '>='
79
109
  - !ruby/object:Gem::Version
80
110
  version: 2.1.0
111
+ segments:
112
+ - 2
113
+ - 1
114
+ - 0
115
+ segments_generated: true
81
116
  type: :development
82
117
  prerelease: false
83
- version_requirements: *21067180
118
+ version_requirements: *32386220
84
119
  description: Convert a executable command in a Ruby-like class you are able to start,
85
120
  define params and send signals (like kill, or stop)
86
121
  email:
@@ -105,7 +140,7 @@ has_rdoc: true
105
140
  homepage: http://github.com/nosolosoftware/runnable
106
141
  licenses:
107
142
  - GPL-3
108
- post_install_message:
143
+ post_install_message: !!null
109
144
  rdoc_options: []
110
145
  require_paths:
111
146
  - lib
@@ -117,17 +152,21 @@ required_ruby_version: !ruby/object:Gem::Requirement
117
152
  version: '0'
118
153
  segments:
119
154
  - 0
120
- hash: -599557484973593353
155
+ segments_generated: true
156
+ hash: -3646317310813273179
121
157
  required_rubygems_version: !ruby/object:Gem::Requirement
122
158
  none: false
123
159
  requirements:
124
160
  - - ! '>='
125
161
  - !ruby/object:Gem::Version
126
162
  version: '0'
163
+ segments:
164
+ - 0
165
+ segments_generated: true
127
166
  requirements: []
128
- rubyforge_project:
129
- rubygems_version: 1.6.2
130
- signing_key:
167
+ rubyforge_project: !!null
168
+ rubygems_version: 1.3.7
169
+ signing_key: !!null
131
170
  specification_version: 3
132
171
  summary: A Ruby gem for execute and control system commands
133
172
  test_files: []