rink 1.0.0 → 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,5 +1,7 @@
1
1
  = rink
2
2
 
3
+ gem install rink
4
+
3
5
  Makes interactive consoles awesome. More specifically, it does this by automating as much as conceivably possible so
4
6
  that you can get right down to what you really care about: your application.
5
7
 
@@ -23,8 +25,56 @@ application-specific interactive console, extend the Rink::Console class:
23
25
  #...
24
26
  MyConsole.new
25
27
 
26
- By default, Rink will execute code within the context of its #namespace (see the Rink::Console class documentation for
27
- details). You can, however, add specific commands to Rink like so:
28
+ === The Ruby Console
29
+
30
+ With the default set of options, any input that is not processed as a custom command will be executed as Ruby code,
31
+ much like the Ruby IRB. Guess there's not much more to say about that, so here's an example to drive the point home:
32
+
33
+ >> Interactive Console <<
34
+
35
+ Rink::Console > class Person
36
+ Rink::Console > attr_reader :first_name
37
+ Rink::Console > def initialize
38
+ Rink::Console > @first_name = "Colin"
39
+ Rink::Console > end
40
+ Rink::Console > end
41
+ => nil
42
+ Rink::Console > Person.new.first_name
43
+ => "Colin"
44
+ Rink::Console >
45
+
46
+
47
+ === The Rink Namespace
48
+
49
+ By default, Rink will execute code within the context of its namespace (see the Rink::Console class documentation for
50
+ details). Basically, you can choose any Ruby object and run the console within the context of that object. For example:
51
+
52
+ class Person
53
+ attr_reader :first_name
54
+
55
+ def initialize
56
+ @first_name = "Colin"
57
+ end
58
+ end
59
+
60
+ class MyConsole < Rink::Console
61
+ option :namespace => Person.new
62
+ end
63
+
64
+ MyConsole.new
65
+
66
+ >> Interactive Console <<
67
+
68
+ MyConsole > self
69
+ => #<Person:0x10171c3a0 @first_name="Colin">
70
+
71
+ MyConsole > first_name
72
+ => "Colin"
73
+
74
+
75
+ === Custom Commands
76
+
77
+ Rink isn't limited only to running Ruby code, however. You can also add specific commands to Rink like so:
28
78
 
29
79
  class MyConsole < Rink::Console
30
80
  command :help do |args|
@@ -71,10 +121,13 @@ In addition to commands, you can also easily add or override default options in
71
121
  MyConsole > greet_me
72
122
  Hello there!
73
123
 
124
+ See the class documentation for Rink::Console for much more detailed information, including how to disable Ruby code
125
+ processing entirely.
126
+
74
127
  == Running From The Command Line
75
128
 
76
- You've seen numerous examples of how to start Rink from within Ruby. The same thing works from within IRB or a Rake
77
- task. Additionally, Rink ships with a script so that you can run it directly from the command line:
129
+ You've seen numerous examples of how to start Rink from within Ruby. The same thing works from within IRB or inside of
130
+ a Rake task. Additionally, Rink ships with a script so that you can run it directly from the command line:
78
131
 
79
132
  $ rink
80
133
 
@@ -113,9 +166,11 @@ You can also pass IO objects in directly:
113
166
  end
114
167
  end
115
168
 
169
+ == Dealing With Errors
170
+
116
171
  Normally, if an error occurs, Rink will print a nicely-formatted message to its output stream. This is helpful if you're
117
172
  using the console but not if you're trying to write tests for one. So, you can disable error catching within Rink by
118
- passing :rescue_errors => false to the initializer:
173
+ passing +:rescue_errors => false+ to the initializer:
119
174
 
120
175
  MyConsole.new(:input => "raise", :rescue_errors => false)
121
176
  #=> RuntimeError!
data/Rakefile CHANGED
@@ -8,7 +8,7 @@ begin
8
8
  gem.summary = %Q{Makes interactive consoles awesome.}
9
9
  gem.description = %Q{Makes interactive consoles awesome.}
10
10
  gem.email = "sinisterchipmunk@gmail.com"
11
- gem.homepage = "http://github.com/sinisterchipmunk/rink"
11
+ gem.homepage = "http://www.thoughtsincomputation.com"
12
12
  gem.authors = ["Colin MacKenzie IV"]
13
13
 
14
14
  gem.add_development_dependency "rspec", ">= 1.3.0"
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.0.0
1
+ 1.0.1
@@ -1,6 +1,8 @@
1
1
  #require 'sc-ansi'
2
2
 
3
+ require File.expand_path(File.join(File.dirname(__FILE__), "core_ext/object"))
3
4
  require File.expand_path(File.join(File.dirname(__FILE__), "rink/delegation"))
5
+ require File.expand_path(File.join(File.dirname(__FILE__), 'rink/namespace'))
4
6
  require File.expand_path(File.join(File.dirname(__FILE__), "rink/lexer"))
5
7
  require File.expand_path(File.join(File.dirname(__FILE__), 'rink/io_methods'))
6
8
  require File.expand_path(File.join(File.dirname(__FILE__), "rink/line_processor/base"))
@@ -2,7 +2,7 @@ module Rink
2
2
  class Console
3
3
  extend Rink::Delegation
4
4
  attr_reader :line_processor
5
- attr_writer :namespace, :silenced
5
+ attr_writer :silenced
6
6
  attr_reader :input, :output
7
7
  delegate :silenced?, :print, :write, :puts, :to => :output, :allow_nil => true
8
8
  delegate :banner, :commands, :to => 'self.class'
@@ -11,10 +11,15 @@ module Rink
11
11
  # call super with :defer => true -- because otherwise Rink will start the console before your init code executes.
12
12
  def initialize(options = {})
13
13
  options = default_options.merge(options)
14
+ @namespace = Rink::Namespace.new
14
15
  apply_options(options)
15
16
  run(options) unless options[:defer]
16
17
  end
17
18
 
19
+ def namespace=(ns)
20
+ @namespace.replace(ns)
21
+ end
22
+
18
23
  # The Ruby object within whose context the console will be run.
19
24
  # For example:
20
25
  # class CustomNamespace
@@ -37,16 +42,7 @@ module Rink
37
42
  # Rink::Console.new(:namespace => :self)
38
43
  #
39
44
  def namespace
40
- @namespace ||= begin
41
- # We want namespace to be any object, and in order to do that, Rink will call namespace#binding.
42
- # But by default, the namespace should be TOPLEVEL_BINDING. If we set @namespace to this,
43
- # Rink will call TOPLEVEL_BINDING#binding, which is an error. So instead we'll create a singleton
44
- # object and override #binding on that object to return TOPLEVEL_BINDING. Effectively, that
45
- # singleton object becomes (more-or-less) a proxy into the toplevel object. (Is there a better way?)
46
- klass = Class.new(Object)
47
- klass.send(:define_method, :binding) { TOPLEVEL_BINDING }
48
- klass.new
49
- end
45
+ @namespace.ns
50
46
  end
51
47
 
52
48
  # Runs a series of commands in the context of this Console. Input can be either a string
@@ -103,10 +99,7 @@ module Rink
103
99
 
104
100
  if options[:namespace]
105
101
  ns = options[:namespace] == :self ? self : options[:namespace]
106
- if ns != @namespace
107
- @namespace = ns
108
- @namespace_binding = nil
109
- end
102
+ @namespace.replace(ns)
110
103
  end
111
104
 
112
105
  if @input
@@ -255,10 +248,10 @@ module Rink
255
248
  include Rink::IOMethods
256
249
 
257
250
  def evaluate_scanner_statement
258
- _caller = eval("caller", namespace_binding)
251
+ _caller = @namespace.evaluate("caller")
259
252
  scanner.each_top_level_statement do |code, line_no|
260
253
  begin
261
- return eval(code, namespace_binding, self.class.name, line_no)
254
+ return @namespace.evaluate(code, self.class.name, line_no)
262
255
  rescue
263
256
  # clean out the backtrace so that it starts with the console line instead of program invocation.
264
257
  _caller.reverse.each { |line| $!.backtrace.pop if $!.backtrace.last == line }
@@ -267,10 +260,6 @@ module Rink
267
260
  end
268
261
  end
269
262
 
270
- def namespace_binding
271
- @namespace_binding ||= namespace.send(:binding)
272
- end
273
-
274
263
  def prepare_scanner_for(code)
275
264
  # the scanner prompt should be empty at first because we've already received the first line. Nothing to prompt for.
276
265
  scanner.set_prompt nil
@@ -319,7 +308,7 @@ module Rink
319
308
  # Runs the autocomplete method from the line processor, then reformats its result to be an array.
320
309
  def autocomplete(line)
321
310
  return [] unless @line_processor
322
- result = @line_processor.autocomplete(line, namespace)
311
+ result = @line_processor.autocomplete(line, namespace.ns)
323
312
  case result
324
313
  when String
325
314
  [result]
@@ -13,6 +13,10 @@ module Rink
13
13
  attr_accessor :prompt
14
14
  attr_accessor :output
15
15
 
16
+ def encoding
17
+ input.external_encoding
18
+ end
19
+
16
20
  def input
17
21
  raise NotImplementedError, "input"
18
22
  end
@@ -7,6 +7,10 @@ module Rink
7
7
  @line_num = 0
8
8
  @lines = []
9
9
  end
10
+
11
+ def input
12
+ @io
13
+ end
10
14
 
11
15
  def eof?
12
16
  @io.eof?
@@ -16,6 +16,10 @@ begin
16
16
  @eof = false
17
17
  end
18
18
 
19
+ def input
20
+ $stdin
21
+ end
22
+
19
23
  def gets
20
24
  # in case they were changed. Do we need this here?
21
25
  ::Readline.completion_append_character = completion_append_character
@@ -119,7 +119,7 @@ module Rink
119
119
 
120
120
  def autocomplete(line, namespace)
121
121
  # Borrowed from irb/completion.rb
122
- case line
122
+ result = case line
123
123
  when /^(\/[^\/]*\/)\.([^.]*)$/
124
124
  autocomplete_for_regexp($1, Regexp.quote($2))
125
125
 
@@ -161,6 +161,9 @@ module Rink
161
161
  candidates = eval("methods | private_methods | local_variables | self.class.constants", namespace.send(:binding))
162
162
  (candidates|RESERVED_WORDS).grep(/^#{Regexp.quote(line)}/)
163
163
  end
164
+ result.kind_of?(Array) ?
165
+ result.collect { |r| r.kind_of?(String) ? r : r.to_s } :
166
+ result.kind_of?(String) ? result : result.to_s
164
167
  end
165
168
 
166
169
  private
@@ -0,0 +1,37 @@
1
+ module Rink
2
+ class Namespace
3
+ def initialize(ns = self.default_ns)
4
+ replace(ns)
5
+ end
6
+
7
+ def binding
8
+ @ns_binding
9
+ end
10
+
11
+ def ns
12
+ @namespace
13
+ end
14
+
15
+ def replace(ns)
16
+ return ns if ns.eql?(@namespace)
17
+ @ns_binding = ns.instance_eval { binding }
18
+ #ns.send(:binding) # this no worky in 1.9
19
+ @namespace = ns
20
+ end
21
+
22
+ def evaluate(code, *filename_lineno)
23
+ eval code, @ns_binding, *filename_lineno
24
+ end
25
+
26
+ def default_ns
27
+ # We want namespace to be any object, and in order to do that, Rink will call namespace#binding.
28
+ # But by default, the namespace should be TOPLEVEL_BINDING. If we set @namespace to this,
29
+ # Rink will call TOPLEVEL_BINDING#binding, which is an error. So instead we'll create a singleton
30
+ # object and override #binding on that object to return TOPLEVEL_BINDING. Effectively, that
31
+ # singleton object becomes (more-or-less) a proxy into the toplevel object. (Is there a better way?)
32
+ klass = Class.new(Object)
33
+ klass.send(:define_method, :binding) { TOPLEVEL_BINDING }
34
+ klass.new
35
+ end
36
+ end
37
+ end
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{rink}
8
- s.version = "1.0.0"
8
+ s.version = "1.0.1"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Colin MacKenzie IV"]
12
- s.date = %q{2010-08-06}
12
+ s.date = %q{2010-08-07}
13
13
  s.default_executable = %q{rink}
14
14
  s.description = %q{Makes interactive consoles awesome.}
15
15
  s.email = %q{sinisterchipmunk@gmail.com}
@@ -38,18 +38,20 @@ Gem::Specification.new do |s|
38
38
  "lib/rink/lexer.rb",
39
39
  "lib/rink/line_processor/base.rb",
40
40
  "lib/rink/line_processor/pure_ruby.rb",
41
+ "lib/rink/namespace.rb",
41
42
  "lib/rink/output_method/base.rb",
42
43
  "lib/rink/output_method/io.rb",
43
44
  "rink.gemspec",
44
45
  "spec/lib/core_ext/object_spec.rb",
45
46
  "spec/lib/rink/console_spec.rb",
46
47
  "spec/lib/rink/io_methods_spec.rb",
48
+ "spec/lib/rink/namespace_spec.rb",
47
49
  "spec/lib/rink/pure_ruby_line_processor_spec.rb",
48
50
  "spec/lib/rink_spec.rb",
49
51
  "spec/spec.opts",
50
52
  "spec/spec_helper.rb"
51
53
  ]
52
- s.homepage = %q{http://github.com/sinisterchipmunk/rink}
54
+ s.homepage = %q{http://www.thoughtsincomputation.com}
53
55
  s.rdoc_options = ["--charset=UTF-8"]
54
56
  s.require_paths = ["lib"]
55
57
  s.rubygems_version = %q{1.3.6}
@@ -61,6 +63,7 @@ Gem::Specification.new do |s|
61
63
  "spec/lib/rink",
62
64
  "spec/lib/rink/console_spec.rb",
63
65
  "spec/lib/rink/io_methods_spec.rb",
66
+ "spec/lib/rink/namespace_spec.rb",
64
67
  "spec/lib/rink/pure_ruby_line_processor_spec.rb",
65
68
  "spec/lib/rink_spec.rb",
66
69
  "spec/spec.opts",
@@ -1,7 +1,7 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Rink::Console do
4
- class ExampleObject
4
+ class ::ExampleObject
5
5
  def inspect
6
6
  "#<example>"
7
7
  end
@@ -13,7 +13,7 @@ describe Rink::Console do
13
13
  else options = {}
14
14
  end
15
15
  input = input.flatten.join("\n")
16
- subject.run(input, options.merge(:output => @output, :silent => false))
16
+ subject.run(input, {:output => @output, :silent => false, :rescue_errors => false}.merge(options))
17
17
  end
18
18
 
19
19
  before(:each) { @input = ""; @output = "" }
@@ -93,16 +93,16 @@ describe Rink::Console do
93
93
  end
94
94
 
95
95
  it "should print return value, inspected" do
96
- console("ExampleObject.new")
96
+ console("ExampleObject.new", :rescue_errors => false)
97
97
  @output.should =~ / => #<example>$/
98
98
  end
99
99
 
100
100
  it "should not raise exceptions" do
101
- proc { console("test") }.should_not raise_error
101
+ proc { console("test", :rescue_errors => true) }.should_not raise_error
102
102
  end
103
103
 
104
104
  it "should print exceptions" do
105
- console("test")
105
+ console("test", :rescue_errors => true)
106
106
  @output.should =~ /ArgumentError: /
107
107
  end
108
108
 
@@ -115,6 +115,8 @@ describe Rink::Console do
115
115
  it "should allow setting namespace" do
116
116
  obj = ExampleObject.new
117
117
  subject.namespace = obj
118
+ subject.namespace.should == obj
119
+
118
120
  console("self").should == obj
119
121
  end
120
122
 
@@ -0,0 +1,34 @@
1
+ require 'spec_helper'
2
+
3
+ describe Rink::Namespace do
4
+ class ExampleObject
5
+ def initialize
6
+ @i = 5
7
+ end
8
+ end
9
+
10
+ subject { Rink::Namespace.new }
11
+
12
+ it "should use the top ns by default" do
13
+ subject.binding.should == TOPLEVEL_BINDING
14
+ end
15
+
16
+ context "with a different ns" do
17
+ subject { Rink::Namespace.new(ExampleObject.new) }
18
+
19
+ it "should not use the toplevel binding" do
20
+ subject.binding.should_not == TOPLEVEL_BINDING
21
+ end
22
+
23
+ it "should evaluate code" do
24
+ subject.evaluate("@i").should == 5
25
+ end
26
+ end
27
+
28
+ it "should be replaceable" do
29
+ subject.evaluate("@i").should_not == 5
30
+
31
+ subject.replace(ExampleObject.new)
32
+ subject.evaluate("@i").should == 5
33
+ end
34
+ end
@@ -1,6 +1,8 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Rink::LineProcessor::PureRuby do
4
+ subject { Rink::LineProcessor::PureRuby.new }
5
+
4
6
  it "should autocomplete" do
5
7
  subject.autocomplete('insp', Object.new).should == ["inspect"]
6
8
  end
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 1
7
7
  - 0
8
- - 0
9
- version: 1.0.0
8
+ - 1
9
+ version: 1.0.1
10
10
  platform: ruby
11
11
  authors:
12
12
  - Colin MacKenzie IV
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2010-08-06 00:00:00 -04:00
17
+ date: 2010-08-07 00:00:00 -04:00
18
18
  default_executable: rink
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
@@ -60,18 +60,20 @@ files:
60
60
  - lib/rink/lexer.rb
61
61
  - lib/rink/line_processor/base.rb
62
62
  - lib/rink/line_processor/pure_ruby.rb
63
+ - lib/rink/namespace.rb
63
64
  - lib/rink/output_method/base.rb
64
65
  - lib/rink/output_method/io.rb
65
66
  - rink.gemspec
66
67
  - spec/lib/core_ext/object_spec.rb
67
68
  - spec/lib/rink/console_spec.rb
68
69
  - spec/lib/rink/io_methods_spec.rb
70
+ - spec/lib/rink/namespace_spec.rb
69
71
  - spec/lib/rink/pure_ruby_line_processor_spec.rb
70
72
  - spec/lib/rink_spec.rb
71
73
  - spec/spec.opts
72
74
  - spec/spec_helper.rb
73
75
  has_rdoc: true
74
- homepage: http://github.com/sinisterchipmunk/rink
76
+ homepage: http://www.thoughtsincomputation.com
75
77
  licenses: []
76
78
 
77
79
  post_install_message:
@@ -104,6 +106,7 @@ test_files:
104
106
  - spec/lib/core_ext/object_spec.rb
105
107
  - spec/lib/rink/console_spec.rb
106
108
  - spec/lib/rink/io_methods_spec.rb
109
+ - spec/lib/rink/namespace_spec.rb
107
110
  - spec/lib/rink/pure_ruby_line_processor_spec.rb
108
111
  - spec/lib/rink_spec.rb
109
112
  - spec/spec.opts