ripl-readline-em 0.1.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/.gemspec +25 -0
- data/LICENSE.txt +22 -0
- data/README.rdoc +34 -0
- data/Rakefile +35 -0
- data/lib/readline/callback.rb +74 -0
- data/lib/readline_cb.rb +37 -0
- data/lib/ripl/readline/em.rb +96 -0
- metadata +101 -0
data/.gemspec
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require 'rubygems' unless Object.const_defined?(:Gem)
|
3
|
+
$:.push File.dirname(__FILE__) + "/lib"
|
4
|
+
require 'ripl/readline/em'
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = "ripl-readline-em"
|
8
|
+
s.version = Ripl::Readline::Em::VERSION
|
9
|
+
s.authors = ["Patrick Mahoney"]
|
10
|
+
s.email = "pat@polycrystal.org"
|
11
|
+
s.homepage = "http://github.com/pmahoney/ripl-readline-em"
|
12
|
+
s.summary = "A ripl plugin to run readline within eventmachine"
|
13
|
+
s.description = "Run EventMachine code in a ripl shell asynchronously with readline editing and completion"
|
14
|
+
s.required_rubygems_version = ">= 1.3.6"
|
15
|
+
|
16
|
+
s.add_dependency 'ripl', '>= 0.4.2'
|
17
|
+
s.add_dependency 'eventmachine'
|
18
|
+
s.add_dependency 'ffi'
|
19
|
+
|
20
|
+
s.add_development_dependency 'bacon', '>= 1.1.0'
|
21
|
+
|
22
|
+
s.files = Dir.glob(%w[lib/**/*.rb [A-Z]*.{txt,rdoc}]) + %w{Rakefile .gemspec}
|
23
|
+
s.extra_rdoc_files = ["README.rdoc", "LICENSE.txt"]
|
24
|
+
s.license = 'MIT'
|
25
|
+
end
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
The MIT LICENSE
|
2
|
+
|
3
|
+
Copyright (c) 2011 Patrick Mahoney
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
== Description
|
2
|
+
|
3
|
+
Run EventMachine code in a ripl shell asynchronously with readline
|
4
|
+
editing and completion. Uses FFI to access the alternate Readline
|
5
|
+
callback interface.
|
6
|
+
|
7
|
+
== Install
|
8
|
+
Install the gem with:
|
9
|
+
|
10
|
+
gem install ripl-readline-em
|
11
|
+
|
12
|
+
== Usage
|
13
|
+
|
14
|
+
require 'ripl/readline/em'
|
15
|
+
|
16
|
+
EventMachine.run do
|
17
|
+
EventMachine.add_periodic_timer(2) do
|
18
|
+
# example writing output while line is being edited
|
19
|
+
puts "#{Time.now}"
|
20
|
+
Readline.refresh_line
|
21
|
+
end
|
22
|
+
|
23
|
+
Ripl.start # exiting ripl shell shuts down EventMachine
|
24
|
+
end
|
25
|
+
|
26
|
+
Writing output to stdout writes over the current input line. A call
|
27
|
+
to Readline.refresh_line fixes things up, but a copy of the prompt and
|
28
|
+
any input text follows along with the line of output. I suspect this
|
29
|
+
isn't the best way...
|
30
|
+
|
31
|
+
== Todo
|
32
|
+
|
33
|
+
Improve technique of being able to write output without messing up the
|
34
|
+
input line.
|
data/Rakefile
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'fileutils'
|
3
|
+
|
4
|
+
def gemspec
|
5
|
+
@gemspec ||= eval(File.read('.gemspec'), binding, '.gemspec')
|
6
|
+
end
|
7
|
+
|
8
|
+
desc "Build the gem"
|
9
|
+
task :gem => :gemspec do
|
10
|
+
sh "gem build .gemspec"
|
11
|
+
FileUtils.mkdir_p 'pkg'
|
12
|
+
FileUtils.mv "#{gemspec.name}-#{gemspec.version}.gem", 'pkg'
|
13
|
+
end
|
14
|
+
|
15
|
+
desc "Install the gem locally"
|
16
|
+
task :install => :gem do
|
17
|
+
sh %{gem install pkg/#{gemspec.name}-#{gemspec.version}}
|
18
|
+
end
|
19
|
+
|
20
|
+
desc "Generate the gemspec"
|
21
|
+
task :generate do
|
22
|
+
puts gemspec.to_ruby
|
23
|
+
end
|
24
|
+
|
25
|
+
desc "Validate the gemspec"
|
26
|
+
task :gemspec do
|
27
|
+
gemspec.validate
|
28
|
+
end
|
29
|
+
|
30
|
+
desc 'Run tests'
|
31
|
+
task :test do |t|
|
32
|
+
sh 'bacon -q -Ilib -I. test/**_test.rb'
|
33
|
+
end
|
34
|
+
|
35
|
+
task :default => :test
|
@@ -0,0 +1,74 @@
|
|
1
|
+
require 'ffi'
|
2
|
+
|
3
|
+
module Readline
|
4
|
+
# An alternate, callback-based interface to Readline for use in a
|
5
|
+
# larger event loop.
|
6
|
+
#
|
7
|
+
# Used FFI for access to the Readline C library. The Readline
|
8
|
+
# module (Ruby core) is extended with this module.
|
9
|
+
#
|
10
|
+
# See http://cnswww.cns.cwru.edu/php/chet/readline/readline.html#SEC41
|
11
|
+
module Callback
|
12
|
+
extend FFI::Library
|
13
|
+
|
14
|
+
ffi_lib 'readline'
|
15
|
+
|
16
|
+
callback :rl_vcpfunc_t, [:string], :void
|
17
|
+
attach_function :rl_callback_handler_install, [:string, :rl_vcpfunc_t], :void
|
18
|
+
attach_function :rl_callback_read_char, [], :void
|
19
|
+
attach_function :rl_callback_handler_remove, [], :void
|
20
|
+
|
21
|
+
# as-is functions
|
22
|
+
|
23
|
+
attach_function :set_prompt, :rl_set_prompt, [:string], :int
|
24
|
+
|
25
|
+
# Set up the terminal for readline I/O and display the initial
|
26
|
+
# expanded value of prompt. Save the value of `block` to call when a
|
27
|
+
# complete line of input has been entered.
|
28
|
+
#
|
29
|
+
# A reference to the handler is saved in an instance variable so
|
30
|
+
# that it will not be garbage collected. Subsequent calls to
|
31
|
+
# #handler_install will displace this reference. A call to
|
32
|
+
# #handler_remove will remove the reference.
|
33
|
+
#
|
34
|
+
# @param [String] prompt
|
35
|
+
#
|
36
|
+
# @yield [String] a handler taking the text of the line as the sole
|
37
|
+
# argument, called when a complete line of input has been entered.
|
38
|
+
def callback_handler_install(prompt = nil, &block)
|
39
|
+
raise ArgumentError, 'block is required' unless block
|
40
|
+
@rl_callback_handler = block
|
41
|
+
rl_callback_handler_install(prompt, block)
|
42
|
+
end
|
43
|
+
|
44
|
+
# When keyboard input is available (determined by, e.g. calling
|
45
|
+
# select on $stdin), this method should be called. If that
|
46
|
+
# character completes the line, the block registered by
|
47
|
+
# #callback_handler_install will be called. Before calling the
|
48
|
+
# handler function, the terminal settings are reset to the values
|
49
|
+
# they had before calling #callback_handler_install. If the
|
50
|
+
# handler function returns, the terminal settings are modified for
|
51
|
+
# Readline's use again. EOF is indicated by calling handler with a
|
52
|
+
# NULL line.
|
53
|
+
def callback_read_char
|
54
|
+
$stderr.puts "reading char"
|
55
|
+
rl_callback_read_char
|
56
|
+
end
|
57
|
+
|
58
|
+
# Restore the terminal to its initial state and remove the line
|
59
|
+
# handler. This may be called from within a callback as well as
|
60
|
+
# independently. If the handler installed by #handler_install does
|
61
|
+
# not exit the program, either this function or the function
|
62
|
+
# referred to by the value of rl_deprep_term_function (not sure what
|
63
|
+
# that translates to in Ruby) should be called before the program
|
64
|
+
# exits to reset the terminal settings.
|
65
|
+
def callback_handler_remove
|
66
|
+
rl_callback_handler_remove
|
67
|
+
@rl_callback_handler = nil
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
module Readline
|
73
|
+
extend Callback
|
74
|
+
end
|
data/lib/readline_cb.rb
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'readline/alt'
|
2
|
+
|
3
|
+
module Readline::Alt::Demo
|
4
|
+
class << self
|
5
|
+
# Demonstration method to read a line of input using the callback
|
6
|
+
# functions rather than a direct call to Readline#readline.
|
7
|
+
def readline(prompt = nil)
|
8
|
+
readline_string = nil
|
9
|
+
|
10
|
+
Readline.handler_install(prompt) do |str|
|
11
|
+
readline_string = str
|
12
|
+
end
|
13
|
+
|
14
|
+
begin
|
15
|
+
Readline.read_char until readline_string
|
16
|
+
ensure
|
17
|
+
Readline.handler_remove
|
18
|
+
end
|
19
|
+
|
20
|
+
readline_string
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
#line = Readline::Alt::Demo.readline('> ')
|
26
|
+
#puts "READ A LINE::: #{line.inspect}"
|
27
|
+
|
28
|
+
require 'ripl/readline/em'
|
29
|
+
|
30
|
+
EventMachine.run do
|
31
|
+
EventMachine.add_periodic_timer(2) do
|
32
|
+
puts "#{Time.now} alive!"
|
33
|
+
Readline.refresh_line
|
34
|
+
end
|
35
|
+
|
36
|
+
Ripl.start
|
37
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
require 'eventmachine'
|
2
|
+
require 'readline/callback'
|
3
|
+
require 'ripl'
|
4
|
+
require 'ripl/readline'
|
5
|
+
|
6
|
+
module Ripl
|
7
|
+
module Readline
|
8
|
+
module Em
|
9
|
+
module InputHandler
|
10
|
+
def notify_readable
|
11
|
+
$stderr.puts "is readable"
|
12
|
+
::Readline.callback_read_char
|
13
|
+
$stderr.puts "done"
|
14
|
+
end
|
15
|
+
|
16
|
+
def unbind
|
17
|
+
$stderr.puts "unbind!"
|
18
|
+
::Readline.callback_handler_remove
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
module Ripl
|
26
|
+
module Readline
|
27
|
+
module Em
|
28
|
+
VERSION = '0.1.0'
|
29
|
+
|
30
|
+
def get_input
|
31
|
+
history << @input
|
32
|
+
@input
|
33
|
+
end
|
34
|
+
|
35
|
+
def redisplay
|
36
|
+
::Readline.set_prompt(Ripl.shell.prompt)
|
37
|
+
::Readline.refresh_line
|
38
|
+
end
|
39
|
+
|
40
|
+
def handle_line(line)
|
41
|
+
catch(:normal_exit) do
|
42
|
+
catch(:ripl_exit) do
|
43
|
+
throw :ripl_exit unless line # line = nil implies EOF
|
44
|
+
|
45
|
+
$stderr.puts "have line #{line}"
|
46
|
+
|
47
|
+
Ripl.shell.input = line
|
48
|
+
Ripl.shell.loop_once
|
49
|
+
redisplay
|
50
|
+
throw :normal_exit
|
51
|
+
end
|
52
|
+
|
53
|
+
# If we got here, it means :ripl_exit was caught
|
54
|
+
::Readline.callback_handler_remove
|
55
|
+
after_loop
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def loop_override
|
60
|
+
before_loop
|
61
|
+
|
62
|
+
::Readline.callback_handler_install do |line|
|
63
|
+
EventMachine.next_tick { handle_line(line) }
|
64
|
+
end
|
65
|
+
|
66
|
+
# is hardcoded $stdin always appropriate?
|
67
|
+
conn = EventMachine.watch $stdin, InputHandler
|
68
|
+
conn.notify_readable = true
|
69
|
+
|
70
|
+
redisplay
|
71
|
+
end
|
72
|
+
|
73
|
+
def before_loop
|
74
|
+
super
|
75
|
+
trap('SIGINT') { handle_interrupt }
|
76
|
+
end
|
77
|
+
|
78
|
+
def after_loop
|
79
|
+
super
|
80
|
+
EventMachine.stop_event_loop
|
81
|
+
end
|
82
|
+
|
83
|
+
def handle_interrupt
|
84
|
+
super
|
85
|
+
redisplay
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
Ripl::Shell.include Ripl::Readline::Em
|
92
|
+
class Ripl::Shell
|
93
|
+
def loop
|
94
|
+
loop_override
|
95
|
+
end
|
96
|
+
end
|
metadata
ADDED
@@ -0,0 +1,101 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ripl-readline-em
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Patrick Mahoney
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2011-11-25 00:00:00.000000000 -06:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: ripl
|
17
|
+
requirement: &8353400 !ruby/object:Gem::Requirement
|
18
|
+
none: false
|
19
|
+
requirements:
|
20
|
+
- - ! '>='
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 0.4.2
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: *8353400
|
26
|
+
- !ruby/object:Gem::Dependency
|
27
|
+
name: eventmachine
|
28
|
+
requirement: &8352820 !ruby/object:Gem::Requirement
|
29
|
+
none: false
|
30
|
+
requirements:
|
31
|
+
- - ! '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: *8352820
|
37
|
+
- !ruby/object:Gem::Dependency
|
38
|
+
name: ffi
|
39
|
+
requirement: &8314360 !ruby/object:Gem::Requirement
|
40
|
+
none: false
|
41
|
+
requirements:
|
42
|
+
- - ! '>='
|
43
|
+
- !ruby/object:Gem::Version
|
44
|
+
version: '0'
|
45
|
+
type: :runtime
|
46
|
+
prerelease: false
|
47
|
+
version_requirements: *8314360
|
48
|
+
- !ruby/object:Gem::Dependency
|
49
|
+
name: bacon
|
50
|
+
requirement: &8313560 !ruby/object:Gem::Requirement
|
51
|
+
none: false
|
52
|
+
requirements:
|
53
|
+
- - ! '>='
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: 1.1.0
|
56
|
+
type: :development
|
57
|
+
prerelease: false
|
58
|
+
version_requirements: *8313560
|
59
|
+
description: Run EventMachine code in a ripl shell asynchronously with readline editing
|
60
|
+
and completion
|
61
|
+
email: pat@polycrystal.org
|
62
|
+
executables: []
|
63
|
+
extensions: []
|
64
|
+
extra_rdoc_files:
|
65
|
+
- README.rdoc
|
66
|
+
- LICENSE.txt
|
67
|
+
files:
|
68
|
+
- lib/ripl/readline/em.rb
|
69
|
+
- lib/readline_cb.rb
|
70
|
+
- lib/readline/callback.rb
|
71
|
+
- LICENSE.txt
|
72
|
+
- README.rdoc
|
73
|
+
- Rakefile
|
74
|
+
- .gemspec
|
75
|
+
has_rdoc: true
|
76
|
+
homepage: http://github.com/pmahoney/ripl-readline-em
|
77
|
+
licenses:
|
78
|
+
- MIT
|
79
|
+
post_install_message:
|
80
|
+
rdoc_options: []
|
81
|
+
require_paths:
|
82
|
+
- lib
|
83
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
84
|
+
none: false
|
85
|
+
requirements:
|
86
|
+
- - ! '>='
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
version: '0'
|
89
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
90
|
+
none: false
|
91
|
+
requirements:
|
92
|
+
- - ! '>='
|
93
|
+
- !ruby/object:Gem::Version
|
94
|
+
version: 1.3.6
|
95
|
+
requirements: []
|
96
|
+
rubyforge_project:
|
97
|
+
rubygems_version: 1.6.2
|
98
|
+
signing_key:
|
99
|
+
specification_version: 3
|
100
|
+
summary: A ripl plugin to run readline within eventmachine
|
101
|
+
test_files: []
|