coral_core 0.2.23 → 0.2.24
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.
- data/.document +5 -0
- data/.gitmodules +12 -0
- data/Gemfile +14 -0
- data/Gemfile.lock +39 -0
- data/Rakefile +79 -0
- data/VERSION +1 -0
- data/coral_core.gemspec +102 -0
- data/lib/coral_core.rb +260 -0
- data/lib/coral_core/command.rb +244 -0
- data/lib/coral_core/config.rb +360 -0
- data/lib/coral_core/core.rb +212 -0
- data/lib/coral_core/event.rb +170 -0
- data/lib/coral_core/event/regexp_event.rb +55 -0
- data/lib/coral_core/interface.rb +180 -0
- data/lib/coral_core/memory.rb +226 -0
- data/lib/coral_core/repository.rb +164 -0
- data/lib/coral_core/resource.rb +243 -0
- data/lib/coral_core/template.rb +92 -0
- data/lib/coral_core/template/environment.rb +72 -0
- data/lib/coral_core/template/json.rb +13 -0
- data/lib/coral_core/template/wrapper.rb +13 -0
- data/lib/coral_core/template/yaml.rb +13 -0
- data/lib/coral_core/util/data.rb +219 -0
- data/lib/coral_core/util/disk.rb +92 -0
- data/lib/coral_core/util/git.rb +15 -0
- data/lib/coral_core/util/git/base.rb +58 -0
- data/lib/coral_core/util/git/lib.rb +82 -0
- data/lib/coral_core/util/git/remote.rb +12 -0
- data/lib/coral_core/util/shell.rb +183 -0
- data/lib/hiera_backend.rb +63 -0
- data/spec/coral_core/interface_spec.rb +489 -0
- data/spec/coral_mock_input.rb +29 -0
- data/spec/coral_test_kernel.rb +22 -0
- data/spec/spec_helper.rb +15 -0
- metadata +38 -4
@@ -0,0 +1,15 @@
|
|
1
|
+
|
2
|
+
require 'git'
|
3
|
+
|
4
|
+
module Git
|
5
|
+
|
6
|
+
#-----------------------------------------------------------------------------
|
7
|
+
# Utilities
|
8
|
+
|
9
|
+
def self.url(host, repo, options = {})
|
10
|
+
options[:user] = ( options[:user] ? options[:user] : 'git' )
|
11
|
+
options[:auth] = ( options[:auth] ? options[:auth] : true )
|
12
|
+
|
13
|
+
return options[:user] + ( options[:auth] ? '@' : '://' ) + host + ( options[:auth] ? ':' : '/' ) + repo
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
|
2
|
+
module Git
|
3
|
+
|
4
|
+
#*******************************************************************************
|
5
|
+
# Errors
|
6
|
+
|
7
|
+
class GitDirectoryError < StandardError
|
8
|
+
end
|
9
|
+
|
10
|
+
#*******************************************************************************
|
11
|
+
# Base Git definition
|
12
|
+
|
13
|
+
class Base
|
14
|
+
|
15
|
+
#-----------------------------------------------------------------------------
|
16
|
+
# Constructor / Destructor
|
17
|
+
|
18
|
+
def initialize(options = {})
|
19
|
+
if working_dir = options[:working_directory]
|
20
|
+
options[:repository] ||= File.join(working_dir, '.git')
|
21
|
+
|
22
|
+
if File.file?(options[:repository])
|
23
|
+
File.read(options[:repository]).each_line do |line|
|
24
|
+
matches = line.match(/^\s*gitdir:\s*(.+)\s*/)
|
25
|
+
if matches.length && matches[1]
|
26
|
+
options[:repository] = matches[1]
|
27
|
+
break
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
if File.directory?(options[:repository])
|
33
|
+
options[:index] ||= File.join(options[:repository], 'index')
|
34
|
+
else
|
35
|
+
raise GitDirectoryError.new("Git repository directory #{options[:repository]} not found for #{working_dir}")
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
if options[:log]
|
40
|
+
@logger = options[:log]
|
41
|
+
@logger.info("Starting Git")
|
42
|
+
else
|
43
|
+
@logger = nil
|
44
|
+
end
|
45
|
+
|
46
|
+
@working_directory = options[:working_directory] ? Git::WorkingDirectory.new(options[:working_directory]) : nil
|
47
|
+
@repository = options[:repository] ? Git::Repository.new(options[:repository]) : nil
|
48
|
+
@index = options[:index] ? Git::Index.new(options[:index], false) : nil
|
49
|
+
end
|
50
|
+
|
51
|
+
#-----------------------------------------------------------------------------
|
52
|
+
# Commit extensions
|
53
|
+
|
54
|
+
def add(path = '.', opts = {})
|
55
|
+
self.lib.add(path, opts)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
|
2
|
+
module Git
|
3
|
+
class Lib
|
4
|
+
|
5
|
+
#-----------------------------------------------------------------------------
|
6
|
+
# Commit extensions
|
7
|
+
|
8
|
+
def add(path = '.', opts = {})
|
9
|
+
arr_opts = []
|
10
|
+
arr_opts << '-u' if opts[:update]
|
11
|
+
if path.is_a?(Array)
|
12
|
+
arr_opts += path
|
13
|
+
else
|
14
|
+
arr_opts << path
|
15
|
+
end
|
16
|
+
command('add', arr_opts)
|
17
|
+
end
|
18
|
+
|
19
|
+
#---
|
20
|
+
|
21
|
+
def commit(message, opts = {})
|
22
|
+
arr_opts = ['-m', message]
|
23
|
+
arr_opts << "--author=\'#{opts[:author]}\'" unless opts[:author] && opts[:author].empty?
|
24
|
+
arr_opts << '-a' if opts[:add_all]
|
25
|
+
arr_opts << '--allow-empty' if opts[:allow_empty]
|
26
|
+
command('commit', arr_opts)
|
27
|
+
end
|
28
|
+
|
29
|
+
#-----------------------------------------------------------------------------
|
30
|
+
# Remote extensions
|
31
|
+
|
32
|
+
def remote_add(name, url, opts = {})
|
33
|
+
arr_opts = ['add']
|
34
|
+
arr_opts << '-f' if opts[:with_fetch]
|
35
|
+
arr_opts << name
|
36
|
+
arr_opts << url
|
37
|
+
|
38
|
+
command('remote', arr_opts)
|
39
|
+
end
|
40
|
+
|
41
|
+
#---
|
42
|
+
|
43
|
+
def remote_set_url(name, url, opts = {})
|
44
|
+
arr_opts = ['set-url']
|
45
|
+
|
46
|
+
if opts[:add]
|
47
|
+
arr_opts << '--add' if opts[:add]
|
48
|
+
end
|
49
|
+
|
50
|
+
if opts[:delete]
|
51
|
+
arr_opts << '--delete' if opts[:delete]
|
52
|
+
end
|
53
|
+
|
54
|
+
if opts[:push]
|
55
|
+
arr_opts << '--push' if opts[:push]
|
56
|
+
end
|
57
|
+
|
58
|
+
arr_opts << name
|
59
|
+
arr_opts << url
|
60
|
+
|
61
|
+
command('remote', arr_opts)
|
62
|
+
end
|
63
|
+
|
64
|
+
#---
|
65
|
+
|
66
|
+
def remote_remove(name)
|
67
|
+
command('remote', ['rm', name])
|
68
|
+
end
|
69
|
+
|
70
|
+
#-----------------------------------------------------------------------------
|
71
|
+
# Utilities
|
72
|
+
|
73
|
+
def escape(s)
|
74
|
+
escaped = s.to_s.gsub('"', '\'')
|
75
|
+
if escaped =~ /^\-+/
|
76
|
+
escaped
|
77
|
+
else
|
78
|
+
%Q{"#{escaped}"}
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,183 @@
|
|
1
|
+
|
2
|
+
module Coral
|
3
|
+
module Util
|
4
|
+
class Shell < Core
|
5
|
+
|
6
|
+
#-----------------------------------------------------------------------------
|
7
|
+
# Utilities
|
8
|
+
|
9
|
+
def self.exec!(command, options = {})
|
10
|
+
config = Config.ensure(options)
|
11
|
+
|
12
|
+
min = config.get(:min, 1).to_i
|
13
|
+
tries = config.get(:tries, min).to_i
|
14
|
+
tries = ( min > tries ? min : tries )
|
15
|
+
|
16
|
+
info_prefix = config.get(:info_prefix, '')
|
17
|
+
info_suffix = config.get(:info_suffix, '')
|
18
|
+
error_prefix = config.get(:error_prefix, '')
|
19
|
+
error_suffix = config.get(:error_suffix, '')
|
20
|
+
|
21
|
+
ui = config.get(:ui, Coral.ui)
|
22
|
+
|
23
|
+
conditions = Coral::Event.instance(config.get(:exit, {}), true)
|
24
|
+
|
25
|
+
$stdout.sync = true
|
26
|
+
$stderr.sync = true
|
27
|
+
|
28
|
+
for i in tries.downto(1)
|
29
|
+
ui.info(">> running: #{command}")
|
30
|
+
|
31
|
+
begin
|
32
|
+
t1, output_new, output_orig, output_reader = pipe_exec_stream!($stdout, conditions, {
|
33
|
+
:prefix => info_prefix,
|
34
|
+
:suffix => info_suffix,
|
35
|
+
}, 'output') do |line|
|
36
|
+
block_given? ? yield(line) : true
|
37
|
+
end
|
38
|
+
|
39
|
+
t2, error_new, error_orig, error_reader = pipe_exec_stream!($stderr, conditions, {
|
40
|
+
:prefix => error_prefix,
|
41
|
+
:suffix => error_suffix,
|
42
|
+
}, 'error') do |line|
|
43
|
+
block_given? ? yield(line) : true
|
44
|
+
end
|
45
|
+
|
46
|
+
system_success = system(command)
|
47
|
+
|
48
|
+
ensure
|
49
|
+
output_success = close_exec_pipe(t1, $stdout, output_orig, output_new, 'output')
|
50
|
+
error_success = close_exec_pipe(t2, $stderr, error_orig, error_new, 'error')
|
51
|
+
end
|
52
|
+
ui.info('')
|
53
|
+
|
54
|
+
success = ( system_success && output_success && error_success )
|
55
|
+
|
56
|
+
min -= 1
|
57
|
+
break if success && min <= 0 && conditions.empty?
|
58
|
+
end
|
59
|
+
unless conditions.empty?
|
60
|
+
success = false
|
61
|
+
end
|
62
|
+
|
63
|
+
return success
|
64
|
+
end
|
65
|
+
|
66
|
+
#---
|
67
|
+
|
68
|
+
def self.exec(command, options = {})
|
69
|
+
return exec!(command, options)
|
70
|
+
end
|
71
|
+
|
72
|
+
#---
|
73
|
+
|
74
|
+
def self.pipe_exec_stream!(output, conditions, options, label)
|
75
|
+
original = output.dup
|
76
|
+
read, write = IO.pipe
|
77
|
+
|
78
|
+
match_prefix = ( options[:match_prefix] ? options[:match_prefix] : 'EXIT' )
|
79
|
+
|
80
|
+
thread = process_stream!(read, original, options, label) do |line|
|
81
|
+
check_conditions!(line, conditions, match_prefix) do
|
82
|
+
block_given? ? yield(line) : true
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
thread.abort_on_exception = false
|
87
|
+
|
88
|
+
output.reopen(write)
|
89
|
+
return thread, write, original, read
|
90
|
+
end
|
91
|
+
|
92
|
+
#---
|
93
|
+
|
94
|
+
def self.close_exec_pipe(thread, output, original, write, label)
|
95
|
+
output.reopen(original)
|
96
|
+
|
97
|
+
write.close
|
98
|
+
success = thread.value
|
99
|
+
|
100
|
+
original.close
|
101
|
+
return success
|
102
|
+
end
|
103
|
+
|
104
|
+
#---
|
105
|
+
|
106
|
+
def self.check_conditions!(line, conditions, match_prefix = '')
|
107
|
+
prefix = ''
|
108
|
+
|
109
|
+
unless ! conditions || conditions.empty?
|
110
|
+
conditions.each do |key, event|
|
111
|
+
if event.check(line)
|
112
|
+
prefix = match_prefix
|
113
|
+
conditions.delete(key)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
result = true
|
119
|
+
if block_given?
|
120
|
+
result = yield
|
121
|
+
|
122
|
+
unless prefix.empty?
|
123
|
+
case result
|
124
|
+
when Hash
|
125
|
+
result[:prefix] = prefix
|
126
|
+
else
|
127
|
+
result = { :success => result, :prefix => prefix }
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
return result
|
132
|
+
end
|
133
|
+
|
134
|
+
#---
|
135
|
+
|
136
|
+
def self.process_stream!(input, output, options, label)
|
137
|
+
return Thread.new do
|
138
|
+
success = true
|
139
|
+
default_prefix = ( options[:prefix] ? options[:prefix] : '' )
|
140
|
+
default_suffix = ( options[:suffix] ? options[:suffix] : '' )
|
141
|
+
|
142
|
+
begin
|
143
|
+
while ( data = input.readpartial(1024) )
|
144
|
+
message = data.strip
|
145
|
+
newline = ( data[-1,1].match(/\n/) ? true : false )
|
146
|
+
|
147
|
+
unless message.empty?
|
148
|
+
lines = message.split(/\n/)
|
149
|
+
lines.each_with_index do |line, index|
|
150
|
+
prefix = default_prefix
|
151
|
+
suffix = default_suffix
|
152
|
+
|
153
|
+
unless line.empty?
|
154
|
+
if block_given?
|
155
|
+
result = yield(line)
|
156
|
+
|
157
|
+
if result && result.is_a?(Hash)
|
158
|
+
prefix = result[:prefix]
|
159
|
+
suffix = result[:suffix]
|
160
|
+
result = result[:success]
|
161
|
+
end
|
162
|
+
success = result if success
|
163
|
+
end
|
164
|
+
|
165
|
+
prefix = ( prefix && ! prefix.empty? ? "#{prefix}: " : '' )
|
166
|
+
suffix = ( suffix && ! suffix.empty? ? suffix : '' )
|
167
|
+
eol = ( index < lines.length - 1 || newline ? "\n" : ' ' )
|
168
|
+
|
169
|
+
output.write(prefix.lstrip + line + suffix.rstrip + eol)
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
174
|
+
rescue EOFError
|
175
|
+
end
|
176
|
+
|
177
|
+
input.close()
|
178
|
+
success
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
begin
|
2
|
+
require 'hiera/backend'
|
3
|
+
|
4
|
+
class Hiera
|
5
|
+
module Backend
|
6
|
+
#
|
7
|
+
# NOTE: This function is overridden so we can collect accumulated hiera
|
8
|
+
# parameters and their values on a particular puppet run for reporting
|
9
|
+
# purposes.
|
10
|
+
#
|
11
|
+
# Calls out to all configured backends in the order they
|
12
|
+
# were specified. The first one to answer will win.
|
13
|
+
#
|
14
|
+
# This lets you declare multiple backends, a possible
|
15
|
+
# use case might be in Puppet where a Puppet module declares
|
16
|
+
# default data using in-module data while users can override
|
17
|
+
# using JSON/YAML etc. By layering the backends and putting
|
18
|
+
# the Puppet one last you can override module author data
|
19
|
+
# easily.
|
20
|
+
#
|
21
|
+
# Backend instances are cached so if you need to connect to any
|
22
|
+
# databases then do so in your constructor, future calls to your
|
23
|
+
# backend will not create new instances
|
24
|
+
def lookup(key, default, scope, order_override, resolution_type)
|
25
|
+
@backends ||= {}
|
26
|
+
answer = nil
|
27
|
+
|
28
|
+
Config[:backends].each do |backend|
|
29
|
+
if constants.include?("#{backend.capitalize}_backend") || constants.include?("#{backend.capitalize}_backend".to_sym)
|
30
|
+
@backends[backend] ||= Backend.const_get("#{backend.capitalize}_backend").new
|
31
|
+
new_answer = @backends[backend].lookup(key, scope, order_override, resolution_type)
|
32
|
+
|
33
|
+
if not new_answer.nil?
|
34
|
+
case resolution_type
|
35
|
+
when :array
|
36
|
+
raise Exception, "Hiera type mismatch: expected Array and got #{new_answer.class}" unless new_answer.kind_of? Array or new_answer.kind_of? String
|
37
|
+
answer ||= []
|
38
|
+
answer << new_answer
|
39
|
+
when :hash
|
40
|
+
raise Exception, "Hiera type mismatch: expected Hash and got #{new_answer.class}" unless new_answer.kind_of? Hash
|
41
|
+
answer ||= {}
|
42
|
+
answer = merge_answer(new_answer,answer)
|
43
|
+
else
|
44
|
+
answer = new_answer
|
45
|
+
break
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
answer = resolve_answer(answer, resolution_type) unless answer.nil?
|
52
|
+
answer = parse_string(default, scope) if answer.nil? and default.is_a?(String)
|
53
|
+
|
54
|
+
answer = default if answer.nil?
|
55
|
+
|
56
|
+
Coral::Config.set_property(key, answer) # This is why we override this function!!
|
57
|
+
return answer
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
rescue LoadError
|
63
|
+
end
|
@@ -0,0 +1,489 @@
|
|
1
|
+
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
module Coral
|
5
|
+
|
6
|
+
describe Interface do
|
7
|
+
|
8
|
+
#---------------------------------------------------------------------------
|
9
|
+
# UI functionality
|
10
|
+
|
11
|
+
describe "#say" do
|
12
|
+
|
13
|
+
#-------------------------------------------------------------------------
|
14
|
+
# Delegation
|
15
|
+
|
16
|
+
it "can delegate to another class that contains this method" do
|
17
|
+
output = double('output')
|
18
|
+
output.should_receive(:puts).with('message')
|
19
|
+
|
20
|
+
ui = Interface.new({
|
21
|
+
:output => output,
|
22
|
+
:printer => :puts,
|
23
|
+
})
|
24
|
+
Interface.new({ :ui_delegate => ui }).say(:info, 'message')
|
25
|
+
end
|
26
|
+
|
27
|
+
#-------------------------------------------------------------------------
|
28
|
+
# Output formats
|
29
|
+
|
30
|
+
it "prints a message with default options" do
|
31
|
+
output1 = double('output1')
|
32
|
+
output1.should_receive(:puts).with('message')
|
33
|
+
|
34
|
+
Interface.new({ :output => output1 }).say(:info, 'message')
|
35
|
+
|
36
|
+
output2 = double('output2')
|
37
|
+
output2.should_receive(:puts).with('[component] message')
|
38
|
+
|
39
|
+
Interface.new({
|
40
|
+
:resource => 'component',
|
41
|
+
:output => output2,
|
42
|
+
}).say(:info, 'message')
|
43
|
+
end
|
44
|
+
|
45
|
+
#---
|
46
|
+
|
47
|
+
it "prints a message with and without newlines included" do
|
48
|
+
output1 = double('output1')
|
49
|
+
output1.should_receive(:puts).with('message')
|
50
|
+
|
51
|
+
test = Interface.new({ :output => output1 })
|
52
|
+
test.say(:info, 'message', { :new_line => true })
|
53
|
+
|
54
|
+
output2 = double('output2')
|
55
|
+
output2.should_receive(:print).with('message')
|
56
|
+
|
57
|
+
test = Interface.new({ :output => output2 })
|
58
|
+
test.say(:info, 'message', { :new_line => false })
|
59
|
+
end
|
60
|
+
|
61
|
+
#---
|
62
|
+
|
63
|
+
it "routes message to output and error channels based on type given" do
|
64
|
+
[:info, :warn, :success].each do |type|
|
65
|
+
output = double('output')
|
66
|
+
output.should_receive(:puts).with('message')
|
67
|
+
|
68
|
+
Interface.new({
|
69
|
+
:output => output,
|
70
|
+
:printer => :puts,
|
71
|
+
:color => false,
|
72
|
+
}).say(type, 'message')
|
73
|
+
end
|
74
|
+
|
75
|
+
error = double('error')
|
76
|
+
error.should_receive(:puts).with('message')
|
77
|
+
|
78
|
+
Interface.new({
|
79
|
+
:error => error,
|
80
|
+
:printer => :puts,
|
81
|
+
:color => false,
|
82
|
+
}).say(:error, 'message')
|
83
|
+
end
|
84
|
+
|
85
|
+
#---
|
86
|
+
|
87
|
+
it "routes message to output and error channels based on channel given" do
|
88
|
+
[:info, :warn, :success].each do |type|
|
89
|
+
output = double('output')
|
90
|
+
output.should_receive(:puts).with('message')
|
91
|
+
|
92
|
+
Interface.new({
|
93
|
+
:output => output,
|
94
|
+
:printer => :puts,
|
95
|
+
}).say(:info, 'message', { :channel => type })
|
96
|
+
end
|
97
|
+
|
98
|
+
error = double('error')
|
99
|
+
error.should_receive(:puts).with('message')
|
100
|
+
|
101
|
+
Interface.new({
|
102
|
+
:error => error,
|
103
|
+
:printer => :puts,
|
104
|
+
:color => false,
|
105
|
+
}).say(:info, 'message', { :channel => :error })
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
#---
|
110
|
+
|
111
|
+
describe "#ask" do
|
112
|
+
|
113
|
+
#-------------------------------------------------------------------------
|
114
|
+
# Delegation
|
115
|
+
|
116
|
+
it "can delegate to another class that contains this method"
|
117
|
+
|
118
|
+
#-------------------------------------------------------------------------
|
119
|
+
# Input
|
120
|
+
|
121
|
+
it "displays a prompt and returns user feedback"
|
122
|
+
end
|
123
|
+
|
124
|
+
#---
|
125
|
+
|
126
|
+
describe "#info" do
|
127
|
+
|
128
|
+
#-------------------------------------------------------------------------
|
129
|
+
# Delegation
|
130
|
+
|
131
|
+
it "can delegate to another class that contains this method" do
|
132
|
+
output = double('output')
|
133
|
+
output.should_receive(:puts).with('message')
|
134
|
+
|
135
|
+
ui = Interface.new({
|
136
|
+
:output => output,
|
137
|
+
:printer => :puts,
|
138
|
+
})
|
139
|
+
Interface.new({ :ui_delegate => ui }).info('message')
|
140
|
+
end
|
141
|
+
|
142
|
+
#-------------------------------------------------------------------------
|
143
|
+
# Printing
|
144
|
+
|
145
|
+
it "prints an uncolored information message" do
|
146
|
+
output = double('output')
|
147
|
+
output.should_receive(:puts).with('message')
|
148
|
+
|
149
|
+
Interface.new({
|
150
|
+
:output => output,
|
151
|
+
:printer => :puts,
|
152
|
+
}).info('message')
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
#---
|
157
|
+
|
158
|
+
describe "#warn" do
|
159
|
+
|
160
|
+
#-------------------------------------------------------------------------
|
161
|
+
# Delegation
|
162
|
+
|
163
|
+
it "can delegate to another class that contains this method" do
|
164
|
+
output = double('output')
|
165
|
+
output.should_receive(:puts).with('message')
|
166
|
+
|
167
|
+
ui = Interface.new({
|
168
|
+
:output => output,
|
169
|
+
:printer => :puts,
|
170
|
+
:color => false,
|
171
|
+
})
|
172
|
+
Interface.new({ :ui_delegate => ui }).warn('message')
|
173
|
+
end
|
174
|
+
|
175
|
+
#-------------------------------------------------------------------------
|
176
|
+
# Printing
|
177
|
+
|
178
|
+
it "prints an uncolored warning message" do
|
179
|
+
output = double('output')
|
180
|
+
output.should_receive(:puts).with('message')
|
181
|
+
|
182
|
+
Interface.new({
|
183
|
+
:output => output,
|
184
|
+
:printer => :puts,
|
185
|
+
:color => false,
|
186
|
+
}).warn('message')
|
187
|
+
end
|
188
|
+
|
189
|
+
#---
|
190
|
+
|
191
|
+
it "prints a colored warning message" do
|
192
|
+
output = double('output')
|
193
|
+
output.should_receive(:print).with(/^\e\[33mmessage\e\[0m$/)
|
194
|
+
|
195
|
+
Interface.new({
|
196
|
+
:output => output,
|
197
|
+
:color => true,
|
198
|
+
}).warn('message', { :new_line => false })
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
#---
|
203
|
+
|
204
|
+
describe "#error" do
|
205
|
+
|
206
|
+
#-------------------------------------------------------------------------
|
207
|
+
# Delegation
|
208
|
+
|
209
|
+
it "can delegate to another class that contains this method" do
|
210
|
+
error = double('error')
|
211
|
+
error.should_receive(:puts).with('message')
|
212
|
+
|
213
|
+
ui = Interface.new({
|
214
|
+
:error => error,
|
215
|
+
:printer => :puts,
|
216
|
+
:color => false,
|
217
|
+
})
|
218
|
+
Interface.new({ :ui_delegate => ui }).error('message')
|
219
|
+
end
|
220
|
+
|
221
|
+
#-------------------------------------------------------------------------
|
222
|
+
# Printing
|
223
|
+
|
224
|
+
it "prints an uncolored error message" do
|
225
|
+
error = double('error')
|
226
|
+
error.should_receive(:puts).with('message')
|
227
|
+
|
228
|
+
Interface.new({
|
229
|
+
:error => error,
|
230
|
+
:printer => :puts,
|
231
|
+
:color => false,
|
232
|
+
}).error('message')
|
233
|
+
end
|
234
|
+
|
235
|
+
#---
|
236
|
+
|
237
|
+
it "prints a colored error message" do
|
238
|
+
error = double('error')
|
239
|
+
error.should_receive(:print).with(/^\e\[31mmessage\e\[0m$/)
|
240
|
+
|
241
|
+
Interface.new({
|
242
|
+
:error => error,
|
243
|
+
:color => true,
|
244
|
+
}).error('message', { :new_line => false })
|
245
|
+
end
|
246
|
+
end
|
247
|
+
|
248
|
+
#---
|
249
|
+
|
250
|
+
describe "#success" do
|
251
|
+
|
252
|
+
#-------------------------------------------------------------------------
|
253
|
+
# Delegation
|
254
|
+
|
255
|
+
it "can delegate to another class that contains this method" do
|
256
|
+
output = double('output')
|
257
|
+
output.should_receive(:puts).with('message')
|
258
|
+
|
259
|
+
ui = Interface.new({
|
260
|
+
:output => output,
|
261
|
+
:printer => :puts,
|
262
|
+
:color => false,
|
263
|
+
})
|
264
|
+
Interface.new({ :ui_delegate => ui }).success('message')
|
265
|
+
end
|
266
|
+
|
267
|
+
#-------------------------------------------------------------------------
|
268
|
+
# Printing
|
269
|
+
|
270
|
+
it "prints an uncolored success message" do
|
271
|
+
output = double('output')
|
272
|
+
output.should_receive(:puts).with('message')
|
273
|
+
|
274
|
+
Interface.new({
|
275
|
+
:output => output,
|
276
|
+
:printer => :puts,
|
277
|
+
:color => false,
|
278
|
+
}).success('message')
|
279
|
+
end
|
280
|
+
|
281
|
+
#---
|
282
|
+
|
283
|
+
it "prints a colored success message" do
|
284
|
+
output = double('output')
|
285
|
+
output.should_receive(:print).with(/^\e\[32mmessage\e\[0m$/)
|
286
|
+
|
287
|
+
Interface.new({
|
288
|
+
:output => output,
|
289
|
+
:color => true,
|
290
|
+
}).success('message', { :new_line => false })
|
291
|
+
end
|
292
|
+
end
|
293
|
+
|
294
|
+
#---------------------------------------------------------------------------
|
295
|
+
# Utilities
|
296
|
+
|
297
|
+
describe "#format_message" do
|
298
|
+
|
299
|
+
#-------------------------------------------------------------------------
|
300
|
+
# Delegation
|
301
|
+
|
302
|
+
it "can delegate to another class that contains this method" do
|
303
|
+
message = Interface.new({
|
304
|
+
:ui_delegate => Interface.new('delegate')
|
305
|
+
}).format_message(:info, 'message', { :prefix => true })
|
306
|
+
|
307
|
+
message.should == '[delegate] message'
|
308
|
+
end
|
309
|
+
|
310
|
+
#-------------------------------------------------------------------------
|
311
|
+
# Prefix specifications
|
312
|
+
|
313
|
+
it "returns without a prefix because no resource" do
|
314
|
+
message = Interface.new.format_message(:info, 'message', { :prefix => true })
|
315
|
+
message.should == 'message'
|
316
|
+
end
|
317
|
+
|
318
|
+
#---
|
319
|
+
|
320
|
+
it "returns without a prefix because prefix is false" do
|
321
|
+
message = Interface.new('component').format_message(:info, 'message', { :prefix => false })
|
322
|
+
message.should == 'message'
|
323
|
+
end
|
324
|
+
|
325
|
+
#---
|
326
|
+
|
327
|
+
it "returns without a prefix because no prefix option given" do
|
328
|
+
message = Interface.new('component').format_message(:info, 'message')
|
329
|
+
message.should == 'message'
|
330
|
+
end
|
331
|
+
|
332
|
+
#---
|
333
|
+
|
334
|
+
it "returns with a prefix if resource and prefix option given" do
|
335
|
+
message = Interface.new('component').format_message(:info, 'message', { :prefix => true })
|
336
|
+
message.should == '[component] message'
|
337
|
+
end
|
338
|
+
|
339
|
+
#-------------------------------------------------------------------------
|
340
|
+
# Color specifications
|
341
|
+
|
342
|
+
it "formats a error message in red if color enabled" do
|
343
|
+
message = Interface.new({
|
344
|
+
:resource => 'component',
|
345
|
+
:color => true,
|
346
|
+
}).format_message(:error, 'message')
|
347
|
+
message.should match(/^\e\[31mmessage\e\[0m$/)
|
348
|
+
end
|
349
|
+
|
350
|
+
#---
|
351
|
+
|
352
|
+
it "formats a warning message in yellow if color enabled" do
|
353
|
+
message = Interface.new({
|
354
|
+
:resource => 'component',
|
355
|
+
:color => true,
|
356
|
+
}).format_message(:warn, 'message')
|
357
|
+
message.should match(/^\e\[33mmessage\e\[0m$/)
|
358
|
+
end
|
359
|
+
|
360
|
+
#---
|
361
|
+
|
362
|
+
it "formats a success message in green if color enabled" do
|
363
|
+
message = Interface.new({
|
364
|
+
:resource => 'component',
|
365
|
+
:color => true,
|
366
|
+
}).format_message(:success, 'message')
|
367
|
+
message.should match(/^\e\[32mmessage\e\[0m$/)
|
368
|
+
end
|
369
|
+
end
|
370
|
+
|
371
|
+
#---------------------------------------------------------------------------
|
372
|
+
|
373
|
+
describe "#safe_puts" do
|
374
|
+
|
375
|
+
#-------------------------------------------------------------------------
|
376
|
+
# Delegation
|
377
|
+
|
378
|
+
it "can delegate to another class that contains this method" do
|
379
|
+
output = double('output')
|
380
|
+
output.should_receive(:puts).with('message')
|
381
|
+
|
382
|
+
ui = Interface.new({
|
383
|
+
:output => output,
|
384
|
+
:printer => :puts,
|
385
|
+
})
|
386
|
+
Interface.new({ :ui_delegate => ui }).safe_puts('message')
|
387
|
+
end
|
388
|
+
|
389
|
+
#-------------------------------------------------------------------------
|
390
|
+
# Instance configuration
|
391
|
+
|
392
|
+
it "prints an empty string unless message given" do
|
393
|
+
output = double('output')
|
394
|
+
output.should_receive(:puts).with('')
|
395
|
+
|
396
|
+
Interface.new({
|
397
|
+
:output => output,
|
398
|
+
:printer => :puts,
|
399
|
+
}).safe_puts()
|
400
|
+
end
|
401
|
+
|
402
|
+
#---
|
403
|
+
|
404
|
+
it "prints to different output channels if they are given" do
|
405
|
+
output1 = double('output1')
|
406
|
+
output1.should_receive(:puts).with('message')
|
407
|
+
|
408
|
+
test = Interface.new({
|
409
|
+
:output => output1,
|
410
|
+
:printer => :puts,
|
411
|
+
})
|
412
|
+
test.safe_puts('message')
|
413
|
+
|
414
|
+
output2 = double('output2')
|
415
|
+
output2.should_receive(:puts).with('message')
|
416
|
+
|
417
|
+
test.output = output2
|
418
|
+
test.safe_puts('message')
|
419
|
+
end
|
420
|
+
|
421
|
+
#---
|
422
|
+
|
423
|
+
it "prints with puts if puts printer option given" do
|
424
|
+
output = double('output')
|
425
|
+
output.should_receive(:puts).with('message')
|
426
|
+
|
427
|
+
Interface.new({
|
428
|
+
:output => output,
|
429
|
+
:printer => :puts,
|
430
|
+
}).safe_puts('message')
|
431
|
+
end
|
432
|
+
|
433
|
+
#---
|
434
|
+
|
435
|
+
it "prints with print if print printer option given" do
|
436
|
+
output = double('output')
|
437
|
+
output.should_receive(:print).with('message')
|
438
|
+
|
439
|
+
Interface.new({
|
440
|
+
:output => output,
|
441
|
+
:printer => :print,
|
442
|
+
}).safe_puts('message')
|
443
|
+
end
|
444
|
+
|
445
|
+
#-------------------------------------------------------------------------
|
446
|
+
# Method configuration
|
447
|
+
|
448
|
+
it "can override the instance output channel" do
|
449
|
+
output1 = double('output1')
|
450
|
+
output1.should_not_receive(:puts).with('message')
|
451
|
+
|
452
|
+
output2 = double('output2')
|
453
|
+
output2.should_receive(:puts).with('message')
|
454
|
+
|
455
|
+
Interface.new({
|
456
|
+
:output => output1,
|
457
|
+
:printer => :puts,
|
458
|
+
}).safe_puts('message', { :channel => output2 })
|
459
|
+
end
|
460
|
+
|
461
|
+
#---
|
462
|
+
|
463
|
+
it "can override the instance printer handler" do
|
464
|
+
output = double('output')
|
465
|
+
output.should_not_receive(:puts).with('message')
|
466
|
+
output.should_receive(:print).with('message')
|
467
|
+
|
468
|
+
Interface.new({
|
469
|
+
:output => output,
|
470
|
+
:printer => :puts,
|
471
|
+
}).safe_puts('message', { :printer => :print })
|
472
|
+
end
|
473
|
+
end
|
474
|
+
|
475
|
+
#---------------------------------------------------------------------------
|
476
|
+
|
477
|
+
describe "#check_delegate" do
|
478
|
+
|
479
|
+
it "returns false if no delegate exists" do
|
480
|
+
Interface.new.check_delegate('safe_puts').should be_false
|
481
|
+
end
|
482
|
+
it "returns true if a delegate exists and it implements given method" do
|
483
|
+
test = Interface.new({ :ui_delegate => Interface.new })
|
484
|
+
test.check_delegate('safe_puts').should be_true
|
485
|
+
test.check_delegate('nonexistent').should be_false
|
486
|
+
end
|
487
|
+
end
|
488
|
+
end
|
489
|
+
end
|