cuprum-cli 0.1.0 → 0.2.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 (59) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +43 -0
  3. data/README.md +10 -0
  4. data/lib/cuprum/cli/argument.rb +2 -2
  5. data/lib/cuprum/cli/command.rb +2 -4
  6. data/lib/cuprum/cli/commands/ci/rspec_each_command.rb +34 -8
  7. data/lib/cuprum/cli/commands/ci.rb +8 -0
  8. data/lib/cuprum/cli/commands/file/new_command.rb +42 -49
  9. data/lib/cuprum/cli/commands/file.rb +8 -5
  10. data/lib/cuprum/cli/dependencies/clock/mock.rb +28 -0
  11. data/lib/cuprum/cli/dependencies/clock.rb +29 -0
  12. data/lib/cuprum/cli/dependencies/file_system/mock.rb +150 -18
  13. data/lib/cuprum/cli/dependencies/file_system.rb +145 -10
  14. data/lib/cuprum/cli/dependencies.rb +2 -0
  15. data/lib/cuprum/cli/errors.rb +0 -1
  16. data/lib/cuprum/cli/{commands/file/generate_file.rb → files/create_file.rb} +6 -48
  17. data/lib/cuprum/cli/{commands/file → files/engines}/render_erb.rb +6 -6
  18. data/lib/cuprum/cli/files/engines.rb +76 -0
  19. data/lib/cuprum/cli/{errors/files → files/errors}/file_not_writeable.rb +3 -3
  20. data/lib/cuprum/cli/files/errors/generator_error.rb +46 -0
  21. data/lib/cuprum/cli/{errors/files → files/errors}/missing_parameter.rb +5 -5
  22. data/lib/cuprum/cli/{errors/files → files/errors}/missing_template.rb +3 -3
  23. data/lib/cuprum/cli/{errors/files → files/errors}/template_error.rb +3 -3
  24. data/lib/cuprum/cli/files/errors.rb +19 -0
  25. data/lib/cuprum/cli/files/generator.rb +431 -0
  26. data/lib/cuprum/cli/files/generators/basic_generator.rb +15 -0
  27. data/lib/cuprum/cli/files/generators/rspec_generator.rb +19 -0
  28. data/lib/cuprum/cli/files/generators/ruby_generator.rb +32 -0
  29. data/lib/cuprum/cli/files/generators.rb +25 -0
  30. data/lib/cuprum/cli/files/template.rb +62 -0
  31. data/lib/cuprum/cli/files/templates/basic_template.rb +39 -0
  32. data/lib/cuprum/cli/files/templates/file_template.rb +60 -0
  33. data/lib/cuprum/cli/files/templates/string_template.rb +29 -0
  34. data/lib/cuprum/cli/files/templates.rb +59 -0
  35. data/lib/cuprum/cli/files.rb +18 -0
  36. data/lib/cuprum/cli/integrations/async/commands/rspec_each_command.rb +32 -0
  37. data/lib/cuprum/cli/integrations/async/commands.rb +11 -0
  38. data/lib/cuprum/cli/integrations/async.rb +21 -0
  39. data/lib/cuprum/cli/integrations/thor/registry.rb +7 -29
  40. data/lib/cuprum/cli/integrations/thor/task.rb +37 -7
  41. data/lib/cuprum/cli/metadata.rb +54 -5
  42. data/lib/cuprum/cli/option.rb +10 -4
  43. data/lib/cuprum/cli/options/class_methods.rb +19 -1
  44. data/lib/cuprum/cli/registry.rb +131 -55
  45. data/lib/cuprum/cli/rspec/deferred/dependencies/file_system_examples.rb +1303 -1001
  46. data/lib/cuprum/cli/rspec/deferred/generators_examples.rb +112 -0
  47. data/lib/cuprum/cli/rspec/deferred/metadata_examples.rb +300 -0
  48. data/lib/cuprum/cli/rspec/deferred/options_examples.rb +8 -2
  49. data/lib/cuprum/cli/rspec/deferred/registry_examples.rb +343 -108
  50. data/lib/cuprum/cli/rspec/deferred/templates_examples.rb +183 -0
  51. data/lib/cuprum/cli/version.rb +1 -1
  52. data/lib/cuprum/cli.rb +1 -0
  53. metadata +31 -14
  54. data/lib/cuprum/cli/commands/file/resolve_template.rb +0 -136
  55. data/lib/cuprum/cli/commands/file/templates.rb +0 -71
  56. data/lib/cuprum/cli/errors/files/template_not_resolved.rb +0 -54
  57. data/lib/cuprum/cli/errors/files.rb +0 -19
  58. /data/lib/cuprum/cli/{commands/file → files}/templates/rspec.rb.erb +0 -0
  59. /data/lib/cuprum/cli/{commands/file → files}/templates/ruby.rb.erb +0 -0
@@ -32,7 +32,7 @@ module Cuprum::Cli::Dependencies
32
32
  def initialize(files: {}, root_path: Dir.pwd)
33
33
  super(root_path:)
34
34
 
35
- @files = files
35
+ @files = split_files(files)
36
36
  @tempfiles = []
37
37
  end
38
38
 
@@ -44,7 +44,7 @@ module Cuprum::Cli::Dependencies
44
44
 
45
45
  # (see Cuprum::Cli::Dependencies::FileSystem#create_directory)
46
46
  def create_directory(path, recursive: false) # rubocop:disable Metrics/MethodLength
47
- tools.assertions.validate_name(path, as: 'path')
47
+ validate_file_path(path, as: 'path')
48
48
 
49
49
  *dir_names, dir_name = split_path(resolve_path(path))
50
50
 
@@ -60,15 +60,69 @@ module Cuprum::Cli::Dependencies
60
60
  "unable to create directory #{path} - directory is a file"
61
61
  end
62
62
 
63
- directory[dir_name] = {}
63
+ directory[dir_name] ||= {}
64
64
 
65
65
  path
66
66
  end
67
67
  alias make_directory create_directory
68
68
 
69
+ # (see Cuprum::Cli::Dependencies::FileSystem#delete_directory)
70
+ def delete_directory(path, force: false, recursive: false) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
71
+ validate_file_path(path, as: 'path')
72
+
73
+ *dir_names, dir_name = split_path(resolve_path(path))
74
+
75
+ dir = dir_names.reduce(files) do |dir, dir_name|
76
+ require_directory(action: 'delete directory', dir: dir[dir_name], path:)
77
+
78
+ dir[dir_name]
79
+ end
80
+
81
+ require_directory(action: 'delete directory', dir: dir[dir_name], path:)
82
+
83
+ is_empty =
84
+ (recursive && empty_directories?(dir[dir_name])) || dir[dir_name].empty?
85
+
86
+ if force || is_empty
87
+ dir.delete(dir_name)
88
+
89
+ return path
90
+ end
91
+
92
+ raise DirectoryNotEmptyError,
93
+ "unable to delete directory #{path} - directory is not empty"
94
+ end
95
+ alias remove_directory delete_directory
96
+
97
+ # (see Cuprum::Cli::Dependencies::FileSystem#delete_file)
98
+ def delete_file(path) # rubocop:disable Metrics/MethodLength
99
+ validate_file_path(path, as: 'path')
100
+
101
+ resolved = resolve_path(path)
102
+
103
+ if directory?(resolved)
104
+ raise FileIsADirectoryError,
105
+ "unable to delete file #{path} - file is a directory"
106
+ end
107
+
108
+ unless file?(resolved)
109
+ raise FileNotFoundError,
110
+ "unable to delete file #{path} - file not found"
111
+ end
112
+
113
+ *relative, file = split_path(resolved)
114
+
115
+ directory = relative.empty? ? files : files.dig(*relative)
116
+
117
+ directory.delete(file)
118
+
119
+ path
120
+ end
121
+ alias remove_file delete_file
122
+
69
123
  # (see Cuprum::Cli::Dependencies::FileSystem#directory?)
70
124
  def directory?(path)
71
- tools.assertions.validate_name(path, as: 'path')
125
+ validate_file_path(path, as: 'path')
72
126
 
73
127
  path = resolve_path(path)
74
128
  mock = resolve_mock(path)
@@ -78,21 +132,33 @@ module Cuprum::Cli::Dependencies
78
132
  alias directory_exists? directory?
79
133
 
80
134
  # (see Cuprum::Cli::Dependencies::FileSystem#each_file)
81
- def each_file(pattern, &)
135
+ def each_file(pattern, &) # rubocop:disable Metrics/AbcSize
82
136
  return enum_for(:each_file, pattern) unless block_given?
83
137
 
84
- flattened_files.each do |file_path|
138
+ absolute_path = pattern.is_a?(String) && pattern.start_with?(root_path)
139
+
140
+ pattern = pattern[(root_path.length + 1)..] if absolute_path
141
+
142
+ [*expanded_dirs, *flattened_files].each do |file_path|
85
143
  next unless matches_pattern?(file_path:, pattern:)
86
144
 
87
- yield File.join(root_path, file_path)
145
+ yield absolute_path ? File.join(root_path, file_path) : file_path
88
146
  end
89
147
 
90
148
  nil
91
149
  end
92
150
 
151
+ # @return [Array<String>] a list of the defined directory paths in the mock
152
+ # file system.
153
+ def expanded_dirs = expand_dirs(files:).to_a.sort
154
+
155
+ # @return [Array<String>] a list of the defined file paths in the mock file
156
+ # system.
157
+ def flattened_files = flatten_files(files:).sort
158
+
93
159
  # (see Cuprum::Cli::Dependencies::FileSystem#directory?)
94
160
  def file?(path)
95
- tools.assertions.validate_name(path, as: 'path')
161
+ validate_file_path(path, as: 'path')
96
162
 
97
163
  path = resolve_path(path)
98
164
  mock = resolve_mock(path)
@@ -177,6 +243,32 @@ module Cuprum::Cli::Dependencies
177
243
 
178
244
  private
179
245
 
246
+ def empty_directories?(dir)
247
+ return false unless dir.is_a?(Hash)
248
+
249
+ return true if dir.empty?
250
+
251
+ dir.each_value.all? { |item| empty_directories?(item) }
252
+ end
253
+
254
+ def expand_dirs(files:, flat: Set.new, path: '')
255
+ files.each do |name, value|
256
+ qualified_path = path.empty? ? name : File.join(path, name)
257
+
258
+ next unless value.is_a?(Hash)
259
+
260
+ flat << qualified_path
261
+
262
+ qualified_path.split('/').reduce do |memo, segment|
263
+ "#{memo}/#{segment}".tap { |str| flat << str }
264
+ end
265
+
266
+ expand_dirs(files: value, flat:, path: qualified_path)
267
+ end
268
+
269
+ flat
270
+ end
271
+
180
272
  def flatten_files(files:, flat: [], path: '')
181
273
  files.each do |name, value|
182
274
  qualified_path = path.empty? ? name : File.join(path, name)
@@ -189,10 +281,6 @@ module Cuprum::Cli::Dependencies
189
281
  flat
190
282
  end
191
283
 
192
- def flattened_files
193
- @flattened_files || flatten_files(files:)
194
- end
195
-
196
284
  def io_stream?(file_or_path)
197
285
  super || file_or_path.is_a?(MockTempfile)
198
286
  end
@@ -207,12 +295,19 @@ module Cuprum::Cli::Dependencies
207
295
 
208
296
  return false unless entry_names.length >= prefix_count + suffix_count
209
297
 
210
- entry_names[...prefix_count]
211
- .zip(prefix_strings)
212
- .concat(entry_names[-suffix_count...].zip(suffix_strings))
213
- .all? do |entry_name, pattern_string|
214
- matches_pattern_string?(entry_name:, pattern_string:)
215
- end
298
+ matchers = entry_names[...prefix_count].zip(prefix_strings)
299
+
300
+ if suffix_count.zero?
301
+ # For a globbed pattern, if there is no suffix there must still be at
302
+ # least one entry to match the '**' pattern.
303
+ matchers.push([entry_names[prefix_count], '*'])
304
+ else
305
+ matchers.concat(entry_names[-suffix_count...].zip(suffix_strings))
306
+ end
307
+
308
+ matchers.all? do |entry_name, pattern_string|
309
+ matches_pattern_string?(entry_name:, pattern_string:)
310
+ end
216
311
  end
217
312
 
218
313
  def matches_pattern?(file_path:, pattern:)
@@ -242,6 +337,16 @@ module Cuprum::Cli::Dependencies
242
337
  end
243
338
  end
244
339
 
340
+ def require_directory(action:, dir:, path:)
341
+ if io_stream?(dir)
342
+ raise DirectoryIsAFileError,
343
+ "unable to #{action} #{path} - directory is a file"
344
+ elsif dir.nil?
345
+ raise DirectoryNotFoundError,
346
+ "unable to #{action} #{path} - directory not found"
347
+ end
348
+ end
349
+
245
350
  def resolve_mock(path)
246
351
  return unless path.start_with?(root_path)
247
352
 
@@ -256,6 +361,33 @@ module Cuprum::Cli::Dependencies
256
361
  dir&.[](last)
257
362
  end
258
363
 
364
+ def split_files(files) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
365
+ files.each.with_object({}) do |(key, value), hsh|
366
+ value = split_files(value) if value.is_a?(Hash)
367
+ value = StringIO.new(value) if value.is_a?(String)
368
+
369
+ next hsh[key] = value unless key.include?('/')
370
+
371
+ # Normalize key, removing root path and leading slash.
372
+ key = key[root_path.length..] if key.start_with?(root_path)
373
+ key = key[1..] if key.start_with?('/')
374
+
375
+ *dir, file = key.split('/')
376
+
377
+ # Ensure that each directory is represented by a Hash.
378
+ dir.each do |segment|
379
+ hsh[segment] = {} unless hsh.key?(segment)
380
+
381
+ raise "invalid file path #{key}" unless hsh[segment].is_a?(Hash)
382
+
383
+ hsh = hsh[segment]
384
+ end
385
+
386
+ # Assign the file or directory value.
387
+ hsh[file] = value
388
+ end
389
+ end
390
+
259
391
  def split_path(path)
260
392
  path[(1 + root_path.length)..]
261
393
  &.split(File::SEPARATOR) || []
@@ -17,9 +17,15 @@ module Cuprum::Cli::Dependencies
17
17
  # Exception raised when attempting to access a file as a directory.
18
18
  class DirectoryIsAFileError < FileError; end
19
19
 
20
+ # Exception raised when attempting to delete a non-empty directory.
21
+ class DirectoryNotEmptyError < FileError; end
22
+
20
23
  # Exception raised when attempting to access a non-existent directory.
21
24
  class DirectoryNotFoundError < FileError; end
22
25
 
26
+ # Exception raised when attempting to overwrite an existing file.
27
+ class FileAlreadyExistsError < FileError; end
28
+
23
29
  # Exception raised when attempting to access a directory as a file.
24
30
  class FileIsADirectoryError < FileError; end
25
31
 
@@ -35,6 +41,57 @@ module Cuprum::Cli::Dependencies
35
41
  # @return [String] the path to the root directory.
36
42
  attr_reader :root_path
37
43
 
44
+ # @overload copy_file(source_path, destination_path, force: false)
45
+ # Copies the contents of the source file to the destination path.
46
+ #
47
+ # @param source_path [String] the path of the file to copy.
48
+ # @param target_path [String] the path to write the file to.
49
+ # @param force [true, false] if true, overwrites an existing file (not a
50
+ # directory) at the destination path. Defaults to false.
51
+ #
52
+ # @return [Integer] the number of bytes written.
53
+ #
54
+ # @raise [FileNotFoundError] if the file to copy does not exist.
55
+ # @raise [FileIsADirectoryError] if the file to copy is a directory, or if
56
+ # there is a directory at the destination path.
57
+ # @raise [FileAlreadyExistsError] if there is a file at the destination
58
+ # path and the force: option is false.
59
+ #
60
+ # @overload copy_file(source_path, destination_path, force: false) { |source| }
61
+ # Reads the source file and generates a new file with modified contents.
62
+ #
63
+ # @param source_path [String] the path of the file to copy.
64
+ # @param target_path [String] the path to write the file to.
65
+ # @param force [true, false] if true, overwrites an existing file (not a
66
+ # directory) at the destination path. Defaults to false.
67
+ #
68
+ # @return [Integer] the number of bytes written.
69
+ #
70
+ # @yield the transformation function used to modify the contents of the
71
+ # file.
72
+ # @yieldparam source [String] the contents of the source file.
73
+ # @yieldreturn [String] the contents of the destination file.
74
+ #
75
+ # @raise [FileNotFoundError] if the file to copy does not exist.
76
+ # @raise [FileIsADirectoryError] if the file to copy is a directory, or if
77
+ # there is a directory at the destination path.
78
+ # @raise [FileAlreadyExistsError] if there is a file at the destination
79
+ # path and the force: option is false.
80
+ def copy_file(source_path, destination_path, force: false, &block)
81
+ validate_file_path(source_path, as: 'source_path')
82
+ validate_file_path(destination_path, as: 'destination_path')
83
+
84
+ if !force && file?(destination_path)
85
+ raise FileAlreadyExistsError,
86
+ "unable to write file #{destination_path} - file already exists"
87
+ end
88
+
89
+ contents = read_file(source_path)
90
+ contents = block.call(contents) if block
91
+
92
+ write_file(destination_path, contents)
93
+ end
94
+
38
95
  # Creates a directory at the requested path.
39
96
  #
40
97
  # @param path [String] the path to the directory.
@@ -43,13 +100,13 @@ module Cuprum::Cli::Dependencies
43
100
  #
44
101
  # @return [String] the path to the created directory.
45
102
  def create_directory(path, recursive: false)
46
- tools.assertions.validate_name(path, as: 'path')
103
+ validate_file_path(path, as: 'path')
47
104
 
48
105
  resolved = resolve_path(path)
49
106
 
50
107
  return path if directory?(resolved)
51
108
 
52
- handle_create_errors(path) do
109
+ handle_create_directory_errors(path) do
53
110
  recursive ? FileUtils.mkdir_p(resolved) : FileUtils.mkdir(resolved)
54
111
  end
55
112
 
@@ -57,6 +114,58 @@ module Cuprum::Cli::Dependencies
57
114
  end
58
115
  alias make_directory create_directory
59
116
 
117
+ # Removes the directory at the requested path.
118
+ #
119
+ # Fails if the directory contains any files or child directories. The
120
+ # :recursive option enables removing empty child or descendent directories,
121
+ # while the :force option enables removing both files and directories.
122
+ #
123
+ # @param path [String] the path to the directory.
124
+ # @param force [true, false] if true, removes nested files and directories.
125
+ # @param recursive [true, false] if true, removes nested empty directories.
126
+ #
127
+ # @return [String] the path to the removed directory.
128
+ def delete_directory(path, force: false, recursive: false)
129
+ validate_file_path(path, as: 'path')
130
+
131
+ resolved = resolve_path(path)
132
+
133
+ handle_delete_directory_errors(path) do
134
+ if force || (recursive && empty_directories?(resolved))
135
+ FileUtils.remove_dir(resolved)
136
+ else
137
+ Dir.rmdir(resolved)
138
+ end
139
+ end
140
+
141
+ path
142
+ end
143
+ alias remove_directory delete_directory
144
+
145
+ # Removes the file at the requested path.
146
+ #
147
+ # @param path [String] the path to the file.
148
+ #
149
+ # @return [String] the path to the removed file.
150
+ def delete_file(path) # rubocop:disable Metrics/MethodLength
151
+ validate_file_path(path, as: 'path')
152
+
153
+ resolved = resolve_path(path)
154
+
155
+ if directory?(resolved)
156
+ raise FileIsADirectoryError,
157
+ "unable to delete file #{path} - file is a directory"
158
+ end
159
+
160
+ File.delete(resolved)
161
+
162
+ path
163
+ rescue Errno::ENOENT, Errno::EPERM
164
+ raise FileNotFoundError,
165
+ "unable to delete file #{path} - file not found"
166
+ end
167
+ alias remove_file delete_file
168
+
60
169
  # Checks if the requested directory exists.
61
170
  #
62
171
  # @param path [String] the path to the requested directory.
@@ -64,7 +173,7 @@ module Cuprum::Cli::Dependencies
64
173
  # @return [true, false] true if the directory exists and is a directory,
65
174
  # otherwise false.
66
175
  def directory?(path)
67
- tools.assertions.validate_name(path, as: 'path')
176
+ validate_file_path(path, as: 'path')
68
177
 
69
178
  path = resolve_path(path)
70
179
 
@@ -90,9 +199,7 @@ module Cuprum::Cli::Dependencies
90
199
  def each_file(pattern, &)
91
200
  return enum_for(:each_file, pattern) unless block_given?
92
201
 
93
- path = resolve_path(pattern)
94
-
95
- Dir[path].each(&)
202
+ Dir.glob(pattern, base: root_path, &)
96
203
 
97
204
  nil
98
205
  end
@@ -104,7 +211,7 @@ module Cuprum::Cli::Dependencies
104
211
  # @return [true, false] true if the file exists and is a file,
105
212
  # otherwise false.
106
213
  def file?(path)
107
- tools.assertions.validate_name(path, as: 'path')
214
+ validate_file_path(path, as: 'path')
108
215
 
109
216
  path = resolve_path(path)
110
217
 
@@ -180,17 +287,21 @@ module Cuprum::Cli::Dependencies
180
287
 
181
288
  path = resolve_path(file_or_path)
182
289
 
183
- handle_write_errors(file_or_path) { File.write(path, data) }
290
+ handle_write_file_errors(file_or_path) { File.write(path, data) }
184
291
  end
185
292
  alias write write_file
186
293
 
187
294
  private
188
295
 
296
+ def empty_directories?(dir)
297
+ Dir[File.join(dir, '**', '*')].all? { |dir| File.directory?(dir) }
298
+ end
299
+
189
300
  def empty_file_message(as:)
190
301
  tools.assertions.error_message_for('presence', as:)
191
302
  end
192
303
 
193
- def handle_create_errors(path)
304
+ def handle_create_directory_errors(path)
194
305
  yield
195
306
  rescue Errno::EEXIST
196
307
  raise Cuprum::Cli::Dependencies::FileSystem::DirectoryIsAFileError,
@@ -198,9 +309,25 @@ module Cuprum::Cli::Dependencies
198
309
  rescue Errno::ENOENT
199
310
  raise Cuprum::Cli::Dependencies::FileSystem::DirectoryNotFoundError,
200
311
  "unable to create directory #{path} - directory not found"
312
+ rescue Errno::ENOTDIR
313
+ raise DirectoryIsAFileError,
314
+ "unable to create directory #{path} - directory is a file"
315
+ end
316
+
317
+ def handle_delete_directory_errors(path)
318
+ yield
319
+ rescue Errno::ENOENT
320
+ raise DirectoryNotFoundError,
321
+ "unable to delete directory #{path} - directory not found"
322
+ rescue Errno::ENOTDIR
323
+ raise DirectoryIsAFileError,
324
+ "unable to delete directory #{path} - directory is a file"
325
+ rescue Errno::ENOTEMPTY
326
+ raise DirectoryNotEmptyError,
327
+ "unable to delete directory #{path} - directory is not empty"
201
328
  end
202
329
 
203
- def handle_write_errors(file_or_path)
330
+ def handle_write_file_errors(file_or_path)
204
331
  yield
205
332
  rescue Errno::EISDIR
206
333
  raise FileIsADirectoryError,
@@ -243,5 +370,13 @@ module Cuprum::Cli::Dependencies
243
370
  raise ArgumentError, invalid_file_message(as:)
244
371
  end
245
372
  end
373
+
374
+ def validate_file_path(path, as:)
375
+ tools.assertions.validate_presence(path, as:) if path.nil?
376
+
377
+ tools.assertions.validate_instance_of(path, as:, expected: String)
378
+
379
+ tools.assertions.validate_presence(path, as:)
380
+ end
246
381
  end
247
382
  end
@@ -7,6 +7,7 @@ require 'cuprum/cli'
7
7
  module Cuprum::Cli
8
8
  # Dependencies provide standard functionality to commands.
9
9
  module Dependencies
10
+ autoload :Clock, 'cuprum/cli/dependencies/clock'
10
11
  autoload :FileSystem, 'cuprum/cli/dependencies/file_system'
11
12
  autoload :StandardIo, 'cuprum/cli/dependencies/standard_io'
12
13
  autoload :SystemCommand, 'cuprum/cli/dependencies/system_command'
@@ -15,6 +16,7 @@ module Cuprum::Cli
15
16
  def self.provider
16
17
  @provider ||= Plumbum::ManyProvider.new(
17
18
  values: {
19
+ clock: Clock.new,
18
20
  file_system: FileSystem.new,
19
21
  standard_io: StandardIo.new,
20
22
  system_command: SystemCommand.new
@@ -5,7 +5,6 @@ require 'cuprum/cli'
5
5
  module Cuprum::Cli
6
6
  # Namespace for errors, which represent failure states of commands.
7
7
  module Errors
8
- autoload :Files, 'cuprum/cli/errors/files'
9
8
  autoload :SystemCommandFailure, 'cuprum/cli/errors/system_command_failure'
10
9
  end
11
10
  end
@@ -3,22 +3,18 @@
3
3
  require 'cuprum/command'
4
4
  require 'plumbum'
5
5
 
6
- require 'cuprum/cli/commands/file'
7
- require 'cuprum/cli/commands/file/render_erb'
8
6
  require 'cuprum/cli/dependencies'
9
7
  require 'cuprum/cli/dependencies/file_system'
10
- require 'cuprum/cli/errors/files/missing_template'
8
+ require 'cuprum/cli/files'
11
9
  require 'cuprum/cli/options'
12
10
 
13
- module Cuprum::Cli::Commands::File
14
- # Utility command for generating a file from a template.
15
- class GenerateFile < Cuprum::Command
11
+ module Cuprum::Cli::Files
12
+ # Utility command for creating a file with specified contents.
13
+ class CreateFile < Cuprum::Command
16
14
  include Plumbum::Consumer
17
15
  prepend Plumbum::Parameters
18
16
  include Cuprum::Cli::Dependencies::StandardIo::Helpers
19
17
  extend Cuprum::Cli::Options::ClassMethods
20
- include Cuprum::Cli::Options::Quiet
21
- include Cuprum::Cli::Options::Verbose
22
18
 
23
19
  dependency :file_system
24
20
  dependency :standard_io
@@ -77,28 +73,10 @@ module Cuprum::Cli::Commands::File
77
73
  end
78
74
 
79
75
  def file_not_writeable_error(**)
80
- Cuprum::Cli::Errors::Files::FileNotWriteable.new(**)
76
+ Cuprum::Cli::Files::Errors::FileNotWriteable.new(**)
81
77
  end
82
78
 
83
- def load_template(file_path:, template_path:)
84
- file_system.read_file(template_path)
85
- rescue Cuprum::Cli::Dependencies::FileSystem::FileNotFoundError
86
- error = Cuprum::Cli::Errors::Files::MissingTemplate.new(
87
- message: "unable to generate file #{file_path}",
88
- template_path:
89
- )
90
- failure(error)
91
- end
92
-
93
- def process(file_path:, parameters:, template_path:)
94
- say "Generating file #{file_path}..."
95
-
96
- template = step { load_template(file_path:, template_path:) }
97
- contents =
98
- step { render_template(parameters:, template:, template_path:) }
99
-
100
- report_file_contents(contents)
101
-
79
+ def process(contents:, file_path:)
102
80
  step { create_directory(file_path:) }
103
81
 
104
82
  step { write_file(contents:, file_path:) }
@@ -106,26 +84,6 @@ module Cuprum::Cli::Commands::File
106
84
  file_path
107
85
  end
108
86
 
109
- def render_template(parameters:, template:, template_path:)
110
- case File.extname(template_path)
111
- when '.erb'
112
- RenderErb.new(template_name: template_path).call(template, **parameters)
113
- else
114
- template
115
- end
116
- end
117
-
118
- def report_file_contents(contents)
119
- say "\n", verbose: true
120
- say(
121
- contents
122
- .each_line
123
- .map { |line| line == "\n" ? "\n" : " #{line}" }.join,
124
- verbose: true
125
- )
126
- say "\n", verbose: true
127
- end
128
-
129
87
  def write_file(contents:, file_path:)
130
88
  step { check_if_file_is_directory(file_path:) }
131
89
  step { check_if_file_already_exists(file_path:) }
@@ -3,10 +3,10 @@
3
3
  require 'cuprum/command'
4
4
  require 'herb'
5
5
 
6
- require 'cuprum/cli/commands/file'
7
- require 'cuprum/cli/errors/files/missing_parameter'
6
+ require 'cuprum/cli/files/engines'
7
+ require 'cuprum/cli/files/errors/missing_parameter'
8
8
 
9
- module Cuprum::Cli::Commands::File
9
+ module Cuprum::Cli::Files::Engines
10
10
  # Utility command for generating file contents from an .erb template.
11
11
  class RenderErb < Cuprum::Command
12
12
  class RenderingContext < BasicObject; end
@@ -29,7 +29,7 @@ module Cuprum::Cli::Commands::File
29
29
  message = 'unable to render ERB template'
30
30
  message = "#{message} #{template_name}" if template_name
31
31
 
32
- Cuprum::Cli::Errors::Files::TemplateError.new(message:, details:)
32
+ Cuprum::Cli::Files::Errors::TemplateError.new(message:, details:)
33
33
  end
34
34
 
35
35
  def empty_binding = RenderingContext.new.instance_exec { Kernel.binding }
@@ -50,7 +50,7 @@ module Cuprum::Cli::Commands::File
50
50
  end
51
51
 
52
52
  def missing_parameter_error(parameter_name)
53
- Cuprum::Cli::Errors::Files::MissingParameter.new(
53
+ Cuprum::Cli::Files::Errors::MissingParameter.new(
54
54
  message: 'unable to render ERB template',
55
55
  parameter_name:,
56
56
  template_name:
@@ -79,7 +79,7 @@ module Cuprum::Cli::Commands::File
79
79
  end
80
80
 
81
81
  def template_error(message)
82
- Cuprum::Cli::Errors::Files::TemplateError.new(
82
+ Cuprum::Cli::Files::Errors::TemplateError.new(
83
83
  message: "unable to render ERB template - #{message}",
84
84
  template_name:
85
85
  )