samovar 1.10.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -18,90 +18,16 @@
18
18
  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
19
  # THE SOFTWARE.
20
20
 
21
- require_relative 'flags'
21
+ require_relative 'option'
22
22
 
23
23
  module Samovar
24
- class Option
25
- def initialize(flags, description, key: nil, default: nil, value: nil, type: nil, &block)
26
- @flags = Flags.new(flags)
27
- @description = description
28
-
29
- if key
30
- @key = key
31
- else
32
- @key = @flags.first.key
33
- end
34
-
35
- @default = default
36
-
37
- # If the value is given, it overrides the user specified input.
38
- @value = value
39
- @value ||= true if @flags.boolean?
40
-
41
- @type = type
42
- @block = block
43
- end
44
-
45
- attr :flags
46
- attr :description
47
- attr :type
48
-
49
- attr :default
50
-
51
- attr :key
52
-
53
- def coerce_type(result)
54
- if @type == Integer
55
- Integer(result)
56
- elsif @type == Float
57
- Float(result)
58
- elsif @type == Symbol
59
- result.to_sym
60
- elsif @type.respond_to? :call
61
- @type.call(result)
62
- elsif @type.respond_to? :new
63
- @type.new(result)
64
- end
65
- end
66
-
67
- def coerce(result)
68
- if @type
69
- result = coerce_type(result)
70
- end
71
-
72
- if @block
73
- result = @block.call(result)
74
- end
75
-
76
- return result
77
- end
78
-
79
- def parse(input, default = @default)
80
- if result = @flags.parse(input)
81
- @value.nil? ? coerce(result) : @value
82
- end || default
83
- end
84
-
85
- def to_s
86
- @flags
87
- end
88
-
89
- def to_a
90
- unless @default.nil?
91
- [@flags, @description, "Default: #{@default}"]
92
- else
93
- [@flags, @description]
94
- end
95
- end
96
- end
97
-
98
24
  class Options
99
25
  def self.parse(*args, **options, &block)
100
26
  options = self.new(*args, **options)
101
27
 
102
28
  options.instance_eval(&block) if block_given?
103
29
 
104
- return options
30
+ return options.freeze
105
31
  end
106
32
 
107
33
  def initialize(title = "Options", key: :options)
@@ -116,13 +42,50 @@ module Samovar
116
42
  @defaults = {}
117
43
  end
118
44
 
45
+ def initialize_dup(source)
46
+ super
47
+
48
+ @ordered = @ordered.dup
49
+ @keyed = @keyed.dup
50
+ @defaults = @defaults.dup
51
+ end
52
+
53
+ attr :title
54
+ attr :ordered
55
+
119
56
  attr :key
120
57
  attr :defaults
121
58
 
59
+ def freeze
60
+ return self if frozen?
61
+
62
+ @ordered.freeze
63
+ @keyed.freeze
64
+ @defaults.freeze
65
+
66
+ @ordered.each(&:freeze)
67
+
68
+ super
69
+ end
70
+
71
+ def each(&block)
72
+ @ordered.each(&block)
73
+ end
74
+
75
+ def empty?
76
+ @ordered.empty?
77
+ end
78
+
122
79
  def option(*args, **options, &block)
123
80
  self << Option.new(*args, **options, &block)
124
81
  end
125
82
 
83
+ def merge!(options)
84
+ options.each do |option|
85
+ self << option
86
+ end
87
+ end
88
+
126
89
  def << option
127
90
  @ordered << option
128
91
  option.flags.each do |flag|
@@ -138,7 +101,7 @@ module Samovar
138
101
  end
139
102
  end
140
103
 
141
- def parse(input, default)
104
+ def parse(input, parent = nil, default = nil)
142
105
  values = (default || @defaults).dup
143
106
 
144
107
  while option = @keyed[input.first]
@@ -18,154 +18,4 @@
18
18
  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
19
  # THE SOFTWARE.
20
20
 
21
- require 'mapping/model'
22
-
23
- require 'event/terminal'
24
-
25
- module Samovar
26
- module Output
27
- class Header
28
- def initialize(name, object)
29
- @name = name
30
- @object = object
31
- end
32
-
33
- attr :name
34
- attr :object
35
-
36
- def align(columns)
37
- @object.command_line(@name)
38
- end
39
- end
40
-
41
- class Row < Array
42
- def initialize(object)
43
- @object = object
44
- super object.to_a.collect(&:to_s)
45
- end
46
-
47
- attr :object
48
-
49
- def align(columns)
50
- self.collect.with_index do |value, index|
51
- value.ljust(columns.widths[index])
52
- end.join(' ')
53
- end
54
- end
55
-
56
- class Columns
57
- def initialize(rows)
58
- @rows = rows
59
- @widths = calculate_widths(rows)
60
- end
61
-
62
- attr :widths
63
-
64
- def calculate_widths(rows)
65
- widths = []
66
-
67
- rows.each do |row|
68
- row.each.with_index do |column, index|
69
- (widths[index] ||= []) << column.size
70
- end
71
- end
72
-
73
- return widths.collect(&:max)
74
- end
75
- end
76
-
77
- class Rows
78
- include Enumerable
79
-
80
- def initialize(level = 0)
81
- @level = level
82
- @rows = []
83
- end
84
-
85
- attr :level
86
-
87
- def empty?
88
- @rows.empty?
89
- end
90
-
91
- def first
92
- @rows.first
93
- end
94
-
95
- def last
96
- @rows.last
97
- end
98
-
99
- def indentation
100
- @indentation ||= "\t" * @level
101
- end
102
-
103
- def each(ignore_nested: false, &block)
104
- return to_enum(:each, ignore_nested: ignore_nested) unless block_given?
105
-
106
- @rows.each do |row|
107
- if row.is_a?(self.class)
108
- row.each(&block) unless ignore_nested
109
- else
110
- yield row, self
111
- end
112
- end
113
- end
114
-
115
- def << object
116
- @rows << Row.new(object)
117
-
118
- return self
119
- end
120
-
121
- def columns
122
- @columns ||= Columns.new(@rows.select{|row| row.is_a? Array})
123
- end
124
-
125
- def nested(*args)
126
- @rows << Header.new(*args)
127
-
128
- nested_rows = self.class.new(@level + 1)
129
-
130
- yield nested_rows
131
-
132
- @rows << nested_rows
133
- end
134
- end
135
-
136
- class DetailedFormatter < Mapping::Model
137
- def self.print(rows, output)
138
- self.new(rows, output).print
139
- end
140
-
141
- def initialize(rows, output)
142
- @rows = rows
143
- @output = output
144
- @width = 80
145
-
146
- @terminal = Event::Terminal.for(@output)
147
- @terminal[:header] = @terminal.style(:blue, nil, :bright)
148
- @terminal[:description] = @terminal.style(:blue)
149
- end
150
-
151
- map(Header) do |header, rows|
152
- @terminal.puts unless header == @rows.first
153
- @terminal.puts "#{rows.indentation}#{header.object.command_line(header.name)}", style: :header
154
- @terminal.puts "#{rows.indentation}\t#{header.object.description}", style: :description
155
- @terminal.puts
156
- end
157
-
158
- map(Row) do |row, rows|
159
- @terminal.puts "#{rows.indentation}#{row.align(rows.columns)}"
160
- end
161
-
162
- map(Rows) do |items|
163
- items.collect{|row, rows| map(row, rows)}
164
- end
165
-
166
- def print
167
- map(@rows)
168
- end
169
- end
170
- end
171
- end
21
+ require_relative 'output/usage_formatter'
@@ -18,22 +18,27 @@
18
18
  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
19
  # THE SOFTWARE.
20
20
 
21
- require 'time'
22
-
23
- require_relative 'terminal'
24
-
25
21
  module Samovar
26
- class Command
27
- def track_time
28
- start_time = Time.now
22
+ module Output
23
+ class Columns
24
+ def initialize(rows)
25
+ @rows = rows
26
+ @widths = calculate_widths(rows)
27
+ end
29
28
 
30
- yield
31
- ensure
32
- end_time = Time.now
33
- elapsed_time = end_time - start_time
29
+ attr :widths
34
30
 
35
- $stdout.flush
36
- terminal.puts("Elapsed Time: %0.3fs" % elapsed_time, style: :summary)
31
+ def calculate_widths(rows)
32
+ widths = []
33
+
34
+ rows.each do |row|
35
+ row.each.with_index do |column, index|
36
+ (widths[index] ||= []) << column.size
37
+ end
38
+ end
39
+
40
+ return widths.collect(&:max)
41
+ end
37
42
  end
38
43
  end
39
44
  end
@@ -18,14 +18,19 @@
18
18
  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
19
  # THE SOFTWARE.
20
20
 
21
- require 'time'
22
-
23
21
  module Samovar
24
- class Command
25
- def terminal(output = $stderr)
26
- Event::Terminal.for(output).tap do |terminal|
27
- terminal[:command] = terminal.style(:blue)
28
- terminal[:summary] = terminal.style(:magenta)
22
+ module Output
23
+ class Header
24
+ def initialize(name, object)
25
+ @name = name
26
+ @object = object
27
+ end
28
+
29
+ attr :name
30
+ attr :object
31
+
32
+ def align(columns)
33
+ @object.command_line(@name)
29
34
  end
30
35
  end
31
36
  end
@@ -0,0 +1,38 @@
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 Samovar
22
+ module Output
23
+ class Row < Array
24
+ def initialize(object)
25
+ @object = object
26
+ super object.to_a.collect(&:to_s)
27
+ end
28
+
29
+ attr :object
30
+
31
+ def align(columns)
32
+ self.collect.with_index do |value, index|
33
+ value.ljust(columns.widths[index])
34
+ end.join(' ')
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,86 @@
1
+ # Copyright, 2016, 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 'header'
22
+ require_relative 'columns'
23
+ require_relative 'row'
24
+
25
+ module Samovar
26
+ module Output
27
+ class Rows
28
+ include Enumerable
29
+
30
+ def initialize(level = 0)
31
+ @level = level
32
+ @rows = []
33
+ end
34
+
35
+ attr :level
36
+
37
+ def empty?
38
+ @rows.empty?
39
+ end
40
+
41
+ def first
42
+ @rows.first
43
+ end
44
+
45
+ def last
46
+ @rows.last
47
+ end
48
+
49
+ def indentation
50
+ @indentation ||= "\t" * @level
51
+ end
52
+
53
+ def each(ignore_nested: false, &block)
54
+ return to_enum(:each, ignore_nested: ignore_nested) unless block_given?
55
+
56
+ @rows.each do |row|
57
+ if row.is_a?(self.class)
58
+ row.each(&block) unless ignore_nested
59
+ else
60
+ yield row, self
61
+ end
62
+ end
63
+ end
64
+
65
+ def << object
66
+ @rows << Row.new(object)
67
+
68
+ return self
69
+ end
70
+
71
+ def columns
72
+ @columns ||= Columns.new(@rows.select{|row| row.is_a? Array})
73
+ end
74
+
75
+ def nested(*args)
76
+ @rows << Header.new(*args)
77
+
78
+ nested_rows = self.class.new(@level + 1)
79
+
80
+ yield nested_rows
81
+
82
+ @rows << nested_rows
83
+ end
84
+ end
85
+ end
86
+ end