ripl 0.2.0 → 0.2.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/.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