console 0.5 → 1.0.0

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,119 @@
1
+ # Copyright, 2017, by Samuel G. D. Williams. <http://www.codeotaku.com>
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ # of this software and associated documentation files (the "Software"), to deal
5
+ # in the Software without restriction, including without limitation the rights
6
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ # copies of the Software, and to permit persons to whom the Software is
8
+ # furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in
11
+ # all copies or substantial portions of the Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ # THE SOFTWARE.
20
+
21
+ require_relative 'buffer'
22
+
23
+ module Console
24
+ UNKNOWN = 'unknown'
25
+
26
+ class Filter
27
+ def self.[] **levels
28
+ klass = Class.new(self)
29
+
30
+ klass.instance_exec do
31
+ const_set(:LEVELS, levels)
32
+ const_set(:MAXIMUM_LEVEL, levels.values.max)
33
+
34
+ levels.each do |name, level|
35
+ const_set(name.to_s.upcase, level)
36
+
37
+ define_method(name) do |subject = nil, *arguments, &block|
38
+ enabled = @subjects[subject.class]
39
+
40
+ if enabled == true or (enabled != false and level >= @level)
41
+ self.call(subject, *arguments, severity: name, **@options, &block)
42
+ end
43
+ end
44
+
45
+ define_method("#{name}!") do
46
+ @level = level
47
+ end
48
+
49
+ define_method("#{name}?") do
50
+ @level >= level
51
+ end
52
+ end
53
+ end
54
+
55
+ return klass
56
+ end
57
+
58
+ def initialize(output, verbose: true, level: 0, **options)
59
+ @level = level
60
+ @verbose = verbose
61
+
62
+ @subjects = {}
63
+
64
+ @output = output
65
+ @options = options
66
+ end
67
+
68
+ def dup(**options)
69
+ super().tap do |logger|
70
+ logger.options = @options.merge(options)
71
+ end
72
+ end
73
+
74
+ attr :level
75
+ attr :verbose
76
+
77
+ attr :subjects
78
+
79
+ attr_accessor :output
80
+ attr_accessor :options
81
+
82
+ def level= level
83
+ if level.is_a? Symbol
84
+ @level = self.class::LEVELS[level]
85
+ else
86
+ @level = level
87
+ end
88
+ end
89
+
90
+ def verbose!(value = true)
91
+ @verbose = value
92
+ @output.verbose!(value)
93
+ end
94
+
95
+ def off!
96
+ @level = -1
97
+ end
98
+
99
+ def all!
100
+ @level = self.class::MAXIMUM_LEVEL
101
+ end
102
+
103
+ def enabled?(subject)
104
+ @subjects[subject.class] == true
105
+ end
106
+
107
+ def enable(subject)
108
+ @subjects[subject.class] = true
109
+ end
110
+
111
+ def disable(subject)
112
+ @subjects[subject.class] = false
113
+ end
114
+
115
+ def call(*arguments, &block)
116
+ @output.call(*arguments, &block)
117
+ end
118
+ end
119
+ end
@@ -0,0 +1,26 @@
1
+ # Copyright, 2019, by Samuel G. D. Williams. <http://www.codeotaku.com>
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ # of this software and associated documentation files (the "Software"), to deal
5
+ # in the Software without restriction, including without limitation the rights
6
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ # copies of the Software, and to permit persons to whom the Software is
8
+ # furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in
11
+ # all copies or substantial portions of the Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ # THE SOFTWARE.
20
+
21
+ module Console
22
+ class Generic
23
+ def format(buffer, terminal)
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,31 @@
1
+ # Copyright, 2017, by Samuel G. D. Williams. <http://www.codeotaku.com>
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ # of this software and associated documentation files (the "Software"), to deal
5
+ # in the Software without restriction, including without limitation the rights
6
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ # copies of the Software, and to permit persons to whom the Software is
8
+ # furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in
11
+ # all copies or substantial portions of the Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ # THE SOFTWARE.
20
+
21
+ require_relative 'filter'
22
+
23
+ module Console
24
+ class Logger < Filter[debug: 0, info: 1, warn: 2, error: 3, fatal: 4]
25
+ def initialize(output, **options)
26
+ super(output, **options)
27
+
28
+ self.info!
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,71 @@
1
+ # Copyright, 2017, by Samuel G. D. Williams. <http://www.codeotaku.com>
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ # of this software and associated documentation files (the "Software"), to deal
5
+ # in the Software without restriction, including without limitation the rights
6
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ # copies of the Software, and to permit persons to whom the Software is
8
+ # furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in
11
+ # all copies or substantial portions of the Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ # THE SOFTWARE.
20
+
21
+ require_relative '../buffer'
22
+ require_relative '../filter'
23
+
24
+ require 'time'
25
+ require 'json'
26
+
27
+ module Console
28
+ module Serialized
29
+ class Logger
30
+ def initialize(io = $stderr, format: JSON)
31
+ @io = io
32
+ @start = Time.now
33
+ @format = format
34
+ end
35
+
36
+ attr :io
37
+ attr :start
38
+ attr :format
39
+
40
+ def verbose!(value = true)
41
+ end
42
+
43
+ def call(subject = nil, *arguments, severity: UNKNOWN, &block)
44
+ message = {
45
+ time: Time.now.iso8601,
46
+ severity: severity,
47
+ }
48
+
49
+ if subject
50
+ message[:subject] = subject
51
+ end
52
+
53
+ if arguments.any?
54
+ message[:arguments] = arguments
55
+ end
56
+
57
+ if block_given?
58
+ if block.arity.zero?
59
+ message[:message] = yield
60
+ else
61
+ buffer = StringIO.new
62
+ yield buffer
63
+ message[:message] = buffer.string
64
+ end
65
+ end
66
+
67
+ @io.puts(@format.dump(message))
68
+ end
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,65 @@
1
+ # Copyright, 2017, by Samuel G. D. Williams. <http://www.codeotaku.com>
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ # of this software and associated documentation files (the "Software"), to deal
5
+ # in the Software without restriction, including without limitation the rights
6
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ # copies of the Software, and to permit persons to whom the Software is
8
+ # furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in
11
+ # all copies or substantial portions of the Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ # THE SOFTWARE.
20
+
21
+ require_relative 'generic'
22
+
23
+ module Console
24
+ class Shell < Generic
25
+ def self.for(*arguments, **options)
26
+ if arguments.first.is_a?(Hash)
27
+ self.new(*arguments, **options)
28
+ else
29
+ self.new(nil, arguments, **options)
30
+ end
31
+ end
32
+
33
+ def initialize(environment, *arguments, **options)
34
+ @environment = environment
35
+ @arguments = arguments
36
+ @options = options
37
+ end
38
+
39
+ attr :environment
40
+ attr :arguments
41
+ attr :options
42
+
43
+ def chdir_string(options)
44
+ if options and chdir = options[:chdir]
45
+ " in #{chdir}"
46
+ end
47
+ end
48
+
49
+ def self.register(terminal)
50
+ terminal[:shell_command] ||= terminal.style(:blue, nil, :bold)
51
+ end
52
+
53
+ def format(output, terminal, verbose)
54
+ arguments = @arguments.flatten.collect(&:to_s)
55
+
56
+ output.puts " #{terminal[:shell_command]}#{arguments.join(' ')}#{terminal.reset}#{chdir_string(options)}"
57
+
58
+ if verbose and @environment
59
+ @environment.each do |key, value|
60
+ output.puts " export #{key}=#{value}"
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,42 @@
1
+
2
+ # Copyright, 2017, by Samuel G. D. Williams. <http://www.codeotaku.com>
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ # of this software and associated documentation files (the "Software"), to deal
6
+ # in the Software without restriction, including without limitation the rights
7
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ # copies of the Software, and to permit persons to whom the Software is
9
+ # furnished to do so, subject to the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be included in
12
+ # all copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20
+ # THE SOFTWARE.
21
+
22
+ module Console
23
+ class Split
24
+ def self.[] *outputs
25
+ self.new(outputs)
26
+ end
27
+
28
+ def initialize(outputs)
29
+ @outputs = outputs
30
+ end
31
+
32
+ def verbose!(value = true)
33
+ @outputs.each{|output| output.verbose!(value)}
34
+ end
35
+
36
+ def call(level, subject = nil, *arguments, **options, &block)
37
+ @outputs.each do |output|
38
+ output.call(level, subject, *arguments, **options, &block)
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,21 @@
1
+ # Copyright, 2019, by Samuel G. D. Williams. <http://www.codeotaku.com>
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ # of this software and associated documentation files (the "Software"), to deal
5
+ # in the Software without restriction, including without limitation the rights
6
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ # copies of the Software, and to permit persons to whom the Software is
8
+ # furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in
11
+ # all copies or substantial portions of the Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ # THE SOFTWARE.
20
+
21
+ require_relative 'terminal/logger'
@@ -0,0 +1,150 @@
1
+ # Copyright, 2017, by Samuel G. D. Williams. <http://www.codeotaku.com>
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ # of this software and associated documentation files (the "Software"), to deal
5
+ # in the Software without restriction, including without limitation the rights
6
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ # copies of the Software, and to permit persons to whom the Software is
8
+ # furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in
11
+ # all copies or substantial portions of the Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ # THE SOFTWARE.
20
+
21
+ require_relative '../buffer'
22
+
23
+ require_relative '../shell'
24
+ require_relative '../error'
25
+
26
+ require_relative 'text'
27
+ require_relative 'xterm'
28
+
29
+ module Console
30
+ module Terminal
31
+ def self.for(io)
32
+ if io.isatty
33
+ XTerm.new(io)
34
+ else
35
+ Text.new(io)
36
+ end
37
+ end
38
+
39
+ class Logger
40
+ def initialize(io = $stderr, verbose: false, **options)
41
+ @io = io
42
+ @verbose = verbose
43
+ @start = Time.now
44
+
45
+ @terminal = Terminal.for(io)
46
+ @terminal[:logger_prefix] ||= @terminal.style(nil, nil, :bold)
47
+ @terminal[:logger_suffix] ||= @terminal.style(:white, nil, :faint)
48
+ @terminal[:debug] = @terminal.style(:cyan)
49
+ @terminal[:info] = @terminal.style(:green)
50
+ @terminal[:warn] = @terminal.style(:yellow)
51
+ @terminal[:error] = @terminal.style(:red)
52
+ @terminal[:fatal] = @terminal[:error]
53
+
54
+ self.register_defaults(@terminal)
55
+ end
56
+
57
+ attr :io
58
+ attr_accessor :verbose
59
+ attr :start
60
+ attr :terminal
61
+
62
+ def verbose!(value = true)
63
+ @verbose = value
64
+ end
65
+
66
+ def register_defaults(terminal)
67
+ Shell.register(terminal)
68
+ Error.register(terminal)
69
+ end
70
+
71
+ UNKNOWN = 'unknown'
72
+
73
+ def call(subject = nil, *arguments, name: nil, severity: UNKNOWN, &block)
74
+ prefix = build_prefix(name || severity.to_s)
75
+ indent = " " * prefix.size
76
+
77
+ buffer = Buffer.new("#{indent}| ")
78
+
79
+ if subject
80
+ format_subject(severity, prefix, subject, buffer)
81
+ end
82
+
83
+ arguments.each do |argument|
84
+ format_argument(argument, buffer)
85
+ end
86
+
87
+ if block_given?
88
+ if block.arity.zero?
89
+ format_argument(yield, buffer)
90
+ else
91
+ yield(buffer, @terminal)
92
+ end
93
+ end
94
+
95
+ @io.write buffer.string
96
+ end
97
+
98
+ protected
99
+
100
+ def format_argument(argument, output)
101
+ case argument
102
+ when Exception
103
+ Error.new(argument).format(output, @terminal, @verbose)
104
+ when Generic
105
+ argument.format(output, @terminal, @verbose)
106
+ else
107
+ format_value(argument, output)
108
+ end
109
+ end
110
+
111
+ def format_subject(severity, prefix, subject, output)
112
+ prefix_style = @terminal[severity]
113
+
114
+ if @verbose
115
+ suffix = " #{@terminal[:logger_suffix]}[pid=#{Process.pid}]#{@terminal.reset}"
116
+ end
117
+
118
+ output.puts "#{@terminal[:logger_prefix]}#{subject}#{@terminal.reset}#{suffix}", prefix: "#{prefix_style}#{prefix}:#{@terminal.reset} "
119
+ end
120
+
121
+ def format_value(value, output)
122
+ string = value.to_s
123
+
124
+ string.each_line do |line|
125
+ output.puts "#{line}"
126
+ end
127
+ end
128
+
129
+ def time_offset_prefix
130
+ offset = Time.now - @start
131
+ minutes = (offset/60).floor
132
+ seconds = (offset - (minutes*60))
133
+
134
+ if minutes > 0
135
+ "#{minutes}m#{seconds.floor}s"
136
+ else
137
+ "#{seconds.round(2)}s"
138
+ end.rjust(6)
139
+ end
140
+
141
+ def build_prefix(name)
142
+ if @verbose
143
+ "#{time_offset_prefix} #{name.rjust(8)}"
144
+ else
145
+ time_offset_prefix
146
+ end
147
+ end
148
+ end
149
+ end
150
+ end