lino 3.2.0.pre.5 → 3.2.0.pre.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +93 -58
  3. data/lib/lino/builders/command_line.rb +59 -0
  4. data/lib/lino/builders/mixins/appliables.rb +27 -0
  5. data/lib/lino/builders/mixins/arguments.rb +38 -0
  6. data/lib/lino/builders/mixins/defaulting.rb +19 -0
  7. data/lib/lino/builders/mixins/environment_variables.rb +46 -0
  8. data/lib/lino/builders/mixins/executor.rb +24 -0
  9. data/lib/lino/builders/mixins/option_config.rb +50 -0
  10. data/lib/lino/builders/mixins/options.rb +118 -0
  11. data/lib/lino/builders/mixins/state_boundary.rb +22 -0
  12. data/lib/lino/builders/mixins/subcommands.rb +52 -0
  13. data/lib/lino/builders/mixins/validation.rb +21 -0
  14. data/lib/lino/builders/mixins/working_directory.rb +24 -0
  15. data/lib/lino/builders/subcommand.rb +47 -0
  16. data/lib/lino/builders.rb +9 -0
  17. data/lib/lino/errors/execution_error.rb +18 -0
  18. data/lib/lino/errors.rb +8 -0
  19. data/lib/lino/executors/childprocess.rb +63 -0
  20. data/lib/lino/executors/open4.rb +42 -0
  21. data/lib/lino/executors.rb +9 -0
  22. data/lib/lino/model/argument.rb +41 -0
  23. data/lib/lino/model/command_line.rb +117 -0
  24. data/lib/lino/model/environment_variable.rb +63 -0
  25. data/lib/lino/model/flag.rb +53 -0
  26. data/lib/lino/model/option.rb +73 -0
  27. data/lib/lino/model/subcommand.rb +52 -0
  28. data/lib/lino/model.rb +13 -0
  29. data/lib/lino/version.rb +1 -1
  30. data/lib/lino.rb +11 -2
  31. metadata +72 -10
  32. data/lib/lino/appliables.rb +0 -23
  33. data/lib/lino/command_line.rb +0 -28
  34. data/lib/lino/command_line_builder.rb +0 -225
  35. data/lib/lino/options.rb +0 -72
  36. data/lib/lino/subcommand_builder.rb +0 -49
  37. data/lib/lino/utilities.rb +0 -59
data/lib/lino/model.rb ADDED
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'model/command_line'
4
+ require_relative 'model/subcommand'
5
+ require_relative 'model/option'
6
+ require_relative 'model/flag'
7
+ require_relative 'model/argument'
8
+ require_relative 'model/environment_variable'
9
+
10
+ module Lino
11
+ module Model
12
+ end
13
+ end
data/lib/lino/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Lino
4
- VERSION = '3.2.0.pre.5'
4
+ VERSION = '3.2.0.pre.6'
5
5
  end
data/lib/lino.rb CHANGED
@@ -1,8 +1,17 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'lino/version'
4
- require 'lino/command_line'
5
- require 'lino/command_line_builder'
4
+ require 'lino/model'
5
+ require 'lino/builders'
6
+ require 'lino/executors'
7
+ require 'lino/errors'
6
8
 
7
9
  module Lino
10
+ class CommandLineBuilder
11
+ class << self
12
+ def for_command(command)
13
+ Lino::Builders::CommandLine.new(command:)
14
+ end
15
+ end
16
+ end
8
17
  end
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lino
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.2.0.pre.5
4
+ version: 3.2.0.pre.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - InfraBlocks Maintainers
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-11-06 00:00:00.000000000 Z
11
+ date: 2024-07-07 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: childprocess
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 5.0.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 5.0.0
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: hamster
15
29
  requirement: !ruby/object:Gem::Requirement
@@ -66,6 +80,34 @@ dependencies:
66
80
  - - ">="
67
81
  - !ruby/object:Gem::Version
68
82
  version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: guard
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: guard-rspec
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
69
111
  - !ruby/object:Gem::Dependency
70
112
  name: rake
71
113
  requirement: !ruby/object:Gem::Requirement
@@ -250,12 +292,32 @@ files:
250
292
  - bin/console
251
293
  - bin/setup
252
294
  - lib/lino.rb
253
- - lib/lino/appliables.rb
254
- - lib/lino/command_line.rb
255
- - lib/lino/command_line_builder.rb
256
- - lib/lino/options.rb
257
- - lib/lino/subcommand_builder.rb
258
- - lib/lino/utilities.rb
295
+ - lib/lino/builders.rb
296
+ - lib/lino/builders/command_line.rb
297
+ - lib/lino/builders/mixins/appliables.rb
298
+ - lib/lino/builders/mixins/arguments.rb
299
+ - lib/lino/builders/mixins/defaulting.rb
300
+ - lib/lino/builders/mixins/environment_variables.rb
301
+ - lib/lino/builders/mixins/executor.rb
302
+ - lib/lino/builders/mixins/option_config.rb
303
+ - lib/lino/builders/mixins/options.rb
304
+ - lib/lino/builders/mixins/state_boundary.rb
305
+ - lib/lino/builders/mixins/subcommands.rb
306
+ - lib/lino/builders/mixins/validation.rb
307
+ - lib/lino/builders/mixins/working_directory.rb
308
+ - lib/lino/builders/subcommand.rb
309
+ - lib/lino/errors.rb
310
+ - lib/lino/errors/execution_error.rb
311
+ - lib/lino/executors.rb
312
+ - lib/lino/executors/childprocess.rb
313
+ - lib/lino/executors/open4.rb
314
+ - lib/lino/model.rb
315
+ - lib/lino/model/argument.rb
316
+ - lib/lino/model/command_line.rb
317
+ - lib/lino/model/environment_variable.rb
318
+ - lib/lino/model/flag.rb
319
+ - lib/lino/model/option.rb
320
+ - lib/lino/model/subcommand.rb
259
321
  - lib/lino/version.rb
260
322
  homepage: https://github.com/infrablocks/lino
261
323
  licenses:
@@ -270,14 +332,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
270
332
  requirements:
271
333
  - - ">="
272
334
  - !ruby/object:Gem::Version
273
- version: '2.7'
335
+ version: '3.1'
274
336
  required_rubygems_version: !ruby/object:Gem::Requirement
275
337
  requirements:
276
338
  - - ">"
277
339
  - !ruby/object:Gem::Version
278
340
  version: 1.3.1
279
341
  requirements: []
280
- rubygems_version: 3.1.6
342
+ rubygems_version: 3.3.7
281
343
  signing_key:
282
344
  specification_version: 4
283
345
  summary: Command line execution utilities
@@ -1,23 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative 'utilities'
4
-
5
- module Lino
6
- module Appliables
7
- include Lino::Utilities
8
-
9
- def with_appliable(appliable)
10
- return self if nil?(appliable)
11
-
12
- appliable.apply(self)
13
- end
14
-
15
- def with_appliables(appliables)
16
- return self if nil_or_empty?(appliables)
17
-
18
- appliables.inject(self) do |s, appliable|
19
- s.with_appliable(appliable)
20
- end
21
- end
22
- end
23
- end
@@ -1,28 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'open4'
4
-
5
- module Lino
6
- class CommandLine
7
- def initialize(command_line)
8
- @command_line = command_line
9
- end
10
-
11
- def execute(
12
- stdin: '',
13
- stdout: $stdout,
14
- stderr: $stderr
15
- )
16
- Open4.spawn(
17
- @command_line,
18
- stdin: stdin,
19
- stdout: stdout,
20
- stderr: stderr
21
- )
22
- end
23
-
24
- def to_s
25
- @command_line
26
- end
27
- end
28
- end
@@ -1,225 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'hamster'
4
- require_relative 'utilities'
5
- require_relative 'command_line'
6
- require_relative 'subcommand_builder'
7
- require_relative 'options'
8
- require_relative 'appliables'
9
-
10
- module Lino
11
- # rubocop:disable Metrics/ClassLength
12
- class CommandLineBuilder
13
- include Lino::Utilities
14
- include Lino::Options
15
- include Lino::Appliables
16
-
17
- class << self
18
- def for_command(command)
19
- CommandLineBuilder.new(command: command)
20
- end
21
- end
22
-
23
- # rubocop:disable Metrics/ParameterLists
24
- def initialize(
25
- command: nil,
26
- subcommands: [],
27
- options: [],
28
- arguments: [],
29
- environment_variables: [],
30
- option_separator: ' ',
31
- option_quoting: nil,
32
- option_placement: :after_command
33
- )
34
- @command = command
35
- @subcommands = Hamster::Vector.new(subcommands)
36
- @options = Hamster::Vector.new(options)
37
- @arguments = Hamster::Vector.new(arguments)
38
- @environment_variables = Hamster::Vector.new(environment_variables)
39
- @option_separator = option_separator
40
- @option_quoting = option_quoting
41
- @option_placement = option_placement
42
- end
43
-
44
- # rubocop:enable Metrics/ParameterLists
45
-
46
- def with_subcommand(subcommand, &block)
47
- return self if nil?(subcommand)
48
-
49
- with(
50
- subcommands: @subcommands.add(
51
- (block || ->(sub) { sub }).call(
52
- SubcommandBuilder.for_subcommand(subcommand)
53
- )
54
- )
55
- )
56
- end
57
-
58
- def with_subcommands(subcommands, &block)
59
- return self if nil_or_empty?(subcommands)
60
-
61
- without_block = subcommands[0...-1]
62
- with_block = subcommands.last
63
-
64
- without_block
65
- .inject(self) { |s, sc| s.with_subcommand(sc) }
66
- .with_subcommand(with_block, &block)
67
- end
68
-
69
- def with_option_separator(option_separator)
70
- with(option_separator: option_separator)
71
- end
72
-
73
- def with_option_quoting(character)
74
- with(option_quoting: character)
75
- end
76
-
77
- def with_option_placement(option_placement)
78
- with(option_placement: option_placement)
79
- end
80
-
81
- def with_options_after_command
82
- with_option_placement(:after_command)
83
- end
84
-
85
- def with_options_after_subcommands
86
- with_option_placement(:after_subcommands)
87
- end
88
-
89
- def with_options_after_arguments
90
- with_option_placement(:after_arguments)
91
- end
92
-
93
- def with_argument(argument)
94
- return self if nil?(argument)
95
-
96
- with(arguments: @arguments.add({ components: [argument] }))
97
- end
98
-
99
- def with_arguments(arguments)
100
- return self if nil_or_empty?(arguments)
101
-
102
- arguments.inject(self) { |s, argument| s.with_argument(argument) }
103
- end
104
-
105
- def with_environment_variable(environment_variable, value)
106
- with(
107
- environment_variables:
108
- @environment_variables.add(
109
- [
110
- environment_variable, value
111
- ]
112
- )
113
- )
114
- end
115
-
116
- def with_environment_variables(environment_variables)
117
- return self if nil_or_empty?(environment_variables)
118
-
119
- environment_variables.entries.inject(self) do |s, var|
120
- s.with_environment_variable(
121
- var.include?(:name) ? var[:name] : var[0],
122
- var.include?(:value) ? var[:value] : var[1]
123
- )
124
- end
125
- end
126
-
127
- def build
128
- components = formatted_components
129
- command_line =
130
- component_paths
131
- .collect { |path| path.inject(components) { |c, p| c && c[p] } }
132
- .reject(&:empty?)
133
- .join(' ')
134
-
135
- CommandLine.new(command_line)
136
- end
137
-
138
- private
139
-
140
- def component_paths
141
- [
142
- %i[environment_variables],
143
- %i[command],
144
- %i[options after_command],
145
- %i[subcommands],
146
- %i[options after_subcommands],
147
- %i[arguments],
148
- %i[options after_arguments]
149
- ]
150
- end
151
-
152
- def formatted_components
153
- {
154
- environment_variables: formatted_environment_variables,
155
- command: @command,
156
- options: formatted_options,
157
- subcommands: formatted_subcommands,
158
- arguments: formatted_arguments
159
- }
160
- end
161
-
162
- def formatted_environment_variables
163
- map_and_join(@environment_variables) do |var|
164
- "#{var[0]}=\"#{var[1].to_s.gsub('"', '\\"')}\""
165
- end
166
- end
167
-
168
- def formatted_options_with_placement(placement)
169
- map_and_join(
170
- options_with_placement(placement),
171
- &(quote_with(@option_quoting) >> join_with(@option_separator))
172
- )
173
- end
174
-
175
- def formatted_options
176
- %i[
177
- after_command
178
- after_subcommands
179
- after_arguments
180
- ].inject({}) do |options, placement|
181
- options
182
- .merge({ placement => formatted_options_with_placement(placement) })
183
- end
184
- end
185
-
186
- def formatted_subcommands
187
- map_and_join(@subcommands) do |sub|
188
- sub.build(@option_separator, @option_quoting)
189
- end
190
- end
191
-
192
- def formatted_arguments
193
- map_and_join(
194
- @arguments,
195
- &join_with(' ')
196
- )
197
- end
198
-
199
- def options_with_placement(placement)
200
- @options.select { |o| o[:placement] == placement } +
201
- if @option_placement == placement
202
- @options.select { |o| o[:placement].nil? }
203
- end
204
- end
205
-
206
- def with(**replacements)
207
- CommandLineBuilder.new(**state.merge(replacements))
208
- end
209
-
210
- def state
211
- {
212
- command: @command,
213
- subcommands: @subcommands,
214
- options: @options,
215
- arguments: @arguments,
216
- environment_variables: @environment_variables,
217
- option_separator: @option_separator,
218
- option_quoting: @option_quoting,
219
- option_placement: @option_placement
220
- }
221
- end
222
- end
223
-
224
- # rubocop:enable Metrics/ClassLength
225
- end
data/lib/lino/options.rb DELETED
@@ -1,72 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative 'utilities'
4
-
5
- module Lino
6
- module Options
7
- include Lino::Utilities
8
-
9
- def with_option(
10
- option,
11
- value,
12
- separator: nil,
13
- quoting: nil,
14
- placement: nil
15
- )
16
- return self if nil?(value)
17
-
18
- with(options: @options.add(
19
- {
20
- components: [option, value],
21
- separator: separator,
22
- quoting: quoting,
23
- placement: placement
24
- }
25
- ))
26
- end
27
-
28
- def with_options(options)
29
- return self if nil_or_empty?(options)
30
-
31
- options.entries.inject(self) do |s, entry|
32
- s.with_option(
33
- or_nth(entry, :option, 0),
34
- or_nth(entry, :value, 1),
35
- separator: or_nil(entry, :separator),
36
- quoting: or_nil(entry, :quoting),
37
- placement: or_nil(entry, :placement)
38
- )
39
- end
40
- end
41
-
42
- def with_repeated_option(
43
- option,
44
- values,
45
- separator: nil,
46
- quoting: nil,
47
- placement: nil
48
- )
49
- values.inject(self) do |s, value|
50
- s.with_option(
51
- option,
52
- value,
53
- separator: separator,
54
- quoting: quoting,
55
- placement: placement
56
- )
57
- end
58
- end
59
-
60
- def with_flag(flag)
61
- return self if nil?(flag)
62
-
63
- with(options: @options.add({ components: [flag] }))
64
- end
65
-
66
- def with_flags(flags)
67
- return self if nil_or_empty?(flags)
68
-
69
- flags.inject(self) { |s, flag| s.with_flag(flag) }
70
- end
71
- end
72
- end
@@ -1,49 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'hamster'
4
- require_relative 'utilities'
5
- require_relative 'options'
6
- require_relative 'appliables'
7
-
8
- module Lino
9
- class SubcommandBuilder
10
- include Lino::Utilities
11
- include Lino::Options
12
- include Lino::Appliables
13
-
14
- class << self
15
- def for_subcommand(subcommand)
16
- SubcommandBuilder.new(subcommand: subcommand)
17
- end
18
- end
19
-
20
- def initialize(subcommand: nil, options: [])
21
- @subcommand = subcommand
22
- @options = Hamster::Vector.new(options)
23
- end
24
-
25
- def build(option_separator, option_quoting)
26
- components = [
27
- @subcommand,
28
- map_and_join(
29
- @options,
30
- &(quote_with(option_quoting) >> join_with(option_separator))
31
- )
32
- ]
33
- components.reject(&:empty?).join(' ')
34
- end
35
-
36
- private
37
-
38
- def with(**replacements)
39
- SubcommandBuilder.new(**state.merge(replacements))
40
- end
41
-
42
- def state
43
- {
44
- subcommand: @subcommand,
45
- options: @options
46
- }
47
- end
48
- end
49
- end
@@ -1,59 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Lino
4
- module Utilities
5
- def map_and_join(collection, &block)
6
- collection.map { |item| block.call(item) }.join(' ')
7
- end
8
-
9
- def join_with(global_separator)
10
- lambda do |item|
11
- item[:components].join(item[:separator] || global_separator)
12
- end
13
- end
14
-
15
- def quote_with(global_character)
16
- lambda do |item|
17
- item.merge(
18
- components: resolve_components(item, global_character)
19
- )
20
- end
21
- end
22
-
23
- def nil?(value)
24
- value.nil?
25
- end
26
-
27
- def empty?(value)
28
- value.respond_to?(:empty?) && value.empty?
29
- end
30
-
31
- def nil_or_empty?(value)
32
- nil?(value) || empty?(value)
33
- end
34
-
35
- private
36
-
37
- def resolve_components(item, global_character)
38
- components = item[:components]
39
- switch = components[0]
40
-
41
- if components.count > 1
42
- character = item[:quoting] || global_character
43
- value = components[1]
44
-
45
- [switch, "#{character}#{value}#{character}"]
46
- else
47
- components
48
- end
49
- end
50
-
51
- def or_nil(enumerable, key)
52
- enumerable.include?(key) ? enumerable[key] : nil
53
- end
54
-
55
- def or_nth(enumerable, key, index)
56
- enumerable.include?(key) ? enumerable[key] : enumerable[index]
57
- end
58
- end
59
- end