toys-core 0.3.6 → 0.3.7

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.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +13 -0
  3. data/lib/toys-core.rb +20 -5
  4. data/lib/toys/cli.rb +39 -32
  5. data/lib/toys/core_version.rb +1 -1
  6. data/lib/toys/{tool → definition}/acceptor.rb +21 -15
  7. data/lib/toys/{utils/line_output.rb → definition/alias.rb} +47 -59
  8. data/lib/toys/{tool/arg_definition.rb → definition/arg.rb} +17 -7
  9. data/lib/toys/{tool/flag_definition.rb → definition/flag.rb} +19 -9
  10. data/lib/toys/definition/tool.rb +574 -0
  11. data/lib/toys/dsl/arg.rb +118 -0
  12. data/lib/toys/dsl/flag.rb +132 -0
  13. data/lib/toys/dsl/tool.rb +521 -0
  14. data/lib/toys/errors.rb +2 -2
  15. data/lib/toys/helpers.rb +3 -3
  16. data/lib/toys/helpers/exec.rb +31 -25
  17. data/lib/toys/helpers/fileutils.rb +8 -2
  18. data/lib/toys/helpers/highline.rb +8 -1
  19. data/lib/toys/{alias.rb → helpers/terminal.rb} +44 -53
  20. data/lib/toys/input_file.rb +61 -0
  21. data/lib/toys/loader.rb +87 -77
  22. data/lib/toys/middleware.rb +3 -3
  23. data/lib/toys/middleware/add_verbosity_flags.rb +22 -20
  24. data/lib/toys/middleware/base.rb +53 -5
  25. data/lib/toys/middleware/handle_usage_errors.rb +9 -12
  26. data/lib/toys/middleware/set_default_descriptions.rb +6 -7
  27. data/lib/toys/middleware/show_help.rb +71 -67
  28. data/lib/toys/middleware/show_root_version.rb +9 -9
  29. data/lib/toys/runner.rb +157 -0
  30. data/lib/toys/template.rb +4 -3
  31. data/lib/toys/templates.rb +2 -2
  32. data/lib/toys/templates/clean.rb +2 -2
  33. data/lib/toys/templates/gem_build.rb +5 -5
  34. data/lib/toys/templates/minitest.rb +2 -2
  35. data/lib/toys/templates/rubocop.rb +2 -2
  36. data/lib/toys/templates/yardoc.rb +2 -2
  37. data/lib/toys/tool.rb +168 -625
  38. data/lib/toys/utils/exec.rb +19 -18
  39. data/lib/toys/utils/gems.rb +140 -0
  40. data/lib/toys/utils/help_text.rb +25 -20
  41. data/lib/toys/utils/terminal.rb +412 -0
  42. data/lib/toys/utils/wrappable_string.rb +3 -1
  43. metadata +15 -24
  44. data/lib/toys/config_dsl.rb +0 -699
  45. data/lib/toys/context.rb +0 -290
  46. data/lib/toys/helpers/spinner.rb +0 -142
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1552f14b276734b92f59f9c1d4464679ec1facdc6480e8ecb01b7818d7541712
4
- data.tar.gz: d8da75bf066fa32de202edc57151a37c20b08a29537e7fbb25e9683d705fe625
3
+ metadata.gz: 3f7ff775c645d4bbd1906fab469307dcf06852e83d9fa02aba978fd0db53af21
4
+ data.tar.gz: 408ffcc9b47eff78b05228d811e2a32932a56eebe8e64381a5a96ce1c0e22caf
5
5
  SHA512:
6
- metadata.gz: b3816d90527525a282e55b534a2c250fd7667b7c4a9c4922dbd9a67c9bea72223eb6e16f2d1a0d035213ce86be013bdce2a073c56b8f35c4e223262a494faaaa
7
- data.tar.gz: d73196fce65e1c0cc5904dd93e529bd798cfd10a19a1ac4ac9c138b30c62d516f5e76380502e38306ad91105526fd699dbf41fa20643c2b8bd852dfa1914ce06
6
+ metadata.gz: 4969720705d06c492e7083dbd5d139b71ef3f3e260980acca8ec33771b4ee06b90e8138c341984681ff53a747fcdb256fffcbe412d30d64c9a0b32a82b0975ac
7
+ data.tar.gz: 4db5eed3cc44658511b14d017a3afac43daafc397e3094c1955ae08a95b60886673cfa2196b269a06b9c534f4614300573bf33cc2b43a39981c2bd4500c19cd6
data/CHANGELOG.md CHANGED
@@ -1,5 +1,18 @@
1
1
  # Release History
2
2
 
3
+ ### 0.3.7 / 2018-05-30
4
+
5
+ * CHANGED: Execution runs in the same scope as the DSL, which lets us use normal methods instead of helper-blocks.
6
+ * CHANGED: Renamed "script" to "run", and allow setting of runnable by defining a "run" method
7
+ * CHANGED: Set up a constant scope for each config file, to make constant lookup make sense.
8
+ * CHANGED: Removed run_toys and dropped EXIT_ON_NONZERO_STATUS key in favor of using cli directly.
9
+ * CHANGED: Renamed definition_path to source_path
10
+ * CHANGED: LineOutput util changed to a simple Terminal util, and folded spinner into it.
11
+ * CHANGED: Removed spinner helper and added terminal helper.
12
+ * CHANGED: Organized DSL and definition classes
13
+ * ADDED: Helper modules scoped to the tool hierarchy
14
+ * ADDED: Utility that installs and activates third-party gems.
15
+
3
16
  ### 0.3.6 / 2018-05-21
4
17
 
5
18
  * CHANGED: Renamed show_version middleware to show_root_version.
data/lib/toys-core.rb CHANGED
@@ -27,8 +27,6 @@
27
27
  # POSSIBILITY OF SUCH DAMAGE.
28
28
  ;
29
29
 
30
- gem "highline", "~> 1.7"
31
-
32
30
  ##
33
31
  # Toys is a Ruby library and command line tool that lets you build your own
34
32
  # command line suite of tools (with commands and subcommands) using a Ruby DSL.
@@ -40,17 +38,34 @@ module Toys
40
38
  # Namespace for common utility classes.
41
39
  #
42
40
  module Utils; end
41
+
42
+ ##
43
+ # Namespace for object definition classes.
44
+ #
45
+ module Definition; end
46
+
47
+ ##
48
+ # Namespace for DSL classes.
49
+ #
50
+ module DSL; end
43
51
  end
44
52
 
45
- require "toys/alias"
46
53
  require "toys/cli"
47
- require "toys/config_dsl"
48
- require "toys/context"
49
54
  require "toys/core_version"
55
+ require "toys/definition/acceptor"
56
+ require "toys/definition/alias"
57
+ require "toys/definition/arg"
58
+ require "toys/definition/flag"
59
+ require "toys/definition/tool"
60
+ require "toys/dsl/arg"
61
+ require "toys/dsl/flag"
62
+ require "toys/dsl/tool"
50
63
  require "toys/errors"
51
64
  require "toys/helpers"
65
+ require "toys/input_file"
52
66
  require "toys/loader"
53
67
  require "toys/middleware"
68
+ require "toys/runner"
54
69
  require "toys/template"
55
70
  require "toys/templates"
56
71
  require "toys/tool"
data/lib/toys/cli.rb CHANGED
@@ -28,9 +28,8 @@
28
28
  ;
29
29
 
30
30
  require "logger"
31
- require "highline"
32
31
 
33
- require "toys/utils/line_output"
32
+ require "toys/utils/terminal"
34
33
 
35
34
  module Toys
36
35
  ##
@@ -99,7 +98,7 @@ module Toys
99
98
  @loader = Loader.new(
100
99
  index_file_name: index_file_name,
101
100
  preload_file_name: preload_file_name,
102
- middleware_stack: middleware_stack
101
+ middleware_stack: @middleware_stack
103
102
  )
104
103
  @error_handler = error_handler || DefaultErrorHandler.new
105
104
  end
@@ -209,10 +208,15 @@ module Toys
209
208
  # @return [Integer] The resulting status code
210
209
  #
211
210
  def run(*args, verbosity: 0)
212
- tool, remaining = ContextualError.capture("Error finding tool definition") do
211
+ tool_definition, remaining = ContextualError.capture("Error finding tool definition") do
213
212
  @loader.lookup(args.flatten)
214
213
  end
215
- tool.execute(self, remaining, verbosity: verbosity)
214
+ ContextualError.capture_path(
215
+ "Error during tool execution!", tool_definition.source_path,
216
+ tool_name: tool_definition.full_name, tool_args: remaining
217
+ ) do
218
+ Runner.new(self, tool_definition).run(remaining, verbosity: verbosity)
219
+ end
216
220
  rescue ContextualError => e
217
221
  @error_handler.call(e)
218
222
  end
@@ -247,16 +251,20 @@ module Toys
247
251
  ##
248
252
  # Create an error handler.
249
253
  #
250
- # @param [IO,Logger,nil] sink Where to write errors. Default is `$stderr`.
254
+ # @param [IO] output Where to write errors. Default is `$stderr`.
251
255
  #
252
- def initialize(sink = $stderr)
253
- @line_output = Utils::LineOutput.new(sink, log_level: ::Logger::FATAL)
256
+ def initialize(output = $stderr)
257
+ @terminal = Utils::Terminal.new(output: output)
254
258
  end
255
259
 
256
- ## @private
260
+ ##
261
+ # The error handler routine. Prints out the error message and backtrace.
262
+ #
263
+ # @param [Exception] error The error that occurred.
264
+ #
257
265
  def call(error)
258
- @line_output.puts(cause_string(error.cause))
259
- @line_output.puts(context_string(error), :bold)
266
+ @terminal.puts(cause_string(error.cause))
267
+ @terminal.puts(context_string(error), :bold)
260
268
  -1
261
269
  end
262
270
 
@@ -315,13 +323,14 @@ module Toys
315
323
  end
316
324
 
317
325
  ##
318
- # Returns a default logger that logs to `STDERR`.
326
+ # Returns a default logger that logs to `$stderr`.
319
327
  #
320
328
  # @param [IO] stream Stream to write to. Defaults to `$stderr`.
321
329
  # @return [Logger]
322
330
  #
323
331
  def default_logger(stream = $stderr)
324
332
  logger = ::Logger.new(stream)
333
+ terminal = Utils::Terminal.new(output: stream)
325
334
  logger.formatter = proc do |severity, time, _progname, msg|
326
335
  msg_str =
327
336
  case msg
@@ -332,7 +341,7 @@ module Toys
332
341
  else
333
342
  msg.inspect
334
343
  end
335
- format_log(stream.tty?, time, severity, msg_str)
344
+ format_log(terminal, time, severity, msg_str)
336
345
  end
337
346
  logger.level = ::Logger::WARN
338
347
  logger
@@ -340,27 +349,25 @@ module Toys
340
349
 
341
350
  private
342
351
 
343
- def format_log(is_tty, time, severity, msg)
352
+ def format_log(terminal, time, severity, msg)
344
353
  timestr = time.strftime("%Y-%m-%d %H:%M:%S")
345
354
  header = format("[%s %5s]", timestr, severity)
346
- if is_tty
347
- header =
348
- case severity
349
- when "FATAL"
350
- ::HighLine.color(header, :bright_magenta, :bold, :underline)
351
- when "ERROR"
352
- ::HighLine.color(header, :bright_red, :bold)
353
- when "WARN"
354
- ::HighLine.color(header, :bright_yellow)
355
- when "INFO"
356
- ::HighLine.color(header, :bright_cyan)
357
- when "DEBUG"
358
- ::HighLine.color(header, :white)
359
- else
360
- header
361
- end
362
- end
363
- "#{header} #{msg}\n"
355
+ styled_header =
356
+ case severity
357
+ when "FATAL"
358
+ terminal.apply_styles(header, :bright_magenta, :bold, :underline)
359
+ when "ERROR"
360
+ terminal.apply_styles(header, :bright_red, :bold)
361
+ when "WARN"
362
+ terminal.apply_styles(header, :bright_yellow)
363
+ when "INFO"
364
+ terminal.apply_styles(header, :bright_cyan)
365
+ when "DEBUG"
366
+ terminal.apply_styles(header, :white)
367
+ else
368
+ header
369
+ end
370
+ "#{styled_header} #{msg}\n"
364
371
  end
365
372
  end
366
373
  end
@@ -32,5 +32,5 @@ module Toys
32
32
  # Current version of Toys core
33
33
  # @return [String]
34
34
  #
35
- CORE_VERSION = "0.3.6".freeze
35
+ CORE_VERSION = "0.3.7".freeze
36
36
  end
@@ -28,7 +28,7 @@
28
28
  ;
29
29
 
30
30
  module Toys
31
- class Tool
31
+ module Definition
32
32
  ##
33
33
  # An Acceptor validates and converts arguments. It is designed to be
34
34
  # compatible with the OptionParser accept mechanism.
@@ -47,16 +47,19 @@ module Toys
47
47
  ##
48
48
  # Create a base acceptor.
49
49
  #
50
- # The basic acceptor does not do any validation (i.e. it accepts all
51
- # arguments). You may subclass this object and implement the {#match}
50
+ # The base acceptor does not do any validation (i.e. it accepts all
51
+ # arguments). You may subclass this object and override the {#match}
52
52
  # method to change this behavior.
53
53
  #
54
- # The converter should take one or more arguments, the first of which is
55
- # the entire argument string, and the others of which may be returned
56
- # from validation. The converter should return the final converted value
57
- # of the argument. If you do not provide a converter, this acceptor will
58
- # set the final value to the input argument string by default.
59
- # You may provide a converter either as a proc or a block.
54
+ # The base acceptor lets you provide a converter as a proc. The proc
55
+ # should take one or more arguments, the first of which is the entire
56
+ # argument string, and the others of which are any additional values
57
+ # returned from validation. The converter should return the final
58
+ # converted value of the argument.
59
+ #
60
+ # The converter may be provided either as a proc in the `converter`
61
+ # parameter, or as a block. If neither is provided, the base acceptor
62
+ # performs no conversion and uses the argument string.
60
63
  #
61
64
  # @param [String] name A visible name for the acceptor, shown in help.
62
65
  # @param [Proc] converter A converter function. May also be given as a
@@ -105,7 +108,8 @@ module Toys
105
108
  end
106
109
 
107
110
  ##
108
- # Convert the given input.
111
+ # Convert the given input. Uses the converter provided to this object's
112
+ # constructor. Subclasses may also override this method.
109
113
  #
110
114
  # @param [String] str Original argument string
111
115
  # @param [Object...] extra Zero or more additional arguments comprising
@@ -123,10 +127,11 @@ module Toys
123
127
  #
124
128
  class PatternAcceptor < Acceptor
125
129
  ##
126
- # Create an acceptor.
130
+ # Create a pattern acceptor.
127
131
  #
128
132
  # You must provide a regular expression as a validator. You may also
129
- # provide a converter.
133
+ # provide a converter proc. See {Toys::Definition::Acceptor} for details
134
+ # on the converter.
130
135
  #
131
136
  # @param [String] name A visible name for the acceptor, shown in help.
132
137
  # @param [Regexp] regex Regular expression defining value values.
@@ -140,7 +145,7 @@ module Toys
140
145
  end
141
146
 
142
147
  ##
143
- # Overrides match to match from the given regex.
148
+ # Overrides {Toys::Definition::Acceptor#match} to use the given regex.
144
149
  #
145
150
  def match(str)
146
151
  @regex.match(str)
@@ -173,14 +178,15 @@ module Toys
173
178
  end
174
179
 
175
180
  ##
176
- # Overrides match to find the value.
181
+ # Overrides {Toys::Definition::Acceptor#match} to find the value.
177
182
  #
178
183
  def match(str)
179
184
  @values.find { |s, _e| s == str }
180
185
  end
181
186
 
182
187
  ##
183
- # Overrides convert to return the original element.
188
+ # Overrides {Toys::Definition::Acceptor#convert} to return the original
189
+ # element.
184
190
  #
185
191
  def convert(_str, elem)
186
192
  elem
@@ -27,95 +27,83 @@
27
27
  # POSSIBILITY OF SUCH DAMAGE.
28
28
  ;
29
29
 
30
- require "highline"
31
-
32
30
  module Toys
33
- module Utils
31
+ module Definition
34
32
  ##
35
- # Something that outputs lines to the console or log.
33
+ # An alias is a name that refers to another name.
36
34
  #
37
- class LineOutput
35
+ class Alias
38
36
  ##
39
- # Create a line output.
37
+ # Create a new alias.
40
38
  #
41
- # @param [IO,Logger,nil] sink Where to write lines.
39
+ # @param [Array<String>] full_name The name of the alias.
40
+ # @param [String,Array<String>] target The name of the target. May either
41
+ # be a local reference (a single string) or a global reference (an
42
+ # array of strings)
42
43
  #
43
- def initialize(sink, log_level: ::Logger::INFO, styled: nil)
44
- @sink = sink
45
- @log_level = sink.is_a?(::Logger) ? log_level : nil
46
- @styled =
47
- if styled.nil?
48
- sink.respond_to?(:tty?) && sink.tty?
44
+ def initialize(loader, full_name, target, priority)
45
+ @target_name =
46
+ if target.is_a?(::String)
47
+ full_name[0..-2] + [target]
49
48
  else
50
- styled ? true : false
49
+ target.dup
51
50
  end
52
- @buffer = ""
51
+ @target_name.freeze
52
+ @full_name = full_name.dup.freeze
53
+ @priority = priority
54
+ @tool_class = DSL::Tool.new_class(@full_name, priority, loader)
53
55
  end
54
56
 
55
57
  ##
56
- # Where to write lines
57
- # @return [IO,Logger,nil]
58
+ # Return the tool class.
59
+ # @return [Class]
58
60
  #
59
- attr_reader :sink
61
+ attr_reader :tool_class
60
62
 
61
63
  ##
62
- # Whether output is styled
63
- # @return [Boolean]
64
+ # Return the name of the tool as an array of strings.
65
+ # This array may not be modified.
66
+ # @return [Array<String>]
64
67
  #
65
- attr_accessor :styled
68
+ attr_reader :full_name
66
69
 
67
70
  ##
68
- # If the sink is a Logger, the level to log, otherwise `nil`.
69
- # @return [Integer,nil]
71
+ # Return the priority of this alias.
72
+ # @return [Integer]
70
73
  #
71
- attr_reader :log_level
74
+ attr_reader :priority
72
75
 
73
76
  ##
74
- # Write a line.
75
- #
76
- # @param [String] str The line to write
77
- # @param [Symbol...] styles Styles to apply to the entire line.
77
+ # Return the name of the target as an array of strings.
78
+ # This array may not be modified.
79
+ # @return [Array<String>]
78
80
  #
79
- def puts(str = "", *styles)
80
- str = @buffer + apply_styles(str, styles)
81
- @buffer = ""
82
- case sink
83
- when ::Logger
84
- sink.log(log_level, str)
85
- when ::IO
86
- sink.puts(str)
87
- sink.flush
88
- end
89
- self
90
- end
81
+ attr_reader :target_name
91
82
 
92
83
  ##
93
- # Write a newline and flush the current line.
84
+ # Returns the local name of this tool.
85
+ # @return [String]
94
86
  #
95
- def newline
96
- puts
87
+ def simple_name
88
+ full_name.last
97
89
  end
98
90
 
99
91
  ##
100
- # Buffer a partial line but do not write it out yet because the line
101
- # may not yet be complete.
102
- #
103
- # @param [String] str The line to write
104
- # @param [Symbol...] styles Styles to apply to the partial line.
92
+ # Returns a displayable name of this tool, generally the full name
93
+ # delimited by spaces.
94
+ # @return [String]
105
95
  #
106
- def write(str = "", *styles)
107
- @buffer << apply_styles(str, styles)
108
- self
96
+ def display_name
97
+ full_name.join(" ")
109
98
  end
110
99
 
111
- private
112
-
113
- def apply_styles(str, styles)
114
- if styled
115
- styles.empty? ? str : ::HighLine.color(str, *styles)
116
- else
117
- ::HighLine.uncolor(str)
118
- end
100
+ ##
101
+ # Returns a displayable name of the target, generally the full name
102
+ # delimited by spaces.
103
+ # @return [String]
104
+ #
105
+ def display_target
106
+ target_name.join(" ")
119
107
  end
120
108
  end
121
109
  end