poepod 0.1.5 → 0.1.6
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.
- checksums.yaml +4 -4
- data/README.adoc +47 -10
- data/lib/poepod/cli.rb +80 -27
- data/lib/poepod/file_processor.rb +25 -59
- data/lib/poepod/gem_processor.rb +48 -33
- data/lib/poepod/processor.rb +108 -7
- data/lib/poepod/version.rb +1 -1
- data/poepod.gemspec +1 -1
- data/spec/poepod/cli_spec.rb +49 -13
- data/spec/poepod/file_processor_spec.rb +112 -25
- data/spec/poepod/gem_processor_spec.rb +66 -53
- metadata +4 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: b205fe50c5830d75893fbfa378b81984bf8a2b73fa8d104509fbbf698e0001fc
|
|
4
|
+
data.tar.gz: d4e87cef72c92cdcfaadd6bcf5a452bc1a05b13c4927cce10b6c81250ff99c9c
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c32f1ffb23fcf86f8cd1625c1deab4dc3599a0baf7b4ad80618f1e37a23f7b8e815b6065d628bf138f0e8ca9c2c849d1a08c31599737bee85711a6b4cd3e88f0
|
|
7
|
+
data.tar.gz: bdc4de92b51c89cfbeb484a119ce829e8a5c0a7768a032f4ec4299b06f2b35724038b13a2093827fbe839c650c0a18902c544ddd85f842e47ab4e633089edb38
|
data/README.adoc
CHANGED
|
@@ -42,37 +42,62 @@ Commands:
|
|
|
42
42
|
poepod wrap GEMSPEC_PATH # Wrap a gem based on its gemspec file
|
|
43
43
|
----
|
|
44
44
|
|
|
45
|
+
=== Global options
|
|
46
|
+
|
|
47
|
+
All options can be used for both `wrap` and `concat` commands:
|
|
48
|
+
|
|
49
|
+
* `--exclude`: List of patterns to exclude (default: `["node_modules/", ".git/", ".gitignore$", ".DS_Store$", "^\\..+"]`)
|
|
50
|
+
* `--config`: Path to configuration file
|
|
51
|
+
* `--include-binary`: Include binary files (encoded in MIME format)
|
|
52
|
+
* `--include-dot-files`: Include dot files
|
|
53
|
+
* `--output-file`: Output path
|
|
54
|
+
* `--base-dir`: Base directory for relative file paths in output
|
|
55
|
+
* `--include-unstaged`: Include unstaged files from `lib`, `spec`, and `test` directories (for `wrap` command only)
|
|
56
|
+
|
|
57
|
+
[source,shell]
|
|
58
|
+
----
|
|
59
|
+
$ poepod concat FILES [OUTPUT_FILE] --exclude PATTERNS --config PATH --include-binary --include-dot-files --output-file PATH --base-dir PATH
|
|
60
|
+
$ poepod wrap GEMSPEC_PATH --exclude PATTERNS --config PATH --include-binary --include-dot-files --output-file PATH --base-dir PATH --include-unstaged
|
|
61
|
+
----
|
|
62
|
+
|
|
45
63
|
=== Concatenating files
|
|
46
64
|
|
|
47
65
|
The `concat` command allows you to combine multiple files into a single text
|
|
48
|
-
file.
|
|
66
|
+
file.
|
|
67
|
+
|
|
68
|
+
This is particularly useful when you want to review or analyze code from
|
|
49
69
|
multiple files in one place, or when preparing code submissions for AI-powered
|
|
50
70
|
coding assistants.
|
|
51
71
|
|
|
72
|
+
By default, it excludes binary files, dot files, and certain patterns like
|
|
73
|
+
`node_modules/` and `.git/`.
|
|
74
|
+
|
|
52
75
|
[source,shell]
|
|
53
76
|
----
|
|
54
77
|
$ poepod concat path/to/files/* output.txt
|
|
55
78
|
----
|
|
56
79
|
|
|
57
|
-
This will concatenate all files from the specified path into
|
|
80
|
+
This will concatenate all non-binary, non-dot files from the specified path into
|
|
81
|
+
`output.txt`.
|
|
58
82
|
|
|
59
|
-
====
|
|
83
|
+
==== Including dot files
|
|
60
84
|
|
|
61
|
-
|
|
85
|
+
By default, dot files (hidden files starting with a dot) are excluded.
|
|
86
|
+
|
|
87
|
+
To include them, use the `--include-dot-files` option:
|
|
62
88
|
|
|
63
89
|
[source,shell]
|
|
64
90
|
----
|
|
65
|
-
$ poepod concat path/to/files/* output.txt --
|
|
91
|
+
$ poepod concat path/to/files/* output.txt --include-dot-files
|
|
66
92
|
----
|
|
67
93
|
|
|
68
|
-
This is helpful when you want to focus on specific parts of your codebase,
|
|
69
|
-
excluding irrelevant or large directories.
|
|
70
|
-
|
|
71
94
|
==== Including binary files
|
|
72
95
|
|
|
73
96
|
By default, binary files are excluded to keep the output focused on readable
|
|
74
|
-
code.
|
|
75
|
-
|
|
97
|
+
code.
|
|
98
|
+
|
|
99
|
+
To include binary files (encoded in MIME format), use the `--include-binary`
|
|
100
|
+
option:
|
|
76
101
|
|
|
77
102
|
[source,shell]
|
|
78
103
|
----
|
|
@@ -82,6 +107,18 @@ $ poepod concat path/to/files/* output.txt --include-binary
|
|
|
82
107
|
This can be useful when you need to include binary assets or compiled files in
|
|
83
108
|
your analysis.
|
|
84
109
|
|
|
110
|
+
==== Excluding patterns
|
|
111
|
+
|
|
112
|
+
You can exclude certain patterns using the `--exclude` option:
|
|
113
|
+
|
|
114
|
+
[source,shell]
|
|
115
|
+
----
|
|
116
|
+
$ poepod concat path/to/files/* output.txt --exclude node_modules .git build test
|
|
117
|
+
----
|
|
118
|
+
|
|
119
|
+
This is helpful when you want to focus on specific parts of your codebase,
|
|
120
|
+
excluding irrelevant or large directories.
|
|
121
|
+
|
|
85
122
|
=== Wrapping a gem
|
|
86
123
|
|
|
87
124
|
The `wrap` command creates a comprehensive snapshot of your gem, including all
|
data/lib/poepod/cli.rb
CHANGED
|
@@ -6,44 +6,48 @@ require_relative "file_processor"
|
|
|
6
6
|
require_relative "gem_processor"
|
|
7
7
|
|
|
8
8
|
module Poepod
|
|
9
|
+
# Command-line interface for Poepod
|
|
9
10
|
class Cli < Thor
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
output_file ||= default_output_file(files.first)
|
|
22
|
-
output_path = Pathname.new(output_file).expand_path
|
|
11
|
+
# Define shared options
|
|
12
|
+
def self.shared_options
|
|
13
|
+
option :exclude, type: :array, default: Poepod::FileProcessor::EXCLUDE_DEFAULT,
|
|
14
|
+
desc: "List of patterns to exclude"
|
|
15
|
+
option :config, type: :string, desc: "Path to configuration file"
|
|
16
|
+
option :include_binary, type: :boolean, default: false, desc: "Include binary files (encoded in MIME format)"
|
|
17
|
+
option :include_dot_files, type: :boolean, default: false, desc: "Include dot files"
|
|
18
|
+
option :output_file, type: :string, desc: "Output path"
|
|
19
|
+
option :base_dir, type: :string, desc: "Base directory for relative file paths in output"
|
|
20
|
+
end
|
|
23
21
|
|
|
24
|
-
|
|
25
|
-
|
|
22
|
+
desc "concat FILES [OUTPUT_FILE]", "Concatenate specified files into one text file"
|
|
23
|
+
shared_options
|
|
26
24
|
|
|
27
|
-
|
|
28
|
-
|
|
25
|
+
def concat(*files)
|
|
26
|
+
check_files(files)
|
|
27
|
+
output_file = determine_output_file(files)
|
|
28
|
+
base_dir = options[:base_dir] || Dir.pwd
|
|
29
|
+
process_files(files, output_file, base_dir)
|
|
29
30
|
end
|
|
30
31
|
|
|
31
32
|
desc "wrap GEMSPEC_PATH", "Wrap a gem based on its gemspec file"
|
|
33
|
+
shared_options
|
|
32
34
|
option :include_unstaged, type: :boolean, default: false,
|
|
33
35
|
desc: "Include unstaged files from lib, spec, and test directories"
|
|
34
36
|
|
|
35
37
|
def wrap(gemspec_path)
|
|
36
|
-
|
|
38
|
+
base_dir = options[:base_dir] || File.dirname(gemspec_path)
|
|
39
|
+
processor = Poepod::GemProcessor.new(
|
|
40
|
+
gemspec_path,
|
|
41
|
+
include_unstaged: options[:include_unstaged],
|
|
42
|
+
exclude: options[:exclude],
|
|
43
|
+
include_binary: options[:include_binary],
|
|
44
|
+
include_dot_files: options[:include_dot_files],
|
|
45
|
+
base_dir: base_dir,
|
|
46
|
+
config_file: options[:config]
|
|
47
|
+
)
|
|
37
48
|
success, result, unstaged_files = processor.process
|
|
38
|
-
|
|
39
49
|
if success
|
|
40
|
-
|
|
41
|
-
if unstaged_files.any?
|
|
42
|
-
puts "\nWarning: The following files are not staged in git:"
|
|
43
|
-
puts unstaged_files
|
|
44
|
-
puts "\nThese files are #{options[:include_unstaged] ? "included" : "not included"} in the wrap."
|
|
45
|
-
puts "Use --include-unstaged option to include these files." unless options[:include_unstaged]
|
|
46
|
-
end
|
|
50
|
+
handle_wrap_result(success, result, unstaged_files)
|
|
47
51
|
else
|
|
48
52
|
puts result
|
|
49
53
|
exit(1)
|
|
@@ -56,13 +60,62 @@ module Poepod
|
|
|
56
60
|
|
|
57
61
|
private
|
|
58
62
|
|
|
63
|
+
def check_files(files)
|
|
64
|
+
return unless files.empty?
|
|
65
|
+
|
|
66
|
+
puts "Error: No files specified."
|
|
67
|
+
exit(1)
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def determine_output_file(files)
|
|
71
|
+
options[:output_file] || default_output_file(files.first)
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def process_files(files, output_file, base_dir)
|
|
75
|
+
output_path = Pathname.new(output_file).expand_path
|
|
76
|
+
processor = Poepod::FileProcessor.new(
|
|
77
|
+
files,
|
|
78
|
+
output_path,
|
|
79
|
+
config_file: options[:config],
|
|
80
|
+
include_binary: options[:include_binary],
|
|
81
|
+
include_dot_files: options[:include_dot_files],
|
|
82
|
+
exclude: options[:exclude],
|
|
83
|
+
base_dir: base_dir
|
|
84
|
+
)
|
|
85
|
+
total_files, copied_files = processor.process
|
|
86
|
+
print_result(total_files, copied_files, output_path)
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def print_result(total_files, copied_files, output_path)
|
|
90
|
+
puts "-> #{total_files} files detected."
|
|
91
|
+
puts "=> #{copied_files} files have been concatenated into #{output_path.relative_path_from(Dir.pwd)}."
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def handle_wrap_result(success, result, unstaged_files)
|
|
95
|
+
if success
|
|
96
|
+
puts "=> The gem has been wrapped into '#{result}'."
|
|
97
|
+
print_unstaged_files_warning(unstaged_files) if unstaged_files.any?
|
|
98
|
+
else
|
|
99
|
+
puts result
|
|
100
|
+
exit(1)
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def print_unstaged_files_warning(unstaged_files)
|
|
105
|
+
puts "\nWarning: The following files are not staged in git:"
|
|
106
|
+
puts unstaged_files
|
|
107
|
+
puts "\nThese files are #{options[:include_unstaged] ? "included" : "not included"} in the wrap."
|
|
108
|
+
puts "Use --include-unstaged option to include these files." unless options[:include_unstaged]
|
|
109
|
+
end
|
|
110
|
+
|
|
59
111
|
def default_output_file(first_pattern)
|
|
60
112
|
first_item = Dir.glob(first_pattern).first
|
|
61
113
|
if first_item
|
|
62
114
|
if File.directory?(first_item)
|
|
63
115
|
"#{File.basename(first_item)}.txt"
|
|
64
116
|
else
|
|
65
|
-
"#{File.basename(first_item,
|
|
117
|
+
"#{File.basename(first_item,
|
|
118
|
+
".*")}_concat.txt"
|
|
66
119
|
end
|
|
67
120
|
else
|
|
68
121
|
"concatenated_output.txt"
|
|
@@ -1,79 +1,45 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require_relative "processor"
|
|
4
|
-
require "yaml"
|
|
5
|
-
require "tqdm"
|
|
6
|
-
require "pathname"
|
|
7
|
-
require "open3"
|
|
8
|
-
require "base64"
|
|
9
|
-
require "mime/types"
|
|
10
4
|
|
|
11
5
|
module Poepod
|
|
6
|
+
# Processes files for concatenation, handling binary and dot files
|
|
12
7
|
class FileProcessor < Processor
|
|
13
8
|
EXCLUDE_DEFAULT = [
|
|
14
|
-
%r{node_modules/}, %r{.git/}, /.gitignore$/, /.DS_Store
|
|
9
|
+
%r{node_modules/}, %r{.git/}, /.gitignore$/, /.DS_Store$/, /^\..+/
|
|
15
10
|
].freeze
|
|
16
11
|
|
|
17
|
-
def initialize(
|
|
18
|
-
|
|
12
|
+
def initialize(
|
|
13
|
+
files,
|
|
14
|
+
output_file,
|
|
15
|
+
config_file: nil,
|
|
16
|
+
include_binary: false,
|
|
17
|
+
include_dot_files: false,
|
|
18
|
+
exclude: [],
|
|
19
|
+
base_dir: nil
|
|
20
|
+
)
|
|
21
|
+
super(
|
|
22
|
+
config_file,
|
|
23
|
+
include_binary: include_binary,
|
|
24
|
+
include_dot_files: include_dot_files,
|
|
25
|
+
exclude: exclude,
|
|
26
|
+
base_dir: base_dir,
|
|
27
|
+
)
|
|
19
28
|
@files = files
|
|
20
29
|
@output_file = output_file
|
|
21
|
-
@failed_files = []
|
|
22
|
-
@include_binary = include_binary
|
|
23
30
|
end
|
|
24
31
|
|
|
25
|
-
|
|
26
|
-
total_files = 0
|
|
27
|
-
copied_files = 0
|
|
32
|
+
private
|
|
28
33
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
34
|
+
def collect_files_to_process
|
|
35
|
+
@files.flatten.each_with_object([]) do |file, files_to_process|
|
|
36
|
+
Dir.glob(file, File::FNM_DOTMATCH).each do |matched_file|
|
|
37
|
+
next unless File.file?(matched_file)
|
|
38
|
+
next if should_exclude?(matched_file)
|
|
33
39
|
|
|
34
|
-
|
|
35
|
-
file_path, content, error = process_file(matched_file)
|
|
36
|
-
if content
|
|
37
|
-
output.puts "--- START FILE: #{file_path} ---"
|
|
38
|
-
output.puts content
|
|
39
|
-
output.puts "--- END FILE: #{file_path} ---"
|
|
40
|
-
copied_files += 1
|
|
41
|
-
elsif error
|
|
42
|
-
output.puts "#{file_path}\n#{error}"
|
|
43
|
-
end
|
|
44
|
-
end
|
|
40
|
+
files_to_process << matched_file
|
|
45
41
|
end
|
|
46
42
|
end
|
|
47
|
-
|
|
48
|
-
[total_files, copied_files]
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
private
|
|
52
|
-
|
|
53
|
-
def process_file(file_path)
|
|
54
|
-
if text_file?(file_path)
|
|
55
|
-
content = File.read(file_path, encoding: "utf-8")
|
|
56
|
-
[file_path, content, nil]
|
|
57
|
-
elsif @include_binary
|
|
58
|
-
content = encode_binary_file(file_path)
|
|
59
|
-
[file_path, content, nil]
|
|
60
|
-
else
|
|
61
|
-
[file_path, nil, "Skipped binary file"]
|
|
62
|
-
end
|
|
63
|
-
rescue Encoding::InvalidByteSequenceError, Encoding::UndefinedConversionError
|
|
64
|
-
@failed_files << file_path
|
|
65
|
-
[file_path, nil, "Failed to decode the file, as it is not saved with UTF-8 encoding."]
|
|
66
|
-
end
|
|
67
|
-
|
|
68
|
-
def text_file?(file_path)
|
|
69
|
-
stdout, status = Open3.capture2("file", "-b", "--mime-type", file_path)
|
|
70
|
-
status.success? && stdout.strip.start_with?("text/")
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
def encode_binary_file(file_path)
|
|
74
|
-
mime_type = MIME::Types.type_for(file_path).first.content_type
|
|
75
|
-
encoded_content = Base64.strict_encode64(File.binread(file_path))
|
|
76
|
-
"Content-Type: #{mime_type}\nContent-Transfer-Encoding: base64\n\n#{encoded_content}"
|
|
77
43
|
end
|
|
78
44
|
end
|
|
79
45
|
end
|
data/lib/poepod/gem_processor.rb
CHANGED
|
@@ -6,61 +6,76 @@ require "rubygems/specification"
|
|
|
6
6
|
require "git"
|
|
7
7
|
|
|
8
8
|
module Poepod
|
|
9
|
+
# Processes gem files for wrapping, handling unstaged files
|
|
9
10
|
class GemProcessor < Processor
|
|
10
|
-
def initialize(
|
|
11
|
-
|
|
11
|
+
def initialize(
|
|
12
|
+
gemspec_path,
|
|
13
|
+
include_unstaged: false,
|
|
14
|
+
exclude: [],
|
|
15
|
+
include_binary: false,
|
|
16
|
+
include_dot_files: false,
|
|
17
|
+
base_dir: nil,
|
|
18
|
+
config_file: nil
|
|
19
|
+
)
|
|
20
|
+
super(
|
|
21
|
+
config_file,
|
|
22
|
+
include_binary: include_binary,
|
|
23
|
+
include_dot_files: include_dot_files,
|
|
24
|
+
exclude: exclude,
|
|
25
|
+
base_dir: base_dir || File.dirname(gemspec_path),
|
|
26
|
+
)
|
|
12
27
|
@gemspec_path = gemspec_path
|
|
13
28
|
@include_unstaged = include_unstaged
|
|
14
29
|
end
|
|
15
30
|
|
|
16
31
|
def process
|
|
17
|
-
unless File.exist?(@gemspec_path)
|
|
18
|
-
return [false, "Error: The specified gemspec file '#{@gemspec_path}' does not exist."]
|
|
19
|
-
end
|
|
32
|
+
return error_no_gemspec unless File.exist?(@gemspec_path)
|
|
20
33
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
rescue StandardError => e
|
|
24
|
-
return [false, "Error loading gemspec: #{e.message}"]
|
|
25
|
-
end
|
|
34
|
+
spec = load_gemspec
|
|
35
|
+
return spec unless spec.is_a?(Gem::Specification)
|
|
26
36
|
|
|
27
37
|
gem_name = spec.name
|
|
28
|
-
output_file = "#{gem_name}_wrapped.txt"
|
|
38
|
+
@output_file = "#{gem_name}_wrapped.txt"
|
|
29
39
|
unstaged_files = check_unstaged_files
|
|
30
40
|
|
|
31
|
-
|
|
32
|
-
file.puts "# Wrapped Gem: #{gem_name}"
|
|
33
|
-
file.puts "## Gemspec: #{File.basename(@gemspec_path)}"
|
|
41
|
+
super()
|
|
34
42
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
file.puts unstaged_files.join("\n")
|
|
38
|
-
file.puts "\nThese files are not included in the wrap unless --include-unstaged option is used."
|
|
39
|
-
end
|
|
43
|
+
[true, @output_file, unstaged_files]
|
|
44
|
+
end
|
|
40
45
|
|
|
41
|
-
|
|
46
|
+
private
|
|
42
47
|
|
|
43
|
-
|
|
44
|
-
|
|
48
|
+
def collect_files_to_process
|
|
49
|
+
spec = load_gemspec
|
|
50
|
+
files_to_include = (spec.files +
|
|
51
|
+
spec.test_files +
|
|
52
|
+
find_readme_files).uniq
|
|
45
53
|
|
|
46
|
-
|
|
47
|
-
full_path = File.join(File.dirname(@gemspec_path), relative_path)
|
|
48
|
-
next unless File.file?(full_path)
|
|
54
|
+
files_to_include += check_unstaged_files if @include_unstaged
|
|
49
55
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
56
|
+
files_to_include.sort.uniq.reject do |relative_path|
|
|
57
|
+
should_exclude?(File.join(@base_dir, relative_path))
|
|
58
|
+
end.map do |relative_path|
|
|
59
|
+
File.join(@base_dir, relative_path)
|
|
54
60
|
end
|
|
61
|
+
end
|
|
55
62
|
|
|
56
|
-
|
|
63
|
+
def error_no_gemspec
|
|
64
|
+
[false, "Error: The specified gemspec file '#{@gemspec_path}' does not exist."]
|
|
57
65
|
end
|
|
58
66
|
|
|
59
|
-
|
|
67
|
+
def load_gemspec
|
|
68
|
+
Gem::Specification.load(@gemspec_path)
|
|
69
|
+
rescue StandardError => e
|
|
70
|
+
[false, "Error loading gemspec: #{e.message}"]
|
|
71
|
+
end
|
|
60
72
|
|
|
61
73
|
def find_readme_files
|
|
62
|
-
Dir.glob(File.join(File.dirname(@gemspec_path), "README*"))
|
|
63
|
-
|
|
74
|
+
Dir.glob(File.join(File.dirname(@gemspec_path), "README*")).map do |path|
|
|
75
|
+
Pathname.new(path).relative_path_from(
|
|
76
|
+
Pathname.new(File.dirname(@gemspec_path))
|
|
77
|
+
).to_s
|
|
78
|
+
end
|
|
64
79
|
end
|
|
65
80
|
|
|
66
81
|
def check_unstaged_files
|
data/lib/poepod/processor.rb
CHANGED
|
@@ -1,22 +1,123 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
require "yaml"
|
|
4
|
+
require "base64"
|
|
5
|
+
require "marcel"
|
|
6
|
+
require "stringio"
|
|
7
|
+
|
|
4
8
|
module Poepod
|
|
9
|
+
# Base processor class
|
|
5
10
|
class Processor
|
|
6
|
-
def initialize(
|
|
11
|
+
def initialize(
|
|
12
|
+
config_file = nil,
|
|
13
|
+
include_binary: false,
|
|
14
|
+
include_dot_files: false,
|
|
15
|
+
exclude: [],
|
|
16
|
+
base_dir: nil
|
|
17
|
+
)
|
|
7
18
|
@config = load_config(config_file)
|
|
19
|
+
@include_binary = include_binary
|
|
20
|
+
@include_dot_files = include_dot_files
|
|
21
|
+
@exclude = exclude || []
|
|
22
|
+
@base_dir = base_dir
|
|
23
|
+
@failed_files = []
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def process
|
|
27
|
+
files_to_process = collect_files_to_process
|
|
28
|
+
total_files, copied_files = process_files(files_to_process)
|
|
29
|
+
[total_files, copied_files]
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
private
|
|
33
|
+
|
|
34
|
+
def collect_files_to_process
|
|
35
|
+
raise NotImplementedError, "Subclasses must implement collect_files_to_process"
|
|
8
36
|
end
|
|
9
37
|
|
|
10
38
|
def load_config(config_file)
|
|
11
|
-
|
|
12
|
-
|
|
39
|
+
return {} unless config_file && File.exist?(config_file)
|
|
40
|
+
|
|
41
|
+
YAML.load_file(config_file)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def binary_file?(file_path)
|
|
45
|
+
return false unless File.exist?(file_path) && File.file?(file_path)
|
|
46
|
+
|
|
47
|
+
File.open(file_path, "rb") do |file|
|
|
48
|
+
content = file.read(8192) # Read first 8KB for magic byte detection
|
|
49
|
+
mime_type = Marcel::MimeType.for(content, name: File.basename(file_path), declared_type: "text/plain")
|
|
50
|
+
!mime_type.start_with?("text/") && mime_type != "application/json"
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def process_files(files)
|
|
55
|
+
total_files = files.size
|
|
56
|
+
copied_files = 0
|
|
57
|
+
|
|
58
|
+
File.open(@output_file, "w", encoding: "utf-8") do |output|
|
|
59
|
+
files.sort.each do |file_path|
|
|
60
|
+
process_file(output, file_path)
|
|
61
|
+
copied_files += 1
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
[total_files, copied_files]
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def process_file(output = nil, file_path)
|
|
69
|
+
output ||= StringIO.new
|
|
70
|
+
|
|
71
|
+
relative_path = if @base_dir
|
|
72
|
+
Pathname.new(file_path).relative_path_from(Pathname.new(@base_dir)).to_s
|
|
73
|
+
else
|
|
74
|
+
file_path
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
output.puts "--- START FILE: #{relative_path} ---"
|
|
78
|
+
|
|
79
|
+
if binary_file?(file_path) && @include_binary
|
|
80
|
+
output.puts encode_binary_file(file_path)
|
|
13
81
|
else
|
|
14
|
-
|
|
82
|
+
output.puts File.read(file_path)
|
|
15
83
|
end
|
|
84
|
+
|
|
85
|
+
output.puts "--- END FILE: #{relative_path} ---\n"
|
|
86
|
+
|
|
87
|
+
output.string if output.is_a?(StringIO) # Return the string if using StringIO
|
|
16
88
|
end
|
|
17
89
|
|
|
18
|
-
def
|
|
19
|
-
|
|
90
|
+
def encode_binary_file(file_path)
|
|
91
|
+
content = File.binread(file_path)
|
|
92
|
+
mime_type = Marcel::MimeType.for(content, name: File.basename(file_path))
|
|
93
|
+
encoded_content = Base64.strict_encode64(content)
|
|
94
|
+
<<~HERE
|
|
95
|
+
Content-Type: #{mime_type}
|
|
96
|
+
Content-Transfer-Encoding: base64
|
|
97
|
+
|
|
98
|
+
#{encoded_content}
|
|
99
|
+
HERE
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def dot_file?(file_path)
|
|
103
|
+
File.basename(file_path).start_with?(".")
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def should_exclude?(file_path)
|
|
107
|
+
return true if !@include_dot_files && dot_file?(file_path)
|
|
108
|
+
return true if !@include_binary && binary_file?(file_path)
|
|
109
|
+
|
|
110
|
+
exclude_file?(file_path)
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def exclude_file?(file_path)
|
|
114
|
+
@exclude.any? do |pattern|
|
|
115
|
+
if pattern.is_a?(Regexp)
|
|
116
|
+
file_path.match?(pattern)
|
|
117
|
+
else
|
|
118
|
+
File.fnmatch?(pattern, file_path)
|
|
119
|
+
end
|
|
120
|
+
end
|
|
20
121
|
end
|
|
21
122
|
end
|
|
22
123
|
end
|
data/lib/poepod/version.rb
CHANGED
data/poepod.gemspec
CHANGED
|
@@ -31,7 +31,7 @@ Gem::Specification.new do |spec|
|
|
|
31
31
|
spec.test_files = `git ls-files -- spec/*`.split("\n")
|
|
32
32
|
|
|
33
33
|
spec.add_runtime_dependency "git", "~> 1.11"
|
|
34
|
-
spec.add_runtime_dependency "
|
|
34
|
+
spec.add_runtime_dependency "marcel", "~> 1.0"
|
|
35
35
|
spec.add_runtime_dependency "parallel", "~> 1.20"
|
|
36
36
|
spec.add_runtime_dependency "thor", "~> 1.0"
|
|
37
37
|
spec.add_runtime_dependency "tqdm"
|
data/spec/poepod/cli_spec.rb
CHANGED
|
@@ -10,37 +10,62 @@ RSpec.describe Poepod::Cli do
|
|
|
10
10
|
let(:temp_dir) { Dir.mktmpdir }
|
|
11
11
|
let(:text_file) { File.join(temp_dir, "text_file.txt") }
|
|
12
12
|
let(:binary_file) { File.join(temp_dir, "binary_file.bin") }
|
|
13
|
+
let(:dot_file) { File.join(temp_dir, ".hidden_file") }
|
|
13
14
|
|
|
14
15
|
before do
|
|
15
16
|
File.write(text_file, "Hello, World!")
|
|
16
17
|
File.write(binary_file, [0xFF, 0xD8, 0xFF, 0xE0].pack("C*"))
|
|
18
|
+
File.write(dot_file, "Hidden content")
|
|
17
19
|
end
|
|
18
20
|
|
|
19
21
|
after do
|
|
20
22
|
FileUtils.remove_entry(temp_dir)
|
|
21
23
|
end
|
|
22
24
|
|
|
23
|
-
it "concatenates text files" do
|
|
25
|
+
it "concatenates text files and excludes binary and dot files by default" do
|
|
24
26
|
output_file = File.join(temp_dir, "output.txt")
|
|
25
|
-
expect
|
|
27
|
+
expect do
|
|
28
|
+
cli.invoke(:concat, [File.join(temp_dir, "*")], { output_file: output_file })
|
|
29
|
+
end.to output(/1 files detected\.\n.*1 files have been concatenated/).to_stdout
|
|
26
30
|
expect(File.exist?(output_file)).to be true
|
|
27
|
-
|
|
31
|
+
content = File.read(output_file)
|
|
32
|
+
expect(content).to include("Hello, World!")
|
|
33
|
+
expect(content).not_to include("Hidden content")
|
|
28
34
|
end
|
|
29
35
|
|
|
30
|
-
it "
|
|
36
|
+
it "includes binary files when specified" do
|
|
31
37
|
output_file = File.join(temp_dir, "output.txt")
|
|
32
38
|
expect do
|
|
33
|
-
cli.concat(
|
|
34
|
-
|
|
35
|
-
|
|
39
|
+
cli.invoke(:concat, [File.join(temp_dir, "*")], { output_file: output_file, include_binary: true })
|
|
40
|
+
end.to output(/2 files detected\.\n.*2 files have been concatenated/).to_stdout
|
|
41
|
+
expect(File.exist?(output_file)).to be true
|
|
42
|
+
content = File.read(output_file)
|
|
43
|
+
expect(content).to include("Hello, World!")
|
|
44
|
+
expect(content).to include("Content-Type: image/jpeg")
|
|
36
45
|
end
|
|
37
46
|
|
|
38
|
-
it "includes
|
|
47
|
+
it "includes dot files when specified" do
|
|
39
48
|
output_file = File.join(temp_dir, "output.txt")
|
|
40
49
|
expect do
|
|
41
|
-
cli.invoke(:concat, [
|
|
42
|
-
|
|
43
|
-
|
|
50
|
+
cli.invoke(:concat, [File.join(temp_dir, "*")], { output_file: output_file, include_dot_files: true })
|
|
51
|
+
end.to output(/2 files detected\.\n.*2 files have been concatenated/).to_stdout
|
|
52
|
+
expect(File.exist?(output_file)).to be true
|
|
53
|
+
content = File.read(output_file)
|
|
54
|
+
expect(content).to include("Hello, World!")
|
|
55
|
+
expect(content).to include("Hidden content")
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
it "uses the specified base directory for relative paths" do
|
|
59
|
+
output_file = File.join(temp_dir, "output.txt")
|
|
60
|
+
base_dir = File.dirname(text_file)
|
|
61
|
+
expect do
|
|
62
|
+
cli.invoke(:concat, [File.join(temp_dir, "*")], { output_file: output_file, base_dir: base_dir })
|
|
63
|
+
end.to output(/1 files detected\.\n.*1 files have been concatenated/).to_stdout
|
|
64
|
+
expect(File.exist?(output_file)).to be true
|
|
65
|
+
content = File.read(output_file)
|
|
66
|
+
expect(content).to include("--- START FILE: text_file.txt ---")
|
|
67
|
+
expect(content).to include("Hello, World!")
|
|
68
|
+
expect(content).to include("--- END FILE: text_file.txt ---")
|
|
44
69
|
end
|
|
45
70
|
end
|
|
46
71
|
|
|
@@ -74,8 +99,6 @@ RSpec.describe Poepod::Cli do
|
|
|
74
99
|
output_file = File.join(Dir.pwd, "test_gem_wrapped.txt")
|
|
75
100
|
expect(File.exist?(output_file)).to be true
|
|
76
101
|
content = File.read(output_file)
|
|
77
|
-
expect(content).to include("# Wrapped Gem: test_gem")
|
|
78
|
-
expect(content).to include("## Gemspec: test_gem.gemspec")
|
|
79
102
|
expect(content).to include("--- START FILE: lib/test_gem.rb ---")
|
|
80
103
|
expect(content).to include("puts 'Hello from test_gem'")
|
|
81
104
|
expect(content).to include("--- END FILE: lib/test_gem.rb ---")
|
|
@@ -86,5 +109,18 @@ RSpec.describe Poepod::Cli do
|
|
|
86
109
|
cli.wrap("non_existent.gemspec")
|
|
87
110
|
end.to output(/Error: The specified gemspec file/).to_stdout.and raise_error(SystemExit)
|
|
88
111
|
end
|
|
112
|
+
|
|
113
|
+
it "uses the specified base directory for relative paths" do
|
|
114
|
+
base_dir = File.dirname(gemspec_file)
|
|
115
|
+
expect do
|
|
116
|
+
cli.invoke(:wrap, [gemspec_file], { base_dir: base_dir })
|
|
117
|
+
end.to output(/The gem has been wrapped into/).to_stdout
|
|
118
|
+
output_file = File.join(Dir.pwd, "test_gem_wrapped.txt")
|
|
119
|
+
expect(File.exist?(output_file)).to be true
|
|
120
|
+
content = File.read(output_file)
|
|
121
|
+
expect(content).to include("--- START FILE: lib/test_gem.rb ---")
|
|
122
|
+
expect(content).to include("puts 'Hello from test_gem'")
|
|
123
|
+
expect(content).to include("--- END FILE: lib/test_gem.rb ---")
|
|
124
|
+
end
|
|
89
125
|
end
|
|
90
126
|
end
|
|
@@ -11,11 +11,13 @@ RSpec.describe Poepod::FileProcessor do
|
|
|
11
11
|
let(:text_file1) { File.join(temp_dir, "file1.txt") }
|
|
12
12
|
let(:text_file2) { File.join(temp_dir, "file2.txt") }
|
|
13
13
|
let(:binary_file) { File.join(temp_dir, "binary_file.bin") }
|
|
14
|
+
let(:dot_file) { File.join(temp_dir, ".hidden_file") }
|
|
14
15
|
|
|
15
16
|
before do
|
|
16
17
|
File.write(text_file1, "Content of file1.\n")
|
|
17
18
|
File.write(text_file2, "Content of file2.\n")
|
|
18
19
|
File.write(binary_file, [0xFF, 0xD8, 0xFF, 0xE0].pack("C*"))
|
|
20
|
+
File.write(dot_file, "Content of hidden file.\n")
|
|
19
21
|
end
|
|
20
22
|
|
|
21
23
|
after do
|
|
@@ -23,41 +25,126 @@ RSpec.describe Poepod::FileProcessor do
|
|
|
23
25
|
output_file.unlink
|
|
24
26
|
end
|
|
25
27
|
|
|
26
|
-
let(:processor) { described_class.new([text_file1, text_file2], output_file.path) }
|
|
27
|
-
|
|
28
28
|
describe "#process" do
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
29
|
+
context "with default options" do
|
|
30
|
+
let(:processor) { described_class.new([File.join(temp_dir, "*")], output_file.path) }
|
|
31
|
+
|
|
32
|
+
it "processes text files and excludes binary and dot files" do
|
|
33
|
+
total_files, copied_files = processor.process
|
|
34
|
+
expect(total_files).to eq(2)
|
|
35
|
+
expect(copied_files).to eq(2)
|
|
36
|
+
|
|
37
|
+
output_content = File.read(output_file.path, encoding: "utf-8")
|
|
38
|
+
expected_content = <<~TEXT
|
|
39
|
+
--- START FILE: #{text_file1} ---
|
|
40
|
+
Content of file1.
|
|
41
|
+
--- END FILE: #{text_file1} ---
|
|
42
|
+
--- START FILE: #{text_file2} ---
|
|
43
|
+
Content of file2.
|
|
44
|
+
--- END FILE: #{text_file2} ---
|
|
45
|
+
TEXT
|
|
46
|
+
expect(output_content).to eq(expected_content)
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
context "with include_binary option" do
|
|
51
|
+
let(:processor) { described_class.new([File.join(temp_dir, "*")], output_file.path, include_binary: true) }
|
|
52
|
+
|
|
53
|
+
it "includes binary files" do
|
|
54
|
+
total_files, copied_files = processor.process
|
|
55
|
+
expect(total_files).to eq(3)
|
|
56
|
+
expect(copied_files).to eq(3)
|
|
57
|
+
|
|
58
|
+
output_content = File.read(output_file.path, encoding: "utf-8")
|
|
59
|
+
expected_content = <<~TEXT
|
|
60
|
+
--- START FILE: #{binary_file} ---
|
|
61
|
+
Content-Type: image/jpeg
|
|
62
|
+
Content-Transfer-Encoding: base64
|
|
63
|
+
|
|
64
|
+
/9j/4A==
|
|
65
|
+
--- END FILE: #{binary_file} ---
|
|
66
|
+
--- START FILE: #{text_file1} ---
|
|
67
|
+
Content of file1.
|
|
68
|
+
--- END FILE: #{text_file1} ---
|
|
69
|
+
--- START FILE: #{text_file2} ---
|
|
70
|
+
Content of file2.
|
|
71
|
+
--- END FILE: #{text_file2} ---
|
|
72
|
+
TEXT
|
|
73
|
+
expect(output_content).to eq(expected_content)
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
context "with include_dot_files option" do
|
|
78
|
+
let(:processor) { described_class.new([File.join(temp_dir, "*")], output_file.path, include_dot_files: true) }
|
|
79
|
+
|
|
80
|
+
it "includes dot files" do
|
|
81
|
+
total_files, copied_files = processor.process
|
|
82
|
+
expect(total_files).to eq(3)
|
|
83
|
+
expect(copied_files).to eq(3)
|
|
84
|
+
|
|
85
|
+
output_content = File.read(output_file.path, encoding: "utf-8")
|
|
86
|
+
expected_content = <<~TEXT
|
|
87
|
+
--- START FILE: #{dot_file} ---
|
|
88
|
+
Content of hidden file.
|
|
89
|
+
--- END FILE: #{dot_file} ---
|
|
90
|
+
--- START FILE: #{text_file1} ---
|
|
91
|
+
Content of file1.
|
|
92
|
+
--- END FILE: #{text_file1} ---
|
|
93
|
+
--- START FILE: #{text_file2} ---
|
|
94
|
+
Content of file2.
|
|
95
|
+
--- END FILE: #{text_file2} ---
|
|
96
|
+
TEXT
|
|
97
|
+
expect(output_content).to eq(expected_content)
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
context "with both include_binary and include_dot_files options" do
|
|
102
|
+
let(:processor) do
|
|
103
|
+
described_class.new([File.join(temp_dir, "*")], output_file.path, include_binary: true, include_dot_files: true)
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
it "includes all files in sorted order" do
|
|
107
|
+
total_files, copied_files = processor.process
|
|
108
|
+
expect(total_files).to eq(4)
|
|
109
|
+
expect(copied_files).to eq(4)
|
|
110
|
+
|
|
111
|
+
output_content = File.read(output_file.path, encoding: "utf-8")
|
|
112
|
+
expected_content = <<~HERE
|
|
113
|
+
--- START FILE: #{dot_file} ---
|
|
114
|
+
Content of hidden file.
|
|
115
|
+
--- END FILE: #{dot_file} ---
|
|
116
|
+
--- START FILE: #{binary_file} ---
|
|
117
|
+
Content-Type: image/jpeg
|
|
118
|
+
Content-Transfer-Encoding: base64
|
|
119
|
+
|
|
120
|
+
/9j/4A==
|
|
121
|
+
--- END FILE: #{binary_file} ---
|
|
122
|
+
--- START FILE: #{text_file1} ---
|
|
123
|
+
Content of file1.
|
|
124
|
+
--- END FILE: #{text_file1} ---
|
|
125
|
+
--- START FILE: #{text_file2} ---
|
|
126
|
+
Content of file2.
|
|
127
|
+
--- END FILE: #{text_file2} ---
|
|
128
|
+
HERE
|
|
129
|
+
|
|
130
|
+
expect(output_content).to eq(expected_content)
|
|
131
|
+
end
|
|
44
132
|
end
|
|
45
133
|
end
|
|
46
134
|
|
|
47
135
|
describe "#process_file" do
|
|
136
|
+
let(:processor) { described_class.new([text_file1], output_file.path) }
|
|
137
|
+
|
|
48
138
|
it "reads the content of a file" do
|
|
49
|
-
|
|
50
|
-
expect(
|
|
51
|
-
expect(content).to eq("Content of file1.\n")
|
|
52
|
-
expect(error).to be_nil
|
|
139
|
+
content = processor.send(:process_file, nil, text_file1)
|
|
140
|
+
expect(content).to include("Content of file1.\n")
|
|
53
141
|
end
|
|
54
142
|
|
|
55
143
|
it "handles encoding errors gracefully" do
|
|
56
144
|
allow(File).to receive(:read).and_raise(Encoding::InvalidByteSequenceError)
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
expect(error).to eq("Failed to decode the file, as it is not saved with UTF-8 encoding.")
|
|
145
|
+
expect do
|
|
146
|
+
processor.send(:process_file, nil, text_file1)
|
|
147
|
+
end.to raise_error(Encoding::InvalidByteSequenceError)
|
|
61
148
|
end
|
|
62
149
|
end
|
|
63
150
|
end
|
|
@@ -40,26 +40,42 @@ RSpec.describe Poepod::GemProcessor do
|
|
|
40
40
|
allow(Git).to receive(:open).and_return(double(status: double(untracked: {}, changed: {})))
|
|
41
41
|
end
|
|
42
42
|
|
|
43
|
-
it "processes the gem files, includes README files, and spec files" do
|
|
43
|
+
it "processes the gem files, includes README files, and spec files in sorted order" do
|
|
44
44
|
success, output_file = processor.process
|
|
45
45
|
expect(success).to be true
|
|
46
46
|
expect(File.exist?(output_file)).to be true
|
|
47
47
|
|
|
48
48
|
content = File.read(output_file)
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
expect(
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
49
|
+
|
|
50
|
+
file_order = content.scan(/--- START FILE: (.+) ---/).flatten
|
|
51
|
+
expected_order = [
|
|
52
|
+
"README.md",
|
|
53
|
+
"README.txt",
|
|
54
|
+
"lib/test_gem.rb",
|
|
55
|
+
"spec/test_gem_spec.rb"
|
|
56
|
+
]
|
|
57
|
+
expect(file_order).to eq(expected_order)
|
|
58
|
+
|
|
59
|
+
expected = <<~HERE
|
|
60
|
+
--- START FILE: README.md ---
|
|
61
|
+
# Test Gem
|
|
62
|
+
|
|
63
|
+
This is a test gem.
|
|
64
|
+
--- END FILE: README.md ---
|
|
65
|
+
--- START FILE: README.txt ---
|
|
66
|
+
Test Gem
|
|
67
|
+
|
|
68
|
+
This is a test gem in plain text.
|
|
69
|
+
--- END FILE: README.txt ---
|
|
70
|
+
--- START FILE: lib/test_gem.rb ---
|
|
71
|
+
puts 'Hello from test_gem'
|
|
72
|
+
--- END FILE: lib/test_gem.rb ---
|
|
73
|
+
--- START FILE: spec/test_gem_spec.rb ---
|
|
74
|
+
RSpec.describe TestGem do
|
|
75
|
+
end
|
|
76
|
+
--- END FILE: spec/test_gem_spec.rb ---
|
|
77
|
+
HERE
|
|
78
|
+
expect(content).to eq(expected)
|
|
63
79
|
end
|
|
64
80
|
|
|
65
81
|
context "with non-existent gemspec" do
|
|
@@ -73,28 +89,21 @@ RSpec.describe Poepod::GemProcessor do
|
|
|
73
89
|
end
|
|
74
90
|
|
|
75
91
|
context "with unstaged files" do
|
|
92
|
+
let(:processor) { described_class.new(gemspec_file, include_unstaged: false) }
|
|
76
93
|
let(:mock_git) { instance_double(Git::Base) }
|
|
77
94
|
let(:mock_status) { instance_double(Git::Status) }
|
|
78
95
|
|
|
79
96
|
before do
|
|
80
97
|
allow(Git).to receive(:open).and_return(mock_git)
|
|
81
98
|
allow(mock_git).to receive(:status).and_return(mock_status)
|
|
82
|
-
allow(mock_status).to receive(:untracked).and_return(
|
|
99
|
+
allow(mock_status).to receive(:untracked).and_return(
|
|
100
|
+
{ "lib/unstaged_file.rb" => "??" }
|
|
101
|
+
)
|
|
83
102
|
allow(mock_status).to receive(:changed).and_return({})
|
|
84
103
|
end
|
|
85
104
|
|
|
86
|
-
it "warns about unstaged files" do
|
|
87
|
-
success, output_file, unstaged_files = processor.process
|
|
88
|
-
expect(success).to be true
|
|
89
|
-
expect(unstaged_files).to eq(["lib/unstaged_file.rb"])
|
|
90
|
-
|
|
91
|
-
content = File.read(output_file)
|
|
92
|
-
expect(content).to include("## Warning: Unstaged Files")
|
|
93
|
-
expect(content).to include("lib/unstaged_file.rb")
|
|
94
|
-
end
|
|
95
|
-
|
|
96
105
|
context "with include_unstaged option" do
|
|
97
|
-
let(:processor) { described_class.new(gemspec_file,
|
|
106
|
+
let(:processor) { described_class.new(gemspec_file, include_unstaged: true) }
|
|
98
107
|
|
|
99
108
|
it "includes unstaged files" do
|
|
100
109
|
allow(File).to receive(:file?).and_return(true)
|
|
@@ -115,17 +124,13 @@ RSpec.describe Poepod::GemProcessor do
|
|
|
115
124
|
file_contents[file_name]
|
|
116
125
|
elsif path.end_with?("_wrapped.txt")
|
|
117
126
|
# This is the output file, so we'll construct its content here
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
wrapped_content += "#{content}\n"
|
|
126
|
-
wrapped_content += "--- END FILE: #{file} ---\n\n"
|
|
127
|
-
end
|
|
128
|
-
wrapped_content
|
|
127
|
+
file_contents.map do |file, content|
|
|
128
|
+
<<~HERE
|
|
129
|
+
--- START FILE: #{file} ---
|
|
130
|
+
#{content}
|
|
131
|
+
--- END FILE: #{file} ---
|
|
132
|
+
HERE
|
|
133
|
+
end.join("")
|
|
129
134
|
else
|
|
130
135
|
"Default content for #{path}"
|
|
131
136
|
end
|
|
@@ -136,21 +141,29 @@ RSpec.describe Poepod::GemProcessor do
|
|
|
136
141
|
expect(unstaged_files).to eq(["lib/unstaged_file.rb"])
|
|
137
142
|
|
|
138
143
|
content = File.read(output_file)
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
144
|
+
expected = <<~HERE
|
|
145
|
+
--- START FILE: lib/test_gem.rb ---
|
|
146
|
+
puts 'Hello from test_gem'
|
|
147
|
+
--- END FILE: lib/test_gem.rb ---
|
|
148
|
+
--- START FILE: spec/test_gem_spec.rb ---
|
|
149
|
+
RSpec.describe TestGem do
|
|
150
|
+
end
|
|
151
|
+
--- END FILE: spec/test_gem_spec.rb ---
|
|
152
|
+
--- START FILE: README.md ---
|
|
153
|
+
# Test Gem
|
|
154
|
+
|
|
155
|
+
This is a test gem.
|
|
156
|
+
--- END FILE: README.md ---
|
|
157
|
+
--- START FILE: README.txt ---
|
|
158
|
+
Test Gem
|
|
159
|
+
|
|
160
|
+
This is a test gem in plain text.
|
|
161
|
+
--- END FILE: README.txt ---
|
|
162
|
+
--- START FILE: lib/unstaged_file.rb ---
|
|
163
|
+
Unstaged content
|
|
164
|
+
--- END FILE: lib/unstaged_file.rb ---
|
|
165
|
+
HERE
|
|
166
|
+
expect(content).to eq(expected)
|
|
154
167
|
end
|
|
155
168
|
end
|
|
156
169
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: poepod
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.6
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ribose Inc.
|
|
@@ -25,19 +25,19 @@ dependencies:
|
|
|
25
25
|
- !ruby/object:Gem::Version
|
|
26
26
|
version: '1.11'
|
|
27
27
|
- !ruby/object:Gem::Dependency
|
|
28
|
-
name:
|
|
28
|
+
name: marcel
|
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
|
30
30
|
requirements:
|
|
31
31
|
- - "~>"
|
|
32
32
|
- !ruby/object:Gem::Version
|
|
33
|
-
version: '
|
|
33
|
+
version: '1.0'
|
|
34
34
|
type: :runtime
|
|
35
35
|
prerelease: false
|
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
|
37
37
|
requirements:
|
|
38
38
|
- - "~>"
|
|
39
39
|
- !ruby/object:Gem::Version
|
|
40
|
-
version: '
|
|
40
|
+
version: '1.0'
|
|
41
41
|
- !ruby/object:Gem::Dependency
|
|
42
42
|
name: parallel
|
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|