coral_core 0.2.23 → 0.2.24

Sign up to get free protection for your applications and to get access to all the features.
@@ -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,12 @@
1
+
2
+ module Git
3
+ class Remote
4
+
5
+ #-----------------------------------------------------------------------------
6
+ # Remote endpoints
7
+
8
+ def set_url(url, opts = {})
9
+ @base.lib.remote_set_url(@name, url, opts)
10
+ end
11
+ end
12
+ 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