findr 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/bin/findr +6 -0
- data/findr.gemspec +43 -0
- data/lib/findr.rb +2 -0
- data/lib/findr/cli.rb +131 -0
- data/lib/findr/version.rb +3 -0
- metadata +53 -0
data/bin/findr
ADDED
data/findr.gemspec
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
|
2
|
+
# -*- encoding: utf-8 -*-
|
3
|
+
$:.push('lib')
|
4
|
+
require "findr/version"
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = "findr"
|
8
|
+
s.version = Findr::VERSION.dup
|
9
|
+
s.date = "2012-06-01"
|
10
|
+
s.summary = "A ruby find and replace tool for batch editing text files."
|
11
|
+
s.email = "Markus@ITstrauss.eu"
|
12
|
+
s.homepage = "https://github.com/mstrauss/findr"
|
13
|
+
s.authors = ['Markus Strauss']
|
14
|
+
|
15
|
+
s.description = <<-EOF
|
16
|
+
A ruby find and replace tool for batch editing text files.
|
17
|
+
EOF
|
18
|
+
|
19
|
+
dependencies = [
|
20
|
+
# Examples:
|
21
|
+
# [:runtime, "rack", "~> 1.1"],
|
22
|
+
# [:development, "rspec", "~> 2.1"],
|
23
|
+
]
|
24
|
+
|
25
|
+
s.files = Dir['**/*']
|
26
|
+
s.test_files = Dir['test/**/*'] + Dir['spec/**/*']
|
27
|
+
s.executables = Dir['bin/*'].map { |f| File.basename(f) }
|
28
|
+
s.require_paths = ["lib"]
|
29
|
+
|
30
|
+
|
31
|
+
## Make sure you can build the gem on older versions of RubyGems too:
|
32
|
+
s.rubygems_version = "1.8.11"
|
33
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
34
|
+
s.specification_version = 3 if s.respond_to? :specification_version
|
35
|
+
|
36
|
+
dependencies.each do |type, name, version|
|
37
|
+
if s.respond_to?("add_#{type}_dependency")
|
38
|
+
s.send("add_#{type}_dependency", name, version)
|
39
|
+
else
|
40
|
+
s.add_dependency(name, version)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
data/lib/findr.rb
ADDED
data/lib/findr/cli.rb
ADDED
@@ -0,0 +1,131 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'pathname'
|
3
|
+
require 'tempfile'
|
4
|
+
require 'optparse'
|
5
|
+
|
6
|
+
# this is deprecated on 1.9, but still works fine
|
7
|
+
require 'iconv'
|
8
|
+
|
9
|
+
module Findr
|
10
|
+
|
11
|
+
class CLI
|
12
|
+
|
13
|
+
def colorize(text, color_code)
|
14
|
+
"\e[#{color_code}m#{text}\e[0m"
|
15
|
+
end
|
16
|
+
|
17
|
+
def red(text); colorize(text, 31); end
|
18
|
+
def green(text); colorize(text, 32); end
|
19
|
+
def yellow(text); colorize(text, 33); end
|
20
|
+
def blue(text); colorize(text, 34); end
|
21
|
+
|
22
|
+
def banner
|
23
|
+
("Usage: #{Pathname($0).basename} [options] <search regex> [<replacement string>]" + $/) +
|
24
|
+
red("THIS PROGRAM COMES WITH NO WARRANTY WHATSOEVER. MAKE BACKUPS!")
|
25
|
+
end
|
26
|
+
|
27
|
+
def show_usage
|
28
|
+
puts(@option_parser.help)
|
29
|
+
exit
|
30
|
+
end
|
31
|
+
|
32
|
+
def execute(stdout, arguments=[])
|
33
|
+
# unless arguments[0]
|
34
|
+
# end
|
35
|
+
|
36
|
+
# default options
|
37
|
+
options = {}
|
38
|
+
options[:glob] = '*'
|
39
|
+
options[:coding] = 'utf-8'
|
40
|
+
|
41
|
+
@option_parser = OptionParser.new do |opts|
|
42
|
+
opts.on('-g', '--glob FILE SEARCH GLOB', 'e.g. "*.{rb,erb}"') do |glob|
|
43
|
+
options[:glob] = glob
|
44
|
+
end
|
45
|
+
opts.on('-x', '--execute', 'actually execute the replacement') do
|
46
|
+
options[:force] = true
|
47
|
+
end
|
48
|
+
opts.on('-c', '--coding FILE CODING SYSTEM', 'e.g. "latin-1"') do |coding|
|
49
|
+
options[:coding] = coding
|
50
|
+
end
|
51
|
+
end
|
52
|
+
@option_parser.banner = self.banner
|
53
|
+
@option_parser.parse!( arguments )
|
54
|
+
|
55
|
+
show_usage if arguments.size == 0
|
56
|
+
arguments.clone.each do |arg|
|
57
|
+
if !options[:find]
|
58
|
+
options[:find] = Regexp.compile( arg )
|
59
|
+
arguments.delete_at(0)
|
60
|
+
elsif !options[:replace]
|
61
|
+
options[:replace] = arg
|
62
|
+
arguments.delete_at(0)
|
63
|
+
else
|
64
|
+
show_usage
|
65
|
+
end
|
66
|
+
end
|
67
|
+
show_usage if arguments.size != 0
|
68
|
+
|
69
|
+
|
70
|
+
stdout.puts green "File inclusion glob: " + options[:glob]
|
71
|
+
stdout.puts green "Searching for regex " + options[:find].to_s
|
72
|
+
|
73
|
+
# some statistics
|
74
|
+
stats = {}
|
75
|
+
stats[:total_hits] = stats[:local_hits] = stats[:hit_files] = stats[:total_files] = 0
|
76
|
+
|
77
|
+
replacement_done = false
|
78
|
+
tempfile = nil
|
79
|
+
|
80
|
+
coding_to_utf8 = Iconv.new('utf-8', options[:coding])
|
81
|
+
utf8_to_coding = Iconv.new(options[:coding], 'utf-8')
|
82
|
+
|
83
|
+
Pathname.glob("**/#{options[:glob]}").each do |current_file|
|
84
|
+
next unless current_file.file?
|
85
|
+
stats[:total_files] += 1
|
86
|
+
stats[:local_hits] = 0
|
87
|
+
firstmatch = true
|
88
|
+
linenumber = 0
|
89
|
+
tempfile = Tempfile.new( 'current_file.basename' ) if options[:replace] && options[:force]
|
90
|
+
current_file.each_line do |l|
|
91
|
+
l = coding_to_utf8.iconv(l)
|
92
|
+
linenumber += 1
|
93
|
+
if l=~ options[:find]
|
94
|
+
stats[:local_hits] += 1
|
95
|
+
if firstmatch
|
96
|
+
stdout.puts red("#{current_file.cleanpath}:")
|
97
|
+
end
|
98
|
+
stdout.write( yellow( "%6d:" % [linenumber, l] ) )
|
99
|
+
stdout.puts l
|
100
|
+
firstmatch = false
|
101
|
+
if options[:replace]
|
102
|
+
stdout.write( blue( "%6d:" % [linenumber, l] ) )
|
103
|
+
l_repl = l.gsub( options[:find], options[:replace] )
|
104
|
+
tempfile.puts utf8_to_coding.iconv(l_repl) if tempfile
|
105
|
+
stdout.puts blue l_repl
|
106
|
+
replacement_done = true
|
107
|
+
end
|
108
|
+
elsif tempfile
|
109
|
+
tempfile.puts utf8_to_coding.iconv(l)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
if tempfile
|
113
|
+
tempfile.close
|
114
|
+
FileUtils.cp( tempfile.path, current_file ) if stats[:local_hits] > 0
|
115
|
+
tempfile.unlink
|
116
|
+
end
|
117
|
+
|
118
|
+
if stats[:local_hits] > 0
|
119
|
+
stats[:total_hits] += stats[:local_hits]
|
120
|
+
stats[:hit_files] += 1
|
121
|
+
end
|
122
|
+
|
123
|
+
end
|
124
|
+
|
125
|
+
# some statistics
|
126
|
+
stdout.puts green( "#{stats[:total_hits]} occurences (lines) in #{stats[:hit_files]} of #{stats[:total_files]} files found." )
|
127
|
+
end
|
128
|
+
|
129
|
+
end
|
130
|
+
|
131
|
+
end
|
metadata
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: findr
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Markus Strauss
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-06-01 00:00:00.000000000 Z
|
13
|
+
dependencies: []
|
14
|
+
description: ! 'A ruby find and replace tool for batch editing text files.
|
15
|
+
|
16
|
+
'
|
17
|
+
email: Markus@ITstrauss.eu
|
18
|
+
executables:
|
19
|
+
- findr
|
20
|
+
extensions: []
|
21
|
+
extra_rdoc_files: []
|
22
|
+
files:
|
23
|
+
- bin/findr
|
24
|
+
- findr.gemspec
|
25
|
+
- lib/findr/cli.rb
|
26
|
+
- lib/findr/version.rb
|
27
|
+
- lib/findr.rb
|
28
|
+
homepage: https://github.com/mstrauss/findr
|
29
|
+
licenses: []
|
30
|
+
post_install_message:
|
31
|
+
rdoc_options: []
|
32
|
+
require_paths:
|
33
|
+
- lib
|
34
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
35
|
+
none: false
|
36
|
+
requirements:
|
37
|
+
- - ! '>='
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '0'
|
40
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
requirements: []
|
47
|
+
rubyforge_project:
|
48
|
+
rubygems_version: 1.8.11
|
49
|
+
signing_key:
|
50
|
+
specification_version: 3
|
51
|
+
summary: A ruby find and replace tool for batch editing text files.
|
52
|
+
test_files: []
|
53
|
+
has_rdoc:
|