ruby-screen 0.9.0

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.
Files changed (45) hide show
  1. data/History.txt +3 -0
  2. data/License.txt +20 -0
  3. data/Manifest.txt +44 -0
  4. data/README.textile +226 -0
  5. data/README.txt +1 -0
  6. data/Rakefile +4 -0
  7. data/bin/ruby-screen +5 -0
  8. data/config/hoe.rb +71 -0
  9. data/config/requirements.rb +17 -0
  10. data/lib/ruby_screen.rb +14 -0
  11. data/lib/ruby_screen/configuration/description.rb +60 -0
  12. data/lib/ruby_screen/configuration/generator.rb +54 -0
  13. data/lib/ruby_screen/configuration/parser.rb +35 -0
  14. data/lib/ruby_screen/configuration/parser/block_processor.rb +43 -0
  15. data/lib/ruby_screen/configuration/parser/iterator.rb +31 -0
  16. data/lib/ruby_screen/configuration/parser/nesting_hash.rb +37 -0
  17. data/lib/ruby_screen/executer.rb +26 -0
  18. data/lib/ruby_screen/preferences_loader.rb +26 -0
  19. data/lib/ruby_screen/version.rb +9 -0
  20. data/log/debug.log +0 -0
  21. data/script/destroy +14 -0
  22. data/script/generate +14 -0
  23. data/script/txt2html +74 -0
  24. data/setup.rb +1585 -0
  25. data/spec/configuration/description_spec.rb +93 -0
  26. data/spec/configuration/generator_spec.rb +49 -0
  27. data/spec/configuration/parser/block_processor_spec.rb +46 -0
  28. data/spec/configuration/parser/iterator_spec.rb +35 -0
  29. data/spec/configuration/parser/nesting_hash_spec.rb +59 -0
  30. data/spec/configuration/parser_spec.rb +73 -0
  31. data/spec/executer_spec.rb +63 -0
  32. data/spec/preferences_loader_spec.rb +46 -0
  33. data/spec/ruby_screen_spec.rb +33 -0
  34. data/spec/spec.opts +1 -0
  35. data/spec/spec_helper.rb +9 -0
  36. data/tasks/deployment.rake +34 -0
  37. data/tasks/environment.rake +7 -0
  38. data/tasks/rspec.rake +21 -0
  39. data/tasks/website.rake +17 -0
  40. data/website/index.html +289 -0
  41. data/website/index.txt +226 -0
  42. data/website/javascripts/rounded_corners_lite.inc.js +285 -0
  43. data/website/stylesheets/screen.css +138 -0
  44. data/website/template.rhtml +48 -0
  45. metadata +111 -0
@@ -0,0 +1,93 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper.rb'
2
+
3
+ describe RubyScreen::Configuration::Description do
4
+ before { @configuration = RubyScreen::Configuration::Description.new }
5
+
6
+ it "should delegate #to_screen_configuration to Configuration::Generator" do
7
+ configuration_string = "my configuration string"
8
+ generator_mock = mock("mock Configuration::Generator")
9
+ generator_mock.should_receive(:to_screen_configuration).and_return(configuration_string)
10
+ RubyScreen::Configuration::Generator.should_receive(:new).and_return(generator_mock)
11
+ @configuration.to_screen_configuration.should equal(configuration_string)
12
+ end
13
+
14
+ describe "customizations" do
15
+ it "should be able to be added and retrieved" do
16
+ @configuration.add_customization(:startup_message, "off")
17
+ @configuration.add_customization(:foo, "bar")
18
+
19
+ customizations = @configuration.customizations
20
+ customizations[:startup_message].should eql("off")
21
+ customizations[:foo].should eql("bar")
22
+ end
23
+
24
+ it "should overwrite customizations with the same name on subsequent addition" do
25
+ @configuration.add_customization(:foo, "bar")
26
+ @configuration.add_customization(:foo, "new value")
27
+ @configuration.customizations[:foo].should eql("new value")
28
+ end
29
+ end
30
+
31
+ describe "working_directory" do
32
+ it "should be nil on initialization" do
33
+ @configuration.working_directory.should be_nil
34
+ end
35
+
36
+ it "should be able to be set" do
37
+ @configuration.working_directory = "/my/dir/"
38
+ @configuration.working_directory.should eql("/my/dir/")
39
+ end
40
+
41
+ it "should call File.expand_path when setting a working_directory that begins with a '~'" do
42
+ File.should_receive(:expand_path).and_return("from_expand_path")
43
+ @configuration.working_directory = "~/path"
44
+ @configuration.working_directory.should eql("from_expand_path")
45
+ end
46
+ end
47
+
48
+ describe "#append_directory" do
49
+ it "should properly add directory names to the current working_directory" do
50
+ @configuration.working_directory = "/first"
51
+ @configuration.append_directory("second")
52
+ @configuration.working_directory.should eql("/first/second")
53
+ end
54
+
55
+ it "should handle directories that have leading and/or trailing slashes" do
56
+ @configuration.working_directory = "/first"
57
+ @configuration.append_directory("/second")
58
+ @configuration.working_directory.should eql("/first/second")
59
+ @configuration.append_directory("third/")
60
+ @configuration.working_directory.should eql("/first/second/third")
61
+ end
62
+
63
+ it "should work properly when no working_directory has been set" do
64
+ @configuration.working_directory.should be_nil
65
+ @configuration.append_directory("second")
66
+ @configuration.working_directory.should eql("second")
67
+ end
68
+
69
+ it "should correctly handle entries that begin with '~' and call File.expand_path on them" do
70
+ @configuration.working_directory = "something"
71
+ File.should_receive(:expand_path).with("~/path").and_return("from_expand_path")
72
+ @configuration.append_directory("~/path")
73
+ @configuration.working_directory.should eql("from_expand_path")
74
+ end
75
+ end
76
+
77
+ describe "windows" do
78
+ it "should be able to add numberless windows" do
79
+ @configuration.add_window("title" => "server window", "command" => "script/server")
80
+ numberless_windows = @configuration.numberless_windows
81
+ numberless_windows.length.should eql(1)
82
+ numberless_windows.first["title"].should eql("server window")
83
+ numberless_windows.first["command"].should eql("script/server")
84
+ end
85
+
86
+ it "should be able to add numbered windows" do
87
+ @configuration.add_window("title" => "My Window", "number" => 1)
88
+ numbered_windows = @configuration.numbered_windows
89
+ numbered_windows.length.should eql(1)
90
+ numbered_windows[1]["title"].should eql("My Window")
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,49 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper.rb'
2
+
3
+ describe RubyScreen::Configuration::Generator, "#to_screen_configuration" do
4
+ before do
5
+ @description = mock("Configuration::Description mock")
6
+
7
+ @description.stub!(:customizations).and_return(
8
+ { :first => "custom", :second => "2" }
9
+ )
10
+
11
+ @description.stub!(:numbered_windows).and_return({
12
+ 0 => { "title" => "misc" },
13
+ 3 => { "title" => "three", "command" => "another command" },
14
+ 9 => { "command" => "final command" }
15
+ })
16
+
17
+ @description.stub!(:numberless_windows).and_return([
18
+ { "title" => "second" },
19
+ { "command" => "command-only window" }
20
+ ])
21
+
22
+ @description.stub!(:initial_directory).and_return("initial/directory")
23
+
24
+ @original_shell = ENV["SHELL"]
25
+ ENV["SHELL"] = "/usr/bin/my_shell"
26
+
27
+ @configuration_string = RubyScreen::Configuration::Generator.new(@description).to_screen_configuration
28
+
29
+ ENV["SHELL"] = @original_shell
30
+ end
31
+
32
+ it "should include top level customizations" do
33
+ @configuration_string.should match(/first custom/)
34
+ @configuration_string.should match(/second 2/)
35
+ end
36
+
37
+ it "should include numbered windows" do
38
+ s1 = "screen -t misc 0"
39
+ s2 = "screen -t three 3 sh -c \"another command; /usr/bin/my_shell\""
40
+ s3 = "screen 9 sh -c \"final command; /usr/bin/my_shell\""
41
+ @configuration_string.should match(/#{s1}\s#{s2}\s#{s3}/)
42
+ end
43
+
44
+ it "should include numberless windows" do
45
+ n1 = "screen -t second"
46
+ n2 = "screen sh -c \"command-only window; /usr/bin/my_shell\""
47
+ @configuration_string.should match(/#{n1}\s#{n2}/)
48
+ end
49
+ end
@@ -0,0 +1,46 @@
1
+ require File.dirname(__FILE__) + '/../../spec_helper.rb'
2
+
3
+ describe RubyScreen::Configuration::Parser::BlockProcessor do
4
+ before { @mock_description = mock("Description") }
5
+
6
+ after { RubyScreen::Configuration::Parser::BlockProcessor.new(@preferences_hash, @mock_description) }
7
+
8
+ it "should call Description#add_window for any window configurations" do
9
+ @mock_description.should_receive(:add_window).with({ "window1" => "settings1" }).ordered
10
+ @mock_description.should_receive(:add_window).with({ "window2" => "settings2" }).ordered
11
+
12
+ @preferences_hash = {
13
+ "windows" => [
14
+ { "window1" => "settings1" },
15
+ { "window2" => "settings2" }
16
+ ]
17
+ }
18
+ end
19
+
20
+ it "should call Description#working_directory for any working_directory settings" do
21
+ @mock_description = mock("Description")
22
+ @mock_description.should_receive(:working_directory=).with("dir")
23
+
24
+ @preferences_hash = { "working_directory" => "dir" }
25
+ end
26
+
27
+ it "should call Description#append_directory for any relative_directory settings" do
28
+ @mock_description.should_receive(:append_directory).with("dir")
29
+
30
+ @preferences_hash = { "relative_directory" => "dir" }
31
+ end
32
+
33
+ it "should call Description#add_customization for any abritrary settings" do
34
+ @mock_description.should_receive(:add_customization).with("key1", "val1")
35
+ @mock_description.should_receive(:add_customization).with("key2", "val2")
36
+
37
+ @preferences_hash = { "key1" => "val1", "key2" => "val2" }
38
+ end
39
+
40
+ it "should change any boolean values to the strings 'on' and 'off'" do
41
+ @mock_description.should_receive(:add_customization).with("true_thing", "on")
42
+ @mock_description.should_receive(:add_customization).with("false_thing", "off")
43
+
44
+ @preferences_hash = { "true_thing" => true, "false_thing" => false }
45
+ end
46
+ end
@@ -0,0 +1,35 @@
1
+ require File.dirname(__FILE__) + '/../../spec_helper.rb'
2
+
3
+ describe RubyScreen::Configuration::Parser::Iterator do
4
+ def capture_yield(arguments, hash)
5
+ @iterator = RubyScreen::Configuration::Parser::Iterator.new(arguments, hash)
6
+ @yielded = []
7
+ @iterator.each_applicable_configuration_block { |b| @yielded << b }
8
+ end
9
+
10
+ describe "with no nested configurations" do
11
+ it "should return the top level items in the hash" do
12
+ capture_yield([], { "one" => 1 })
13
+
14
+ @yielded.length.should eql(1)
15
+ @yielded[0].should == { "one" => 1 }
16
+ end
17
+ end
18
+
19
+ describe "with nested configurations" do
20
+ it "should not yield any nested configurations that the arguments do not specify" do
21
+ capture_yield([], { "one" => 1, "nested" => { "two" => 2 } })
22
+
23
+ @yielded.length.should eql(1)
24
+ @yielded[0].should == { "one" => 1 }
25
+ end
26
+
27
+ it "should yield nested configuration hashes one at a time as dictated by the arguments" do
28
+ capture_yield(["nested"], { "one" => 1, "nested" => { "two" => 2 } })
29
+
30
+ @yielded.length.should eql(2)
31
+ @yielded[0].should == { "one" => 1 }
32
+ @yielded[1].should == { "two" => 2 }
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,59 @@
1
+ require File.dirname(__FILE__) + '/../../spec_helper.rb'
2
+
3
+ describe RubyScreen::Configuration::Parser::NestingHash do
4
+ nested_preferences_hash = {
5
+ "top" => "top_level",
6
+ "nested1" => {
7
+ "one" => 1,
8
+ "nested2" => {
9
+ "two" => 2,
10
+ "nested3" => {
11
+ "three" => 3
12
+ }
13
+ },
14
+ "nested2.5" => {
15
+ "nested4" => {
16
+ "four" => 4
17
+ }}}}
18
+
19
+ duplicate_preferences_hash = {
20
+ "first" => {
21
+ "the_same" => {
22
+ "second" => {
23
+ "the_same" => {
24
+ }}}}}
25
+
26
+ before { nested_preferences_hash.extend(RubyScreen::Configuration::Parser::NestingHash) }
27
+
28
+ it "should define a find_nested_key method when extended" do
29
+ nested_preferences_hash.should respond_to(:find_nested_key)
30
+ end
31
+
32
+ describe "#find_nested_key" do
33
+ it "should return nil when a search result isn't found" do
34
+ nested_preferences_hash.find_nested_key("wang").should be_nil
35
+ end
36
+
37
+ it "should return an array of the hierarchy of hash keys that lead to the key that was searched for" do
38
+ nested_preferences_hash.find_nested_key("nested2").should eql(["nested1", "nested2"])
39
+ nested_preferences_hash.find_nested_key("nested4").should eql(["nested1", "nested2.5", "nested4"])
40
+ end
41
+
42
+ describe "given a hash with duplicate keys" do
43
+ it "should raise a DuplicateKeyException" do
44
+ lambda {
45
+ duplicate_preferences_hash.extend(RubyScreen::Configuration::Parser::NestingHash)
46
+ }.should raise_error(DuplicateKeyException)
47
+
48
+ end
49
+
50
+ it "should contain the name of the duplicated hash key in the exception" do
51
+ begin
52
+ duplicate_preferences_hash.extend(RubyScreen::Configuration::Parser::NestingHash)
53
+ rescue DuplicateKeyException => e
54
+ e.key.should eql("the_same")
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,73 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper.rb'
2
+
3
+ describe RubyScreen::Configuration::Parser do
4
+ before do
5
+ @preferences_hash = { "preferences" => "hash" }
6
+ @preferences_hash.stub!(:find_nested_key).and_return(["first", "second"])
7
+
8
+ @mock_iterator = mock("Iterator")
9
+ @mock_iterator.stub!(:each_applicable_configuration_block)
10
+ RubyScreen::Configuration::Parser::Iterator.stub!(:new).and_return(@mock_iterator)
11
+
12
+ @mock_description = mock("Description")
13
+ @mock_description.stub!(:append_directory)
14
+ RubyScreen::Configuration::Description.stub!(:new).and_return(@mock_description)
15
+ end
16
+
17
+ after do
18
+ arguments = ["first_argument", "second_argument", "third_argument"]
19
+ RubyScreen::Configuration::Parser.parse(arguments, @preferences_hash)
20
+ end
21
+
22
+ it "should extend the preferences_hash with the NestingHash module" do
23
+ @preferences_hash.should_receive(:extend).with(RubyScreen::Configuration::Parser::NestingHash)
24
+ end
25
+
26
+ it "should call #find_nested_key on the preferences_hash with the first argument" do
27
+ @preferences_hash.should_receive(:find_nested_key).with("first_argument")
28
+ end
29
+
30
+ it "should instantiate a new Iterator with the path returned by #find_nested_key and preferences_hash" do
31
+ RubyScreen::Configuration::Parser::Iterator.should_receive(:new).with(["first", "second"], @preferences_hash).and_return(@mock_iterator)
32
+ end
33
+
34
+ it "should set the configuration path to a blank array if no key is found" do
35
+ @preferences_hash.stub!(:find_nested_key).and_return(nil)
36
+ RubyScreen::Configuration::Parser::Iterator.should_receive(:new).with([], @preferences_hash).and_return(@mock_iterator)
37
+ end
38
+
39
+ it "should catch a DuplicateKeyException from the preferences_hash and abort if so, naming the offending key" do
40
+ @preferences_hash.should_receive(:extend).and_raise(DuplicateKeyException.new("problem_key"))
41
+ Kernel.should_receive(:abort).with /problem_key/
42
+ end
43
+
44
+ it "should instantiate a new Description" do
45
+ RubyScreen::Configuration::Description.should_receive(:new).and_return(@mock_description)
46
+ end
47
+
48
+ it "should call the Iterator#each_applicable_configuration_block and pass the yielded block to a BlockProcessor" do
49
+ mock_configuration_block = mock("Configuration Block")
50
+ @mock_iterator.should_receive(:each_applicable_configuration_block).and_yield(mock_configuration_block)
51
+ RubyScreen::Configuration::Parser::BlockProcessor.should_receive(:new).with(mock_configuration_block, @mock_description)
52
+ end
53
+
54
+ # Oi, what a cluster. Can't specify global ordering, and to do this perfectly I'd have to mock a ton.
55
+ it "should call Description#append_directory for each additional argument only after main configuration has been parsed" do
56
+ @iterated = false
57
+ @second_arg_called = false
58
+ @third_arg_called = false
59
+
60
+ @mock_iterator.should_receive(:each_applicable_configuration_block) { @iterated = true }
61
+ @mock_description.should_receive(:append_directory).twice { |arg|
62
+ fail "Called out of order, additional arguments added before configuration processed!" unless @iterated
63
+
64
+ if arg == "second_argument" && !@second_arg_called && !@third_arg_called
65
+ @second_arg_called = true
66
+ elsif arg == "third_argument" && @second_arg_called && !@third_arg_called
67
+ @third_arg_called = true
68
+ else
69
+ fail "Called out of order, with arg #{arg}"
70
+ end
71
+ }
72
+ end
73
+ end
@@ -0,0 +1,63 @@
1
+ require File.dirname(__FILE__) + '/spec_helper.rb'
2
+
3
+ describe RubyScreen::Executer do
4
+ before do
5
+ @description = mock("mock Configuration::Description")
6
+ @description.stub!(:to_screen_configuration)
7
+ @description.stub!(:working_directory)
8
+
9
+ @file_mock = mock("mock File")
10
+ @file_mock.stub!(:print)
11
+ File.stub!(:open).and_yield(@file_mock)
12
+ File.stub!(:exists?).and_return(true)
13
+ File.stub!(:directory?).and_return(true)
14
+ Dir.stub!(:chdir)
15
+ Dir.stub!(:tmpdir).and_return("/tmp")
16
+ Kernel.stub!(:exec)
17
+ end
18
+
19
+ after { RubyScreen::Executer.new(@description) }
20
+
21
+ describe "provided a valid Configuration::Description" do
22
+ describe "#initialize" do
23
+ it "should request the file systems' temporary directory" do
24
+ Dir.should_receive(:tmpdir).any_number_of_times.and_return("/tmp")
25
+ end
26
+
27
+ it "should open a file to store the compiled screen configuration" do
28
+ File.should_receive(:open).with("/tmp/.ruby-screen.compiled_configuration", "w").and_yield(@file_mock)
29
+ end
30
+
31
+ it "should check that the working_directory from the Description is valid" do
32
+ @description.stub!(:working_directory).and_return("initial/directory/path")
33
+ File.should_receive(:exists?).with("initial/directory/path").and_return(true)
34
+ File.should_receive(:directory?).with("initial/directory/path").and_return(true)
35
+ end
36
+
37
+ it "should attempt to change directory to correct working directory" do
38
+ @description.should_receive(:working_directory).any_number_of_times.and_return("initial/directory/path")
39
+ Dir.should_receive(:chdir).with("initial/directory/path")
40
+ end
41
+
42
+ it "should write compiled configuration from description to the opened file" do
43
+ @description.should_receive(:to_screen_configuration).and_return("my configuration string")
44
+ @file_mock.should_receive(:print).with("my configuration string")
45
+ end
46
+
47
+ it "should exec screen, passing the path to the compiled configuration" do
48
+ Kernel.should_receive(:exec).with("screen -c /tmp/.ruby-screen.compiled_configuration")
49
+ end
50
+ end
51
+ end
52
+
53
+ describe "provided a Configuration::Description with an invalid working directory" do
54
+ before do
55
+ @description.stub!(:working_directory).and_return("initial/directory/path")
56
+ File.stub!(:exists?).and_return(false)
57
+ end
58
+
59
+ it "should abort with an error" do
60
+ Kernel.should_receive(:abort).with(/initial\/directory\/path/)
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,46 @@
1
+ require File.dirname(__FILE__) + '/spec_helper.rb'
2
+
3
+ describe RubyScreen::PreferencesLoader do
4
+ before do
5
+ @original_home = ENV["HOME"]
6
+ ENV["HOME"] = "/my/home/path"
7
+
8
+ YAML.stub!(:load)
9
+ erb = mock("ERB Mock")
10
+ erb.stub!(:result)
11
+ ERB.stub!(:new).and_return(erb)
12
+ IO.stub!(:read)
13
+ end
14
+
15
+ after { ENV["HOME"] = @original_home }
16
+
17
+ it "should call IO#read with the default file path" do
18
+ IO.should_receive(:read).with("/my/home/path/.ruby-screen.yml")
19
+ RubyScreen::PreferencesLoader.load
20
+ end
21
+
22
+ it "should display a helpful error message when the file cannot be loaded" do
23
+ lambda {
24
+ Kernel.should_receive(:abort).with(/\.ruby-screen\.yml/)
25
+ IO.stub!(:read).and_raise("not want!")
26
+ RubyScreen::PreferencesLoader.load
27
+ }.should_not raise_error
28
+ end
29
+
30
+ it "should pass output from IO#read through ERB#new, and call #result" do
31
+ read_results = mock("read results")
32
+ IO.stub!(:read).and_return(read_results)
33
+ erb_mock = mock("ERB Mock")
34
+ erb_mock.should_receive(:result)
35
+ ERB.should_receive(:new).and_return(erb_mock)
36
+ RubyScreen::PreferencesLoader.load
37
+ end
38
+
39
+ it "should pass return value from erb results to YAML#load" do
40
+ erb_mock = mock("ERB Mock")
41
+ erb_mock.stub!(:result).and_return("return from erb")
42
+ ERB.stub!(:new).and_return(erb_mock)
43
+ YAML.should_receive(:load).with("return from erb").and_return("return from YAML")
44
+ RubyScreen::PreferencesLoader.load.should eql("return from YAML")
45
+ end
46
+ end