ripl 0.2.0 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gemspec CHANGED
@@ -14,6 +14,9 @@ Gem::Specification.new do |s|
14
14
  s.rubyforge_project = 'tagaholic'
15
15
  s.executables = %w(ripl)
16
16
  s.add_dependency 'bond', '~> 0.3.1'
17
+ s.add_development_dependency 'bacon', '>= 1.1.0'
18
+ s.add_development_dependency 'rr', '= 0.10.10'
19
+ s.add_development_dependency 'bacon-bits'
17
20
  s.files = Dir.glob(%w[{lib,test}/**/*.rb bin/* [A-Z]*.{txt,rdoc} ext/**/*.{rb,c} **/deps.rip]) + %w{Rakefile .gemspec}
18
21
  s.extra_rdoc_files = ["README.rdoc", "LICENSE.txt"]
19
22
  s.license = 'MIT'
@@ -1,3 +1,9 @@
1
+ == 0.2.1
2
+ * Add tests
3
+ * Add more flexible -I and -r
4
+ * Update Shell::API to be more plugin friendly
5
+ * Handle invalid options
6
+
1
7
  == 0.2.0
2
8
  * Full support for plugins
3
9
  * Add history support for all shells
@@ -26,7 +26,7 @@ Install the gem with:
26
26
  * Easy to create and invoke ripl subcommands
27
27
  * ~/.irbrc errors caught
28
28
  * Different from irb
29
- * No multi-line evaluation
29
+ * No multi-line evaluation by default (there is a plugin. See Available Plugins below).
30
30
  * No irb subsessions or workspaces
31
31
  * No IRB.conf features i.e. preconfigured prompts and auto indent
32
32
 
@@ -68,6 +68,8 @@ extension, see Ripl::Shell::API and Ripl::Runner::API.
68
68
  If we want to add a config for this plugin, we can simply add a key to Ripl.config that matches the
69
69
  underscored version of the plugin name i.e. Ripl.config[:red_error].
70
70
 
71
+ For available plugins, see Available Plugins below.
72
+
71
73
  == Create Custom Shells
72
74
 
73
75
  Creating and starting a custom shell is as simple as:
@@ -95,6 +97,13 @@ Since ripl is highly customizable, it loads ~/.riplrc before it does anything. T
95
97
  require and/or define plugins. Any ripl configurations via Ripl.config should also be done here.
96
98
  For an example riplrc, see {mine}[http://github.com/cldwalker/dotfiles/tree/master/.riplrc].
97
99
 
100
+ == Available Plugins
101
+
102
+ * {ripl-rails}[http://github.com/cldwalker/ripl-rails] : script/console for ripl
103
+ * {ripl-color_error}[http://github.com/cldwalker/ripl-color_error] : colorize errors
104
+ * {ripl-after_rc}[http://github.com/cldwalker/ripl-after_rc] : provide blocks to run after ~/.irbrc is loaded
105
+ * {ripl-multi_line}[http://github.com/janlelis/ripl-multi_line] : evaluate multiple lines
106
+
98
107
  == Credits
99
108
  * janlelis for bug fix and tweaks
100
109
 
@@ -104,6 +113,3 @@ Some other irb alternatives to check out:
104
113
  * {ir}[http://github.com/raggi/ir]: nice and light
105
114
  * {irb2}[http://github.com/wycats/irb2]: yehuda katz's partial attempt at rewriting irb
106
115
  * {dietrb}[http://github.com/alloy/dietrb]: mac and ruby 1.9 specific
107
-
108
- == Todo
109
- * Everything (tests especially)!
@@ -2,8 +2,8 @@ require 'bond'
2
2
 
3
3
  module Ripl::Completion
4
4
  def before_loop
5
+ Bond.start(config[:completion] || {})
5
6
  super
6
- Bond.start(config[:completion] || {}) unless Bond.started?
7
7
  end
8
8
  end
9
9
  Ripl::Shell.send :include, Ripl::Completion
@@ -4,20 +4,20 @@ module Ripl::Runner
4
4
  end
5
5
 
6
6
  module API
7
- def run
7
+ def run(argv=ARGV)
8
8
  load_rc(Ripl.config[:riplrc])
9
9
  @riplrc = true
10
- parse_options(ARGV)
11
- ARGV[0] ? run_command(ARGV) : start
10
+ parse_options(argv)
11
+ argv[0] ? run_command(argv) : start
12
12
  end
13
13
 
14
14
  def parse_options(argv)
15
15
  while argv[0] =~ /^-/
16
16
  case argv.shift
17
17
  when /-I=?(.*)/
18
- $LOAD_PATH.unshift(*$1.split(":"))
18
+ $LOAD_PATH.unshift(*($1.empty? ? argv.shift.to_s : $1).split(":"))
19
19
  when /-r=?(.*)/
20
- require $1
20
+ require $1.empty? ? argv.shift.to_s : $1
21
21
  when '-d'
22
22
  $DEBUG = true
23
23
  when '-v', '--version'
@@ -26,6 +26,8 @@ module Ripl::Runner
26
26
  ENV['RIPL_IRBRC'] = 'false'
27
27
  when '-h', '--help'
28
28
  puts IO.readlines(__FILE__).grep(/^#/).map {|e| e.sub(/^#\s/,'') }; exit
29
+ when /^--?([^-]+)/
30
+ warn "ripl: invalid option `#{$1}'"
29
31
  end
30
32
  end
31
33
  end
@@ -61,7 +63,7 @@ __END__
61
63
  # Options:
62
64
  # -f Supress loading ~/.irbrc
63
65
  # -d, --debug Set $DEBUG to true (same as `ruby -d')
64
- # -I=PATH Add to front of $LOAD_PATH. Delimit multiple paths with ':'
65
- # -r, --require=FILE Require file (same as `ruby -r')
66
+ # -I PATH Add to front of $LOAD_PATH. Delimit multiple paths with ':'
67
+ # -r, --require FILE Require file (same as `ruby -r')
66
68
  # -v, --version Print ripl version
67
69
  # -h, --help Print help
@@ -10,7 +10,7 @@ class Ripl::Shell
10
10
  new(options)
11
11
  end
12
12
 
13
- attr_accessor :line, :binding, :result_prompt, :last_result
13
+ attr_accessor :line, :binding, :result_prompt, :result, :options
14
14
  def initialize(options={})
15
15
  @options = OPTIONS.merge options
16
16
  @name, @binding, @line = @options.values_at(:name, :binding, :line)
@@ -19,7 +19,7 @@ class Ripl::Shell
19
19
 
20
20
  def loop
21
21
  before_loop
22
- during_loop
22
+ catch(:ripl_exit) { while(true) do; loop_once; end }
23
23
  after_loop
24
24
  end
25
25
 
@@ -30,14 +30,12 @@ class Ripl::Shell
30
30
  Ripl::Runner.load_rc(@irbrc) if @irbrc
31
31
  end
32
32
 
33
- def during_loop
34
- while true do
35
- @error_raised = nil
36
- input = get_input
37
- break if !input || input == 'exit'
38
- loop_once(input)
39
- puts(format_result(@last_result)) unless @error_raised
40
- end
33
+ def loop_once
34
+ @error_raised = nil
35
+ @input = get_input
36
+ throw(:ripl_exit) if !@input || @input == 'exit'
37
+ eval_input(@input)
38
+ print_result(@result)
41
39
  end
42
40
 
43
41
  def get_input
@@ -49,9 +47,9 @@ class Ripl::Shell
49
47
  @options[:prompt].respond_to?(:call) ? @options[:prompt].call : @options[:prompt]
50
48
  end
51
49
 
52
- def loop_once(input)
53
- @last_result = loop_eval(input)
54
- eval("_ = Ripl.shell.last_result", @binding)
50
+ def eval_input(input)
51
+ @result = loop_eval(input)
52
+ eval("_ = Ripl.shell.result", @binding)
55
53
  rescue Exception => e
56
54
  @error_raised = true
57
55
  print_eval_error(e)
@@ -67,6 +65,10 @@ class Ripl::Shell
67
65
  warn format_error(err)
68
66
  end
69
67
 
68
+ def print_result(result)
69
+ puts(format_result(result)) unless @error_raised
70
+ end
71
+
70
72
  def format_error(err); Ripl::Runner.format_error(err); end
71
73
 
72
74
  def format_result(result)
@@ -1,3 +1,3 @@
1
1
  module Ripl
2
- VERSION = '0.2.0'
2
+ VERSION = '0.2.1'
3
3
  end
@@ -0,0 +1,3 @@
1
+ bacon >=1.1.0
2
+ rr =0.10.10
3
+ bacon-bits >=0
@@ -0,0 +1,163 @@
1
+ require File.join(File.dirname(__FILE__), 'test_helper')
2
+
3
+ describe "Runner" do
4
+ describe ".start" do
5
+ before { reset_ripl }
6
+
7
+ it "loads riplrc" do
8
+ mock_riplrc
9
+ mock(Ripl).shell(anything) { shell = Shell.new; mock(shell).loop; shell }
10
+ Ripl.start
11
+ end
12
+
13
+ it "sets a shell's options" do
14
+ mock_riplrc
15
+ mock(Shell).create(anything) {|e| shell = Shell.new(e); mock(shell).loop; shell }
16
+ Ripl.start(:prompt=>'$')
17
+ Ripl.shell.options[:prompt].should == '$'
18
+ end
19
+
20
+ it "overrides options set in riplrc" do
21
+ mock_riplrc { Ripl.config[:readline] = false }
22
+ mock(Shell).create(anything) {|e| shell = Shell.new(e); mock(shell).loop; shell }
23
+ Ripl.start(:readline=>true)
24
+ Ripl.shell.options[:readline].should == true
25
+ end
26
+ end
27
+
28
+ describe ".run" do
29
+ describe "riplrc" do
30
+ before { reset_ripl }
31
+
32
+ it "sets a shell's options" do
33
+ mock_riplrc { Ripl.config[:blah] = true }
34
+ mock(Shell).create(anything) {|e| shell = Shell.new(e); mock(shell).loop; shell }
35
+ Runner.run([])
36
+ Ripl.shell.options[:blah].should == true
37
+ end
38
+
39
+ it "catches and prints error" do
40
+ mock(Runner).load(anything) { raise SyntaxError }
41
+ mock(Ripl).shell(anything) { shell = Shell.new; mock(shell).loop; shell }
42
+ capture_stderr { Runner.run([]) }.should =~ %r{^Error while loading ~/.riplrc:\nSyntaxError:}
43
+ end
44
+ end
45
+
46
+ describe "with subcommand" do
47
+ it "that is valid gets invoked with arguments" do
48
+ mock(Runner).exec('ripl-rails', '--blah')
49
+ ripl("rails", '--blah')
50
+ end
51
+
52
+ it "has global options before it parsed" do
53
+ mock(Runner).parse_options(anything) {|e| e.shift }
54
+ mock(Runner).exec('ripl-rails')
55
+ ripl("-f", "rails")
56
+ end
57
+
58
+ it "that is invalid aborts" do
59
+ mock(Runner).abort("`zzz' is not a ripl command.")
60
+ ripl 'zzz'
61
+ end
62
+ end
63
+
64
+ describe "with -I option" do
65
+ before { @old_load_path = $:.dup }
66
+ after { $:.replace @old_load_path }
67
+
68
+ it "and equal sign adds to $LOAD_PATH" do
69
+ ripl("-I=blah", :start=>true)
70
+ $:[0].should == 'blah'
71
+ end
72
+
73
+ it "and no equal sign adds to $LOAD_PATH" do
74
+ ripl("-Ispec", :start=>true)
75
+ $:[0].should == 'spec'
76
+ end
77
+
78
+ it "and whitespace delimited argument adds to $LOAD_PATH" do
79
+ ripl("-I", "spec", :start=>true)
80
+ $:[0].should == 'spec'
81
+ end
82
+
83
+ it "containing multiple paths adds to $LOAD_PATH" do
84
+ ripl("-I=app:lib", :start=>true)
85
+ $:[0,2].should == ['app', 'lib']
86
+ end
87
+
88
+ it "called more than once adds to $LOAD_PATH" do
89
+ ripl("-Ilib", "-Ispec", :start=>true)
90
+ $:[0,2].should == ['spec', 'lib']
91
+ end
92
+
93
+ it "with invalid argument doesn't add to $LOAD_PATH" do
94
+ previous_size = $:.size
95
+ ripl("-I", :start=>true)
96
+ $:.size.should == previous_size
97
+ end
98
+ end
99
+
100
+ describe "with -r option" do
101
+ it "and equal sign requires path" do
102
+ mock(Runner).require('rip')
103
+ ripl("-r=rip", :start=>true)
104
+ end
105
+
106
+ it "and no equal sign requires path" do
107
+ mock(Runner).require('rip')
108
+ ripl("-rrip", :start=>true)
109
+ end
110
+
111
+ it "and whitespace delimited argument requires path" do
112
+ mock(Runner).require('rip')
113
+ ripl("-r", "rip", :start=>true)
114
+ end
115
+
116
+ it "called more than once requires paths" do
117
+ mock(Runner).require('rip')
118
+ mock(Runner).require('dude')
119
+ ripl("-rrip", "-rdude", :start=>true)
120
+ end
121
+
122
+ it "with invalid argument requires blank" do
123
+ mock(Runner).require('')
124
+ ripl('-r', :start=>true)
125
+ end
126
+ end
127
+
128
+ it "with -f option doesn't load irbrc" do
129
+ reset_ripl
130
+ mock(Shell).create(anything) {|e|
131
+ shell = Shell.new(e)
132
+ mock(shell).loop_once { throw :ripl_exit }
133
+ dont_allow(Runner).load_rc(anything)
134
+ shell
135
+ }
136
+ ripl("-f")
137
+ end
138
+
139
+ it "with -d option sets $DEBUG" do
140
+ ripl("-d", :start=>true)
141
+ $DEBUG.should == true
142
+ $DEBUG = nil
143
+ end
144
+
145
+ it "with -v option prints version" do
146
+ should.raise(SystemExit) { ripl("-v").should == Ripl::VERSION }
147
+ end
148
+
149
+ it "with -h option prints help" do
150
+ should.raise(SystemExit) {
151
+ actual = ripl("-v")
152
+ actual.should =~ /^Usage: ripl/
153
+ actual.should =~ /Options:\n -f/
154
+ }
155
+ end
156
+
157
+ it "with invalid options prints errors" do
158
+ capture_stderr {
159
+ ripl('--blah', '-z', :start=>true)
160
+ }.chomp.should == "ripl: invalid option `blah'\nripl: invalid option `z'"
161
+ end
162
+ end
163
+ end
@@ -0,0 +1,72 @@
1
+ require File.join(File.dirname(__FILE__), 'test_helper')
2
+
3
+ describe "Shell" do
4
+ before { reset_ripl }
5
+
6
+ def shell(options={})
7
+ Ripl.shell(options)
8
+ end
9
+
10
+ describe "#loop" do
11
+ before { mock(shell).before_loop }
12
+ it "exits with exit" do
13
+ mock(shell).get_input { 'exit' }
14
+ dont_allow(shell).eval_input
15
+ shell.loop
16
+ end
17
+
18
+ it "exits with Control-D" do
19
+ mock(shell).get_input { nil }
20
+ dont_allow(shell).eval_input
21
+ shell.loop
22
+ end
23
+ end
24
+
25
+ describe "#prompt" do
26
+ it "as a string" do
27
+ shell(:prompt=>'> ').prompt.should == '> '
28
+ end
29
+
30
+ it "as a lambda" do
31
+ shell(:prompt=>lambda { "#{10 + 10}> " }).prompt.should == '20> '
32
+ end
33
+ end
34
+
35
+ describe "#eval_input" do
36
+ before { @line = shell.line; shell.eval_input("10 ** 2") }
37
+
38
+ describe "normally" do
39
+ it "sets result" do
40
+ shell.result.should == 100
41
+ end
42
+
43
+ it "sets _" do
44
+ shell.eval_input('_')
45
+ shell.result.should == 100
46
+ end
47
+
48
+ it "increments line" do
49
+ shell.line.should == @line + 1
50
+ end
51
+ end
52
+
53
+ describe "with error" do
54
+ before {
55
+ @line = shell.line
56
+ @stderr = capture_stderr { shell.eval_input('{') }
57
+ }
58
+
59
+ it "prints it" do
60
+ @stderr.should =~ /^SyntaxError: compile error/
61
+ end
62
+
63
+ it "sets @error_raised" do
64
+ shell.instance_variable_get("@error_raised").should == true
65
+ end
66
+
67
+ it "increments line" do
68
+ shell.line.should == @line + 1
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,48 @@
1
+ require 'bacon'
2
+ require 'bacon/bits'
3
+ require 'rr'
4
+ require 'bacon/rr'
5
+ require 'stringio'
6
+ require 'ripl'
7
+ include Ripl
8
+
9
+ module Helpers
10
+ def ripl(*args)
11
+ options = args[-1].is_a?(Hash) ? args.pop : {}
12
+ mock(Runner).load_rc(Ripl.config[:riplrc])
13
+ mock(Runner).start if options[:start]
14
+ capture_stdout { Ripl::Runner.run(args) }
15
+ end
16
+
17
+ def mock_riplrc(&block)
18
+ mock(Runner).load_rc(Ripl.config[:riplrc]) { block.call if block }
19
+ end
20
+
21
+ def reset_ripl
22
+ Ripl.instance_eval "@shell = @riplrc = nil"
23
+ end
24
+
25
+ def capture_stdout(&block)
26
+ original_stdout = $stdout
27
+ $stdout = fake = StringIO.new
28
+ begin
29
+ yield
30
+ ensure
31
+ $stdout = original_stdout
32
+ end
33
+ fake.string
34
+ end
35
+
36
+ def capture_stderr(&block)
37
+ original_stderr = $stderr
38
+ $stderr = fake = StringIO.new
39
+ begin
40
+ yield
41
+ ensure
42
+ $stderr = original_stderr
43
+ end
44
+ fake.string
45
+ end
46
+ end
47
+
48
+ Bacon::Context.send :include, Helpers
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ripl
3
3
  version: !ruby/object:Gem::Version
4
- hash: 23
4
+ hash: 21
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
8
  - 2
9
- - 0
10
- version: 0.2.0
9
+ - 1
10
+ version: 0.2.1
11
11
  platform: ruby
12
12
  authors:
13
13
  - Gabriel Horner
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2010-11-08 00:00:00 -05:00
18
+ date: 2010-11-11 00:00:00 -05:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
@@ -34,6 +34,52 @@ dependencies:
34
34
  version: 0.3.1
35
35
  type: :runtime
36
36
  version_requirements: *id001
37
+ - !ruby/object:Gem::Dependency
38
+ name: bacon
39
+ prerelease: false
40
+ requirement: &id002 !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ">="
44
+ - !ruby/object:Gem::Version
45
+ hash: 19
46
+ segments:
47
+ - 1
48
+ - 1
49
+ - 0
50
+ version: 1.1.0
51
+ type: :development
52
+ version_requirements: *id002
53
+ - !ruby/object:Gem::Dependency
54
+ name: rr
55
+ prerelease: false
56
+ requirement: &id003 !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - "="
60
+ - !ruby/object:Gem::Version
61
+ hash: 35
62
+ segments:
63
+ - 0
64
+ - 10
65
+ - 10
66
+ version: 0.10.10
67
+ type: :development
68
+ version_requirements: *id003
69
+ - !ruby/object:Gem::Dependency
70
+ name: bacon-bits
71
+ prerelease: false
72
+ requirement: &id004 !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ">="
76
+ - !ruby/object:Gem::Version
77
+ hash: 3
78
+ segments:
79
+ - 0
80
+ version: "0"
81
+ type: :development
82
+ version_requirements: *id004
37
83
  description: Ruby Interactive Print Loop - A light, modular alternative to irb
38
84
  email: gabriel.horner@gmail.com
39
85
  executables:
@@ -51,11 +97,15 @@ files:
51
97
  - lib/ripl/shell.rb
52
98
  - lib/ripl/version.rb
53
99
  - lib/ripl.rb
100
+ - test/runner_test.rb
101
+ - test/shell_test.rb
102
+ - test/test_helper.rb
54
103
  - bin/ripl
55
104
  - LICENSE.txt
56
105
  - CHANGELOG.rdoc
57
106
  - README.rdoc
58
107
  - deps.rip
108
+ - test/deps.rip
59
109
  - Rakefile
60
110
  - .gemspec
61
111
  has_rdoc: true