poepod 0.1.3 → 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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c54370c2df957654eb4ae1fea362455f862164a7f96fd1b8fd538b86464f57d1
4
- data.tar.gz: 98719e8e94e7da6010cd468c5dcb6c695ae0a4700f35a4436c99ba060265d2ae
3
+ metadata.gz: b205fe50c5830d75893fbfa378b81984bf8a2b73fa8d104509fbbf698e0001fc
4
+ data.tar.gz: d4e87cef72c92cdcfaadd6bcf5a452bc1a05b13c4927cce10b6c81250ff99c9c
5
5
  SHA512:
6
- metadata.gz: 3d81a22b7571bbb1212b43089c4ca8e6e60cfe0a32228fce9116cab97c0b347ac9d3a2b8ccfb752a4b409537f6ce4841f535266c9a7b69e25a27a82d5139691a
7
- data.tar.gz: a96111a90ab4583e043ba316dd08ccf1b3e5530e4ad68f883c9b4626a612adb0ff5e890ab5e688062ff84d4fa26c0fd7619d3210f2d3cea8ddcc9eba99f4ca5e
6
+ metadata.gz: c32f1ffb23fcf86f8cd1625c1deab4dc3599a0baf7b4ad80618f1e37a23f7b8e815b6065d628bf138f0e8ca9c2c849d1a08c31599737bee85711a6b4cd3e88f0
7
+ data.tar.gz: bdc4de92b51c89cfbeb484a119ce829e8a5c0a7768a032f4ec4299b06f2b35724038b13a2093827fbe839c650c0a18902c544ddd85f842e47ab4e633089edb38
@@ -1,5 +1,3 @@
1
- # Auto-generated by Cimas: Do not edit it manually!
2
- # See https://github.com/metanorma/cimas
3
1
  name: rake
4
2
 
5
3
  on:
@@ -7,9 +5,8 @@ on:
7
5
  branches: [ master, main ]
8
6
  tags: [ v* ]
9
7
  pull_request:
8
+ workflow_dispatch:
10
9
 
11
10
  jobs:
12
11
  rake:
13
12
  uses: metanorma/ci/.github/workflows/generic-rake.yml@main
14
- secrets:
15
- pat_token: ${{ secrets.METANORMA_CI_PAT_TOKEN }}
@@ -1,5 +1,3 @@
1
- # Auto-generated by Cimas: Do not edit it manually!
2
- # See https://github.com/metanorma/cimas
3
1
  name: release
4
2
 
5
3
  on:
@@ -10,8 +8,8 @@ on:
10
8
  Next release version. Possible values: x.y.z, major, minor, patch or pre|rc|etc
11
9
  required: true
12
10
  default: 'skip'
13
- repository_dispatch:
14
- types: [ do-release ]
11
+ push:
12
+ tags: [ v* ]
15
13
 
16
14
  jobs:
17
15
  release:
@@ -19,5 +17,6 @@ jobs:
19
17
  with:
20
18
  next_version: ${{ github.event.inputs.next_version }}
21
19
  secrets:
22
- rubygems-api-key: ${{ secrets.METANORMA_CI_RUBYGEMS_API_KEY }}
23
- pat_token: ${{ secrets.METANORMA_CI_PAT_TOKEN }}
20
+ rubygems-api-key: ${{ secrets.RIBOSE_RUBYGEMS_API_KEY }}
21
+ pat_token: ${{ secrets.RIBOSE_CI_PAT_TOKEN }}
22
+
data/README.adoc CHANGED
@@ -1,7 +1,10 @@
1
1
  = Poepod
2
2
 
3
- Poepod is a Ruby gem that provides functionality to concatenate code files from
4
- a directory into one text file for analysis by Poe.
3
+ Poepod is a Ruby gem that streamlines the process of preparing code for analysis
4
+ by Poe. It offers two main features: concatenating multiple files into a single
5
+ text file, and wrapping gem contents including unstaged files. These features
6
+ are particularly useful for developers who want to quickly gather code for
7
+ review, analysis, or submission to AI-powered coding assistants.
5
8
 
6
9
  == Installation
7
10
 
@@ -28,49 +31,139 @@ $ gem install poepod
28
31
 
29
32
  == Usage
30
33
 
31
- After installation, you can use the `poepod` command line tool to concatenate
32
- code files:
34
+ After installation, you can use the `poepod` command line tool:
33
35
 
34
36
  [source,shell]
35
37
  ----
36
38
  $ poepod help
37
39
  Commands:
38
- poepod concat DIRECTORY OUTPUT_FILE # Concatenate code from a directory into one text file
39
- poepod help [COMMAND] # Describe available commands or one specific command
40
+ poepod concat FILES [OUTPUT_FILE] # Concatenate specified files into one text file
41
+ poepod help [COMMAND] # Describe available commands or one specific command
42
+ poepod wrap GEMSPEC_PATH # Wrap a gem based on its gemspec file
43
+ ----
44
+
45
+ === Global options
46
+
47
+ All options can be used for both `wrap` and `concat` commands:
40
48
 
41
- $ poepod help concat
42
- Usage:
43
- poepod concat DIRECTORY OUTPUT_FILE
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)
44
56
 
45
- Options:
46
- [--exclude=one two three] # List of patterns to exclude
47
- # Default: "node_modules/" ".git/" "build" "test" ".gitignore" ".DS_Store" "*.jpg" "*.jpeg" "*.png" "*.svg" "*.gif" "*.exe" "*.dll" "*.so" "*.bin" "*.o" "*.a"
48
- [--config=CONFIG] # Path to configuration file
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
+ ----
49
62
 
50
- Concatenate code from a directory into one text file
63
+ === Concatenating files
64
+
65
+ The `concat` command allows you to combine multiple files into a single text
66
+ file.
67
+
68
+ This is particularly useful when you want to review or analyze code from
69
+ multiple files in one place, or when preparing code submissions for AI-powered
70
+ coding assistants.
71
+
72
+ By default, it excludes binary files, dot files, and certain patterns like
73
+ `node_modules/` and `.git/`.
74
+
75
+ [source,shell]
51
76
  ----
77
+ $ poepod concat path/to/files/* output.txt
78
+ ----
79
+
80
+ This will concatenate all non-binary, non-dot files from the specified path into
81
+ `output.txt`.
82
+
83
+ ==== Including dot files
52
84
 
53
- For example:
85
+ By default, dot files (hidden files starting with a dot) are excluded.
86
+
87
+ To include them, use the `--include-dot-files` option:
54
88
 
55
89
  [source,shell]
56
90
  ----
57
- $ poepod concat my_project
58
- # => concatenated into my_project.txt
91
+ $ poepod concat path/to/files/* output.txt --include-dot-files
59
92
  ----
60
93
 
61
- This will concatenate all code files from the specified directory into `output.txt`.
94
+ ==== Including binary files
95
+
96
+ By default, binary files are excluded to keep the output focused on readable
97
+ code.
62
98
 
63
- You can also exclude certain directories or files by using the `--exclude` option:
99
+ To include binary files (encoded in MIME format), use the `--include-binary`
100
+ option:
64
101
 
65
102
  [source,shell]
66
103
  ----
67
- $ poepod concat my_project output.txt --exclude node_modules .git build test .gitignore .DS_Store .jpg .png .svg
104
+ $ poepod concat path/to/files/* output.txt --include-binary
105
+ ----
106
+
107
+ This can be useful when you need to include binary assets or compiled files in
108
+ your analysis.
109
+
110
+ ==== Excluding patterns
111
+
112
+ You can exclude certain patterns using the `--exclude` option:
113
+
114
+ [source,shell]
68
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
+
122
+ === Wrapping a gem
123
+
124
+ The `wrap` command creates a comprehensive snapshot of your gem, including all
125
+ files specified in the gemspec and README files. This is particularly useful for
126
+ gem developers who want to review their entire gem contents or prepare it for
127
+ submission to code review tools.
128
+
129
+ [source,shell]
130
+ ----
131
+ $ poepod wrap path/to/your_gem.gemspec
132
+ ----
133
+
134
+ This will create a file named `your_gem_wrapped.txt` containing all the files
135
+ specified in the gemspec, including README files.
136
+
137
+ ==== Handling unstaged files
138
+
139
+ By default, unstaged files in the `lib/`, `spec/`, and `test/` directories are
140
+ not included in the wrap, but they will be listed as a warning. This default
141
+ behavior ensures that the wrapped content matches what's currently tracked in
142
+ your version control system.
143
+
144
+ However, there are cases where including unstaged files can be beneficial:
145
+
146
+ . When you're actively developing and want to include recent changes that
147
+ haven't been committed yet.
148
+
149
+ . When you're seeking feedback on work-in-progress code.
150
+
151
+ . When you want to ensure you're not missing any important files in your commit.
152
+
153
+ To include these unstaged files in the wrap:
154
+
155
+ [source,shell]
156
+ ----
157
+ $ poepod wrap path/to/your_gem.gemspec --include-unstaged
158
+ ----
159
+
160
+ This option allows you to capture a true snapshot of your gem's current state,
161
+ including any work in progress.
69
162
 
70
163
  == Development
71
164
 
72
165
  After checking out the repo, run `bin/setup` to install dependencies. Then, run
73
- `rake test` to run the tests. You can also run `bin/console` for an interactive
166
+ `rake spec` to run the tests. You can also run `bin/console` for an interactive
74
167
  prompt that will allow you to experiment.
75
168
 
76
169
  To install this gem onto your local machine, run `bundle exec rake install`. To
@@ -81,4 +174,5 @@ https://rubygems.org.
81
174
 
82
175
  == Contributing
83
176
 
84
- Bug reports and pull requests are welcome on GitHub at https://github.com/riboseinc/poepod.
177
+ Bug reports and pull requests are welcome on GitHub at https://github.com/riboseinc/poepod.
178
+ Please adhere to the link:CODE_OF_CONDUCT.md[code of conduct].
data/lib/poepod/cli.rb CHANGED
@@ -1,36 +1,125 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # lib/poepod/cli.rb
3
4
  require "thor"
4
- require_relative "processor"
5
+ require_relative "file_processor"
6
+ require_relative "gem_processor"
5
7
 
6
8
  module Poepod
9
+ # Command-line interface for Poepod
7
10
  class Cli < Thor
8
- desc "concat DIRECTORY OUTPUT_FILE", "Concatenate code from a directory into one text file"
9
- option :exclude, type: :array, default: Poepod::Processor::EXCLUDE_DEFAULT, desc: "List of patterns to exclude"
10
- option :config, type: :string, desc: "Path to configuration file"
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
21
+
22
+ desc "concat FILES [OUTPUT_FILE]", "Concatenate specified files into one text file"
23
+ shared_options
24
+
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)
30
+ end
11
31
 
12
- def concat(directory, output_file = nil)
13
- dir_path = Pathname.new(directory)
32
+ desc "wrap GEMSPEC_PATH", "Wrap a gem based on its gemspec file"
33
+ shared_options
34
+ option :include_unstaged, type: :boolean, default: false,
35
+ desc: "Include unstaged files from lib, spec, and test directories"
14
36
 
15
- # Check if the directory exists
16
- unless dir_path.directory?
17
- puts "Error: Directory '#{directory}' does not exist."
37
+ def wrap(gemspec_path)
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
+ )
48
+ success, result, unstaged_files = processor.process
49
+ if success
50
+ handle_wrap_result(success, result, unstaged_files)
51
+ else
52
+ puts result
18
53
  exit(1)
19
54
  end
55
+ end
56
+
57
+ def self.exit_on_failure?
58
+ true
59
+ end
20
60
 
21
- dir_path = dir_path.expand_path unless dir_path.absolute?
61
+ private
22
62
 
23
- output_file ||= "#{dir_path.basename}.txt"
24
- output_path = dir_path.dirname.join(output_file)
25
- processor = Poepod::Processor.new(options[:config])
26
- total_files, copied_files = processor.write_directory_structure_to_file(directory, output_path, options[:exclude])
63
+ def check_files(files)
64
+ return unless files.empty?
27
65
 
28
- puts "-> #{total_files} files detected in the #{dir_path.relative_path_from(Dir.pwd)} directory."
29
- puts "=> #{copied_files} files have been concatenated into #{Pathname.new(output_path).relative_path_from(Dir.pwd)}."
66
+ puts "Error: No files specified."
67
+ exit(1)
30
68
  end
31
69
 
32
- def self.exit_on_failure?
33
- true
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
+
111
+ def default_output_file(first_pattern)
112
+ first_item = Dir.glob(first_pattern).first
113
+ if first_item
114
+ if File.directory?(first_item)
115
+ "#{File.basename(first_item)}.txt"
116
+ else
117
+ "#{File.basename(first_item,
118
+ ".*")}_concat.txt"
119
+ end
120
+ else
121
+ "concatenated_output.txt"
122
+ end
34
123
  end
35
124
  end
36
125
  end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "processor"
4
+
5
+ module Poepod
6
+ # Processes files for concatenation, handling binary and dot files
7
+ class FileProcessor < Processor
8
+ EXCLUDE_DEFAULT = [
9
+ %r{node_modules/}, %r{.git/}, /.gitignore$/, /.DS_Store$/, /^\..+/
10
+ ].freeze
11
+
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
+ )
28
+ @files = files
29
+ @output_file = output_file
30
+ end
31
+
32
+ private
33
+
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)
39
+
40
+ files_to_process << matched_file
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,96 @@
1
+ # frozen_string_literal: true
2
+
3
+ # lib/poepod/gem_processor.rb
4
+ require_relative "processor"
5
+ require "rubygems/specification"
6
+ require "git"
7
+
8
+ module Poepod
9
+ # Processes gem files for wrapping, handling unstaged files
10
+ class GemProcessor < Processor
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
+ )
27
+ @gemspec_path = gemspec_path
28
+ @include_unstaged = include_unstaged
29
+ end
30
+
31
+ def process
32
+ return error_no_gemspec unless File.exist?(@gemspec_path)
33
+
34
+ spec = load_gemspec
35
+ return spec unless spec.is_a?(Gem::Specification)
36
+
37
+ gem_name = spec.name
38
+ @output_file = "#{gem_name}_wrapped.txt"
39
+ unstaged_files = check_unstaged_files
40
+
41
+ super()
42
+
43
+ [true, @output_file, unstaged_files]
44
+ end
45
+
46
+ private
47
+
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
53
+
54
+ files_to_include += check_unstaged_files if @include_unstaged
55
+
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)
60
+ end
61
+ end
62
+
63
+ def error_no_gemspec
64
+ [false, "Error: The specified gemspec file '#{@gemspec_path}' does not exist."]
65
+ end
66
+
67
+ def load_gemspec
68
+ Gem::Specification.load(@gemspec_path)
69
+ rescue StandardError => e
70
+ [false, "Error loading gemspec: #{e.message}"]
71
+ end
72
+
73
+ def find_readme_files
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
79
+ end
80
+
81
+ def check_unstaged_files
82
+ gem_root = File.dirname(@gemspec_path)
83
+ git = Git.open(gem_root)
84
+
85
+ untracked_files = git.status.untracked.keys
86
+ modified_files = git.status.changed.keys
87
+
88
+ (untracked_files + modified_files).select do |file|
89
+ file.start_with?("lib/", "spec/", "test/")
90
+ end
91
+ rescue Git::GitExecuteError => e
92
+ warn "Git error: #{e.message}. Assuming no unstaged files."
93
+ []
94
+ end
95
+ end
96
+ end
@@ -1,86 +1,123 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "yaml"
4
- require "tqdm"
5
- require "pathname"
4
+ require "base64"
5
+ require "marcel"
6
+ require "stringio"
6
7
 
7
8
  module Poepod
9
+ # Base processor class
8
10
  class Processor
9
- EXCLUDE_DEFAULT = [
10
- /node_modules\//, /.git\//, /.gitignore$/, /.DS_Store$/,
11
- /.jpg$/, /.jpeg$/, /.png/, /.svg$/, /.gif$/,
12
- /.exe$/, /.dll$/, /.so$/, /.bin$/, /.o$/, /.a$/, /.gem$/, /.cap$/,
13
- /.zip$/,
14
- ].freeze
15
-
16
- def initialize(config_file = nil)
17
- @failed_files = []
11
+ def initialize(
12
+ config_file = nil,
13
+ include_binary: false,
14
+ include_dot_files: false,
15
+ exclude: [],
16
+ base_dir: nil
17
+ )
18
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 = []
19
24
  end
20
25
 
21
- def load_config(config_file)
22
- if config_file && File.exist?(config_file)
23
- YAML.load_file(config_file)
24
- else
25
- {}
26
- end
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]
27
30
  end
28
31
 
29
- def process_file(file_path)
30
- content = File.read(file_path, encoding: "utf-8")
31
- [file_path, content, nil]
32
- rescue Encoding::InvalidByteSequenceError, Encoding::UndefinedConversionError
33
- @failed_files << file_path
34
- [file_path, nil, "Failed to decode the file, as it is not saved with UTF-8 encoding."]
32
+ private
33
+
34
+ def collect_files_to_process
35
+ raise NotImplementedError, "Subclasses must implement collect_files_to_process"
35
36
  end
36
37
 
37
- def gather_files(directory_path, exclude)
38
- exclude += @config["exclude"] if @config["exclude"]
39
- exclude_pattern = Regexp.union(exclude.map { |ex| Regexp.new(ex) })
38
+ def load_config(config_file)
39
+ return {} unless config_file && File.exist?(config_file)
40
40
 
41
- Dir.glob("#{directory_path}/**/*").reject do |file_path|
42
- File.directory?(file_path) || file_path.match?(exclude_pattern)
43
- end.map do |file_path|
44
- Pathname.new(file_path).expand_path.to_s
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"
45
51
  end
46
52
  end
47
53
 
48
- def write_results_to_file(results, output_file)
49
- results.each_with_index do |(file_path, content, error), index|
50
- relative = relative_path(file_path)
51
- if content
52
- output_file.puts "--- START FILE: #{relative} ---"
53
- output_file.puts content
54
- output_file.puts "--- END FILE: #{relative} ---"
55
- elsif error
56
- output_file.puts "#{relative}\n#{error}"
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
57
62
  end
58
- output_file.puts if index < results.size - 1 # Add a newline between files
59
63
  end
60
- end
61
64
 
62
- def relative_path(file_path)
63
- Pathname.new(file_path).relative_path_from(Dir.pwd)
65
+ [total_files, copied_files]
64
66
  end
65
67
 
66
- def write_directory_structure_to_file(directory_path, output_file_name, exclude = EXCLUDE_DEFAULT)
67
- dir_path = Pathname.new(directory_path)
68
+ def process_file(output = nil, file_path)
69
+ output ||= StringIO.new
68
70
 
69
- dir_path = dir_path.expand_path unless dir_path.absolute?
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
70
76
 
71
- file_list = gather_files(dir_path, exclude)
72
- total_files = file_list.size
77
+ output.puts "--- START FILE: #{relative_path} ---"
73
78
 
74
- File.open(output_file_name, "w", encoding: "utf-8") do |output_file|
75
- results = file_list.tqdm(desc: "Progress", unit: " file").map do |file|
76
- process_file(file)
77
- end
78
- write_results_to_file(results, output_file)
79
+ if binary_file?(file_path) && @include_binary
80
+ output.puts encode_binary_file(file_path)
81
+ else
82
+ output.puts File.read(file_path)
79
83
  end
80
84
 
81
- copied_files = total_files - @failed_files.size
85
+ output.puts "--- END FILE: #{relative_path} ---\n"
82
86
 
83
- [total_files, copied_files]
87
+ output.string if output.is_a?(StringIO) # Return the string if using StringIO
88
+ end
89
+
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
84
121
  end
85
122
  end
86
123
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Poepod
4
- VERSION = "0.1.3"
4
+ VERSION = "0.1.6"
5
5
  end
data/poepod.gemspec CHANGED
@@ -16,10 +16,6 @@ Gem::Specification.new do |spec|
16
16
  spec.homepage = "https://github.com/riboseinc/poepod"
17
17
  spec.license = "BSD-2-Clause"
18
18
 
19
- spec.bindir = "bin"
20
- spec.require_paths = ["lib"]
21
- spec.files = `git ls-files`.split("\n")
22
- spec.test_files = `git ls-files -- {spec}/*`.split("\n")
23
19
  spec.required_ruby_version = Gem::Requirement.new(">= 3.0.0")
24
20
 
25
21
  # Specify which files should be added to the gem when it is released.
@@ -32,10 +28,14 @@ Gem::Specification.new do |spec|
32
28
  spec.bindir = "exe"
33
29
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
34
30
  spec.require_paths = ["lib"]
31
+ spec.test_files = `git ls-files -- spec/*`.split("\n")
35
32
 
33
+ spec.add_runtime_dependency "git", "~> 1.11"
34
+ spec.add_runtime_dependency "marcel", "~> 1.0"
36
35
  spec.add_runtime_dependency "parallel", "~> 1.20"
37
36
  spec.add_runtime_dependency "thor", "~> 1.0"
38
37
  spec.add_runtime_dependency "tqdm"
38
+
39
39
  spec.add_development_dependency "rake"
40
40
  spec.add_development_dependency "rspec"
41
41
  spec.add_development_dependency "rubocop"
@@ -0,0 +1,126 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+ require "poepod/cli"
5
+
6
+ RSpec.describe Poepod::Cli do
7
+ let(:cli) { described_class.new }
8
+
9
+ describe "#concat" do
10
+ let(:temp_dir) { Dir.mktmpdir }
11
+ let(:text_file) { File.join(temp_dir, "text_file.txt") }
12
+ let(:binary_file) { File.join(temp_dir, "binary_file.bin") }
13
+ let(:dot_file) { File.join(temp_dir, ".hidden_file") }
14
+
15
+ before do
16
+ File.write(text_file, "Hello, World!")
17
+ File.write(binary_file, [0xFF, 0xD8, 0xFF, 0xE0].pack("C*"))
18
+ File.write(dot_file, "Hidden content")
19
+ end
20
+
21
+ after do
22
+ FileUtils.remove_entry(temp_dir)
23
+ end
24
+
25
+ it "concatenates text files and excludes binary and dot files by default" do
26
+ output_file = File.join(temp_dir, "output.txt")
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
30
+ expect(File.exist?(output_file)).to be true
31
+ content = File.read(output_file)
32
+ expect(content).to include("Hello, World!")
33
+ expect(content).not_to include("Hidden content")
34
+ end
35
+
36
+ it "includes binary files when specified" do
37
+ output_file = File.join(temp_dir, "output.txt")
38
+ expect do
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")
45
+ end
46
+
47
+ it "includes dot files when specified" do
48
+ output_file = File.join(temp_dir, "output.txt")
49
+ expect do
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 ---")
69
+ end
70
+ end
71
+
72
+ describe "#wrap" do
73
+ let(:temp_dir) { Dir.mktmpdir }
74
+ let(:gemspec_file) { File.join(temp_dir, "test_gem.gemspec") }
75
+
76
+ before do
77
+ File.write(gemspec_file, <<~GEMSPEC)
78
+ Gem::Specification.new do |spec|
79
+ spec.name = "test_gem"
80
+ spec.version = "0.1.0"
81
+ spec.authors = ["Test Author"]
82
+ spec.files = ["lib/test_gem.rb"]
83
+ end
84
+ GEMSPEC
85
+
86
+ FileUtils.mkdir_p(File.join(temp_dir, "lib"))
87
+ File.write(File.join(temp_dir, "lib/test_gem.rb"), "puts 'Hello from test_gem'")
88
+
89
+ # Mock Git operations
90
+ allow(Git).to receive(:open).and_return(double(status: double(untracked: {}, changed: {})))
91
+ end
92
+
93
+ after do
94
+ FileUtils.remove_entry(temp_dir)
95
+ end
96
+
97
+ it "wraps a gem" do
98
+ expect { cli.wrap(gemspec_file) }.to output(/The gem has been wrapped into/).to_stdout
99
+ output_file = File.join(Dir.pwd, "test_gem_wrapped.txt")
100
+ expect(File.exist?(output_file)).to be true
101
+ content = File.read(output_file)
102
+ expect(content).to include("--- START FILE: lib/test_gem.rb ---")
103
+ expect(content).to include("puts 'Hello from test_gem'")
104
+ expect(content).to include("--- END FILE: lib/test_gem.rb ---")
105
+ end
106
+
107
+ it "handles non-existent gemspec" do
108
+ expect do
109
+ cli.wrap("non_existent.gemspec")
110
+ end.to output(/Error: The specified gemspec file/).to_stdout.and raise_error(SystemExit)
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
125
+ end
126
+ end
@@ -0,0 +1,150 @@
1
+ # frozen_string_literal: true
2
+
3
+ # spec/poepod/file_processor_spec.rb
4
+ require "spec_helper"
5
+ require "poepod/file_processor"
6
+ require "tempfile"
7
+
8
+ RSpec.describe Poepod::FileProcessor do
9
+ let(:temp_dir) { Dir.mktmpdir }
10
+ let(:output_file) { Tempfile.new("output.txt") }
11
+ let(:text_file1) { File.join(temp_dir, "file1.txt") }
12
+ let(:text_file2) { File.join(temp_dir, "file2.txt") }
13
+ let(:binary_file) { File.join(temp_dir, "binary_file.bin") }
14
+ let(:dot_file) { File.join(temp_dir, ".hidden_file") }
15
+
16
+ before do
17
+ File.write(text_file1, "Content of file1.\n")
18
+ File.write(text_file2, "Content of file2.\n")
19
+ File.write(binary_file, [0xFF, 0xD8, 0xFF, 0xE0].pack("C*"))
20
+ File.write(dot_file, "Content of hidden file.\n")
21
+ end
22
+
23
+ after do
24
+ FileUtils.remove_entry(temp_dir)
25
+ output_file.unlink
26
+ end
27
+
28
+ describe "#process" do
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
132
+ end
133
+ end
134
+
135
+ describe "#process_file" do
136
+ let(:processor) { described_class.new([text_file1], output_file.path) }
137
+
138
+ it "reads the content of a file" do
139
+ content = processor.send(:process_file, nil, text_file1)
140
+ expect(content).to include("Content of file1.\n")
141
+ end
142
+
143
+ it "handles encoding errors gracefully" do
144
+ allow(File).to receive(:read).and_raise(Encoding::InvalidByteSequenceError)
145
+ expect do
146
+ processor.send(:process_file, nil, text_file1)
147
+ end.to raise_error(Encoding::InvalidByteSequenceError)
148
+ end
149
+ end
150
+ end
@@ -0,0 +1,171 @@
1
+ # frozen_string_literal: true
2
+
3
+ # spec/poepod/gem_processor_spec.rb
4
+ require "spec_helper"
5
+ require "poepod/gem_processor"
6
+ require "tempfile"
7
+
8
+ RSpec.describe Poepod::GemProcessor do
9
+ let(:temp_dir) { Dir.mktmpdir }
10
+ let(:gemspec_file) { File.join(temp_dir, "test_gem.gemspec") }
11
+
12
+ before do
13
+ File.write(gemspec_file, <<~GEMSPEC)
14
+ Gem::Specification.new do |spec|
15
+ spec.name = "test_gem"
16
+ spec.version = "0.1.0"
17
+ spec.authors = ["Test Author"]
18
+ spec.files = ["lib/test_gem.rb"]
19
+ spec.test_files = ["spec/test_gem_spec.rb"]
20
+ end
21
+ GEMSPEC
22
+
23
+ FileUtils.mkdir_p(File.join(temp_dir, "lib"))
24
+ FileUtils.mkdir_p(File.join(temp_dir, "spec"))
25
+ File.write(File.join(temp_dir, "lib/test_gem.rb"), "puts 'Hello from test_gem'")
26
+ File.write(File.join(temp_dir, "spec/test_gem_spec.rb"), "RSpec.describe TestGem do\nend")
27
+ File.write(File.join(temp_dir, "README.md"), "# Test Gem\n\nThis is a test gem.")
28
+ File.write(File.join(temp_dir, "README.txt"), "Test Gem\n\nThis is a test gem in plain text.")
29
+ end
30
+
31
+ after do
32
+ FileUtils.remove_entry(temp_dir)
33
+ end
34
+
35
+ describe "#process" do
36
+ let(:processor) { described_class.new(gemspec_file) }
37
+
38
+ before do
39
+ # Mock Git operations
40
+ allow(Git).to receive(:open).and_return(double(status: double(untracked: {}, changed: {})))
41
+ end
42
+
43
+ it "processes the gem files, includes README files, and spec files in sorted order" do
44
+ success, output_file = processor.process
45
+ expect(success).to be true
46
+ expect(File.exist?(output_file)).to be true
47
+
48
+ content = File.read(output_file)
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)
79
+ end
80
+
81
+ context "with non-existent gemspec" do
82
+ let(:processor) { described_class.new("non_existent.gemspec") }
83
+
84
+ it "returns an error" do
85
+ success, error_message = processor.process
86
+ expect(success).to be false
87
+ expect(error_message).to include("Error: The specified gemspec file")
88
+ end
89
+ end
90
+
91
+ context "with unstaged files" do
92
+ let(:processor) { described_class.new(gemspec_file, include_unstaged: false) }
93
+ let(:mock_git) { instance_double(Git::Base) }
94
+ let(:mock_status) { instance_double(Git::Status) }
95
+
96
+ before do
97
+ allow(Git).to receive(:open).and_return(mock_git)
98
+ allow(mock_git).to receive(:status).and_return(mock_status)
99
+ allow(mock_status).to receive(:untracked).and_return(
100
+ { "lib/unstaged_file.rb" => "??" }
101
+ )
102
+ allow(mock_status).to receive(:changed).and_return({})
103
+ end
104
+
105
+ context "with include_unstaged option" do
106
+ let(:processor) { described_class.new(gemspec_file, include_unstaged: true) }
107
+
108
+ it "includes unstaged files" do
109
+ allow(File).to receive(:file?).and_return(true)
110
+
111
+ # Create a hash to store file contents
112
+ file_contents = {
113
+ "lib/test_gem.rb" => "puts 'Hello from test_gem'",
114
+ "spec/test_gem_spec.rb" => "RSpec.describe TestGem do\nend",
115
+ "README.md" => "# Test Gem\n\nThis is a test gem.",
116
+ "README.txt" => "Test Gem\n\nThis is a test gem in plain text.",
117
+ "lib/unstaged_file.rb" => "Unstaged content"
118
+ }
119
+
120
+ # Mock File.read
121
+ allow(File).to receive(:read) do |path|
122
+ file_name = File.basename(path)
123
+ if file_contents.key?(file_name)
124
+ file_contents[file_name]
125
+ elsif path.end_with?("_wrapped.txt")
126
+ # This is the output file, so we'll construct its content here
127
+ file_contents.map do |file, content|
128
+ <<~HERE
129
+ --- START FILE: #{file} ---
130
+ #{content}
131
+ --- END FILE: #{file} ---
132
+ HERE
133
+ end.join("")
134
+ else
135
+ "Default content for #{path}"
136
+ end
137
+ end
138
+
139
+ success, output_file, unstaged_files = processor.process
140
+ expect(success).to be true
141
+ expect(unstaged_files).to eq(["lib/unstaged_file.rb"])
142
+
143
+ content = File.read(output_file)
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)
167
+ end
168
+ end
169
+ end
170
+ end
171
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Poepod do
4
+ it "has a version number" do
5
+ expect(Poepod::VERSION).not_to be nil
6
+ end
7
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "poepod"
4
+ require "fileutils"
5
+
6
+ RSpec.configure do |config|
7
+ # Enable flags like --only-failures and --next-failure
8
+ config.example_status_persistence_file_path = ".rspec_status"
9
+
10
+ # Disable RSpec exposing methods globally on `Module` and `main`
11
+ config.disable_monkey_patching!
12
+
13
+ config.expect_with :rspec do |c|
14
+ c.syntax = :expect
15
+ end
16
+ end
@@ -0,0 +1 @@
1
+ Content of file1.
@@ -0,0 +1 @@
1
+ Content of file2.
metadata CHANGED
@@ -1,15 +1,43 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: poepod
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.3
4
+ version: 0.1.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Inc.
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-06-12 00:00:00.000000000 Z
11
+ date: 2024-07-22 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: git
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.11'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.11'
27
+ - !ruby/object:Gem::Dependency
28
+ name: marcel
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.0'
13
41
  - !ruby/object:Gem::Dependency
14
42
  name: parallel
15
43
  requirement: !ruby/object:Gem::Requirement
@@ -146,15 +174,24 @@ files:
146
174
  - exe/poepod
147
175
  - lib/poepod.rb
148
176
  - lib/poepod/cli.rb
177
+ - lib/poepod/file_processor.rb
178
+ - lib/poepod/gem_processor.rb
149
179
  - lib/poepod/processor.rb
150
180
  - lib/poepod/version.rb
151
181
  - poepod.gemspec
152
182
  - sig/poepod.rbs
183
+ - spec/poepod/cli_spec.rb
184
+ - spec/poepod/file_processor_spec.rb
185
+ - spec/poepod/gem_processor_spec.rb
186
+ - spec/poepod_spec.rb
187
+ - spec/spec_helper.rb
188
+ - spec/support/test_files/file1.txt
189
+ - spec/support/test_files/file2.txt
153
190
  homepage: https://github.com/riboseinc/poepod
154
191
  licenses:
155
192
  - BSD-2-Clause
156
193
  metadata: {}
157
- post_install_message:
194
+ post_install_message:
158
195
  rdoc_options: []
159
196
  require_paths:
160
197
  - lib
@@ -169,8 +206,15 @@ required_rubygems_version: !ruby/object:Gem::Requirement
169
206
  - !ruby/object:Gem::Version
170
207
  version: '0'
171
208
  requirements: []
172
- rubygems_version: 3.5.11
173
- signing_key:
209
+ rubygems_version: 3.3.27
210
+ signing_key:
174
211
  specification_version: 4
175
212
  summary: Utilities for uploading code to Poe
176
- test_files: []
213
+ test_files:
214
+ - spec/poepod/cli_spec.rb
215
+ - spec/poepod/file_processor_spec.rb
216
+ - spec/poepod/gem_processor_spec.rb
217
+ - spec/poepod_spec.rb
218
+ - spec/spec_helper.rb
219
+ - spec/support/test_files/file1.txt
220
+ - spec/support/test_files/file2.txt