irb-history 1.0.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/LICENSE +16 -0
- data/README +63 -0
- data/Rakefile +61 -0
- data/THANKS +5 -0
- data/bin/irb-history-server +79 -0
- data/lib/irb/history.rb +5 -0
- data/lib/irb/history/base.rb +26 -0
- data/lib/irb/history/client.rb +36 -0
- data/lib/irb/history/server.rb +95 -0
- metadata +62 -0
data/LICENSE
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
Copyright (c) 2005 Sam Stephenson
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
of this software and associated documentation files (the "Software"), to deal
|
5
|
+
in the Software without restriction, including without limitation the rights
|
6
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
+
copies of the Software, and to permit persons to whom the Software is
|
8
|
+
furnished to do so, subject to the following conditions:
|
9
|
+
|
10
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
11
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
12
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
13
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
14
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
15
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
16
|
+
SOFTWARE.
|
data/README
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
= irb-history
|
2
|
+
|
3
|
+
irb-history gives IRB <b>persistent, shared Readline history</b> by way of
|
4
|
+
Distributed Ruby (DRb). What does that mean?
|
5
|
+
|
6
|
+
==== Persistent
|
7
|
+
|
8
|
+
<tt>irb-history-server</tt> stores its history in YAML in a file of your
|
9
|
+
choice (the default is <tt>~/.irb_history</tt>).
|
10
|
+
|
11
|
+
==== Shared
|
12
|
+
|
13
|
+
Load the irb-history client in your <tt>~/.irbrc</tt>, and you'll instantly
|
14
|
+
have access to the irb-history store. Every line you type is sent to the
|
15
|
+
server and will appear in other clients' histories immediately.
|
16
|
+
|
17
|
+
Because irb-history uses DRb, you can share your history with other IRB
|
18
|
+
sessions:
|
19
|
+
|
20
|
+
* on the same computer
|
21
|
+
* on other computers on your local network
|
22
|
+
* on computers connected to the Internet (fun, but not recommended :))
|
23
|
+
|
24
|
+
=== Installation and usage
|
25
|
+
|
26
|
+
It's a simple process:
|
27
|
+
|
28
|
+
1. <b>Install the gem</b>.
|
29
|
+
$ gem install irb-history
|
30
|
+
|
31
|
+
2. <b>Start a history server</b> listening on <tt>127.0.0.1</tt>,
|
32
|
+
port <tt>26501</tt> (see the {irb-history-server
|
33
|
+
documentation}[link:files/bin/irb-history-server.html] for more options).
|
34
|
+
$ irb-history-server -d
|
35
|
+
|
36
|
+
Note: If you wish to use irb-history on a network, you'll need to pass
|
37
|
+
the <tt>-h</tt> flag with an appropriate address to listen on.
|
38
|
+
|
39
|
+
3. <b>Add three lines to your <tt>~/.irbrc</tt></b>.
|
40
|
+
require 'rubygems'
|
41
|
+
require 'irb/history'
|
42
|
+
IRB::History.start_client
|
43
|
+
This connects to the history server on <tt>127.0.0.1</tt>, port
|
44
|
+
<tt>26501</tt>. If you need to specify a different host and/or port, just
|
45
|
+
pass a DRb URI to <tt>start_client</tt>. For example:
|
46
|
+
IRB::History.start_client 'druby://galt:4000'
|
47
|
+
connects to the history server on host <tt>galt</tt>, port <tt>4000</tt>.
|
48
|
+
|
49
|
+
=== Source code
|
50
|
+
|
51
|
+
Check out the darcs[http://darcs.net/] repository:
|
52
|
+
|
53
|
+
$ darcs get http://dev.conio.net/repos/irb-history
|
54
|
+
|
55
|
+
=== License
|
56
|
+
|
57
|
+
irb-history is freely distributable under the terms of a {MIT-style
|
58
|
+
license}[link:files/LICENSE.html].
|
59
|
+
|
60
|
+
=== Author
|
61
|
+
|
62
|
+
Sam Stephenson <{sam@conio.net}[mailto:sam@conio.net]>
|
63
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'rake/rdoctask'
|
3
|
+
require 'rake/gempackagetask'
|
4
|
+
|
5
|
+
class String
|
6
|
+
def unquote
|
7
|
+
self.gsub /^(['"])(.*)\1$/, '\2'
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
PKG_NAME = 'irb-history'
|
12
|
+
PKG_VERSION = '1.0.0'
|
13
|
+
PKG_DESCRIPTION = 'Persistent, shared IRB Readline history'
|
14
|
+
PKG_FILE_NAME = "#{PKG_NAME}-#{PKG_VERSION}"
|
15
|
+
PKG_DESTINATION = "pkg/#{PKG_NAME}"
|
16
|
+
PKG_AUTHOR = 'Sam Stephenson'
|
17
|
+
PKG_AUTHOR_EMAIL = 'sam@conio.net'
|
18
|
+
PKG_DOC_DIR = 'rdoc'
|
19
|
+
|
20
|
+
task :default => [:rdoc, :package]
|
21
|
+
|
22
|
+
SOURCE_FILES = FileList[
|
23
|
+
'[A-Z]*',
|
24
|
+
'bin/**',
|
25
|
+
'lib/**/*.rb'
|
26
|
+
].to_a
|
27
|
+
|
28
|
+
RDOC_FILES = SOURCE_FILES - %w(Rakefile)
|
29
|
+
|
30
|
+
desc 'Generate documentation'
|
31
|
+
rdoc = Rake::RDocTask.new do |rd|
|
32
|
+
rd.main = 'README'
|
33
|
+
rd.title = PKG_NAME
|
34
|
+
rd.rdoc_dir = PKG_DOC_DIR
|
35
|
+
rd.options += %w(--inline-source --line-numbers)
|
36
|
+
rd.rdoc_files.include RDOC_FILES
|
37
|
+
end
|
38
|
+
|
39
|
+
spec = Gem::Specification.new do |s|
|
40
|
+
s.name = PKG_NAME
|
41
|
+
s.version = PKG_VERSION
|
42
|
+
s.summary = PKG_DESCRIPTION
|
43
|
+
s.description = PKG_DESCRIPTION
|
44
|
+
s.author = PKG_AUTHOR
|
45
|
+
s.email = PKG_AUTHOR_EMAIL
|
46
|
+
|
47
|
+
s.files = SOURCE_FILES
|
48
|
+
s.bindir = 'bin'
|
49
|
+
s.require_path = 'lib'
|
50
|
+
s.executables = %w(irb-history-server)
|
51
|
+
|
52
|
+
s.has_rdoc = true
|
53
|
+
s.rdoc_options = rdoc.option_list.map {|o| o.unquote}
|
54
|
+
s.extra_rdoc_files = RDOC_FILES
|
55
|
+
end
|
56
|
+
|
57
|
+
Rake::GemPackageTask.new(spec) do |pkg|
|
58
|
+
end
|
59
|
+
|
60
|
+
desc 'Removes documentation and package files'
|
61
|
+
task :clean => [:clobber_rdoc, :clobber_package]
|
data/THANKS
ADDED
@@ -0,0 +1,79 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# = irb-history-server
|
4
|
+
#
|
5
|
+
# Manages an irb-history YAML store and starts a DRb service for irb-history
|
6
|
+
# clients.
|
7
|
+
#
|
8
|
+
# Usage: <tt>irb-history-server [options]</tt>
|
9
|
+
#
|
10
|
+
# -p, --port=port listen on the specified port
|
11
|
+
# (default: 26501)
|
12
|
+
# -h, --host=host bind to the specified host
|
13
|
+
# (default: "127.0.0.1")
|
14
|
+
# -f, --filename=filename use the specified history file
|
15
|
+
# (default: ~/.irb_history)
|
16
|
+
# -d, --daemon make irb-history-server run as a daemon
|
17
|
+
|
18
|
+
begin
|
19
|
+
require 'rubygems'
|
20
|
+
require 'irb/history'
|
21
|
+
rescue LoadError
|
22
|
+
$:.unshift File.join(File.dirname(__FILE__), '..', 'lib')
|
23
|
+
require 'irb/history'
|
24
|
+
end
|
25
|
+
|
26
|
+
require 'optparse'
|
27
|
+
|
28
|
+
OPTIONS = {
|
29
|
+
:port => IRB::History::DEFAULT_PORT,
|
30
|
+
:host => IRB::History::DEFAULT_HOST,
|
31
|
+
:file => IRB::History::DEFAULT_FILE,
|
32
|
+
:fork => false
|
33
|
+
}
|
34
|
+
|
35
|
+
SCRIPT_NAME = File.basename(__FILE__)
|
36
|
+
|
37
|
+
ARGV.options do |opts|
|
38
|
+
opts.banner = "Usage: #{SCRIPT_NAME} [options]"
|
39
|
+
|
40
|
+
opts.separator ''
|
41
|
+
|
42
|
+
opts.on('-p', '--port=port', Integer,
|
43
|
+
"listen on the specified port",
|
44
|
+
"(default: #{OPTIONS[:port]})") {|OPTIONS[:port]|}
|
45
|
+
opts.on('-h', '--host=host', String,
|
46
|
+
"bind to the specified host",
|
47
|
+
"(default: #{OPTIONS[:host].inspect})") {|OPTIONS[:host]|}
|
48
|
+
opts.on('-f', '--filename=filename', String,
|
49
|
+
"use the specified history file",
|
50
|
+
"(default: #{OPTIONS[:file]})") {|OPTIONS[:file]|}
|
51
|
+
opts.on('-d', '--daemon',
|
52
|
+
"make #{SCRIPT_NAME} run as a daemon") {|OPTIONS[:fork]|}
|
53
|
+
|
54
|
+
opts.separator ''
|
55
|
+
|
56
|
+
opts.on(nil, '--help', 'show this help message') {puts opts; exit}
|
57
|
+
|
58
|
+
opts.parse!
|
59
|
+
end
|
60
|
+
|
61
|
+
uri = "druby://#{OPTIONS[:host]}:#{OPTIONS[:port]}"
|
62
|
+
puts "*** #{SCRIPT_NAME} starting on #{uri}"
|
63
|
+
puts "*** history file: #{OPTIONS[:file]}"
|
64
|
+
|
65
|
+
if OPTIONS[:fork]
|
66
|
+
exit if fork
|
67
|
+
Process.setsid
|
68
|
+
exit if fork
|
69
|
+
Dir.chdir '/'
|
70
|
+
[STDIN, STDOUT, STDERR].each {|io| io.reopen('/dev/null', 'r+')}
|
71
|
+
else
|
72
|
+
trap :INT do
|
73
|
+
puts "*** #{SCRIPT_NAME} exiting"
|
74
|
+
exit!
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
IRB::History.start_server uri, OPTIONS[:file]
|
79
|
+
DRb.thread.join
|
data/lib/irb/history.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
module IRB #:nododc:
|
2
|
+
module History
|
3
|
+
DEFAULT_HOST = '127.0.0.1'
|
4
|
+
DEFAULT_PORT = 26501
|
5
|
+
DEFAULT_URI = "druby://#{DEFAULT_HOST}:#{DEFAULT_PORT}"
|
6
|
+
DEFAULT_FILE = '~/.irb_history'
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
module Kernel
|
11
|
+
# A Ruby-ized realization of the K combinator, courtesy of Mikael Brockman.
|
12
|
+
#
|
13
|
+
# def foo
|
14
|
+
# returning values = [] do
|
15
|
+
# values << 'bar'
|
16
|
+
# values << 'baz'
|
17
|
+
# end
|
18
|
+
# end
|
19
|
+
#
|
20
|
+
# foo # => ['bar', 'baz']
|
21
|
+
#
|
22
|
+
def returning(value)
|
23
|
+
yield
|
24
|
+
value
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'base')
|
2
|
+
|
3
|
+
module IRB #:nodoc:
|
4
|
+
module History
|
5
|
+
# Reconfigures a running IRB session to use the given remote history
|
6
|
+
# service specified by +uri+, initially retrieving +lines_to_recall+
|
7
|
+
# lines of history.
|
8
|
+
#
|
9
|
+
# Note: This method overrides +gets+ in IRB::ReadlineInputMethod; it
|
10
|
+
# can't be "stopped," and you shouldn't call it more than once.
|
11
|
+
#
|
12
|
+
def self.start_client(uri = DEFAULT_URI, lines_to_recall = 100)
|
13
|
+
require 'drb'
|
14
|
+
|
15
|
+
DRb.start_service
|
16
|
+
history = DRbObject.new nil, uri
|
17
|
+
|
18
|
+
IRB::ReadlineInputMethod.instance_eval do
|
19
|
+
alias_method :old_gets, :gets
|
20
|
+
|
21
|
+
define_method :gets do
|
22
|
+
returning old_gets do
|
23
|
+
line = Readline::HISTORY[-1]
|
24
|
+
history.remember line unless @eof rescue nil
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
Readline::HISTORY.push *history.recall(lines_to_recall)
|
30
|
+
|
31
|
+
at_exit {history.unsubscribe_from Readline::HISTORY} if
|
32
|
+
history.subscribe_to Readline::HISTORY
|
33
|
+
rescue
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
require 'drb'
|
2
|
+
require 'yaml'
|
3
|
+
|
4
|
+
require File.join(File.dirname(__FILE__), 'base')
|
5
|
+
|
6
|
+
module IRB #:nodoc:
|
7
|
+
module History
|
8
|
+
class Server
|
9
|
+
attr_accessor :service
|
10
|
+
|
11
|
+
# Creates a new Server with the YAML history store file specified
|
12
|
+
# by +filename+.
|
13
|
+
def initialize(filename)
|
14
|
+
@filename = File.expand_path(filename)
|
15
|
+
@subscriptions = []
|
16
|
+
@mutex = Mutex.new
|
17
|
+
load
|
18
|
+
end
|
19
|
+
|
20
|
+
# Returns the number of lines in the history store.
|
21
|
+
def length
|
22
|
+
@store.length
|
23
|
+
end
|
24
|
+
|
25
|
+
# Stores the given +values+ in the history store, saves the history
|
26
|
+
# store to disk, and notifies any subscribers of the added lines.
|
27
|
+
def remember(*values)
|
28
|
+
@mutex.synchronize do
|
29
|
+
@store += values
|
30
|
+
notify_subscriptions_with *values
|
31
|
+
save
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# Returns the last +limit+ history lines from the history store. If
|
36
|
+
# +limit+ is 0 (the default value), a copy of the entire history
|
37
|
+
# store is returned.
|
38
|
+
def recall(limit = 0)
|
39
|
+
@mutex.synchronize do
|
40
|
+
limit = length if limit > length
|
41
|
+
@store[-limit..-1] || []
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
# Subscribes to the given +readline_history+ (which can be any object
|
46
|
+
# that responds to +push+, but is intended to be used with the
|
47
|
+
# Readline::HISTORY object). When new history lines are added, they'll
|
48
|
+
# be pushed onto subscriptions.
|
49
|
+
def subscribe_to(readline_history)
|
50
|
+
@subscriptions |= [readline_history]
|
51
|
+
true
|
52
|
+
end
|
53
|
+
|
54
|
+
# Removes the given +readline_history+ object from the subscription
|
55
|
+
# list. This should be called from +at_exit+ in history clients.
|
56
|
+
def unsubscribe_from(readline_history)
|
57
|
+
@subscriptions -= [readline_history]
|
58
|
+
true
|
59
|
+
end
|
60
|
+
|
61
|
+
protected
|
62
|
+
def load
|
63
|
+
@store = YAML.load_file(@filename) rescue []
|
64
|
+
end
|
65
|
+
|
66
|
+
def save
|
67
|
+
File.open(@filename, 'w+') {|file| file << YAML.dump(@store)}
|
68
|
+
end
|
69
|
+
|
70
|
+
def notify_subscriptions_with(*values)
|
71
|
+
@subscriptions.each do |readline_history|
|
72
|
+
Thread.new do
|
73
|
+
readline_history.push *values rescue nil or
|
74
|
+
unsubscribe_from readline_history
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
# Starts a Server on the given +uri+ and using the YAML history
|
81
|
+
# file specified by +store_path+. The Server object is instantiated,
|
82
|
+
# a DRb service is started on it, and the Server object is returned.
|
83
|
+
# The DRb service object is accessible via Server#service.
|
84
|
+
def self.start_server(uri = DEFAULT_URI, store_path = DEFAULT_FILE)
|
85
|
+
returning server = Server.new(store_path) do
|
86
|
+
server.service = DRb.start_service uri, server
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
if __FILE__ == $0
|
93
|
+
IRB::History.start_server *ARGV
|
94
|
+
DRb.thread.join
|
95
|
+
end
|
metadata
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
rubygems_version: 0.8.10
|
3
|
+
specification_version: 1
|
4
|
+
name: irb-history
|
5
|
+
version: !ruby/object:Gem::Version
|
6
|
+
version: 1.0.0
|
7
|
+
date: 2005-06-17
|
8
|
+
summary: "Persistent, shared IRB Readline history"
|
9
|
+
require_paths:
|
10
|
+
- lib
|
11
|
+
email: sam@conio.net
|
12
|
+
homepage:
|
13
|
+
rubyforge_project:
|
14
|
+
description: "Persistent, shared IRB Readline history"
|
15
|
+
autorequire:
|
16
|
+
default_executable:
|
17
|
+
bindir: bin
|
18
|
+
has_rdoc: true
|
19
|
+
required_ruby_version: !ruby/object:Gem::Version::Requirement
|
20
|
+
requirements:
|
21
|
+
-
|
22
|
+
- ">"
|
23
|
+
- !ruby/object:Gem::Version
|
24
|
+
version: 0.0.0
|
25
|
+
version:
|
26
|
+
platform: ruby
|
27
|
+
authors:
|
28
|
+
- Sam Stephenson
|
29
|
+
files:
|
30
|
+
- LICENSE
|
31
|
+
- Rakefile
|
32
|
+
- README
|
33
|
+
- THANKS
|
34
|
+
- bin/irb-history-server
|
35
|
+
- lib/irb/history.rb
|
36
|
+
- lib/irb/history/server.rb
|
37
|
+
- lib/irb/history/client.rb
|
38
|
+
- lib/irb/history/base.rb
|
39
|
+
test_files: []
|
40
|
+
rdoc_options:
|
41
|
+
- "--inline-source"
|
42
|
+
- "--line-numbers"
|
43
|
+
- "--main"
|
44
|
+
- README
|
45
|
+
- "--title"
|
46
|
+
- irb-history
|
47
|
+
- "-T"
|
48
|
+
- html
|
49
|
+
extra_rdoc_files:
|
50
|
+
- LICENSE
|
51
|
+
- README
|
52
|
+
- THANKS
|
53
|
+
- bin/irb-history-server
|
54
|
+
- lib/irb/history.rb
|
55
|
+
- lib/irb/history/server.rb
|
56
|
+
- lib/irb/history/client.rb
|
57
|
+
- lib/irb/history/base.rb
|
58
|
+
executables:
|
59
|
+
- irb-history-server
|
60
|
+
extensions: []
|
61
|
+
requirements: []
|
62
|
+
dependencies: []
|