live_console 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/bin/udscat ADDED
@@ -0,0 +1,51 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # This is a client for the unix domain socket version of LiveConsole. It just
4
+ # talks to the socket. It has been included so that you don't have to track
5
+ # down a version of netcat that does this.
6
+
7
+ require 'socket'
8
+
9
+ socket_path = ARGV.first
10
+ if socket_path.nil?
11
+ $stderr.puts "You must supply a path to the socket you want to connect to."
12
+ exit 1
13
+ end
14
+
15
+ client = UNIXSocket.new socket_path
16
+
17
+ $stdin.sync = $stdout.sync = client.sync = true
18
+
19
+ read_thread =
20
+ Thread.new {
21
+ loop {
22
+ begin
23
+ Thread.pass
24
+ $stdout.write client.read_nonblock(1024)
25
+ rescue Errno::EAGAIN, Errno::EINTR => e
26
+ IO.select [client], [], [], 1
27
+ rescue Errno::EOFError, Errno::EPIPE => e
28
+ # nothing
29
+ end
30
+ }
31
+ }
32
+
33
+ Thread.new {
34
+ loop {
35
+ begin
36
+ l = $stdin.read_nonblock(1024)
37
+ rescue Errno::EAGAIN
38
+ retry
39
+ end
40
+
41
+ begin
42
+ client.print l if IO.select [], [client], [], 1
43
+ rescue Errno::EPIPE => e
44
+ $stderr.puts "Other end closed."
45
+ exit 0
46
+ end
47
+ }
48
+ }
49
+
50
+ trap('INT') { exit 0 }
51
+ loop { sleep 1 }
data/doc/README CHANGED
@@ -2,15 +2,16 @@
2
2
 
3
3
  == Summary
4
4
 
5
- LiveConsole is a library for providing IRB over a TCP connection . If you add
6
- it to your application, you can run arbitrary code against your application.
5
+ LiveConsole is a library for providing IRB over a TCP connection or a Unix
6
+ Domain Socket. If you add it to your application, you can run arbitrary code
7
+ against your application.
7
8
  For example, you can:
8
9
  * Inspect the state of a running application
9
10
  * Change the state of the application
10
11
  * Patch code on the fly, without a restart.
11
- * Let anyone on the net 0wn you if you bind to anything other than
12
- localhost. :)
13
- It's useful as a diagnostic tool, a debugging tool, and a way to impress your friends or get those Lisp guys off your back. You know the ones.
12
+ * Let anyone on the net 0wn you if you bind to a public interface. :)
13
+ It's useful as a diagnostic tool, a debugging tool, and a way to impress your
14
+ friends or get those Lisp guys off your back. You know the ones I mean.
14
15
 
15
16
  == Stern Security Warning. Grrr.
16
17
 
@@ -35,14 +36,32 @@ LiveConsole is very easy to use in your own app:
35
36
  require 'rubygems'
36
37
  require 'live_console'
37
38
 
38
- lc = LiveConsole.new 1337 # Creates a LiveConsole on port 1337
39
- # We're not yet listening on the port. We need to start it up:
40
- lc.run # Starts the LiveConsole thread
39
+ # Create a LiveConsole using TCP on port 1337
40
+ lc = LiveConsole.new :socket, :port => 1337
41
+ # We're not yet accepting connections. We need to start it up:
42
+ lc.start # Starts the LiveConsole thread
41
43
  # At this point, users can connect and get an IRB prompt.
42
- lc.stop # Kills the LiveConsole thread
44
+ lc.stop # Kills the LiveConsole thread
43
45
  # Now, no one can connect.
44
46
 
45
- Have a look at doc/lc_example.rb for a brief example of how to use LiveConsole.
47
+ # Create a LiveConsole using a Unix socket in /tmp/live-console.sock
48
+ lc = LiveConsole.new :unix_socket, :path => '/tmp/live-console.sock'
49
+ # As above:
50
+ lc.start
51
+ lc.stop
52
+
53
+ # Have a LiveConsole run code in a binding other than the top-level:
54
+ lc = LiveConsole.new :unix_socket, :path => '/tmp/live-console.sock'
55
+ :bind => binding
56
+ lc.start
57
+ # That will start IRB in the current binding. There is also an accessor:
58
+ lc.bind = binding
59
+ # Of course, you must restart before IRB will see the new binding:
60
+ lc.restart
61
+
62
+ Have a look at doc/lc_example.rb or doc/lc_unix_example.rb for brief examples
63
+ of how to use LiveConsole.
64
+
46
65
  Try just running it:
47
66
 
48
67
  $ ruby doc/lc_example.rb 4000 test
@@ -50,30 +69,54 @@ Try just running it:
50
69
  $ netcat localhost 4000
51
70
  irb(main):001:0> puts 'Wow, magic!'
52
71
 
72
+ $ ruby doc/lc_unix_example.rb /tmp/live-console.sock
73
+ # Then, in a different shell:
74
+ $ udscat /tmp/live-console.sock
75
+ irb(main):001:0> puts 'Words cannot describe the joy I feel.'
76
+
53
77
  You can get creative about it, only starting LiveConsole when there's an
54
78
  unhandled exception in your server, and then calling LiveConsole#stop when
55
79
  you've diagnosed and fixed whatever the problem was.
56
80
 
81
+ Additionally, if you want to run LiveConsole on a server, but run netcat
82
+ locally, you can use SSH port forwarding to avoid having to open LiveConsole
83
+ to the world:
84
+
85
+ ssh -L4000:localhost:4000 you@server
86
+
87
+ Then, locally, you can do
88
+
89
+ netcat localhost 4000
90
+
91
+ and get the remote LiveConsole. man ssh for more details. Of course, this
92
+ only works for the TCP socket mode.
93
+
57
94
  == Bugs
58
95
 
59
96
  LiveConsole lacks many of the niceties of IRB on the console, like Readline
60
97
  support.
61
98
 
62
99
  Typing exit, hitting ^D, or sending signals (like INT or STOP) doesn't work.
63
- Just exit the program you used to connect to it.
100
+ Just exit the program you used to connect to it. This has more to do with the
101
+ program you use to connect to the socket.
102
+
103
+ For TCP connections, there is no authentication support yet, although it is
104
+ planned for the near future. This creates a security risk: anyone that can
105
+ connect to the socket can run arbitrary Ruby code as the user who owns the
106
+ process. In fact, even binding to localhost can be a security issue if you're
107
+ on a box with any untrusted users. If there's a chance you don't know what
108
+ you're doing, avoid using this library. The Unix Domain Socket version is more
109
+ secure, as you can control access via filesystem permissions.
64
110
 
65
- There is no authentication support yet, although it is planned for the near
66
- future. This creates a security risk: anyone that can connect to the socket
67
- can run arbitrary Ruby code as the user who owns the process. In fact, even
68
- binding to localhost can be a security issue if you're on a box with any
69
- untrusted users. If there's a chance you don't know what you're doing, avoid
70
- using this library.
111
+ Only one client can connect at a time. I don't think anyone needs multiple LC
112
+ connections to serve multiple instances of IRB to various clients, but if you
113
+ need it, let me know.
71
114
 
72
115
  The README contains a slur against Lisp guys. Please stop hitting me with that PDP-10 manual. I love your language and the lambda tattoo on your chest.
73
116
 
74
- Other than that, LiveConsole doesn't have any known bugs, but it is alpha
75
- software, so they are likely to be there. Bug reports and patches gratefully
76
- accepted.
117
+ Other than that, LiveConsole doesn't have any known bugs, but it is odd
118
+ software that also monkey-patches IRB, so they are likely to be there. Bug
119
+ reports and patches gratefully accepted.
77
120
 
78
121
  == Credits
79
122
 
data/doc/lc_example.rb CHANGED
@@ -14,14 +14,18 @@ and then in a different terminal, connect to it via netcat or telnet. You can
14
14
  check that the value of $x is exactly what you set it to, and that you're
15
15
  working inside this process, but there's not much to do inside the example
16
16
  script. :)
17
+
17
18
  EOF
18
19
 
19
20
  port = ARGV.first.to_i
20
21
  port = port.zero? ? 3333 : port
21
22
  $x = ARGV[1]
22
23
 
23
- lc = LiveConsole.new port
24
- lc.run
24
+ lc = LiveConsole.new :socket, :port => port, :bind => binding
25
+ lc.start
26
+
27
+ puts "My PID is #{Process.pid}, " \
28
+ "I'm running on port #{port}, and $x = #{$x.inspect}"
25
29
 
26
30
  oldx = $x
27
31
  loop {
@@ -0,0 +1,37 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ require 'live_console'
5
+
6
+ default_path = "/tmp/lc_example_#{Process.uid}.sock"
7
+
8
+ print <<-EOF
9
+ This is a demo program for LiveConsole. It starts a LiveConsole at the
10
+ specified path, and you can connect to it by using netcat or telnet to connect
11
+ to the specified port.
12
+ Usage:
13
+ #{$0} [path_to_socket [value_for_$x]]
14
+ The default path is #{default_path}, and $x is set by default to nil.
15
+ Run this program, and then in a different terminal, connect to it via
16
+ the supplied udscat program or the BSD version of netcat.
17
+ EOF
18
+
19
+ path = ARGV.first
20
+ path = path.nil? ? default_path : path
21
+ $x = ARGV[1]
22
+
23
+ lc = LiveConsole.new :unix_socket, :path => path, :bind => binding
24
+ lc.start
25
+
26
+ puts "My PID is #{Process.pid}, " \
27
+ "I'm running on #{path}, and $x = #{$x.inspect}"
28
+
29
+ oldx = $x
30
+ loop {
31
+ if $x != oldx
32
+ puts "The time is now #{Time.now.strftime('%R:%S')}.",
33
+ "The value of $x changed from #{oldx.inspect} to #{$x.inspect}."
34
+ oldx = $x
35
+ end
36
+ sleep 1
37
+ }
@@ -0,0 +1,27 @@
1
+ class LiveConsole::IOMethods::SocketIO
2
+ DefaultOpts = {
3
+ :host => '127.0.0.1',
4
+ }.freeze
5
+ RequiredOpts = DefaultOpts.keys + [:port]
6
+
7
+ include LiveConsole::IOMethods::IOMethod
8
+
9
+ def start
10
+ @server ||= TCPServer.new host, port
11
+
12
+ begin
13
+ self.raw_input = self.raw_output = server.accept_nonblock
14
+ return true
15
+ rescue Errno::EAGAIN, Errno::ECONNABORTED, Errno::EPROTO,
16
+ Errno::EINTR => e
17
+ select
18
+ retry
19
+ end
20
+ end
21
+
22
+ def stop
23
+ select
24
+ raw_input.close rescue nil
25
+ end
26
+
27
+ end
@@ -0,0 +1,31 @@
1
+ require 'socket'
2
+
3
+ class LiveConsole::IOMethods::UnixSocketIO
4
+ DefaultOpts = {
5
+ :mode => 0600,
6
+ :uid => Process.uid,
7
+ :gid => Process.gid,
8
+ }
9
+ RequiredOpts = DefaultOpts.keys + [:path]
10
+
11
+ include LiveConsole::IOMethods::IOMethod
12
+
13
+ def start
14
+ @server ||= UNIXServer.new path
15
+
16
+ begin
17
+ self.raw_input = self.raw_output = server.accept_nonblock
18
+ raw_input.sync = true
19
+ return true
20
+ rescue Errno::EAGAIN, Errno::ECONNABORTED, Errno::EPROTO,
21
+ Errno::EINTR => e
22
+ select
23
+ retry
24
+ end
25
+ end
26
+
27
+ def stop
28
+ select
29
+ raw_input.close
30
+ end
31
+ end
@@ -0,0 +1,53 @@
1
+ module LiveConsole::IOMethods
2
+ List = []
3
+
4
+ Dir[File.join(File.dirname(__FILE__), 'io_methods', '*.rb')].each { |entry|
5
+ fname = entry.sub /\.rb$/, ''
6
+ classname = File.basename(entry, '.rb').capitalize.
7
+ gsub(/_(\w)/) { $1.upcase }.sub(/io$/i, 'IO').to_sym
8
+ mname = File.basename(fname).sub(/_io$/, '').to_sym
9
+
10
+ autoload classname, fname
11
+ List << mname
12
+
13
+ define_method(mname) {
14
+ const_get classname
15
+ }
16
+ }
17
+ List.freeze
18
+
19
+ extend self
20
+
21
+ module IOMethod
22
+ def initialize(opts)
23
+ self.opts = self.class::DefaultOpts.merge opts
24
+ unless missing_opts.empty?
25
+ raise ArgumentError, "Missing opts for " \
26
+ "#{self.class.name}: #{missing_opts.inspect}"
27
+ end
28
+ end
29
+
30
+ def missing_opts
31
+ self.class::RequiredOpts - opts.keys
32
+ end
33
+
34
+ def self.included(other)
35
+ other.instance_eval {
36
+ readers = [:opts, :raw_input, :raw_output]
37
+ attr_accessor *readers
38
+ private *readers.map { |r| (r.to_s + '=').to_sym }
39
+
40
+ other::RequiredOpts.each { |opt|
41
+ define_method(opt) { opts[opt] }
42
+ }
43
+ }
44
+ end
45
+
46
+ def select
47
+ IO.select [server], [], [], 1 if server
48
+ end
49
+
50
+ private
51
+ attr_accessor :server
52
+ end
53
+ end
data/lib/live_console.rb CHANGED
@@ -5,73 +5,119 @@
5
5
 
6
6
  require 'irb'
7
7
  require 'socket'
8
+ require 'live_console_config'
8
9
 
9
10
  # LiveConsole provides a socket that can be connected to via netcat or telnet
10
11
  # to use to connect to an IRB session inside a running process. It creates a
11
- # thread that listens on the specified address/port, and presents connecting
12
- # clients with an IRB shell. Using this, you can execute code on a running
13
- # instance of a Ruby process to inspect the state or even patch code on the
14
- # fly. There is currently no readline support.
12
+ # thread that listens on the specified address/port or Unix Domain Socket path,
13
+ # and presents connecting clients with an IRB shell. Using this, you can
14
+ # execute code on a running instance of a Ruby process to inspect the state or
15
+ # even patch code on the fly. There is currently no readline support.
15
16
  class LiveConsole
16
17
  include Socket::Constants
18
+ autoload :IOMethods, 'live_console/io_methods'
17
19
 
18
- attr_accessor :tcp_server, :lc_thread
19
- private :tcp_server=, :lc_thread=
20
+ attr_accessor :io_method, :io, :thread, :bind
21
+ private :io_method=, :io=, :thread=
20
22
 
21
23
  # call-seq:
22
- # # Bind a LiveConsole to localhost:3030:
23
- # LiveConsole.new 3030
24
+ # # Bind a LiveConsole to localhost:3030 (only allow clients on this
25
+ # # machine to connect):
26
+ # LiveConsole.new :socket, :port => 3030
24
27
  # # Accept connections from anywhere on port 3030. Ridiculously insecure:
25
- # LiveConsole.new(3030, 'Your.IP.address')
28
+ # LiveConsole.new(:socket, :port => 3030, :host => '0.0.0.0')
29
+ # # Use a Unix Domain Socket (which is more secure) instead:
30
+ # LiveConsole.new(:unix_socket, :path => '/tmp/my_liveconsole.sock',
31
+ # :mode => 0600, :uid => Process.uid, :gid => Process.gid)
32
+ # # By default, the mode is 0600, and the uid and gid are those of the
33
+ # # current process. These three options are for the file's permissions.
34
+ # # You can also supply a binding for IRB's toplevel:
35
+ # LiveConsole.new(:unix_socket,
36
+ # :path => "/tmp/live_console_#{Process.pid}.sock", :bind => binding)
26
37
  #
27
- # Creates a new LiveConsole. You must next call LiveConsole#run when you
28
- # want to spawn the thread to accept connections and run the console.
29
- def initialize(listen_port, listen_addr = '127.0.0.1')
30
- self.tcp_server = TCPServer.new listen_addr, listen_port
31
- end
32
-
33
- # LiveConsole#run spawns a thread to listen for, accept, and provide an IRB
34
- # console to new connections. If a thread is already running, this method
35
- # simply returns false; otherwise, it returns the new thread.
36
- def run
37
- return false if lc_thread
38
- self.lc_thread = Thread.new {
38
+ # Creates a new LiveConsole. You must next call LiveConsole#start when you
39
+ # want to spawn the thread to accept connections and start the console.
40
+ def initialize(io_method, opts = {})
41
+ self.io_method = io_method.to_sym
42
+ self.bind = opts.delete :bind
43
+ unless IOMethods::List.include?(self.io_method)
44
+ raise ArgumentError, "Unknown IO method: #{io_method}"
45
+ end
46
+
47
+ init_io opts
48
+ end
49
+
50
+ # LiveConsole#start spawns a thread to listen for, accept, and provide an
51
+ # IRB console to new connections. If a thread is already running, this
52
+ # method simply returns false; otherwise, it returns the new thread.
53
+ def start
54
+ if thread
55
+ if thread.alive?
56
+ return false
57
+ else
58
+ thread.join
59
+ self.thread = nil
60
+ end
61
+ end
62
+
63
+ self.thread = Thread.new {
39
64
  loop {
40
- socket = nil
41
- begin
42
- Thread.pass
43
- socket = tcp_server.accept_nonblock
44
- io = SocketIOMethod.new(socket)
45
- IRB.start_with_io(io)
46
- rescue Errno::EAGAIN, Errno::ECONNABORTED, Errno::EPROTO,
47
- Errno::EINTR
48
- socket.close rescue nil
49
- IO.select([tcp_server], [], [], 1)
50
-
51
- retry
65
+ Thread.pass
66
+ if io.start
67
+ irb_io = GenericIOMethod.new io.raw_input, io.raw_output
68
+ begin
69
+ IRB.start_with_io(irb_io, bind)
70
+ rescue Errno::EPIPE => e
71
+ io.stop
72
+ end
52
73
  end
53
74
  }
54
75
  }
55
- lc_thread
76
+ thread
56
77
  end
57
78
 
58
79
  # Ends the running thread, if it exists. Returns true if a thread was
59
80
  # running, false otherwise.
60
81
  def stop
61
- if lc_thread
62
- lc_thread.exit
63
- self.lc_thread = nil
82
+ if thread
83
+ if thread == Thread.current
84
+ self.thread = nil
85
+ Thread.current.exit!
86
+ end
87
+
88
+ thread.exit
89
+ if thread.join(0.1).nil?
90
+ thread.exit!
91
+ end
92
+ self.thread = nil
64
93
  true
65
94
  else
66
95
  false
67
96
  end
68
97
  end
69
98
 
99
+ # Restarts. Useful for binding changes. Return value is the same as for
100
+ # LiveConsole#start.
101
+ def restart
102
+ r = lambda { stop; start }
103
+ if thread == Thread.current # An odd case.
104
+ Thread.new &r
105
+ else
106
+ r.call
107
+ end
108
+ end
109
+
110
+ private
111
+
70
112
  def init_irb
71
113
  return if @@irb_inited_already
72
114
  IRB.setup nil
73
115
  @@irb_inited_already = true
74
116
  end
117
+
118
+ def init_io opts
119
+ self.io = IOMethods.send(io_method).new opts
120
+ end
75
121
  end
76
122
 
77
123
  # We need to make a couple of changes to the IRB module to account for using a
@@ -80,7 +126,7 @@ module IRB
80
126
  @inited = false
81
127
 
82
128
  # Overridden a la FXIrb to accomodate our needs.
83
- def IRB.start_with_io(io, &block)
129
+ def IRB.start_with_io(io, bind, &block)
84
130
  unless @inited
85
131
  setup '/dev/null'
86
132
  IRB.parse_opts
@@ -88,7 +134,9 @@ module IRB
88
134
  @inited = true
89
135
  end
90
136
 
91
- irb = Irb.new(nil, io, io)
137
+ bind ||= IRB::Frame.top(1)
138
+ ws = IRB::WorkSpace.new(bind)
139
+ irb = Irb.new(ws, io, io)
92
140
 
93
141
  @CONF[:IRB_RC].call(irb.context) if @CONF[:IRB_RC]
94
142
  @CONF[:MAIN_CONTEXT] = irb.context
@@ -102,7 +150,7 @@ module IRB
102
150
  retry
103
151
  end
104
152
  }
105
- print "\n"
153
+ irb.print "\n"
106
154
  end
107
155
 
108
156
  class Context
@@ -125,32 +173,52 @@ module IRB
125
173
  end
126
174
  end
127
175
 
128
- # The SocketIOMethod is a class that wraps I/O over a socket for IRB.
129
- class SocketIOMethod < IRB::StdioInputMethod
130
- def initialize(socket)
131
- @socket = socket
176
+ # The GenericIOMethod is a class that wraps I/O for IRB.
177
+ class GenericIOMethod < IRB::StdioInputMethod
178
+ # call-seq:
179
+ # GenericIOMethod.new io
180
+ # GenericIOMethod.new input, output
181
+ #
182
+ # Creates a GenericIOMethod, using either a single object for both input
183
+ # and output, or one object for input and another for output.
184
+ def initialize(input, output = nil)
185
+ @input, @output = input, output
132
186
  @line = []
133
187
  @line_no = 0
134
188
  end
135
189
 
190
+ attr_reader :input
191
+ def output
192
+ @output || input
193
+ end
194
+
136
195
  def gets
137
- @socket.print @prompt
138
- @socket.flush
139
- @line[@line_no += 1] = @socket.gets
140
- @socket.flush
196
+ output.print @prompt
197
+ output.flush
198
+ @line[@line_no += 1] = input.gets
199
+ # @io.flush # Not sure this is needed.
141
200
  @line[@line_no]
142
201
  end
143
202
 
144
- # These just pass through to the socket.
145
- %w(eof? close).each { |mname|
146
- define_method(mname) { || @socket.send mname }
147
- }
203
+ # Returns the user input history.
204
+ def lines
205
+ @line.dup
206
+ end
148
207
 
149
208
  def print(*a)
150
- @socket.print *a
209
+ output.print *a
151
210
  end
152
211
 
153
212
  def file_name
154
- @socket.inspect
213
+ input.inspect
214
+ end
215
+
216
+ def eof?
217
+ input.eof?
218
+ end
219
+
220
+ def close
221
+ input.close
222
+ output.close if @output
155
223
  end
156
224
  end
@@ -3,6 +3,7 @@ module LiveConsoleConfig
3
3
  Authors = 'Pete Elmore'
4
4
  Email = 'pete.elmore@gmail.com'
5
5
  PkgName = 'live_console'
6
- Version = '0.1.0'
6
+ Version = '0.2.0'
7
7
  URL = 'http://debu.gs/live-console'
8
+ Project = 'live-console'
8
9
  end
metadata CHANGED
@@ -1,52 +1,67 @@
1
1
  --- !ruby/object:Gem::Specification
2
- rubygems_version: 0.9.4
3
- specification_version: 1
4
2
  name: live_console
5
3
  version: !ruby/object:Gem::Version
6
- version: 0.1.0
7
- date: 2007-10-19 00:00:00 -07:00
8
- summary: A library to support adding a console to your running application.
9
- require_paths:
10
- - lib
11
- email: pete.elmore@gmail.com
12
- homepage: http://debu.gs/live-console
13
- rubyforge_project:
14
- description:
15
- autorequire: live_console
16
- default_executable:
17
- bindir: bin
18
- has_rdoc: true
19
- required_ruby_version: !ruby/object:Gem::Version::Requirement
20
- requirements:
21
- - - ">"
22
- - !ruby/object:Gem::Version
23
- version: 0.0.0
24
- version:
4
+ version: 0.2.0
25
5
  platform: ruby
26
- signing_key:
27
- cert_chain:
28
- post_install_message:
29
6
  authors:
30
7
  - Pete Elmore
31
- files:
32
- - doc/LICENSE
33
- - doc/README
34
- - doc/lc_example.rb
35
- - lib/live_console.rb
36
- - lib/live_console_config.rb
37
- test_files: []
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
38
11
 
39
- rdoc_options: []
12
+ date: 2008-10-15 00:00:00 -07:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description:
17
+ email: pete.elmore@gmail.com
18
+ executables:
19
+ - udscat
20
+ extensions: []
40
21
 
41
22
  extra_rdoc_files:
42
- - doc/README
23
+ - doc/lc_example.rb
43
24
  - doc/LICENSE
25
+ - doc/README
26
+ - doc/lc_unix_example.rb
27
+ files:
28
+ - bin/udscat
44
29
  - doc/lc_example.rb
45
- executables: []
46
-
47
- extensions: []
30
+ - doc/LICENSE
31
+ - doc/README
32
+ - doc/lc_unix_example.rb
33
+ - lib/live_console_config.rb
34
+ - lib/live_console.rb
35
+ - lib/live_console
36
+ - lib/live_console/io_methods
37
+ - lib/live_console/io_methods/socket_io.rb
38
+ - lib/live_console/io_methods/unix_socket_io.rb
39
+ - lib/live_console/io_methods.rb
40
+ has_rdoc: true
41
+ homepage: http://debu.gs/live-console
42
+ post_install_message:
43
+ rdoc_options: []
48
44
 
45
+ require_paths:
46
+ - lib
47
+ required_ruby_version: !ruby/object:Gem::Requirement
48
+ requirements:
49
+ - - ">="
50
+ - !ruby/object:Gem::Version
51
+ version: "0"
52
+ version:
53
+ required_rubygems_version: !ruby/object:Gem::Requirement
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ version: "0"
58
+ version:
49
59
  requirements: []
50
60
 
51
- dependencies: []
61
+ rubyforge_project: live-console
62
+ rubygems_version: 1.3.0
63
+ signing_key:
64
+ specification_version: 2
65
+ summary: A library to support adding a console to your running application.
66
+ test_files: []
52
67