far 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.document +5 -0
- data/.rspec +1 -0
- data/Gemfile +14 -0
- data/Gemfile.lock +129 -0
- data/Guardfile +33 -0
- data/LICENSE.txt +20 -0
- data/README.md +37 -0
- data/Rakefile +51 -0
- data/VERSION +1 -0
- data/authors.cool_guys +12 -0
- data/bin/far +38 -0
- data/example_files/cats.tirade +5 -0
- data/example_files/everyone.rb +10 -0
- data/example_files/people.rb +5 -0
- data/lib/far.rb +2 -0
- data/lib/far/change_report.rb +20 -0
- data/lib/far/differ.rb +46 -0
- data/lib/far/file.rb +28 -0
- data/lib/far/option.rb +50 -0
- data/lib/far/options.rb +21 -0
- data/lib/far/replacer.rb +104 -0
- data/spec/lib/far/options_spec.rb +11 -0
- data/spec/lib/far/replacer_spec.rb +45 -0
- data/spec/spec_helper.rb +7 -0
- metadata +197 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 58059e9da9cb4d6186392a98019e4b4d5e19ea9f
|
4
|
+
data.tar.gz: b17226efff91a36458b7c1c51dd75781c564765f
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 0079b71dcb1f08208720d3b5e0387b4b5ab83b5fdf657e4c289c18f88d2a13312aaa681ed0b69d59ff49aa1f5df4445a2fcc521467e2ebfc0ec3ad6d5a4e1f28
|
7
|
+
data.tar.gz: 6cd21b0545454b0d7ccc4689944cd888e0c87b20c23598db548d52dd7f4d16bd6d863ec86c594ccc09f366917625dcfd30e9b69815bb057caaec36b2f4350987
|
data/.document
ADDED
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
data/Gemfile
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
source "http://rubygems.org"
|
2
|
+
|
3
|
+
group :development do
|
4
|
+
gem "shoulda", ">= 0"
|
5
|
+
gem "rdoc", "~> 3.12"
|
6
|
+
gem "bundler", "~> 1.0"
|
7
|
+
gem "jeweler", "~> 2.0.1"
|
8
|
+
gem "simplecov", ">= 0"
|
9
|
+
gem "rspec"
|
10
|
+
gem "guard-rspec"
|
11
|
+
gem "terminal-notifier-guard"
|
12
|
+
end
|
13
|
+
|
14
|
+
gem "differ"
|
data/Gemfile.lock
ADDED
@@ -0,0 +1,129 @@
|
|
1
|
+
GEM
|
2
|
+
remote: http://rubygems.org/
|
3
|
+
specs:
|
4
|
+
activesupport (4.1.4)
|
5
|
+
i18n (~> 0.6, >= 0.6.9)
|
6
|
+
json (~> 1.7, >= 1.7.7)
|
7
|
+
minitest (~> 5.1)
|
8
|
+
thread_safe (~> 0.1)
|
9
|
+
tzinfo (~> 1.1)
|
10
|
+
addressable (2.3.6)
|
11
|
+
builder (3.2.2)
|
12
|
+
celluloid (0.15.2)
|
13
|
+
timers (~> 1.1.0)
|
14
|
+
coderay (1.1.0)
|
15
|
+
descendants_tracker (0.0.4)
|
16
|
+
thread_safe (~> 0.3, >= 0.3.1)
|
17
|
+
diff-lcs (1.2.5)
|
18
|
+
differ (0.1.2)
|
19
|
+
docile (1.1.5)
|
20
|
+
faraday (0.9.0)
|
21
|
+
multipart-post (>= 1.2, < 3)
|
22
|
+
ffi (1.9.3)
|
23
|
+
formatador (0.2.5)
|
24
|
+
git (1.2.7)
|
25
|
+
github_api (0.11.3)
|
26
|
+
addressable (~> 2.3)
|
27
|
+
descendants_tracker (~> 0.0.1)
|
28
|
+
faraday (~> 0.8, < 0.10)
|
29
|
+
hashie (>= 1.2)
|
30
|
+
multi_json (>= 1.7.5, < 2.0)
|
31
|
+
nokogiri (~> 1.6.0)
|
32
|
+
oauth2
|
33
|
+
guard (2.6.1)
|
34
|
+
formatador (>= 0.2.4)
|
35
|
+
listen (~> 2.7)
|
36
|
+
lumberjack (~> 1.0)
|
37
|
+
pry (>= 0.9.12)
|
38
|
+
thor (>= 0.18.1)
|
39
|
+
guard-rspec (4.3.1)
|
40
|
+
guard (~> 2.1)
|
41
|
+
rspec (>= 2.14, < 4.0)
|
42
|
+
hashie (3.2.0)
|
43
|
+
highline (1.6.21)
|
44
|
+
i18n (0.6.11)
|
45
|
+
jeweler (2.0.1)
|
46
|
+
builder
|
47
|
+
bundler (>= 1.0)
|
48
|
+
git (>= 1.2.5)
|
49
|
+
github_api
|
50
|
+
highline (>= 1.6.15)
|
51
|
+
nokogiri (>= 1.5.10)
|
52
|
+
rake
|
53
|
+
rdoc
|
54
|
+
json (1.8.1)
|
55
|
+
jwt (1.0.0)
|
56
|
+
listen (2.7.9)
|
57
|
+
celluloid (>= 0.15.2)
|
58
|
+
rb-fsevent (>= 0.9.3)
|
59
|
+
rb-inotify (>= 0.9)
|
60
|
+
lumberjack (1.0.9)
|
61
|
+
method_source (0.8.2)
|
62
|
+
mini_portile (0.6.0)
|
63
|
+
minitest (5.4.0)
|
64
|
+
multi_json (1.10.1)
|
65
|
+
multi_xml (0.5.5)
|
66
|
+
multipart-post (2.0.0)
|
67
|
+
nokogiri (1.6.3.1)
|
68
|
+
mini_portile (= 0.6.0)
|
69
|
+
oauth2 (1.0.0)
|
70
|
+
faraday (>= 0.8, < 0.10)
|
71
|
+
jwt (~> 1.0)
|
72
|
+
multi_json (~> 1.3)
|
73
|
+
multi_xml (~> 0.5)
|
74
|
+
rack (~> 1.2)
|
75
|
+
pry (0.10.0)
|
76
|
+
coderay (~> 1.1.0)
|
77
|
+
method_source (~> 0.8.1)
|
78
|
+
slop (~> 3.4)
|
79
|
+
rack (1.5.2)
|
80
|
+
rake (10.3.2)
|
81
|
+
rb-fsevent (0.9.4)
|
82
|
+
rb-inotify (0.9.5)
|
83
|
+
ffi (>= 0.5.0)
|
84
|
+
rdoc (3.12.2)
|
85
|
+
json (~> 1.4)
|
86
|
+
rspec (3.0.0)
|
87
|
+
rspec-core (~> 3.0.0)
|
88
|
+
rspec-expectations (~> 3.0.0)
|
89
|
+
rspec-mocks (~> 3.0.0)
|
90
|
+
rspec-core (3.0.3)
|
91
|
+
rspec-support (~> 3.0.0)
|
92
|
+
rspec-expectations (3.0.3)
|
93
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
94
|
+
rspec-support (~> 3.0.0)
|
95
|
+
rspec-mocks (3.0.3)
|
96
|
+
rspec-support (~> 3.0.0)
|
97
|
+
rspec-support (3.0.3)
|
98
|
+
shoulda (3.5.0)
|
99
|
+
shoulda-context (~> 1.0, >= 1.0.1)
|
100
|
+
shoulda-matchers (>= 1.4.1, < 3.0)
|
101
|
+
shoulda-context (1.2.1)
|
102
|
+
shoulda-matchers (2.6.2)
|
103
|
+
activesupport (>= 3.0.0)
|
104
|
+
simplecov (0.9.0)
|
105
|
+
docile (~> 1.1.0)
|
106
|
+
multi_json
|
107
|
+
simplecov-html (~> 0.8.0)
|
108
|
+
simplecov-html (0.8.0)
|
109
|
+
slop (3.6.0)
|
110
|
+
terminal-notifier-guard (1.5.3)
|
111
|
+
thor (0.19.1)
|
112
|
+
thread_safe (0.3.4)
|
113
|
+
timers (1.1.0)
|
114
|
+
tzinfo (1.2.1)
|
115
|
+
thread_safe (~> 0.1)
|
116
|
+
|
117
|
+
PLATFORMS
|
118
|
+
ruby
|
119
|
+
|
120
|
+
DEPENDENCIES
|
121
|
+
bundler (~> 1.0)
|
122
|
+
differ
|
123
|
+
guard-rspec
|
124
|
+
jeweler (~> 2.0.1)
|
125
|
+
rdoc (~> 3.12)
|
126
|
+
rspec
|
127
|
+
shoulda
|
128
|
+
simplecov
|
129
|
+
terminal-notifier-guard
|
data/Guardfile
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
# A sample Guardfile
|
2
|
+
# More info at https://github.com/guard/guard#readme
|
3
|
+
|
4
|
+
# Note: The cmd option is now required due to the increasing number of ways
|
5
|
+
# rspec may be run, below are examples of the most common uses.
|
6
|
+
# * bundler: 'bundle exec rspec'
|
7
|
+
# * bundler binstubs: 'bin/rspec'
|
8
|
+
# * spring: 'bin/rsspec' (This will use spring if running and you have
|
9
|
+
# installed the spring binstubs per the docs)
|
10
|
+
# * zeus: 'zeus rspec' (requires the server to be started separetly)
|
11
|
+
# * 'just' rspec: 'rspec'
|
12
|
+
guard :rspec, cmd: 'bundle exec rspec' do
|
13
|
+
watch(%r{^spec/.+_spec\.rb$})
|
14
|
+
watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
|
15
|
+
watch('spec/spec_helper.rb') { "spec" }
|
16
|
+
|
17
|
+
# Rails example
|
18
|
+
watch(%r{^app/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
|
19
|
+
watch(%r{^app/(.*)(\.erb|\.haml|\.slim)$}) { |m| "spec/#{m[1]}#{m[2]}_spec.rb" }
|
20
|
+
watch(%r{^app/controllers/(.+)_(controller)\.rb$}) { |m| ["spec/routing/#{m[1]}_routing_spec.rb", "spec/#{m[2]}s/#{m[1]}_#{m[2]}_spec.rb", "spec/acceptance/#{m[1]}_spec.rb"] }
|
21
|
+
watch(%r{^spec/support/(.+)\.rb$}) { "spec" }
|
22
|
+
watch('config/routes.rb') { "spec/routing" }
|
23
|
+
watch('app/controllers/application_controller.rb') { "spec/controllers" }
|
24
|
+
watch('spec/rails_helper.rb') { "spec" }
|
25
|
+
|
26
|
+
# Capybara features specs
|
27
|
+
watch(%r{^app/views/(.+)/.*\.(erb|haml|slim)$}) { |m| "spec/features/#{m[1]}_spec.rb" }
|
28
|
+
|
29
|
+
# Turnip features and steps
|
30
|
+
watch(%r{^spec/acceptance/(.+)\.feature$})
|
31
|
+
watch(%r{^spec/acceptance/steps/(.+)_steps\.rb$}) { |m| Dir[File.join("**/#{m[1]}.feature")][0] || 'spec/acceptance' }
|
32
|
+
end
|
33
|
+
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2014 Brett Shollenberger & Zach MacHardy
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
# far
|
2
|
+
|
3
|
+
Project-wide find and replace. Far will recursively fix your current directory.
|
4
|
+
|
5
|
+
#### Dry run the output of a replace
|
6
|
+
```
|
7
|
+
far 's/Fun\:\:Stuff/Cool\:\:Things/'
|
8
|
+
```
|
9
|
+
#### To actually run, pass the "please" and "run" options
|
10
|
+
```
|
11
|
+
far --please --run 's/Fun\:\:Stuff/Cool\:\:Things/'
|
12
|
+
far -pr 's/Fun\:\:Stuff/Cool\:\:Things/'
|
13
|
+
```
|
14
|
+
#### Ignore directory
|
15
|
+
```
|
16
|
+
far --ignore-dir=spec -pr 's/Fun\:\:Stuff/Cool\:\:Things/'
|
17
|
+
```
|
18
|
+
|
19
|
+
#### Ignore file
|
20
|
+
```
|
21
|
+
far --ignore-file=cats.rb -pr 's/Fun\:\:Stuff/Cool\:\:Things/'
|
22
|
+
```
|
23
|
+
|
24
|
+
## Contributing to far
|
25
|
+
|
26
|
+
* Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet.
|
27
|
+
* Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it.
|
28
|
+
* Fork the project.
|
29
|
+
* Start a feature/bugfix branch.
|
30
|
+
* Commit and push until you are happy with your contribution.
|
31
|
+
* Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
|
32
|
+
* Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
|
33
|
+
|
34
|
+
## Copyright
|
35
|
+
|
36
|
+
Copyright (c) 2014 Brett Shollenberger & Zach MacHardy. See LICENSE.txt for
|
37
|
+
further details.
|
data/Rakefile
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'bundler'
|
5
|
+
begin
|
6
|
+
Bundler.setup(:default, :development)
|
7
|
+
rescue Bundler::BundlerError => e
|
8
|
+
$stderr.puts e.message
|
9
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
10
|
+
exit e.status_code
|
11
|
+
end
|
12
|
+
require 'rake'
|
13
|
+
|
14
|
+
require 'jeweler'
|
15
|
+
Jeweler::Tasks.new do |gem|
|
16
|
+
# gem is a Gem::Specification... see http://guides.rubygems.org/specification-reference/ for more options
|
17
|
+
gem.name = "far"
|
18
|
+
gem.homepage = "http://github.com/brettshollenberger/far"
|
19
|
+
gem.license = "MIT"
|
20
|
+
gem.summary = %Q{Project-wide find and replace.}
|
21
|
+
gem.description = %Q{Recursively find and replace in your current directory.}
|
22
|
+
gem.email = "brett.shollenberger@gmail.com"
|
23
|
+
gem.authors = ["Brett Shollenberger", "Zach MacHardy"]
|
24
|
+
# dependencies defined in Gemfile
|
25
|
+
end
|
26
|
+
Jeweler::RubygemsDotOrgTasks.new
|
27
|
+
|
28
|
+
require 'rake/testtask'
|
29
|
+
Rake::TestTask.new(:test) do |test|
|
30
|
+
test.libs << 'lib' << 'test'
|
31
|
+
test.pattern = 'test/**/test_*.rb'
|
32
|
+
test.verbose = true
|
33
|
+
end
|
34
|
+
|
35
|
+
desc "Code coverage detail"
|
36
|
+
task :simplecov do
|
37
|
+
ENV['COVERAGE'] = "true"
|
38
|
+
Rake::Task['test'].execute
|
39
|
+
end
|
40
|
+
|
41
|
+
task :default => :test
|
42
|
+
|
43
|
+
require 'rdoc/task'
|
44
|
+
Rake::RDocTask.new do |rdoc|
|
45
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
46
|
+
|
47
|
+
rdoc.rdoc_dir = 'rdoc'
|
48
|
+
rdoc.title = "far #{version}"
|
49
|
+
rdoc.rdoc_files.include('README*')
|
50
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
51
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.1.2
|
data/authors.cool_guys
ADDED
data/bin/far
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
#! /usr/bin/env ruby
|
2
|
+
|
3
|
+
require "optparse"
|
4
|
+
require "differ"
|
5
|
+
|
6
|
+
require_relative "../lib/far/change_report"
|
7
|
+
require_relative "../lib/far/differ"
|
8
|
+
require_relative "../lib/far/file"
|
9
|
+
require_relative "../lib/far/option"
|
10
|
+
require_relative "../lib/far/options"
|
11
|
+
require_relative "../lib/far/replacer"
|
12
|
+
|
13
|
+
@options = {:replace => false, :please => false}
|
14
|
+
|
15
|
+
OptionParser.new do |opts|
|
16
|
+
opts.on("-r", "--[no-]replace", "Replace. Not a dry run. Must be combined with --please") do |r|
|
17
|
+
@options[:replace] = r
|
18
|
+
end
|
19
|
+
|
20
|
+
opts.on("-p", "--[no-]please", "Manners are important.") do |p|
|
21
|
+
@options[:please] = p
|
22
|
+
end
|
23
|
+
|
24
|
+
opts.on("--ignore-dir DIR", "Directory to ignore. Uses Ack options") do |dir|
|
25
|
+
@options[:ignore_dir] = dir
|
26
|
+
end
|
27
|
+
|
28
|
+
opts.on("--ignore-file FILE", "File(s) to ignore. Uses Ack options") do |file|
|
29
|
+
@options[:ignore_file] = file
|
30
|
+
end
|
31
|
+
end.parse!
|
32
|
+
|
33
|
+
@replacer = Far::Replacer.new(ARGV[0], @options)
|
34
|
+
|
35
|
+
@replacer.diff
|
36
|
+
@replacer.change_report.print
|
37
|
+
|
38
|
+
`rm far.tmp 2> /dev/null`
|
data/lib/far.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
module Far
|
2
|
+
class ChangeReport < Hash
|
3
|
+
attr_accessor :report
|
4
|
+
|
5
|
+
def initialize(files)
|
6
|
+
files.each { |file| self[file.name] = file.changes }
|
7
|
+
end
|
8
|
+
|
9
|
+
def print
|
10
|
+
each do |file, changes|
|
11
|
+
changes.each do |change|
|
12
|
+
puts "\033[32m#{file}\033[0m #{change[:line_number]}:"
|
13
|
+
puts change[:original]
|
14
|
+
puts change[:changed]
|
15
|
+
puts
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
data/lib/far/differ.rb
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
module Differ
|
2
|
+
class << self
|
3
|
+
def format_for(f)
|
4
|
+
Kernel.send :const_get, "Differ::Format::#{f.to_s.capitalize}"
|
5
|
+
end
|
6
|
+
end
|
7
|
+
|
8
|
+
class Diff
|
9
|
+
def format_as(f)
|
10
|
+
f = Differ.format_for(f)
|
11
|
+
@raw.inject("") do |sum, part|
|
12
|
+
part = case part
|
13
|
+
when String then ""
|
14
|
+
when Change then f.format(part)
|
15
|
+
end
|
16
|
+
sum << part
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
module Format
|
22
|
+
module Plain
|
23
|
+
class << self
|
24
|
+
def format(change)
|
25
|
+
(change.change? && as_change(change)) ||
|
26
|
+
(change.delete? && as_delete(change)) ||
|
27
|
+
(change.insert? && as_insert(change)) ||
|
28
|
+
''
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
def as_insert(change)
|
33
|
+
"#{change.insert}"
|
34
|
+
end
|
35
|
+
|
36
|
+
def as_delete(change)
|
37
|
+
"#{change.delete}"
|
38
|
+
end
|
39
|
+
|
40
|
+
def as_change(change)
|
41
|
+
"#{as_delete(change)}\n#{as_insert(change)}\n"
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
data/lib/far/file.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
module Far
|
2
|
+
class File
|
3
|
+
attr_accessor :name, :colorized_name, :changes, :find, :parts, :original_version, :changed_version
|
4
|
+
|
5
|
+
def initialize(name, find)
|
6
|
+
@name = name
|
7
|
+
@parts ||= `ack #{find} #{name} /dev/null`.split("\n")
|
8
|
+
end
|
9
|
+
|
10
|
+
def colorized_name
|
11
|
+
@colorized_name ||= @parts[0]
|
12
|
+
end
|
13
|
+
|
14
|
+
def changes
|
15
|
+
@changes ||= @parts[1..-1].map do |change|
|
16
|
+
parts = change.split(/\:/)
|
17
|
+
line_number = parts[0]
|
18
|
+
replacement = parts[1..-1].join(":")
|
19
|
+
{line_number: line_number, original: replacement}
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
def parts
|
25
|
+
@parts ||= `#{lines_to_change_cmd}`.split("\n")
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
data/lib/far/option.rb
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
module Far
|
2
|
+
class Option
|
3
|
+
attr_accessor :key, :value
|
4
|
+
|
5
|
+
def initialize(key, value)
|
6
|
+
@key = key.to_s
|
7
|
+
@value = value
|
8
|
+
end
|
9
|
+
|
10
|
+
def to_command_line
|
11
|
+
"#{prefix}#{negator}#{@key.gsub(/\_/) { |k| "-" }}#{equals}#{@value unless boolean?}"
|
12
|
+
end
|
13
|
+
|
14
|
+
def far_option?
|
15
|
+
Options.far_options.include? @key.to_sym
|
16
|
+
end
|
17
|
+
|
18
|
+
def flag?
|
19
|
+
@key.length > 1
|
20
|
+
end
|
21
|
+
|
22
|
+
def switch?
|
23
|
+
@key.length == 1
|
24
|
+
end
|
25
|
+
|
26
|
+
def negator
|
27
|
+
"no-" unless @value
|
28
|
+
end
|
29
|
+
|
30
|
+
def equals
|
31
|
+
"=" unless boolean?
|
32
|
+
end
|
33
|
+
|
34
|
+
def boolean?
|
35
|
+
!!@value == @value
|
36
|
+
end
|
37
|
+
|
38
|
+
def prefix
|
39
|
+
return "--" if flag?
|
40
|
+
return "-" if switch?
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
class Hash
|
46
|
+
def hmap(&block)
|
47
|
+
Hash[self.map {|k, v| block.call(k,v) }]
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
data/lib/far/options.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
module Far
|
2
|
+
class Options < Hash
|
3
|
+
attr_accessor :options
|
4
|
+
|
5
|
+
def self.far_options
|
6
|
+
[:replace, :no_replace, :please, :no_please]
|
7
|
+
end
|
8
|
+
|
9
|
+
def initialize(options={})
|
10
|
+
options.each do |k, v|
|
11
|
+
self[k.to_sym] = Option.new k, v
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def to_command_line
|
16
|
+
self.reject do |k, v|
|
17
|
+
v.far_option?
|
18
|
+
end.values.map(&:to_command_line).join(" ")
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
data/lib/far/replacer.rb
ADDED
@@ -0,0 +1,104 @@
|
|
1
|
+
module Far
|
2
|
+
class Replacer
|
3
|
+
attr_reader :substitution
|
4
|
+
attr_accessor :file_list, :options, :change_report
|
5
|
+
|
6
|
+
def initialize(substitution, options)
|
7
|
+
self.substitution = substitution
|
8
|
+
@options = Options.new options
|
9
|
+
generate_change_report
|
10
|
+
end
|
11
|
+
|
12
|
+
def substitution=(value)
|
13
|
+
value += "/" unless value[-1] == "/"
|
14
|
+
@substitution = value
|
15
|
+
end
|
16
|
+
|
17
|
+
def find
|
18
|
+
@substitution.split('/')[1]
|
19
|
+
end
|
20
|
+
|
21
|
+
def replace
|
22
|
+
@substitution.split('/')[2]
|
23
|
+
end
|
24
|
+
|
25
|
+
def file_list
|
26
|
+
@file_list ||= `#{file_list_cmd}`.split(" ")
|
27
|
+
end
|
28
|
+
|
29
|
+
def files
|
30
|
+
file_list.map { |file| File.new file, find }
|
31
|
+
end
|
32
|
+
|
33
|
+
def in_place
|
34
|
+
return "" if dry_run?
|
35
|
+
return "-i ''"
|
36
|
+
end
|
37
|
+
|
38
|
+
def redirection
|
39
|
+
"> #{tmp_file}" if dry_run?
|
40
|
+
end
|
41
|
+
|
42
|
+
def replaced_file(file)
|
43
|
+
return tmp_file if dry_run?
|
44
|
+
file
|
45
|
+
end
|
46
|
+
|
47
|
+
def run?
|
48
|
+
!dry_run?
|
49
|
+
end
|
50
|
+
|
51
|
+
def dry_run?
|
52
|
+
!@options[:please].value || !@options[:replace].value
|
53
|
+
end
|
54
|
+
|
55
|
+
def generate_change_report
|
56
|
+
change_report
|
57
|
+
end
|
58
|
+
|
59
|
+
def change_report
|
60
|
+
@change_report ||= ChangeReport.new(files)
|
61
|
+
end
|
62
|
+
|
63
|
+
def replace_file(file)
|
64
|
+
original_version = `cat #{file.name}`
|
65
|
+
`#{change_file_cmd(file)}`
|
66
|
+
changed_version = `cat #{replaced_file(file.name)}`
|
67
|
+
|
68
|
+
return original_version, changed_version
|
69
|
+
end
|
70
|
+
|
71
|
+
def diff_file(file)
|
72
|
+
original_version, changed_version = replace_file(file)
|
73
|
+
Differ.diff_by_line(changed_version, original_version).format_as :plain
|
74
|
+
end
|
75
|
+
|
76
|
+
def diff
|
77
|
+
files.each do |file|
|
78
|
+
replacement_number = 0
|
79
|
+
|
80
|
+
diff_file(file).lines.each_slice(2) do |slice|
|
81
|
+
change_report[file.name][replacement_number][:changed] = slice[1]
|
82
|
+
replacement_number += 1
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
private
|
88
|
+
def file_list_cmd
|
89
|
+
"ack #{find} -l #{@options.to_command_line}"
|
90
|
+
end
|
91
|
+
|
92
|
+
def lines_to_change_cmd(file)
|
93
|
+
"ack #{find} #{file} /dev/null"
|
94
|
+
end
|
95
|
+
|
96
|
+
def change_file_cmd(file)
|
97
|
+
"sed #{in_place} -e #{substitution} #{file.name} #{redirection}"
|
98
|
+
end
|
99
|
+
|
100
|
+
def tmp_file
|
101
|
+
"./far.tmp"
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Far::Replacer do
|
4
|
+
before(:each) do
|
5
|
+
@replacer = Far::Replacer.new 's/cats/dogs', {:ignore_dir => "spec"}
|
6
|
+
@replacer2 = Far::Replacer.new 's/Cool\:\:Guy/Cool\:\:Dude', {:ignore_dir => "spec",
|
7
|
+
:please => true,
|
8
|
+
:replace => true}
|
9
|
+
end
|
10
|
+
|
11
|
+
it "accepts a Vim-like substitution argument" do
|
12
|
+
expect(@replacer.substitution).to eq('s/cats/dogs/')
|
13
|
+
expect(@replacer2.substitution).to eq('s/Cool\:\:Guy/Cool\:\:Dude/')
|
14
|
+
end
|
15
|
+
|
16
|
+
it "parses the 'find' argument" do
|
17
|
+
expect(@replacer.find).to eq('cats')
|
18
|
+
expect(@replacer2.find).to eq('Cool\:\:Guy')
|
19
|
+
end
|
20
|
+
|
21
|
+
it "parses the 'replace' argument" do
|
22
|
+
expect(@replacer.replace).to eq('cats')
|
23
|
+
expect(@replacer2.replace).to eq('Cool\:\:Dude')
|
24
|
+
end
|
25
|
+
|
26
|
+
it "gets file list" do
|
27
|
+
expect(@replacer.file_list).to eq ["example_files/cats.tirade"]
|
28
|
+
expect(@replacer2.file_list).to eq ["example_files/everyone.rb", "example_files/people.rb"]
|
29
|
+
end
|
30
|
+
|
31
|
+
it "gets file list" do
|
32
|
+
expect(@replacer.file_list).to eq ["example_files/cats.tirade"]
|
33
|
+
expect(@replacer2.file_list).to eq ["example_files/everyone.rb", "example_files/people.rb"]
|
34
|
+
end
|
35
|
+
|
36
|
+
it "is dry run if --please --replace not passed" do
|
37
|
+
expect(@replacer.dry_run?).to be true
|
38
|
+
expect(@replacer2.dry_run?).to be false
|
39
|
+
end
|
40
|
+
|
41
|
+
it "is run if --please --replace is passed" do
|
42
|
+
expect(@replacer.run?).to be false
|
43
|
+
expect(@replacer2.run?).to be true
|
44
|
+
end
|
45
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
require "pry"
|
2
|
+
require "differ"
|
3
|
+
|
4
|
+
# Requires supporting ruby files with custom matchers and macros, etc,
|
5
|
+
# in spec/support/ and its subdirectories.
|
6
|
+
Dir[File.expand_path("./lib/**/*.rb")].each { |f| require f }
|
7
|
+
Dir[File.expand_path("./spec/support/**/*.rb")].each { |f| require f }
|
metadata
ADDED
@@ -0,0 +1,197 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: far
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.2
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Brett Shollenberger
|
8
|
+
- Zach MacHardy
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2014-07-26 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: differ
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
requirements:
|
18
|
+
- - ">="
|
19
|
+
- !ruby/object:Gem::Version
|
20
|
+
version: '0'
|
21
|
+
type: :runtime
|
22
|
+
prerelease: false
|
23
|
+
version_requirements: !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - ">="
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
version: '0'
|
28
|
+
- !ruby/object:Gem::Dependency
|
29
|
+
name: shoulda
|
30
|
+
requirement: !ruby/object:Gem::Requirement
|
31
|
+
requirements:
|
32
|
+
- - ">="
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: '0'
|
35
|
+
type: :development
|
36
|
+
prerelease: false
|
37
|
+
version_requirements: !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- - ">="
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
version: '0'
|
42
|
+
- !ruby/object:Gem::Dependency
|
43
|
+
name: rdoc
|
44
|
+
requirement: !ruby/object:Gem::Requirement
|
45
|
+
requirements:
|
46
|
+
- - "~>"
|
47
|
+
- !ruby/object:Gem::Version
|
48
|
+
version: '3.12'
|
49
|
+
type: :development
|
50
|
+
prerelease: false
|
51
|
+
version_requirements: !ruby/object:Gem::Requirement
|
52
|
+
requirements:
|
53
|
+
- - "~>"
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: '3.12'
|
56
|
+
- !ruby/object:Gem::Dependency
|
57
|
+
name: bundler
|
58
|
+
requirement: !ruby/object:Gem::Requirement
|
59
|
+
requirements:
|
60
|
+
- - "~>"
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: '1.0'
|
63
|
+
type: :development
|
64
|
+
prerelease: false
|
65
|
+
version_requirements: !ruby/object:Gem::Requirement
|
66
|
+
requirements:
|
67
|
+
- - "~>"
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '1.0'
|
70
|
+
- !ruby/object:Gem::Dependency
|
71
|
+
name: jeweler
|
72
|
+
requirement: !ruby/object:Gem::Requirement
|
73
|
+
requirements:
|
74
|
+
- - "~>"
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: 2.0.1
|
77
|
+
type: :development
|
78
|
+
prerelease: false
|
79
|
+
version_requirements: !ruby/object:Gem::Requirement
|
80
|
+
requirements:
|
81
|
+
- - "~>"
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
version: 2.0.1
|
84
|
+
- !ruby/object:Gem::Dependency
|
85
|
+
name: simplecov
|
86
|
+
requirement: !ruby/object:Gem::Requirement
|
87
|
+
requirements:
|
88
|
+
- - ">="
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
version: '0'
|
91
|
+
type: :development
|
92
|
+
prerelease: false
|
93
|
+
version_requirements: !ruby/object:Gem::Requirement
|
94
|
+
requirements:
|
95
|
+
- - ">="
|
96
|
+
- !ruby/object:Gem::Version
|
97
|
+
version: '0'
|
98
|
+
- !ruby/object:Gem::Dependency
|
99
|
+
name: rspec
|
100
|
+
requirement: !ruby/object:Gem::Requirement
|
101
|
+
requirements:
|
102
|
+
- - ">="
|
103
|
+
- !ruby/object:Gem::Version
|
104
|
+
version: '0'
|
105
|
+
type: :development
|
106
|
+
prerelease: false
|
107
|
+
version_requirements: !ruby/object:Gem::Requirement
|
108
|
+
requirements:
|
109
|
+
- - ">="
|
110
|
+
- !ruby/object:Gem::Version
|
111
|
+
version: '0'
|
112
|
+
- !ruby/object:Gem::Dependency
|
113
|
+
name: guard-rspec
|
114
|
+
requirement: !ruby/object:Gem::Requirement
|
115
|
+
requirements:
|
116
|
+
- - ">="
|
117
|
+
- !ruby/object:Gem::Version
|
118
|
+
version: '0'
|
119
|
+
type: :development
|
120
|
+
prerelease: false
|
121
|
+
version_requirements: !ruby/object:Gem::Requirement
|
122
|
+
requirements:
|
123
|
+
- - ">="
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
version: '0'
|
126
|
+
- !ruby/object:Gem::Dependency
|
127
|
+
name: terminal-notifier-guard
|
128
|
+
requirement: !ruby/object:Gem::Requirement
|
129
|
+
requirements:
|
130
|
+
- - ">="
|
131
|
+
- !ruby/object:Gem::Version
|
132
|
+
version: '0'
|
133
|
+
type: :development
|
134
|
+
prerelease: false
|
135
|
+
version_requirements: !ruby/object:Gem::Requirement
|
136
|
+
requirements:
|
137
|
+
- - ">="
|
138
|
+
- !ruby/object:Gem::Version
|
139
|
+
version: '0'
|
140
|
+
description: Recursively find and replace in your current directory.
|
141
|
+
email: brett.shollenberger@gmail.com
|
142
|
+
executables:
|
143
|
+
- far
|
144
|
+
extensions: []
|
145
|
+
extra_rdoc_files:
|
146
|
+
- LICENSE.txt
|
147
|
+
- README.md
|
148
|
+
files:
|
149
|
+
- ".document"
|
150
|
+
- ".rspec"
|
151
|
+
- Gemfile
|
152
|
+
- Gemfile.lock
|
153
|
+
- Guardfile
|
154
|
+
- LICENSE.txt
|
155
|
+
- README.md
|
156
|
+
- Rakefile
|
157
|
+
- VERSION
|
158
|
+
- authors.cool_guys
|
159
|
+
- bin/far
|
160
|
+
- example_files/cats.tirade
|
161
|
+
- example_files/everyone.rb
|
162
|
+
- example_files/people.rb
|
163
|
+
- lib/far.rb
|
164
|
+
- lib/far/change_report.rb
|
165
|
+
- lib/far/differ.rb
|
166
|
+
- lib/far/file.rb
|
167
|
+
- lib/far/option.rb
|
168
|
+
- lib/far/options.rb
|
169
|
+
- lib/far/replacer.rb
|
170
|
+
- spec/lib/far/options_spec.rb
|
171
|
+
- spec/lib/far/replacer_spec.rb
|
172
|
+
- spec/spec_helper.rb
|
173
|
+
homepage: http://github.com/brettshollenberger/far
|
174
|
+
licenses:
|
175
|
+
- MIT
|
176
|
+
metadata: {}
|
177
|
+
post_install_message:
|
178
|
+
rdoc_options: []
|
179
|
+
require_paths:
|
180
|
+
- lib
|
181
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
182
|
+
requirements:
|
183
|
+
- - ">="
|
184
|
+
- !ruby/object:Gem::Version
|
185
|
+
version: '0'
|
186
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
187
|
+
requirements:
|
188
|
+
- - ">="
|
189
|
+
- !ruby/object:Gem::Version
|
190
|
+
version: '0'
|
191
|
+
requirements: []
|
192
|
+
rubyforge_project:
|
193
|
+
rubygems_version: 2.2.2
|
194
|
+
signing_key:
|
195
|
+
specification_version: 4
|
196
|
+
summary: Project-wide find and replace.
|
197
|
+
test_files: []
|