irb_hacks 0.2.0 → 0.2.2
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/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
|