toys-core 0.11.5 → 0.12.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.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +31 -0
  3. data/README.md +1 -1
  4. data/lib/toys-core.rb +4 -1
  5. data/lib/toys/acceptor.rb +3 -3
  6. data/lib/toys/arg_parser.rb +6 -7
  7. data/lib/toys/cli.rb +44 -14
  8. data/lib/toys/compat.rb +19 -22
  9. data/lib/toys/completion.rb +3 -1
  10. data/lib/toys/context.rb +2 -2
  11. data/lib/toys/core.rb +1 -1
  12. data/lib/toys/dsl/base.rb +85 -0
  13. data/lib/toys/dsl/flag.rb +3 -3
  14. data/lib/toys/dsl/flag_group.rb +7 -7
  15. data/lib/toys/dsl/internal.rb +206 -0
  16. data/lib/toys/dsl/positional_arg.rb +3 -3
  17. data/lib/toys/dsl/tool.rb +174 -216
  18. data/lib/toys/errors.rb +1 -0
  19. data/lib/toys/flag.rb +15 -18
  20. data/lib/toys/flag_group.rb +5 -4
  21. data/lib/toys/input_file.rb +4 -4
  22. data/lib/toys/loader.rb +189 -50
  23. data/lib/toys/middleware.rb +1 -1
  24. data/lib/toys/mixin.rb +2 -2
  25. data/lib/toys/positional_arg.rb +3 -3
  26. data/lib/toys/settings.rb +900 -0
  27. data/lib/toys/source_info.rb +121 -18
  28. data/lib/toys/standard_middleware/apply_config.rb +5 -4
  29. data/lib/toys/standard_middleware/set_default_descriptions.rb +18 -18
  30. data/lib/toys/standard_middleware/show_help.rb +17 -5
  31. data/lib/toys/standard_mixins/exec.rb +12 -14
  32. data/lib/toys/standard_mixins/git_cache.rb +48 -0
  33. data/lib/toys/standard_mixins/xdg.rb +56 -0
  34. data/lib/toys/template.rb +2 -2
  35. data/lib/toys/{tool.rb → tool_definition.rb} +100 -41
  36. data/lib/toys/utils/exec.rb +4 -5
  37. data/lib/toys/utils/gems.rb +8 -7
  38. data/lib/toys/utils/git_cache.rb +184 -0
  39. data/lib/toys/utils/help_text.rb +90 -34
  40. data/lib/toys/utils/terminal.rb +1 -1
  41. data/lib/toys/utils/xdg.rb +293 -0
  42. metadata +14 -7
@@ -14,7 +14,7 @@ module Toys
14
14
  ##
15
15
  # A simple terminal class.
16
16
  #
17
- # ## Styles
17
+ # ### Styles
18
18
  #
19
19
  # This class supports ANSI styled output where supported.
20
20
  #
@@ -0,0 +1,293 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Toys
4
+ module Utils
5
+ ##
6
+ # A class that provides tools for working with the XDG Base Directory
7
+ # Specification.
8
+ #
9
+ # This class provides utility methods that locate base directories and
10
+ # search paths for application state, configuration, caches, and other
11
+ # data, according to the [XDG Base Directory Spec version
12
+ # 0.8](https://specifications.freedesktop.org/basedir-spec/0.8/).
13
+ #
14
+ # Tools can use the `:xdg` mixin for convenient access to this class.
15
+ #
16
+ # ### Example
17
+ #
18
+ # require "toys/utils/xdg"
19
+ #
20
+ # xdg = Toys::Utils::XDG.new
21
+ #
22
+ # # Get config file paths, in order from most to least inportant
23
+ # config_files = xdg.lookup_config("my-config.toml")
24
+ # config_files.each { |path| read_my_config(path) }
25
+ #
26
+ # ### Windows operation
27
+ #
28
+ # The Spec assumes a unix-like environment, and cannot be applied directly
29
+ # to Windows without modification. In general, this class will function on
30
+ # Windows, but with the following caveats:
31
+ #
32
+ # * All file paths must use Windows-style absolute paths, beginning with
33
+ # the drive letter.
34
+ # * Environment variables that can contain multiple paths (`XDG_*_DIRS`)
35
+ # use the Windows path delimiter (`;`) rather than the unix path
36
+ # delimiter (`:`).
37
+ # * Defaults for home directories (`XDG_*_HOME`) will follow unix
38
+ # conventions, using subdirectories under the user's profile directory
39
+ # rather than the Windows known folder paths.
40
+ # * Defaults for search paths (`XDG_*_DIRS`) will be empty and will not
41
+ # use the Windows known folder paths.
42
+ #
43
+ class XDG
44
+ ##
45
+ # Create an instance of XDG.
46
+ #
47
+ # @param env [Hash{String=>String}] the environment variables. Normally,
48
+ # you can omit this argument, as it will default to `::ENV`.
49
+ #
50
+ def initialize(env: ::ENV)
51
+ @env = env
52
+ end
53
+
54
+ ##
55
+ # Returns the absolute path to the current user's home directory.
56
+ #
57
+ # @return [String]
58
+ #
59
+ def home_dir
60
+ @home_dir ||= validate_dir_env("HOME") || ::Dir.home
61
+ end
62
+
63
+ ##
64
+ # Returns the absolute path to the single base directory relative to
65
+ # which user-specific data files should be written.
66
+ # Corresponds to the value of the `$XDG_DATA_HOME` environment variable
67
+ # and its defaults according to the XDG Base Directory Spec.
68
+ #
69
+ # @return [String]
70
+ #
71
+ def data_home
72
+ @data_home ||=
73
+ validate_dir_env("XDG_DATA_HOME") || ::File.join(home_dir, ".local", "share")
74
+ end
75
+
76
+ ##
77
+ # Returns the absolute path to the single base directory relative to
78
+ # which user-specific configuration files should be written.
79
+ # Corresponds to the value of the `$XDG_CONFIG_HOME` environment variable
80
+ # and its defaults according to the XDG Base Directory Spec.
81
+ #
82
+ # @return [String]
83
+ #
84
+ def config_home
85
+ @config_home ||= validate_dir_env("XDG_CONFIG_HOME") || ::File.join(home_dir, ".config")
86
+ end
87
+
88
+ ##
89
+ # Returns the absolute path to the single base directory relative to
90
+ # which user-specific state files should be written.
91
+ # Corresponds to the value of the `$XDG_STATE_HOME` environment variable
92
+ # and its defaults according to the XDG Base Directory Spec.
93
+ #
94
+ # @return [String]
95
+ #
96
+ def state_home
97
+ @state_home ||=
98
+ validate_dir_env("XDG_STATE_HOME") || ::File.join(home_dir, ".local", "state")
99
+ end
100
+
101
+ ##
102
+ # Returns the absolute path to the single base directory relative to
103
+ # which user-specific non-essential (cached) data should be written.
104
+ # Corresponds to the value of the `$XDG_CACHE_HOME` environment variable
105
+ # and its defaults according to the XDG Base Directory Spec.
106
+ #
107
+ # @return [String]
108
+ #
109
+ def cache_home
110
+ @cache_home ||= validate_dir_env("XDG_CACHE_HOME") || ::File.join(home_dir, ".cache")
111
+ end
112
+
113
+ ##
114
+ # Returns the absolute path to the single base directory relative to
115
+ # which user-specific executable files may be written.
116
+ # Returns the value of `$HOME/.local/bin` as specified by the XDG Base
117
+ # Directory Spec.
118
+ #
119
+ # @return [String]
120
+ #
121
+ def executable_home
122
+ @executable_home ||= ::File.join(home_dir, ".local", "bin")
123
+ end
124
+
125
+ ##
126
+ # Returns the set of preference ordered base directories relative to
127
+ # which data files should be searched, as an array of absolute paths.
128
+ # The array is ordered from most to least important, and does _not_
129
+ # include the data home directory.
130
+ # Corresponds to the value of the `$XDG_DATA_DIRS` environment variable
131
+ # and its defaults according to the XDG Base Directory Spec.
132
+ #
133
+ # @return [Array<String>]
134
+ #
135
+ def data_dirs
136
+ @data_dirs ||= validate_dirs_env("XDG_DATA_DIRS") ||
137
+ validate_dirs(["/usr/local/share", "/usr/share"]) || []
138
+ end
139
+
140
+ ##
141
+ # Returns the set of preference ordered base directories relative to
142
+ # which configuration files should be searched, as an array of absolute
143
+ # paths. The array is ordered from most to least important, and does
144
+ # _not_ include the config home directory.
145
+ # Corresponds to the value of the `$XDG_CONFIG_DIRS` environment variable
146
+ # and its defaults according to the XDG Base Directory Spec.
147
+ #
148
+ # @return [Array<String>]
149
+ #
150
+ def config_dirs
151
+ @config_dirs ||= validate_dirs_env("XDG_CONFIG_DIRS") ||
152
+ validate_dirs(["/etc/xdg"]) || []
153
+ end
154
+
155
+ ##
156
+ # Returns the absolute path to the single base directory relative to
157
+ # which user-specific runtime files and other file objects should be
158
+ # placed. May return `nil` if no such directory could be determined.
159
+ #
160
+ # @return [String,nil]
161
+ #
162
+ def runtime_dir
163
+ @runtime_dir = validate_dir_env("XDG_RUNTIME_DIR") unless defined? @runtime_dir
164
+ @runtime_dir
165
+ end
166
+
167
+ ##
168
+ # Searches the data directories for an object with the given relative
169
+ # path, and returns an array of absolute paths to all objects found in
170
+ # the data directories (i.e. in {#data_dirs} or {#data_home}), in order
171
+ # from most to least important.
172
+ #
173
+ # @param path [String] Relative path of the object to search for
174
+ # @param type [String,Symbol,Array<String,Symbol>] The type(s) of objects
175
+ # to find. You can specify any of the types defined by
176
+ # [File::Stat#ftype](https://ruby-doc.org/core/File/Stat.html#method-i-ftype),
177
+ # such as `file` or `directory`, or the special type `any`. Types can
178
+ # be specified as strings or the corresponding symbols. If this
179
+ # argument is not provided, the default of `file` is used.
180
+ # @return [Array<String>]
181
+ #
182
+ def lookup_data(path, type: :file)
183
+ lookup_internal([data_home] + data_dirs, path, type)
184
+ end
185
+
186
+ ##
187
+ # Searches the config directories for an object with the given relative
188
+ # path, and returns an array of absolute paths to all objects found in
189
+ # the config directories (i.e. in {#config_dirs} or {#config_home}), in
190
+ # order from most to least important.
191
+ #
192
+ # @param path [String] Relative path of the object to search for
193
+ # @param type [String,Symbol,Array<String,Symbol>] The type(s) of objects
194
+ # to find. You can specify any of the types defined by
195
+ # [File::Stat#ftype](https://ruby-doc.org/core/File/Stat.html#method-i-ftype),
196
+ # such as `file` or `directory`, or the special type `any`. Types can
197
+ # be specified as strings or the corresponding symbols. If this
198
+ # argument is not provided, the default of `file` is used.
199
+ # @return [Array<String>]
200
+ #
201
+ def lookup_config(path, type: :file)
202
+ lookup_internal([config_home] + config_dirs, path, type)
203
+ end
204
+
205
+ ##
206
+ # Returns the absolute path to a directory under {#data_home}, creating
207
+ # it if it doesn't already exist.
208
+ #
209
+ # @param path [String] The relative path to the subdir within the base
210
+ # data directory.
211
+ # @return [String] The absolute path to the subdir.
212
+ # @raise [Errno::EEXIST] If a non-directory already exists there
213
+ #
214
+ def ensure_data_subdir(path)
215
+ ensure_subdir_internal(data_home, path)
216
+ end
217
+
218
+ ##
219
+ # Returns the absolute path to a directory under {#config_home}, creating
220
+ # it if it doesn't already exist.
221
+ #
222
+ # @param path [String] The relative path to the subdir within the base
223
+ # config directory.
224
+ # @return [String] The absolute path to the subdir.
225
+ # @raise [Errno::EEXIST] If a non-directory already exists there
226
+ #
227
+ def ensure_config_subdir(path)
228
+ ensure_subdir_internal(config_home, path)
229
+ end
230
+
231
+ ##
232
+ # Returns the absolute path to a directory under {#state_home}, creating
233
+ # it if it doesn't already exist.
234
+ #
235
+ # @param path [String] The relative path to the subdir within the base
236
+ # state directory.
237
+ # @return [String] The absolute path to the subdir.
238
+ # @raise [Errno::EEXIST] If a non-directory already exists there
239
+ #
240
+ def ensure_state_subdir(path)
241
+ ensure_subdir_internal(state_home, path)
242
+ end
243
+
244
+ ##
245
+ # Returns the absolute path to a directory under {#cache_home}, creating
246
+ # it if it doesn't already exist.
247
+ #
248
+ # @param path [String] The relative path to the subdir within the base
249
+ # cache directory.
250
+ # @return [String] The absolute path to the subdir.
251
+ # @raise [Errno::EEXIST] If a non-directory already exists there
252
+ #
253
+ def ensure_cache_subdir(path)
254
+ ensure_subdir_internal(cache_home, path)
255
+ end
256
+
257
+ private
258
+
259
+ def validate_dir_env(name)
260
+ path = @env[name].to_s
261
+ !path.empty? && Compat.absolute_path?(path) ? path : nil
262
+ end
263
+
264
+ def validate_dirs_env(name)
265
+ validate_dirs(@env[name].to_s.split(::File::PATH_SEPARATOR))
266
+ end
267
+
268
+ def validate_dirs(paths)
269
+ paths = paths.find_all { |path| Compat.absolute_path?(path) }
270
+ paths.empty? ? nil : paths
271
+ end
272
+
273
+ def lookup_internal(dirs, path, types)
274
+ results = []
275
+ types = Array(types).map(&:to_s)
276
+ dirs.each do |dir|
277
+ to_check = ::File.join(dir, path)
278
+ stat = ::File.stat(to_check) rescue nil # rubocop:disable Style/RescueModifier
279
+ if stat&.readable? && (types.include?("any") || types.include?(stat.ftype))
280
+ results << to_check
281
+ end
282
+ end
283
+ results
284
+ end
285
+
286
+ def ensure_subdir_internal(base_dir, path)
287
+ path = ::File.join(base_dir, path)
288
+ ::FileUtils.mkdir_p(path, mode: 0o700)
289
+ path
290
+ end
291
+ end
292
+ end
293
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: toys-core
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.11.5
4
+ version: 0.12.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Daniel Azuma
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-03-28 00:00:00.000000000 Z
11
+ date: 2021-08-05 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Toys-Core is the command line tool framework underlying Toys. It can
14
14
  be used to create command line executables using the Toys DSL and classes.
@@ -31,8 +31,10 @@ files:
31
31
  - lib/toys/completion.rb
32
32
  - lib/toys/context.rb
33
33
  - lib/toys/core.rb
34
+ - lib/toys/dsl/base.rb
34
35
  - lib/toys/dsl/flag.rb
35
36
  - lib/toys/dsl/flag_group.rb
37
+ - lib/toys/dsl/internal.rb
36
38
  - lib/toys/dsl/positional_arg.rb
37
39
  - lib/toys/dsl/tool.rb
38
40
  - lib/toys/errors.rb
@@ -44,6 +46,7 @@ files:
44
46
  - lib/toys/mixin.rb
45
47
  - lib/toys/module_lookup.rb
46
48
  - lib/toys/positional_arg.rb
49
+ - lib/toys/settings.rb
47
50
  - lib/toys/source_info.rb
48
51
  - lib/toys/standard_middleware/add_verbosity_flags.rb
49
52
  - lib/toys/standard_middleware/apply_config.rb
@@ -55,24 +58,28 @@ files:
55
58
  - lib/toys/standard_mixins/exec.rb
56
59
  - lib/toys/standard_mixins/fileutils.rb
57
60
  - lib/toys/standard_mixins/gems.rb
61
+ - lib/toys/standard_mixins/git_cache.rb
58
62
  - lib/toys/standard_mixins/highline.rb
59
63
  - lib/toys/standard_mixins/terminal.rb
64
+ - lib/toys/standard_mixins/xdg.rb
60
65
  - lib/toys/template.rb
61
- - lib/toys/tool.rb
66
+ - lib/toys/tool_definition.rb
62
67
  - lib/toys/utils/completion_engine.rb
63
68
  - lib/toys/utils/exec.rb
64
69
  - lib/toys/utils/gems.rb
70
+ - lib/toys/utils/git_cache.rb
65
71
  - lib/toys/utils/help_text.rb
66
72
  - lib/toys/utils/terminal.rb
73
+ - lib/toys/utils/xdg.rb
67
74
  - lib/toys/wrappable_string.rb
68
75
  homepage: https://github.com/dazuma/toys
69
76
  licenses:
70
77
  - MIT
71
78
  metadata:
72
- changelog_uri: https://dazuma.github.io/toys/gems/toys-core/v0.11.5/file.CHANGELOG.html
79
+ changelog_uri: https://dazuma.github.io/toys/gems/toys-core/v0.12.0/file.CHANGELOG.html
73
80
  source_code_uri: https://github.com/dazuma/toys/tree/main/toys-core
74
81
  bug_tracker_uri: https://github.com/dazuma/toys/issues
75
- documentation_uri: https://dazuma.github.io/toys/gems/toys-core/v0.11.5
82
+ documentation_uri: https://dazuma.github.io/toys/gems/toys-core/v0.12.0
76
83
  post_install_message:
77
84
  rdoc_options: []
78
85
  require_paths:
@@ -81,14 +88,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
81
88
  requirements:
82
89
  - - ">="
83
90
  - !ruby/object:Gem::Version
84
- version: 2.3.0
91
+ version: 2.4.0
85
92
  required_rubygems_version: !ruby/object:Gem::Requirement
86
93
  requirements:
87
94
  - - ">="
88
95
  - !ruby/object:Gem::Version
89
96
  version: '0'
90
97
  requirements: []
91
- rubygems_version: 3.1.4
98
+ rubygems_version: 3.1.6
92
99
  signing_key:
93
100
  specification_version: 4
94
101
  summary: Framework for creating command line executables