irb_hacks 0.2.0 → 0.2.2
Sign up to get free protection for your applications and to get access to all the features.
- data/README.html +32 -16
- data/README.md +32 -15
- data/Rakefile +13 -4
- data/VERSION.yml +2 -2
- data/irb_hacks.gemspec +5 -5
- data/lib/irb_hacks/break_exception.rb +4 -0
- data/lib/irb_hacks/config.rb +33 -0
- data/lib/irb_hacks/core_ext/kernel/a_and_ae.rb +6 -8
- data/lib/irb_hacks/core_ext/kernel/less.rb +32 -28
- data/lib/irb_hacks/snippet.rb +66 -35
- data/lib/irb_hacks.rb +36 -12
- metadata +6 -13
- data/CHANGELOG.md +0 -10
data/README.html
CHANGED
@@ -31,14 +31,14 @@ irb> ae
|
|
31
31
|
|
32
32
|
<p>There’s often a need to invoke our work-in-progress code a number of times using the same arguments, wrapping block, etc. For that, “code snippets” feature is quite handy.</p>
|
33
33
|
|
34
|
-
<p><code>irb_hacks</code>
|
34
|
+
<p><code>irb_hacks</code> provides the two methods with short, meaningless (and thus conflict-free) names – <code>a</code> and <code>ae</code>. <code>a</code> means nothing, it’s just the first letter of the alphabet. <code>a</code> <strong>invokes</strong> the last-edited snippet. <code>ae</code> <strong>lets you edit</strong> the actual snippet (it roughly stands for “a” + “edit”).</p>
|
35
35
|
|
36
36
|
<p>A very basic example:</p>
|
37
37
|
|
38
38
|
<pre><code>irb> ae
|
39
|
-
(snippet)>> puts "Hello, world"
|
39
|
+
(snippet)>> puts "Hello, world!"
|
40
40
|
irb> a
|
41
|
-
Hello, world
|
41
|
+
Hello, world!
|
42
42
|
</code></pre>
|
43
43
|
|
44
44
|
<p>Snippet arguments are supported. It’s an array called <code>args</code> in snippet context.</p>
|
@@ -61,7 +61,7 @@ charlie
|
|
61
61
|
zulu
|
62
62
|
</code></pre>
|
63
63
|
|
64
|
-
<p>Snippets support code blocks. It’s a <code>Proc</code> called <code>block</code> in snippet context. Usage example follows
|
64
|
+
<p>Snippets support code blocks. It’s a <code>Proc</code> object called <code>block</code> in snippet context. Usage example follows. Suppose you’re building a simplistic <code>/etc/passwd</code> parser. You put the actual reading in the snippet, but do line data manipulation in a block:</p>
|
65
65
|
|
66
66
|
<pre><code>irb> ae
|
67
67
|
(snippet)>> File.readlines("/etc/passwd").map(&block).each {|s| p s}; nil
|
@@ -73,7 +73,7 @@ irb> a {|s| ar = s.split(":"); {:name => ar[0], :uid => ar[2]}}
|
|
73
73
|
...
|
74
74
|
</code></pre>
|
75
75
|
|
76
|
-
<p>Snippets are <strong>persistent</strong>
|
76
|
+
<p>Snippets are <strong>persistent</strong> thoughout IRB invocations. That’s quite handy, since not all stuff can be dynamically reloaded and sometimes we have to restart IRB to ensure a clean reload.</p>
|
77
77
|
|
78
78
|
<pre><code>irb> ae
|
79
79
|
(snippet)>> puts "Snippets are persistent!"
|
@@ -83,9 +83,9 @@ irb> a
|
|
83
83
|
Snippets are persistent!
|
84
84
|
</code></pre>
|
85
85
|
|
86
|
-
<p>Just in case, snippet history file is called <code
|
86
|
+
<p>Just in case, snippet history file is called <code>~/.irb_snippet_history</code> by default.</p>
|
87
87
|
|
88
|
-
<p>Snippets maintain <strong>their own</strong> Readline history. When you press [Up] and [Down] keys in <code>ae</code>, you browse the previously used snippets, not just your previous IRB input.
|
88
|
+
<p>Snippets maintain <strong>their own</strong> Readline history. When you press [Up] and [Down] keys in <code>ae</code>, you browse the previously used snippets, not just your previous IRB input. So don’t retype the snippet you used yesterday – press [Up] a few times and you’ll see it.</p>
|
89
89
|
|
90
90
|
<pre><code>irb> ae
|
91
91
|
(snippet)>> puts "snippet one"
|
@@ -103,6 +103,8 @@ irb> ae
|
|
103
103
|
(snippet)>> puts "snippet one"
|
104
104
|
</code></pre>
|
105
105
|
|
106
|
+
<p>You can configure some aspects of the snippets. Read “Configuration” chapter below.</p>
|
107
|
+
|
106
108
|
<h3 id="browse-program-data-with-gnu-less">Browse program data with GNU <code>less</code></h3>
|
107
109
|
|
108
110
|
<p>Sometimes the data your code works with is too long to fit in a console window. The clearest example of this are variables filled with text content, e.g. <a href="http://github.com/whymirror/hpricot">Hpricot</a> documents/elements.</p>
|
@@ -113,7 +115,7 @@ irb> ae
|
|
113
115
|
irb> files = Dir["/etc/*"].sort
|
114
116
|
# Some bulky array...
|
115
117
|
irb> less files
|
116
|
-
# ...
|
118
|
+
# ...which you browse interactively!
|
117
119
|
</code></pre>
|
118
120
|
|
119
121
|
<p>In block form, <code>less</code> hack intercepts everything output to <code>STDOUT</code> (and, optionally, to <code>STDERR</code>), and feeds it to the pager.</p>
|
@@ -133,16 +135,11 @@ STDERR.puts "to stderr"
|
|
133
135
|
end
|
134
136
|
</code></pre>
|
135
137
|
|
136
|
-
<p>
|
137
|
-
|
138
|
-
<pre><code>IrbHacks.less_cmd = "more"
|
139
|
-
</code></pre>
|
140
|
-
|
141
|
-
<p>, or something else you find appropriate.</p>
|
138
|
+
<p>You can configure which pager program to use and with which options. Read “Configuration” chapter below.</p>
|
142
139
|
|
143
140
|
<h3 id="break-execution-and-return-instant-value">Break execution and return instant value</h3>
|
144
141
|
|
145
|
-
<p>By using <code>IrbHacks.break(value)</code> you break snippet execution and make it return <code>value</code>. This is a simple yet powerful debugging technique.</p>
|
142
|
+
<p>By using <code>IrbHacks.break(value)</code> you break snippet (<code>a</code>) execution and make it return <code>value</code>. This is a simple yet powerful debugging technique.</p>
|
146
143
|
|
147
144
|
<p>Suppose you’re debugging the code which contains something like:</p>
|
148
145
|
|
@@ -167,7 +164,26 @@ irb> row = a
|
|
167
164
|
irb>
|
168
165
|
</code></pre>
|
169
166
|
|
170
|
-
<p>Each <code>IrbHacks.break</code> call raises an <code>IrbHacks::BreakException</code>. If you see them popping out
|
167
|
+
<p>Each <code>IrbHacks.break</code> call raises an <code>IrbHacks::BreakException</code>. If you see them popping out runtime, find the appropriate <code>IrbHacks.break</code> calls and defuse them.</p>
|
168
|
+
|
169
|
+
<h2 id="configuration">Configuration</h2>
|
170
|
+
|
171
|
+
<p>Via <code>IrbHacks.conf</code> object you can configure various features of <code>irb_hacks</code>. Add <code>IrbHacks.conf</code> manipulation code to your <code>.irbrc</code>:</p>
|
172
|
+
|
173
|
+
<pre><code>require "rubygems"
|
174
|
+
require "irb_hacks"
|
175
|
+
|
176
|
+
IrbHacks.conf.snippet_prompt = ">>> "
|
177
|
+
</code></pre>
|
178
|
+
|
179
|
+
<h3 id="configuration-variables-irbhacksconf">Configuration Variables (<code>IrbHacks.conf.*</code>)</h3>
|
180
|
+
|
181
|
+
<ul>
|
182
|
+
<li><code>less_cmd</code> – System command to invoke pager for <code>less</code>.</li>
|
183
|
+
<li><code>snippet_history_file</code> – Snippet (<code>a</code>, <code>ae</code>) history file.</li>
|
184
|
+
<li><code>snippet_history_size</code> – Snippet history size.</li>
|
185
|
+
<li><code>snippet_prompt</code> – Snippet input prompt.</li>
|
186
|
+
</ul>
|
171
187
|
|
172
188
|
<h2 id="feedback">Feedback</h2>
|
173
189
|
|
data/README.md
CHANGED
@@ -28,14 +28,14 @@ The Hacks
|
|
28
28
|
|
29
29
|
There's often a need to invoke our work-in-progress code a number of times using the same arguments, wrapping block, etc. For that, "code snippets" feature is quite handy.
|
30
30
|
|
31
|
-
`irb_hacks`
|
31
|
+
`irb_hacks` provides the two methods with short, meaningless (and thus conflict-free) names -- `a` and `ae`. `a` means nothing, it's just the first letter of the alphabet. `a` **invokes** the last-edited snippet. `ae` **lets you edit** the actual snippet (it roughly stands for "a" + "edit").
|
32
32
|
|
33
33
|
A very basic example:
|
34
34
|
|
35
35
|
irb> ae
|
36
|
-
(snippet)>> puts "Hello, world"
|
36
|
+
(snippet)>> puts "Hello, world!"
|
37
37
|
irb> a
|
38
|
-
Hello, world
|
38
|
+
Hello, world!
|
39
39
|
|
40
40
|
Snippet arguments are supported. It's an array called `args` in snippet context.
|
41
41
|
|
@@ -55,7 +55,7 @@ Snippets work just like normal Ruby methods -- they return the value of the last
|
|
55
55
|
charlie
|
56
56
|
zulu
|
57
57
|
|
58
|
-
Snippets support code blocks. It's a `Proc` called `block` in snippet context. Usage example follows
|
58
|
+
Snippets support code blocks. It's a `Proc` object called `block` in snippet context. Usage example follows. Suppose you're building a simplistic `/etc/passwd` parser. You put the actual reading in the snippet, but do line data manipulation in a block:
|
59
59
|
|
60
60
|
irb> ae
|
61
61
|
(snippet)>> File.readlines("/etc/passwd").map(&block).each {|s| p s}; nil
|
@@ -66,7 +66,7 @@ Snippets support code blocks. It's a `Proc` called `block` in snippet context. U
|
|
66
66
|
{:uid=>"3", :name=>"adm"}
|
67
67
|
...
|
68
68
|
|
69
|
-
Snippets are **persistent**
|
69
|
+
Snippets are **persistent** thoughout IRB invocations. That's quite handy, since not all stuff can be dynamically reloaded and sometimes we have to restart IRB to ensure a clean reload.
|
70
70
|
|
71
71
|
irb> ae
|
72
72
|
(snippet)>> puts "Snippets are persistent!"
|
@@ -75,9 +75,9 @@ Snippets are **persistent** though IRB invocations. That's quite handy, since no
|
|
75
75
|
irb> a
|
76
76
|
Snippets are persistent!
|
77
77
|
|
78
|
-
Just in case, snippet history file is called
|
78
|
+
Just in case, snippet history file is called `~/.irb_snippet_history` by default.
|
79
79
|
|
80
|
-
Snippets maintain **their own** Readline history. When you press [Up] and [Down] keys in `ae`, you browse the previously used snippets, not just your previous IRB input.
|
80
|
+
Snippets maintain **their own** Readline history. When you press [Up] and [Down] keys in `ae`, you browse the previously used snippets, not just your previous IRB input. So don't retype the snippet you used yesterday -- press [Up] a few times and you'll see it.
|
81
81
|
|
82
82
|
irb> ae
|
83
83
|
(snippet)>> puts "snippet one"
|
@@ -94,6 +94,8 @@ Snippets maintain **their own** Readline history. When you press [Up] and [Down]
|
|
94
94
|
# Pressing [Up] again will give you...
|
95
95
|
(snippet)>> puts "snippet one"
|
96
96
|
|
97
|
+
You can configure some aspects of the snippets. Read "Configuration" chapter below.
|
98
|
+
|
97
99
|
|
98
100
|
### Browse program data with GNU `less` ###
|
99
101
|
|
@@ -105,7 +107,7 @@ To solve that, the greatest paging program of all times, GNU `less`, comes to th
|
|
105
107
|
irb> files = Dir["/etc/*"].sort
|
106
108
|
# Some bulky array...
|
107
109
|
irb> less files
|
108
|
-
# ...
|
110
|
+
# ...which you browse interactively!
|
109
111
|
|
110
112
|
In block form, `less` hack intercepts everything output to `STDOUT` (and, optionally, to `STDERR`), and feeds it to the pager.
|
111
113
|
|
@@ -122,16 +124,12 @@ Now with `STDERR` capture:
|
|
122
124
|
STDERR.puts "to stderr"
|
123
125
|
end
|
124
126
|
|
125
|
-
|
126
|
-
|
127
|
-
IrbHacks.less_cmd = "more"
|
128
|
-
|
129
|
-
, or something else you find appropriate.
|
127
|
+
You can configure which pager program to use and with which options. Read "Configuration" chapter below.
|
130
128
|
|
131
129
|
|
132
130
|
### Break execution and return instant value ###
|
133
131
|
|
134
|
-
By using `IrbHacks.break(value)` you break snippet execution and make it return `value`. This is a simple yet powerful debugging technique.
|
132
|
+
By using `IrbHacks.break(value)` you break snippet (`a`) execution and make it return `value`. This is a simple yet powerful debugging technique.
|
135
133
|
|
136
134
|
Suppose you're debugging the code which contains something like:
|
137
135
|
|
@@ -153,7 +151,26 @@ Now all you have to do is write an `ae` snippet and call it. `row` value will be
|
|
153
151
|
# Back in IRB. Do whatever you want with `row` value now.
|
154
152
|
irb>
|
155
153
|
|
156
|
-
Each `IrbHacks.break` call raises an `IrbHacks::BreakException`. If you see them popping out
|
154
|
+
Each `IrbHacks.break` call raises an `IrbHacks::BreakException`. If you see them popping out runtime, find the appropriate `IrbHacks.break` calls and defuse them.
|
155
|
+
|
156
|
+
|
157
|
+
Configuration
|
158
|
+
-------------
|
159
|
+
|
160
|
+
Via `IrbHacks.conf` object you can configure various features of `irb_hacks`. Add `IrbHacks.conf` manipulation code to your `.irbrc`:
|
161
|
+
|
162
|
+
require "rubygems"
|
163
|
+
require "irb_hacks"
|
164
|
+
|
165
|
+
IrbHacks.conf.snippet_prompt = ">>> "
|
166
|
+
|
167
|
+
|
168
|
+
### Configuration Variables (`IrbHacks.conf.*`)###
|
169
|
+
|
170
|
+
* `less_cmd` -- System command to invoke pager for `less`.
|
171
|
+
* `snippet_history_file` -- Snippet (`a`, `ae`) history file.
|
172
|
+
* `snippet_history_size` -- Snippet history size.
|
173
|
+
* `snippet_prompt` -- Snippet input prompt.
|
157
174
|
|
158
175
|
|
159
176
|
Feedback
|
data/Rakefile
CHANGED
@@ -1,5 +1,5 @@
|
|
1
|
+
require "rake/rdoctask"
|
1
2
|
require "yaml"
|
2
|
-
#require 'rake/gempackagetask'
|
3
3
|
|
4
4
|
GEM_NAME = "irb_hacks"
|
5
5
|
|
@@ -25,15 +25,24 @@ end
|
|
25
25
|
desc "Rebuild gemspec and package"
|
26
26
|
task :rebuild => [:gemspec, :build]
|
27
27
|
|
28
|
-
desc "Push (publish) gem to
|
28
|
+
desc "Push (publish) gem to RubyGems.org"
|
29
29
|
task :push do
|
30
30
|
# Yet found no way to ask Jeweler forge a complete version string for us.
|
31
31
|
vh = YAML.load(File.read("VERSION.yml"))
|
32
|
-
version = [vh[:major], vh[:minor], vh[:patch]].join(".")
|
33
|
-
pkgfile = File.join("pkg", [GEM_NAME, "-", version, ".gem"].
|
32
|
+
version = [vh[:major], vh[:minor], vh[:patch], (if (v = vh[:build]); v; end)].compact.join(".")
|
33
|
+
pkgfile = File.join("pkg", [GEM_NAME, "-", version, ".gem"].join)
|
34
34
|
Kernel.system("gem", "push", pkgfile)
|
35
35
|
end
|
36
36
|
|
37
|
+
desc "Generate RDoc documentation"
|
38
|
+
Rake::RDocTask.new(:rdoc) do |rdoc|
|
39
|
+
rdoc.rdoc_dir = "doc"
|
40
|
+
rdoc.title = "IrbHacks"
|
41
|
+
#rdoc.options << "--line-numbers"
|
42
|
+
#rdoc.options << "--inline-source"
|
43
|
+
rdoc.rdoc_files.include("lib/**/*.rb")
|
44
|
+
end
|
45
|
+
|
37
46
|
#Rake::GemPackageTask.new(spec) do |p|
|
38
47
|
# p.need_tar = true if RUBY_PLATFORM !~ /mswin/
|
39
48
|
#end
|
data/VERSION.yml
CHANGED
data/irb_hacks.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{irb_hacks}
|
8
|
-
s.version = "0.2.
|
8
|
+
s.version = "0.2.2"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Alex Fortuna"]
|
12
|
-
s.date = %q{
|
12
|
+
s.date = %q{2011-07-12}
|
13
13
|
s.description = %q{Yet another set of IRB hacks}
|
14
14
|
s.email = %q{alex.r@askit.org}
|
15
15
|
s.extra_rdoc_files = [
|
@@ -17,7 +17,6 @@ Gem::Specification.new do |s|
|
|
17
17
|
"README.md"
|
18
18
|
]
|
19
19
|
s.files = [
|
20
|
-
"CHANGELOG.md",
|
21
20
|
"MIT-LICENSE",
|
22
21
|
"README.html",
|
23
22
|
"README.md",
|
@@ -25,17 +24,18 @@ Gem::Specification.new do |s|
|
|
25
24
|
"VERSION.yml",
|
26
25
|
"irb_hacks.gemspec",
|
27
26
|
"lib/irb_hacks.rb",
|
27
|
+
"lib/irb_hacks/break_exception.rb",
|
28
|
+
"lib/irb_hacks/config.rb",
|
28
29
|
"lib/irb_hacks/core_ext/kernel/a_and_ae.rb",
|
29
30
|
"lib/irb_hacks/core_ext/kernel/less.rb",
|
30
31
|
"lib/irb_hacks/snippet.rb"
|
31
32
|
]
|
32
33
|
s.homepage = %q{http://github.com/dadooda/irb_hacks}
|
33
34
|
s.require_paths = ["lib"]
|
34
|
-
s.rubygems_version = %q{1.
|
35
|
+
s.rubygems_version = %q{1.6.2}
|
35
36
|
s.summary = %q{Yet another set of IRB hacks}
|
36
37
|
|
37
38
|
if s.respond_to? :specification_version then
|
38
|
-
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
39
39
|
s.specification_version = 3
|
40
40
|
|
41
41
|
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module IrbHacks
|
2
|
+
# IrbHacks configuration object.
|
3
|
+
class Config
|
4
|
+
# System command to invoke pager for <tt>less</tt>. Default:
|
5
|
+
#
|
6
|
+
# less -R
|
7
|
+
attr_accessor :less_cmd
|
8
|
+
|
9
|
+
# Snippet (<tt>a</tt>, <tt>ae</tt>) history file. Default:
|
10
|
+
#
|
11
|
+
# ~/.irb_snippet_history
|
12
|
+
attr_accessor :snippet_history_file
|
13
|
+
|
14
|
+
# Snippet history size. Default is <tt>100</tt>.
|
15
|
+
attr_accessor :snippet_history_size
|
16
|
+
|
17
|
+
# Snippet input prompt. Default:
|
18
|
+
#
|
19
|
+
# (snippet)>>
|
20
|
+
attr_accessor :snippet_prompt
|
21
|
+
|
22
|
+
def initialize(attrs = {})
|
23
|
+
defaults = {
|
24
|
+
:less_cmd => "less -R",
|
25
|
+
:snippet_history_file => "~/.irb_snippet_history",
|
26
|
+
:snippet_history_size => 100,
|
27
|
+
:snippet_prompt => "(snippet)>> ",
|
28
|
+
}
|
29
|
+
|
30
|
+
defaults.merge(attrs).each {|k, v| send("#{k}=", v)}
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -1,27 +1,25 @@
|
|
1
|
-
module IrbHacks
|
1
|
+
module IrbHacks
|
2
2
|
module CoreExtensions #:nodoc:
|
3
3
|
module Kernel #:nodoc:
|
4
|
-
module SingletonMethods
|
5
|
-
# Run code snippet.
|
6
|
-
# See <tt>IrbHacks::Snippet.run</tt>.
|
4
|
+
module SingletonMethods #:nodoc:
|
7
5
|
def a(*args, &block)
|
8
|
-
|
6
|
+
Snippet.run(*args, &block)
|
9
7
|
end
|
10
8
|
|
11
|
-
# Edit code snippet.
|
12
|
-
# See <tt>IrbHacks::Snippet.edit</tt>.
|
13
9
|
def ae(*args)
|
14
|
-
|
10
|
+
Snippet.edit(*args)
|
15
11
|
end
|
16
12
|
end # SingletonMethods
|
17
13
|
|
18
14
|
module InstanceMethods
|
19
15
|
private
|
20
16
|
|
17
|
+
# Run code snippet. See IrbHacks::Snippet::run.
|
21
18
|
def a(*args, &block)
|
22
19
|
::Kernel.a(*args, &block)
|
23
20
|
end
|
24
21
|
|
22
|
+
# Interactively edit code snippet. See IrbHacks::Snippet::edit.
|
25
23
|
def ae(*args)
|
26
24
|
::Kernel.ae(*args)
|
27
25
|
end
|
@@ -1,39 +1,16 @@
|
|
1
|
-
module IrbHacks
|
1
|
+
module IrbHacks
|
2
2
|
module CoreExtensions #:nodoc:
|
3
3
|
module Kernel #:nodoc:
|
4
|
-
module SingletonMethods
|
5
|
-
#
|
6
|
-
#
|
7
|
-
# Plain form:
|
8
|
-
# less "hello", "world"
|
9
|
-
# less mydata
|
10
|
-
#
|
11
|
-
# Block form:
|
12
|
-
# less do
|
13
|
-
# puts "hello, world"
|
14
|
-
# end
|
15
|
-
#
|
16
|
-
# less(:stderr => true) do
|
17
|
-
# puts "to stdout"
|
18
|
-
# STDERR.puts "to stderr"
|
19
|
-
# end
|
20
|
-
#
|
21
|
-
# Block form options:
|
22
|
-
# :stderr => T|F # Redirect STDERR too.
|
23
|
-
#
|
24
|
-
# If block form option is <tt>String</tt> or <tt>Symbol</tt>, it's automatically
|
25
|
-
# converted to a hash like <tt>{:var => true}</tt>. Thus, <tt>less(:stderr => true)</tt>
|
26
|
-
# and <tt>less(:stderr)</tt> are identical.
|
4
|
+
module SingletonMethods #:nodoc:
|
5
|
+
# See InstanceMethods for documentation.
|
27
6
|
def less(*args, &block)
|
28
|
-
less_cmd = IrbHacks.less_cmd
|
29
|
-
|
30
7
|
if not block
|
31
8
|
# Non-block invocation.
|
32
9
|
if args.size < 1
|
33
10
|
# We're interactive anyway. Why not give user a quick prompt?
|
34
11
|
STDERR.puts "Nothing to show. Invoke as less(args) or less(options, &block)"
|
35
12
|
else
|
36
|
-
File.popen(less_cmd, "w") do |f|
|
13
|
+
File.popen(IrbHacks.conf.less_cmd, "w") do |f|
|
37
14
|
f.puts args
|
38
15
|
end
|
39
16
|
end
|
@@ -62,7 +39,7 @@ module IrbHacks #:nodoc:
|
|
62
39
|
old_stdout = STDOUT.clone
|
63
40
|
old_stderr = STDERR.clone if o_stderr
|
64
41
|
|
65
|
-
File.popen(less_cmd, "w") do |f|
|
42
|
+
File.popen(IrbHacks.conf.less_cmd, "w") do |f|
|
66
43
|
STDOUT.reopen(f)
|
67
44
|
STDERR.reopen(f) if o_stderr
|
68
45
|
yield
|
@@ -78,6 +55,33 @@ module IrbHacks #:nodoc:
|
|
78
55
|
module InstanceMethods
|
79
56
|
private
|
80
57
|
|
58
|
+
# Dump program data with GNU <tt>less</tt> or the other configured OS pager.
|
59
|
+
#
|
60
|
+
# Plain form:
|
61
|
+
#
|
62
|
+
# less "hello", "world"
|
63
|
+
# less mydata
|
64
|
+
#
|
65
|
+
# Block form:
|
66
|
+
#
|
67
|
+
# less do
|
68
|
+
# puts "hello, world"
|
69
|
+
# end
|
70
|
+
#
|
71
|
+
# less(:stderr => true) do
|
72
|
+
# puts "to stdout"
|
73
|
+
# STDERR.puts "to stderr"
|
74
|
+
# end
|
75
|
+
#
|
76
|
+
# Block form options:
|
77
|
+
#
|
78
|
+
# :stderr => T|F # Redirect STDERR too.
|
79
|
+
#
|
80
|
+
# If block form option is String or Symbol, it's automatically
|
81
|
+
# converted to Hash like <tt>{:var => true}</tt>. Thus, you can write <tt>less(:stderr)</tt>
|
82
|
+
# for <tt>less(:stderr => true)</tt>, they are functionally identical.
|
83
|
+
#
|
84
|
+
# See also IrbHacks::Config::less_cmd.
|
81
85
|
def less(*args, &block)
|
82
86
|
::Kernel.less(*args, &block)
|
83
87
|
end
|
data/lib/irb_hacks/snippet.rb
CHANGED
@@ -1,43 +1,66 @@
|
|
1
1
|
require "readline"
|
2
2
|
|
3
|
-
module IrbHacks
|
3
|
+
module IrbHacks
|
4
|
+
# Snippet manipulation internals.
|
4
5
|
module Snippet
|
5
|
-
#
|
6
|
-
|
7
|
-
|
6
|
+
# Initializer.
|
7
|
+
def self._initialize #:nodoc:
|
8
|
+
load_history
|
9
|
+
end
|
10
|
+
|
11
|
+
# On-the-fly initializer.
|
12
|
+
def self._otf_init #:nodoc:
|
13
|
+
# Consider job done, replace self with a blank.
|
14
|
+
class_eval {
|
15
|
+
def self._otf_init #:nodoc:
|
16
|
+
end
|
17
|
+
}
|
8
18
|
|
9
|
-
|
19
|
+
_initialize
|
20
|
+
end
|
21
|
+
|
22
|
+
# Interactively edit code snippet.
|
10
23
|
def self.edit
|
11
|
-
|
24
|
+
_otf_init
|
25
|
+
|
26
|
+
# Gracefully catch Ctrl-C.
|
27
|
+
old_sigint = trap("INT") do
|
28
|
+
puts "\nAborted"
|
29
|
+
return nil
|
30
|
+
end
|
31
|
+
|
32
|
+
#DEBUG
|
33
|
+
##p "RH at inv", Readline::HISTORY.to_a
|
12
34
|
##p "@history at inv", @history
|
13
35
|
|
14
|
-
|
15
|
-
npushed = @history.size
|
16
|
-
@history.each {|s| Readline::HISTORY.push s}
|
36
|
+
rl_history = _replace_rl_history(@history)
|
17
37
|
|
18
|
-
##p "
|
38
|
+
##p "RH at cp 1", Readline::HISTORY.to_a #DEBUG
|
19
39
|
|
20
|
-
#
|
21
|
-
|
40
|
+
# Read input.
|
41
|
+
# NOTE: Readline help is missing.
|
42
|
+
input = Readline.readline(IrbHacks.conf.snippet_prompt, true).strip
|
22
43
|
|
23
|
-
if
|
24
|
-
# Accept entry.
|
25
|
-
@history << input
|
44
|
+
return nil if input.empty?
|
26
45
|
|
27
|
-
|
28
|
-
|
29
|
-
end
|
46
|
+
# Accept input.
|
47
|
+
@history << input
|
30
48
|
|
31
|
-
#
|
32
|
-
|
49
|
+
# Remove duplicates. Most recent bubble up.
|
50
|
+
# [1, 2, 3, 2] will render into [1, 3, 2] with 2 being the last snippet.
|
51
|
+
@history = (@history.reverse.uniq).reverse
|
33
52
|
|
34
|
-
##p "
|
53
|
+
##p "RH after restore", Readline::HISTORY.to_a #DEBUG
|
35
54
|
|
36
|
-
# Save history
|
55
|
+
# Save our history now.
|
37
56
|
save_history
|
38
57
|
|
39
58
|
# Don't clutter IRB screen with anything extra.
|
40
59
|
nil
|
60
|
+
ensure
|
61
|
+
##puts "-- ensure" #DEBUG
|
62
|
+
trap("INT", &old_sigint) if old_sigint
|
63
|
+
_replace_rl_history(rl_history) if rl_history
|
41
64
|
end
|
42
65
|
|
43
66
|
def self.history
|
@@ -48,20 +71,19 @@ module IrbHacks #:nodoc:
|
|
48
71
|
@history = ar
|
49
72
|
end
|
50
73
|
|
74
|
+
# Load history from a file.
|
51
75
|
def self.load_history
|
52
76
|
@history = begin
|
53
|
-
|
54
|
-
YAML.load(content)
|
77
|
+
File.readlines(File.expand_path(IrbHacks.conf.snippet_history_file)).map(&:chomp)
|
55
78
|
rescue
|
56
|
-
|
79
|
+
[%{puts "YOUR test code here"}]
|
57
80
|
end
|
58
|
-
|
59
|
-
@history = [%{puts "YOUR test code here"}] if not @history
|
60
81
|
end
|
61
82
|
|
62
|
-
# Run code snippet.
|
63
|
-
# If <tt>IrbHacks.break</tt> is called anywhere, immediately return its argument.
|
83
|
+
# Run latest edited code snippet. If IrbHacks::break is called anywhere, immediately return its argument.
|
64
84
|
def self.run(*args, &block)
|
85
|
+
_otf_init
|
86
|
+
|
65
87
|
if (code = @history.last)
|
66
88
|
begin
|
67
89
|
eval(code, &block)
|
@@ -72,16 +94,25 @@ module IrbHacks #:nodoc:
|
|
72
94
|
end
|
73
95
|
end
|
74
96
|
|
97
|
+
# Save history to a file.
|
75
98
|
def self.save_history
|
76
|
-
# Truncate
|
77
|
-
|
78
|
-
|
79
|
-
|
99
|
+
# Truncate and save history.
|
100
|
+
# NOTE: It's more logical (WYSIWYG) to truncate @history live, not its copy. Thus the user will see what's going to be saved & restored.
|
101
|
+
@history.slice!(0..-(IrbHacks.conf.snippet_history_size + 1))
|
102
|
+
File.open(File.expand_path(IrbHacks.conf.snippet_history_file), "w") do |f|
|
103
|
+
f.puts @history
|
80
104
|
end
|
81
105
|
end
|
82
106
|
|
83
|
-
#---------------------------------------
|
107
|
+
#---------------------------------------
|
84
108
|
|
85
|
-
|
109
|
+
# Clear Readline history and optionally replace it with new content.
|
110
|
+
# Return previous content.
|
111
|
+
def self._replace_rl_history(ar = nil) #:nodoc:
|
112
|
+
out = []
|
113
|
+
while (s = Readline::HISTORY.shift); out << s; end
|
114
|
+
ar.each {|s| Readline::HISTORY << s} if ar
|
115
|
+
out
|
116
|
+
end
|
86
117
|
end # Snippet
|
87
118
|
end # IrbHacks
|
data/lib/irb_hacks.rb
CHANGED
@@ -1,27 +1,51 @@
|
|
1
|
-
require "yaml"
|
2
|
-
|
3
1
|
Dir[File.join(File.dirname(__FILE__), "irb_hacks/**/*.rb")].each {|fn| require fn}
|
4
2
|
|
5
|
-
|
6
|
-
|
3
|
+
# Yet another set of IRB hacks.
|
4
|
+
#
|
5
|
+
# Summary of features brought to IRB:
|
6
|
+
#
|
7
|
+
# * <tt>a</tt> and <tt>ae</tt> methods to invoke or edit code snippets.
|
8
|
+
# * <tt>less</tt> method to interactively dump data with OS pages like <tt>less</tt>.
|
9
|
+
# * IrbHacks::break to instantly return value from code into IRB.
|
10
|
+
module IrbHacks #:doc:
|
11
|
+
# Break execution, instantly return value if caller is invoked from a snippet.
|
12
|
+
#
|
13
|
+
# def myfunc
|
14
|
+
# puts "Reading name..."
|
15
|
+
# name = File.read(...)
|
16
|
+
# IrbHacks.break name #DEBUG: See what's been read.
|
17
|
+
#
|
18
|
+
# # Other code...
|
19
|
+
# end
|
7
20
|
#
|
8
|
-
#
|
9
|
-
#
|
21
|
+
# irb> ae
|
22
|
+
# snippet>> myfunc
|
23
|
+
# irb> a
|
24
|
+
# Reading name...
|
25
|
+
# => "John Smith"
|
10
26
|
def self.break(value = nil)
|
11
27
|
raise BreakException, [value]
|
12
28
|
end
|
13
29
|
|
14
|
-
|
30
|
+
# Access configuration object. See IrbHacks::Config.
|
31
|
+
#
|
32
|
+
# IrbHacks.conf
|
33
|
+
# IrbHacks.conf.snippet_history_size = 200
|
34
|
+
def self.conf
|
35
|
+
@conf ||= Config.new
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
#--------------------------------------- Junk
|
40
|
+
|
41
|
+
if false
|
42
|
+
def self.less_cmd #:nodoc:
|
15
43
|
@less_cmd
|
16
44
|
end
|
17
45
|
|
18
|
-
def self.less_cmd=(cmd)
|
46
|
+
def self.less_cmd=(cmd) #:nodoc:
|
19
47
|
@less_cmd = cmd
|
20
48
|
end
|
21
49
|
|
22
|
-
class BreakException < Exception; end
|
23
|
-
|
24
|
-
#--------------------------------------- Defaults
|
25
|
-
|
26
50
|
self.less_cmd = "less -R"
|
27
51
|
end
|
metadata
CHANGED
@@ -1,12 +1,8 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: irb_hacks
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
prerelease:
|
5
|
-
|
6
|
-
- 0
|
7
|
-
- 2
|
8
|
-
- 0
|
9
|
-
version: 0.2.0
|
4
|
+
prerelease:
|
5
|
+
version: 0.2.2
|
10
6
|
platform: ruby
|
11
7
|
authors:
|
12
8
|
- Alex Fortuna
|
@@ -14,7 +10,7 @@ autorequire:
|
|
14
10
|
bindir: bin
|
15
11
|
cert_chain: []
|
16
12
|
|
17
|
-
date:
|
13
|
+
date: 2011-07-12 00:00:00 +04:00
|
18
14
|
default_executable:
|
19
15
|
dependencies: []
|
20
16
|
|
@@ -28,7 +24,6 @@ extra_rdoc_files:
|
|
28
24
|
- README.html
|
29
25
|
- README.md
|
30
26
|
files:
|
31
|
-
- CHANGELOG.md
|
32
27
|
- MIT-LICENSE
|
33
28
|
- README.html
|
34
29
|
- README.md
|
@@ -36,6 +31,8 @@ files:
|
|
36
31
|
- VERSION.yml
|
37
32
|
- irb_hacks.gemspec
|
38
33
|
- lib/irb_hacks.rb
|
34
|
+
- lib/irb_hacks/break_exception.rb
|
35
|
+
- lib/irb_hacks/config.rb
|
39
36
|
- lib/irb_hacks/core_ext/kernel/a_and_ae.rb
|
40
37
|
- lib/irb_hacks/core_ext/kernel/less.rb
|
41
38
|
- lib/irb_hacks/snippet.rb
|
@@ -53,21 +50,17 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
53
50
|
requirements:
|
54
51
|
- - ">="
|
55
52
|
- !ruby/object:Gem::Version
|
56
|
-
segments:
|
57
|
-
- 0
|
58
53
|
version: "0"
|
59
54
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
60
55
|
none: false
|
61
56
|
requirements:
|
62
57
|
- - ">="
|
63
58
|
- !ruby/object:Gem::Version
|
64
|
-
segments:
|
65
|
-
- 0
|
66
59
|
version: "0"
|
67
60
|
requirements: []
|
68
61
|
|
69
62
|
rubyforge_project:
|
70
|
-
rubygems_version: 1.
|
63
|
+
rubygems_version: 1.6.2
|
71
64
|
signing_key:
|
72
65
|
specification_version: 3
|
73
66
|
summary: Yet another set of IRB hacks
|