grepfruit 2.0.2 → 2.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +7 -0
- data/README.md +95 -41
- data/exe/grepfruit +1 -1
- data/grepfruit.gemspec +1 -1
- data/lib/grepfruit/decorator.rb +58 -0
- data/lib/{search.rb → grepfruit/search.rb} +9 -41
- data/lib/grepfruit/version.rb +1 -1
- data/lib/grepfruit.rb +1 -1
- metadata +8 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 510715dadc6ac5afba47b5a02b122eb6ae53e46dcb4454a3d83adf7374615b1e
|
4
|
+
data.tar.gz: 4797c7612d6f0ab3e0ec3c15a3c48941984f9eba4837a919ba98f10551d3c4fb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a62a669cb08f455f3105ee73b4f70d991216c7b34e68477adf6546d922e43e5994ff9a9cfca38671adf69b90cb89edf1960019b8d5dd2fb3bb8df5602f6ccc2c
|
7
|
+
data.tar.gz: b85bd902107f90713cd14be4ce8662250975c76dfd95e7757a12f36da4004261098545e7929abe103c9b8204b7c457c011d129ff5daff5cc5dafa5e4aa163b34
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,10 @@
|
|
1
|
+
## v2.0.4
|
2
|
+
- Fixed path resolution bug where searching in relative directories such as `.`, `./`, or `..` did not work correctly
|
3
|
+
|
4
|
+
## v2.0.3
|
5
|
+
|
6
|
+
- Updated gemspec metadata to include the correct homepage URL
|
7
|
+
|
1
8
|
## v2.0.2
|
2
9
|
|
3
10
|
- Replaced `git ls-files` with `Dir.glob` in gemspec for improved portability and compatibility
|
data/README.md
CHANGED
@@ -1,102 +1,156 @@
|
|
1
|
-
# Grepfruit
|
1
|
+
# Grepfruit: File Pattern Search Tool for Ruby
|
2
2
|
|
3
3
|
[](http://badge.fury.io/rb/grepfruit)
|
4
|
-
[](https://github.com/brownboxdev/grepfruit/actions/workflows/ci.yml)
|
5
5
|
|
6
|
-
Grepfruit is a Ruby gem for searching files within a directory for
|
6
|
+
Grepfruit is a Ruby gem for searching files within a directory for specified regular expression patterns, with intelligent exclusion options and colorized output for enhanced readability. Originally designed for CI/CD pipelines to search for `TODO` comments in Ruby on Rails applications, Grepfruit provides more user-friendly output than the standard `grep` command while maintaining the flexibility for diverse search scenarios.
|
7
7
|
|
8
|
-
|
8
|
+
**Key Features:**
|
9
9
|
|
10
|
-
|
10
|
+
- Regular expression search within files and directories
|
11
|
+
- Intelligent file and directory exclusion capabilities
|
12
|
+
- Colorized output for improved readability
|
13
|
+
- Hidden file and directory search support
|
14
|
+
- Configurable output truncation
|
15
|
+
- CI/CD pipeline friendly with meaningful exit codes
|
16
|
+
- Line-specific exclusion for precise control
|
17
|
+
|
18
|
+
## Table of Contents
|
19
|
+
|
20
|
+
**Gem Usage:**
|
21
|
+
- [Installation](#installation)
|
22
|
+
- [Basic Usage](#basic-usage)
|
23
|
+
- [Command Line Options](#command-line-options)
|
24
|
+
- [Usage Examples](#usage-examples)
|
25
|
+
- [Exit Status](#exit-status)
|
26
|
+
|
27
|
+
**Community Resources:**
|
28
|
+
- [Contributing](#contributing)
|
29
|
+
- [License](#license)
|
30
|
+
- [Code of Conduct](#code-of-conduct)
|
11
31
|
|
12
32
|
## Installation
|
13
33
|
|
14
|
-
Add
|
34
|
+
Add Grepfruit to your Gemfile:
|
15
35
|
|
16
|
-
```
|
36
|
+
```rb
|
17
37
|
gem "grepfruit"
|
18
38
|
```
|
19
39
|
|
20
|
-
|
40
|
+
Install the gem:
|
21
41
|
|
22
|
-
```
|
42
|
+
```bash
|
23
43
|
bundle install
|
24
44
|
```
|
25
45
|
|
26
|
-
Or install it
|
46
|
+
Or install it directly:
|
27
47
|
|
28
|
-
```
|
48
|
+
```bash
|
29
49
|
gem install grepfruit
|
30
50
|
```
|
31
51
|
|
32
|
-
## Usage
|
52
|
+
## Basic Usage
|
33
53
|
|
34
|
-
|
54
|
+
Search for regex patterns within files in a specified directory:
|
35
55
|
|
36
|
-
```
|
56
|
+
```bash
|
37
57
|
grepfruit [options] PATH
|
38
58
|
```
|
39
59
|
|
40
|
-
If no
|
60
|
+
If no PATH is specified, Grepfruit searches the current directory.
|
61
|
+
|
62
|
+
## Command Line Options
|
41
63
|
|
42
|
-
|
64
|
+
| Option | Description |
|
65
|
+
|--------|-------------|
|
66
|
+
| `-r, --regex REGEX` | Regex pattern to search for (required) |
|
67
|
+
| `-e, --exclude x,y,z` | Comma-separated list of files, directories, or lines to exclude |
|
68
|
+
| `-t, --truncate N` | Truncate search result output to N characters |
|
69
|
+
| `--search-hidden` | Include hidden files and directories in search |
|
43
70
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
71
|
+
## Usage Examples
|
72
|
+
|
73
|
+
### Basic Pattern Search
|
74
|
+
|
75
|
+
Search for `TODO` comments in the current directory:
|
76
|
+
|
77
|
+
```bash
|
78
|
+
grepfruit -r 'TODO'
|
79
|
+
```
|
48
80
|
|
49
|
-
###
|
81
|
+
### Excluding Directories
|
50
82
|
|
51
|
-
Search for
|
83
|
+
Search for `TODO` patterns while excluding common build and dependency directories:
|
52
84
|
|
53
|
-
```
|
85
|
+
```bash
|
54
86
|
grepfruit -r 'TODO' -e 'log,tmp,vendor,node_modules,assets'
|
55
87
|
```
|
56
88
|
|
57
|
-
|
89
|
+
### Multiple Pattern Search Excluding Both Directories and Files
|
58
90
|
|
59
|
-
|
91
|
+
Search for both `FIXME` and `TODO` comments in a specific directory:
|
92
|
+
|
93
|
+
```bash
|
60
94
|
grepfruit -r 'FIXME|TODO' -e 'bin,tmp/log,Gemfile.lock' dev/grepfruit
|
61
95
|
```
|
62
96
|
|
63
|
-
|
97
|
+
### Line-Specific Exclusion
|
98
|
+
|
99
|
+
Exclude specific lines from search results:
|
64
100
|
|
65
|
-
```
|
101
|
+
```bash
|
66
102
|
grepfruit -r 'FIXME|TODO' -e 'README.md:18'
|
67
103
|
```
|
68
104
|
|
69
|
-
|
105
|
+
### Output Truncation
|
70
106
|
|
71
|
-
|
107
|
+
Limit output length for cleaner results:
|
108
|
+
|
109
|
+
```bash
|
72
110
|
grepfruit -r 'FIXME|TODO' -t 50
|
73
111
|
```
|
74
112
|
|
75
|
-
|
113
|
+
### Including Hidden Files
|
114
|
+
|
115
|
+
Search hidden files and directories:
|
76
116
|
|
77
|
-
```
|
117
|
+
```bash
|
78
118
|
grepfruit -r 'FIXME|TODO' --search-hidden
|
79
119
|
```
|
80
120
|
|
81
|
-
##
|
121
|
+
## Exit Status
|
82
122
|
|
83
|
-
|
123
|
+
Grepfruit returns meaningful exit codes for CI/CD integration:
|
84
124
|
|
85
|
-
- **
|
125
|
+
- **Exit code 0**: No matches found
|
126
|
+
- **Exit code 1**: Pattern matches were found
|
86
127
|
|
87
|
-
|
128
|
+
## Contributing
|
88
129
|
|
89
|
-
|
90
|
-
|
130
|
+
### Getting Help
|
131
|
+
Have a question or need assistance? Open a discussion in our [discussions section](https://github.com/brownboxdev/grepfruit/discussions) for:
|
132
|
+
- Usage questions
|
133
|
+
- Implementation guidance
|
134
|
+
- Feature suggestions
|
91
135
|
|
92
|
-
|
136
|
+
### Reporting Issues
|
137
|
+
Found a bug? Please [create an issue](https://github.com/brownboxdev/grepfruit/issues) with:
|
138
|
+
- A clear description of the problem
|
139
|
+
- Steps to reproduce the issue
|
140
|
+
- Your environment details (Ruby version, OS, etc.)
|
141
|
+
|
142
|
+
### Contributing Code
|
143
|
+
Ready to contribute? You can:
|
144
|
+
- Fix bugs by submitting pull requests
|
145
|
+
- Improve documentation
|
146
|
+
- Add new features (please discuss first in our [discussions section](https://github.com/brownboxdev/grepfruit/discussions))
|
93
147
|
|
94
|
-
Before
|
148
|
+
Before contributing, please read the [contributing guidelines](https://github.com/brownboxdev/grepfruit/blob/master/CONTRIBUTING.md)
|
95
149
|
|
96
150
|
## License
|
97
151
|
|
98
|
-
The gem is available as open source under the terms of the [MIT License](https://github.com/
|
152
|
+
The gem is available as open source under the terms of the [MIT License](https://github.com/brownboxdev/grepfruit/blob/master/LICENSE.txt).
|
99
153
|
|
100
154
|
## Code of Conduct
|
101
155
|
|
102
|
-
Everyone interacting in the Grepfruit project is expected to follow the [code of conduct](https://github.com/
|
156
|
+
Everyone interacting in the Grepfruit project is expected to follow the [code of conduct](https://github.com/brownboxdev/grepfruit/blob/master/CODE_OF_CONDUCT.md).
|
data/exe/grepfruit
CHANGED
data/grepfruit.gemspec
CHANGED
@@ -4,7 +4,7 @@ Gem::Specification.new do |spec|
|
|
4
4
|
spec.name = "grepfruit"
|
5
5
|
spec.version = Grepfruit::VERSION
|
6
6
|
spec.authors = ["enjaku4"]
|
7
|
-
spec.homepage = "https://github.com/
|
7
|
+
spec.homepage = "https://github.com/brownboxdev/grepfruit"
|
8
8
|
spec.metadata["homepage_uri"] = spec.homepage
|
9
9
|
spec.metadata["source_code_uri"] = spec.homepage
|
10
10
|
spec.metadata["changelog_uri"] = "#{spec.homepage}/blob/master/CHANGELOG.md"
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module Grepfruit
|
2
|
+
module Decorator
|
3
|
+
COLORS = { cyan: "\e[36m", red: "\e[31m", green: "\e[32m", reset: "\e[0m" }
|
4
|
+
private_constant :COLORS
|
5
|
+
|
6
|
+
private
|
7
|
+
|
8
|
+
def green(text)
|
9
|
+
"#{COLORS[:green]}#{text}#{COLORS[:reset]}"
|
10
|
+
end
|
11
|
+
|
12
|
+
def red(text)
|
13
|
+
"#{COLORS[:red]}#{text}#{COLORS[:reset]}"
|
14
|
+
end
|
15
|
+
|
16
|
+
def cyan(text)
|
17
|
+
"#{COLORS[:cyan]}#{text}#{COLORS[:reset]}"
|
18
|
+
end
|
19
|
+
|
20
|
+
def number_of_files(num)
|
21
|
+
"#{num} file#{'s' if num > 1}"
|
22
|
+
end
|
23
|
+
|
24
|
+
def number_of_matches(num)
|
25
|
+
"#{num} match#{'es' if num > 1}"
|
26
|
+
end
|
27
|
+
|
28
|
+
def relative_path(path)
|
29
|
+
Pathname.new(path).relative_path_from(Pathname.new(dir)).to_s
|
30
|
+
end
|
31
|
+
|
32
|
+
def relative_path_with_line_num(path, line_num)
|
33
|
+
"#{relative_path(path)}:#{line_num + 1}"
|
34
|
+
end
|
35
|
+
|
36
|
+
def processed_line(line)
|
37
|
+
stripped_line = line.strip
|
38
|
+
truncate && stripped_line.length > truncate ? "#{stripped_line[0..truncate - 1]}..." : stripped_line
|
39
|
+
end
|
40
|
+
|
41
|
+
def decorated_line(path, line_num, line)
|
42
|
+
"#{cyan(relative_path_with_line_num(path, line_num))}: #{processed_line(line)}"
|
43
|
+
end
|
44
|
+
|
45
|
+
def display_results(lines, files, files_with_matches)
|
46
|
+
puts "\n\n" if files.positive?
|
47
|
+
|
48
|
+
if lines.empty?
|
49
|
+
puts "#{number_of_files(files)} checked, #{green('no matches found')}"
|
50
|
+
exit(0)
|
51
|
+
else
|
52
|
+
puts "Matches:\n\n#{lines.join("\n")}\n\n"
|
53
|
+
puts "#{number_of_files(files)} checked, #{red("#{number_of_matches(lines.size)} found in #{number_of_files(files_with_matches)}")}"
|
54
|
+
exit(1)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -1,12 +1,17 @@
|
|
1
1
|
require "pathname"
|
2
2
|
require "find"
|
3
|
+
require "byebug"
|
4
|
+
|
5
|
+
require_relative "decorator"
|
3
6
|
|
4
7
|
module Grepfruit
|
5
8
|
class Search
|
9
|
+
include Decorator
|
10
|
+
|
6
11
|
attr_reader :dir, :regex, :excluded_paths, :excluded_lines, :truncate, :search_hidden
|
7
12
|
|
8
13
|
def initialize(dir:, regex:, exclude:, truncate:, search_hidden:)
|
9
|
-
@dir = dir
|
14
|
+
@dir = File.expand_path(dir)
|
10
15
|
@regex = regex
|
11
16
|
@excluded_lines, @excluded_paths = exclude.map { _1.split("/") }.partition { _1.last.include?(":") }
|
12
17
|
@truncate = truncate
|
@@ -28,18 +33,15 @@ module Grepfruit
|
|
28
33
|
|
29
34
|
if match
|
30
35
|
files_with_matches += 1
|
31
|
-
print "
|
36
|
+
print red("M")
|
32
37
|
else
|
33
|
-
print
|
38
|
+
print green(".")
|
34
39
|
end
|
35
40
|
end
|
36
41
|
|
37
42
|
display_results(lines, files, files_with_matches)
|
38
43
|
end
|
39
44
|
|
40
|
-
COLORS = { cyan: "\e[36m", red: "\e[31m", green: "\e[32m", reset: "\e[0m" }
|
41
|
-
private_constant :COLORS
|
42
|
-
|
43
45
|
private
|
44
46
|
|
45
47
|
def not_searchable?(path)
|
@@ -52,25 +54,12 @@ module Grepfruit
|
|
52
54
|
File.foreach(path).with_index do |line, line_num|
|
53
55
|
next if !line.valid_encoding? || !line.match?(regex) || excluded_line?(path, line_num)
|
54
56
|
|
55
|
-
lines <<
|
57
|
+
lines << decorated_line(path, line_num, line)
|
56
58
|
end
|
57
59
|
|
58
60
|
lines.size > lines_size
|
59
61
|
end
|
60
62
|
|
61
|
-
def display_results(lines, files, files_with_matches)
|
62
|
-
puts "\n\n" if files.positive?
|
63
|
-
|
64
|
-
if lines.empty?
|
65
|
-
puts "#{number_of_files(files)} checked, #{COLORS[:green]}no matches found#{COLORS[:reset]}"
|
66
|
-
exit(0)
|
67
|
-
else
|
68
|
-
puts "Matches:\n\n#{lines.join("\n")}\n\n"
|
69
|
-
puts "#{number_of_files(files)} checked, #{COLORS[:red]}#{number_of_matches(lines.size)} found in #{number_of_files(files_with_matches)}#{COLORS[:reset]}"
|
70
|
-
exit(1)
|
71
|
-
end
|
72
|
-
end
|
73
|
-
|
74
63
|
def excluded_path?(path)
|
75
64
|
excluded?(excluded_paths, relative_path(path)) || !search_hidden && hidden?(path)
|
76
65
|
end
|
@@ -83,29 +72,8 @@ module Grepfruit
|
|
83
72
|
list.any? { path.split("/").last(_1.length) == _1 }
|
84
73
|
end
|
85
74
|
|
86
|
-
def relative_path(path)
|
87
|
-
Pathname.new(path).relative_path_from(Pathname.new(dir)).to_s
|
88
|
-
end
|
89
|
-
|
90
|
-
def relative_path_with_line_num(path, line_num)
|
91
|
-
"#{relative_path(path)}:#{line_num + 1}"
|
92
|
-
end
|
93
|
-
|
94
|
-
def processed_line(line)
|
95
|
-
stripped_line = line.strip
|
96
|
-
truncate && stripped_line.length > truncate ? "#{stripped_line[0..truncate - 1]}..." : stripped_line
|
97
|
-
end
|
98
|
-
|
99
75
|
def hidden?(path)
|
100
76
|
File.basename(path).start_with?(".")
|
101
77
|
end
|
102
|
-
|
103
|
-
def number_of_files(num)
|
104
|
-
"#{num} file#{'s' if num > 1}"
|
105
|
-
end
|
106
|
-
|
107
|
-
def number_of_matches(num)
|
108
|
-
"#{num} match#{'es' if num > 1}"
|
109
|
-
end
|
110
78
|
end
|
111
79
|
end
|
data/lib/grepfruit/version.rb
CHANGED
data/lib/grepfruit.rb
CHANGED
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: grepfruit
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0.
|
4
|
+
version: 2.0.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- enjaku4
|
8
8
|
bindir: exe
|
9
9
|
cert_chain: []
|
10
|
-
date: 2025-
|
10
|
+
date: 2025-05-30 00:00:00.000000000 Z
|
11
11
|
dependencies: []
|
12
12
|
executables:
|
13
13
|
- grepfruit
|
@@ -20,15 +20,16 @@ files:
|
|
20
20
|
- exe/grepfruit
|
21
21
|
- grepfruit.gemspec
|
22
22
|
- lib/grepfruit.rb
|
23
|
+
- lib/grepfruit/decorator.rb
|
24
|
+
- lib/grepfruit/search.rb
|
23
25
|
- lib/grepfruit/version.rb
|
24
|
-
|
25
|
-
homepage: https://github.com/enjaku4/grepfruit
|
26
|
+
homepage: https://github.com/brownboxdev/grepfruit
|
26
27
|
licenses:
|
27
28
|
- MIT
|
28
29
|
metadata:
|
29
|
-
homepage_uri: https://github.com/
|
30
|
-
source_code_uri: https://github.com/
|
31
|
-
changelog_uri: https://github.com/
|
30
|
+
homepage_uri: https://github.com/brownboxdev/grepfruit
|
31
|
+
source_code_uri: https://github.com/brownboxdev/grepfruit
|
32
|
+
changelog_uri: https://github.com/brownboxdev/grepfruit/blob/master/CHANGELOG.md
|
32
33
|
rubygems_mfa_required: 'true'
|
33
34
|
rdoc_options: []
|
34
35
|
require_paths:
|