mfe 1.1
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/bin/mfe +37 -0
- data/doc/LICENSE +19 -0
- data/doc/README +136 -0
- data/lib/mfe-config.rb +8 -0
- data/lib/mfe.rb +260 -0
- metadata +75 -0
data/bin/mfe
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
#! /usr/bin/ruby
|
2
|
+
# MFE the meta-frontend
|
3
|
+
# Reducing clutter in ~/bin since 2005.
|
4
|
+
#
|
5
|
+
# By Pete Elmore (1337p337@gmail.com)
|
6
|
+
# http://debu.gs/mfe
|
7
|
+
#
|
8
|
+
# For licensing and copyright information, see the file LICENSE in doc/ .
|
9
|
+
|
10
|
+
require 'rubygems'
|
11
|
+
require 'mfe'
|
12
|
+
|
13
|
+
# int main(int argc, char *argv[])
|
14
|
+
include MFE
|
15
|
+
cmdname = ARGV.shift
|
16
|
+
case cmdname
|
17
|
+
when nil
|
18
|
+
usage
|
19
|
+
when '-h', /^-?-?help$/ # Help
|
20
|
+
usage $stdout
|
21
|
+
when '-V', /^-?-?version$/ # Version info
|
22
|
+
puts version_string
|
23
|
+
when CommandSig # MFE mode
|
24
|
+
methname = MLook[ARGV.first]
|
25
|
+
unless methname
|
26
|
+
usage
|
27
|
+
exit 1
|
28
|
+
end
|
29
|
+
ARGV.shift
|
30
|
+
send methname, *ARGV
|
31
|
+
else # Execution mode
|
32
|
+
exec_cmd(cmdname, *ARGV)
|
33
|
+
# exec_cmd() doesn't return unless there was an error.
|
34
|
+
exit 1
|
35
|
+
end
|
36
|
+
|
37
|
+
exit 0
|
data/doc/LICENSE
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
Copyright (c) 2005-2006, 2008-2010, 2012 Peter Elmore (pete at debu dot gs)
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a
|
4
|
+
copy of this software and associated documentation files (the "Software"),
|
5
|
+
to deal in the Software without restriction, including without limitation
|
6
|
+
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
7
|
+
and/or sell copies of the Software, and to permit persons to whom the
|
8
|
+
Software is furnished to do so, subject to the following conditions:
|
9
|
+
|
10
|
+
The above copyright notice and this permission notice shall be included in
|
11
|
+
all copies or substantial portions of the Software.
|
12
|
+
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
16
|
+
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
18
|
+
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
19
|
+
DEALINGS IN THE SOFTWARE.
|
data/doc/README
ADDED
@@ -0,0 +1,136 @@
|
|
1
|
+
= MFE
|
2
|
+
|
3
|
+
== Installation
|
4
|
+
|
5
|
+
You can install via rubygems,
|
6
|
+
|
7
|
+
gem install mfe
|
8
|
+
|
9
|
+
or plain old setup.rb:
|
10
|
+
|
11
|
+
ruby setup.rb install
|
12
|
+
|
13
|
+
== How to use MFE
|
14
|
+
|
15
|
+
MFE has two main modes: command mode, and execution mode.
|
16
|
+
|
17
|
+
=== Quick Version
|
18
|
+
|
19
|
+
Here's the quick version of this README, because seriously, you're not going
|
20
|
+
to read this until you get confused:
|
21
|
+
|
22
|
+
mfe - add say-hi echo hi
|
23
|
+
mfe say-hi
|
24
|
+
=> hi
|
25
|
+
mfe - add say-whatever echo ARGS
|
26
|
+
mfe say-whatever it can be whatever
|
27
|
+
=> it can be whatever
|
28
|
+
mfe - add argplay echo 'ARGEVAL[ arg.sub(/d/, "date"); ]' 'EVAL[(argv.map { |arg| arg.sub "date", `date`.chomp }).join " -- "]'
|
29
|
+
mfe argplay a s d f
|
30
|
+
=> "a -- s -- Tue Sep 19 01:28:48 PDT 2006 -- f"
|
31
|
+
|
32
|
+
Also, several variations of 'mfe -h', 'mfe --help', 'mfe help', etc., do what
|
33
|
+
you expect.
|
34
|
+
|
35
|
+
=== Command Mode
|
36
|
+
|
37
|
+
In command mode, you can add, edit, remove, or otherwise manipulate the
|
38
|
+
user-defined commands.
|
39
|
+
|
40
|
+
==== To add a new command
|
41
|
+
|
42
|
+
mfe - add cmdname command-and-args
|
43
|
+
|
44
|
+
This is the format for adding a command to MFE. The first argument to mfe is
|
45
|
+
'-', the command character. This signals to MFE that we will be running an
|
46
|
+
MFE command, as opposed to executing a command we have defined. After that
|
47
|
+
comes 'add', the keyword that tells MFE which command to perform. 'cmdname'
|
48
|
+
is the name given to the command. It can be whatever you want, but must be
|
49
|
+
legal as a filename. The 'command-and-args' part is the command you actually
|
50
|
+
want to run when you type 'mfe cmdname'. As a more concrete example, have a
|
51
|
+
look at this:
|
52
|
+
|
53
|
+
mfe - add hgr grep ARGS /usr/log/httpd.log
|
54
|
+
|
55
|
+
Which creates a command named 'hgr' that greps /usr/log/httpd.log for whatever
|
56
|
+
arguments you pass it:
|
57
|
+
|
58
|
+
mfe hgr -i googlebot
|
59
|
+
|
60
|
+
Executing the previous command is equivalent to running
|
61
|
+
|
62
|
+
grep -i googlebot /usr/log/httpd.log
|
63
|
+
|
64
|
+
As you might have guessed, ARGS is replaced by whatever arguments you pass
|
65
|
+
when you execute the command. There are two other special strings: EVAL[]
|
66
|
+
and ARGEVAL[]. EVAL[] is replaced with the value of the Ruby code inside the
|
67
|
+
brackets. The Ruby inside ARGVEVAL[] is evaluated once for each argument
|
68
|
+
(bound to 'arg') and its value replaces the argument. The variable 'argv' is
|
69
|
+
exposed to both constructs. A couple of examples should make it clearer:
|
70
|
+
|
71
|
+
mfe - add reverse-args echo 'ARGEVAL[ arg.reverse ]' ARGS
|
72
|
+
mfe reverse-args Hello, World.
|
73
|
+
=> ,olleH .dlroW
|
74
|
+
mfe - add reverse-argv echo 'EVAL[ argv.reverse.join(" ") ]'
|
75
|
+
mfe reverse-argv Hello, World.
|
76
|
+
=> World. Hello,
|
77
|
+
mfe - add reverse-both echo 'ARGEVAL[ arg.reverse ]' 'EVAL[ argv.reverse.join(" ") ]'
|
78
|
+
mfe reverse-both Hello, World.
|
79
|
+
=> .dlroW ,olleH
|
80
|
+
mfe reverse-both $(mfe reverse-args $(mfe reverse-argv Hello, World.))
|
81
|
+
=> Hello, World.
|
82
|
+
|
83
|
+
==== To edit a command
|
84
|
+
|
85
|
+
mfe - edit cmdname
|
86
|
+
|
87
|
+
This brings up the JSON representing the command in your editor.
|
88
|
+
|
89
|
+
==== To remove a command
|
90
|
+
|
91
|
+
Simply do
|
92
|
+
|
93
|
+
mfe - rm cmdname1 cmdname2
|
94
|
+
|
95
|
+
==== To generate a shell script from a command
|
96
|
+
|
97
|
+
mfe - add echo-args echo ARGS
|
98
|
+
mfe - to-shell echo-args A S D F > echoargs.sh
|
99
|
+
|
100
|
+
Or, a little more creatively,
|
101
|
+
|
102
|
+
mfe - to-shell useful-command | ssh user@host-without-ruby 'cat > bin/cmd'
|
103
|
+
|
104
|
+
=== Execution Mode
|
105
|
+
|
106
|
+
mfe cmdname args
|
107
|
+
|
108
|
+
Execution mode refers to the loading and evaluation of a command. Execution
|
109
|
+
mode is invoked by running mfe followed by the name of a command and
|
110
|
+
(optionally) any arguments you wish to pass to it. For example:
|
111
|
+
|
112
|
+
Add a command,
|
113
|
+
|
114
|
+
mfe - add testcommand for i in ARGS; do indent \$i; done
|
115
|
+
|
116
|
+
then execute it:
|
117
|
+
|
118
|
+
mfe testcommand *.c
|
119
|
+
|
120
|
+
== Environment Variables
|
121
|
+
|
122
|
+
There are two relevant environment variables: MFE_HOME and MFE_COMMAND_SIG .
|
123
|
+
MFE_HOME can be used to change the location of your MFE command directory
|
124
|
+
(the default is ~/.mfe). MFE_COMMAND_SIG changes the string used for
|
125
|
+
signaling command mode (default '-'). For example,
|
126
|
+
|
127
|
+
MFE_HOME=/tmp/foo MFE_COMMAND_SIG=c_mode mfe c_mode add hi echo hi
|
128
|
+
|
129
|
+
creates a command named 'hi' which executes 'echo hi', and places it in
|
130
|
+
/tmp/foo/hi . Note that the mfe home is created automatically, with
|
131
|
+
permissions set to 0700.
|
132
|
+
|
133
|
+
== Credits
|
134
|
+
|
135
|
+
Pete Elmore -- (pete at debu dot gs)
|
136
|
+
|
data/lib/mfe-config.rb
ADDED
data/lib/mfe.rb
ADDED
@@ -0,0 +1,260 @@
|
|
1
|
+
# MFE the meta-frontend!
|
2
|
+
#
|
3
|
+
# Reducing clutter in ~/bin since 2005. And, although it seems to have survived
|
4
|
+
# several major revisions of Ruby without blinking, it finally needed
|
5
|
+
# maintenance when the damned YAML parser changed. It's JSON now; MFE was
|
6
|
+
# written before JSON was cool. In fact, it is so old there is no Rakefile, but
|
7
|
+
# there is a _darcs. Hopefully JSON will change less frequently and I won't
|
8
|
+
# have to open this file again for another few years.
|
9
|
+
#
|
10
|
+
# By Pete Elmore (http://debu.gs/)
|
11
|
+
#
|
12
|
+
# For licensing and copyright information, see the file LICENSE in doc/ .
|
13
|
+
|
14
|
+
%w(mfe-config fileutils json tempfile etc metaid escape
|
15
|
+
).each(&method(:require))
|
16
|
+
|
17
|
+
class String
|
18
|
+
def shell_escape
|
19
|
+
Escape.shell_single_word self
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
# This module houses the main logic for MFE.
|
24
|
+
module MFE
|
25
|
+
# Method lookup table for commands
|
26
|
+
MLook = {
|
27
|
+
'add' => :add_cmd,
|
28
|
+
'edit' => :edit_json,
|
29
|
+
'show' => :show_cmd,
|
30
|
+
'to-shell' => :cmd_to_shell,
|
31
|
+
'rm' => :rm_cmd,
|
32
|
+
'remove' => :rm_cmd,
|
33
|
+
}
|
34
|
+
|
35
|
+
# This is the character (or string) that indicates that we will be
|
36
|
+
# running an MFE command rather than loading and executing a
|
37
|
+
# user-defined command.
|
38
|
+
CommandSig = ENV['MFE_COMMAND_SIG'] || '-'
|
39
|
+
|
40
|
+
def dirnames
|
41
|
+
# Possible directories for housing mfe commands.
|
42
|
+
@dirnames ||= [ENV['MFE_HOME'],
|
43
|
+
(File.join(ENV['HOME'], '/.mfe') rescue nil),
|
44
|
+
File.join(Etc.getpwuid(Process.euid).dir, '/.mfe'),
|
45
|
+
].compact
|
46
|
+
end
|
47
|
+
|
48
|
+
# Loads a command with the given name
|
49
|
+
def load_cmd(name)
|
50
|
+
Cmd.load full_path(name)
|
51
|
+
end
|
52
|
+
|
53
|
+
# Loads and executes a command named by +name+ with args +argv+.
|
54
|
+
def exec_cmd(name, *argv)
|
55
|
+
begin
|
56
|
+
exec load_cmd(name).expand(argv)
|
57
|
+
rescue Errno::E2BIG
|
58
|
+
fp = full_path name
|
59
|
+
$stderr.puts "Couldn't execute #{name}!", "Argument list too long."
|
60
|
+
rescue Exception => e
|
61
|
+
fp = full_path name
|
62
|
+
$stderr.puts "Couldn't execute #{name}! (#{e.message})"
|
63
|
+
|
64
|
+
if !File.exist? fp
|
65
|
+
$stderr.puts 'File does not exist.'
|
66
|
+
elsif !File.readable? fp
|
67
|
+
$stderr.puts 'File is not readable.'
|
68
|
+
elsif File.directory? fp
|
69
|
+
$stderr.puts 'It\'s a directory.'
|
70
|
+
else
|
71
|
+
$stderr.puts e.inspect
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
# Given a list of command names, show_cmd will print what each one does.
|
77
|
+
# In the absense of a list of names, it will print all commands in the
|
78
|
+
# .mfe directory.
|
79
|
+
def show_cmd(*names)
|
80
|
+
if names.empty?
|
81
|
+
names = Dir["#{dirname}/*"] - %w(. ..)
|
82
|
+
names.map! &File.method(:basename)
|
83
|
+
end
|
84
|
+
|
85
|
+
names.sort.each { |name|
|
86
|
+
puts "#{name}: #{load_cmd(name).to_s}"
|
87
|
+
}
|
88
|
+
end
|
89
|
+
|
90
|
+
# Given a name and a list of args, this method prints a shell script
|
91
|
+
# that would have the effect of running the command.
|
92
|
+
def cmd_to_shell(name, *argv)
|
93
|
+
cmd = load_cmd(name)
|
94
|
+
shell = [
|
95
|
+
`which ENV['SHELL'] 2>/dev/null`,
|
96
|
+
Etc.getpwuid(Process.uid).shell,
|
97
|
+
'/bin/sh',
|
98
|
+
].find { |shell| !shell.chomp.empty? }
|
99
|
+
|
100
|
+
puts("#!#{shell}",
|
101
|
+
cmd.expand(argv))
|
102
|
+
true
|
103
|
+
end
|
104
|
+
|
105
|
+
# Removes commands! :O
|
106
|
+
def rm_cmd(names)
|
107
|
+
names.each { |name|
|
108
|
+
File.unlink full_path(name)
|
109
|
+
}
|
110
|
+
end
|
111
|
+
|
112
|
+
# Adds a new command.
|
113
|
+
def add_cmd(name, *cmd)
|
114
|
+
if cmd.empty?
|
115
|
+
cmd = edit_json(name)
|
116
|
+
return false if cmd.to_s.empty?
|
117
|
+
else
|
118
|
+
cmd = Cmd.new(name, cmd)
|
119
|
+
end
|
120
|
+
cmd.save(dirname!)
|
121
|
+
end
|
122
|
+
|
123
|
+
# Allows the user to directly edit the JSON representation of a command.
|
124
|
+
def edit_json(name, *argv)
|
125
|
+
system editor, full_path!(name)
|
126
|
+
$?.exited?
|
127
|
+
end
|
128
|
+
|
129
|
+
# Returns the first viable directory for the MFE directory. If none is
|
130
|
+
# found, returns nil. Otherwise, it's guaranteed to always return the
|
131
|
+
# same value.
|
132
|
+
def dirname
|
133
|
+
dir = dirnames.find { |d| File.directory?(d) }
|
134
|
+
if dir
|
135
|
+
# It's important for this to be consistent (and faster anyway).
|
136
|
+
meta_def(:dirname) { dir }
|
137
|
+
return dir
|
138
|
+
end
|
139
|
+
nil
|
140
|
+
end
|
141
|
+
|
142
|
+
# Returns the dirname, but if it's nil, makes the directory with
|
143
|
+
# permissions 0700.
|
144
|
+
def dirname!
|
145
|
+
return dirname if dirname
|
146
|
+
Dir.mkdir(dirnames.first, 0700)
|
147
|
+
dirname
|
148
|
+
end
|
149
|
+
|
150
|
+
# Returns the user's (suspected) preferred editor.
|
151
|
+
def editor
|
152
|
+
ENV['VISUAL'] ||
|
153
|
+
ENV['EDITOR'] ||
|
154
|
+
'vi' # Reasonable default.
|
155
|
+
end
|
156
|
+
|
157
|
+
# Returns the full path for a given command with name +name+.
|
158
|
+
def full_path(name)
|
159
|
+
File.join(dirname, name)
|
160
|
+
end
|
161
|
+
|
162
|
+
# Returns the full path for a given command with name +name+, and
|
163
|
+
# creates the path if it does not exist.
|
164
|
+
def full_path!(name)
|
165
|
+
fn = File.join(dirname!, name)
|
166
|
+
File.open(fn, 'a').close
|
167
|
+
fn
|
168
|
+
end
|
169
|
+
|
170
|
+
def usage(out = $stderr)
|
171
|
+
out.puts [ "",
|
172
|
+
"MFE, the meta front-end (#{MFEConfig::URL})",
|
173
|
+
"Usage:",
|
174
|
+
"#{$0} #{CommandSig} command [args ...]",
|
175
|
+
" Where command is one of",
|
176
|
+
" add name script [args ...]:",
|
177
|
+
" Adds a command named 'name' that executes " +
|
178
|
+
"'script [args ...]'.",
|
179
|
+
" show [name(s)]",
|
180
|
+
" Shows the command(s) named, or all commands if none " +
|
181
|
+
"are named.",
|
182
|
+
" edit name",
|
183
|
+
" Runs your favorite editor on the named command.",
|
184
|
+
" to-shell name [args ...]",
|
185
|
+
" Turns the user-defined command into a shell script.",
|
186
|
+
"#{$0} your_command [args ...]",
|
187
|
+
" Runs the user-defined command named 'your_command' with the " +
|
188
|
+
"specified\n arguments.",
|
189
|
+
"#{$0} ['-h'|'-help'|'--help']",
|
190
|
+
" This help screen.",
|
191
|
+
"See the README for more info about usage and influential " +
|
192
|
+
"environment\nvariables.",
|
193
|
+
]
|
194
|
+
end
|
195
|
+
|
196
|
+
def version_string
|
197
|
+
"MFE, version #{MFEConfig::Version}."
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
# Represents an individual command
|
202
|
+
class Cmd
|
203
|
+
attr_accessor :name
|
204
|
+
|
205
|
+
# Turns a filename into a command! Amazing! Pass the full path.
|
206
|
+
def self.load(filename)
|
207
|
+
obj = JSON.parse(File.read(filename))
|
208
|
+
|
209
|
+
new(File.basename(filename), obj['cmd'])
|
210
|
+
end
|
211
|
+
|
212
|
+
# +save+, saves the command to a file.
|
213
|
+
def save(dirname)
|
214
|
+
File.open(File.join(dirname, @name), 'w') { |f|
|
215
|
+
f.puts JSON.pretty_unparse(to_hash)
|
216
|
+
}
|
217
|
+
end
|
218
|
+
|
219
|
+
# Creates a new command.
|
220
|
+
def initialize(name, cmd)
|
221
|
+
@name = name
|
222
|
+
@cmd = cmd
|
223
|
+
end
|
224
|
+
|
225
|
+
# +to_s+ simply returns the command string.
|
226
|
+
def to_s
|
227
|
+
@cmd.join(' ')
|
228
|
+
end
|
229
|
+
|
230
|
+
def to_hash
|
231
|
+
{name: @name, cmd: @cmd}
|
232
|
+
end
|
233
|
+
|
234
|
+
# Turns the command into a line of shell, fit to be exec()'d or ``'d.
|
235
|
+
def expand(argv)
|
236
|
+
argv = argv.map(&:shell_escape)
|
237
|
+
@cmd.map { |this_arg|
|
238
|
+
a = this_arg.dup
|
239
|
+
a.gsub!(/\bARGS\b/, argv.join(' '))
|
240
|
+
a.gsub!(/\bARGEVAL\[(.*)\]/) { |m|
|
241
|
+
argeval = $1
|
242
|
+
argv.map! { |frozen_arg|
|
243
|
+
arg = frozen_arg.dup
|
244
|
+
eval(argeval, binding).to_s
|
245
|
+
}
|
246
|
+
''
|
247
|
+
}
|
248
|
+
a.gsub!(/\bEVAL\[(.*)\]/) { |m|
|
249
|
+
eval($1, binding).to_s
|
250
|
+
}
|
251
|
+
a
|
252
|
+
}.join(' ')
|
253
|
+
end
|
254
|
+
|
255
|
+
# +run+ runs the command, returning the output.
|
256
|
+
def run(argv)
|
257
|
+
`#{expand argv}`
|
258
|
+
end
|
259
|
+
end
|
260
|
+
|
metadata
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: mfe
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: '1.1'
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Pete Elmore
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-06-13 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: metaid
|
16
|
+
requirement: &6886860 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *6886860
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: escape
|
27
|
+
requirement: &8227460 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ! '>='
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '0'
|
33
|
+
type: :runtime
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *8227460
|
36
|
+
description:
|
37
|
+
email: pete@debu.gs
|
38
|
+
executables:
|
39
|
+
- mfe
|
40
|
+
extensions: []
|
41
|
+
extra_rdoc_files:
|
42
|
+
- doc/README
|
43
|
+
- doc/LICENSE
|
44
|
+
files:
|
45
|
+
- bin/mfe
|
46
|
+
- doc/LICENSE
|
47
|
+
- doc/README
|
48
|
+
- lib/mfe.rb
|
49
|
+
- lib/mfe-config.rb
|
50
|
+
homepage: http://debu.gs/mfe
|
51
|
+
licenses: []
|
52
|
+
post_install_message:
|
53
|
+
rdoc_options: []
|
54
|
+
require_paths:
|
55
|
+
- lib
|
56
|
+
- lib
|
57
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
58
|
+
none: false
|
59
|
+
requirements:
|
60
|
+
- - ! '>='
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: '0'
|
63
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
64
|
+
none: false
|
65
|
+
requirements:
|
66
|
+
- - ! '>='
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
requirements: []
|
70
|
+
rubyforge_project:
|
71
|
+
rubygems_version: 1.8.6
|
72
|
+
signing_key:
|
73
|
+
specification_version: 3
|
74
|
+
summary: A program which remembers and executes brief scripts.
|
75
|
+
test_files: []
|