pageme 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +17 -0
- data/Gemfile +4 -0
- data/LICENSE +22 -0
- data/README.md +92 -0
- data/Rakefile +2 -0
- data/lib/pageme/version.rb +3 -0
- data/lib/pageme.rb +133 -0
- data/pageme.gemspec +19 -0
- metadata +80 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2012 David R. MacIver
|
2
|
+
|
3
|
+
MIT License
|
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.md
ADDED
@@ -0,0 +1,92 @@
|
|
1
|
+
# PageMe
|
2
|
+
|
3
|
+
PageMe is a trivial rubygem for invoking a pager on application data.
|
4
|
+
|
5
|
+
It even works under JRuby. The implementation for the JRuby support is an awful hack (it relies on netcat + unix domain sockets) and I've only tested it under linux, but it appears to be fully functional.
|
6
|
+
|
7
|
+
## Usage
|
8
|
+
|
9
|
+
Include PageMe for use:
|
10
|
+
|
11
|
+
include PageMe
|
12
|
+
|
13
|
+
Paging a string:
|
14
|
+
|
15
|
+
page "some long string\nwhich spans many lines"
|
16
|
+
|
17
|
+
Paging an enumerable will page each element to its own line:
|
18
|
+
|
19
|
+
page (1..10000)
|
20
|
+
|
21
|
+
You can page multiple things at once
|
22
|
+
|
23
|
+
page "these", "strings", "will", "each", "go", "on", "their", "own", "line"
|
24
|
+
|
25
|
+
You can also page to a block
|
26
|
+
|
27
|
+
page do |o|
|
28
|
+
10000.times do |i|
|
29
|
+
o.puts i
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
You can combine the different formats, which will page the arguments then the block
|
34
|
+
|
35
|
+
page "this is the first string" do |o|
|
36
|
+
10000.times do |i|
|
37
|
+
o.puts i
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
It's ok for the blocks to throw exceptions
|
42
|
+
|
43
|
+
page{ raise "Denied!" }
|
44
|
+
|
45
|
+
Their results will be printed to the pager.
|
46
|
+
|
47
|
+
If you're passing multiple arguments and one of them raises an error then no further data will be paged
|
48
|
+
|
49
|
+
page lambda{raise "Denied!"}, "this line will never be printed"
|
50
|
+
|
51
|
+
If you want to page the results of the block first you can pass it as an argument
|
52
|
+
|
53
|
+
page "This line is printed first", lambda{ |o| 10.times{|i| o.puts i } }, "I just printed a bunch of lines"
|
54
|
+
|
55
|
+
You can page to a file either by passing its file name to page\_file
|
56
|
+
|
57
|
+
page_file "path/to/some/file"
|
58
|
+
|
59
|
+
or by passing an IO object
|
60
|
+
|
61
|
+
page File.open("path/to/some/file")
|
62
|
+
|
63
|
+
but the above example is bad because it won't close the file handle.
|
64
|
+
|
65
|
+
You can configure the pager being invoked:
|
66
|
+
|
67
|
+
self.pager = "more"
|
68
|
+
page %w{I hate fun}
|
69
|
+
|
70
|
+
You can also just disable paging if you want to print to STDOUT:
|
71
|
+
|
72
|
+
self.disable_paging
|
73
|
+
page %w{this will go to STDOUT as if it were the pager}
|
74
|
+
|
75
|
+
This is the default if STDOUT is not a tty.
|
76
|
+
|
77
|
+
You can of course enable it again:
|
78
|
+
|
79
|
+
self.enable_paging
|
80
|
+
page %w{this will go to a pager as normal}
|
81
|
+
|
82
|
+
## Known bugs
|
83
|
+
|
84
|
+
Closing the pager does not work correctly in some versions of JRuby due to a bug in the Unix domain socket implementation. I've yet to pin down exactly where it's fixed (it might not be fixed in any released versions. It works in head and doesn't work in 1.6.2), but you may see that page continues to block after the pager closes. This is due to JRuby not raising an error when writing to a broken socket and there's not much I can do about it. Sorry.
|
85
|
+
|
86
|
+
## Contributing
|
87
|
+
|
88
|
+
1. Fork it
|
89
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
90
|
+
3. Commit your changes (`git commit -am 'Added some feature'`)
|
91
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
92
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
data/lib/pageme.rb
ADDED
@@ -0,0 +1,133 @@
|
|
1
|
+
require "#{File.dirname __FILE__}/pageme/version"
|
2
|
+
require "rubygems"
|
3
|
+
|
4
|
+
module PageMe
|
5
|
+
if RUBY_VERSION < "1.9" || defined?(JRUBY_VERSION)
|
6
|
+
require "posix/spawn"
|
7
|
+
include POSIX::Spawn
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.use_domain_socket_for_paging=(f)
|
11
|
+
if f
|
12
|
+
require "tempfile"
|
13
|
+
require "socket"
|
14
|
+
end
|
15
|
+
@use_domain_socket_for_paging = f
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.use_domain_socket_for_paging?
|
19
|
+
@use_domain_socket_for_paging
|
20
|
+
end
|
21
|
+
|
22
|
+
self.use_domain_socket_for_paging = (defined? JRUBY_VERSION)
|
23
|
+
|
24
|
+
attr_writer :pager, :paging_disabled
|
25
|
+
|
26
|
+
def paging_disabled?
|
27
|
+
return @paging_disabled if defined? paging_disabled
|
28
|
+
|
29
|
+
!(STDOUT.tty?)
|
30
|
+
end
|
31
|
+
|
32
|
+
def disable_paging
|
33
|
+
self.paging_disabled = true
|
34
|
+
end
|
35
|
+
|
36
|
+
def enable_paging
|
37
|
+
self.paging_disabled = false
|
38
|
+
end
|
39
|
+
|
40
|
+
def pager
|
41
|
+
@pager || ENV["PAGER"] || "less"
|
42
|
+
end
|
43
|
+
|
44
|
+
def page *args, &p
|
45
|
+
args << p
|
46
|
+
args.compact!
|
47
|
+
|
48
|
+
if paging_disabled?
|
49
|
+
page_to STDOUT, args
|
50
|
+
return
|
51
|
+
end
|
52
|
+
|
53
|
+
t, w, server = nil
|
54
|
+
|
55
|
+
if defined? JRUBY_VERSION
|
56
|
+
loop do
|
57
|
+
begin
|
58
|
+
t = File.join(Dir::tmpdir, "socket-for-jruby-pager-#{rand(2**16)}")
|
59
|
+
server = UNIXServer.new(t)
|
60
|
+
break
|
61
|
+
rescue Errno::EADDRINUSE
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
|
66
|
+
child_pid = spawn "netcat -U #{t} | #{pager}"
|
67
|
+
|
68
|
+
w = server.accept
|
69
|
+
else
|
70
|
+
r, w = IO.pipe
|
71
|
+
child_pid = spawn pager, :in => r, w => :close
|
72
|
+
r.close
|
73
|
+
end
|
74
|
+
|
75
|
+
Kernel.trap("SIGINT"){ Process.kill "INT", child_pid }
|
76
|
+
|
77
|
+
begin
|
78
|
+
page_to w, args
|
79
|
+
rescue Errno::EPIPE
|
80
|
+
rescue Exception => e
|
81
|
+
unless w.closed?
|
82
|
+
w.puts "#{e.class}: #{e.message}"
|
83
|
+
e.backtrace.each{|l| w.puts "\t#{l}" }
|
84
|
+
end
|
85
|
+
raise
|
86
|
+
ensure
|
87
|
+
w.close
|
88
|
+
Process.wait child_pid
|
89
|
+
Kernel.trap("SIGINT", "DEFAULT")
|
90
|
+
File.delete(t) if t
|
91
|
+
server.close if server
|
92
|
+
end
|
93
|
+
nil
|
94
|
+
end
|
95
|
+
|
96
|
+
def page_file file
|
97
|
+
raise Errno::ENOENT, file unless File.exist? file
|
98
|
+
|
99
|
+
system pager, file
|
100
|
+
nil
|
101
|
+
end
|
102
|
+
|
103
|
+
def with_paged_output
|
104
|
+
page do |o|
|
105
|
+
original_stdout = STDOUT.dup
|
106
|
+
original_stderr = STDERR.dup
|
107
|
+
begin
|
108
|
+
STDERR.reopen(o)
|
109
|
+
STDOUT.reopen(o)
|
110
|
+
yield
|
111
|
+
ensure
|
112
|
+
STDERR.reopen(original_stderr)
|
113
|
+
STDOUT.reopen(original_stdout)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
private
|
119
|
+
|
120
|
+
def page_to w, a
|
121
|
+
if a.kind_of? IO
|
122
|
+
a.each{|d| w.write d }
|
123
|
+
elsif a.kind_of? Proc
|
124
|
+
a.call(w)
|
125
|
+
elsif a.kind_of? String
|
126
|
+
w.write a
|
127
|
+
elsif a.kind_of? Enumerable
|
128
|
+
a.each{|e| page_to w, e; w.puts }
|
129
|
+
else
|
130
|
+
w.write a.to_s
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
data/pageme.gemspec
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../lib/pageme/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |gem|
|
5
|
+
gem.authors = ["David R. MacIver"]
|
6
|
+
gem.email = ["david@drmaciver.com"]
|
7
|
+
gem.description = %q{Methods for invoking a pager}
|
8
|
+
gem.summary = %q{Trivial gem for invoking a pager for your program data}
|
9
|
+
gem.homepage = "https://github.com/DRMacIver/pageme"
|
10
|
+
|
11
|
+
gem.add_dependency 'posix-spawn', '>= 0.3.6'
|
12
|
+
|
13
|
+
gem.files = `git ls-files`.split($\)
|
14
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
15
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
16
|
+
gem.name = "pageme"
|
17
|
+
gem.require_paths = ["lib"]
|
18
|
+
gem.version = Pageme::VERSION
|
19
|
+
end
|
metadata
ADDED
@@ -0,0 +1,80 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: pageme
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease:
|
5
|
+
version: 0.0.1
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- David R. MacIver
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-04-29 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: posix-spawn
|
16
|
+
version_requirements: !ruby/object:Gem::Requirement
|
17
|
+
requirements:
|
18
|
+
- - ! '>='
|
19
|
+
- !ruby/object:Gem::Version
|
20
|
+
version: 0.3.6
|
21
|
+
none: false
|
22
|
+
requirement: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ! '>='
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 0.3.6
|
27
|
+
none: false
|
28
|
+
prerelease: false
|
29
|
+
type: :runtime
|
30
|
+
description: Methods for invoking a pager
|
31
|
+
email:
|
32
|
+
- david@drmaciver.com
|
33
|
+
executables: []
|
34
|
+
extensions: []
|
35
|
+
extra_rdoc_files: []
|
36
|
+
files:
|
37
|
+
- !binary |-
|
38
|
+
LmdpdGlnbm9yZQ==
|
39
|
+
- !binary |-
|
40
|
+
R2VtZmlsZQ==
|
41
|
+
- !binary |-
|
42
|
+
TElDRU5TRQ==
|
43
|
+
- !binary |-
|
44
|
+
UkVBRE1FLm1k
|
45
|
+
- !binary |-
|
46
|
+
UmFrZWZpbGU=
|
47
|
+
- !binary |-
|
48
|
+
bGliL3BhZ2VtZS5yYg==
|
49
|
+
- !binary |-
|
50
|
+
bGliL3BhZ2VtZS92ZXJzaW9uLnJi
|
51
|
+
- !binary |-
|
52
|
+
cGFnZW1lLmdlbXNwZWM=
|
53
|
+
homepage: https://github.com/DRMacIver/pageme
|
54
|
+
licenses: []
|
55
|
+
post_install_message:
|
56
|
+
rdoc_options: []
|
57
|
+
require_paths:
|
58
|
+
- lib
|
59
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
60
|
+
requirements:
|
61
|
+
- - ! '>='
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: !binary |-
|
64
|
+
MA==
|
65
|
+
none: false
|
66
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
67
|
+
requirements:
|
68
|
+
- - ! '>='
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
version: !binary |-
|
71
|
+
MA==
|
72
|
+
none: false
|
73
|
+
requirements: []
|
74
|
+
rubyforge_project:
|
75
|
+
rubygems_version: 1.8.24
|
76
|
+
signing_key:
|
77
|
+
specification_version: 3
|
78
|
+
summary: Trivial gem for invoking a pager for your program data
|
79
|
+
test_files: []
|
80
|
+
...
|