ripl-shell_commands 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/.document ADDED
@@ -0,0 +1,3 @@
1
+ -
2
+ ChangeLog.md
3
+ LICENSE.txt
data/.gitignore ADDED
@@ -0,0 +1,2 @@
1
+ doc/
2
+ pkg/
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --colour --format documentation
data/.yardopts ADDED
@@ -0,0 +1 @@
1
+ --markup markdown --title "ripl-shell_commands Documentation" --protected
data/ChangeLog.md ADDED
@@ -0,0 +1,12 @@
1
+ ### 0.1.0 / 2012-12-02
2
+
3
+ * Initial release
4
+ * Extracted from [ronin](https://github.com/ronin-ruby/ronin).
5
+ * Use `Ripl.shell.binding` instead of `Ripl.config[:binding]`, which is not
6
+ set when running the `ripl` executable.
7
+ * No longer use `singleton_class.method_defined?` (Ruby 1.9 only) in
8
+ {Ripl::ShellCommands#loop_eval}.
9
+ * No longer use `Shellwords.shelljoin` in {Ripl::ShellCommands.exec},
10
+ which was re-escaping all arguments.
11
+ * Added specs.
12
+
data/LICENSE.txt ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2012 Hal Brodigan
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,47 @@
1
+ # ripl-shell_commands
2
+
3
+ * [Homepage](https://github.com/postmodern/ripl-shell_commands#readme)
4
+ * [Issues](https://github.com/postmodern/ripl-shell_commands/issues)
5
+ * [Documentation](http://rubydoc.info/gems/ripl-shell_commands/frames)
6
+ * [Email](mailto:postmodern.mod3 at gmail.com)
7
+
8
+ ## Description
9
+
10
+ A [ripl] plugin that allows inline shell commands.
11
+
12
+ ## Features
13
+
14
+ ## Examples
15
+
16
+ >> require 'ripl/shell_commands'
17
+ => true
18
+ >> !date
19
+ Sat Dec 1 21:47:55 PST 2012
20
+ => true
21
+ >> !cd /etc/
22
+ => true
23
+ >> @path = '/etc/profile.d/'
24
+ => "/etc/profile.d/"
25
+ >> !ls #{@path}
26
+ bash_completion.sh colorls.csh less.sh qt.sh
27
+ chgems.sh colorls.sh PackageKit.sh vim.csh
28
+ chruby.sh lang.csh qt.csh vim.sh
29
+ colorgrep.csh lang.sh qt-graphicssystem.csh which2.csh
30
+ colorgrep.sh less.csh qt-graphicssystem.sh which2.sh
31
+ >> true
32
+
33
+ ## Requirements
34
+
35
+ * [ripl] ~> 0.3
36
+
37
+ ## Install
38
+
39
+ $ gem install ripl-shell_commands
40
+
41
+ ## Copyright
42
+
43
+ Copyright (c) 2012 Hal Brodigan
44
+
45
+ See {file:LICENSE.txt} for details.
46
+
47
+ [ripl]: https://github.com/cldwalker/ripl#readme
data/Rakefile ADDED
@@ -0,0 +1,40 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rubygems'
4
+ require 'rake'
5
+
6
+ begin
7
+ gem 'rubygems-tasks', '~> 0.2'
8
+ require 'rubygems/tasks'
9
+
10
+ Gem::Tasks.new
11
+ rescue LoadError => e
12
+ warn e.message
13
+ warn "Run `gem install rubygems-tasks` to install Gem::Tasks."
14
+ end
15
+
16
+ begin
17
+ gem 'rspec', '~> 2.4'
18
+ require 'rspec/core/rake_task'
19
+
20
+ RSpec::Core::RakeTask.new
21
+ rescue LoadError => e
22
+ task :spec do
23
+ abort "Please run `gem install rspec` to install RSpec."
24
+ end
25
+ end
26
+
27
+ task :test => :spec
28
+ task :default => :spec
29
+
30
+ begin
31
+ gem 'yard', '~> 0.8'
32
+ require 'yard'
33
+
34
+ YARD::Rake::YardocTask.new
35
+ rescue LoadError => e
36
+ task :yard do
37
+ abort "Please run `gem install yard` to install YARD."
38
+ end
39
+ end
40
+ task :doc => :yard
data/gemspec.yml ADDED
@@ -0,0 +1,16 @@
1
+ name: ripl-shell_commands
2
+ version: 0.1.0
3
+ summary: Ripl plugin that allows inline shell commands
4
+ description: A ripl plugin that allows inline shell commands in the Ripl Shell.
5
+ license: MIT
6
+ authors: Postmodern
7
+ email: postmodern.mod3@gmail.com
8
+ homepage: https://github.com/postmodern/ripl-shell_commands#readme
9
+
10
+ dependencies:
11
+ ripl: ~> 0.3
12
+
13
+ development_dependencies:
14
+ rspec: ~> 2.4
15
+ rubygems-tasks: ~> 0.2
16
+ yard: ~> 0.8
@@ -0,0 +1,21 @@
1
+ complete(:on => Ripl::ShellCommands::PATTERN) do |cmd|
2
+ name = cmd[1..-1]
3
+ glob = "#{name}*"
4
+ paths = Set[]
5
+
6
+ # search through $PATH for similar program names
7
+ Ripl::ShellCommands::PATHS.each do |dir|
8
+ Dir.glob(File.join(dir,glob)) do |path|
9
+ if (File.file?(path) && File.executable?(path))
10
+ paths << "!#{File.basename(path)}"
11
+ end
12
+ end
13
+ end
14
+
15
+ # add the black-listed keywords last
16
+ Ripl::ShellCommands::BLACKLIST.each do |keyword|
17
+ paths << "!#{keyword}" if keyword.start_with?(name)
18
+ end
19
+
20
+ paths
21
+ end
@@ -0,0 +1,159 @@
1
+ require 'set'
2
+ require 'shellwords'
3
+ require 'ripl'
4
+
5
+ module Ripl
6
+ #
7
+ # Allows for executing shell commands prefixed by a `!`.
8
+ #
9
+ module ShellCommands
10
+ # The directories of `$PATH`.
11
+ PATHS = ENV['PATH'].split(File::PATH_SEPARATOR)
12
+
13
+ # Names and statuses of executables.
14
+ EXECUTABLES = Hash.new do |hash,key|
15
+ hash[key] = executable?(key) || PATHS.any? do |dir|
16
+ executable?(File.join(dir,key))
17
+ end
18
+ end
19
+
20
+ # Builtin commands
21
+ BUILTIN = Set['cd', 'export']
22
+
23
+ # Blacklist of known commands that conflict with Ruby keywords.
24
+ BLACKLIST = Set[
25
+ '[', 'ap', 'begin', 'case', 'class', 'def', 'fail', 'false',
26
+ 'for', 'if', 'lambda', 'load', 'loop', 'module', 'p', 'pp',
27
+ 'print', 'proc', 'puts', 'raise', 'require', 'true', 'undef',
28
+ 'unless', 'until', 'warn', 'while'
29
+ ]
30
+
31
+ # Regexp to recognize `!commands`.
32
+ PATTERN = /^![a-zA-Z][a-zA-Z0-9\._-]*/
33
+
34
+ #
35
+ # Dynamically execute shell commands, instead of Ruby.
36
+ #
37
+ # @param [String] input
38
+ # The input from the console.
39
+ #
40
+ def loop_eval(input)
41
+ if (@buffer.nil? && input =~ PATTERN)
42
+ command = input[1..-1]
43
+ name, arguments = ShellCommands.parse(command)
44
+
45
+ unless BLACKLIST.include?(name)
46
+ if BUILTIN.include?(name)
47
+ arguments ||= []
48
+
49
+ return ShellCommands.send(name,*arguments)
50
+ elsif EXECUTABLES[name]
51
+ return ShellCommands.exec(name,*arguments)
52
+ end
53
+ end
54
+ end
55
+
56
+ super(input)
57
+ end
58
+
59
+ #
60
+ # Parses a Console command.
61
+ #
62
+ # @param [String] command
63
+ # The Console command to parse.
64
+ #
65
+ # @return [String, Array<String>]
66
+ # The command name and additional arguments.
67
+ #
68
+ def self.parse(command)
69
+ # evaluate embedded Ruby expressions
70
+ command = command.gsub(/\#\{[^\}]*\}/) do |expression|
71
+ eval(expression[2..-2],Ripl.shell.binding).to_s.dump
72
+ end
73
+
74
+ arguments = Shellwords.shellsplit(command)
75
+ name = arguments.shift
76
+
77
+ return name, arguments
78
+ end
79
+
80
+ #
81
+ # Determines if an executable exists on the system.
82
+ #
83
+ # @param [String] path
84
+ # The program path.
85
+ #
86
+ # @return [Boolean]
87
+ # Specifies whether the executable exists.
88
+ #
89
+ def self.executable?(path)
90
+ File.file?(path) && File.executable?(path)
91
+ end
92
+
93
+ #
94
+ # Default command which executes a command in the shell.
95
+ #
96
+ # @param [Array<String>] arguments
97
+ # The arguments of the command.
98
+ #
99
+ # @return [Boolean]
100
+ # Specifies whether the command exited successfully.
101
+ #
102
+ def self.exec(*arguments)
103
+ system(arguments.join(' '))
104
+ end
105
+
106
+ #
107
+ # Equivalent of the `cd` command, using `Dir.chdir`.
108
+ #
109
+ # @param [Array<String>] arguments
110
+ # The arguments of the command.
111
+ #
112
+ # @return [Boolean]
113
+ # Specifies whether the directory change was successful.
114
+ #
115
+ def self.cd(*arguments)
116
+ old_pwd = Dir.pwd
117
+
118
+ new_cwd = if arguments.empty?
119
+ unless ENV['HOME']
120
+ warn "cd: HOME not set"
121
+ return false
122
+ end
123
+
124
+ ENV['HOME']
125
+ elsif arguments.first == '-'
126
+ unless ENV['OLDPWD']
127
+ warn 'cd: OLDPWD not set'
128
+ return false
129
+ end
130
+
131
+ ENV['OLDPWD']
132
+ else
133
+ arguments.first
134
+ end
135
+
136
+ Dir.chdir(new_cwd)
137
+ ENV['OLDPWD'] = old_pwd
138
+ return true
139
+ end
140
+
141
+ #
142
+ # Equivalent of the `export` or `set` commands.
143
+ #
144
+ # @param [Array<String>] arguments
145
+ # The arguments of the command.
146
+ #
147
+ # @return [true]
148
+ #
149
+ def self.export(*arguments)
150
+ arguments.each do |pair|
151
+ name, value = pair.split('=',2)
152
+
153
+ ENV[name] = value
154
+ end
155
+ end
156
+ end
157
+ end
158
+
159
+ Ripl::Shell.send :include, Ripl::ShellCommands
@@ -0,0 +1,60 @@
1
+ # encoding: utf-8
2
+
3
+ require 'yaml'
4
+
5
+ Gem::Specification.new do |gem|
6
+ gemspec = YAML.load_file('gemspec.yml')
7
+
8
+ gem.name = gemspec.fetch('name')
9
+ gem.version = gemspec.fetch('version') do
10
+ lib_dir = File.join(File.dirname(__FILE__),'lib')
11
+ $LOAD_PATH << lib_dir unless $LOAD_PATH.include?(lib_dir)
12
+
13
+ require 'ripl/shell_commands/version'
14
+ Ripl::ShellCommands::VERSION
15
+ end
16
+
17
+ gem.summary = gemspec['summary']
18
+ gem.description = gemspec['description']
19
+ gem.licenses = Array(gemspec['license'])
20
+ gem.authors = Array(gemspec['authors'])
21
+ gem.email = gemspec['email']
22
+ gem.homepage = gemspec['homepage']
23
+
24
+ glob = lambda { |patterns| gem.files & Dir[*patterns] }
25
+
26
+ gem.files = `git ls-files`.split($/)
27
+ gem.files = glob[gemspec['files']] if gemspec['files']
28
+
29
+ gem.executables = gemspec.fetch('executables') do
30
+ glob['bin/*'].map { |path| File.basename(path) }
31
+ end
32
+ gem.default_executable = gem.executables.first if Gem::VERSION < '1.7.'
33
+
34
+ gem.extensions = glob[gemspec['extensions'] || 'ext/**/extconf.rb']
35
+ gem.test_files = glob[gemspec['test_files'] || '{test/{**/}*_test.rb']
36
+ gem.extra_rdoc_files = glob[gemspec['extra_doc_files'] || '*.{txt,md}']
37
+
38
+ gem.require_paths = Array(gemspec.fetch('require_paths') {
39
+ %w[ext lib].select { |dir| File.directory?(dir) }
40
+ })
41
+
42
+ gem.requirements = gemspec['requirements']
43
+ gem.required_ruby_version = gemspec['required_ruby_version']
44
+ gem.required_rubygems_version = gemspec['required_rubygems_version']
45
+ gem.post_install_message = gemspec['post_install_message']
46
+
47
+ split = lambda { |string| string.split(/,\s*/) }
48
+
49
+ if gemspec['dependencies']
50
+ gemspec['dependencies'].each do |name,versions|
51
+ gem.add_dependency(name,split[versions])
52
+ end
53
+ end
54
+
55
+ if gemspec['development_dependencies']
56
+ gemspec['development_dependencies'].each do |name,versions|
57
+ gem.add_development_dependency(name,split[versions])
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,189 @@
1
+ require 'spec_helper'
2
+ require 'ripl/shell_commands'
3
+
4
+ describe Ripl::ShellCommands do
5
+ describe "PATHS" do
6
+ subject { described_class::PATHS }
7
+
8
+ it "should parse ENV['PATH']" do
9
+ subject.join(File::PATH_SEPARATOR).should == ENV['PATH']
10
+ end
11
+ end
12
+
13
+ describe "EXECUTABLES" do
14
+ subject { described_class::EXECUTABLES }
15
+
16
+ it "should determine if an executable exists in PATHS" do
17
+ subject['dir'].should be_true
18
+ end
19
+
20
+ it "should ignore non-executable files" do
21
+ subject['brltty-config'].should be_false
22
+ end
23
+
24
+ it "should ignore aliases" do
25
+ subject['cd'].should be_false
26
+ end
27
+ end
28
+
29
+ describe "PATTERN" do
30
+ subject { described_class::PATTERN }
31
+
32
+ it "should match !commands" do
33
+ subject.should =~ "!ls"
34
+ end
35
+
36
+ it "should not match leading whitespace" do
37
+ subject.should_not =~ " !ls"
38
+ end
39
+
40
+ it "should not match commands beginning with decimals" do
41
+ subject.should_not =~ "!10"
42
+ end
43
+
44
+ it "should not match commands beginning with punctuation" do
45
+ subject.should_not =~ "!["
46
+ end
47
+ end
48
+
49
+ describe "parse" do
50
+ it "should commands into the command name and additional arguments" do
51
+ subject.parse("echo foo").should == ['echo', ['foo']]
52
+ end
53
+
54
+ it "should respect single quoted Strings" do
55
+ subject.parse("echo 'foo bar'").should == ['echo', ['foo bar']]
56
+ end
57
+
58
+ it "should respect double quoted Strings" do
59
+ subject.parse("echo \"foo bar\"").should == ['echo', ['foo bar']]
60
+ end
61
+
62
+ it "should respect escaped characters" do
63
+ subject.parse("echo foo\\ bar").should == ['echo', ['foo bar']]
64
+ end
65
+
66
+ context "when \#{ } is present" do
67
+ let(:variable) { 'x' }
68
+ let(:value) { '42' }
69
+ before(:all) do
70
+ eval("#{variable} = #{value}",Ripl.shell.binding)
71
+ end
72
+
73
+ it "should evaluate each embedded expression in the Ripl shell" do
74
+ subject.parse("echo \#{x}").should == ['echo', [value]]
75
+ end
76
+ end
77
+ end
78
+
79
+ describe "executable?" do
80
+ let(:path) { `which dir`.chomp }
81
+
82
+ it "should not be true for regular files" do
83
+ subject.executable?('README.md').should be_false
84
+ end
85
+
86
+ it "should not be true for directories" do
87
+ subject.executable?('.').should be_false
88
+ end
89
+
90
+ it "should be true for executables" do
91
+ subject.executable?(path).should be_true
92
+ end
93
+ end
94
+
95
+ describe "exec" do
96
+ it "should execute commands" do
97
+ subject.exec('true').should be_true
98
+ end
99
+
100
+ it "should allow redirecting output" do
101
+ subject.exec('echo foo >/dev/null').should be_true
102
+ end
103
+
104
+ it "should return the exit status" do
105
+ subject.exec('false').should be_false
106
+ end
107
+ end
108
+
109
+ describe "cd" do
110
+ let(:old) { Dir.pwd }
111
+ let(:dir) { ENV['HOME'] }
112
+
113
+ before(:all) { subject.cd(dir) }
114
+ after(:all) { Dir.chdir(old) }
115
+
116
+ it "should change the current working directory" do
117
+ Dir.pwd.should == dir
118
+ end
119
+
120
+ it "should update ENV['OLDPWD']" do
121
+ ENV['OLDPWD'].should_not == old
122
+ end
123
+
124
+ context "when given no arguments" do
125
+ before(:all) { subject.cd }
126
+
127
+ it "should switch back to the current working directory" do
128
+ Dir.pwd.should == ENV['HOME']
129
+ end
130
+ end
131
+
132
+ context "when given -" do
133
+ before(:all) { subject.cd('-') }
134
+
135
+ it "should switch back to the current working directory" do
136
+ Dir.pwd.should == old
137
+ end
138
+ end
139
+ end
140
+
141
+ describe "export" do
142
+ context "when given NAME=VALUE pairs" do
143
+ let(:name) { 'FOO' }
144
+ let(:value) { '1' }
145
+
146
+ before(:all) { subject.export("#{name}=#{value}") }
147
+
148
+ it "should set ENV[NAME] to VALUE" do
149
+ ENV[name].should == value
150
+ end
151
+ end
152
+
153
+ context "when given NAME= pairs" do
154
+ let(:name) { 'BAR' }
155
+
156
+ before(:all) { subject.export("#{name}=") }
157
+
158
+ it "should set ENV[NAME] to ''" do
159
+ ENV[name].should == ''
160
+ end
161
+ end
162
+ end
163
+
164
+ describe "#loop_eval" do
165
+ subject { Ripl.shell }
166
+
167
+ it "should eval normal Ruby input" do
168
+ subject.eval_input('1 + 1').should == 2
169
+ end
170
+
171
+ it "should execut !commands" do
172
+ subject.eval_input('!dir >/dev/null').should be_true
173
+ end
174
+
175
+ it "should not execute blacklisted !commands" do
176
+ subject.eval_input('!true').should be_false
177
+ end
178
+
179
+ it "should not execut !commands within multi-line input" do
180
+ lines = [
181
+ '1 + 1',
182
+ '!true',
183
+ '2 + 2'
184
+ ]
185
+
186
+ subject.eval_input(lines.join($/)).should == 4
187
+ end
188
+ end
189
+ end
@@ -0,0 +1,2 @@
1
+ gem 'rspec', '~> 2.4'
2
+ require 'rspec'
metadata ADDED
@@ -0,0 +1,126 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ripl-shell_commands
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Postmodern
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-12-02 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: ripl
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: '0.3'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: '0.3'
30
+ - !ruby/object:Gem::Dependency
31
+ name: rspec
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ~>
36
+ - !ruby/object:Gem::Version
37
+ version: '2.4'
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ version: '2.4'
46
+ - !ruby/object:Gem::Dependency
47
+ name: rubygems-tasks
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ~>
52
+ - !ruby/object:Gem::Version
53
+ version: '0.2'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: '0.2'
62
+ - !ruby/object:Gem::Dependency
63
+ name: yard
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ~>
68
+ - !ruby/object:Gem::Version
69
+ version: '0.8'
70
+ type: :development
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ~>
76
+ - !ruby/object:Gem::Version
77
+ version: '0.8'
78
+ description: A ripl plugin that allows inline shell commands in the Ripl Shell.
79
+ email: postmodern.mod3@gmail.com
80
+ executables: []
81
+ extensions: []
82
+ extra_rdoc_files:
83
+ - ChangeLog.md
84
+ - LICENSE.txt
85
+ - README.md
86
+ files:
87
+ - .document
88
+ - .gitignore
89
+ - .rspec
90
+ - .yardopts
91
+ - ChangeLog.md
92
+ - LICENSE.txt
93
+ - README.md
94
+ - Rakefile
95
+ - gemspec.yml
96
+ - lib/ripl/completions/shell_commands.rb
97
+ - lib/ripl/shell_commands.rb
98
+ - ripl-shell_commands.gemspec
99
+ - spec/shell_commands_spec.rb
100
+ - spec/spec_helper.rb
101
+ homepage: https://github.com/postmodern/ripl-shell_commands#readme
102
+ licenses:
103
+ - MIT
104
+ post_install_message:
105
+ rdoc_options: []
106
+ require_paths:
107
+ - lib
108
+ required_ruby_version: !ruby/object:Gem::Requirement
109
+ none: false
110
+ requirements:
111
+ - - ! '>='
112
+ - !ruby/object:Gem::Version
113
+ version: '0'
114
+ required_rubygems_version: !ruby/object:Gem::Requirement
115
+ none: false
116
+ requirements:
117
+ - - ! '>='
118
+ - !ruby/object:Gem::Version
119
+ version: '0'
120
+ requirements: []
121
+ rubyforge_project:
122
+ rubygems_version: 1.8.24
123
+ signing_key:
124
+ specification_version: 3
125
+ summary: Ripl plugin that allows inline shell commands
126
+ test_files: []