wizard 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,95 @@
1
+ require 'wizard/spells/make_file'
2
+
3
+ module Wizard
4
+ class Formula
5
+
6
+ colorizers.merge!(
7
+ :missing => :red
8
+ )
9
+
10
+ def update_file(filename, content=nil, options={})
11
+ spell = Spells::UpdateFile.new(filename, content, options)
12
+ spell.perform
13
+ render(spell)
14
+ end
15
+ alias_method :update, :update_file
16
+
17
+ def append_to_file(filename, content, options={})
18
+ update_file(filename, content, options.merge(:before => :EOF))
19
+ end
20
+ alias_method :append, :append_to_file
21
+ alias_method :append_to, :append_to_file
22
+
23
+ def prepend_to_file(filename, content, options={})
24
+ update_file(filename, content, options.merge(:after => :BOF))
25
+ end
26
+ alias_method :prepend, :prepend_to_file
27
+ alias_method :prepend_to, :prepend_to_file
28
+
29
+ def replace_in_file(filename, content, replace, options={})
30
+ update_file(filename, content, options.merge(:replace => replace))
31
+ end
32
+ alias_method :replace, :replace_in_file
33
+ alias_method :replace_content, :replace_in_file
34
+
35
+ end # Formula
36
+
37
+ module Spells
38
+ class UpdateFile < MakeFile
39
+
40
+ attr_reader :filename, :chmod, :content, :before, :after, :replace
41
+ attr_status :missing
42
+
43
+ def initialize(filename, content=nil, options={})
44
+ super(filename, nil, options)
45
+
46
+ @content = content
47
+ @before = options[:before]
48
+ @after = options[:after]
49
+ @replace = options[:replace]
50
+ end
51
+
52
+ def perform_with_content_update
53
+ if File.exist?(filename)
54
+ force! and rebuild_content and perform_without_content_update
55
+ elsif content && !before && !after && !replace
56
+ perform_without_content_update
57
+ else
58
+ missing!
59
+ end
60
+ rescue Object
61
+ error!
62
+ end
63
+
64
+ alias_method :perform_without_content_update, :perform
65
+ alias_method :perform, :perform_with_content_update
66
+
67
+ # Build new content based on original one, including specified update
68
+ # directives. All directives can't be mixed, which mean that only
69
+ # one update can ba applied on the file at one time. If none directive
70
+ # is specified, then whole file content will be replaced with specified
71
+ # in constructor.
72
+ def rebuild_content
73
+ if (before || after) && !replace
74
+ content = File.read(filename)
75
+
76
+ return @content = [@content, content].join("\n") if after == :BOF
77
+ return @content = [content, @content].join("\n") if before == :EOF
78
+
79
+ content = content.sub(/\r\n/, "\n").sub(/\r/, "\n").split(/\n/)
80
+ content.each_with_index do |line, id|
81
+ content[id] = [@content, line].join("\n") if !after && before && line =~ before
82
+ content[id] = [line, @content].join("\n") if !before && after && line =~ after
83
+ end
84
+
85
+ @content = content.join("\n")
86
+ elsif replace
87
+ @content = File.read(filename).sub(replace, @content)
88
+ else
89
+ @content
90
+ end
91
+ end
92
+
93
+ end # UpdateFile
94
+ end # Spells
95
+ end # Wizard
@@ -0,0 +1,55 @@
1
+ require File.expand_path("../spec_helper", __FILE__)
2
+
3
+ describe Wizard::Helpers do
4
+ subject do
5
+ Wizard
6
+ end
7
+
8
+ context "#say!" do
9
+ Wizard::Helpers::COLORS.each do |color, code|
10
+ [false, true].each do |bold|
11
+ it "should properly display #{bold ? "bold and" : ""}#{color.to_s} text on screen" do
12
+ capture { Wizard.say!(color.to_s, color, bold) }
13
+ last_stdout.should == "\e[#{bold ? 1 : 0};#{code}m#{color.to_s}\n\e[0m"
14
+ end
15
+ end
16
+ end
17
+ end
18
+
19
+ describe "#print" do
20
+ it "should properly print given text to stdout" do
21
+ capture { subject.print "This is SPARTA!" }
22
+ last_stdout.should == "This is SPARTA!"
23
+ end
24
+ end
25
+
26
+ describe "#colorize" do
27
+ it "should colorize given text" do
28
+ subject.colorize("foo", :red).should == "\e[0;31mfoo\e[0m"
29
+ subject.colorize("bar", :red, true).should == "\e[1;31mbar\e[0m"
30
+ end
31
+ end
32
+
33
+ describe "#console_width" do
34
+ it "should return actual console width" do
35
+ # tested manualy...
36
+ subject.console_width
37
+ end
38
+ end
39
+
40
+ describe "#adjust" do
41
+ context "when size given" do
42
+ it "should adjust text to given size" do
43
+ subject.adjust("foo", 8).should == "foo \e[0;30m....\e[0m"
44
+ subject.adjust("foo", 8, '-').should == "foo \e[0;30m----\e[0m"
45
+ end
46
+ end
47
+
48
+ context "when no size given" do
49
+ it "should adjust text to console size" do
50
+ subject.expects(:console_width).returns(10)
51
+ subject.adjust("foo").should == "foo \e[0;30m......\e[0m"
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,71 @@
1
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
2
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
3
+
4
+ require 'rubygems'
5
+ require 'stringio'
6
+ require 'ostruct'
7
+ require 'rspec'
8
+ require 'mocha'
9
+ require 'wizard'
10
+
11
+ module Helpers
12
+ # Capture and silence output streams (stdout, stderr), and return it values.
13
+ #
14
+ # capture { puts "This is sparta!" }
15
+ # last_stdout # => "This is sparta!"
16
+ # last_stderr # => ""
17
+ def capture
18
+ @last_stdout = StringIO.new
19
+ @last_stderr = StringIO.new
20
+ begin
21
+ $stdout = @last_stdout
22
+ $stderr = @last_stderr
23
+ yield
24
+ ensure
25
+ $stdout = STDERR
26
+ $stderr = STDOUT
27
+ end
28
+ [@last_stdout.string, @last_stderr.string]
29
+ end
30
+
31
+ # Replace standard input with faked one StringIO.
32
+ def fake_stdin(text)
33
+ begin
34
+ $stdin = StringIO.new
35
+ $stdin.puts(text)
36
+ $stdin.rewind
37
+ yield
38
+ ensure
39
+ $stdin = STDIN
40
+ end
41
+ end
42
+
43
+ # Returns last string written to captured output stream.
44
+ def last_stdout
45
+ @last_stdout.string if @last_stdout
46
+ end
47
+
48
+ # Returns last string written to captured error stream.
49
+ def last_stderr
50
+ @last_stdout.string if @last_stdout
51
+ end
52
+
53
+ # Executes code within given temp directory context.
54
+ def within_tmp(&block)
55
+ FileUtils.mkdir(dirname = File.join(File.dirname(__FILE__), 'tmp'))
56
+ yield(File.expand_path(dirname))
57
+ ensure
58
+ FileUtils.rm_rf(dirname)
59
+ end
60
+
61
+ # Returns mock generator.
62
+ def mock_gen(opts={})
63
+ Ryori::Generator.new(File.dirname(__FILE__)+"/tmp", opts)
64
+ end
65
+ end
66
+
67
+ RSpec.configure do |config|
68
+ config.mock_with :mocha
69
+ config.include Helpers
70
+ end
71
+
@@ -0,0 +1,60 @@
1
+ require File.expand_path("../../spec_helper", __FILE__)
2
+
3
+ describe Wizard::Spells::CompileTemplate do
4
+ subject do
5
+ Wizard::Spells::CompileTemplate
6
+ end
7
+
8
+ describe "#initialize" do
9
+ it "should set given filename" do
10
+ subject.new("/path/to/file", "/path/to/tpl").filename.should == "/path/to/file"
11
+ end
12
+
13
+ context "given template name" do
14
+ it "should be set" do
15
+ subject.new("/path/to/file", "/path/to/tpl").template.should == "/path/to/tpl"
16
+ end
17
+ end
18
+
19
+ it "should set default chmod" do
20
+ subject.new("/path/to/file", "/path/to/tpl").chmod.should == 644
21
+ end
22
+
23
+ context "given :mode option" do
24
+ it "should set it" do
25
+ subject.new("/path/to/file", "/path/to/tpl", :mode => 755).chmod.should == 755
26
+ end
27
+ end
28
+
29
+ context "given :force option" do
30
+ it "should run in force mode" do
31
+ subject.new("/path/to/file", "/path/to/tpl", :force => true).should be_forced
32
+ end
33
+ end
34
+ end
35
+
36
+ context "#perform" do
37
+ subject do
38
+ Wizard::Spells::CompileTemplate.new("/path/to/file", "/path/to/tpl")
39
+ end
40
+
41
+ context "when specified template causes errors" do
42
+ it "should set :error state" do
43
+ File.expects(:read).with("/path/to/tpl").raises(Exception)
44
+ spell = subject
45
+ spell.perform.should == :error
46
+ spell.should be_error
47
+ end
48
+ end
49
+
50
+ context "when specified template is ok" do
51
+ it "should compile it and invoke make_file" do
52
+ File.expects(:read).with("/path/to/tpl").returns("<%='test'%>")
53
+ spell = subject
54
+ spell.expects(:perform_without_template_compilation).returns(:created)
55
+ spell.perform.should == :created
56
+ spell.content.should == 'test'
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,58 @@
1
+ require File.expand_path("../../spec_helper", __FILE__)
2
+
3
+ describe Wizard::Spells::ExecuteShell do
4
+ subject do
5
+ Wizard::Spells::ExecuteShell
6
+ end
7
+
8
+ describe "#initialize" do
9
+ it "should set given command" do
10
+ subject.new("echo 'test'").command.should == "echo 'test'"
11
+ end
12
+ end
13
+
14
+ describe "#perform" do
15
+ context "when given command is valid" do
16
+ subject do
17
+ Wizard::Spells::ExecuteShell.new("echo 'test'")
18
+ end
19
+
20
+ it "should execute command and set :executed status" do
21
+ spell = subject
22
+ spell.perform == :executed
23
+ spell.should be_executed
24
+ end
25
+
26
+ it "should set it output to instance variable" do
27
+ spell = subject
28
+ spell.perform
29
+ spell.output.should == "test\n"
30
+ end
31
+ end
32
+
33
+ context "when given command causes errors" do
34
+ subject do
35
+ Wizard::Spells::ExecuteShell.new("some-error")
36
+ end
37
+
38
+ it "should execute command and set :executed status" do
39
+ spell = subject
40
+ spell.expects(:failed!).raises(Exception)
41
+ spell.perform == :error
42
+ spell.should be_error
43
+ end
44
+ end
45
+
46
+ context "when given command can't be executed" do
47
+ subject do
48
+ Wizard::Spells::ExecuteShell.new("no-such-command")
49
+ end
50
+
51
+ it "should execute command and set :executed status" do
52
+ spell = subject
53
+ spell.perform == :failed
54
+ spell.should be_failed
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,77 @@
1
+ require File.expand_path("../../spec_helper", __FILE__)
2
+
3
+ describe Wizard::Spells::MakeDir do
4
+ subject do
5
+ Wizard::Spells::MakeDir
6
+ end
7
+
8
+ describe "#initialize" do
9
+ it "should set given dirname" do
10
+ subject.new("/path/to/dir").dirname.should == "/path/to/dir"
11
+ end
12
+
13
+ it "should have empty chmod by default" do
14
+ subject.new("/path/to/dir").chmod.should == nil
15
+ end
16
+
17
+ context "given :mode" do
18
+ it "should set it" do
19
+ subject.new("/path/to/dir", :mode => 755).chmod.should == 755
20
+ end
21
+ end
22
+ end
23
+
24
+ describe "#perform" do
25
+ subject do
26
+ Wizard::Spells::MakeDir.new("/path/to/dir")
27
+ end
28
+
29
+ context "when specified directory exists" do
30
+ it "should set :exist status" do
31
+ File.expects(:exist?).returns(true)
32
+ spell = subject
33
+ spell.perform.should == :exist
34
+ spell.should be_exist
35
+ end
36
+ end
37
+
38
+ context "when specified directory doesn't exist" do
39
+ context "and user have access to create it" do
40
+ it "should set :created status" do
41
+ FileUtils.expects(:mkdir_p).with("/path/to/dir", :mode => 644).returns("/path/to/dir")
42
+ spell = subject
43
+ spell.perform.should == :created
44
+ spell.should be_created
45
+ end
46
+ end
47
+
48
+ context "and user don't have access to create it" do
49
+ it "should set :noaccess status" do
50
+ FileUtils.expects(:mkdir_p).with("/path/to/dir", :mode => 644).raises(Errno::EACCES)
51
+ spell = subject
52
+ spell.perform.should == :noaccess
53
+ spell.should be_noaccess
54
+ end
55
+ end
56
+ end
57
+
58
+ context "when unknown error raised while creating directory" do
59
+ it "shouldn't create it and set :noaccess status" do
60
+ FileUtils.expects(:mkdir_p).with("/path/to/dir", :mode => 644).raises(Exception)
61
+ spell = subject
62
+ spell.perform.should == :error
63
+ spell.should be_error
64
+ end
65
+ end
66
+
67
+ context "when directory can't been created" do
68
+ it "shouldn't create it and set :error status" do
69
+ FileUtils.expects(:mkdir_p).with("/path/to/dir", :mode => 644).returns(false)
70
+ spell = subject
71
+ spell.perform.should == :error
72
+ spell.should be_error
73
+ end
74
+ end
75
+ end
76
+ end
77
+
@@ -0,0 +1,125 @@
1
+ require File.expand_path("../../spec_helper", __FILE__)
2
+
3
+ describe Wizard::Spells::MakeFile do
4
+ subject do
5
+ Wizard::Spells::MakeFile
6
+ end
7
+
8
+ describe "#initialize" do
9
+ it "should set given filename" do
10
+ subject.new("/path/to/file").filename.should == "/path/to/file"
11
+ end
12
+
13
+ context "given content" do
14
+ it "should be set" do
15
+ subject.new("/path/to/file", "hello world!").content.should == "hello world!"
16
+ end
17
+ end
18
+
19
+ it "should have empty chmod by default" do
20
+ subject.new("/path/to/file").chmod.should == nil
21
+ end
22
+
23
+ context "given :mode option" do
24
+ it "should set it" do
25
+ subject.new("/path/to/file", nil, :mode => 755).chmod.should == 755
26
+ end
27
+ end
28
+
29
+ context "given :force option" do
30
+ it "should run in force mode" do
31
+ subject.new("/path/to/file", nil, :force => true).should be_forced
32
+ end
33
+ end
34
+ end
35
+
36
+ describe "#perform" do
37
+ subject do
38
+ Wizard::Spells::MakeFile.new("/path/to/file")
39
+ end
40
+
41
+ context "when specified file exists" do
42
+ subject do
43
+ Wizard::Spells::MakeFile.new("/path/to/file", "testing")
44
+ end
45
+
46
+ context "and it content is identical as given one" do
47
+ it "should set :identical status" do
48
+ File.expects(:exist?).returns(true)
49
+ File.expects(:read).with("/path/to/file").returns("testing")
50
+ spell = subject
51
+ spell.perform.should == :identical
52
+ spell.should be_identical
53
+ end
54
+ end
55
+
56
+ context "and it content is different than given one" do
57
+ subject do
58
+ Wizard::Spells::MakeFile.new("/path/to/file", "testing")
59
+ end
60
+
61
+ it "should set :conflict status" do
62
+ File.expects(:exist?).returns(true)
63
+ File.expects(:read).with("/path/to/file").returns("not-testing")
64
+ spell = subject
65
+ spell.perform.should == :conflict
66
+ spell.should be_conflict
67
+ end
68
+
69
+ context "and force mode is on" do
70
+ subject do
71
+ Wizard::Spells::MakeFile.new("/path/to/file", "testing", :force => true)
72
+ end
73
+
74
+ it "should overwrite current file" do
75
+ File.expects(:exist?).returns(true)
76
+ File.expects(:read).with("/path/to/file").returns("not-testing")
77
+ spell = subject
78
+ spell.expects(:create_file!).returns(true)
79
+ spell.perform.should == :updated
80
+ spell.should be_updated
81
+ end
82
+ end
83
+ end
84
+ end
85
+
86
+ context "when specified file doesn't exist" do
87
+ context "and user have access to create it" do
88
+ it "should set :created status" do
89
+ File.expects(:open).with("/path/to/file", "w+").returns(true)
90
+ FileUtils.expects(:chmod).with(644, "/path/to/file").returns(true)
91
+ spell = subject
92
+ spell.perform.should == :created
93
+ spell.should be_created
94
+ end
95
+ end
96
+
97
+ context "and user don't have access to create it" do
98
+ it "should set :noaccess status" do
99
+ File.expects(:open).with("/path/to/file", "w+").raises(Errno::EACCES)
100
+ spell = subject
101
+ spell.perform.should == :noaccess
102
+ spell.should be_noaccess
103
+ end
104
+ end
105
+ end
106
+
107
+ context "when unknown error raised while creating file" do
108
+ it "shouldn't create it and set :noaccess status" do
109
+ File.expects(:open).with("/path/to/file", "w+").raises(Exception)
110
+ spell = subject
111
+ spell.perform.should == :error
112
+ spell.should be_error
113
+ end
114
+ end
115
+
116
+ context "when file can't be created or chmod not set" do
117
+ it "shouldn't create it and set :error status" do
118
+ File.expects(:open).with("/path/to/file", "w+").returns(false)
119
+ spell = subject
120
+ spell.perform.should == :error
121
+ spell.should be_error
122
+ end
123
+ end
124
+ end
125
+ end