rs 35

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.
@@ -0,0 +1,114 @@
1
+ $LOAD_PATH.unshift File.dirname(__FILE__)
2
+
3
+ # Testing
4
+ require "spec_helper"
5
+
6
+ # Project
7
+ require "rs/eval"
8
+
9
+
10
+ # TODO: Dunno how much point there is to add stuff to spec
11
+ # here, but I suppose some coverage is useful. --rue
12
+
13
+ describe "Executing Ruby code with the evaluator" do
14
+ before :each do
15
+ @rs = RS::Evaluator.new
16
+ @topmeth = "rs_eval_toplevel_def_#{$$}"
17
+ end
18
+
19
+ after :each do
20
+ @rs.execute "Object.send :remove_method, :#{@topmeth} if Object.instance_methods.include?(:#{@topmeth})"
21
+ @rs.execute "Object.send :remove_const, :RSEvalSpecsClass if defined? RSEvalSpecsClass"
22
+ @rs.execute "Object.send :remove_const, :RSEvalSpecsModule if defined? RSEvalSpecsModule"
23
+ @rs.execute "Object.send :remove_const, :RSEvalSpecsExtModule if defined? RSEvalSpecsExtModule"
24
+ end
25
+
26
+ it "has a top-level self object" do
27
+ @rs.execute("self").should be_kind_of(Object)
28
+ end
29
+
30
+ it "provides #rs which gives access to an OpenStruct" do
31
+ @rs.execute("rs").should be_kind_of(OpenStruct)
32
+ end
33
+
34
+ it "allows access to a #config OpenStruct through #rs" do
35
+ @rs.execute("rs.config").should be_kind_of(OpenStruct)
36
+ end
37
+
38
+ it "allows top-level method definitions" do
39
+ @rs.execute("def #{@topmeth}; :gots; end").should == nil
40
+ @rs.execute(@topmeth).should == :gots
41
+ end
42
+
43
+ it "allows top-level class and module definitions" do
44
+ @rs.execute "class RSEvalSpecsClass; end"
45
+ @rs.execute "module RSEvalSpecsModule; end"
46
+
47
+ @rs.execute("RSEvalSpecsClass").should be_kind_of(Class)
48
+ @rs.execute("RSEvalSpecsModule").should be_kind_of(Module)
49
+ end
50
+
51
+ it "has no wrapping nesting in top-level modules" do
52
+ @rs.execute("Module.nesting").should == []
53
+ @rs.execute("module RSEvalSpecsModule; Module.nesting; end").should == [RSEvalSpecsModule]
54
+ end
55
+
56
+ it "supports extending and including into self" do
57
+ @rs.execute "module RSEvalSpecsModule; def rsesm; end; end"
58
+ @rs.execute "module RSEvalSpecsExtModule; def rsesem; end; end"
59
+
60
+ @rs.execute "include RSEvalSpecsModule"
61
+ @rs.execute("Object.ancestors").include?(RSEvalSpecsModule).should == true
62
+
63
+ @rs.execute "extend RSEvalSpecsExtModule"
64
+ @rs.execute("class << self; ancestors; end").include?(RSEvalSpecsExtModule).should == true
65
+ end
66
+
67
+ it "gracefully returns error object if an error bubbles to top level" do
68
+ @rs.execute("raise SyntaxError").should be_kind_of(SyntaxError)
69
+ end
70
+
71
+ it "supports normal error handling" do
72
+ @rs.execute("begin; raise SyntaxError; rescue SyntaxError; :yay; end").should == :yay
73
+ end
74
+
75
+ it "lets SystemExit bubble up" do
76
+ lambda { @rs.execute "exit 1" }.should raise_error(SystemExit)
77
+ end
78
+
79
+ it "returns error object given top-level return" do
80
+ @rs.execute("return").should be_kind_of(Exception)
81
+ end
82
+
83
+ it "returns error object given top-level break" do
84
+ @rs.execute("break").should be_kind_of(Exception)
85
+ end
86
+
87
+ it "returns error object given top-level next" do
88
+ pending "Escapes on 1.8" if RUBY_VERSION =~ /1\.8/
89
+ @rs.execute("next").should be_kind_of(Exception)
90
+ end
91
+
92
+ it "returns error object given top-level redo" do
93
+ pending "Escapes on 1.8" if RUBY_VERSION =~ /1\.8/
94
+ @rs.execute("redo").should be_kind_of(Exception)
95
+ end
96
+
97
+ end
98
+
99
+
100
+ describe "Evaluator creation using RS.start" do
101
+
102
+ it "yields an Evaluator to the block given" do
103
+ RS.start {|rs| rs.should be_kind_of(RS::Evaluator) }
104
+ end
105
+
106
+ it "does not rescue errors raised in the block" do
107
+ lambda { RS.start {|rs| raise "hi" } }.should raise_error("hi")
108
+ end
109
+
110
+ it "gives access to the eval context's main object with #main" do
111
+ RS.start {|rs| rs.main.should be_eql(rs.execute "self") }
112
+ end
113
+
114
+ end
@@ -0,0 +1,67 @@
1
+ $LOAD_PATH.unshift File.join(File.dirname(__FILE__), "..", "lib")
2
+
3
+ require "tempfile"
4
+
5
+
6
+ class OutputMatcher
7
+ def initialize(expected, stream)
8
+ @expected = expected
9
+ @stream = stream
10
+ end
11
+
12
+ # TODO: cleanup unnecessary error stuffs
13
+ def matches?(block)
14
+ old_to = @stream.dup
15
+
16
+ # Obtain a filehandle to replace (works with Readline)
17
+ @stream.reopen File.open(File.join(Dir.tmpdir, "should_output_#{$$}"), "w+")
18
+
19
+ # Execute
20
+ block.call
21
+
22
+ # Restore
23
+ out = @stream.dup
24
+ @stream.reopen old_to
25
+
26
+ # Grab the data
27
+ out.rewind
28
+ @data = out.read
29
+
30
+ # Match up
31
+ case @expected
32
+ when Regexp
33
+ @data.should =~ @expected
34
+ else
35
+ @data.should == @expected
36
+ end
37
+
38
+ # Clean up
39
+ ensure
40
+ out.close if out and !out.closed?
41
+
42
+ # STDIO redirection will break else
43
+ begin
44
+ @stream.seek 0, IO::SEEK_END
45
+ rescue Errno::ESPIPE, Errno::EPIPE
46
+ # Ignore
47
+ end
48
+
49
+ FileUtils.rm out.path if out
50
+ end
51
+
52
+ def failure_message()
53
+ fail
54
+ # "Output to #{@stream.to_i} was:\n#{@data.inspect}\nshould have been:\n#{@expected.inspect}"
55
+ end
56
+
57
+ def negative_failure_message()
58
+ fail
59
+ end
60
+ end
61
+
62
+ # Top-level matching
63
+ #
64
+ def output(expected, into_stream = $stdout)
65
+ OutputMatcher.new expected, into_stream
66
+ end
67
+
@@ -0,0 +1,144 @@
1
+ $LOAD_PATH.unshift File.dirname(__FILE__)
2
+
3
+ # Testing
4
+ require "spec_helper"
5
+
6
+ # Project
7
+ require "rs/ui"
8
+
9
+
10
+ describe "UI creation" do
11
+
12
+ it "yields the UI instance to the given block" do
13
+ RS::UI.new {|ui| ui.should be_kind_of(RS::UI) }
14
+ end
15
+
16
+ it "provides some kind of a default prompt String" do
17
+ Readline.should_receive(:readline).with(an_instance_of(String), true).once.and_return nil
18
+
19
+ RS::UI.new {|ui| ui.run }
20
+ end
21
+
22
+ it "allows prompt to be assigned to" do
23
+ lambda {
24
+ RS::UI.new {|ui| ui.prompt = lambda { "hi>" } }
25
+ }.should_not raise_error
26
+ end
27
+
28
+ it "accepts a ^C handler in #on_SIGINT" do
29
+ lambda {
30
+ RS::UI.new {|ui| ui.on_SIGINT { :hi } }
31
+ }.should_not raise_error
32
+ end
33
+
34
+ it "accepts a linewise input handler in #on_input" do
35
+ lambda {
36
+ RS::UI.new {|ui| ui.on_input {|i| i.reverse } }
37
+ }.should_not raise_error
38
+ end
39
+
40
+ end
41
+
42
+
43
+ describe "UI loop/processing" do
44
+
45
+ it "terminates when ^D, EOF, received." do
46
+ Readline.should_receive(:readline).once.and_return nil
47
+
48
+ RS::UI.new {|ui|
49
+ ui.run
50
+ }
51
+ end
52
+
53
+ it "calls the current prompt and uses its value going out for each loop" do
54
+ str = "rs_ui_spec_prompt #{$$}> "
55
+
56
+ prompt = Object.new
57
+ prompt.should_receive(:call).exactly(2).times.and_return { str }
58
+
59
+ inputs = ["hi\n", "ho\n", nil]
60
+ prompts = [//, str, str]
61
+
62
+ # TODO: Slightly iffy, improve.
63
+ Readline.should_receive(:readline).exactly(3).times {|output_prompt, _|
64
+ prompts.shift.should === output_prompt
65
+ inputs.shift
66
+ }
67
+
68
+ RS::UI.new {|ui|
69
+ ui.on_input {|input|
70
+ ui.prompt = prompt
71
+ }
72
+
73
+ ui.run
74
+ }
75
+ end
76
+
77
+ end
78
+
79
+
80
+ describe "UI event handling" do
81
+
82
+ it "calls block given to #on_SIGINT on ^C" do
83
+ inputs = [lambda { raise Interrupt }, lambda { nil }]
84
+
85
+ Readline.should_receive(:readline).exactly(2).times.and_return { inputs.shift.call }
86
+
87
+ called = false
88
+
89
+ RS::UI.new {|ui|
90
+ ui.on_SIGINT { called = true }
91
+ ui.run
92
+ }
93
+
94
+ called.should == true
95
+ end
96
+
97
+ it "continues processing after invoking #on_SIGINT" do
98
+ continued = false
99
+
100
+ inputs = [lambda { raise Interrupt }, lambda { continued = true; nil } ]
101
+
102
+ Readline.should_receive(:readline).exactly(2).times.and_return { inputs.shift.call }
103
+
104
+ RS::UI.new {|ui|
105
+ ui.on_SIGINT { :yay }
106
+ ui.run
107
+ }
108
+
109
+ continued.should == true
110
+ end
111
+
112
+ it "invokes #on_input block for each line of input until terminated by ^D" do
113
+ inputs = ["hi\n", "ha\n", "hoo bee\n", nil, "blee\n"]
114
+ expected = inputs.map {|i| i.chomp if i }
115
+
116
+ Readline.should_receive(:readline).exactly(4).times.and_return { inputs.shift }
117
+
118
+ RS::UI.new {|ui|
119
+ ui.on_input {|input|
120
+ input.should == expected.shift
121
+ }
122
+
123
+ ui.run
124
+ }
125
+
126
+ expected.should == [nil, "blee"]
127
+ end
128
+
129
+ end
130
+
131
+
132
+ describe "UI output" do
133
+
134
+ it "calls #to_s on its argument and writes it to output with a newline when using #puts" do
135
+ lambda {
136
+ RS::UI.new {|ui|
137
+ ui.puts "Hiya"
138
+ ui.puts "Really"
139
+ }
140
+ }.should output("Hiya\nReally\n")
141
+ end
142
+
143
+ end
144
+
metadata ADDED
@@ -0,0 +1,84 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rs
3
+ version: !ruby/object:Gem::Version
4
+ version: "35"
5
+ platform: ruby
6
+ authors:
7
+ - Eero Saynatkari
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2010-01-15 00:00:00 +02:00
13
+ default_executable: rs
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: rspec
17
+ type: :development
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: 1.3.0
24
+ version:
25
+ description: " rs is the result of my object-oriented shell musings, experiments and implementations. Its focus is above all on simplicity and the best possible implementation of modern shell usage and needs. "
26
+ email: rs@projects.kittensoft.org
27
+ executables:
28
+ - rs
29
+ extensions: []
30
+
31
+ extra_rdoc_files: []
32
+
33
+ files:
34
+ - .gitignore
35
+ - Rakefile
36
+ - bin/rs
37
+ - doc/LICENCE
38
+ - doc/README.markdown
39
+ - lib/rs/eval.rb
40
+ - lib/rs/string.rb
41
+ - lib/rs/ui.rb
42
+ - setup.rb
43
+ - spec/evaluator_spec.rb
44
+ - spec/spec_helper.rb
45
+ - spec/ui_spec.rb
46
+ has_rdoc: true
47
+ homepage: http://github.com/rue/rs
48
+ licenses: []
49
+
50
+ post_install_message: |+
51
+
52
+ =======================================
53
+
54
+ /path/to/cwd rs> _
55
+
56
+ =======================================
57
+
58
+ rdoc_options:
59
+ - --charset=UTF-8
60
+ require_paths:
61
+ - lib
62
+ required_ruby_version: !ruby/object:Gem::Requirement
63
+ requirements:
64
+ - - ">="
65
+ - !ruby/object:Gem::Version
66
+ version: "0"
67
+ version:
68
+ required_rubygems_version: !ruby/object:Gem::Requirement
69
+ requirements:
70
+ - - ">="
71
+ - !ruby/object:Gem::Version
72
+ version: "0"
73
+ version:
74
+ requirements: []
75
+
76
+ rubyforge_project:
77
+ rubygems_version: 1.3.5
78
+ signing_key:
79
+ specification_version: 3
80
+ summary: Object-oriented shell in full Ruby environment.
81
+ test_files:
82
+ - spec/evaluator_spec.rb
83
+ - spec/spec_helper.rb
84
+ - spec/ui_spec.rb