live_console 0.1.0 → 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.
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