wizard 0.0.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.
@@ -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