poepod 0.1.3 → 0.1.6

Sign up to get free protection for your applications and to get access to all the features.
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