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