├── .gitignore ├── Features.txt ├── History.txt ├── README.md ├── Rakefile ├── bin ├── glark └── jlark ├── doc └── glark.pod ├── glark.spec ├── glark.yml ├── install.rb ├── lib ├── glark.rb └── glark │ ├── app │ ├── app.rb │ ├── help.rb │ ├── info │ │ └── options.rb │ ├── options.rb │ ├── rcfile.rb │ ├── runner.rb │ └── spec.rb │ ├── input │ ├── filter │ │ ├── criteria_opts.rb │ │ ├── dir_criteria_opts.rb │ │ ├── file_criteria_opts.rb │ │ ├── filter.rb │ │ └── options.rb │ ├── options.rb │ ├── range.rb │ └── spec.rb │ ├── io │ └── file │ │ ├── archive_file.rb │ │ ├── binary_file.rb │ │ ├── file.rb │ │ ├── gz_file.rb │ │ ├── tar_file.rb │ │ ├── tar_gz_file.rb │ │ └── zip_file.rb │ ├── match │ ├── and.rb │ ├── and_distance.rb │ ├── compound.rb │ ├── expression.rb │ ├── factory.rb │ ├── ior.rb │ ├── options.rb │ ├── or.rb │ ├── re.rb │ ├── re_factory.rb │ ├── spec.rb │ └── xor.rb │ ├── output │ ├── binary_file_summary.rb │ ├── common.rb │ ├── context.rb │ ├── count.rb │ ├── file_header.rb │ ├── file_name_only.rb │ ├── formatted.rb │ ├── glark_count.rb │ ├── glark_format.rb │ ├── glark_lines.rb │ ├── grep_count.rb │ ├── grep_lines.rb │ ├── line_status.rb │ ├── lines.rb │ ├── match_list.rb │ ├── options.rb │ ├── results.rb │ ├── spec.rb │ └── unfiltered_lines.rb │ └── util │ ├── colors │ ├── options.rb │ └── spec.rb │ ├── highlight.rb │ ├── io │ ├── depth.rb │ ├── fileset.rb │ ├── filter │ │ ├── criteria.rb │ │ └── filter.rb │ └── lines.rb │ ├── option.rb │ ├── options.rb │ ├── optutil.rb │ └── timestamper.rb ├── setup.rb └── test ├── glark ├── app │ ├── and_test.rb │ ├── compound_test.rb │ ├── context_test.rb │ ├── count_test.rb │ ├── expression_file_test.rb │ ├── extended_regexp_test.rb │ ├── extract_matches_test.rb │ ├── files_with_match_test.rb │ ├── files_without_match_test.rb │ ├── filter_test.rb │ ├── highlight_test.rb │ ├── ignore_case_test.rb │ ├── invert_test.rb │ ├── ior_test.rb │ ├── label_test.rb │ ├── line_number_color_test.rb │ ├── line_numbers_test.rb │ ├── match_limit_test.rb │ ├── options_test.rb │ ├── range_test.rb │ ├── rcfile_test.rb │ ├── record_separator_test.rb │ ├── regexp_test.rb │ ├── stdin_test.rb │ ├── tc.rb │ ├── text_color_test.rb │ ├── whole_lines_test.rb │ ├── whole_words_test.rb │ └── xor_test.rb ├── input │ ├── binary_file_test.rb │ ├── directory_test.rb │ ├── dirname_test.rb │ ├── exclude_matching_test.rb │ ├── ext_test.rb │ ├── filter │ │ ├── criteria_test.rb │ │ └── filter_test.rb │ ├── name_test.rb │ ├── path_test.rb │ ├── range_test.rb │ ├── size_limit_test.rb │ └── split_as_path_test.rb ├── match_test.rb ├── resources.rb └── tc.rb └── resources ├── 04-TheCooksTale.txt ├── aaa.zip ├── abcfile.txt ├── add.rb ├── canterbury ├── franklin │ ├── prologue.txt │ └── tale.txt └── prologue.txt ├── cat.pl ├── checkdot.gif ├── echo.rb ├── expressions.txt ├── filelist.txt ├── greet.rb ├── org-incava-ijdk-1.0.1.jar ├── rc.tar ├── rcext.txt ├── rcfile.txt ├── rcgrep.txt ├── rcmatch.txt ├── rcpath.txt ├── rubies.tar.gz ├── spaces.txt ├── textfile.txt ├── textfile.txt.gz ├── txt.tgz ├── zfile.txt └── zfile.txt.gz /.gitignore: -------------------------------------------------------------------------------- 1 | man 2 | pkg 3 | -------------------------------------------------------------------------------- /Features.txt: -------------------------------------------------------------------------------- 1 | Sun Oct 28 08:57:48 2012 2 | 3 | Removed -F short option for --file-color, reducing the number of options. 4 | 5 | Removed --word-regexp as another tag for the -w, --word option. 6 | 7 | Removed undocumented and unused --multiline option. 8 | 9 | Tue Oct 30 08:55:25 2012 10 | 11 | Removed --verbosity; redundant with --verbose. 12 | 13 | Wed Oct 31 07:50:46 2012 14 | 15 | Documented --extended option. 16 | 17 | Thu Nov 1 14:41:02 2012 18 | 19 | Removed filter from rcfile; unused and useless. 20 | 21 | Fri Nov 2 20:07:20 2012 22 | 23 | --dump: fixed to display the current settings. 24 | 25 | --conf: now displays configuration without empty lines between fields. 26 | 27 | Sat Nov 3 14:25:54 2012 28 | 29 | help: improved comment for --null. 30 | 31 | Sun Nov 4 16:32:00 2012 32 | 33 | help: added --split-as-path. 34 | 35 | help: simplified --with[out]-[base|full]name to --[match|not]-[name|path]. 36 | 37 | Wed Nov 7 20:21:59 2012 38 | 39 | --split-as-path: removed --split-as-path=true, which is redundant with 40 | --no-split-as-path. 41 | 42 | Thu Nov 8 08:58:14 2012 43 | 44 | --filter: removed as an option, since it is the default. 45 | readme: refined formatting. 46 | 47 | Fri Nov 9 14:02:25 2012 48 | 49 | --directories=action: refined the action to be skip, list, and recurse (AKA 50 | find), for simplicity and for integration with planned functionality. 51 | 52 | Added file patterns of the form /path/..., for recursive searching. 53 | 54 | Sat Nov 10 18:02:05 2012 55 | 56 | Added skipping of .svn directories. 57 | 58 | Sun Nov 11 09:09:12 2012 59 | 60 | Refined --match-name, --not-name, --match-path, --not-path to support multiple 61 | patterns. 62 | 63 | Added --match-dirname, --not-dirname, --match-dirpath, and --not-dirpath. 64 | These are for directories what --match-name et al are for files. 65 | 66 | Mon Nov 12 10:02:53 2012 67 | 68 | match-name, not-name, match-path, not-path: added functionality so that those 69 | fields can be defined multiple times in .glarkrc files. 70 | 71 | Tue Nov 13 11:38:28 2012 72 | 73 | Added --match-ext and --not-ext, for matching based on extensions. 74 | 75 | Wed Nov 14 18:53:49 2012 76 | 77 | Added match-ext and not-ext as rc file fields. 78 | 79 | Thu Nov 15 06:38:19 2012 80 | 81 | Removed obsolete "show-break" field from documentation. 82 | 83 | Wed Nov 21 15:28:55 2012 84 | 85 | Refined processing of directories, so that "implied" binary files are 86 | excluded. 87 | 88 | Changed default behavior of --binary to 'skip' instead of 'binary', so that 89 | binary files are omitted by default from being searched. 90 | 91 | Thu Nov 22 09:46:16 2012 92 | 93 | Fixed processing of skipped directories, specified by strings. Thus .svn as a 94 | filter no longer erroneously filters out '.' or '.svndir'. 95 | 96 | Added searching within gz files. 97 | 98 | Added searching of tar files as lists of files. 99 | 100 | Added searching of jar and zip files as lists of files. 101 | 102 | Added searching within jar and zip files. 103 | 104 | Added searching of tgz and tar.gz files as lists of files. 105 | 106 | Updated to work with Ruby 1.9. 107 | 108 | Fri Nov 23 15:31:12 2012 109 | 110 | Added to readme that '-' is the argument for standard input. 111 | 112 | Removed the options to unsuppress warnings, since they are enabled by default. 113 | 114 | Sat Nov 24 18:47:11 2012 115 | 116 | Added .git as excluded. Added commentary as such to the readme. 117 | 118 | Sun Nov 25 17:54:59 2012 119 | 120 | --match-x, --not-x: changed --not to more intuitive --skip. 121 | 122 | Mon Nov 26 15:41:01 2012 123 | 124 | Refined documentation, eliminating misleading angle brackets around values. 125 | 126 | Tue Nov 27 19:54:43 2012 127 | 128 | Refined documentation to explain that a warning will result if the expression 129 | is also a file. 130 | 131 | Wed Nov 28 19:57:29 2012 132 | 133 | Refined documentation to denote that the leading dot should not be included 134 | in the regular expression argument to the --match-ext and --skip-ext options. 135 | 136 | Thu Nov 29 19:57:47 2012 137 | 138 | Fixed so that invalid extensions are ignored with --binary-files=read (and 139 | =list), when globbing from a directory. 140 | 141 | Fri Nov 30 20:20:13 2012 142 | 143 | Worked around an erroneous warning from zlib regarding reading some tarballs. 144 | 145 | Added directories as searched for --binary-files=list. 146 | 147 | Sun Dec 9 10:49:18 2012 148 | 149 | Fixed --man option. 150 | 151 | Fri Dec 14 18:36:03 2012 152 | 153 | Fixed alignment when line numbers are colorized. 154 | 155 | Sat Dec 15 10:03:11 2012 156 | 157 | Added documentation. Added manpage to gem. 158 | 159 | Fixed handling of -Xy option, such as -N -h. 160 | 161 | Sun Dec 16 18:10:19 2012 162 | 163 | Fixed formatting error in documentation. 164 | 165 | Thu Feb 28 08:58:59 2013 166 | 167 | When reading from stdin, '-' is no longer displayed as the filename. 168 | 169 | Mon Mar 4 19:43:46 2013 170 | 171 | Removed 'reading standard input'. 172 | Released version 1.10.2. 173 | 174 | Tue Mar 5 20:01:43 2013 175 | 176 | Changed dependency from riel/log to logue. 177 | 178 | Fri Mar 8 19:30:17 2013 179 | 180 | Fixed dependency on Logue. 181 | Added require of pathname. 182 | 183 | Mon May 6 06:42:03 2013 184 | 185 | Fixed so that a file will not be searched multiple times. 186 | 187 | Thu May 9 08:15:32 2013 188 | 189 | Released version 1.10.3. 190 | -------------------------------------------------------------------------------- /History.txt: -------------------------------------------------------------------------------- 1 | === 1.10.0 2012-12-16 2 | 3 | * 1 major enhancement: 4 | * Initial release 5 | 6 | === 1.10.1 2013-12-16 7 | 8 | === 1.10.3 2013-05-09 9 | 10 | * Fixed so that a file will not be searched multiple times. 11 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require 'rubygems' 2 | require 'fileutils' 3 | require 'rake/testtask' 4 | require 'rubygems/package_task' 5 | 6 | task :default => :test 7 | 8 | Rake::TestTask.new('test') do |t| 9 | t.libs << 'lib' 10 | t.libs << 'test' 11 | t.pattern = 'test/**/*_test.rb' 12 | t.warning = true 13 | t.verbose = true 14 | end 15 | 16 | directory "man" 17 | 18 | desc "generate man page" 19 | task :generate_manpage => [ "man" ] do 20 | sh "ronn -r --pipe README.md > man/glark.1" 21 | end 22 | 23 | spec = Gem::Specification.new do |s| 24 | s.name = "glark" 25 | s.version = "1.10.5" 26 | s.author = "Jeff Pace" 27 | s.email = "jpace317@gmail.com" 28 | 29 | s.homepage = "http://www.incava.org/projects/glark" 30 | s.platform = Gem::Platform::RUBY 31 | s.summary = "Extended searching of text files." 32 | s.description = <<-EODESC 33 | Glark searches files for regular expressions, extending grep by matching complex 34 | expressions ("and", "or", and "xor"), extracting and searching within compressed 35 | files, and excluding .svn and .git subdirectories by default. Different projects 36 | can have their own Glark configuration. 37 | EODESC 38 | s.files = FileList["{lib,man}/**/*"].to_a + FileList["bin/glark"].to_a 39 | s.require_path = "lib" 40 | s.test_files = FileList["{test}/**/*.rb"].to_a 41 | s.has_rdoc = false 42 | s.bindir = 'bin' 43 | s.executables = %w{ glark } 44 | s.default_executable = 'glark' 45 | 46 | s.add_dependency("riel", ">= 1.2.0") 47 | s.add_dependency("logue", ">= 1.0.0") 48 | s.add_dependency("rainbow", ">= 2.0.0") 49 | s.add_dependency("ragol", ">= 1.0.0") 50 | end 51 | 52 | Gem::PackageTask.new(spec) do |pkg| 53 | pkg.need_zip = true 54 | pkg.need_tar_gz = true 55 | end 56 | -------------------------------------------------------------------------------- /bin/glark: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # exec ruby -w -x $0 ${1+"$@"} # -*- ruby -*- 3 | #!ruby -w 4 | # vim: set filetype=ruby : set sw=2 5 | 6 | # An extended grep, with extended functionality including full regular 7 | # expressions, contextual output, highlighting, detection and exclusion of 8 | # nontext files, and complex matching criteria. 9 | 10 | dir = File.dirname(File.dirname(File.expand_path(__FILE__))) 11 | 12 | libpath = dir + "/lib" 13 | $:.unshift libpath 14 | 15 | require 'glark/app/app' 16 | 17 | Glark::App.new 18 | 19 | __END__ 20 | # prototype of forthcoming feature: 21 | 22 | # multi-pass execution: 23 | ./glark --run=2 '/(\w+)\s*=\s*\d+/' *.c 24 | 25 | # means extract twice: 26 | 27 | first run: 28 | matches = Array.new 29 | GlarkOptions.matches = matches 30 | glark = Glark.new(ARGV, :write => false) 31 | glark.search($files) 32 | 33 | second run: 34 | GlarkOptions.matches = nil 35 | expr = MultiOrExpression.new(matches) 36 | glark = Glark.new(ARGV, :expr => expr) 37 | glark.search($files) 38 | -------------------------------------------------------------------------------- /bin/jlark: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | exec ruby -w -x $0 ${1+"$@"} # -*- ruby -*- 3 | #!ruby -w 4 | # vim: set filetype=ruby : set sw=2 5 | 6 | # Extends glark into Java archives (jar and zip files) 7 | 8 | # $Id$ 9 | 10 | dir = File.dirname(File.dirname(File.expand_path(__FILE__))) 11 | 12 | libpath = dir + "/share" 13 | $:.unshift libpath 14 | 15 | require 'glark/glark' 16 | 17 | $PACKAGE = "jlark" 18 | 19 | class Jlark < Glark 20 | 21 | def search(name) 22 | case name[-4 .. -1] 23 | when '.jar' 24 | search_jar_file(name) 25 | when '.zip' 26 | search_zip_file(name) 27 | end 28 | end 29 | 30 | def search_archive_file(fname, command) 31 | if skipped?(fname) 32 | log { "skipping file: #{fname}" } 33 | else 34 | IO.popen(command) do |io| 35 | ifile_args = { 36 | :after => @after, 37 | :before => @before, 38 | :output => @output 39 | } 40 | 41 | input = InputFile.new(fname, io, ifile_args) 42 | search_file(input) 43 | end 44 | end 45 | end 46 | 47 | def search_jar_file(fname) 48 | search_archive_file(fname, "jar tvf #{fname}") 49 | end 50 | 51 | def search_zip_file(fname) 52 | search_archive_file(fname, "unzip -l #{fname}") 53 | end 54 | end 55 | 56 | # and use a cached file for .jar and .zip files 57 | 58 | # the pattern is always -r ., with --classpath optional 59 | class JlarkOptions < GlarkOptions 60 | 61 | end 62 | 63 | Jlark.main 64 | -------------------------------------------------------------------------------- /glark.spec: -------------------------------------------------------------------------------- 1 | Summary: Text search application 2 | Name: glark 3 | Version: 1.8.2 4 | Release: 1 5 | Epoch: 0 6 | License: LGPL 7 | Group: Applications/Text 8 | URL: http://glark.sourceforge.net/ 9 | Source: http://prdownloads.sourceforge.net/glark/glark-%{version}.tar.gz 10 | BuildRoot: %{_tmppath}/%{name}-%{version}-root 11 | BuildArch: noarch 12 | Packager: Jeff Pace (jpace@incava.org) 13 | Vendor: incava.org 14 | Requires: ruby >= 1.6.0 15 | 16 | %description 17 | Similar to grep, glark searches files, automatically excluding binary 18 | file. It uses Perl compatible regular expressions, and can highlight 19 | matches, display context around matches, combine regular expressions 20 | into logical expressions using "and", "or", and "xor". Regular 21 | expressions can be negated. 22 | 23 | %prep 24 | %setup -q 25 | 26 | %build 27 | 28 | %install 29 | [ "$RPM_BUILD_ROOT" -a "$RPM_BUILD_ROOT" != / ] && rm -rf "$RPM_BUILD_ROOT" 30 | 31 | %makeinstall 32 | 33 | %clean 34 | [ "$RPM_BUILD_ROOT" -a "$RPM_BUILD_ROOT" != / ] && rm -rf "$RPM_BUILD_ROOT" 35 | 36 | %files 37 | %defattr(-,root,root,-) 38 | %{_bindir}/glark 39 | %{_mandir}/man1/glark.1* 40 | %attr(0755,root,root) %{_datadir}/glark/*.rb 41 | 42 | %changelog 43 | * Fri Oct 24 2008 Jeff Pace 1.8.2-1 44 | - Fixed error message for the usage of a single hyphen as an option. 45 | 46 | * Tue Aug 29 2006 Jeff Pace 1.7.11-1 47 | - Fixed stack overrun with very large search files. 48 | - Reorganized files. 49 | 50 | * Tue Aug 29 2006 Jeff Pace 1.7.10-1 51 | - Added support for --with/without-fullname/basename. 52 | - Fixed bug handling --after=N and --before=N for non-percentage arguments. 53 | 54 | * Thu Mar 30 2006 Jeff Pace 1.7.9-1 55 | - Fixed bug in --and option, which was getting the closest match within the 56 | maximum distance. 57 | - More refactoring and tests. 58 | 59 | * Sat Mar 18 2006 Jeff Pace 1.7.8-1 60 | - Fixed bug with --invert-match (-v) option. 61 | - Added check for cycles, for links that result in recursive file hierarchies. 62 | - Significant refactoring. 63 | 64 | * Wed Feb 22 2006 Jeff Pace 1.7.7-1 65 | - Fixed --label option to take any string. 66 | - Fixed warnings for unknown options. 67 | 68 | * Fri Jan 27 2006 Jeff Pace 1.7.6-1 69 | - Fixed exit status to match that of grep. 70 | - Extended -H option so that the file name is always printed, even if only one 71 | file is searched. 72 | 73 | * Sat Aug 27 2005 Jeff Pace 1.7.5-1 74 | - Added infix notation. 75 | 76 | * Tue Aug 9 2005 Jeff Pace 1.7.4-1 77 | - Fixed bug in --no-filter. 78 | - Added and refined documentation. 79 | - Added --size-limit option. 80 | 81 | * Tue May 31 2005 Jeff Pace 1.7.3-1 82 | - Added -- as the explicit end of options. 83 | - Bug in --binary-file mode fixed. 84 | - Line number colors disabled by default. 85 | 86 | * Thu Dec 23 2004 Jeff Pace 1.7.2-1 87 | - Fixed problem with line number and start of text. 88 | - Fixed bug in --binary-file mode. 89 | - Disabled line number colors, by default. 90 | 91 | * Thu Nov 4 2004 Jeff Pace 1.7.1-1 92 | - Added multiple colors for highlighting different regular expressions. 93 | - Added HTML output format. 94 | - Output is now unbuffered, that is, is written before end of file is reached. 95 | 96 | * Tue Apr 20 2004 Jeff Pace 1.7.0-1 97 | - Added --config option, for dumping the current configuration. 98 | - Added diff-line break ("---") as optional break between context blocks. 99 | - Added feature to split argument by path separator, for searching recursively 100 | along a path. 101 | - Extended "--and NUM" to "--and=NUM" format. 102 | - Fixed --exclude-matching option. 103 | - Fixed highlighted strings, so that the ANSI codes are not matched with regexps. 104 | - Refined --help output into more logical sections. 105 | - Removed --no-line-regexp and --no-word options, which are not necessary. 106 | 107 | * Thu Apr 8 2004 Jeff Pace 1.7.0-1 108 | - Added --fullname/--path and --basename/--name options. 109 | - Added --xor option. 110 | - Cleanup of RPM spec file and Makefile. 111 | 112 | * Tue Apr 6 2004 Jose Pedro Oliveira 0:1.6.8-2 113 | - removal of several rpmlint warnings/errors 114 | 115 | * Fri Mar 05 2004 Jeff Pace 116 | - Implemented support of '!/expression/'. 117 | -------------------------------------------------------------------------------- /glark.yml: -------------------------------------------------------------------------------- 1 | --- !ruby/object:Bazr::Project 2 | build: 3 | tests: tests 4 | default: '' 5 | type: make 6 | release: 7 | - dist 8 | - "./buildrpms [project]-[version].tar.gz" 9 | description: '' 10 | issues: [] 11 | longname: '' 12 | owner: jpace 13 | rpmspec: glark.spec 14 | shortname: glark 15 | vcs: cvs 16 | version: 1.7.3 17 | -------------------------------------------------------------------------------- /install.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby -w 2 | # -*- ruby -*- 3 | 4 | require "rbconfig" 5 | require "ftools" 6 | 7 | include Config 8 | 9 | prefix = ENV['prefix'] || '/usr' 10 | version = CONFIG["MAJOR"] + "." + CONFIG["MINOR"] 11 | libdest = prefix + CONFIG["sitedir"].sub(Regexp.new(/^\/usr/), "") + File::SEPARATOR + version + File::SEPARATOR + "glark" 12 | bindir = prefix + "/bin" 13 | mandir = prefix + "/share/man/man1" 14 | 15 | libfiles = %w{ apphelp env glark log opt regexp texthighlight } 16 | 17 | # puts "libdest: #{libdest}" 18 | 19 | if ARGV[0] == "uninstall" 20 | libfiles.each do |libfile| 21 | File.safe_unlink(libdest + File::SEPARATOR + libfile + ".rb") 22 | end 23 | Dir.rmdir(libdest) 24 | File.safe_unlink(bindir + File::SEPARATOR + "bin/glark") 25 | File.safe_unlink(mandir + File::SEPARATOR + "glark.1") 26 | else 27 | File.makedirs(libdest) 28 | File.makedirs(bindir) 29 | File.makedirs(mandir) 30 | 31 | libfiles.each do |libfile| 32 | puts "File.install(\"lib/glark/#{libfile}.rb\", #{libdest})" 33 | File.install("lib/glark/" + libfile + ".rb", libdest) 34 | end 35 | 36 | puts "File.install(\"bin/glark\", #{bindir})" 37 | File.install("bin/glark", bindir) 38 | 39 | puts "File.install(\"glark.1\", #{mandir})" 40 | File.install("glark.1", mandir) 41 | end 42 | -------------------------------------------------------------------------------- /lib/glark.rb: -------------------------------------------------------------------------------- 1 | $:.unshift(File.dirname(__FILE__)) unless 2 | $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__))) 3 | 4 | require 'glark/app/app' 5 | -------------------------------------------------------------------------------- /lib/glark/app/app.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby -w 2 | #!ruby -w 3 | # vim: set filetype=ruby : set sw=2 4 | 5 | # An extended grep, with extended functionality including full regular 6 | # expressions, contextual output, highlighting, detection and exclusion of 7 | # nontext files, and complex matching criteria. 8 | 9 | require 'glark/app/options' 10 | require 'glark/app/runner' 11 | 12 | Rainbow.enabled = true 13 | 14 | module Glark 15 | class App 16 | def initialize 17 | begin 18 | Logue::Log.set_widths(-15, -40, -40) 19 | 20 | opts = AppOptions.new 21 | opts.run ARGV 22 | 23 | # To get rid of the annoying stack trace on ctrl-C: 24 | trap("INT") { abort } 25 | 26 | if opts.info_options.explain 27 | puts opts.match_spec.expr.explain 28 | end 29 | 30 | files = ARGV.size > 0 ? ARGV : [ '-' ] 31 | runner = Runner.new opts, files 32 | 33 | exit runner.exit_status 34 | rescue => e 35 | # show the message, and the stack trace only if verbose: 36 | $stderr.puts "error: #{e}" 37 | if Logue::Log.verbose 38 | $stderr.puts e.backtrace 39 | raise 40 | else 41 | exit 2 42 | end 43 | end 44 | end 45 | end 46 | end 47 | 48 | if __FILE__ == $0 49 | Glark::App.new 50 | end 51 | -------------------------------------------------------------------------------- /lib/glark/app/help.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby -w 2 | # -*- ruby -*- 3 | 4 | module Glark 5 | class Help 6 | def show_usage 7 | puts "Usage: glark [options] expression file..." 8 | puts "Search for expression in each file or standard input." 9 | puts "Example: glark --and=3 'try' 'catch' *.java" 10 | puts "" 11 | 12 | puts "Input:" 13 | puts " -0[nnn] Use \\nnn as the input record separator" 14 | puts " --before NUM[%] Restrict the search to the top % or lines" 15 | puts " --after NUM[%] Restrict the search to after the given location" 16 | puts " -d, --directories=ACTION Process directories as list, skip, or find (recurse)" 17 | puts " --binary-files=TYPE Treat binary files as TYPE" 18 | puts " --split-as-path Treat file arguments as paths, to be split into directories and files" 19 | puts " --match-name EXPR Search only files with names (base names) matching EXPR" 20 | puts " --not-name EXPR Ignore files with names matching EXPR" 21 | puts " --match-path EXPR Search only files with paths (full names) matching EXPR" 22 | puts " --not-path EXPR Ignore files with paths matching EXPR" 23 | puts " --match-dirname EXPR Search only directories with base names matching EXPR" 24 | puts " --not-dirname EXPR Ignore directories with names matching EXPR" 25 | puts " --match-dirpath EXPR Search only directories with full paths matching EXPR" 26 | puts " --not-dirpath EXPR Ignore directories with full paths matching EXPR" 27 | puts " -M, --exclude-matching Ignore files with names matching the expression" 28 | puts " -R, --range NUM[%],NUM[%] Restrict the search to the given range of lines per file." 29 | puts " -r, --recurse Recurse through directories" 30 | puts " --size-limit=SIZE Search only files no larger than SIZE" 31 | puts "" 32 | 33 | puts "Matching:" 34 | puts " -a, --and=NUM EXPR1 EXPR2 Match both expressions, within NUM lines" 35 | puts " --extended Use the given regular expression as extended" 36 | puts " -f, --file=FILE Use the lines in the given file as expressions" 37 | puts " -i, --ignore-case Ignore case for matching regular expressions" 38 | puts " -o, --or EXPR1 EXPR2 Match either of the two expressions" 39 | puts " -w, --word Match the pattern(s) with word boundaries added" 40 | puts " -x, --line-regexp Select entire line matching pattern" 41 | puts " --xor EXPR1 EXPR2 Match either expression, but not both" 42 | puts "" 43 | 44 | puts "Output:" 45 | puts " -A, --after-context=NUM Print NUM lines of trailing context" 46 | puts " -B, --before-context=NUM Print NUM lines of leading context" 47 | puts " -C, -NUM, --context[=NUM] Output NUM lines of context" 48 | puts " -c, --count Display only the match count per file" 49 | puts " --file-color COLOR Specify the highlight color for file names" 50 | puts " --no-filter Display the entire file, not only the matching lines" 51 | puts " -g, --grep Produce output like the grep default" 52 | puts " -h, --no-filename Do not display the names of matching files" 53 | puts " -H, --with-filename Display the names of matching files" 54 | puts " -l, --files-with-matches Print only names of matching file" 55 | puts " -L, --files-without-match Print only names of file not matching" 56 | puts " --label=NAME Use NAME as output file name" 57 | puts " -n, --line-number Display line numbers" 58 | puts " -N, --no-line-number Do not display line numbers" 59 | puts " --line-number-color COLOR Specify the highlight color for line numbers" 60 | puts " -m, --match-limit=NUM Find only the first NUM matches in each file" 61 | puts " --text-color COLOR Specify the highlight color for text" 62 | puts " -u, --highlight[=FORMAT] Enable highlighting. Format is single or multi" 63 | puts " -U, --no-highlight Disable highlighting" 64 | puts " -v, --invert-match Show lines not matching the expression" 65 | puts " -y, --extract-matches Display only the matching region, not the entire line" 66 | puts " -Z, --null In --files-with-matches mode, write file names followed by NULL" 67 | puts "" 68 | 69 | puts "Debugging/Errors:" 70 | puts " --conf Write the current options in RC file format" 71 | puts " --dump Write all options and expressions" 72 | puts " --explain Write the expression in a more legible format" 73 | puts " -q, --quiet Suppress warnings" 74 | puts " -Q, --no-quiet Enable warnings" 75 | puts " -s, --no-messages Suppress warnings" 76 | puts " -V, --version Display version information" 77 | puts " --verbose Display normally suppressed output" 78 | 79 | puts "" 80 | puts "Run gem man glark for more information. That requires the installation of the gem-man gem." 81 | end 82 | 83 | def show_man 84 | pn = Pathname.new __FILE__ 85 | 86 | dir = pn 87 | 0.upto(3) do 88 | break unless dir 89 | dir = dir.parent 90 | end 91 | 92 | if dir 93 | # manfile = dir + "man/glark.1" 94 | cmd = "gem man glark" 95 | ::IO.popen(cmd) do |io| 96 | puts io.readlines 97 | end 98 | else 99 | puts "no doc directory" 100 | end 101 | end 102 | end 103 | end 104 | -------------------------------------------------------------------------------- /lib/glark/app/info/options.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby -w 2 | #!ruby -w 3 | # vim: set filetype=ruby : set sw=2 4 | 5 | require 'glark/app/help' 6 | require 'glark/util/options' 7 | 8 | module Glark 9 | PACKAGE = 'glark' 10 | VERSION = '1.10.5' 11 | 12 | class InfoOptions < Options 13 | attr_reader :colors 14 | attr_reader :explain 15 | 16 | def initialize colors, optdata 17 | @colors = colors 18 | @explain = false # display a legible version of the expression 19 | 20 | add_as_options optdata 21 | end 22 | 23 | def config_fields 24 | { 25 | "known-nontext-files" => FileType.nontext_extensions.sort.join(' '), 26 | "known-text-files" => FileType.text_extensions.sort.join(' '), 27 | "quiet" => Logue::Log.quiet, 28 | "verbose" => Logue::Log.verbose, 29 | } 30 | end 31 | 32 | def dump_fields 33 | { 34 | "explain" => @explain, 35 | "known_nontext_files" => FileType.nontext_extensions.join(", "), 36 | "known_text_files" => FileType.text_extensions.join(", "), 37 | "quiet" => Logue::Log.quiet, 38 | "ruby version" => RUBY_VERSION, 39 | "verbose" => Logue::Log.verbose, 40 | "version" => Glark::VERSION, 41 | } 42 | end 43 | 44 | def update_fields fields 45 | fields.each do |name, values| 46 | case name 47 | when "known-nontext-files" 48 | values.last.split.each do |ext| 49 | FileType.set_nontext ext 50 | end 51 | when "known-text-files" 52 | values.last.split.each do |ext| 53 | FileType.set_text ext 54 | end 55 | when "quiet" 56 | Logue::Log.quiet = to_boolean(values.last) 57 | when "verbose" 58 | Logue::Log.verbose = to_boolean(values.last) ? 1 : nil 59 | when "verbosity" 60 | Logue::Log.verbose = values.last.to_i 61 | end 62 | end 63 | end 64 | 65 | def add_as_options optdata 66 | add_opt_blk(optdata, %w{ -V --version }) { show_version } 67 | add_opt_blk(optdata, %w{ --verbose }) { Logue::Log.verbose = true } 68 | add_opt_blk(optdata, %w{ -? --help }) { Help.new.show_usage; exit 0 } 69 | add_opt_blk(optdata, %w{ --man }) { Help.new.show_man; exit 0 } 70 | 71 | add_opt_true optdata, :explain, %w{ --explain } 72 | 73 | add_opt_blk(optdata, %w{ -q -s --quiet --messages }) { Logue::Log.quiet = true } 74 | add_opt_blk(optdata, %w{ -Q -S --no-quiet --no-messages }) { Logue::Log.quiet = false } 75 | end 76 | 77 | def show_version 78 | puts Glark::PACKAGE + ", version " + Glark::VERSION 79 | puts "Written by Jeff Pace (jeugenepace@gmail.com)." 80 | puts "Released under the Lesser GNU Public License." 81 | exit 0 82 | end 83 | end 84 | end 85 | -------------------------------------------------------------------------------- /lib/glark/app/options.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby -w 2 | # -*- ruby -*- 3 | 4 | require 'rubygems' 5 | require 'riel/dir' 6 | require 'ragol/optproc/optproc' 7 | require 'riel/env' 8 | require 'glark/app/info/options' 9 | require 'glark/app/rcfile' 10 | require 'glark/app/spec' 11 | require 'glark/input/options' 12 | require 'glark/match/options' 13 | require 'glark/output/options' 14 | require 'glark/util/colors/options' 15 | require 'glark/util/options' 16 | require 'glark/util/optutil' 17 | require 'pathname' 18 | 19 | module Glark 20 | class OptionSet < OptProc::OptionSet 21 | include Logue::Loggable 22 | 23 | def set_option results 24 | # intercept these, which we'll use to create the expression: 25 | %w{ -o --or --and -a \( \) --xor }.each do |tag| 26 | return nil if results.current_arg.index(tag) == 0 27 | end 28 | super 29 | end 30 | end 31 | 32 | class AppOptions < AppSpec 33 | include OptionUtil 34 | 35 | attr_reader :colors 36 | attr_reader :fileset 37 | attr_reader :info_options 38 | attr_reader :output_options 39 | 40 | def initialize 41 | optdata = Array.new 42 | 43 | @colors = ColorOptions.new 44 | 45 | @input_options = InputOptions.new optdata 46 | @match_options = MatchOptions.new @colors, optdata 47 | @output_options = OutputOptions.new @colors, optdata 48 | 49 | @info_options = InfoOptions.new @colors, optdata 50 | 51 | add_opt_blk(optdata, %w{ --config }) { write_configuration; exit } 52 | add_opt_blk(optdata, %w{ --dump }) { dump_all_fields; exit 0 } 53 | 54 | super @input_options, @match_options, @output_options 55 | 56 | @optset = OptionSet.new optdata 57 | end 58 | 59 | def run args 60 | @args = args 61 | 62 | read_home_rcfile 63 | 64 | if @local_config_files 65 | read_local_rcfiles 66 | end 67 | 68 | read_environment_variable 69 | 70 | # honor thy EMACS; go to grep mode 71 | if ENV["EMACS"] 72 | @output_options.style = "grep" 73 | end 74 | 75 | read_options 76 | 77 | validate! 78 | 79 | @fileset = @input_options.create_fileset @args 80 | 81 | if @output_options.show_file_names.nil? 82 | @output_options.show_file_names = @output_options.label || !one_file? 83 | end 84 | end 85 | 86 | def one_file? 87 | return false if @fileset.size > 1 88 | first = @fileset.files.first 89 | first.to_s != '-' && first.file? 90 | end 91 | 92 | def read_home_rcfile 93 | return unless hdir = Dir.home 94 | hdpn = Pathname.new hdir 95 | homerc = hdpn + '.glarkrc' 96 | read_rcfile homerc 97 | end 98 | 99 | def read_local_rcfiles 100 | hdir = Dir.home 101 | dir = Pathname.new('.').expand_path 102 | while !dir.root? && dir != hdir 103 | rcfile = dir + '.glarkrc' 104 | return if read_rcfile rcfile 105 | dir = dir.dirname 106 | end 107 | end 108 | 109 | def all_option_sets 110 | [ @colors, @match_options, @output_options, @info_options, @input_options ] 111 | end 112 | 113 | def read_rcfile rcfname 114 | return nil unless rcfname.exist? 115 | rcfile = RCFile.new rcfname 116 | rcvalues = rcfile.names.collect { |name| [ name, rcfile.values(name) ] } 117 | 118 | all_option_sets.each do |opts| 119 | opts.update_fields rcvalues 120 | end 121 | update_fields rcvalues 122 | true 123 | end 124 | 125 | def config_fields 126 | { 127 | "local-config-files" => @local_config_files, 128 | } 129 | end 130 | 131 | def dump_fields 132 | config_fields 133 | end 134 | 135 | def update_fields fields 136 | fields.each do |name, values| 137 | case name 138 | when "local-config-files" 139 | @local_config_files = to_boolean values.last 140 | end 141 | end 142 | end 143 | 144 | def read_environment_variable 145 | options = Env.split "GLARKOPTS" 146 | while options.size > 0 147 | @optset.process_option options 148 | end 149 | end 150 | 151 | def read_expression 152 | if @args.size > 0 153 | known_end = false 154 | if @args[0] == "--" 155 | @args.shift 156 | known_end = true 157 | end 158 | 159 | if @args && @args.size > 0 160 | return @match_options.read_expression @args, !known_end 161 | end 162 | end 163 | 164 | if @args.size > 0 165 | raise "No expression provided." 166 | end 167 | 168 | $stderr.puts "Usage: glark [options] expression file..." 169 | $stderr.puts "Try `glark --help' for more information." 170 | exit 1 171 | end 172 | 173 | def read_options 174 | # solitary "-v" means "--version", not --invert-match 175 | @info_options.show_version if @args.size == 1 && @args.first == "-v" 176 | 177 | @match_options.expr = nil 178 | 179 | @optset.process(@args) 180 | 181 | unless @match_options.expr 182 | read_expression 183 | end 184 | end 185 | 186 | def write_configuration 187 | fields = config_fields 188 | all_option_sets.each do |opts| 189 | fields.merge! opts.config_fields 190 | end 191 | 192 | fields.keys.sort.each do |fname| 193 | puts "#{fname}: #{fields[fname]}" 194 | end 195 | end 196 | 197 | def dump_all_fields 198 | fields = dump_fields 199 | all_option_sets.each do |opts| 200 | fields.merge! opts.dump_fields 201 | end 202 | 203 | len = fields.keys.collect { |f| f.length }.max 204 | 205 | fields.keys.sort.each do |field| 206 | printf "%*s : %s\n", len, field, fields[field] 207 | end 208 | end 209 | 210 | # check options for collisions/data validity 211 | def validate! 212 | @input_options.range.validate! 213 | end 214 | end 215 | end 216 | -------------------------------------------------------------------------------- /lib/glark/app/rcfile.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby -w 2 | # -*- ruby -*- 3 | 4 | require 'pathname' 5 | 6 | module Glark 7 | class RCFile 8 | COMMENT_RE = Regexp.new '\s*#.*' 9 | NAME_VALUE_RE = Regexp.new '\s*[=:]\s*' 10 | 11 | def initialize file 12 | @values = Array.new 13 | 14 | pn = file.kind_of?(Pathname) ? file : Pathname.new(file) 15 | 16 | return unless pn.exist? 17 | 18 | pn.each_line do |line| 19 | read_line line 20 | end 21 | end 22 | 23 | def read_line line 24 | line.sub! COMMENT_RE, '' 25 | line.chomp! 26 | return if line.empty? 27 | 28 | name, value = line.split NAME_VALUE_RE 29 | return unless name && value 30 | 31 | add name, value 32 | end 33 | 34 | def names 35 | @values.collect { |x| x[0] } 36 | end 37 | 38 | def values name 39 | ary = @values.assoc name 40 | ary && ary[1 .. -1] 41 | end 42 | 43 | def add name, value 44 | if ary = @values.assoc(name) 45 | ary << value 46 | else 47 | @values << [ name, value ] 48 | end 49 | end 50 | end 51 | end 52 | -------------------------------------------------------------------------------- /lib/glark/app/runner.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby -w 2 | #!ruby -w 3 | # vim: set filetype=ruby : set sw=2 4 | 5 | require 'rubygems' 6 | require 'logue/loggable' 7 | require 'glark/app/options' 8 | require 'glark/io/file/binary_file' 9 | require 'glark/io/file/gz_file' 10 | require 'glark/io/file/tar_file' 11 | require 'glark/io/file/tar_gz_file' 12 | require 'glark/io/file/zip_file' 13 | 14 | $stdout.sync = true # unbuffer 15 | $stderr.sync = true # unbuffer 16 | 17 | module Glark 18 | # The main processor. 19 | class Runner 20 | include Logue::Loggable 21 | 22 | GZ_RE = Regexp.new '\.gz$' 23 | TAR_GZ_RE = Regexp.new '\.(?:tgz|tar\.gz)$' 24 | TAR_RE = Regexp.new '\.tar$' 25 | ZIP_RE = Regexp.new '\.(?:zip|jar)$' 26 | 27 | attr_reader :exit_status 28 | 29 | def initialize opts, files 30 | @opts = opts 31 | @expr = opts.match_spec.expr 32 | @searched_files = Array.new # files searched, so we don't cycle through links 33 | 34 | @exclude_matching = @opts.input_spec.exclude_matching 35 | 36 | @range = @opts.input_spec.range 37 | @output_opts = @opts.output_options 38 | @invert_match = @output_opts.invert_match 39 | 40 | # 0 == matches, 1 == no matches, 2 == error 41 | @exit_status = @invert_match ? 0 : 1 42 | 43 | @output_type_cls = @output_opts.output_type_cls 44 | 45 | @opts.fileset.each do |type, file| 46 | search type, file 47 | end 48 | end 49 | 50 | def search_file file, output_type_cls = @output_type_cls 51 | output_type = output_type_cls.new file, @output_opts 52 | update_status file.search @expr, output_type 53 | end 54 | 55 | def update_status matched 56 | if matched 57 | @exit_status = @invert_match ? 1 : 0 58 | end 59 | end 60 | 61 | def search_text fname, io 62 | file = Glark::File.new fname, io, @range 63 | search_file file 64 | end 65 | 66 | def search_binary fname 67 | file = Glark::BinaryFile.new fname 68 | update_status file.search_as_binary @expr, @output_opts 69 | end 70 | 71 | def search_read_archive_file fname, cls 72 | @output_opts.show_file_names = true 73 | file = cls.new fname, @range 74 | update_status file.search @expr, @output_type_cls, @output_opts 75 | end 76 | 77 | def search_read fname 78 | fstr = fname.to_s 79 | 80 | case 81 | when TAR_GZ_RE.match(fstr) 82 | search_read_archive_file fname, Glark::TarGzFile 83 | when GZ_RE.match(fstr) 84 | search_file Glark::GzFile.new(fname, @range) 85 | when TAR_RE.match(fstr) 86 | search_read_archive_file fname, Glark::TarFile 87 | when ZIP_RE.match(fstr) 88 | search_read_archive_file fname, Glark::ZipFile 89 | else 90 | warn "file '#{fstr}' does not have a handled extension for reading content" 91 | return 92 | end 93 | end 94 | 95 | def search_list fname 96 | fstr = fname.to_s 97 | 98 | cls = case 99 | when TAR_RE.match(fstr) 100 | Glark::TarFile 101 | when ZIP_RE.match(fstr) 102 | Glark::ZipFile 103 | when TAR_GZ_RE.match(fstr) 104 | Glark::TarGzFile 105 | else 106 | warn "file '#{fstr}' does not have a handled extension for reading a list" 107 | return 108 | end 109 | 110 | file = cls.new fname, @range 111 | 112 | update_status file.search_list(@expr, @output_type_cls, @output_opts) 113 | end 114 | 115 | def search type, name 116 | if @exclude_matching 117 | expr = @opts.match_spec.expr 118 | return if expr.respond_to?(:re) && expr.re.match(name.to_s) 119 | end 120 | 121 | if name == "-" 122 | info "reading standard input..." 123 | search_text nil, $stdin 124 | else 125 | case type 126 | when :binary 127 | search_binary name 128 | when :text 129 | search_text name, ::File.new(name) 130 | when :read 131 | search_read name 132 | when :list 133 | search_list name 134 | else 135 | raise "type unknown: file: #{name}; type: #{type}" 136 | end 137 | end 138 | end 139 | end 140 | end 141 | -------------------------------------------------------------------------------- /lib/glark/app/spec.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby -w 2 | # -*- ruby -*- 3 | 4 | module Glark 5 | class AppSpec 6 | attr_reader :local_config_files 7 | 8 | attr_reader :input_spec 9 | attr_reader :match_spec 10 | attr_reader :output_spec 11 | 12 | def initialize input_spec, match_spec, output_spec 13 | @input_spec = input_spec 14 | @match_spec = match_spec 15 | @output_spec = output_spec 16 | @local_config_files = false # use local .glarkrc files 17 | end 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /lib/glark/input/filter/criteria_opts.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby -w 2 | #!ruby -w 3 | # vim: set filetype=ruby : set sw=2 4 | 5 | require 'glark/util/io/filter/criteria' 6 | 7 | module Glark 8 | class CriteriaOpts < Criteria 9 | def initialize 10 | super 11 | @options = opt_classes.collect { |optcls| optcls.new self } 12 | end 13 | 14 | def opt_classes 15 | Array.new 16 | end 17 | 18 | def config_fields 19 | Hash.new 20 | end 21 | 22 | def dump_fields 23 | config_fields 24 | end 25 | 26 | def update_fields rcfields 27 | rcfields.each do |name, values| 28 | @options.each do |opt| 29 | opt.match_rc name, values 30 | end 31 | end 32 | end 33 | 34 | def add_as_options optdata 35 | @options.each do |opt| 36 | opt.add_to_option_data optdata 37 | end 38 | end 39 | end 40 | end 41 | -------------------------------------------------------------------------------- /lib/glark/input/filter/dir_criteria_opts.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby -w 2 | #!ruby -w 3 | # vim: set filetype=ruby : set sw=2 4 | 5 | require 'glark/input/filter/criteria_opts' 6 | require 'glark/input/filter/options' 7 | require 'glark/util/optutil' 8 | 9 | module Glark 10 | class DirCriteriaOpts < CriteriaOpts 11 | include OptionUtil 12 | 13 | attr_accessor :skip_all 14 | 15 | def initialize skip_all 16 | super() 17 | @skip_all = skip_all 18 | 19 | add :name, :negative, BaseNameFilter.new('.svn') 20 | add :name, :negative, BaseNameFilter.new('.git') 21 | end 22 | 23 | def skipped? pn, depth 24 | return true if @skip_all || !depth.nonzero? 25 | super pn 26 | end 27 | 28 | def opt_classes 29 | [ 30 | MatchDirNameOption, 31 | SkipDirNameOption, 32 | MatchDirPathOption, 33 | SkipDirPathOption, 34 | ] 35 | end 36 | end 37 | end 38 | -------------------------------------------------------------------------------- /lib/glark/input/filter/file_criteria_opts.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby -w 2 | #!ruby -w 3 | # vim: set filetype=ruby : set sw=2 4 | 5 | require 'glark/input/filter/criteria_opts' 6 | require 'glark/input/filter/filter' 7 | require 'glark/input/filter/options' 8 | require 'glark/util/optutil' 9 | 10 | module Glark 11 | class FileCriteriaOpts < CriteriaOpts 12 | include OptionUtil 13 | 14 | def opt_classes 15 | [ 16 | SizeLimitOption, 17 | MatchNameOption, 18 | SkipNameOption, 19 | MatchPathOption, 20 | SkipPathOption, 21 | MatchExtOption, 22 | SkipExtOption, 23 | ] 24 | end 25 | 26 | def config_fields 27 | maxsize = (filter = find_by_class(:size, :negative, SizeLimitFilter)) && filter.max_size 28 | { 29 | "size-limit" => maxsize 30 | } 31 | end 32 | end 33 | end 34 | -------------------------------------------------------------------------------- /lib/glark/input/filter/filter.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby -w 2 | #!ruby -w 3 | # vim: set filetype=ruby : set sw=2 4 | 5 | require 'rubygems' 6 | require 'logue/loggable' 7 | require 'glark/util/io/filter/filter' 8 | 9 | module Glark 10 | class PatternFilter < Filter 11 | include Logue::Loggable 12 | 13 | attr_reader :pattern 14 | 15 | def initialize pattern 16 | @pattern = pattern 17 | end 18 | 19 | def pattern_match? str 20 | if @pattern.kind_of? String 21 | @pattern == str 22 | else 23 | @pattern.match str 24 | end 25 | end 26 | 27 | def to_s 28 | @pattern.to_s 29 | end 30 | end 31 | 32 | class BaseNameFilter < PatternFilter 33 | def match? pn 34 | pattern_match? pn.basename.to_s 35 | end 36 | end 37 | 38 | class FullNameFilter < PatternFilter 39 | def match? pn 40 | pattern_match? pn.to_s 41 | end 42 | end 43 | 44 | class SizeLimitFilter < Glark::Filter 45 | attr_reader :max_size 46 | 47 | def initialize maxsize 48 | @max_size = maxsize 49 | end 50 | 51 | def match? pn 52 | pn.size > @max_size 53 | end 54 | end 55 | 56 | class ExtFilter < PatternFilter 57 | def match? pn 58 | pattern_match? pn.extname.to_s[1 .. -1] 59 | end 60 | end 61 | end 62 | -------------------------------------------------------------------------------- /lib/glark/input/filter/options.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby -w 2 | #!ruby -w 3 | # vim: set filetype=ruby : set sw=2 4 | 5 | require 'glark/input/filter/filter' 6 | require 'glark/util/option' 7 | 8 | module Glark 9 | class SizeLimitOption < Option 10 | def argtype 11 | :integer 12 | end 13 | 14 | def posneg 15 | :negative 16 | end 17 | 18 | def field 19 | :size 20 | end 21 | 22 | def set val 23 | @optee.add field, posneg, SizeLimitFilter.new(val.to_i) 24 | end 25 | 26 | def rcfield 27 | 'size-limit' 28 | end 29 | end 30 | 31 | class RegexpOption < Glark::Option 32 | def set val 33 | @optee.add field, posneg, cls.new(Regexp.create val) 34 | end 35 | 36 | def argtype 37 | :string 38 | end 39 | end 40 | 41 | module MatchOption 42 | def rcfield 43 | 'match-' + field.to_s 44 | end 45 | 46 | def posneg 47 | :positive 48 | end 49 | end 50 | 51 | module SkipOption 52 | def tags 53 | %w{ not skip }.collect { |x| '--' + x + '-' + field.to_s } 54 | end 55 | 56 | def rcfield 57 | 'skip-' + field.to_s 58 | end 59 | 60 | def posneg 61 | :negative 62 | end 63 | end 64 | 65 | class ExtOption < RegexpOption 66 | def cls 67 | ExtFilter 68 | end 69 | 70 | def field 71 | :ext 72 | end 73 | end 74 | 75 | class MatchExtOption < ExtOption 76 | include MatchOption 77 | end 78 | 79 | class SkipExtOption < ExtOption 80 | include SkipOption 81 | end 82 | 83 | class NameOption < RegexpOption 84 | def cls 85 | BaseNameFilter 86 | end 87 | 88 | def field 89 | :name 90 | end 91 | end 92 | 93 | class MatchNameOption < NameOption 94 | include MatchOption 95 | 96 | def tags 97 | %w{ --basename --name --with-basename --with-name } + super 98 | end 99 | end 100 | 101 | class SkipNameOption < NameOption 102 | include SkipOption 103 | 104 | def tags 105 | %w{ --without-basename --without-name } + super 106 | end 107 | end 108 | 109 | class DirNameOption < RegexpOption 110 | def cls 111 | BaseNameFilter 112 | end 113 | 114 | def field 115 | :dirname 116 | end 117 | end 118 | 119 | class MatchDirNameOption < DirNameOption 120 | include MatchOption 121 | end 122 | 123 | class SkipDirNameOption < DirNameOption 124 | include SkipOption 125 | end 126 | 127 | class PathOption < RegexpOption 128 | def cls 129 | FullNameFilter 130 | end 131 | 132 | def field 133 | :path 134 | end 135 | end 136 | 137 | class MatchPathOption < PathOption 138 | include MatchOption 139 | 140 | def tags 141 | %w{ --fullname --path --with-fullname --with-path } + super 142 | end 143 | end 144 | 145 | class SkipPathOption < PathOption 146 | include SkipOption 147 | 148 | def tags 149 | %w{ --without-fullname --without-path } + super 150 | end 151 | end 152 | 153 | 154 | class DirPathOption < RegexpOption 155 | def cls 156 | FullNameFilter 157 | end 158 | 159 | def field 160 | :dirpath 161 | end 162 | end 163 | 164 | class MatchDirPathOption < DirPathOption 165 | include MatchOption 166 | end 167 | 168 | class SkipDirPathOption < DirPathOption 169 | include SkipOption 170 | end 171 | end 172 | -------------------------------------------------------------------------------- /lib/glark/input/options.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby -w 2 | #!ruby -w 3 | # vim: set filetype=ruby : set sw=2 4 | 5 | # Options for input. 6 | 7 | require 'rubygems' 8 | require 'logue/loggable' 9 | require 'glark/input/spec' 10 | require 'glark/util/io/fileset' 11 | require 'glark/util/options' 12 | 13 | module Glark 14 | class InputOptions < InputSpec 15 | include OptionUtil, Logue::Loggable 16 | 17 | def initialize optdata 18 | super() 19 | add_as_options optdata 20 | end 21 | 22 | def create_fileset files 23 | fsargs = Hash.new 24 | fsargs[:max_depth] = @max_depth 25 | fsargs[:binary_files] = @binary_files 26 | fsargs[:dir_criteria] = @dir_criteria 27 | fsargs[:file_criteria] = @file_criteria 28 | fsargs[:split_as_path] = @split_as_path 29 | 30 | FileSet.new files, fsargs 31 | end 32 | 33 | def set_record_separator sep 34 | $/ = if sep && sep.to_i > 0 35 | begin 36 | sep.oct.chr 37 | rescue RangeError 38 | # out of range (e.g., 777) means nil: 39 | nil 40 | end 41 | else 42 | "\n\n" 43 | end 44 | end 45 | 46 | def config_fields 47 | fields = { 48 | "binary-files" => binary_files, 49 | "split-as-path" => @split_as_path, 50 | } 51 | fields.merge! @dir_criteria.config_fields 52 | fields.merge! @file_criteria.config_fields 53 | end 54 | 55 | def dump_fields 56 | fields = { 57 | "binary_files" => binary_files, 58 | "directory" => @directory, 59 | "exclude_matching" => @exclude_matching, 60 | "split-as-path" => @split_as_path, 61 | } 62 | fields.merge! @dir_criteria.dump_fields 63 | fields.merge! @file_criteria.dump_fields 64 | fields 65 | end 66 | 67 | def update_fields fields 68 | @dir_criteria.update_fields fields 69 | @file_criteria.update_fields fields 70 | 71 | fields.each do |name, value| 72 | case name 73 | when 'split-as-path' 74 | @split_as_path = to_boolean value 75 | end 76 | end 77 | end 78 | 79 | def set_directory val 80 | @max_depth = val == 'list' ? 0 : nil 81 | @dir_criteria.skip_all = val == 'skip' 82 | # otherwise, it's recurse 83 | end 84 | 85 | def add_as_options optdata 86 | optdata << { 87 | :res => [ Regexp.new('^ -0 (\d{1,3})? $ ', Regexp::EXTENDED) ], 88 | :set => Proc.new { |md| rs = md ? md[1] : 0; set_record_separator rs } 89 | } 90 | 91 | @range.add_as_option optdata 92 | 93 | optdata << { 94 | :tags => %w{ -r --recurse }, 95 | :set => Proc.new { set_directory("recurse") } 96 | } 97 | 98 | optdata << { 99 | :tags => %w{ --directories -d }, 100 | :arg => [ :string ], 101 | :set => Proc.new { |val| set_directory val }, 102 | } 103 | 104 | re = Regexp.new '^[\'\"]?(' + VALID_BINARY_FILE_TYPES.join('|') + ')[\'\"]?$' 105 | optdata << { 106 | :tags => %w{ --binary-files }, 107 | :arg => [ :required, :regexp, re ], 108 | :set => Proc.new { |md| @binary_files = md }, 109 | :rc => %w{ binary-files }, 110 | } 111 | 112 | @file_criteria.add_as_options optdata 113 | @dir_criteria.add_as_options optdata 114 | 115 | add_opt_true optdata, :exclude_matching, %w{ -M --exclude-matching } 116 | 117 | add_opt_false optdata, :split_as_path, %w{ --no-split-as-path } 118 | add_opt_true optdata, :split_as_path, %w{ --split-as-path } 119 | end 120 | end 121 | end 122 | -------------------------------------------------------------------------------- /lib/glark/input/range.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby -w 2 | # -*- ruby -*- 3 | 4 | require 'logue/loggable' 5 | 6 | module Glark 7 | class RangeError < RuntimeError 8 | end 9 | 10 | class Range 11 | include Logue::Loggable, Comparable 12 | 13 | PCT_RE = Regexp.new '([\.\d]+)%' 14 | 15 | attr_accessor :from 16 | attr_accessor :to 17 | 18 | def initialize from = nil, to = nil 19 | @from = from 20 | @to = to 21 | end 22 | 23 | def bound? 24 | @from.nil? && @to.nil? 25 | end 26 | 27 | def to_line var, linecount 28 | return nil unless var 29 | 30 | if pct = as_pct(var) 31 | count = linecount 32 | count * pct.to_f / 100 33 | else 34 | var.to_f 35 | end 36 | end 37 | 38 | def as_pct val 39 | (md = PCT_RE.match(val)) && md[1] 40 | end 41 | 42 | def validate! 43 | return true if @from.nil? || @to.nil? 44 | 45 | frompct, topct = [ @from, @to ].collect { |val| as_pct val } 46 | 47 | # both or neither are percentages: 48 | return true if frompct.nil? != topct.nil? 49 | 50 | if frompct 51 | check_range! frompct, topct 52 | else 53 | check_range! @from, @to 54 | end 55 | true 56 | end 57 | 58 | def check_range! from, to 59 | if from.to_f > to.to_f 60 | raise RangeError.new "error: range start (#{@from}) follows range end (#{@to})" 61 | end 62 | end 63 | 64 | # there is no nil <=> nil in Ruby 65 | def compare x, y 66 | x.nil? && y.nil? ? nil : (x <=> y).nonzero? 67 | end 68 | 69 | def <=> other 70 | compare(from, other.from) || compare(to, other.to) || 0 71 | end 72 | 73 | def clear 74 | @from = nil 75 | @to = nil 76 | end 77 | 78 | def add_as_option optdata 79 | optdata << { 80 | :tags => %w{ --after }, 81 | :arg => [ :required, :regexp, %r{ (\d+%?) $ }x ], 82 | :set => Proc.new { |md| @from = md } 83 | } 84 | 85 | optdata << { 86 | :tags => %w{ --before }, 87 | :arg => [ :required, :regexp, %r{ (\d+%?) $ }x ], 88 | :set => Proc.new { |md| @to = md } 89 | } 90 | 91 | optdata << { 92 | :tags => %w{ -R --range }, 93 | :arg => [ :required, :regexp, Regexp.new('(\d+%?,\d+%?)') ], 94 | :set => Proc.new { |md, opt, args| @from, @to = md.split(',') } 95 | } 96 | end 97 | end 98 | end 99 | -------------------------------------------------------------------------------- /lib/glark/input/spec.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby -w 2 | #!ruby -w 3 | # vim: set filetype=ruby : set sw=2 4 | 5 | require 'glark/input/range' 6 | require 'glark/input/filter/dir_criteria_opts' 7 | require 'glark/input/filter/file_criteria_opts' 8 | 9 | module Glark 10 | class InputSpec 11 | VALID_BINARY_FILE_TYPES = [ 'text', 'without-match', 'skip', 'binary', 'list', 'decompress', 'read' ] 12 | 13 | attr_accessor :binary_files # how to handle binary files 14 | attr_accessor :directory # read, skip, or recurse, a la grep 15 | attr_accessor :exclude_matching # exclude files whose names match the expression 16 | attr_accessor :range # range to start and stop searching; nil => the entire file 17 | attr_accessor :split_as_path # use file arguments as path elements 18 | 19 | attr_accessor :dir_criteria 20 | attr_accessor :file_criteria 21 | attr_accessor :max_depth 22 | 23 | def initialize 24 | @binary_files = 'skip' 25 | @directory = 'list' 26 | @exclude_matching = false 27 | 28 | @range = Range.new 29 | @split_as_path = true 30 | 31 | @file_criteria = FileCriteriaOpts.new 32 | @dir_criteria = DirCriteriaOpts.new nil 33 | 34 | @max_depth = 0 # list directories 35 | 36 | $/ = "\n" 37 | end 38 | end 39 | end 40 | -------------------------------------------------------------------------------- /lib/glark/io/file/archive_file.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby -w 2 | # -*- ruby -*- 3 | 4 | require 'glark/io/file/file' 5 | 6 | module Glark 7 | class ArchiveFile 8 | def initialize fname, range 9 | @fname = fname 10 | @range = range 11 | end 12 | 13 | def search_list expr, output_cls, output_opts 14 | contents = StringIO.new list.collect { |x| x + "\n" }.join('') 15 | contents.rewind 16 | 17 | file = Glark::File.new @fname, contents, @range 18 | output_type = output_cls.new file, output_opts 19 | file.search expr, output_type 20 | end 21 | 22 | def list 23 | contents = Array.new 24 | each do |entry| 25 | contents << entry_name(entry) 26 | end 27 | contents 28 | end 29 | 30 | def each &blk 31 | reader = get_reader 32 | reader.each do |entry| 33 | blk.call entry 34 | end 35 | reader.close 36 | end 37 | 38 | def search_archive_file expr, entry, output_type_cls, output_opts 39 | name = entry_name entry 40 | data = read entry 41 | contents = StringIO.new data 42 | 43 | file = Glark::File.new name + " (in #{@fname})", contents, @range 44 | output = output_type_cls.new file, output_opts 45 | file.search expr, output 46 | end 47 | 48 | def read entry 49 | entry.read 50 | end 51 | 52 | def search expr, output_type_cls, output_opts 53 | matched = nil 54 | each do |entry| 55 | # a glitch with zlib doesn't seem to recognize some tarball entries 56 | # (with entry.header.typeflag == "") as being a file, so we test for 57 | # directory: 58 | next if entry.directory? 59 | matched = search_archive_file(expr, entry, output_type_cls, output_opts) || matched 60 | end 61 | matched 62 | end 63 | end 64 | end 65 | -------------------------------------------------------------------------------- /lib/glark/io/file/binary_file.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby -w 2 | # -*- ruby -*- 3 | 4 | require 'glark/io/file/file' 5 | 6 | module Glark 7 | class BinaryFile < Glark::File 8 | def initialize fname 9 | file = ::File.new fname 10 | file.binmode # for MSDOS/WinWhatever 11 | super fname, file, nil 12 | end 13 | 14 | def search_as_binary expr, output_opts 15 | output_type = BinaryFileSummary.new self, output_opts 16 | search expr, output_type 17 | end 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /lib/glark/io/file/file.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby -w 2 | #!ruby -w 3 | # vim: set filetype=ruby : set sw=2 4 | 5 | require 'glark/util/io/lines' 6 | 7 | module Glark 8 | # A thing that can be grepped (er, glarked). 9 | class File 10 | attr_reader :fname 11 | 12 | def initialize fname, io, range 13 | @fname = fname 14 | @range = range 15 | 16 | linescls = $/ == "\n" ? Glark::IO::LinesCR : Glark::IO::LinesNonCR 17 | @lines = linescls.new fname, io 18 | end 19 | 20 | def linecount 21 | @lines.count 22 | end 23 | 24 | def each_line &blk 25 | @lines.each_line(&blk) 26 | end 27 | 28 | # Returns the lines for this file, separated by end of line sequences. 29 | def get_lines 30 | @lines.get_lines 31 | end 32 | 33 | # Returns the given line for this file. For this method, a line ends with a 34 | # CR, as opposed to the "lines" method, which ends with $/. 35 | def get_line lnum 36 | @lines.get_line lnum 37 | end 38 | 39 | # Returns the region/range that is represented by the region number. 40 | def get_region rnum 41 | @lines.get_region rnum 42 | end 43 | 44 | def get_range_start 45 | @range && @range.from && @range.to_line(@range.from, linecount) 46 | end 47 | 48 | def get_range_end 49 | @range && @range.to && @range.to_line(@range.to, linecount) 50 | end 51 | 52 | def search expr, output 53 | expr.process self, output 54 | output.matched? 55 | end 56 | end 57 | end 58 | -------------------------------------------------------------------------------- /lib/glark/io/file/gz_file.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby -w 2 | # -*- ruby -*- 3 | 4 | require 'glark/io/file/file' 5 | require 'zlib' 6 | 7 | module Glark 8 | class GzFile < Glark::File 9 | def initialize fname, range, &blk 10 | if blk 11 | Zlib::GzipReader.open(fname) do |gz| 12 | super fname, gz, range 13 | blk.call [ self, gz ] 14 | end 15 | else 16 | gz = Zlib::GzipReader.new fname 17 | super fname, gz, range 18 | end 19 | end 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /lib/glark/io/file/tar_file.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby -w 2 | # -*- ruby -*- 3 | 4 | require 'glark/io/file/file' 5 | require 'glark/io/file/archive_file' 6 | 7 | module Glark 8 | class TarFile < ArchiveFile 9 | def initialize fname, range, io = nil, &blk 10 | super fname, range 11 | 12 | # Given that this is a gem, I'm not sure if it is installed with other 13 | # package managers. So the require is down here, used only if needed. 14 | 15 | # module Gem::Package is declared in 'rubygems/package', not in 16 | # .../tar_reader. 17 | require 'rubygems/package' 18 | require 'rubygems/package/tar_reader' 19 | @io = io 20 | end 21 | 22 | def get_reader 23 | io = @io || ::File.new(@fname) 24 | Gem::Package::TarReader.new io 25 | end 26 | 27 | def entry_name entry 28 | entry.full_name 29 | end 30 | 31 | def read entry 32 | entry.read 33 | end 34 | end 35 | end 36 | -------------------------------------------------------------------------------- /lib/glark/io/file/tar_gz_file.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby -w 2 | # -*- ruby -*- 3 | 4 | require 'rubygems' 5 | require 'logue/loggable' 6 | require 'glark/io/file/gz_file' 7 | require 'glark/io/file/tar_file' 8 | 9 | module Glark 10 | class TarGzFile 11 | include Logue::Loggable 12 | 13 | def initialize fname, range 14 | @fname = fname 15 | @range = range 16 | end 17 | 18 | def list 19 | contents = Array.new 20 | each_file do |entry| 21 | contents << entry.full_name 22 | end 23 | contents 24 | end 25 | 26 | def run_search &blk 27 | # a glitch with zlib results in a warning ("attempt to close unfinished 28 | # zstream; reset forced.") for some tarballs, so we turn off warnings for 29 | # a moment: 30 | $-w = false 31 | 32 | Zlib::GzipReader.open(@fname) do |gzio| 33 | tarfile = Glark::TarFile.new @fname, @range, gzio 34 | blk.call tarfile 35 | end 36 | 37 | $-w = true 38 | end 39 | 40 | def search_list expr, output_cls, output_opts 41 | run_search do |tarfile| 42 | tarfile.search_list expr, output_cls, output_opts 43 | end 44 | end 45 | 46 | def search expr, output_type_cls, output_opts 47 | matched = nil 48 | run_search do |tarfile| 49 | matched = tarfile.search(expr, output_type_cls, output_opts) || matched 50 | end 51 | matched 52 | end 53 | end 54 | end 55 | -------------------------------------------------------------------------------- /lib/glark/io/file/zip_file.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby -w 2 | # -*- ruby -*- 3 | 4 | require 'rubygems' 5 | require 'logue/loggable' 6 | require 'glark/io/file/archive_file' 7 | 8 | module Glark 9 | class ZipFile < ArchiveFile 10 | include Logue::Loggable 11 | 12 | def initialize fname, range, &blk 13 | super fname, range 14 | 15 | check_rubyzip 16 | end 17 | 18 | def get_reader 19 | @zipfile = Zip::File.new @fname 20 | end 21 | 22 | def read entry 23 | @zipfile.read entry 24 | end 25 | 26 | def entry_name entry 27 | entry.name 28 | end 29 | 30 | def check_rubyzip 31 | check_rubyzip_exists 32 | check_rubyzip_version 33 | end 34 | 35 | def check_rubyzip_exists 36 | # Given that this is a gem, I'm not sure if it is installed with other 37 | # package managers. So the require is down here, used only if needed. 38 | begin 39 | require 'zip' 40 | rescue LoadError => e 41 | msg = "error loading zip gem: #{e}\n" 42 | msg << "to install this dependency, run 'gem install rubyzip'" 43 | info Rainbow::Presenter.new("msg: #{msg}").color(:red) 44 | raise msg 45 | end 46 | check_rubyzip_version 47 | end 48 | 49 | def check_rubyzip_version 50 | require 'zip/version' 51 | reqver = '1.1.4' 52 | reqnum = version_to_number reqver 53 | currnum = version_to_number Zip::VERSION 54 | if currnum < reqnum 55 | msg = "error: support for zip files requires rubyzip version >= #{reqver}; current version is #{Zip::VERSION}" 56 | info Rainbow::Presenter.new("msg: #{msg}").color(:red) 57 | raise msg 58 | end 59 | end 60 | 61 | def version_to_number ver 62 | vernums = ver.split '.' 63 | vernums.inject(0) { |s, n| 1000 * s + n.to_i } 64 | end 65 | end 66 | end 67 | -------------------------------------------------------------------------------- /lib/glark/match/and.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby -w 2 | #!ruby -w 3 | # vim: set filetype=ruby : set sw=2 4 | 5 | require 'glark/match/compound' 6 | 7 | # Evaluates both expressions, and is satisfied when both return true. 8 | class AndExpression < CompoundExpression 9 | 10 | def initialize dist, op1, op2 11 | @dist = dist 12 | super op1, op2 13 | end 14 | 15 | def match_within_distance op, lnum 16 | op.matches.size > 0 and (op.matches[-1] - lnum <= @dist) 17 | end 18 | 19 | def inspect 20 | str = "("+ @ops[0].to_s 21 | if @dist == 0 22 | str += " same line as " 23 | elsif @dist.kind_of?(Float) && @dist.infinite? 24 | str += " same file as " 25 | else 26 | str += " within " + @dist.to_s + " lines of " 27 | end 28 | str += @ops[1].to_s + ")" 29 | str 30 | end 31 | 32 | def match? line, lnum, file, formatter 33 | matches = (0 ... @ops.length).select do |oi| 34 | @ops[oi].evaluate line, lnum, file, formatter 35 | end 36 | 37 | matches.each do |mi| 38 | oidx = (1 + mi) % @ops.length 39 | other = @ops[oidx] 40 | if match_within_distance other, lnum 41 | # search for the maximum match within the distance limit 42 | other.matches.each do |m| 43 | if lnum - m <= @dist 44 | @last_start = m 45 | return true 46 | end 47 | end 48 | return false 49 | end 50 | end 51 | 52 | false 53 | end 54 | 55 | def end_position 56 | @ops.collect { |op| op.end_position }.max 57 | end 58 | 59 | def evaluate line, lnum, file, formatter 60 | if match? line, lnum, file, formatter 61 | @match_line_number = lnum 62 | true 63 | else 64 | false 65 | end 66 | end 67 | 68 | def explain level = 0 69 | str = "" 70 | if @dist == 0 71 | str += " " * level + "on the same line:\n" 72 | elsif @dist.kind_of?(Float) && @dist.infinite? 73 | str += " " * level + "in the same file:\n" 74 | else 75 | lnstr = @dist == 1 ? "line" : "lines" 76 | str += " " * level + "within #{@dist} #{lnstr} of each other:\n" 77 | end 78 | str += @ops[0].explain(level + 4) 79 | str += " " * level + "and\n" 80 | str += @ops[1].explain(level + 4) 81 | str 82 | end 83 | end 84 | -------------------------------------------------------------------------------- /lib/glark/match/and_distance.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby -w 2 | #!ruby -w 3 | # vim: set filetype=ruby : set sw=2 4 | 5 | # Distance for and expression 6 | 7 | require 'rubygems' 8 | require 'glark/match/re' 9 | require 'glark/match/ior' 10 | require 'glark/match/xor' 11 | require 'glark/match/and' 12 | 13 | class AndDistance 14 | # signifies no limit to the distance between matches, i.e., anywhere within 15 | # the entire file is valid. 16 | INFINITE_DISTANCE = -1 17 | 18 | AND_EQ_NUM_RE = Regexp.new '^--and=(\-?\d+)?$' 19 | 20 | attr_reader :distance 21 | 22 | def initialize arg, args 23 | @distance = if arg == "-a" 24 | args.shift 25 | elsif arg == "--and" 26 | if args.size > 0 && numeric?(args[0]) 27 | args.shift 28 | else 29 | "0" 30 | end 31 | elsif md = AND_EQ_NUM_RE.match(arg) 32 | md[1] 33 | else 34 | raise "invalid 'and' option: '#{arg}'" 35 | end 36 | 37 | # check to ensure that this is numeric 38 | if !numeric? @distance 39 | raise "invalid distance for 'and' expression: '#{@distance}'\n" + 40 | " expecting an integer, or #{INFINITE_DISTANCE} for 'infinite'" 41 | end 42 | 43 | if @distance.to_i == INFINITE_DISTANCE 44 | @distance = 1.0 / 0.0 # infinity 45 | else 46 | @distance = @distance.to_i 47 | end 48 | 49 | @distance 50 | end 51 | 52 | def numeric? x 53 | return nil unless x 54 | return true if x.kind_of?(Fixnum) || x.to_i == INFINITE_DISTANCE 55 | begin 56 | Integer x 57 | rescue ArgumentError 58 | nil 59 | end 60 | end 61 | end 62 | -------------------------------------------------------------------------------- /lib/glark/match/compound.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby -w 2 | #!ruby -w 3 | # vim: set filetype=ruby : set sw=2 4 | 5 | require 'glark/match/expression' 6 | 7 | # ------------------------------------------------------- 8 | # Compound expression function object 9 | # ------------------------------------------------------- 10 | 11 | # Associates a collection of expressions. 12 | class CompoundExpression < Expression 13 | attr_reader :ops 14 | 15 | def initialize(*ops) 16 | @ops = ops 17 | super() 18 | end 19 | 20 | def reset_file file 21 | @ops.each do |op| 22 | op.reset_file file 23 | end 24 | super 25 | end 26 | 27 | def start_position 28 | @last_start 29 | end 30 | 31 | def == other 32 | self.class == other.class && @ops == other.ops 33 | end 34 | end 35 | -------------------------------------------------------------------------------- /lib/glark/match/expression.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby -w 2 | #!ruby -w 3 | # vim: set filetype=ruby : set sw=2 4 | 5 | # Extended regular-expression-based expressions. 6 | 7 | # An expression, which can be applied (processed) against a Glark::File. 8 | class Expression 9 | attr_accessor :matches 10 | 11 | def initialize 12 | @match_line_number = nil 13 | @matches = Array.new 14 | end 15 | 16 | def add_match lnum 17 | @matches.push lnum 18 | end 19 | 20 | def start_position 21 | @match_line_number 22 | end 23 | 24 | def end_position 25 | start_position 26 | end 27 | 28 | def reset_file file 29 | @match_line_number = nil 30 | @matches = Array.new 31 | end 32 | 33 | def process file, formatter 34 | reset_file file.fname 35 | 36 | rgstart = file.get_range_start 37 | rgend = file.get_range_end 38 | 39 | lastmatch = 0 40 | lnum = 0 41 | file.each_line do |line| 42 | if ((!rgstart || lnum >= rgstart) && 43 | (!rgend || lnum < rgend) && 44 | evaluate(line, lnum, file, formatter)) 45 | 46 | break if formatter.process_match start_position, end_position, lastmatch, lnum 47 | lastmatch = lnum + 1 48 | end 49 | lnum += 1 50 | end 51 | 52 | formatter.process_end lnum 53 | end 54 | 55 | def to_s 56 | inspect 57 | end 58 | end 59 | -------------------------------------------------------------------------------- /lib/glark/match/factory.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby -w 2 | #!ruby -w 3 | # vim: set filetype=ruby : set sw=2 4 | 5 | # Expression factory. 6 | 7 | require 'rubygems' 8 | require 'logue/loggable' 9 | require 'glark/match/and' 10 | require 'glark/match/and_distance' 11 | require 'glark/match/ior' 12 | require 'glark/match/re_factory' 13 | require 'glark/match/xor' 14 | 15 | class ExpressionFactory 16 | include Logue::Loggable 17 | 18 | attr_reader :expr 19 | 20 | def initialize matchspec 21 | @regexp_factory = RegexpExpressionFactory.new matchspec 22 | end 23 | 24 | # reads a file containing one regular expression per line. 25 | def read_file fname 26 | expr = nil 27 | File.open(fname) do |file| 28 | file.each_line do |line| 29 | line.strip! 30 | next if line.empty? 31 | 32 | # flatten the or expression instead of nesting it, to avoid 33 | # stack overruns for very large files. 34 | re = make_regular_expression line.chomp 35 | if expr 36 | expr.ops << re 37 | else 38 | expr = InclusiveOrExpression.new re 39 | end 40 | end 41 | end 42 | expr 43 | end 44 | 45 | def make_regular_expression pattern, negated = false 46 | @regexp_factory.create_expression pattern, negated 47 | end 48 | 49 | # creates two expressions and returns them. 50 | def make_expressions args 51 | a1 = make_expression args 52 | a2 = make_expression args 53 | 54 | [ a1, a2 ] 55 | end 56 | 57 | # removes optional end tag 58 | def shift_end_tag name, args 59 | # explicit end tag is optional: 60 | args.shift if args[0] == ("--end-of-" + name) 61 | end 62 | 63 | def make_not_expression args 64 | expr = make_regular_expression args, true 65 | unless expr 66 | raise "'not' expression takes one argument" 67 | end 68 | 69 | # explicit end tag is optional: 70 | shift_end_tag "not", args 71 | expr 72 | end 73 | 74 | def make_two_expressions args, type 75 | a1, a2 = make_expressions args 76 | unless a1 && a2 77 | raise "'" + type + "' expression takes two arguments" 78 | end 79 | 80 | shift_end_tag type, args 81 | [ a1, a2 ] 82 | end 83 | 84 | def make_or_expression args 85 | a1, a2 = make_two_expressions args, "or" 86 | InclusiveOrExpression.new a1, a2 87 | end 88 | 89 | def make_xor_expression args 90 | a1, a2 = make_two_expressions args, "xor" 91 | ExclusiveOrExpression.new a1, a2 92 | end 93 | 94 | def make_and_distance arg, args 95 | adist = AndDistance.new arg, args 96 | adist.distance 97 | end 98 | 99 | def make_and_expression arg, args 100 | dist = make_and_distance arg, args 101 | 102 | a1, a2 = make_two_expressions args, "and" 103 | AndExpression.new dist, a1, a2 104 | end 105 | 106 | def make_infix_expression arg, args = [] 107 | expr = nil 108 | 109 | while arg 110 | case arg 111 | when '(' 112 | arg = args.shift 113 | expr = make_infix_expression arg, args 114 | when '--or', '-o' 115 | arg = args.shift 116 | rhs = make_infix_expression arg, args 117 | expr = InclusiveOrExpression.new expr, rhs 118 | when '--xor' 119 | arg = args.shift 120 | rhs = make_infix_expression arg, args 121 | expr = ExclusiveOrExpression.new expr, rhs 122 | when Regexp.new('^--and'), '-a' 123 | dist = make_and_distance arg, args 124 | arg = args.shift 125 | rhs = make_infix_expression arg, args 126 | expr = AndExpression.new dist, expr, rhs 127 | when ')' 128 | break 129 | else 130 | expr = make_regular_expression arg 131 | break 132 | end 133 | arg = args.shift 134 | end 135 | 136 | if !expr 137 | raise "No expression provided." 138 | end 139 | 140 | expr 141 | end 142 | 143 | def make_expression args, warn_option = false 144 | arg = args[0] 145 | 146 | if arg 147 | case arg 148 | when "--or", "-o" 149 | args.shift 150 | make_or_expression args 151 | when "--xor" 152 | args.shift 153 | make_xor_expression args 154 | when %r{^\-\-and}, %r{^\-a} 155 | args.shift 156 | make_and_expression arg, args 157 | when '(' 158 | args.shift 159 | make_infix_expression arg, args 160 | else 161 | if warn_option && arg.index(%r{^\-{1,2}\w}) 162 | raise "option not understood: #{arg}" 163 | end 164 | 165 | args.shift 166 | make_regular_expression arg 167 | end 168 | else 169 | nil 170 | end 171 | end 172 | end 173 | -------------------------------------------------------------------------------- /lib/glark/match/ior.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby -w 2 | #!ruby -w 3 | # vim: set filetype=ruby : set sw=2 4 | 5 | require 'glark/match/or' 6 | 7 | # Evaluates the expressions, and is satisfied when any one returns true. 8 | class InclusiveOrExpression < OrExpression 9 | def is_match? matched_ops 10 | return matched_ops.size > 0 11 | end 12 | 13 | def operator 14 | "or" 15 | end 16 | 17 | def criteria 18 | ops.size == 2 ? "either" : "any of" 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /lib/glark/match/options.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby -w 2 | #!ruby -w 3 | # vim: set filetype=ruby : set sw=2 4 | 5 | # Options for matching. 6 | 7 | require 'rubygems' 8 | require 'glark/match/spec' 9 | require 'glark/util/options' 10 | 11 | module Glark 12 | class MatchOptions < MatchSpec 13 | include OptionUtil 14 | 15 | def initialize colors, optdata 16 | super colors 17 | add_as_options optdata 18 | end 19 | 20 | def config_fields 21 | { 22 | "ignore-case" => @ignorecase, 23 | "text-color" => text_colors.join(' '), 24 | } 25 | end 26 | 27 | def dump_fields 28 | { 29 | "expr" => @expr, 30 | "extract_matches" => @extract_matches, 31 | "ignorecase" => @ignorecase, 32 | "text_colors" => text_colors.compact.collect { |hl| colorize(hl, "text") }.join(", "), 33 | "whole_lines" => @whole_lines, 34 | "whole_words" => @whole_words, 35 | } 36 | end 37 | 38 | def update_fields fields 39 | fields.each do |name, values| 40 | case name 41 | when "ignore-case" 42 | @ignorecase = to_boolean values.last 43 | end 44 | end 45 | end 46 | 47 | def add_as_options optdata 48 | add_opt_true optdata, :whole_words, %w{ -w --word } 49 | add_opt_true optdata, :ignorecase, %w{ -i --ignore-case } 50 | add_opt_true optdata, :whole_lines, %w{ -x --line-regexp } 51 | add_opt_true optdata, :extended, %w{ --extended } 52 | 53 | optdata << { 54 | :tags => %w{ -f --file }, 55 | :arg => [ :string ], 56 | :set => Proc.new { |fname| @expr = create_expression_factory.read_file fname } 57 | } 58 | 59 | add_opt_blk(optdata, %w{ -o -a }) do |md, opt, args| 60 | args.unshift opt 61 | @expr = create_expression_factory.make_expression args 62 | end 63 | 64 | optdata << { 65 | :tags => %w{ --text-color }, 66 | :arg => [ :string ], 67 | :set => Proc.new { |val| @colors.text_colors = [ @colors.create_color("text-color", val) ] } 68 | } 69 | 70 | add_opt_true optdata, :extract_matches, %w{ -y --extract-matches } 71 | end 72 | end 73 | end 74 | -------------------------------------------------------------------------------- /lib/glark/match/or.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby -w 2 | #!ruby -w 3 | # vim: set filetype=ruby : set sw=2 4 | 5 | require 'glark/match/compound' 6 | 7 | # A collection of expressions, evaluated as 'or'. 8 | class OrExpression < CompoundExpression 9 | 10 | def evaluate line, lnum, file, formatter 11 | matched_ops = @ops.select do |op| 12 | op.evaluate line, lnum, file, formatter 13 | end 14 | 15 | if is_match? matched_ops 16 | lastmatch = matched_ops[-1] 17 | @last_start = lastmatch.start_position 18 | @last_end = lastmatch.end_position 19 | @match_line_number = lnum 20 | 21 | add_match lnum 22 | true 23 | else 24 | false 25 | end 26 | end 27 | 28 | def inspect 29 | "(" + @ops.collect { |op| op.to_s }.join(" " + operator + " ") + ")" 30 | end 31 | 32 | def end_position 33 | @last_end 34 | end 35 | 36 | def explain level = 0 37 | str = " " * level + criteria + ":\n" 38 | str += @ops.collect { |op| op.explain(level + 4) }.join(" " * level + operator + "\n") 39 | str 40 | end 41 | end 42 | -------------------------------------------------------------------------------- /lib/glark/match/re.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby -w 2 | #!ruby -w 3 | # vim: set filetype=ruby : set sw=2 4 | # -*- encoding: UTF-8 -*- 5 | 6 | require 'glark/match/expression' 7 | require 'glark/util/highlight' 8 | 9 | # Applies a regular expression against a File. 10 | class RegexpExpression < Expression 11 | include Highlight 12 | 13 | attr_reader :re 14 | 15 | def initialize re, hlidx, text_colors = nil, extract_matches = false 16 | @re = re 17 | 18 | if @text_colors = text_colors 19 | @hlidx = if @text_colors.length > 0 20 | hlidx % @text_colors.length 21 | else 22 | 0 23 | end 24 | end 25 | @extract_matches = extract_matches 26 | 27 | super() 28 | end 29 | 30 | def == other 31 | @re == other.re 32 | end 33 | 34 | def inspect 35 | @re.inspect 36 | end 37 | 38 | def match? line 39 | begin 40 | @re.match line 41 | rescue 42 | false 43 | end 44 | end 45 | 46 | def evaluate line, lnum, file, formatter 47 | md = match? line 48 | return false unless md 49 | 50 | if @extract_matches 51 | if md.kind_of? MatchData 52 | line.replace md[-1] + "\n" 53 | else 54 | warn "--not is incompatible with -v" 55 | end 56 | end 57 | 58 | @match_line_number = lnum 59 | 60 | if @text_colors && @text_colors.size > 0 61 | highlight_match lnum, file, formatter 62 | end 63 | 64 | add_match lnum 65 | true 66 | end 67 | 68 | def explain level = 0 69 | " " * level + to_s + "\n" 70 | end 71 | 72 | def highlight_match lnum, file, formatter 73 | lnums = file.get_region lnum 74 | return unless lnums 75 | 76 | lnums.each do |ln| 77 | str = formatter.formatted[ln] || file.get_line(ln) 78 | formatter.formatted[ln] = str.gsub(@re) do |m| 79 | lastcapts = Regexp.last_match.captures 80 | # the index of the first non-nil capture: 81 | miidx = (0 ... lastcapts.length).find { |mi| lastcapts[mi] } || @hlidx 82 | adorn(@text_colors[miidx], m) 83 | end 84 | end 85 | end 86 | end 87 | -------------------------------------------------------------------------------- /lib/glark/match/re_factory.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby -w 2 | #!ruby -w 3 | # vim: set filetype=ruby : set sw=2 4 | 5 | # RegexpExpression factory. 6 | 7 | require 'rubygems' 8 | require 'logue/loggable' 9 | require 'riel/regexp' 10 | require 'glark/match/re' 11 | 12 | class RegexpExpressionFactory 13 | include Logue::Loggable 14 | 15 | attr_reader :count 16 | 17 | def initialize exprspec 18 | @count = 0 19 | @extended = exprspec[:extended] 20 | @extract_matches = exprspec[:extract_matches] 21 | @ignorecase = exprspec[:ignorecase] 22 | @text_colors = exprspec[:text_colors] 23 | @wholelines = exprspec[:whole_lines] 24 | @wholewords = exprspec[:whole_words] 25 | end 26 | 27 | def create_expression pattern, negated = false 28 | # this check is because they may have omitted the pattern, e.g.: 29 | # % glark *.cpp 30 | if File.exist? pattern 31 | warn "pattern '#{pattern}' exists as a file.\n Pattern may have been omitted." 32 | end 33 | 34 | regex = Regexp.create(pattern.dup, 35 | :negated => negated, 36 | :ignorecase => @ignorecase, 37 | :wholewords => @wholewords, 38 | :wholelines => @wholelines, 39 | :extended => @extended) 40 | 41 | re = RegexpExpression.new regex, @count, @text_colors, @extract_matches 42 | @count += 1 43 | re 44 | end 45 | end 46 | -------------------------------------------------------------------------------- /lib/glark/match/spec.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby -w 2 | #!ruby -w 3 | # vim: set filetype=ruby : set sw=2 4 | 5 | # Options for matching. 6 | 7 | require 'rubygems' 8 | require 'glark/match/factory' 9 | require 'glark/util/colors/spec' 10 | 11 | module Glark 12 | class MatchSpec 13 | attr_accessor :expr # the expression to be evaluated 14 | attr_accessor :extended # whether to use extended regular expressions 15 | attr_accessor :extract_matches 16 | attr_accessor :ignorecase # match case 17 | attr_accessor :whole_lines # true means patterns must match the entire line 18 | attr_accessor :whole_words # true means all patterns are '\b'ed front and back 19 | 20 | def initialize colors 21 | @colors = colors 22 | @expr = nil 23 | @extended = false 24 | @extract_matches = false 25 | @ignorecase = false 26 | @whole_lines = false 27 | @whole_words = false 28 | end 29 | 30 | def create_expression_factory 31 | exprargs = Hash.new 32 | exprargs[:extended] = @extended 33 | exprargs[:extract_matches] = @extract_matches 34 | exprargs[:ignorecase] = @ignorecase 35 | exprargs[:text_colors] = text_colors 36 | exprargs[:whole_lines] = @whole_lines 37 | exprargs[:whole_words] = @whole_words 38 | 39 | ExpressionFactory.new exprargs 40 | end 41 | 42 | def read_expression args, warn_option = false 43 | @expr = create_expression_factory.make_expression args, warn_option 44 | end 45 | 46 | def text_colors 47 | @colors.text_colors 48 | end 49 | 50 | def set_text_colors text_colors 51 | @colors.text_colors = text_colors 52 | end 53 | 54 | def set_text_color index, text_color 55 | @colors.text_colors[index] = text_color 56 | end 57 | end 58 | end 59 | -------------------------------------------------------------------------------- /lib/glark/match/xor.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby -w 2 | #!ruby -w 3 | # vim: set filetype=ruby : set sw=2 4 | 5 | require 'glark/match/or' 6 | 7 | # Evaluates the expressions, and is satisfied if only one returns true. 8 | class ExclusiveOrExpression < OrExpression 9 | def is_match? matched_ops 10 | return matched_ops.size == 1 11 | end 12 | 13 | def operator 14 | "xor" 15 | end 16 | 17 | def criteria 18 | "only one of" 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /lib/glark/output/binary_file_summary.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby -w 2 | #!ruby -w 3 | # vim: set filetype=ruby : set sw=2 4 | 5 | require 'glark/output/common' 6 | 7 | class BinaryFileSummary < Common 8 | def display_matches? 9 | false 10 | end 11 | 12 | def process_end lnum 13 | if matched? 14 | @out.puts "Binary file " + @file.fname.to_s + " matches" 15 | end 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /lib/glark/output/common.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby -w 2 | #!ruby -w 3 | # vim: set filetype=ruby : set sw=2 4 | 5 | # Generic output. 6 | 7 | require 'glark/io/file/file' 8 | require 'glark/output/formatted' 9 | 10 | class Common < Formatted 11 | def initialize file, spec 12 | super() 13 | 14 | @file = file 15 | @invert_match = spec.invert_match 16 | @label = spec.label 17 | @match_limit = spec.match_limit 18 | @out = spec.out 19 | @show_file_name = spec.show_file_names 20 | @show_line_numbers = spec.show_line_numbers 21 | end 22 | 23 | def display_matches? 24 | true 25 | end 26 | 27 | def at_match_limit? 28 | @match_limit && @count >= @match_limit 29 | end 30 | 31 | def displayed_name 32 | @label || @file.fname 33 | end 34 | 35 | def add_match startline, endline 36 | super() 37 | end 38 | 39 | def process_match startline, endline, fromline, toline 40 | add_match startline, endline 41 | return at_match_limit? 42 | end 43 | end 44 | -------------------------------------------------------------------------------- /lib/glark/output/context.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby -w 2 | # -*- ruby -*- 3 | 4 | module Glark 5 | class Context 6 | include Logue::Loggable 7 | 8 | attr_accessor :after 9 | attr_accessor :before 10 | 11 | def initialize 12 | clear 13 | end 14 | 15 | def clear 16 | @after = 0 17 | @before = 0 18 | end 19 | 20 | def update_fields fields 21 | fields.each do |name, values| 22 | case name 23 | when 'context' 24 | @after = @before = values.last.to_i 25 | when 'after', 'after-context' 26 | @after = values.last.to_i 27 | when 'before', 'before-context' 28 | @before = values.last.to_i 29 | end 30 | end 31 | end 32 | 33 | def add_as_option optdata 34 | optdata << { 35 | :tags => %w{ -C --context }, 36 | :regexp => %r{ ^ - ([1-9]\d*) $ }x, 37 | :arg => [ :optional, :integer ], 38 | :process => Proc.new { |val, opt, args| @after = @before = val == true ? 2 : val }, 39 | :rcname => %w{ context }, 40 | } 41 | 42 | optdata << { 43 | :tags => %w{ --after-context -A }, 44 | :arg => [ :integer ], 45 | :set => Proc.new { |val| @after = val }, 46 | :rc => %w{ after-context }, 47 | } 48 | 49 | optdata << { 50 | :tags => %w{ --before-context -B }, 51 | :arg => [ :integer ], 52 | :set => Proc.new { |val| @before = val }, 53 | :rc => %w{ before-context }, 54 | } 55 | end 56 | end 57 | end 58 | -------------------------------------------------------------------------------- /lib/glark/output/count.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby -w 2 | #!ruby -w 3 | # vim: set filetype=ruby : set sw=2 4 | 5 | require 'glark/output/common' 6 | 7 | class Count < Common 8 | def display_matches? 9 | false 10 | end 11 | 12 | def write_count ct 13 | if @show_file_name 14 | print_file_name 15 | end 16 | print_count ct 17 | end 18 | 19 | def process_end lnum 20 | if @invert_match 21 | write_count @file.get_lines.size - @count 22 | elsif matched? 23 | write_count @count 24 | end 25 | end 26 | end 27 | -------------------------------------------------------------------------------- /lib/glark/output/file_header.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby -w 2 | #!ruby -w 3 | # vim: set filetype=ruby : set sw=2 4 | 5 | require 'glark/util/highlight' 6 | 7 | class FileHeader 8 | include Highlight 9 | 10 | def initialize name, highlighter 11 | @name = name 12 | @highlighter = highlighter 13 | end 14 | 15 | def print out 16 | name = @name.to_s 17 | fname = @highlighter ? adorn(@highlighter, name) : name 18 | out.puts fname 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /lib/glark/output/file_name_only.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby -w 2 | #!ruby -w 3 | # vim: set filetype=ruby : set sw=2 4 | 5 | require 'glark/output/common' 6 | 7 | class FileNameOnly < Common 8 | def initialize fname, spec 9 | super 10 | @write_null = spec.write_null 11 | end 12 | 13 | def at_match_limit? 14 | @count > 0 15 | end 16 | 17 | def display_matches? 18 | false 19 | end 20 | 21 | def print_file_name 22 | if @write_null 23 | @out.print @file.fname 24 | @out.print "\0" 25 | else 26 | @out.puts @file.fname 27 | end 28 | end 29 | 30 | def process_end lnum 31 | if matched? != @invert_match 32 | print_file_name 33 | end 34 | end 35 | end 36 | -------------------------------------------------------------------------------- /lib/glark/output/formatted.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby -w 2 | #!ruby -w 3 | # vim: set filetype=ruby : set sw=2 4 | 5 | # Output that has (possibly) been reformatted, i.e., highlighting of regular 6 | # expressions. 7 | 8 | require 'glark/io/file/file' 9 | require 'glark/output/results' 10 | 11 | class Formatted < Results 12 | attr_reader :formatted 13 | 14 | def initialize 15 | super 16 | @formatted = [] 17 | end 18 | 19 | def get_line_to_print lnum 20 | @formatted[lnum] || @file.get_line(lnum) 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /lib/glark/output/glark_count.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby -w 2 | #!ruby -w 3 | # vim: set filetype=ruby : set sw=2 4 | 5 | require 'glark/output/count' 6 | 7 | module Glark 8 | class Count < ::Count 9 | def initialize fname, spec 10 | super 11 | @fname_highlighter = spec.highlight && spec.file_highlight 12 | end 13 | 14 | def print_file_name 15 | file_header = FileHeader.new displayed_name, @fname_highlighter 16 | file_header.print @out 17 | end 18 | 19 | def print_count ct 20 | @out.puts " " + ct.to_s 21 | end 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /lib/glark/output/glark_format.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby -w 2 | #!ruby -w 3 | # vim: set filetype=ruby : set sw=2 4 | 5 | require 'glark/output/file_header' 6 | require 'glark/util/highlight' 7 | 8 | module Glark; end 9 | 10 | module Glark 11 | module Format 12 | include Highlight 13 | 14 | def initialize file, spec 15 | @file_header = nil # not nil after file header written 16 | @fname_highlighter = spec.highlight && spec.file_highlight 17 | @lnum_highlighter = spec.line_number_highlight 18 | 19 | super 20 | end 21 | 22 | def show_file_header 23 | if @show_file_name && @file_header.nil? && displayed_name 24 | @file_header = FileHeader.new displayed_name, @fname_highlighter 25 | @file_header.print @out 26 | end 27 | end 28 | 29 | def print_line_number lnum 30 | if @lnum_highlighter 31 | lnumstr = (lnum + 1).to_s 32 | pad = " " * ([4 - lnumstr.length, 0].max) 33 | @out.print pad + " " + adorn(@lnum_highlighter, lnumstr) + " " 34 | else 35 | super 36 | end 37 | end 38 | 39 | def println ln, ch 40 | if @show_line_numbers 41 | print_line_number ln 42 | end 43 | 44 | if ch && @print_context 45 | @out.printf "%s ", ch 46 | end 47 | 48 | line = get_line_to_print ln 49 | @out.puts line 50 | end 51 | 52 | # prints the line, and adjusts for the fact that in our world, lines are 53 | # 0-indexed, whereas they are displayed as if 1-indexed. 54 | def print_line lnum, ch = nil 55 | lnums = @file.get_region lnum 56 | return unless lnums 57 | lnums.each do |ln| 58 | println ln, ch 59 | end 60 | end 61 | end 62 | end 63 | -------------------------------------------------------------------------------- /lib/glark/output/glark_lines.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby -w 2 | #!ruby -w 3 | # vim: set filetype=ruby : set sw=2 4 | 5 | require 'glark/output/lines' 6 | require 'glark/output/glark_format' 7 | 8 | # ------------------------------------------------------- 9 | # Glark output format 10 | # ------------------------------------------------------- 11 | 12 | module Glark 13 | class Lines < ::Lines 14 | include Format 15 | 16 | def initialize file, spec 17 | super 18 | @print_context = @after != 0 || @before != 0 19 | end 20 | 21 | def write_matching from, to 22 | show_file_header 23 | super 24 | end 25 | 26 | def write_nonmatching from, to 27 | show_file_header 28 | super 29 | end 30 | 31 | def add_match startline, endline 32 | super 33 | set_status startline, endline 34 | end 35 | end 36 | end 37 | -------------------------------------------------------------------------------- /lib/glark/output/grep_count.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby -w 2 | #!ruby -w 3 | # vim: set filetype=ruby : set sw=2 4 | 5 | require 'glark/output/count' 6 | 7 | module Grep 8 | class Count < ::Count 9 | def print_file_name 10 | fname = displayed_name 11 | @out.print fname, ":" 12 | end 13 | 14 | def print_count ct 15 | @out.puts ct 16 | end 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /lib/glark/output/grep_lines.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby -w 2 | #!ruby -w 3 | # vim: set filetype=ruby : set sw=2 4 | 5 | require 'glark/output/lines' 6 | 7 | # ------------------------------------------------------- 8 | # Grep output format 9 | # ------------------------------------------------------- 10 | 11 | module Grep 12 | # This matches legacy grep, mostly. It is for running within emacs, thus, it 13 | # does not support context or highlighting. 14 | class Lines < ::Lines 15 | # prints the line, and adjusts for the fact that in our world, lines are 16 | # 0-indexed, whereas they are displayed as if 1-indexed. 17 | def print_line lnum, ch = nil 18 | ln = get_line_to_print lnum 19 | return unless ln 20 | 21 | print_file_name 22 | if @show_line_numbers 23 | @out.printf "%d: ", lnum + 1 24 | end 25 | 26 | @out.print ln 27 | end 28 | 29 | def print_file_name 30 | if @show_file_name && displayed_name 31 | @out.print displayed_name, ":" 32 | end 33 | end 34 | 35 | def add_match startline, endline 36 | super 37 | # even with multi-line matches (--and expressions), we'll display 38 | # only the first matching line, not the range between the matches. 39 | set_status startline, startline 40 | end 41 | end 42 | end 43 | -------------------------------------------------------------------------------- /lib/glark/output/line_status.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby -w 2 | # -*- ruby -*- 3 | 4 | module Glark 5 | class LineStatus 6 | WRITTEN = Object.new 7 | PRE_MATCH = '-' 8 | MATCH = ':' 9 | POST_MATCH = '+' 10 | 11 | def initialize 12 | @stati = Array.new 13 | end 14 | 15 | def is_written? lnum 16 | @stati[lnum] == WRITTEN 17 | end 18 | 19 | def set_as_written lnum 20 | @stati[lnum] = WRITTEN 21 | end 22 | 23 | def char lnum 24 | @stati[lnum] 25 | end 26 | 27 | def set_status from, to, status 28 | from.upto(to) do |lnum| 29 | update_status lnum, status 30 | end 31 | end 32 | 33 | def update_status lnum, status 34 | if @stati[lnum].nil? || (status == MATCH && @stati[lnum] != WRITTEN) 35 | @stati[lnum] = status 36 | end 37 | end 38 | 39 | def set_match pre_match_start, match_start, match_end, post_match_end 40 | start = [0, pre_match_start].max 41 | set_status start, match_start - 1, PRE_MATCH 42 | set_status match_start, match_end, MATCH 43 | set_status match_end + 1, post_match_end, POST_MATCH 44 | end 45 | end 46 | end 47 | -------------------------------------------------------------------------------- /lib/glark/output/lines.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby -w 2 | #!ruby -w 3 | # vim: set filetype=ruby : set sw=2 4 | 5 | # Output for displayed lines. 6 | 7 | require 'glark/io/file/file' 8 | require 'glark/output/line_status' 9 | require 'glark/output/common' 10 | 11 | class Lines < Common 12 | def initialize file, spec 13 | super 14 | 15 | @print_context = false 16 | 17 | context = spec.context 18 | @after = context && context.after 19 | @before = context && context.before 20 | 21 | @stati = Glark::LineStatus.new 22 | end 23 | 24 | def display_matches? 25 | true 26 | end 27 | 28 | def at_match_limit? 29 | @match_limit && @count >= @match_limit 30 | end 31 | 32 | def displayed_name 33 | @label || @file.fname 34 | end 35 | 36 | # Prints the line, which is assumed to be 0-indexed, and is thus adjusted by 37 | # one. 38 | def print_line_number lnum 39 | @out.printf "%5d ", lnum + 1 40 | end 41 | 42 | # prints the line, and adjusts for the fact that in our world, lines are 43 | # 0-indexed, whereas they are displayed as if 1-indexed. 44 | def print_line lnum, ch = nil 45 | raise "error: print_line must be implemented by an output subclass" 46 | end 47 | 48 | def write_matching from, to 49 | (from .. to).each do |ln| 50 | next unless @stati.char(ln) && !@stati.is_written?(ln) 51 | 52 | # this used to be conditional on show_break, but no more 53 | if from > 0 && !@stati.char(ln - 1) && @print_context 54 | @out.puts " ---" 55 | end 56 | 57 | print_line ln, @stati.char(ln) 58 | @stati.set_as_written ln 59 | end 60 | end 61 | 62 | def write_nonmatching from, to 63 | (from .. to).each do |ln| 64 | next if @stati.is_written?(ln) || @stati.char(ln) == ':' 65 | print_line ln 66 | @stati.set_as_written ln 67 | end 68 | end 69 | 70 | def write_matches from, to 71 | if @invert_match 72 | write_nonmatching from, to 73 | else 74 | write_matching from, to 75 | end 76 | end 77 | 78 | def process_end lnum 79 | if @invert_match 80 | write_nonmatching 0, lnum 81 | elsif matched? 82 | write_matching 0, lnum 83 | end 84 | end 85 | 86 | def process_match startline, endline, fromline, toline 87 | add_match startline, endline 88 | 89 | if display_matches? 90 | write_matches fromline, toline 91 | end 92 | return at_match_limit? 93 | end 94 | 95 | def set_status startline, endline 96 | fromline = [0, startline - @before].max 97 | toline = endline + @after 98 | @stati.set_match fromline, startline, endline, toline 99 | end 100 | end 101 | -------------------------------------------------------------------------------- /lib/glark/output/match_list.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby -w 2 | #!ruby -w 3 | # vim: set filetype=ruby : set sw=2 4 | 5 | module Glark 6 | # not yet supported; will be matches stored instead of written to stdout. 7 | class MatchList 8 | attr_reader :matches 9 | 10 | def initialize file, show_file_names 11 | super 12 | @matches = Array.new 13 | end 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /lib/glark/output/options.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby -w 2 | #!ruby -w 3 | # vim: set filetype=ruby : set sw=2 4 | 5 | require 'glark/output/spec' 6 | require 'glark/util/options' 7 | 8 | module Glark 9 | class OutputOptions < OutputSpec 10 | include OptionUtil 11 | 12 | def initialize colors, optdata 13 | super colors 14 | 15 | add_as_options optdata 16 | end 17 | 18 | def config_fields 19 | { 20 | "after-context" => @context.after, 21 | "before-context" => @context.before, 22 | "filter" => @filter, 23 | "output" => @style, 24 | } 25 | end 26 | 27 | def dump_fields 28 | { 29 | "after" => @context.after, 30 | "before" => @context.before, 31 | "count" => @count, 32 | "file_names_only" => @file_names_only, 33 | "filter" => @filter, 34 | "invert_match" => @invert_match, 35 | "label" => @label, 36 | "match_limit" => @match_limit, 37 | "output" => @style, 38 | "show_file_names" => @show_file_names, 39 | "show_line_numbers" => @show_line_numbers, 40 | "write_null" => @write_null 41 | } 42 | end 43 | 44 | def update_fields fields 45 | fields.each do |name, values| 46 | case name 47 | when "grep" 48 | self.style = "grep" if to_boolean values.last 49 | when "output" 50 | self.style = values.last 51 | end 52 | end 53 | @context.update_fields fields 54 | end 55 | 56 | def add_as_options optdata 57 | @context.add_as_option optdata 58 | 59 | add_opt_true optdata, :invert_match, %w{ -v --invert-match } 60 | 61 | add_opt_true optdata, :filter, %w{ --filter } 62 | add_opt_false optdata, :filter, %w{ --no-filter --nofilter } 63 | 64 | add_opt_true optdata, :show_line_numbers, %w{ -n --line-number } 65 | add_opt_false optdata, :show_line_numbers, %w{ -N --no-line-number } 66 | 67 | add_opt_blk(optdata, %w{ -l --files-with-matches }) { set_file_names_only false } 68 | add_opt_blk(optdata, %w{ -L --files-without-match }) { set_file_names_only true } 69 | 70 | add_opt_true optdata, :write_null, %w{ -Z --null } 71 | 72 | add_opt_str optdata, :label, %w{ --label } 73 | 74 | add_opt_int optdata, :match_limit, %w{ -m --match-limit } 75 | 76 | add_opt_blk(optdata, %w{ -U --no-highlight }) { @colors.text_color_style = nil } 77 | add_opt_blk(optdata, %w{ -g --grep }) { self.style = "grep" } 78 | 79 | optdata << { 80 | :tags => %w{ --line-number-color }, 81 | :arg => [ :string ], 82 | :set => Proc.new { |val| @colors.line_number_color = @colors.create_color "line-number-color", val }, 83 | } 84 | 85 | add_opt_true optdata, :count, %w{ -c --count } 86 | 87 | add_opt_true optdata, :show_file_names, %w{ -H --with-filename } 88 | add_opt_false optdata, :show_file_names, %w{ -h --no-filename } 89 | 90 | optdata << { 91 | :tags => %w{ -u --highlight }, 92 | :arg => [ :optional, :regexp, %r{ ^ (?:(multi|single)|none) $ }x ], 93 | :set => Proc.new { |md| val = md ? md : "multi"; @colors.text_color_style = val } 94 | } 95 | 96 | optdata << { 97 | :tags => %w{ --file-color }, 98 | :arg => [ :string ], 99 | :set => Proc.new { |val| @colors.file_name_color = @colors.create_color "file-color", val } 100 | } 101 | end 102 | end 103 | end 104 | -------------------------------------------------------------------------------- /lib/glark/output/results.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby -w 2 | #!ruby -w 3 | # vim: set filetype=ruby : set sw=2 4 | 5 | # Results of searching files. 6 | 7 | class Results 8 | attr_reader :count 9 | 10 | def initialize 11 | @count = 0 12 | end 13 | 14 | def matched? 15 | @count > 0 16 | end 17 | 18 | def add_match 19 | @count += 1 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /lib/glark/output/spec.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby -w 2 | #!ruby -w 3 | # vim: set filetype=ruby : set sw=2 4 | 5 | require 'glark/output/binary_file_summary' 6 | require 'glark/output/context' 7 | require 'glark/output/file_name_only' 8 | require 'glark/output/glark_count' 9 | require 'glark/output/glark_lines' 10 | require 'glark/output/grep_count' 11 | require 'glark/output/grep_lines' 12 | require 'glark/output/unfiltered_lines' 13 | 14 | module Glark 15 | class OutputSpec 16 | attr_accessor :context # lines before and after 17 | attr_accessor :count # only count the matches 18 | attr_accessor :file_names_only # display only the file names 19 | attr_accessor :filter # display only matches 20 | attr_accessor :invert_match # display non-matching lines 21 | attr_accessor :label 22 | attr_accessor :match_limit # the maximum number of matches to display per file 23 | attr_accessor :out 24 | attr_accessor :show_file_names # display file names 25 | attr_accessor :show_line_numbers # display numbers of matching lines 26 | attr_accessor :write_null # in @file_names_only mode, write '\0' instead of '\n' 27 | 28 | attr_reader :colors 29 | attr_reader :style # grep, glark 30 | 31 | def initialize colors 32 | @colors = colors 33 | @context = Glark::Context.new 34 | @count = false 35 | @file_names_only = false 36 | @filter = true 37 | @highlight = nil 38 | @invert_match = false 39 | @label = nil 40 | @match_limit = nil 41 | @out = $stdout 42 | @show_file_names = nil # nil == > 1; true == >= 1; false means never 43 | @show_line_numbers = true 44 | @style = nil 45 | @write_null = false 46 | 47 | @output_cls = nil 48 | 49 | self.style = "glark" 50 | end 51 | 52 | def line_number_highlight 53 | @colors.line_number_color 54 | end 55 | 56 | def file_highlight 57 | @colors.file_name_color 58 | end 59 | 60 | def highlight 61 | @colors.text_color_style 62 | end 63 | 64 | def style= style 65 | @style = style 66 | if @style == "glark" 67 | @colors.text_color_style = "multi" 68 | elsif @style == "grep" 69 | @colors.text_color_style = false 70 | @show_line_numbers = false 71 | @context.clear 72 | else 73 | raise "error: unrecognized style '" + style + "'" 74 | end 75 | @output_cls = nil 76 | end 77 | 78 | def create_output_type file 79 | output_type_cls.new file, self 80 | end 81 | 82 | def output_type_cls 83 | @output_cls ||= if @count 84 | if @style == "grep" 85 | Grep::Count 86 | else 87 | Glark::Count 88 | end 89 | elsif @file_names_only 90 | FileNameOnly 91 | elsif !@filter 92 | UnfilteredLines 93 | elsif @style == "grep" 94 | Grep::Lines 95 | else 96 | Glark::Lines 97 | end 98 | end 99 | 100 | def set_file_names_only invert_match 101 | @file_names_only = true 102 | @invert_match = invert_match 103 | end 104 | end 105 | end 106 | -------------------------------------------------------------------------------- /lib/glark/output/unfiltered_lines.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby -w 2 | #!ruby -w 3 | # vim: set filetype=ruby : set sw=2 4 | 5 | require 'glark/output/lines' 6 | require 'glark/output/glark_format' 7 | 8 | module Glark 9 | class UnfilteredLines < Lines 10 | include Glark::Format 11 | 12 | def display_matches? 13 | false 14 | end 15 | 16 | def process_end lnum 17 | show_file_header 18 | write_all 19 | end 20 | 21 | def write_all 22 | show_file_header 23 | (0 ... @file.get_lines.length).each do |ln| 24 | print_line ln 25 | end 26 | end 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /lib/glark/util/colors/options.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby -w 2 | # -*- ruby -*- 3 | 4 | require 'glark/util/colors/spec' 5 | 6 | module Glark 7 | class ColorOptions < ColorSpec 8 | DEFAULT_COLORS = [ 9 | # "FF88CC", 10 | "black on yellow", 11 | "black on green", 12 | "black on magenta", 13 | "yellow on black", 14 | "magenta on black", 15 | "green on black", 16 | "cyan on black", 17 | "blue on yellow", 18 | "blue on magenta", 19 | "blue on green", 20 | "blue on cyan", 21 | "yellow on blue", 22 | "magenta on blue", 23 | "green on blue", 24 | "cyan on blue", 25 | ] 26 | 27 | attr_reader :text_color_style # single, multi, or nil (no text highlights) 28 | 29 | def initialize 30 | super 31 | @highlighter = nil 32 | @text_color_style = "multi" 33 | end 34 | 35 | # creates a color for the given option, based on its value 36 | def create_color opt, value 37 | if @highlighter 38 | if value 39 | make_color value 40 | else 41 | raise "error: '" + opt + "' requires a color" 42 | end 43 | else 44 | log { "no highlighter defined" } 45 | end 46 | end 47 | 48 | def make_color color 49 | @highlighter.to_codes color 50 | end 51 | 52 | def make_colors limit = -1 53 | DEFAULT_COLORS[0 .. limit].collect do |color| 54 | make_color color 55 | end 56 | end 57 | 58 | def multi_colors 59 | make_colors 60 | end 61 | 62 | def single_color 63 | make_colors 0 64 | end 65 | 66 | def text_color_style= tcstyle 67 | @text_color_style = tcstyle 68 | if @text_color_style 69 | @highlighter = @text_color_style && RainbowHighlighter.instance 70 | @text_colors = case @text_color_style 71 | when highlight_multi?(@text_color_style), true 72 | multi_colors 73 | when "single" 74 | single_color 75 | else 76 | raise "highlight format '" + @text_color_style.to_s + "' not recognized" 77 | end 78 | 79 | @file_name_color = make_color "bold" 80 | @line_number_color = nil 81 | else 82 | @highlighter = nil 83 | @text_colors = Array.new 84 | @file_name_color = nil 85 | @line_number_color = nil 86 | end 87 | end 88 | 89 | def set_text_color index, color 90 | @text_colors[index] = color 91 | end 92 | 93 | def highlight_multi? str 94 | %w{ multi on true yes }.detect { |x| str == x } 95 | end 96 | 97 | def config_fields 98 | { 99 | "file-color" => @file_name_color, 100 | "highlight" => @text_color_style, 101 | "line-number-color" => @line_number_color, 102 | } 103 | end 104 | 105 | def dump_fields 106 | { 107 | "file_name_color" => colorize(@file_name_color, "filename"), 108 | "highlight" => @text_color_style, 109 | "line_number_color" => colorize(@line_number_color, "12345"), 110 | } 111 | end 112 | 113 | def colorize field, str 114 | if field 115 | field + str + Sickill::Rainbow::TERM_EFFECTS[:reset] 116 | else 117 | str 118 | end 119 | end 120 | 121 | def update_fields fields 122 | fields.each do |name, values| 123 | case name 124 | when "file-color" 125 | @file_name_color = create_color name, values.last 126 | when "highlight" 127 | self.text_color_style = values.last 128 | when "line-number-color" 129 | @line_number_color = create_color name, values.last 130 | when "text-color" 131 | @text_colors = [ create_color(name, values.last) ] 132 | when %r{^text\-color\-(\d+)$} 133 | set_text_color $1.to_i, create_color(name, values.last) 134 | end 135 | end 136 | end 137 | end 138 | end 139 | -------------------------------------------------------------------------------- /lib/glark/util/colors/spec.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby -w 2 | # -*- ruby -*- 3 | 4 | module Glark 5 | class ColorSpec 6 | attr_accessor :text_colors 7 | attr_accessor :file_name_color 8 | attr_accessor :line_number_color 9 | 10 | def initialize 11 | @text_colors = Array.new 12 | @file_name_color = nil 13 | @line_number_color = nil 14 | end 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /lib/glark/util/highlight.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby -w 2 | # -*- ruby -*- 3 | 4 | require 'rubygems' 5 | require 'rainbow' 6 | require 'singleton' 7 | 8 | module Highlight 9 | RESET = "\x1b[0m" 10 | 11 | def adorn hl, str 12 | hl + str + RESET 13 | end 14 | end 15 | 16 | class RainbowHighlighter 17 | include Singleton 18 | 19 | COLORS = %w{ black red green yellow blue magenta cyan white [\dA-Fa-f]{6} } 20 | DECORATIONS = %w{ none reset bold underscore underline blink reverse inverse negative concealed } 21 | 22 | BACKGROUND_COLORS = COLORS.collect { |color| "on_#{color}" } 23 | FOREGROUND_COLORS = COLORS 24 | 25 | COLORS_RE = Regexp.new('(?: ' + 26 | # background will be in capture 0 27 | 'on(?:\s+|_) ( ' + COLORS.join(' | ') + ' ) | ' + 28 | # foreground will be in capture 1 29 | '( ' + (COLORS + DECORATIONS).join(' | ') + ' ) ' + 30 | ')', Regexp::EXTENDED) 31 | 32 | def get_code color, type 33 | case color 34 | when 'bold', 'bright' 35 | Rainbow::Presenter::TERM_EFFECTS[:bright] 36 | when 'reverse', 'negative', 'inverse' 37 | Rainbow::Presenter::TERM_EFFECTS[:inverse] 38 | when 'underline' 39 | Rainbow::Presenter::TERM_EFFECTS[:underline] 40 | when 'blink' 41 | Rainbow::Presenter::TERM_EFFECTS[:blink] 42 | when %r{^[\dA-Fa-f]{6}$} 43 | ac = Rainbow::Color.build type, [ color ] 44 | ac.codes.join(';') 45 | else 46 | ac = Rainbow::Color.build type, [ color.to_sym ] 47 | ac.codes.join(';') 48 | end 49 | end 50 | 51 | def to_codes color 52 | codes = "" 53 | return codes unless Rainbow.enabled 54 | color.scan(COLORS_RE).collect do |md| 55 | color, type = md[0] ? [ md[0], :background ] : [ md[1], :foreground ] 56 | code = get_code color, type 57 | "\e[#{code}m" 58 | end.join '' 59 | end 60 | end 61 | -------------------------------------------------------------------------------- /lib/glark/util/io/depth.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby -w 2 | #!ruby -w 3 | # vim: set filetype=ruby : set sw=2 4 | 5 | module Glark 6 | # Depth for recursing directories. 7 | class Depth 8 | INFINITY = :infinity 9 | 10 | attr_reader :value 11 | 12 | def initialize value 13 | @value = value 14 | end 15 | 16 | def infinity? 17 | @value == INFINITY 18 | end 19 | 20 | def - num 21 | return self if infinity? || @value.nil? 22 | self.class.new @value - 1 23 | end 24 | 25 | def nonzero? 26 | infinity? || @value.nil? || @value >= 0 27 | end 28 | end 29 | end 30 | -------------------------------------------------------------------------------- /lib/glark/util/io/fileset.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby -w 2 | #!ruby -w 3 | # vim: set filetype=ruby : set sw=2 4 | 5 | require 'rubygems' 6 | require 'logue/loggable' 7 | require 'glark/util/io/depth' 8 | require 'riel/filetype' 9 | 10 | module Glark 11 | # Files and directories. And standard input, just for fun. 12 | class FileSet 13 | include Logue::Loggable, Enumerable 14 | 15 | attr_reader :files 16 | 17 | DEPTH_RE = Regexp.new '\.\.\.(\d*)$' 18 | 19 | def initialize fnames, args 20 | @max_depth = Depth.new args[:max_depth] 21 | @binary_files = args[:binary_files] || 'skip' 22 | @dir_criteria = args[:dir_criteria] 23 | @file_criteria = args[:file_criteria] 24 | @split_as_path = args[:split_as_path] 25 | 26 | @dir_to_max_depth = Hash.new 27 | @files = Array.new 28 | 29 | if fnames.size == 0 30 | @files << '-' 31 | else 32 | add_files fnames 33 | end 34 | end 35 | 36 | def size 37 | @files.size 38 | end 39 | 40 | def add_files fnames 41 | fnames.each do |fname| 42 | if @split_as_path 43 | add_as_path fname 44 | else 45 | add_fd fname 46 | end 47 | end 48 | end 49 | 50 | # this is a path in the form /usr/bin:/home/me/projects 51 | def add_as_path path 52 | path.to_s.split(::File::PATH_SEPARATOR).each do |element| 53 | add_fd element 54 | end 55 | end 56 | 57 | def add_fd fname 58 | pn = nil 59 | 60 | if md = DEPTH_RE.match(fname) 61 | val = md[1].empty? ? nil : md[1].to_i 62 | fname.sub! DEPTH_RE, '' 63 | fname = '.' if fname.empty? 64 | pn = Pathname.new fname 65 | @dir_to_max_depth[pn] = Depth.new val 66 | else 67 | pn = Pathname.new fname 68 | end 69 | 70 | return if pn.file? && @file_criteria.skipped?(pn) 71 | @files << pn 72 | end 73 | 74 | def stdin? 75 | @files.size == 1 && @files.first == '-' 76 | end 77 | 78 | def each &blk 79 | # to keep from cycling through links: 80 | @yielded_files = Array.new 81 | 82 | (0 ... @files.size).each do |idx| 83 | pn = @files[idx] 84 | if stdin? 85 | blk.call [ :text, '-' ] 86 | next 87 | end 88 | 89 | unless pn.readable? 90 | $stderr.puts "directory not readable: #{pn}" 91 | next 92 | end 93 | 94 | dirmax = @dir_to_max_depth[pn] || @max_depth 95 | handle_pathname pn, dirmax, &blk 96 | end 97 | end 98 | 99 | def handle_pathname pn, depth, &blk 100 | if pn.directory? 101 | handle_directory pn, depth, &blk 102 | elsif pn.file? 103 | handle_file pn, &blk 104 | else 105 | $stderr.puts "unknown file type: #{pn}" 106 | end 107 | end 108 | 109 | def handle_directory pn, depth, &blk 110 | return if @dir_criteria.skipped? pn, depth 111 | 112 | subdepth = depth - 1 113 | 114 | pn.children.sort.each do |entry| 115 | if entry.file? 116 | type = FileType.type entry.to_s 117 | next if type == FileType::BINARY && @binary_files == 'skip' 118 | end 119 | handle_pathname entry, subdepth, &blk 120 | end 121 | end 122 | 123 | def handle_file pn, &blk 124 | return if @file_criteria.skipped? pn 125 | return if @yielded_files.include? pn 126 | @yielded_files << pn 127 | 128 | type = FileType.type pn.to_s 129 | case type 130 | when FileType::TEXT 131 | handle_text pn, &blk 132 | when FileType::BINARY 133 | handle_binary pn, &blk 134 | when FileType::NONE 135 | $stderr.puts "no such file: #{pn}" 136 | when FileType::UNKNOWN 137 | $stderr.puts "unknown file type: #{pn}" 138 | end 139 | end 140 | 141 | def handle_text pn, &blk 142 | blk.call [ :text, pn ] 143 | end 144 | 145 | def handle_binary pn, &blk 146 | type = case @binary_files 147 | when 'binary' 148 | :binary 149 | when 'skip', 'without-match' 150 | return 151 | when 'decompress', 'read' 152 | :read 153 | when 'list' 154 | :list 155 | else 156 | :text 157 | end 158 | blk.call [ type, pn ] 159 | end 160 | end 161 | end 162 | -------------------------------------------------------------------------------- /lib/glark/util/io/filter/criteria.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby -w 2 | #!ruby -w 3 | # vim: set filetype=ruby : set sw=2 4 | 5 | require 'rubygems' 6 | require 'logue/loggable' 7 | require 'glark/util/io/filter/filter' 8 | 9 | module Glark 10 | class Criteria 11 | include Logue::Loggable 12 | 13 | def initialize 14 | # by type (hash) => by positive/negative (hash) => filter list (array) 15 | @type_to_posneg = Hash.new 16 | end 17 | 18 | def add type, posneg, filter 19 | posneg_to_filters = (@type_to_posneg[type] ||= Hash.new) 20 | filters = (posneg_to_filters[posneg] ||= Array.new) 21 | filters << filter 22 | end 23 | 24 | def get type, posneg 25 | return nil unless posneg_to_filters = @type_to_posneg[type] 26 | posneg_to_filters[posneg] 27 | end 28 | 29 | def find_by_class type, posneg, cls 30 | return unless filters = get(type, posneg) 31 | filters.detect { |filter| filter.kind_of? cls } 32 | end 33 | 34 | def skipped? pn 35 | !match? pn 36 | end 37 | 38 | def match? pn 39 | @type_to_posneg.values.each do |typefilters| 40 | if (posf = typefilters[:positive]) && !posf.empty? 41 | return false unless posf.detect { |fl| fl.match? pn } 42 | end 43 | 44 | if (negf = typefilters[:negative]) && !negf.empty? 45 | return false if negf.detect { |fl| fl.match? pn } 46 | end 47 | end 48 | true 49 | end 50 | end 51 | end 52 | -------------------------------------------------------------------------------- /lib/glark/util/io/filter/filter.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby -w 2 | #!ruby -w 3 | # vim: set filetype=ruby : set sw=2 4 | 5 | module Glark 6 | class Filter 7 | def match? pn 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /lib/glark/util/io/lines.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby -w 2 | #!ruby -w 3 | # vim: set filetype=ruby : set sw=2 4 | 5 | module Glark 6 | module IO 7 | # Lines of input. Handles non-default ("\n") record separator. 8 | class Lines 9 | def initialize fname 10 | @fname = fname 11 | @count = nil 12 | end 13 | 14 | # Returns the given line for this file. For this method, a line ends with a 15 | # CR, as opposed to the "lines" method, which ends with $/. 16 | def get_line lnum 17 | get_lines[lnum] 18 | end 19 | 20 | # this reads the entire file and returns the number of lines 21 | def count 22 | unless @count 23 | @count = ::IO::readlines(@fname).size 24 | end 25 | @count 26 | end 27 | end 28 | 29 | class LinesCR < Lines 30 | def initialize fname, io 31 | super fname 32 | @lines = Array.new 33 | @io = io 34 | end 35 | 36 | # Returns the lines for this file, separated by end of line sequences. 37 | def get_lines 38 | return @lines 39 | end 40 | 41 | def each_line &blk 42 | while (line = @io.gets) && line.length > 0 43 | @lines << line 44 | blk.call line 45 | end 46 | @io.close 47 | end 48 | 49 | def get_region rnum 50 | # easy case: range is the range number, unless it is out of range. 51 | return rnum < @lines.length ? (rnum .. rnum) : nil 52 | end 53 | end 54 | 55 | class LinesNonCR < Lines 56 | # cross-platform end of line: DOS UNIX MAC 57 | ANY_END_OF_LINE = Regexp.new '(?:\r\n|\n|\r)' 58 | 59 | def initialize fname, io 60 | super fname 61 | @extracted = nil 62 | @regions = nil 63 | @lines = ::IO::readlines fname 64 | end 65 | 66 | def each_line &blk 67 | @lines.each do |line| 68 | blk.call line 69 | end 70 | end 71 | 72 | # Returns the lines for this file, separated by end of line sequences. 73 | def get_lines 74 | @extracted ||= create_extracted 75 | end 76 | 77 | # returns the region/range that is represented by the region number 78 | def get_region rnum 79 | @regions ||= create_regions 80 | @regions[rnum] 81 | end 82 | 83 | private 84 | def create_extracted 85 | # This is much easier. Just resplit the whole thing at end of line 86 | # sequences. 87 | 88 | eoline = "\n" # should be OS-dependent 89 | reallines = @lines.join("").split ANY_END_OF_LINE 90 | 91 | # "\n" after all but the last line 92 | @extracted = (0 ... (reallines.length - 1)).collect { |lnum| reallines[lnum] + eoline } 93 | @extracted << reallines[-1] 94 | 95 | @extracted 96 | end 97 | 98 | def create_regions 99 | @regions = [] # keys = region number; values = range of lines 100 | 101 | lstart = 0 102 | @lines.each do |line| 103 | lend = lstart 104 | line.scan(ANY_END_OF_LINE).each do |cr| 105 | lend += 1 106 | end 107 | 108 | @regions << ::Range.new(lstart, lend - 1) 109 | 110 | lstart = lend 111 | end 112 | @regions 113 | end 114 | end 115 | end 116 | end 117 | -------------------------------------------------------------------------------- /lib/glark/util/option.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby -w 2 | #!ruby -w 3 | # vim: set filetype=ruby : set sw=2 4 | 5 | module Glark 6 | class Option 7 | def initialize optee 8 | @optee = optee 9 | end 10 | 11 | def tags 12 | [ '--' + rcfield ] 13 | end 14 | 15 | def match_rc name, values 16 | if name == rcfield 17 | values.each do |val| 18 | set val 19 | end 20 | true 21 | end 22 | end 23 | 24 | def add_to_option_data optdata 25 | optdata << { 26 | :tags => tags, 27 | :arg => [ argtype ], 28 | :set => Proc.new { |pat| set pat } 29 | } 30 | end 31 | end 32 | end 33 | -------------------------------------------------------------------------------- /lib/glark/util/options.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby -w 2 | #!ruby -w 3 | # vim: set filetype=ruby : set sw=2 4 | 5 | require 'glark/util/optutil' 6 | require 'logue/loggable' 7 | 8 | module Glark 9 | class Options 10 | include Logue::Loggable, Glark::OptionUtil 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /lib/glark/util/optutil.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby -w 2 | # -*- ruby -*- 3 | 4 | require 'rubygems' 5 | require 'rainbow' 6 | 7 | module Glark 8 | module OptionUtil 9 | # returns whether the value matches a true value, such as "yes", "true", or "on". 10 | def to_boolean value 11 | [ "yes", "true", "on" ].include? value.downcase 12 | end 13 | 14 | NONE = Object.new 15 | 16 | def set_var name, val 17 | instance_variable_set '@' + name.to_s, val 18 | end 19 | 20 | def set name, sval = NONE 21 | Proc.new { |optval| set_var name, sval == NONE ? optval : sval } 22 | end 23 | 24 | def add_opt optdata, varname, tags, val = NONE 25 | optdata << { 26 | :tags => tags, 27 | :set => set(varname, val) 28 | } 29 | end 30 | 31 | def add_opt_arg optdata, varname, argtype, tags, val = NONE 32 | optdata << { 33 | :tags => tags, 34 | :arg => [ argtype ], 35 | :set => set(varname, val) 36 | } 37 | end 38 | 39 | def add_opt_true optdata, varname, tags 40 | add_opt optdata, varname, tags, true 41 | end 42 | 43 | def add_opt_false optdata, varname, tags 44 | add_opt optdata, varname, tags, false 45 | end 46 | 47 | def add_opt_str optdata, varname, tags, val = NONE 48 | add_opt_arg optdata, varname, :string, tags, val 49 | end 50 | 51 | def add_opt_int optdata, varname, tags, val = NONE 52 | add_opt_arg optdata, varname, :integer, tags, val 53 | end 54 | 55 | def add_opt_blk optdata, tags, &blk 56 | optdata << { 57 | :tags => tags, 58 | :set => blk 59 | } 60 | end 61 | 62 | def colorize field, str 63 | if field 64 | field + str + Sickill::Rainbow::TERM_EFFECTS[:reset] 65 | else 66 | str 67 | end 68 | end 69 | end 70 | end 71 | -------------------------------------------------------------------------------- /lib/glark/util/timestamper.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby -w 2 | # -*- ruby -*- 3 | 4 | module TimeStamper 5 | def stamp msg = self 6 | @start ||= Time.new 7 | duration = Time.new - @start 8 | printf "%10.6f %-20s %s\n", duration, self.class.to_s, msg.to_s 9 | end 10 | 11 | def interval msg = self 12 | @last ||= @start 13 | last = @last || Time.new 14 | @last = Time.new 15 | duration = @last - last 16 | printf "%10.6f %-20s %s\n", duration, self.class.to_s, msg.to_s 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /test/glark/app/and_test.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby -w 2 | # -*- ruby -*- 3 | 4 | require 'glark/app/tc' 5 | 6 | module Glark 7 | class AndTestCase < AppTestCase 8 | def test_one_line 9 | fname = to_path "textfile.txt" 10 | expected = [ 11 | " 6 -rw-r--r-- 1 jpace jpace 63290 2010-12-04 15:24 05-TheManOfLawsTale.txt", 12 | " 10 -rw-r--r-- 1 jpace jpace 64791 2010-12-04 15:24 09-TheClerksTale.txt", 13 | " 11 -rw-r--r-- 1 jpace jpace 65852 2010-12-04 15:24 10-TheMerchantsTale.txt", 14 | ] 15 | run_app_test expected, [ '--and', '\b6\d{4}\b', 'The.*Tale' ], fname 16 | end 17 | 18 | def test_multi_line 19 | fname = to_path "textfile.txt" 20 | expected = [ 21 | " 12 -rw-r--r-- 1 jpace jpace 42282 2010-12-04 15:24 11-TheSquiresTale.txt", 22 | " 13 -rw-r--r-- 1 jpace jpace 51996 2010-12-04 15:24 12-TheFranklinsTale.txt", 23 | " 14 -rw-r--r-- 1 jpace jpace 15615 2010-12-04 15:24 13-TheDoctorsTale.txt", 24 | " 15 -rw-r--r-- 1 jpace jpace 39546 2010-12-04 15:24 14-ThePardonersTale.txt", 25 | " 16 -rw-r--r-- 1 jpace jpace 25163 2010-12-04 15:24 15-TheShipmansTale.txt", 26 | " 22 -rw-r--r-- 1 jpace jpace 30734 2010-12-04 15:24 21-TheSecondNunsTale.txt", 27 | " 23 -rw-r--r-- 1 jpace jpace 52953 2010-12-04 15:24 22-TheCanonsYeomansTale.txt", 28 | " 24 -rw-r--r-- 1 jpace jpace 21141 2010-12-04 15:24 23-TheManciplesTale.txt", 29 | " 25 -rw-r--r-- 1 jpace jpace 58300 2010-12-04 15:24 24-TheParsonsTale.txt", 30 | ] 31 | run_app_test expected, [ '--and=3', '\b5\d{4}\b', 'TheS.*Tale' ], fname 32 | end 33 | 34 | def test_infinite_distance 35 | fname = to_path "textfile.txt" 36 | expected = [ 37 | " 2 -rw-r--r-- 1 jpace jpace 126084 2010-12-04 15:24 01-TheKnightsTale.txt", 38 | " 3 -rw-r--r-- 1 jpace jpace 45450 2010-12-04 15:24 02-TheMillersTale.txt", 39 | " 4 -rw-r--r-- 1 jpace jpace 29296 2010-12-04 15:24 03-TheReevesTale.txt", 40 | " 5 -rw-r--r-- 1 jpace jpace 6525 2010-12-04 15:24 04-TheCooksTale.txt", 41 | " 6 -rw-r--r-- 1 jpace jpace 63290 2010-12-04 15:24 05-TheManOfLawsTale.txt", 42 | " 7 -rw-r--r-- 1 jpace jpace 71054 2010-12-04 15:24 06-TheWifeOfBathsTale.txt", 43 | " 8 -rw-r--r-- 1 jpace jpace 22754 2010-12-04 15:24 07-TheFriarsTale.txt", 44 | " 9 -rw-r--r-- 1 jpace jpace 35994 2010-12-04 15:24 08-TheSompnoursTale.txt", 45 | " 10 -rw-r--r-- 1 jpace jpace 64791 2010-12-04 15:24 09-TheClerksTale.txt", 46 | " 11 -rw-r--r-- 1 jpace jpace 65852 2010-12-04 15:24 10-TheMerchantsTale.txt", 47 | " 12 -rw-r--r-- 1 jpace jpace 42282 2010-12-04 15:24 11-TheSquiresTale.txt", 48 | " 13 -rw-r--r-- 1 jpace jpace 51996 2010-12-04 15:24 12-TheFranklinsTale.txt", 49 | " 14 -rw-r--r-- 1 jpace jpace 15615 2010-12-04 15:24 13-TheDoctorsTale.txt", 50 | " 15 -rw-r--r-- 1 jpace jpace 39546 2010-12-04 15:24 14-ThePardonersTale.txt", 51 | " 16 -rw-r--r-- 1 jpace jpace 25163 2010-12-04 15:24 15-TheShipmansTale.txt", 52 | " 17 -rw-r--r-- 1 jpace jpace 14979 2010-12-04 15:24 16-ThePrioresssTale.txt", 53 | " 18 -rw-r--r-- 1 jpace jpace 14834 2010-12-04 15:24 17-ChaucersTaleOfSirThopas.txt", 54 | " 19 -rw-r--r-- 1 jpace jpace 43249 2010-12-04 15:24 18-ChaucersTaleOfMeliboeus.txt", 55 | " 20 -rw-r--r-- 1 jpace jpace 49747 2010-12-04 15:24 19-TheMonksTale.txt", 56 | " 21 -rw-r--r-- 1 jpace jpace 45326 2010-12-04 15:24 20-TheNunsPriestsTale.txt", 57 | " 22 -rw-r--r-- 1 jpace jpace 30734 2010-12-04 15:24 21-TheSecondNunsTale.txt", 58 | " 23 -rw-r--r-- 1 jpace jpace 52953 2010-12-04 15:24 22-TheCanonsYeomansTale.txt", 59 | ] 60 | run_app_test expected, [ '--and=-1', '\b529\d{2}\b', 'TheKni.*Tale' ], fname 61 | end 62 | 63 | def test_multi_line_grep_one_file 64 | fname = to_path "textfile.txt" 65 | expected = [ 66 | " -rw-r--r-- 1 jpace jpace 42282 2010-12-04 15:24 11-TheSquiresTale.txt", 67 | " -rw-r--r-- 1 jpace jpace 30734 2010-12-04 15:24 21-TheSecondNunsTale.txt", 68 | " -rw-r--r-- 1 jpace jpace 51996 2010-12-04 15:24 12-TheFranklinsTale.txt", 69 | ] 70 | run_app_test expected, [ '-g', '--and=3', '\b5\d{4}\b', 'TheS.*Tale' ], fname 71 | end 72 | 73 | def test_multi_line_grep_two_files 74 | fnames = [ to_path("textfile.txt"), to_path("filelist.txt") ] 75 | expected = [ 76 | RES_DIR + "/textfile.txt: -rw-r--r-- 1 jpace jpace 30734 2010-12-04 15:24 21-TheSecondNunsTale.txt", 77 | RES_DIR + "/filelist.txt:21-The_Second_Nuns_Tale.txt", 78 | ] 79 | run_app_test expected, [ '-g', '--and=3', '\b21\b', 'The.*Can.*Tale' ], *fnames 80 | end 81 | end 82 | end 83 | -------------------------------------------------------------------------------- /test/glark/app/compound_test.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby -w 2 | # -*- ruby -*- 3 | 4 | require 'glark/app/tc' 5 | require 'glark/resources' 6 | 7 | module Glark 8 | class CompoundTestCase < AppTestCase 9 | include Glark::Resources 10 | 11 | def test_hardly_simple 12 | fname = to_path "textfile.txt" 13 | expected = [ 14 | " 3 -rw-r--r-- 1 jpace jpace 45450 2010-12-04 15:24 02-TheMillersTale.txt", 15 | " 4 -rw-r--r-- 1 jpace jpace 29296 2010-12-04 15:24 03-TheReevesTale.txt", 16 | " 5 -rw-r--r-- 1 jpace jpace 6525 2010-12-04 15:24 04-TheCooksTale.txt", 17 | " 6 -rw-r--r-- 1 jpace jpace 63290 2010-12-04 15:24 05-TheManOfLawsTale.txt", 18 | " 7 -rw-r--r-- 1 jpace jpace 71054 2010-12-04 15:24 06-TheWifeOfBathsTale.txt", 19 | " 8 -rw-r--r-- 1 jpace jpace 22754 2010-12-04 15:24 07-TheFriarsTale.txt", 20 | " 9 -rw-r--r-- 1 jpace jpace 35994 2010-12-04 15:24 08-TheSompnoursTale.txt", 21 | " 10 -rw-r--r-- 1 jpace jpace 64791 2010-12-04 15:24 09-TheClerksTale.txt", 22 | " 11 -rw-r--r-- 1 jpace jpace 65852 2010-12-04 15:24 10-TheMerchantsTale.txt", 23 | " 12 -rw-r--r-- 1 jpace jpace 42282 2010-12-04 15:24 11-TheSquiresTale.txt", 24 | " 13 -rw-r--r-- 1 jpace jpace 51996 2010-12-04 15:24 12-TheFranklinsTale.txt", 25 | " 18 -rw-r--r-- 1 jpace jpace 14834 2010-12-04 15:24 17-ChaucersTaleOfSirThopas.txt", 26 | " 19 -rw-r--r-- 1 jpace jpace 43249 2010-12-04 15:24 18-ChaucersTaleOfMeliboeus.txt", 27 | " 20 -rw-r--r-- 1 jpace jpace 49747 2010-12-04 15:24 19-TheMonksTale.txt", 28 | " 21 -rw-r--r-- 1 jpace jpace 45326 2010-12-04 15:24 20-TheNunsPriestsTale.txt", 29 | " 22 -rw-r--r-- 1 jpace jpace 30734 2010-12-04 15:24 21-TheSecondNunsTale.txt", 30 | " 23 -rw-r--r-- 1 jpace jpace 52953 2010-12-04 15:24 22-TheCanonsYeomansTale.txt", 31 | " 24 -rw-r--r-- 1 jpace jpace 21141 2010-12-04 15:24 23-TheManciplesTale.txt", 32 | ] 33 | run_app_test expected, [ '--and=3', '--or', '\b6\d{4}\b', '\b\d{4}4\b', '--or', 'TheF.*', 'TheM.*Tale' ], fname 34 | end 35 | end 36 | end 37 | -------------------------------------------------------------------------------- /test/glark/app/context_test.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby -w 2 | # -*- ruby -*- 3 | 4 | require 'glark/app/tc' 5 | require 'glark/resources' 6 | 7 | module Glark 8 | class ContextTestCase < AppTestCase 9 | include Glark::Resources 10 | 11 | def test_context 12 | fname = to_path "textfile.txt" 13 | expected = [ 14 | " 11 - -rw-r--r-- 1 jpace jpace 65852 2010-12-04 15:24 10-TheMerchantsTale.txt", 15 | " 12 - -rw-r--r-- 1 jpace jpace 42282 2010-12-04 15:24 11-TheSquiresTale.txt", 16 | " 13 - -rw-r--r-- 1 jpace jpace 51996 2010-12-04 15:24 12-TheFranklinsTale.txt", 17 | " 14 : -rw-r--r-- 1 jpace jpace 15615 2010-12-04 15:24 13-TheDoctorsTale.txt", 18 | " 15 + -rw-r--r-- 1 jpace jpace 39546 2010-12-04 15:24 14-ThePardonersTale.txt", 19 | " 16 + -rw-r--r-- 1 jpace jpace 25163 2010-12-04 15:24 15-TheShipmansTale.txt", 20 | " 17 + -rw-r--r-- 1 jpace jpace 14979 2010-12-04 15:24 16-ThePrioresssTale.txt", 21 | ] 22 | run_app_test expected, %w{ -3 TheDoc }, fname 23 | end 24 | 25 | def test_after 26 | fname = to_path "textfile.txt" 27 | expected = [ 28 | " 14 : -rw-r--r-- 1 jpace jpace 15615 2010-12-04 15:24 13-TheDoctorsTale.txt", 29 | " 15 + -rw-r--r-- 1 jpace jpace 39546 2010-12-04 15:24 14-ThePardonersTale.txt", 30 | " 16 + -rw-r--r-- 1 jpace jpace 25163 2010-12-04 15:24 15-TheShipmansTale.txt", 31 | ] 32 | run_app_test expected, %w{ --after-context 2 TheDoc }, fname 33 | end 34 | 35 | def test_before 36 | fname = to_path "textfile.txt" 37 | expected = [ 38 | " 11 - -rw-r--r-- 1 jpace jpace 65852 2010-12-04 15:24 10-TheMerchantsTale.txt", 39 | " 12 - -rw-r--r-- 1 jpace jpace 42282 2010-12-04 15:24 11-TheSquiresTale.txt", 40 | " 13 - -rw-r--r-- 1 jpace jpace 51996 2010-12-04 15:24 12-TheFranklinsTale.txt", 41 | " 14 : -rw-r--r-- 1 jpace jpace 15615 2010-12-04 15:24 13-TheDoctorsTale.txt", 42 | ] 43 | run_app_test expected, %w{ --before-context 3 TheDoc }, fname 44 | end 45 | end 46 | end 47 | -------------------------------------------------------------------------------- /test/glark/app/count_test.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby -w 2 | # -*- ruby -*- 3 | 4 | require 'glark/app/tc' 5 | require 'glark/resources' 6 | 7 | module Glark 8 | class CountTestCase < AppTestCase 9 | include Glark::Resources 10 | 11 | def test_one_file 12 | fname = to_path "spaces.txt" 13 | expected = [ 14 | " 13", 15 | ] 16 | run_app_test expected, [ '--count', '\wa\w+s' ], fname 17 | end 18 | 19 | def test_two_files_one_matches 20 | fnames = [ to_path("textfile.txt"), to_path("filelist.txt") ] 21 | expected = [ 22 | "" + RES_DIR + "/textfile.txt", 23 | " 2", 24 | ] 25 | run_app_test expected, [ '--count', '2 ' ], *fnames 26 | end 27 | 28 | def test_two_files_both_match 29 | fnames = [ to_path("textfile.txt"), to_path("filelist.txt") ] 30 | expected = [ 31 | "" + RES_DIR + "/textfile.txt", 32 | " 13", 33 | "" + RES_DIR + "/filelist.txt", 34 | " 2", 35 | ] 36 | run_app_test expected, [ '--count', '6.*The' ], *fnames 37 | end 38 | 39 | def test_grep_one_file 40 | fnames = [ to_path("spaces.txt") ] 41 | expected = [ 42 | "2", 43 | ] 44 | run_app_test expected, [ '-g', '--count', '6.*The' ], *fnames 45 | end 46 | 47 | def test_grep_two_files_one_matches 48 | fnames = [ to_path("textfile.txt"), to_path("filelist.txt") ] 49 | expected = [ 50 | RES_DIR + "/textfile.txt:2", 51 | ] 52 | run_app_test expected, [ '-g', '--count', '2 ' ], *fnames 53 | end 54 | 55 | def test_grep_two_files_both_match 56 | fnames = [ to_path("textfile.txt"), to_path("filelist.txt") ] 57 | expected = [ 58 | RES_DIR + "/textfile.txt:13", 59 | RES_DIR + "/filelist.txt:2" 60 | ] 61 | run_app_test expected, [ '-g', '--count', '6.*The' ], *fnames 62 | end 63 | 64 | def test_grep_one_file_invert 65 | fnames = [ to_path("spaces.txt") ] 66 | expected = [ 67 | "24", 68 | ] 69 | run_app_test expected, [ '--invert-match', '-g', '--count', '6.*The' ], *fnames 70 | end 71 | 72 | def test_grep_two_files_invert_one_matches 73 | fnames = [ to_path("textfile.txt"), to_path("filelist.txt") ] 74 | expected = [ 75 | RES_DIR + "/textfile.txt:24", 76 | RES_DIR + "/filelist.txt:26", 77 | ] 78 | run_app_test expected, [ '--invert-match', '-g', '--count', '2 ' ], *fnames 79 | end 80 | 81 | def test_glark_two_files_invert_both_match 82 | fnames = [ to_path("textfile.txt"), to_path("filelist.txt") ] 83 | expected = [ 84 | "" + RES_DIR + "/textfile.txt", 85 | " 13", 86 | "" + RES_DIR + "/filelist.txt", 87 | " 24", 88 | ] 89 | run_app_test expected, [ '--invert-match', '--count', '6.*The' ], *fnames 90 | end 91 | end 92 | end 93 | -------------------------------------------------------------------------------- /test/glark/app/expression_file_test.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby -w 2 | # -*- ruby -*- 3 | 4 | require 'glark/app/tc' 5 | require 'glark/resources' 6 | 7 | module Glark 8 | class ExpressionFileTestCase < AppTestCase 9 | include Glark::Resources 10 | 11 | def test_simple 12 | infile = to_path "expressions.txt" 13 | file = to_path "textfile.txt" 14 | expected = [ 15 | " 3 -rw-r--r-- 1 jpace jpace 45450 2010-12-04 15:24 02-TheMillersTale.txt", 16 | " 6 -rw-r--r-- 1 jpace jpace 63290 2010-12-04 15:24 05-TheManOfLawsTale.txt", 17 | " 10 -rw-r--r-- 1 jpace jpace 64791 2010-12-04 15:24 09-TheClerksTale.txt", 18 | " 11 -rw-r--r-- 1 jpace jpace 65852 2010-12-04 15:24 10-TheMerchantsTale.txt", 19 | " 20 -rw-r--r-- 1 jpace jpace 49747 2010-12-04 15:24 19-TheMonksTale.txt", 20 | " 24 -rw-r--r-- 1 jpace jpace 21141 2010-12-04 15:24 23-TheManciplesTale.txt", 21 | ] 22 | run_app_test expected, [ '--file', infile ], file 23 | end 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /test/glark/app/extended_regexp_test.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby -w 2 | # -*- ruby -*- 3 | 4 | require 'glark/app/tc' 5 | require 'glark/resources' 6 | 7 | module Glark 8 | class ExtendedRegexpTestCase < AppTestCase 9 | include Glark::Resources 10 | 11 | def test_simple 12 | fname = to_path "textfile.txt" 13 | expected = [ 14 | " 15 -rw-r--r-- 1 jpace jpace 39546 2010-12-04 15:24 14-ThePardonersTale.txt", 15 | " 25 -rw-r--r-- 1 jpace jpace 58300 2010-12-04 15:24 24-TheParsonsTale.txt", 16 | ] 17 | run_app_test expected, [ '--extended', 'The P a r' ], fname 18 | end 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /test/glark/app/extract_matches_test.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby -w 2 | # -*- ruby -*- 3 | 4 | require 'glark/app/tc' 5 | require 'glark/resources' 6 | 7 | module Glark 8 | class ExtractMatchesTestCase < AppTestCase 9 | include Glark::Resources 10 | 11 | def test_simple 12 | fname = to_path "textfile.txt" 13 | expected = [ 14 | " 1 ThePrologue", 15 | " 3 TheMillersTale", 16 | " 5 TheCooksTale", 17 | " 6 TheManOfLawsTale", 18 | " 10 TheClerksTale", 19 | " 11 TheMerchantsTale", 20 | " 15 ThePardonersTale", 21 | " 17 ThePrioresssTale", 22 | " 20 TheMonksTale", 23 | " 23 TheCanonsYeomansTale", 24 | " 24 TheManciplesTale", 25 | " 25 TheParsonsTale", 26 | ] 27 | run_app_test expected, %w{ --extract-matches The[MCP]\w+ }, fname 28 | end 29 | end 30 | end 31 | -------------------------------------------------------------------------------- /test/glark/app/files_with_match_test.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby -w 2 | # -*- ruby -*- 3 | 4 | require 'glark/app/tc' 5 | require 'glark/resources' 6 | 7 | module Glark 8 | class FilesWithMatchTestCase < AppTestCase 9 | include Glark::Resources 10 | 11 | def test_one_of_one 12 | file = to_path "textfile.txt" 13 | expected = [ file ] 14 | run_app_test expected, [ '-l', 'TheM\w+Tale' ], file 15 | end 16 | 17 | def test_one_of_two 18 | files = [ to_path("textfile.txt"), to_path("filelist.txt") ] 19 | expected = [ files[0] ] 20 | run_app_test expected, [ '-l', 'TheM\w+Tale' ], *files 21 | end 22 | 23 | def test_two_of_two 24 | files = [ to_path("textfile.txt"), to_path("filelist.txt") ] 25 | expected = files 26 | run_app_test expected, [ '-l', 'The.*M\w+Tale' ], *files 27 | end 28 | 29 | def test_null_two 30 | files = [ to_path("textfile.txt"), to_path("filelist.txt") ] 31 | expected = files.collect { |x| "#{x}\000" }.join('') 32 | run_app_test_exact_output expected, [ '-l', '-Z', 'The.*M\w+Tale' ], *files 33 | end 34 | end 35 | end 36 | -------------------------------------------------------------------------------- /test/glark/app/files_without_match_test.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby -w 2 | # -*- ruby -*- 3 | 4 | require 'glark/app/tc' 5 | require 'glark/resources' 6 | 7 | module Glark 8 | class FilesWithoutMatchTestCase < AppTestCase 9 | include Glark::Resources 10 | 11 | def test_one_of_one 12 | file = to_path "textfile.txt" 13 | expected = [ file ] 14 | run_app_test expected, [ '-L', 'TheX\w+Tale' ], file 15 | end 16 | 17 | def test_one_of_two 18 | files = [ to_path("textfile.txt"), to_path("filelist.txt") ] 19 | expected = [ files[1] ] 20 | run_app_test expected, [ '-L', 'TheM\w+Tale' ], *files 21 | end 22 | 23 | def test_none_of_two 24 | files = [ to_path("textfile.txt"), to_path("filelist.txt") ] 25 | expected = [ ] 26 | run_app_test expected, [ '-L', 'The.*P\w+Tale' ], *files 27 | end 28 | end 29 | end 30 | -------------------------------------------------------------------------------- /test/glark/app/ignore_case_test.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby -w 2 | # -*- ruby -*- 3 | 4 | require 'glark/app/tc' 5 | require 'glark/resources' 6 | 7 | module Glark 8 | class IgnoreCaseTestCase < AppTestCase 9 | include Glark::Resources 10 | 11 | def test_simple 12 | fname = to_path "spaces.txt" 13 | expected = [ 14 | " 6 05 The Man Of Laws Tale.txt", 15 | " 9 08 The Sompnours Tale.txt", 16 | " 11 10 The Merchants Tale.txt", 17 | " 16 15 The Shipmans Tale.txt", 18 | " 20 19 The Monks Tale.txt", 19 | " 23 22 The Canons Yeomans Tale.txt", 20 | " 24 23 The Manciples Tale.txt", 21 | ] 22 | run_app_test expected, [ '-i', 'the.*m.*n' ], fname 23 | end 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /test/glark/app/invert_test.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby -w 2 | # -*- ruby -*- 3 | 4 | require 'glark/app/tc' 5 | 6 | module Glark 7 | class InvertTestCase < AppTestCase 8 | 9 | def test_simple 10 | fname = to_path "textfile.txt" 11 | expected = [ 12 | " 2 -rw-r--r-- 1 jpace jpace 126084 2010-12-04 15:24 01-TheKnightsTale.txt", 13 | " 4 -rw-r--r-- 1 jpace jpace 29296 2010-12-04 15:24 03-TheReevesTale.txt", 14 | " 7 -rw-r--r-- 1 jpace jpace 71054 2010-12-04 15:24 06-TheWifeOfBathsTale.txt", 15 | " 8 -rw-r--r-- 1 jpace jpace 22754 2010-12-04 15:24 07-TheFriarsTale.txt", 16 | " 9 -rw-r--r-- 1 jpace jpace 35994 2010-12-04 15:24 08-TheSompnoursTale.txt", 17 | " 12 -rw-r--r-- 1 jpace jpace 42282 2010-12-04 15:24 11-TheSquiresTale.txt", 18 | " 13 -rw-r--r-- 1 jpace jpace 51996 2010-12-04 15:24 12-TheFranklinsTale.txt", 19 | " 14 -rw-r--r-- 1 jpace jpace 15615 2010-12-04 15:24 13-TheDoctorsTale.txt", 20 | " 16 -rw-r--r-- 1 jpace jpace 25163 2010-12-04 15:24 15-TheShipmansTale.txt", 21 | " 18 -rw-r--r-- 1 jpace jpace 14834 2010-12-04 15:24 17-ChaucersTaleOfSirThopas.txt", 22 | " 19 -rw-r--r-- 1 jpace jpace 43249 2010-12-04 15:24 18-ChaucersTaleOfMeliboeus.txt", 23 | " 22 -rw-r--r-- 1 jpace jpace 30734 2010-12-04 15:24 21-TheSecondNunsTale.txt", 24 | " 26 -rw-r--r-- 1 jpace jpace 3650 2010-12-04 15:24 25-PrecesDeChauceres.txt", 25 | ] 26 | run_app_test expected, %w{ --invert-match The.*[MCP] }, fname 27 | end 28 | 29 | def test_compound_expression 30 | fname = to_path "textfile.txt" 31 | expected = [ 32 | " 1 -rw-r--r-- 1 jpace jpace 52183 2010-12-04 15:24 00-ThePrologue.txt", 33 | " 2 -rw-r--r-- 1 jpace jpace 126084 2010-12-04 15:24 01-TheKnightsTale.txt", 34 | " 3 -rw-r--r-- 1 jpace jpace 45450 2010-12-04 15:24 02-TheMillersTale.txt", 35 | " 4 -rw-r--r-- 1 jpace jpace 29296 2010-12-04 15:24 03-TheReevesTale.txt", 36 | " 5 -rw-r--r-- 1 jpace jpace 6525 2010-12-04 15:24 04-TheCooksTale.txt", 37 | " 6 -rw-r--r-- 1 jpace jpace 63290 2010-12-04 15:24 05-TheManOfLawsTale.txt", 38 | " 7 -rw-r--r-- 1 jpace jpace 71054 2010-12-04 15:24 06-TheWifeOfBathsTale.txt", 39 | " 8 -rw-r--r-- 1 jpace jpace 22754 2010-12-04 15:24 07-TheFriarsTale.txt", 40 | " 17 -rw-r--r-- 1 jpace jpace 14979 2010-12-04 15:24 16-ThePrioresssTale.txt", 41 | " 18 -rw-r--r-- 1 jpace jpace 14834 2010-12-04 15:24 17-ChaucersTaleOfSirThopas.txt", 42 | " 19 -rw-r--r-- 1 jpace jpace 43249 2010-12-04 15:24 18-ChaucersTaleOfMeliboeus.txt", 43 | " 20 -rw-r--r-- 1 jpace jpace 49747 2010-12-04 15:24 19-TheMonksTale.txt", 44 | " 21 -rw-r--r-- 1 jpace jpace 45326 2010-12-04 15:24 20-TheNunsPriestsTale.txt", 45 | " 26 -rw-r--r-- 1 jpace jpace 3650 2010-12-04 15:24 25-PrecesDeChauceres.txt", 46 | ] 47 | run_app_test expected, [ '--invert-match', '--and=6', '\b5\d{4}\b', 'TheS.*Tale' ], fname 48 | end 49 | end 50 | end 51 | -------------------------------------------------------------------------------- /test/glark/app/ior_test.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby -w 2 | # -*- ruby -*- 3 | 4 | require 'glark/app/tc' 5 | require 'glark/resources' 6 | 7 | module Glark 8 | class InclusiveOrTestCase < AppTestCase 9 | include Glark::Resources 10 | 11 | def test_simple 12 | fname = to_path "textfile.txt" 13 | expected = [ 14 | " 3 -rw-r--r-- 1 jpace jpace 45450 2010-12-04 15:24 02-TheMillersTale.txt", 15 | " 6 -rw-r--r-- 1 jpace jpace 63290 2010-12-04 15:24 05-TheManOfLawsTale.txt", 16 | " 10 -rw-r--r-- 1 jpace jpace 64791 2010-12-04 15:24 09-TheClerksTale.txt", 17 | " 11 -rw-r--r-- 1 jpace jpace 65852 2010-12-04 15:24 10-TheMerchantsTale.txt", 18 | " 20 -rw-r--r-- 1 jpace jpace 49747 2010-12-04 15:24 19-TheMonksTale.txt", 19 | " 24 -rw-r--r-- 1 jpace jpace 21141 2010-12-04 15:24 23-TheManciplesTale.txt", 20 | ] 21 | run_app_test expected, [ '--or', '\b6\d{4}\b', 'TheM.*Tale' ], fname 22 | end 23 | end 24 | end 25 | -------------------------------------------------------------------------------- /test/glark/app/label_test.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby -w 2 | # -*- ruby -*- 3 | 4 | require 'glark/app/tc' 5 | 6 | module Glark 7 | class LabelTestCase < AppTestCase 8 | def test_one_file 9 | fname = to_path "textfile.txt" 10 | expected = [ 11 | "TheFileName", 12 | " 14 -rw-r--r-- 1 jpace jpace 15615 2010-12-04 15:24 13-TheDoctorsTale.txt" 13 | ] 14 | run_app_test expected, %w{ --label TheFileName TheDoc }, fname 15 | end 16 | 17 | def test_two_files 18 | fnames = [ to_path("textfile.txt"), to_path("spaces.txt") ] 19 | expected = [ 20 | "TheFileName", 21 | " 14 -rw-r--r-- 1 jpace jpace 15615 2010-12-04 15:24 13-TheDoctorsTale.txt", 22 | "TheFileName", 23 | " 14 13 The Doctors Tale.txt", 24 | ] 25 | run_app_test expected, %w{ --label TheFileName The.*Doc }, *fnames 26 | end 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /test/glark/app/line_number_color_test.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby -w 2 | # -*- ruby -*- 3 | 4 | require 'glark/app/tc' 5 | 6 | module Glark 7 | class LineNumberColorTestCase < AppTestCase 8 | def test_none 9 | fname = to_path "textfile.txt" 10 | expected = [ 11 | " 9 -rw-r--r-- 1 jpace jpace 35994 2010-12-04 15:24 08-TheSompnoursTale.txt", 12 | " 12 -rw-r--r-- 1 jpace jpace 42282 2010-12-04 15:24 11-TheSquiresTale.txt", 13 | " 16 -rw-r--r-- 1 jpace jpace 25163 2010-12-04 15:24 15-TheShipmansTale.txt", 14 | " 22 -rw-r--r-- 1 jpace jpace 30734 2010-12-04 15:24 21-TheSecondNunsTale.txt", 15 | ] 16 | run_app_test expected, [ 'TheS.*Tale' ], fname 17 | end 18 | 19 | def test_single 20 | fname = to_path "textfile.txt" 21 | expected = [ 22 | " 9 -rw-r--r-- 1 jpace jpace 35994 2010-12-04 15:24 08-TheSompnoursTale.txt", 23 | " 12 -rw-r--r-- 1 jpace jpace 42282 2010-12-04 15:24 11-TheSquiresTale.txt", 24 | " 16 -rw-r--r-- 1 jpace jpace 25163 2010-12-04 15:24 15-TheShipmansTale.txt", 25 | " 22 -rw-r--r-- 1 jpace jpace 30734 2010-12-04 15:24 21-TheSecondNunsTale.txt", 26 | ] 27 | run_app_test expected, [ '--line-number-color', 'bold', 'TheS.*Tale' ], fname 28 | end 29 | 30 | def test_multi 31 | fname = to_path "textfile.txt" 32 | expected = [ 33 | # go Purdue! 34 | " 9 -rw-r--r-- 1 jpace jpace 35994 2010-12-04 15:24 08-TheSompnoursTale.txt", 35 | " 12 -rw-r--r-- 1 jpace jpace 42282 2010-12-04 15:24 11-TheSquiresTale.txt", 36 | " 16 -rw-r--r-- 1 jpace jpace 25163 2010-12-04 15:24 15-TheShipmansTale.txt", 37 | " 22 -rw-r--r-- 1 jpace jpace 30734 2010-12-04 15:24 21-TheSecondNunsTale.txt", 38 | ] 39 | run_app_test expected, [ '--line-number-color', 'bold yellow on black', 'TheS.*Tale' ], fname 40 | end 41 | end 42 | end 43 | -------------------------------------------------------------------------------- /test/glark/app/line_numbers_test.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby -w 2 | # -*- ruby -*- 3 | 4 | require 'glark/app/tc' 5 | 6 | module Glark 7 | class LineNumbersTestCase < AppTestCase 8 | def test_glark 9 | fname = to_path "textfile.txt" 10 | expected = [ 11 | " -rw-r--r-- 1 jpace jpace 35994 2010-12-04 15:24 08-TheSompnoursTale.txt", 12 | " -rw-r--r-- 1 jpace jpace 42282 2010-12-04 15:24 11-TheSquiresTale.txt", 13 | " -rw-r--r-- 1 jpace jpace 25163 2010-12-04 15:24 15-TheShipmansTale.txt", 14 | " -rw-r--r-- 1 jpace jpace 30734 2010-12-04 15:24 21-TheSecondNunsTale.txt", 15 | ] 16 | run_app_test expected, [ '-N', 'TheS\w+Tale' ], fname 17 | end 18 | 19 | def test_grep_without_numbers 20 | fname = to_path "textfile.txt" 21 | expected = [ 22 | " -rw-r--r-- 1 jpace jpace 35994 2010-12-04 15:24 08-TheSompnoursTale.txt", 23 | " -rw-r--r-- 1 jpace jpace 42282 2010-12-04 15:24 11-TheSquiresTale.txt", 24 | " -rw-r--r-- 1 jpace jpace 25163 2010-12-04 15:24 15-TheShipmansTale.txt", 25 | " -rw-r--r-- 1 jpace jpace 30734 2010-12-04 15:24 21-TheSecondNunsTale.txt", 26 | ] 27 | run_app_test expected, [ '-g', 'TheS\w+Tale' ], fname 28 | end 29 | 30 | def test_grep_with_numbers 31 | # grep defaults to no numbers 32 | fname = to_path "textfile.txt" 33 | expected = [ 34 | "9: -rw-r--r-- 1 jpace jpace 35994 2010-12-04 15:24 08-TheSompnoursTale.txt", 35 | "12: -rw-r--r-- 1 jpace jpace 42282 2010-12-04 15:24 11-TheSquiresTale.txt", 36 | "16: -rw-r--r-- 1 jpace jpace 25163 2010-12-04 15:24 15-TheShipmansTale.txt", 37 | "22: -rw-r--r-- 1 jpace jpace 30734 2010-12-04 15:24 21-TheSecondNunsTale.txt", 38 | ] 39 | run_app_test expected, [ '-g', '-n', 'TheS.*Tale' ], fname 40 | end 41 | end 42 | end 43 | -------------------------------------------------------------------------------- /test/glark/app/match_limit_test.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby -w 2 | # -*- ruby -*- 3 | 4 | require 'glark/app/tc' 5 | 6 | module Glark 7 | class MatchLimitTestCase < AppTestCase 8 | def test_one_file_limit_one 9 | fname = to_path "textfile.txt" 10 | expected = [ 11 | " 9 -rw-r--r-- 1 jpace jpace 35994 2010-12-04 15:24 08-TheSompnoursTale.txt", 12 | ] 13 | run_app_test expected, [ '-m', '1', 'TheS\w+Tale' ], fname 14 | end 15 | 16 | def test_one_file_limit_two 17 | fname = to_path "textfile.txt" 18 | expected = [ 19 | " 9 -rw-r--r-- 1 jpace jpace 35994 2010-12-04 15:24 08-TheSompnoursTale.txt", 20 | " 12 -rw-r--r-- 1 jpace jpace 42282 2010-12-04 15:24 11-TheSquiresTale.txt", 21 | ] 22 | run_app_test expected, [ '-m', '2', 'TheS\w+Tale' ], fname 23 | end 24 | 25 | def test_two_files_limit_one 26 | fnames = [ to_path("textfile.txt"), to_path("spaces.txt") ] 27 | expected = [ 28 | "" + RES_DIR + "/textfile.txt", 29 | " 9 -rw-r--r-- 1 jpace jpace 35994 2010-12-04 15:24 08-TheSompnoursTale.txt", 30 | "" + RES_DIR + "/spaces.txt", 31 | " 9 08 The Sompnours Tale.txt", 32 | ] 33 | run_app_test expected, [ '-m', '1', 'The.?S.*Tale' ], *fnames 34 | end 35 | 36 | def test_two_files_limit_two 37 | fnames = [ to_path("textfile.txt"), to_path("spaces.txt") ] 38 | expected = [ 39 | "" + RES_DIR + "/textfile.txt", 40 | " 9 -rw-r--r-- 1 jpace jpace 35994 2010-12-04 15:24 08-TheSompnoursTale.txt", 41 | " 12 -rw-r--r-- 1 jpace jpace 42282 2010-12-04 15:24 11-TheSquiresTale.txt", 42 | "" + RES_DIR + "/spaces.txt", 43 | " 9 08 The Sompnours Tale.txt", 44 | " 12 11 The Squires Tale.txt", 45 | ] 46 | run_app_test expected, [ '-m', '2', 'The.?S.*Tale' ], *fnames 47 | end 48 | end 49 | end 50 | -------------------------------------------------------------------------------- /test/glark/app/rcfile_test.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby -w 2 | # -*- ruby -*- 3 | 4 | require 'pathname' 5 | require 'tempfile' 6 | require 'glark/app/tc' 7 | require 'glark/app/options' 8 | 9 | module Glark 10 | class RcfileTestCase < AppTestCase 11 | def run_option_test args, exp, &blk 12 | gopt = Glark::AppOptions.new 13 | gopt.run args 14 | 15 | exp.each do |name, expval| 16 | val = gopt.method(name).call 17 | assert_equal expval, val 18 | end 19 | 20 | blk.call(gopt) if blk 21 | end 22 | 23 | def read_rcfile opts, basename 24 | opts.read_rcfile Pathname.new(RES_DIR) + basename 25 | end 26 | 27 | def test_simple 28 | run_option_test(%w{ foo }, []) do |opts| 29 | # default values 30 | assert_equal "multi", opts.colors.text_color_style 31 | assert_equal false, opts.local_config_files 32 | 33 | read_rcfile opts, 'rcfile.txt' 34 | 35 | assert_equal "single", opts.colors.text_color_style 36 | assert_equal true, opts.local_config_files 37 | ###$$$ assert_equal %w{ bold red }, opts.colors.line_number_highlight.colors 38 | assert opts.match_spec.ignorecase 39 | 40 | assert_file_filter_eq 1000, opts, :size, :negative, SizeLimitFilter, :max_size 41 | ###$$$ assert_equal %w{ underline magenta }, opts.match_spec.text_highlights[3].colors 42 | end 43 | end 44 | 45 | def test_grep 46 | run_option_test(%w{ foo }, []) do |opts| 47 | # default values 48 | assert_equal "glark", opts.output_options.style 49 | read_rcfile opts, 'rcgrep.txt' 50 | assert_equal "grep", opts.output_options.style 51 | end 52 | end 53 | 54 | def assert_has_filter_pattern exppat, filters, cls 55 | clsfilters = filters.select { |pf| pf.kind_of? cls } 56 | expre = Regexp.new exppat 57 | assert clsfilters.detect { |filter| filter.pattern == expre }, "exppat: #{exppat}; cls: #{cls}" 58 | end 59 | 60 | def assert_filters opts, filttype, posneg, cls, *patterns 61 | filtmeth = filttype.to_s + '_filters' 62 | spec = opts.input_options.send filtmeth.to_sym 63 | filters = spec.send posneg 64 | patterns.each do |pat| 65 | assert_has_filter_pattern pat, filters, cls 66 | end 67 | end 68 | 69 | def assert_file_filters opts, posneg, cls, *patterns 70 | assert_filters opts, :file, posneg, cls, *patterns 71 | end 72 | 73 | def assert_directory_filters opts, posneg, cls, *patterns 74 | assert_filters opts, :directory, posneg, cls, *patterns 75 | end 76 | 77 | def test_name 78 | run_option_test(%w{ foo }, []) do |opts| 79 | read_rcfile opts, 'rcmatch.txt' 80 | 81 | [ '\w+.java', '\w+.rb' ].each do |pat| 82 | assert_file_filter_pattern_eq pat, opts, :name, :positive, BaseNameFilter 83 | end 84 | 85 | assert_file_filter_pattern_eq 'zxcdjlk', opts, :name, :negative, BaseNameFilter 86 | end 87 | end 88 | 89 | def test_path 90 | run_option_test(%w{ foo }, []) do |opts| 91 | read_rcfile opts, 'rcpath.txt' 92 | 93 | assert_directory_filter_pattern_eq 'src/main/java', opts, :dirpath, :positive, FullNameFilter 94 | 95 | [ 'src/main/java', 'src/test/ruby' ].each do |pat| 96 | assert_directory_filter_pattern_eq pat, opts, :dirpath, :positive, FullNameFilter 97 | end 98 | 99 | assert_directory_filter_pattern_eq 'org/incava/util', opts, :dirpath, :negative, FullNameFilter 100 | end 101 | end 102 | 103 | def test_ext 104 | run_option_test(%w{ foo }, []) do |opts| 105 | read_rcfile opts, 'rcext.txt' 106 | 107 | assert_file_filter_pattern_eq 'rb', opts, :ext, :positive, ExtFilter 108 | assert_file_filter_pattern_eq 'pl', opts, :ext, :positive, ExtFilter 109 | assert_file_filter_pattern_eq 'txt', opts, :ext, :negative, ExtFilter 110 | end 111 | end 112 | end 113 | end 114 | -------------------------------------------------------------------------------- /test/glark/app/record_separator_test.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby -w 2 | # -*- ruby -*- 3 | 4 | require 'glark/app/tc' 5 | 6 | module Glark 7 | class RecordSeparatorTestCase < AppTestCase 8 | def test_default 9 | fname = to_path "04-TheCooksTale.txt" 10 | expected = [ 11 | " 2 For of thy parsley yet fare they the worse.", 12 | ] 13 | run_app_test expected, [ 'thy.*the' ], fname 14 | end 15 | 16 | def test_paragraph 17 | fname = to_path "04-TheCooksTale.txt" 18 | expected = [ 19 | " 1 Of many a pilgrim hast thou Christe's curse,", 20 | " 2 For of thy parsley yet fare they the worse.", 21 | " 3 ", 22 | " 4 That they have eaten in thy stubble goose:", 23 | " 5 For in thy shop doth many a fly go loose.", 24 | " 6 ", 25 | " 7 Now tell on, gentle Roger, by thy name,", 26 | " 8 But yet I pray thee be not wroth for game;", 27 | " 9 A man may say full sooth in game and play.", 28 | ] 29 | run_app_test expected, [ '-0', '--and=2', 'thy', 'the' ], fname 30 | end 31 | end 32 | end 33 | -------------------------------------------------------------------------------- /test/glark/app/regexp_test.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby -w 2 | # -*- ruby -*- 3 | 4 | require 'glark/app/tc' 5 | 6 | module Glark 7 | class RegexpTestCase < AppTestCase 8 | def test_regexp_no_context 9 | fname = to_path "textfile.txt" 10 | expected = [ 11 | " 2 -rw-r--r-- 1 jpace jpace 126084 2010-12-04 15:24 01-TheKnightsTale.txt", 12 | " 3 -rw-r--r-- 1 jpace jpace 45450 2010-12-04 15:24 02-TheMillersTale.txt", 13 | " 4 -rw-r--r-- 1 jpace jpace 29296 2010-12-04 15:24 03-TheReevesTale.txt", 14 | " 5 -rw-r--r-- 1 jpace jpace 6525 2010-12-04 15:24 04-TheCooksTale.txt", 15 | " 6 -rw-r--r-- 1 jpace jpace 63290 2010-12-04 15:24 05-TheManOfLawsTale.txt", 16 | " 7 -rw-r--r-- 1 jpace jpace 71054 2010-12-04 15:24 06-TheWifeOfBathsTale.txt", 17 | " 8 -rw-r--r-- 1 jpace jpace 22754 2010-12-04 15:24 07-TheFriarsTale.txt", 18 | " 9 -rw-r--r-- 1 jpace jpace 35994 2010-12-04 15:24 08-TheSompnoursTale.txt", 19 | " 10 -rw-r--r-- 1 jpace jpace 64791 2010-12-04 15:24 09-TheClerksTale.txt", 20 | " 11 -rw-r--r-- 1 jpace jpace 65852 2010-12-04 15:24 10-TheMerchantsTale.txt", 21 | " 12 -rw-r--r-- 1 jpace jpace 42282 2010-12-04 15:24 11-TheSquiresTale.txt", 22 | " 13 -rw-r--r-- 1 jpace jpace 51996 2010-12-04 15:24 12-TheFranklinsTale.txt", 23 | " 14 -rw-r--r-- 1 jpace jpace 15615 2010-12-04 15:24 13-TheDoctorsTale.txt", 24 | " 15 -rw-r--r-- 1 jpace jpace 39546 2010-12-04 15:24 14-ThePardonersTale.txt", 25 | " 16 -rw-r--r-- 1 jpace jpace 25163 2010-12-04 15:24 15-TheShipmansTale.txt", 26 | " 17 -rw-r--r-- 1 jpace jpace 14979 2010-12-04 15:24 16-ThePrioresssTale.txt", 27 | " 20 -rw-r--r-- 1 jpace jpace 49747 2010-12-04 15:24 19-TheMonksTale.txt", 28 | " 21 -rw-r--r-- 1 jpace jpace 45326 2010-12-04 15:24 20-TheNunsPriestsTale.txt", 29 | " 22 -rw-r--r-- 1 jpace jpace 30734 2010-12-04 15:24 21-TheSecondNunsTale.txt", 30 | " 23 -rw-r--r-- 1 jpace jpace 52953 2010-12-04 15:24 22-TheCanonsYeomansTale.txt", 31 | " 24 -rw-r--r-- 1 jpace jpace 21141 2010-12-04 15:24 23-TheManciplesTale.txt", 32 | " 25 -rw-r--r-- 1 jpace jpace 58300 2010-12-04 15:24 24-TheParsonsTale.txt", 33 | ] 34 | run_app_test expected, [ 'The\w+Tale' ], fname 35 | end 36 | 37 | def test_one_line_grep 38 | fname = to_path "textfile.txt" 39 | expected = [ 40 | " -rw-r--r-- 1 jpace jpace 35994 2010-12-04 15:24 08-TheSompnoursTale.txt", 41 | " -rw-r--r-- 1 jpace jpace 42282 2010-12-04 15:24 11-TheSquiresTale.txt", 42 | " -rw-r--r-- 1 jpace jpace 25163 2010-12-04 15:24 15-TheShipmansTale.txt", 43 | " -rw-r--r-- 1 jpace jpace 30734 2010-12-04 15:24 21-TheSecondNunsTale.txt", 44 | ] 45 | run_app_test expected, [ '-g', 'TheS.*Tale' ], fname 46 | end 47 | end 48 | end 49 | -------------------------------------------------------------------------------- /test/glark/app/stdin_test.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby -w 2 | # -*- ruby -*- 3 | 4 | require 'glark/app/tc' 5 | 6 | module Glark 7 | class StdInTestCase < AppTestCase 8 | def run_stdin_test expected, args 9 | file = to_path "textfile.txt" 10 | 11 | origstdin = $stdin 12 | 13 | inio = StringIO.new(::IO.readlines(file).join('')) 14 | 15 | gopt = AppOptions.new 16 | $stdin = inio 17 | 18 | outio = StringIO.new 19 | gopt.run(args) 20 | gopt.output_options.out = outio 21 | 22 | Runner.new gopt, gopt.fileset 23 | 24 | # inio.close 25 | outio.close 26 | 27 | $stdin = origstdin 28 | 29 | if false 30 | puts ",,,,," 31 | puts outio.string 32 | puts ",,,,," 33 | end 34 | 35 | result = outio.string 36 | 37 | actual = result.split "\n" 38 | ( 0 ... [ expected.length, actual.length ].max ).each do |idx| 39 | assert_equal expected[idx], actual[idx], "idx: #{idx}" 40 | end 41 | end 42 | 43 | def test_like_grep 44 | expected = [ 45 | " -rw-r--r-- 1 jpace jpace 45450 2010-12-04 15:24 02-TheMillersTale.txt", 46 | " -rw-r--r-- 1 jpace jpace 63290 2010-12-04 15:24 05-TheManOfLawsTale.txt", 47 | " -rw-r--r-- 1 jpace jpace 65852 2010-12-04 15:24 10-TheMerchantsTale.txt", 48 | " -rw-r--r-- 1 jpace jpace 49747 2010-12-04 15:24 19-TheMonksTale.txt", 49 | " -rw-r--r-- 1 jpace jpace 21141 2010-12-04 15:24 23-TheManciplesTale.txt", 50 | ] 51 | run_stdin_test expected, [ '-g', 'M.*Tale' ] 52 | end 53 | 54 | def test_like_glark 55 | expected = [ 56 | " 3 -rw-r--r-- 1 jpace jpace 45450 2010-12-04 15:24 02-TheMillersTale.txt", 57 | " 6 -rw-r--r-- 1 jpace jpace 63290 2010-12-04 15:24 05-TheManOfLawsTale.txt", 58 | " 11 -rw-r--r-- 1 jpace jpace 65852 2010-12-04 15:24 10-TheMerchantsTale.txt", 59 | " 20 -rw-r--r-- 1 jpace jpace 49747 2010-12-04 15:24 19-TheMonksTale.txt", 60 | " 24 -rw-r--r-- 1 jpace jpace 21141 2010-12-04 15:24 23-TheManciplesTale.txt", 61 | ] 62 | run_stdin_test expected, [ 'M.*Tale' ] 63 | end 64 | end 65 | end 66 | -------------------------------------------------------------------------------- /test/glark/app/tc.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby -w 2 | # -*- ruby -*- 3 | 4 | require 'pathname' 5 | require 'tempfile' 6 | require 'stringio' 7 | require 'glark/tc' 8 | require 'glark/app/options' 9 | require 'glark/util/timestamper' 10 | 11 | module Glark 12 | class AppTestCase < Glark::TestCase 13 | include TimeStamper 14 | 15 | def setup 16 | # ignore what they have in ENV[HOME] 17 | ENV['HOME'] = '/this/should/not/exist' 18 | super 19 | end 20 | 21 | def teardown 22 | super 23 | end 24 | 25 | def run_glark args, *files 26 | gopt = AppOptions.new 27 | sio = StringIO.new 28 | gopt.run(args + files) 29 | gopt.output_options.out = sio 30 | 31 | Runner.new gopt, gopt.fileset 32 | 33 | sio.close 34 | 35 | if false 36 | puts "....." 37 | puts sio.string 38 | puts "....." 39 | end 40 | 41 | sio.string 42 | end 43 | 44 | def run_app_test expected, args, *files 45 | result = run_glark args, *files 46 | actual = result.split "\n" 47 | ( 0 ... [ expected.length, actual.length ].max ).each do |idx| 48 | assert_equal expected[idx], actual[idx], "idx: #{idx}" 49 | end 50 | end 51 | 52 | def run_app_test_exact_output expected, args, *files 53 | result = run_glark args, *files 54 | assert_equal expected, result 55 | end 56 | 57 | def assert_file_filter_pattern_eq exppat, opts, field, posneg, cls 58 | expre = Regexp.new exppat 59 | assert_file_filter_eq expre, opts, field, posneg, cls, :pattern 60 | end 61 | 62 | def assert_file_filter_eq expval, opts, field, posneg, cls, matchfield 63 | criteria = opts.input_spec.file_criteria 64 | assert_filter_eq expval, criteria, field, posneg, cls, matchfield 65 | end 66 | 67 | def assert_directory_filter_pattern_eq exppat, opts, field, posneg, cls 68 | expre = Regexp.new exppat 69 | assert_directory_filter_eq expre, opts, field, posneg, cls, :pattern 70 | end 71 | 72 | def assert_directory_filter_eq expval, opts, field, posneg, cls, matchfield 73 | criteria = opts.input_spec.dir_criteria 74 | assert_filter_eq expval, criteria, field, posneg, cls, matchfield 75 | end 76 | 77 | def assert_filter_eq expval, criteria, field, posneg, cls, matchfield 78 | pncrit = criteria.get field, posneg 79 | pncrit.each do |crit| 80 | matchval = crit.send matchfield 81 | if expval == matchval 82 | assert true 83 | return 84 | end 85 | end 86 | 87 | assert false, "no match: #{matchfield}; #{expval}" 88 | end 89 | end 90 | end 91 | -------------------------------------------------------------------------------- /test/glark/app/text_color_test.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby -w 2 | # -*- ruby -*- 3 | 4 | require 'glark/app/tc' 5 | require 'glark/resources' 6 | 7 | module Glark 8 | class TextColorTestCase < AppTestCase 9 | include Glark::Resources 10 | 11 | def initialize name 12 | @fname = to_path'textfile.txt' 13 | super 14 | end 15 | 16 | def test_single 17 | expected = [ 18 | " 9 -rw-r--r-- 1 jpace jpace 35994 2010-12-04 15:24 08-TheSompnoursTale.txt", 19 | " 12 -rw-r--r-- 1 jpace jpace 42282 2010-12-04 15:24 11-TheSquiresTale.txt", 20 | " 16 -rw-r--r-- 1 jpace jpace 25163 2010-12-04 15:24 15-TheShipmansTale.txt", 21 | " 22 -rw-r--r-- 1 jpace jpace 30734 2010-12-04 15:24 21-TheSecondNunsTale.txt", 22 | ] 23 | run_app_test expected, [ '--text-color', 'bold', 'TheS.*Tale' ], @fname 24 | end 25 | 26 | def test_multi 27 | expected = [ 28 | # go IU! 29 | " 9 -rw-r--r-- 1 jpace jpace 35994 2010-12-04 15:24 08-TheSompnoursTale.txt", 30 | " 12 -rw-r--r-- 1 jpace jpace 42282 2010-12-04 15:24 11-TheSquiresTale.txt", 31 | " 16 -rw-r--r-- 1 jpace jpace 25163 2010-12-04 15:24 15-TheShipmansTale.txt", 32 | " 22 -rw-r--r-- 1 jpace jpace 30734 2010-12-04 15:24 21-TheSecondNunsTale.txt", 33 | ] 34 | run_app_test expected, [ '--text-color', 'underline red on white', 'TheS.*Tale' ], @fname 35 | end 36 | end 37 | end 38 | -------------------------------------------------------------------------------- /test/glark/app/whole_lines_test.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby -w 2 | # -*- ruby -*- 3 | 4 | require 'glark/app/tc' 5 | require 'glark/resources' 6 | 7 | module Glark 8 | class WholeLinesTestCase < AppTestCase 9 | include Glark::Resources 10 | 11 | def test_match 12 | fname = to_path "filelist.txt" 13 | expected = [ 14 | " 12 11-The_Squires_Tale.txt", 15 | " 16 15-The_Shipmans_Tale.txt", 16 | ] 17 | run_app_test expected, [ '--line-regexp', '1.*The_S\w+.txt' ], fname 18 | end 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /test/glark/app/whole_words_test.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby -w 2 | # -*- ruby -*- 3 | 4 | require 'glark/app/tc' 5 | 6 | module Glark 7 | class WholeWordsTestCase < AppTestCase 8 | def test_no 9 | fname = to_path "spaces.txt" 10 | expected = [ 11 | " 6 05 The Man Of Laws Tale.txt", 12 | " 7 06 The Wife Of Baths Tale.txt", 13 | " 8 07 The Friars Tale.txt", 14 | " 11 10 The Merchants Tale.txt", 15 | " 13 12 The Franklins Tale.txt", 16 | " 15 14 The Pardoners Tale.txt", 17 | " 16 15 The Shipmans Tale.txt", 18 | " 18 17 Chaucers Tale Of Sir Thopas.txt", 19 | " 19 18 Chaucers Tale Of Meliboeus.txt", 20 | " 23 22 The Canons Yeomans Tale.txt", 21 | " 24 23 The Manciples Tale.txt", 22 | " 25 24 The Parsons Tale.txt", 23 | " 26 25 Preces De Chauceres.txt", 24 | ] 25 | run_app_test expected, [ '\wa\w+s' ], fname 26 | end 27 | 28 | def test_yes 29 | fname = to_path "spaces.txt" 30 | expected = [ 31 | " 6 05 The Man Of Laws Tale.txt", 32 | " 7 06 The Wife Of Baths Tale.txt", 33 | " 15 14 The Pardoners Tale.txt", 34 | " 23 22 The Canons Yeomans Tale.txt", 35 | " 24 23 The Manciples Tale.txt", 36 | " 25 24 The Parsons Tale.txt", 37 | ] 38 | run_app_test expected, [ '-w', '\wa\w+s' ], fname 39 | end 40 | end 41 | end 42 | 43 | -------------------------------------------------------------------------------- /test/glark/app/xor_test.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby -w 2 | # -*- ruby -*- 3 | 4 | require 'glark/app/tc' 5 | require 'glark/resources' 6 | 7 | module Glark 8 | class ExclusiveOrTestCase < AppTestCase 9 | include Glark::Resources 10 | 11 | def test_simple 12 | fname = to_path "textfile.txt" 13 | expected = [ 14 | " 3 -rw-r--r-- 1 jpace jpace 45450 2010-12-04 15:24 02-TheMillersTale.txt", 15 | " 10 -rw-r--r-- 1 jpace jpace 64791 2010-12-04 15:24 09-TheClerksTale.txt", 16 | " 20 -rw-r--r-- 1 jpace jpace 49747 2010-12-04 15:24 19-TheMonksTale.txt", 17 | " 24 -rw-r--r-- 1 jpace jpace 21141 2010-12-04 15:24 23-TheManciplesTale.txt", 18 | ] 19 | run_app_test expected, [ '--xor', '\b6\d{4}\b', 'TheM.*Tale' ], fname 20 | end 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /test/glark/input/dirname_test.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby -w 2 | # -*- ruby -*- 3 | 4 | require 'glark/app/tc' 5 | require 'glark/resources' 6 | 7 | module Glark 8 | class DirNameTestCase < AppTestCase 9 | include Glark::Resources 10 | 11 | def test_skip_svn 12 | expected = [ 13 | "" + RES_DIR + "/canterbury/franklin/tale.txt", 14 | " 10 That well unnethes durst this knight for dread,", 15 | " 149 Why have ye wrought this work unreasonable?", 16 | " 366 Let I this woeful creature lie;", 17 | ] 18 | run_app_test expected, [ '--directories=recurse', 'this.*rea' ], RES_DIR 19 | end 20 | 21 | def test_match_basename 22 | dirnames = [ RES_DIR + "/canterbury", TEST_DIR + "/glark" ] 23 | expected = [ 24 | "" + RES_DIR + "/canterbury/prologue.txt", 25 | " 187 He gave not of the text a pulled hen,", 26 | " 192 This ilke text held he not worth an oyster;", 27 | " 291 Betwixte Middleburg and Orewell", 28 | ] 29 | run_app_test expected, [ '-r', '--match-dirname=canterbury', 'xt.*e' ], *dirnames 30 | end 31 | 32 | def test_not_basename 33 | dirnames = [ TEST_DIR ] 34 | expected = [ 35 | "" + RES_DIR + "/canterbury/franklin/tale.txt", 36 | " 80 That is betwixt a husband and his wife?", 37 | "" + RES_DIR + "/canterbury/prologue.txt", 38 | " 187 He gave not of the text a pulled hen,", 39 | " 192 This ilke text held he not worth an oyster;", 40 | " 291 Betwixte Middleburg and Orewell", 41 | "" + RES_DIR + "/rcfile.txt", 42 | " 10 text-color-3: underline magenta", 43 | ] 44 | run_app_test expected, [ '-r', '--skip-dirname=glark', 'xt.*e' ], *dirnames 45 | end 46 | 47 | def test_match_pathname 48 | dirnames = [ TEST_DIR + "/glark", RES_DIR ] 49 | puts "dirnames: #{dirnames}" 50 | expected = [ 51 | "" + RES_DIR + "/rcfile.txt", 52 | " 10 text-color-3: underline magenta", 53 | ] 54 | run_app_test expected, [ '-r', '--match-dirpath', '^.*es$', 'xt.*e' ], *dirnames 55 | end 56 | 57 | def test_not_pathname 58 | dirnames = [ TEST_DIR + 'glark', RES_DIR ] 59 | expected = [ 60 | "" + RES_DIR + "/canterbury/franklin/tale.txt", 61 | " 80 That is betwixt a husband and his wife?", 62 | "" + RES_DIR + "/canterbury/prologue.txt", 63 | " 187 He gave not of the text a pulled hen,", 64 | " 192 This ilke text held he not worth an oyster;", 65 | " 291 Betwixte Middleburg and Orewell", 66 | "" + RES_DIR + "/rcfile.txt", 67 | " 10 text-color-3: underline magenta", 68 | ] 69 | run_app_test expected, [ '-r', '--skip-dirpath', 'test/glark', 'xt.*e' ], *dirnames 70 | end 71 | end 72 | end 73 | -------------------------------------------------------------------------------- /test/glark/input/exclude_matching_test.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby -w 2 | # -*- ruby -*- 3 | 4 | require 'glark/app/tc' 5 | require 'glark/resources' 6 | 7 | module Glark 8 | class ExcludeMatchingTestCase < AppTestCase 9 | include Glark::Resources 10 | 11 | def test_simple 12 | expected = [ 13 | "" + RES_DIR + "/canterbury/prologue.txt", 14 | " 187 He gave not of the text a pulled hen,", 15 | " 192 This ilke text held he not worth an oyster;", 16 | "" + RES_DIR + "/rcfile.txt", 17 | " 10 text-color-3: underline magenta", 18 | ] 19 | run_app_test expected, [ '-r', '--exclude-matching', 'text' ], RES_DIR 20 | end 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /test/glark/input/ext_test.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby -w 2 | # -*- ruby -*- 3 | 4 | require 'glark/app/tc' 5 | require 'glark/resources' 6 | 7 | module Glark 8 | class ExtTestCase < AppTestCase 9 | include Glark::Resources 10 | 11 | def test_match_single 12 | expected = [ 13 | "" + RES_DIR + "/add.rb", 14 | " 5 def initialize x, y", 15 | "" + RES_DIR + "/greet.rb", 16 | " 5 def initialize name", 17 | " 6 puts \"hello, \" + name", 18 | " 10 Greet.new ARGV.shift || \"world\"", 19 | ] 20 | run_app_test expected, [ '-r', '--match-ext', 'rb', 't.*e' ], RES_DIR 21 | end 22 | 23 | def test_not_single 24 | expected = [ 25 | "" + RES_DIR + "/canterbury/franklin/prologue.txt", 26 | " 60 Have me excused of my rude speech.", 27 | "" + RES_DIR + "/canterbury/franklin/tale.txt", 28 | " 184 And this was on the sixth morrow of May,", 29 | " 560 Neither his collect, nor his expanse years,", 30 | " 706 Why should I more examples hereof sayn?", 31 | " 813 Than to depart the love betwixt you two.", 32 | "" + RES_DIR + "/canterbury/prologue.txt", 33 | " 192 This ilke text held he not worth an oyster;", 34 | ] 35 | run_app_test expected, [ '-r', '--skip-ext', 'rb', 'x.*y' ], RES_DIR 36 | end 37 | 38 | def test_match_multiple 39 | expected = [ 40 | "" + RES_DIR + "/add.rb", 41 | " 5 def initialize x, y", 42 | " 6 puts x.to_s + \" + \" + y.to_s + \" = \" + (x.to_i + y.to_i).to_s", 43 | "" + RES_DIR + "/canterbury/franklin/prologue.txt", 44 | " 60 Have me excused of my rude speech.", 45 | "" + RES_DIR + "/canterbury/franklin/tale.txt", 46 | " 184 And this was on the sixth morrow of May,", 47 | " 560 Neither his collect, nor his expanse years,", 48 | " 706 Why should I more examples hereof sayn?", 49 | " 813 Than to depart the love betwixt you two.", 50 | "" + RES_DIR + "/canterbury/prologue.txt", 51 | " 192 This ilke text held he not worth an oyster;", 52 | ] 53 | run_app_test expected, [ '-r', '--match-ext', 'rb', '--match-ext', 'txt', 'x.*y' ], RES_DIR 54 | end 55 | 56 | def test_not_multiple 57 | expected = [ 58 | "" + RES_DIR + "/cat.pl", 59 | " 6 print <>;", 60 | ] 61 | run_app_test expected, [ '-r', '--skip-ext', 'rb', '--not-ext', 'txt', 'p.*t' ], RES_DIR 62 | end 63 | end 64 | end 65 | -------------------------------------------------------------------------------- /test/glark/input/filter/criteria_test.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby -w 2 | # -*- ruby -*- 3 | 4 | require 'glark/app/tc' 5 | require 'glark/util/io/filter/criteria' 6 | require 'glark/input/filter/filter' 7 | 8 | module Glark 9 | class CriteriaTestCase < AppTestCase 10 | def test_positive_one_match 11 | crit = Criteria.new 12 | crit.add :name, :positive, BaseNameFilter.new('foo.txt') 13 | 14 | assert crit.match?(Pathname.new '/path/to/foo.txt') 15 | end 16 | 17 | def test_positive_one_nomatch 18 | crit = Criteria.new 19 | crit.add :name, :positive, BaseNameFilter.new('foo.txt') 20 | 21 | assert !crit.match?(Pathname.new '/path/to/bar.txt') 22 | end 23 | 24 | def test_negative_one_match 25 | crit = Criteria.new 26 | crit.add :name, :negative, BaseNameFilter.new('foo.txt') 27 | 28 | assert !crit.match?(Pathname.new '/path/to/foo.txt') 29 | end 30 | 31 | def test_negative_one_nomatch 32 | crit = Criteria.new 33 | crit.add :name, :negative, BaseNameFilter.new('foo.txt') 34 | 35 | assert crit.match?(Pathname.new '/path/to/bar.txt') 36 | end 37 | 38 | def test_positive_two_match 39 | crit = Criteria.new 40 | crit.add :name, :positive, BaseNameFilter.new(%r{foo.*}) 41 | crit.add :ext, :positive, ExtFilter.new('txt') 42 | 43 | assert crit.match?(Pathname.new '/path/to/foo.txt') 44 | end 45 | 46 | def test_positive_two_nomatch 47 | crit = Criteria.new 48 | crit.add :name, :positive, BaseNameFilter.new(%r{foo.*}) 49 | crit.add :ext, :positive, ExtFilter.new('rb') 50 | 51 | assert crit.match?(Pathname.new '/path/to/foo.rb') 52 | end 53 | 54 | def test_positive_negative_match 55 | crit = Criteria.new 56 | crit.add :name, :positive, BaseNameFilter.new(%r{foo.*}) 57 | crit.add :ext, :negative, ExtFilter.new('txt') 58 | 59 | assert crit.match?(Pathname.new '/path/to/foo.rb') 60 | end 61 | 62 | def test_positive_negative_nomatch 63 | crit = Criteria.new 64 | crit.add :name, :positive, BaseNameFilter.new(%r{foo.*}) 65 | crit.add :ext, :negative, ExtFilter.new('rb') 66 | 67 | assert !crit.match?(Pathname.new '/path/to/foo.rb') 68 | end 69 | 70 | def test_find_by_class 71 | fl = Criteria.new 72 | bnf = BaseNameFilter.new '.svn' 73 | fl.add :name, :negative, bnf 74 | assert_equal bnf.object_id, fl.find_by_class(:name, :negative, BaseNameFilter).object_id 75 | end 76 | 77 | def test_add 78 | fl = Criteria.new 79 | svnbnf = BaseNameFilter.new '.svn' 80 | fl.add :name, :negative, svnbnf 81 | bldbnf = BaseNameFilter.new 'build' 82 | fl.add :name, :negative, bldbnf 83 | 84 | slf = SizeLimitFilter.new 1000 85 | fl.add :size, :negative, slf 86 | 87 | extf = ExtFilter.new 'rb' 88 | fl.add :ext, :positive, extf 89 | end 90 | end 91 | end 92 | -------------------------------------------------------------------------------- /test/glark/input/filter/filter_test.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby -w 2 | # -*- ruby -*- 3 | 4 | require 'glark/tc' 5 | 6 | module Glark 7 | class BaseNameFilterTest < Glark::TestCase 8 | def run_bnf_test expmatch, pattern, fname 9 | bnf = BaseNameFilter.new pattern 10 | assert_equal expmatch, bnf.match?(Pathname.new fname), "fname: #{fname}" 11 | end 12 | 13 | def test_match_string_to_string 14 | run_bnf_test true, '.svn', '.svn' 15 | end 16 | 17 | def test_no_match_string_with_substring 18 | run_bnf_test false, '.svn', '.' 19 | end 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /test/glark/input/name_test.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby -w 2 | # -*- ruby -*- 3 | 4 | require 'glark/app/tc' 5 | require 'glark/resources' 6 | 7 | module Glark 8 | class NameTestCase < AppTestCase 9 | include Glark::Resources 10 | 11 | def test_match_single 12 | expected = [ 13 | "" + RES_DIR + "/rcfile.txt", 14 | " 1 # comment here", 15 | " 2 highlight: single", 16 | " 4 local-config-files: true", 17 | " 7 ignore-case: true", 18 | " 10 text-color-3: underline magenta", 19 | "" + RES_DIR + "/textfile.txt", 20 | " 2 -rw-r--r-- 1 jpace jpace 126084 2010-12-04 15:24 01-TheKnightsTale.txt", 21 | " 7 -rw-r--r-- 1 jpace jpace 71054 2010-12-04 15:24 06-TheWifeOfBathsTale.txt", 22 | " 11 -rw-r--r-- 1 jpace jpace 65852 2010-12-04 15:24 10-TheMerchantsTale.txt", 23 | " 14 -rw-r--r-- 1 jpace jpace 15615 2010-12-04 15:24 13-TheDoctorsTale.txt", 24 | " 21 -rw-r--r-- 1 jpace jpace 45326 2010-12-04 15:24 20-TheNunsPriestsTale.txt", 25 | ] 26 | run_app_test expected, [ '-r', '--match-name', '^\w+ile.txt$', 't.*e' ], RES_DIR 27 | end 28 | 29 | def test_not_single 30 | expected = [ 31 | "" + RES_DIR + "/04-TheCooksTale.txt", 32 | " 1 Of many a pilgrim hast thou Christe's curse,", 33 | " 7 Now tell on, gentle Roger, by thy name,", 34 | "" + RES_DIR + "/filelist.txt", 35 | " 2 01-The_Knights_Tale.txt", 36 | "" + RES_DIR + "/rcgrep.txt", 37 | " 1 grep: true", 38 | "" + RES_DIR + "/spaces.txt", 39 | " 2 01 The Knights Tale.txt", 40 | ] 41 | run_app_test expected, [ '-r', '--skip-name', '^\w+e.txt$', 'g.*t.*e\b' ], RES_DIR 42 | end 43 | 44 | def test_match_multiple 45 | expected = [ 46 | "" + RES_DIR + "/filelist.txt", 47 | " 7 06-The_Wife_Of_Baths_Tale.txt", 48 | "" + RES_DIR + "/rcext.txt", 49 | " 1 match-ext: rb", 50 | " 2 match-ext: pl", 51 | "" + RES_DIR + "/rcmatch.txt", 52 | " 1 match-name: \\w+.java", 53 | " 2 match-name: \\w+.rb", 54 | "" + RES_DIR + "/rcpath.txt", 55 | " 2 match-dirpath: src/test/ruby", 56 | "" + RES_DIR + "/spaces.txt", 57 | " 7 06 The Wife Of Baths Tale.txt", 58 | ] 59 | run_app_test expected, [ '-r', '--match-name', '^\w+[^e].txt$', '--match-name', 'rcgrep.txt', 't.*h.*e' ], RES_DIR 60 | end 61 | 62 | def test_not_multiple 63 | expected = [ 64 | "" + RES_DIR + "/filelist.txt", 65 | " 2 01-The_Knights_Tale.txt", 66 | "" + RES_DIR + "/rcgrep.txt", 67 | " 1 grep: true", 68 | "" + RES_DIR + "/spaces.txt", 69 | " 2 01 The Knights Tale.txt", 70 | ] 71 | run_app_test expected, [ '-r', '--skip-name', '^\w+e.txt$', '--skip-name', '04.*', 'g.*t.*e\b' ], RES_DIR 72 | end 73 | end 74 | end 75 | -------------------------------------------------------------------------------- /test/glark/input/path_test.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby -w 2 | # -*- ruby -*- 3 | 4 | require 'glark/app/tc' 5 | 6 | module Glark 7 | class PathTestCase < AppTestCase 8 | def test_match_single 9 | expected = [ 10 | "" + RES_DIR + "/rcfile.txt", 11 | " 1 # comment here", 12 | " 2 highlight: single", 13 | " 4 local-config-files: true", 14 | " 7 ignore-case: true", 15 | " 10 text-color-3: underline magenta", 16 | "" + RES_DIR + "/textfile.txt", 17 | " 2 -rw-r--r-- 1 jpace jpace 126084 2010-12-04 15:24 01-TheKnightsTale.txt", 18 | " 7 -rw-r--r-- 1 jpace jpace 71054 2010-12-04 15:24 06-TheWifeOfBathsTale.txt", 19 | " 11 -rw-r--r-- 1 jpace jpace 65852 2010-12-04 15:24 10-TheMerchantsTale.txt", 20 | " 14 -rw-r--r-- 1 jpace jpace 15615 2010-12-04 15:24 13-TheDoctorsTale.txt", 21 | " 21 -rw-r--r-- 1 jpace jpace 45326 2010-12-04 15:24 20-TheNunsPriestsTale.txt", 22 | ] 23 | run_app_test expected, [ '-r', '--match-path', 'test/resources/.*ile.txt$', 't.*e' ], RES_DIR 24 | end 25 | 26 | def test_not_single 27 | expected = [ 28 | "" + RES_DIR + "/filelist.txt", 29 | " 2 01-The_Knights_Tale.txt", 30 | "" + RES_DIR + "/rcgrep.txt", 31 | " 1 grep: true", 32 | "" + RES_DIR + "/spaces.txt", 33 | " 2 01 The Knights Tale.txt", 34 | ] 35 | run_app_test expected, [ '-r', '--skip-path', 'test/resources/.*e.txt$', 'g.*t.*e\b' ], RES_DIR 36 | end 37 | 38 | def test_match_multiple 39 | expected = [ 40 | "" + RES_DIR + "/canterbury/franklin/tale.txt", 41 | " 80 That is betwixt a husband and his wife?", 42 | "" + RES_DIR + "/canterbury/prologue.txt", 43 | " 187 He gave not of the text a pulled hen,", 44 | " 192 This ilke text held he not worth an oyster;", 45 | " 291 Betwixte Middleburg and Orewell", 46 | "" + RES_DIR + "/rcfile.txt", 47 | " 10 text-color-3: underline magenta", 48 | ] 49 | run_app_test expected, [ '-r', '--match-path', 'test/resources/.*ile.txt$', '--match-path', 'test/resources/canterbury/.*.txt$', 'xt.*e' ], RES_DIR 50 | end 51 | 52 | def test_not_multiple 53 | expected = [ 54 | "" + RES_DIR + "/filelist.txt", 55 | " 2 01-The_Knights_Tale.txt", 56 | " 11 10-The_Merchants_Tale.txt", 57 | " 21 20-The_Nuns_Priests_Tale.txt", 58 | "" + RES_DIR + "/rcfile.txt", 59 | " 2 highlight: single", 60 | "" + RES_DIR + "/textfile.txt", 61 | " 2 -rw-r--r-- 1 jpace jpace 126084 2010-12-04 15:24 01-TheKnightsTale.txt", 62 | " 11 -rw-r--r-- 1 jpace jpace 65852 2010-12-04 15:24 10-TheMerchantsTale.txt", 63 | " 21 -rw-r--r-- 1 jpace jpace 45326 2010-12-04 15:24 20-TheNunsPriestsTale.txt", 64 | ] 65 | run_app_test expected, [ '-r', '--skip-path', 'test/resources/\d.*e.txt$', '--skip-path', 'test/resources/canterbury/.*.txt$', 't\W*s\w*e' ], RES_DIR 66 | end 67 | end 68 | end 69 | -------------------------------------------------------------------------------- /test/glark/input/range_test.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby -w 2 | # -*- ruby -*- 3 | 4 | require 'glark/tc' 5 | require 'glark/input/range' 6 | 7 | module Glark 8 | class RangeTestCase < Glark::TestCase 9 | def test_ctor 10 | rg = Glark::Range.new '3', '17' 11 | assert_equal '3', rg.from 12 | assert_equal '17', rg.to 13 | end 14 | 15 | def test_valid_neither 16 | rg = Glark::Range.new 17 | assert rg.validate! 18 | end 19 | 20 | def test_valid_only_from 21 | rg = Glark::Range.new '3' 22 | assert rg.validate! 23 | end 24 | 25 | def test_valid_only_to 26 | rg = Glark::Range.new nil, '17' 27 | assert rg.validate! 28 | end 29 | 30 | def test_valid_from_number_to_number 31 | rg = Glark::Range.new '3', '17' 32 | assert rg.validate! 33 | end 34 | 35 | def test_valid_from_number_to_pct 36 | rg = Glark::Range.new '3', '17%' 37 | assert rg.validate! 38 | end 39 | 40 | def test_valid_from_pct_to_pct 41 | rg = Glark::Range.new '3%', '17%' 42 | assert rg.validate! 43 | end 44 | 45 | def test_valid_from_pct_to_number 46 | rg = Glark::Range.new '3%', '17' 47 | assert rg.validate! 48 | end 49 | 50 | def test_invalid_from_pct_to_pct 51 | rg = Glark::Range.new '13%', '3%' 52 | assert_raises(Glark::RangeError) do 53 | rg.validate! 54 | end 55 | end 56 | 57 | def test_invalid_from_number_to_number 58 | rg = Glark::Range.new '13', '3' 59 | assert_raises(Glark::RangeError) do 60 | rg.validate! 61 | end 62 | end 63 | 64 | def test_eq_from_to 65 | x = Glark::Range.new '5', '17' 66 | y = Glark::Range.new '5', '17' 67 | assert_equal y, x 68 | end 69 | 70 | def test_eq_nil_to 71 | x = Glark::Range.new nil, '5' 72 | y = Glark::Range.new nil, '5' 73 | assert_equal y, x 74 | end 75 | 76 | def test_eq_from_nil 77 | x = Glark::Range.new '5', nil 78 | y = Glark::Range.new '5', nil 79 | assert_equal y, x 80 | end 81 | end 82 | end 83 | -------------------------------------------------------------------------------- /test/glark/input/size_limit_test.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby -w 2 | # -*- ruby -*- 3 | 4 | require 'glark/app/tc' 5 | require 'glark/resources' 6 | 7 | module Glark 8 | class SizeLimitTestCase < AppTestCase 9 | include Glark::Resources 10 | 11 | def test_limit_300 12 | expected = [ 13 | "" + RES_DIR + "/add.rb", 14 | " 4 class Adder", 15 | " 5 def initialize x, y", 16 | "" + RES_DIR + "/expressions.txt", 17 | " 2 TheM.*Tale", 18 | "" + RES_DIR + "/greet.rb", 19 | " 4 class Greet", 20 | " 5 def initialize name", 21 | " 6 puts \"hello, \" + name", 22 | "" + RES_DIR + "/rcfile.txt", 23 | " 2 highlight: single", 24 | " 4 local-config-files: true", 25 | " 6 line-number-color: bold red", 26 | " 10 text-color-3: underline magenta", 27 | "" + RES_DIR + "/zfile.txt", 28 | " 6 zonulae", 29 | " 13 zoogloeae", 30 | " 14 zoogloeal", 31 | " 15 zoogloeas", 32 | ] 33 | run_app_test expected, [ '-r', '--size-limit', '300', 'l.*e' ], RES_DIR 34 | end 35 | 36 | def test_limit_100 37 | expected = [ 38 | "" + RES_DIR + "/rcext.txt", 39 | " 1 match-ext: rb", 40 | " 2 match-ext: pl", 41 | "" + RES_DIR + "/rcgrep.txt", 42 | " 1 grep: true", 43 | "" + RES_DIR + "/rcmatch.txt", 44 | " 1 match-name: \\w+.java", 45 | " 2 match-name: \\w+.rb", 46 | "" + RES_DIR + "/rcpath.txt", 47 | " 2 match-dirpath: src/test/ruby", 48 | ] 49 | run_app_test expected, [ '-r', '--size-limit', '100', 't.*e' ], RES_DIR 50 | end 51 | end 52 | end 53 | -------------------------------------------------------------------------------- /test/glark/input/split_as_path_test.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby -w 2 | # -*- ruby -*- 3 | 4 | require 'glark/app/tc' 5 | require 'glark/resources' 6 | 7 | module Glark 8 | class SplitAsPathTestCase < AppTestCase 9 | include Glark::Resources 10 | 11 | def test_default 12 | path = RES_DIR + ":/var/this/doesnt/exist" 13 | expected = [ 14 | "" + RES_DIR + "/canterbury/franklin/tale.txt", 15 | " 706 Why should I more examples hereof sayn?", 16 | "" + RES_DIR + "/canterbury/prologue.txt", 17 | " 604 That were of law expert and curious:", 18 | "" + RES_DIR + "/rcfile.txt", 19 | " 10 text-color-3: underline magenta", 20 | ] 21 | run_app_test expected, [ '-r', 'x.*er\w' ], path 22 | end 23 | 24 | def test_no_split 25 | path = RES_DIR + ":/var/this/doesnt/exist" 26 | expected = [ 27 | ] 28 | run_app_test expected, [ '-r', '--no-split-as-path', 't.*e\w' ], path 29 | end 30 | end 31 | end 32 | -------------------------------------------------------------------------------- /test/glark/resources.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby -w 2 | # -*- ruby -*- 3 | 4 | require 'rubygems' 5 | require 'logue/loggable' 6 | 7 | module Glark 8 | class Resource 9 | include Logue::Loggable 10 | 11 | RES_DIR = '/opt/org/incava/glark/test/resources/' 12 | 13 | def to_path basename 14 | RES_DIR + basename 15 | end 16 | 17 | def readlines basename 18 | ::IO.readlines to_path 19 | end 20 | end 21 | end 22 | 23 | module Glark 24 | module Resources 25 | PROJ_DIR = '/opt/org/incava/glark' 26 | TEST_DIR = PROJ_DIR + '/test' 27 | RES_DIR = TEST_DIR + '/resources' 28 | 29 | def to_path basename 30 | RES_DIR + (basename[0] == "/" ? "" : "/") + basename 31 | end 32 | 33 | def readlines basename 34 | ::IO.readlines to_path 35 | end 36 | end 37 | end 38 | -------------------------------------------------------------------------------- /test/glark/tc.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby -w 2 | # -*- ruby -*- 3 | 4 | require 'rubygems' 5 | require 'logue/log' 6 | require 'test/unit' 7 | require 'tempfile' 8 | require 'glark/resources' 9 | 10 | STDOUT.sync = true 11 | STDERR.sync = true 12 | 13 | require 'glark/app/runner' 14 | 15 | # Logue::Log.verbose = true 16 | Logue::Log.set_widths(-15, 35, -35) 17 | Logue::Log.quiet = true 18 | Logue::Log.verbose = false 19 | 20 | module Glark 21 | class TestCase < Test::Unit::TestCase 22 | include Logue::Loggable 23 | include Glark::Resources 24 | 25 | # Returns a list of instance methods, in sorted order, so that they are run 26 | # predictably by the unit test framework. 27 | 28 | class << self 29 | alias :unsorted_instance_methods :instance_methods 30 | 31 | def instance_methods b 32 | unsorted_instance_methods(true).sort 33 | end 34 | end 35 | 36 | def test_truth 37 | assert true 38 | end 39 | end 40 | end 41 | -------------------------------------------------------------------------------- /test/resources/04-TheCooksTale.txt: -------------------------------------------------------------------------------- 1 | Of many a pilgrim hast thou Christe's curse, 2 | For of thy parsley yet fare they the worse. 3 | 4 | That they have eaten in thy stubble goose: 5 | For in thy shop doth many a fly go loose. 6 | 7 | Now tell on, gentle Roger, by thy name, 8 | But yet I pray thee be not wroth for game; 9 | A man may say full sooth in game and play. 10 | -------------------------------------------------------------------------------- /test/resources/aaa.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpace/glark/8b54ff7ebfbd54d04ec138407e3d58f1c1cf791e/test/resources/aaa.zip -------------------------------------------------------------------------------- /test/resources/abcfile.txt: -------------------------------------------------------------------------------- 1 | ABC 2 | DEF 3 | GHI 4 | JKL 5 | MNO 6 | PQR 7 | STU 8 | -------------------------------------------------------------------------------- /test/resources/add.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby -w 2 | # -*- ruby -*- 3 | 4 | class Adder 5 | def initialize x, y 6 | puts x.to_s + " + " + y.to_s + " = " + (x.to_i + y.to_i).to_s 7 | end 8 | end 9 | 10 | Adder.new ARGV.shift || 2, ARGV.shift || 2 11 | -------------------------------------------------------------------------------- /test/resources/canterbury/franklin/prologue.txt: -------------------------------------------------------------------------------- 1 | THE FRANKLIN'S TALE. 2 | 3 | THE PROLOGUE. 4 | 5 | "IN faith, Squier, thou hast thee well acquit, 6 | And gentilly; I praise well thy wit," 7 | Quoth the Franklin; "considering thy youthe 8 | So feelingly thou speak'st, Sir, I aloue thee, 9 | As to my doom, there is none that is here 10 | Of eloquence that shall be thy peer, 11 | If that thou live; God give thee goode chance, 12 | And in virtue send thee continuance, 13 | For of thy speaking I have great dainty. 14 | 15 | I have a son, and, by the Trinity; 16 | It were me lever than twenty pound worth land, 17 | Though it right now were fallen in my hand, 18 | He were a man of such discretion 19 | As that ye be: fy on possession, 20 | But if a man be virtuous withal. 21 | 22 | I have my sone snibbed and yet shall, 23 | For he to virtue listeth not t'intend, 24 | But for to play at dice, and to dispend, 25 | And lose all that he hath, is his usage; 26 | And he had lever talke with a page, 27 | Than to commune with any gentle wight, 28 | There he might learen gentilless aright." 29 | 30 | Straw for your gentillesse!" quoth our Host. 31 | 32 | "What? Frankelin, pardie, Sir, well thou wost 33 | That each of you must tellen at the least 34 | A tale or two, or breake his behest." 35 | 36 | "That know I well, Sir," quoth the Frankelin; 37 | "I pray you have me not in disdain, 38 | Though I to this man speak a word or two." 39 | 40 | "Tell on thy tale, withoute wordes mo'." 41 | 42 | "Gladly, Sir Host," quoth he, "I will obey 43 | Unto your will; now hearken what I say; 44 | I will you not contrary in no wise, 45 | As far as that my wittes may suffice. 46 | 47 | "I pray to God that it may please you, 48 | Then wot I well that it is good enow. 49 | 50 | "These olde gentle Bretons, in their days, 51 | Of divers aventures made lays, 52 | Rhymeden in their firste Breton tongue; 53 | Which layes with their instruments they sung, 54 | Or elles reade them for their pleasance; 55 | And one of them have I in remembrance, 56 | Which I shall say with good will as I can. 57 | 58 | "But, Sirs, because I am a borel man, 59 | At my beginning first I you beseech 60 | Have me excused of my rude speech. 61 | 62 | "I learned never rhetoric, certain; 63 | Thing that I speak, it must be bare and plain. 64 | 65 | "I slept never on the mount of Parnasso, 66 | Nor learned Marcus Tullius Cicero. 67 | 68 | "Coloures know I none, withoute dread, 69 | But such colours as growen in the mead, 70 | Or elles such as men dye with or paint; 71 | Colours of rhetoric be to me quaint; 72 | My spirit feeleth not of such mattere. 73 | But, if you list, my tale shall ye hear." 74 | -------------------------------------------------------------------------------- /test/resources/cat.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | # -*- perl -*- 3 | 4 | use strict; 5 | 6 | print <>; 7 | -------------------------------------------------------------------------------- /test/resources/checkdot.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpace/glark/8b54ff7ebfbd54d04ec138407e3d58f1c1cf791e/test/resources/checkdot.gif -------------------------------------------------------------------------------- /test/resources/echo.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby -w 2 | puts ARGV.join(' ') 3 | -------------------------------------------------------------------------------- /test/resources/expressions.txt: -------------------------------------------------------------------------------- 1 | \b6\d{4}\b 2 | TheM.*Tale 3 | -------------------------------------------------------------------------------- /test/resources/filelist.txt: -------------------------------------------------------------------------------- 1 | 00-The_Prologue.txt 2 | 01-The_Knights_Tale.txt 3 | 02-The_Millers_Tale.txt 4 | 03-The_Reeves_Tale.txt 5 | 04-The_Cooks_Tale.txt 6 | 05-The_Man_Of_Laws_Tale.txt 7 | 06-The_Wife_Of_Baths_Tale.txt 8 | 07-The_Friars_Tale.txt 9 | 08-The_Sompnours_Tale.txt 10 | 09-The_Clerks_Tale.txt 11 | 10-The_Merchants_Tale.txt 12 | 11-The_Squires_Tale.txt 13 | 12-The_Franklins_Tale.txt 14 | 13-The_Doctors_Tale.txt 15 | 14-The_Pardoners_Tale.txt 16 | 15-The_Shipmans_Tale.txt 17 | 16-The_Prioresss_Tale.txt 18 | 17-Chaucers_Tale_Of_Sir_Thopas.txt 19 | 18-Chaucers_Tale_Of_Meliboeus.txt 20 | 19-The_Monks_Tale.txt 21 | 20-The_Nuns_Priests_Tale.txt 22 | 21-The_Second_Nuns_Tale.txt 23 | 22-The_Canons_Yeomans_Tale.txt 24 | 23-The_Manciples_Tale.txt 25 | 24-The_Parsons_Tale.txt 26 | 25-Preces_De_Chauceres.txt 27 | -------------------------------------------------------------------------------- /test/resources/greet.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby -w 2 | # -*- ruby -*- 3 | 4 | class Greet 5 | def initialize name 6 | puts "hello, " + name 7 | end 8 | end 9 | 10 | Greet.new ARGV.shift || "world" 11 | -------------------------------------------------------------------------------- /test/resources/org-incava-ijdk-1.0.1.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpace/glark/8b54ff7ebfbd54d04ec138407e3d58f1c1cf791e/test/resources/org-incava-ijdk-1.0.1.jar -------------------------------------------------------------------------------- /test/resources/rcext.txt: -------------------------------------------------------------------------------- 1 | match-ext: rb 2 | match-ext: pl 3 | 4 | skip-ext: txt 5 | -------------------------------------------------------------------------------- /test/resources/rcfile.txt: -------------------------------------------------------------------------------- 1 | # comment here 2 | highlight: single 3 | # highlight: multi 4 | local-config-files: true 5 | 6 | line-number-color: bold red 7 | ignore-case: true 8 | size-limit: 1000 9 | 10 | text-color-3: underline magenta 11 | -------------------------------------------------------------------------------- /test/resources/rcgrep.txt: -------------------------------------------------------------------------------- 1 | grep: true 2 | -------------------------------------------------------------------------------- /test/resources/rcmatch.txt: -------------------------------------------------------------------------------- 1 | match-name: \w+.java 2 | match-name: \w+.rb 3 | 4 | skip-name: zxcdjlk 5 | -------------------------------------------------------------------------------- /test/resources/rcpath.txt: -------------------------------------------------------------------------------- 1 | match-dirpath: src/main/java 2 | match-dirpath: src/test/ruby 3 | 4 | skip-dirpath: org/incava/util 5 | -------------------------------------------------------------------------------- /test/resources/rubies.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpace/glark/8b54ff7ebfbd54d04ec138407e3d58f1c1cf791e/test/resources/rubies.tar.gz -------------------------------------------------------------------------------- /test/resources/spaces.txt: -------------------------------------------------------------------------------- 1 | 00 The Prologue.txt 2 | 01 The Knights Tale.txt 3 | 02 The Millers Tale.txt 4 | 03 The Reeves Tale.txt 5 | 04 The Cooks Tale.txt 6 | 05 The Man Of Laws Tale.txt 7 | 06 The Wife Of Baths Tale.txt 8 | 07 The Friars Tale.txt 9 | 08 The Sompnours Tale.txt 10 | 09 The Clerks Tale.txt 11 | 10 The Merchants Tale.txt 12 | 11 The Squires Tale.txt 13 | 12 The Franklins Tale.txt 14 | 13 The Doctors Tale.txt 15 | 14 The Pardoners Tale.txt 16 | 15 The Shipmans Tale.txt 17 | 16 The Prioresss Tale.txt 18 | 17 Chaucers Tale Of Sir Thopas.txt 19 | 18 Chaucers Tale Of Meliboeus.txt 20 | 19 The Monks Tale.txt 21 | 20 The Nuns Priests Tale.txt 22 | 21 The Second Nuns Tale.txt 23 | 22 The Canons Yeomans Tale.txt 24 | 23 The Manciples Tale.txt 25 | 24 The Parsons Tale.txt 26 | 25 Preces De Chauceres.txt 27 | -------------------------------------------------------------------------------- /test/resources/textfile.txt: -------------------------------------------------------------------------------- 1 | -rw-r--r-- 1 jpace jpace 52183 2010-12-04 15:24 00-ThePrologue.txt 2 | -rw-r--r-- 1 jpace jpace 126084 2010-12-04 15:24 01-TheKnightsTale.txt 3 | -rw-r--r-- 1 jpace jpace 45450 2010-12-04 15:24 02-TheMillersTale.txt 4 | -rw-r--r-- 1 jpace jpace 29296 2010-12-04 15:24 03-TheReevesTale.txt 5 | -rw-r--r-- 1 jpace jpace 6525 2010-12-04 15:24 04-TheCooksTale.txt 6 | -rw-r--r-- 1 jpace jpace 63290 2010-12-04 15:24 05-TheManOfLawsTale.txt 7 | -rw-r--r-- 1 jpace jpace 71054 2010-12-04 15:24 06-TheWifeOfBathsTale.txt 8 | -rw-r--r-- 1 jpace jpace 22754 2010-12-04 15:24 07-TheFriarsTale.txt 9 | -rw-r--r-- 1 jpace jpace 35994 2010-12-04 15:24 08-TheSompnoursTale.txt 10 | -rw-r--r-- 1 jpace jpace 64791 2010-12-04 15:24 09-TheClerksTale.txt 11 | -rw-r--r-- 1 jpace jpace 65852 2010-12-04 15:24 10-TheMerchantsTale.txt 12 | -rw-r--r-- 1 jpace jpace 42282 2010-12-04 15:24 11-TheSquiresTale.txt 13 | -rw-r--r-- 1 jpace jpace 51996 2010-12-04 15:24 12-TheFranklinsTale.txt 14 | -rw-r--r-- 1 jpace jpace 15615 2010-12-04 15:24 13-TheDoctorsTale.txt 15 | -rw-r--r-- 1 jpace jpace 39546 2010-12-04 15:24 14-ThePardonersTale.txt 16 | -rw-r--r-- 1 jpace jpace 25163 2010-12-04 15:24 15-TheShipmansTale.txt 17 | -rw-r--r-- 1 jpace jpace 14979 2010-12-04 15:24 16-ThePrioresssTale.txt 18 | -rw-r--r-- 1 jpace jpace 14834 2010-12-04 15:24 17-ChaucersTaleOfSirThopas.txt 19 | -rw-r--r-- 1 jpace jpace 43249 2010-12-04 15:24 18-ChaucersTaleOfMeliboeus.txt 20 | -rw-r--r-- 1 jpace jpace 49747 2010-12-04 15:24 19-TheMonksTale.txt 21 | -rw-r--r-- 1 jpace jpace 45326 2010-12-04 15:24 20-TheNunsPriestsTale.txt 22 | -rw-r--r-- 1 jpace jpace 30734 2010-12-04 15:24 21-TheSecondNunsTale.txt 23 | -rw-r--r-- 1 jpace jpace 52953 2010-12-04 15:24 22-TheCanonsYeomansTale.txt 24 | -rw-r--r-- 1 jpace jpace 21141 2010-12-04 15:24 23-TheManciplesTale.txt 25 | -rw-r--r-- 1 jpace jpace 58300 2010-12-04 15:24 24-TheParsonsTale.txt 26 | -rw-r--r-- 1 jpace jpace 3650 2010-12-04 15:24 25-PrecesDeChauceres.txt 27 | -------------------------------------------------------------------------------- /test/resources/textfile.txt.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpace/glark/8b54ff7ebfbd54d04ec138407e3d58f1c1cf791e/test/resources/textfile.txt.gz -------------------------------------------------------------------------------- /test/resources/txt.tgz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpace/glark/8b54ff7ebfbd54d04ec138407e3d58f1c1cf791e/test/resources/txt.tgz -------------------------------------------------------------------------------- /test/resources/zfile.txt: -------------------------------------------------------------------------------- 1 | zaffres 2 | zoaea 3 | zoaea's 4 | zoea 5 | zoeas 6 | zonulae 7 | zooea 8 | zooeae 9 | zooeal 10 | zooeas 11 | zooecia 12 | zooecium 13 | zoogloeae 14 | zoogloeal 15 | zoogloeas 16 | zygaenid 17 | -------------------------------------------------------------------------------- /test/resources/zfile.txt.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpace/glark/8b54ff7ebfbd54d04ec138407e3d58f1c1cf791e/test/resources/zfile.txt.gz --------------------------------------------------------------------------------