xlg 0.4.2

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 487577ad7b07e1220696b70de189c3c098a39547c84dc8db0204b5420c4ae0af
4
+ data.tar.gz: 8e58a4ba07793fd06036bbeb3c03069938dab6fe5f3eb0aa21dc38a7d94912bf
5
+ SHA512:
6
+ metadata.gz: 54c70a935c0b50d11d63e70f9d0203172afd17022f8bd058a2ddb8cc8e66de14524a561881d8070ca301d93aede144305c909c9a0fb9d389628bc69ee1dfeeff
7
+ data.tar.gz: da330328bb724784d21f0d1e59322f4eec091fbe57c48fc55ab03cee9238470867c8b321a2b833894a96cf69c80b830f528bfa800188b44b7744aee66516ca21
data/LICENSE ADDED
@@ -0,0 +1,8 @@
1
+ The MIT License (MIT)
2
+ Copyright (c) 2025 Kazto TAKAHASHI (@kazto)
3
+
4
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
5
+
6
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
7
+
8
+ THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,136 @@
1
+ # xlg - Excel Grep Tool
2
+
3
+ `xlg` is a command-line tool that provides functionality to search keywords in Excel files in various formats. It works like `grep` but for Excel files, outputting results in a grep-like format showing file, sheet, cell reference, and matched content.
4
+
5
+ ## Features
6
+
7
+ - Search text in Excel files (.xlsx, .xls, .xlsm)
8
+ - Support for single file, multiple files, and directory-based searches
9
+ - Case-insensitive keyword matching
10
+ - Grep-like output format: `filename:sheet:cell_ref:matched_text`
11
+ - Automatic Excel file discovery in directories
12
+ - Comprehensive error handling and validation
13
+
14
+ ## Installation
15
+
16
+ Build and install the gem:
17
+
18
+ ```bash
19
+ gem build gemspec
20
+ gem install xlg-0.4.2.gem
21
+ ```
22
+
23
+ Or install directly from the built gem files:
24
+
25
+ ```bash
26
+ gem install xlg-0.4.2.gem
27
+ ```
28
+
29
+ ## Usage
30
+
31
+ ### Basic Usage
32
+
33
+ ```bash
34
+ # Search in a single Excel file
35
+ xlg 'keyword' sample.xlsx
36
+
37
+ # Search in multiple Excel files
38
+ xlg 'keyword' file1.xlsx file2.xlsx
39
+
40
+ # Search all Excel files in a directory
41
+ xlg 'keyword' /path/to/directory/
42
+ ```
43
+
44
+ ### Command Line Options
45
+
46
+ ```
47
+ xlg KEYWORD FILE.xlsx # Single file search
48
+ xlg KEYWORD FILE1.xlsx FILE2.xlsx # Multiple file search
49
+ xlg KEYWORD /path/to/directory/ # Directory search
50
+
51
+ Options:
52
+ -h, --help Show help message
53
+ ```
54
+
55
+ ### Examples
56
+
57
+ ```bash
58
+ # Search for "test" in sample.xlsx
59
+ xlg 'test' sample.xlsx
60
+
61
+ # Search for "データ" in multiple files
62
+ xlg 'データ' file1.xlsx file2.xlsx
63
+
64
+ # Search for "keyword" in all Excel files in documents folder
65
+ xlg 'キーワード' /home/user/documents/
66
+ ```
67
+
68
+ ## Output Format
69
+
70
+ The output follows a grep-like format:
71
+
72
+ ```
73
+ filename.xlsx:SheetName:A1:matched content
74
+ filename.xlsx:SheetName:B5:another match
75
+ ```
76
+
77
+ Where:
78
+ - `filename.xlsx`: The Excel file name
79
+ - `SheetName`: The worksheet name
80
+ - `A1`: Cell reference (Excel format)
81
+ - `matched content`: The actual cell content that contains the keyword
82
+
83
+ ## Supported File Formats
84
+
85
+ - `.xlsx` (Excel 2007 and later)
86
+ - `.xls` (Excel 97-2003)
87
+ - `.xlsm` (Excel with macros)
88
+
89
+ ## Requirements
90
+
91
+ - Ruby >= 3.0
92
+ - rubyXL gem (~> 3.4) - automatically installed as dependency
93
+
94
+ ## Architecture
95
+
96
+ The tool consists of four main components:
97
+
98
+ - `ExcelGrep` (lib/excel_grep.rb): Core search functionality for single files
99
+ - `MultiFileSearcher` (lib/multi_file_searcher.rb): Handles multiple files and directories
100
+ - `CellMatcher` (lib/cell_matcher.rb): Performs case-insensitive text matching
101
+ - `OutputFormatter` (lib/output_formatter.rb): Formats output in grep-like style
102
+
103
+ ## Development
104
+
105
+ ### Running Tests
106
+
107
+ ```bash
108
+ ruby test/test_*.rb
109
+ ```
110
+
111
+ ### Project Structure
112
+
113
+ ```
114
+ ├── lib/
115
+ │ ├── excel_grep.rb # Main Excel search engine
116
+ │ ├── multi_file_searcher.rb # Multi-file search coordination
117
+ │ ├── cell_matcher.rb # Text matching logic
118
+ │ └── output_formatter.rb # Output formatting
119
+ ├── bin/
120
+ │ └── xlg # Command-line executable
121
+ ├── test/ # Unit tests
122
+ ├── docs/ # Documentation
123
+ └── gemspec # Gem specification
124
+ ```
125
+
126
+ ## License
127
+
128
+ MIT License - see LICENSE file for details.
129
+
130
+ ## Author
131
+
132
+ Kazto TAKAHASHI (kazto@kazto.dev)
133
+
134
+ ## Repository
135
+
136
+ https://github.com/kazto/xlg
data/bin/xlg ADDED
@@ -0,0 +1,78 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'excel_grep'
4
+ require 'multi_file_searcher'
5
+
6
+ def show_help
7
+ puts "使用方法:"
8
+ puts " xlg KEYWORD FILE.xlsx # 単一ファイル"
9
+ puts " xlg KEYWORD FILE1.xlsx FILE2.xlsx # 複数ファイル"
10
+ puts " xlg KEYWORD /path/to/directory/ # ディレクトリ内全検索"
11
+ puts ""
12
+ puts "Excel ファイル内の文字列を検索し、grep形式で出力します。"
13
+ puts ""
14
+ puts "引数:"
15
+ puts " KEYWORD 検索するキーワード"
16
+ puts " FILE.xlsx 検索対象のExcelファイル(複数指定可能)"
17
+ puts " /path/to/dir/ 検索対象のディレクトリ"
18
+ puts ""
19
+ puts "対応ファイル形式:"
20
+ puts " .xlsx (Excel 2007以降)"
21
+ puts " .xls (Excel 97-2003)"
22
+ puts " .xlsm (マクロ有効Excel)"
23
+ puts ""
24
+ puts "例:"
25
+ puts " xlg 'test' sample.xlsx"
26
+ puts " xlg 'データ' file1.xlsx file2.xlsx"
27
+ puts " xlg 'キーワード' /home/user/documents/"
28
+ puts ""
29
+ puts "オプション:"
30
+ puts " -h, --help このヘルプを表示"
31
+ end
32
+
33
+ def main
34
+ if ARGV.include?('-h') || ARGV.include?('--help') || ARGV.length == 0
35
+ show_help
36
+ exit 0
37
+ end
38
+
39
+ if ARGV.length < 2
40
+ $stderr.puts "エラー: 引数の数が正しくありません"
41
+ $stderr.puts "使用方法: xlg KEYWORD FILE.xlsx [FILE2.xlsx ...]"
42
+ $stderr.puts "詳細は 'xlg --help' を参照してください"
43
+ exit 1
44
+ end
45
+
46
+ keyword = ARGV[0]
47
+ paths = ARGV[1..-1]
48
+
49
+ begin
50
+ if paths.length == 1
51
+ # 単一ファイル/ディレクトリの場合
52
+ path = paths[0]
53
+ if File.directory?(path)
54
+ # ディレクトリの場合はMultiFileSearcherを使用
55
+ searcher = MultiFileSearcher.new(keyword, [path])
56
+ success = searcher.search
57
+ else
58
+ # 単一ファイルの場合はExcelGrepを使用
59
+ grep = ExcelGrep.new(keyword, path)
60
+ success = grep.search
61
+ end
62
+ else
63
+ # 複数パスの場合はMultiFileSearcherを使用
64
+ searcher = MultiFileSearcher.new(keyword, paths)
65
+ success = searcher.search
66
+ end
67
+
68
+ exit(success ? 0 : 1)
69
+ rescue ArgumentError => e
70
+ $stderr.puts "エラー: #{e.message}"
71
+ exit 1
72
+ rescue => e
73
+ $stderr.puts "予期しないエラーが発生しました: #{e.message}"
74
+ exit 1
75
+ end
76
+ end
77
+
78
+ main
@@ -0,0 +1,22 @@
1
+ class CellMatcher
2
+ def match?(cell_value, keyword)
3
+ return false if cell_value.nil? || keyword.nil? || keyword.empty?
4
+
5
+ cell_str = cell_value.to_s
6
+ return false if cell_str.empty?
7
+
8
+ cell_str.downcase.include?(keyword.downcase)
9
+ end
10
+
11
+ def extract_match(cell_value, keyword)
12
+ return nil unless match?(cell_value, keyword)
13
+
14
+ cell_str = cell_value.to_s
15
+ keyword_lower = keyword.downcase
16
+
17
+ start_index = cell_str.downcase.index(keyword_lower)
18
+ return nil if start_index.nil?
19
+
20
+ cell_str[start_index, keyword.length]
21
+ end
22
+ end
data/lib/excel_grep.rb ADDED
@@ -0,0 +1,62 @@
1
+ require 'rubyXL'
2
+ require 'cell_matcher'
3
+ require 'output_formatter'
4
+
5
+ class ExcelGrep
6
+ attr_reader :keyword, :file_path
7
+
8
+ def initialize(keyword, file_path)
9
+ raise ArgumentError, "キーワードが空です" if keyword.nil? || keyword.empty?
10
+ raise ArgumentError, "ファイルパスが空です" if file_path.nil? || file_path.empty?
11
+
12
+ @keyword = keyword
13
+ @file_path = file_path
14
+ @matcher = CellMatcher.new
15
+ @formatter = OutputFormatter.new
16
+ end
17
+
18
+ def validate_file(file_path)
19
+ return false if file_path.nil? || file_path.empty?
20
+ return false unless File.exist?(file_path)
21
+ return false unless file_path.match?(/\.(xlsx?|xlsm)$/i)
22
+
23
+ true
24
+ end
25
+
26
+ def search
27
+ unless validate_file(@file_path)
28
+ $stderr.puts "エラー: ファイルが見つかりません、またはExcelファイルではありません: #{@file_path}"
29
+ return false
30
+ end
31
+
32
+ begin
33
+ workbook = RubyXL::Parser.parse(@file_path)
34
+ file_name = File.basename(@file_path)
35
+
36
+ workbook.worksheets.each do |worksheet|
37
+ next if worksheet.nil?
38
+
39
+ sheet_name = worksheet.sheet_name || "Sheet#{worksheet.index + 1}"
40
+
41
+ worksheet.each_with_index do |row, row_index|
42
+ next if row.nil?
43
+
44
+ row.cells.each_with_index do |cell, col_index|
45
+ next if cell.nil? || cell.value.nil?
46
+
47
+ cell_value = cell.value.to_s
48
+ if @matcher.match?(cell_value, @keyword)
49
+ cell_ref = RubyXL::Reference.ind2ref(row_index, col_index)
50
+ puts @formatter.format(file_name, sheet_name, cell_ref, cell_value)
51
+ end
52
+ end
53
+ end
54
+ end
55
+
56
+ true
57
+ rescue => e
58
+ $stderr.puts "エラー: Excelファイルの読み込みに失敗しました: #{e.message}"
59
+ false
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,68 @@
1
+ require 'excel_grep'
2
+
3
+ class MultiFileSearcher
4
+ attr_reader :keyword, :paths
5
+
6
+ def initialize(keyword, paths)
7
+ raise ArgumentError, "キーワードが空です" if keyword.nil? || keyword.empty?
8
+ raise ArgumentError, "パスが空です" if paths.nil? || paths.empty?
9
+
10
+ @keyword = keyword
11
+ @paths = paths
12
+ end
13
+
14
+ def search
15
+ expanded_files = expand_paths(@paths)
16
+ success_count = 0
17
+
18
+ expanded_files.each do |file_path|
19
+ begin
20
+ grep = ExcelGrep.new(@keyword, file_path)
21
+ if grep.search
22
+ success_count += 1
23
+ end
24
+ rescue => e
25
+ $stderr.puts "エラー: #{file_path} - #{e.message}"
26
+ end
27
+ end
28
+
29
+ success_count > 0
30
+ end
31
+
32
+ def expand_paths(paths)
33
+ expanded = []
34
+
35
+ paths.each do |path|
36
+ if File.directory?(path)
37
+ expanded.concat(find_excel_files(path))
38
+ else
39
+ expanded << path
40
+ end
41
+ end
42
+
43
+ expanded.uniq
44
+ end
45
+
46
+ def find_excel_files(directory)
47
+ return [] unless File.exist?(directory) && File.directory?(directory)
48
+
49
+ excel_files = []
50
+
51
+ begin
52
+ Dir.entries(directory).each do |entry|
53
+ next if entry.start_with?('.') # 隠しファイルとカレント/親ディレクトリを除外
54
+
55
+ file_path = File.join(directory, entry)
56
+ next if File.directory?(file_path) # サブディレクトリを除外
57
+
58
+ if entry.match?(/\.(xlsx?|xlsm)$/i)
59
+ excel_files << file_path
60
+ end
61
+ end
62
+ rescue => e
63
+ $stderr.puts "ディレクトリ読み込みエラー: #{directory} - #{e.message}"
64
+ end
65
+
66
+ excel_files.sort
67
+ end
68
+ end
@@ -0,0 +1,5 @@
1
+ class OutputFormatter
2
+ def format(file_name, sheet_name, cell_ref, match_text)
3
+ "#{file_name}:#{sheet_name}:#{cell_ref}:#{match_text}"
4
+ end
5
+ end
metadata ADDED
@@ -0,0 +1,66 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: xlg
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.4.2
5
+ platform: ruby
6
+ authors:
7
+ - Kazto TAKAHASHI
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2025-08-08 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rubyXL
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '3.4'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '3.4'
27
+ description: "`xlg` is a command-line tool that provides functionality to search keywords
28
+ in Excel files in various formats."
29
+ email:
30
+ - kazto@kazto.dev
31
+ executables:
32
+ - xlg
33
+ extensions: []
34
+ extra_rdoc_files: []
35
+ files:
36
+ - LICENSE
37
+ - README.md
38
+ - bin/xlg
39
+ - lib/cell_matcher.rb
40
+ - lib/excel_grep.rb
41
+ - lib/multi_file_searcher.rb
42
+ - lib/output_formatter.rb
43
+ homepage: https://github.com/kazto/xlg
44
+ licenses:
45
+ - MIT
46
+ metadata: {}
47
+ post_install_message:
48
+ rdoc_options: []
49
+ require_paths:
50
+ - lib
51
+ required_ruby_version: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ version: '3.0'
56
+ required_rubygems_version: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: '0'
61
+ requirements: []
62
+ rubygems_version: 3.4.19
63
+ signing_key:
64
+ specification_version: 4
65
+ summary: A Ruby library for reading and writing Excel files.
66
+ test_files: []