sherlock 0.1.1 → 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/collection.rb +8 -8
- data/lib/collection/base.rb +75 -76
- data/lib/collection/files.rb +77 -62
- data/lib/collection/lines.rb +32 -32
- data/lib/collection/matched_line.rb +56 -56
- data/lib/core_ext.rb +42 -42
- data/lib/latex.rb +55 -44
- data/lib/sherlock.rb +23 -32
- data/lib/version.rb +10 -0
- data/spec/collection/base_spec.rb +139 -141
- data/spec/collection/files_spec.rb +59 -46
- data/spec/collection/lines_spec.rb +1 -1
- data/spec/collection/matched_line_spec.rb +1 -1
- data/spec/fixtures/simple/lines.txt +5 -5
- data/spec/fixtures/simple/lorem.txt +18 -18
- data/spec/{detective_spec.rb → sherlock_spec.rb} +14 -14
- data/spec/spec_helper.rb +38 -38
- metadata +8 -9
data/lib/collection.rb
CHANGED
@@ -1,8 +1,8 @@
|
|
1
|
-
#!/usr/bin/env ruby -wKU
|
2
|
-
|
3
|
-
sub_dir = File.basename(__FILE__, '.rb')
|
4
|
-
all_files = Dir[File.join(File.dirname(__FILE__), sub_dir, '*.rb')]
|
5
|
-
all_files.sort.map { |f| File.basename(f, '.rb') }.each do |_module|
|
6
|
-
require File.join(File.dirname(__FILE__), sub_dir, _module)
|
7
|
-
end
|
8
|
-
|
1
|
+
#!/usr/bin/env ruby -wKU
|
2
|
+
|
3
|
+
sub_dir = File.basename(__FILE__, '.rb')
|
4
|
+
all_files = Dir[File.join(File.dirname(__FILE__), sub_dir, '*.rb')]
|
5
|
+
all_files.sort.map { |f| File.basename(f, '.rb') }.each do |_module|
|
6
|
+
require File.join(File.dirname(__FILE__), sub_dir, _module)
|
7
|
+
end
|
8
|
+
|
data/lib/collection/base.rb
CHANGED
@@ -1,76 +1,75 @@
|
|
1
|
-
#!/usr/bin/env ruby -wKU
|
2
|
-
|
3
|
-
module Sherlock
|
4
|
-
module Collection
|
5
|
-
class Base < Array
|
6
|
-
def initialize(arr = [], opts = {})
|
7
|
-
super(0)
|
8
|
-
self.concat filter_array_by_options(arr, opts)
|
9
|
-
end
|
10
|
-
|
11
|
-
# Returns the first value of the collection (matching the value, if given).
|
12
|
-
def first(*value)
|
13
|
-
item = if value.empty?
|
14
|
-
super
|
15
|
-
else
|
16
|
-
filter(value)[0]
|
17
|
-
end
|
18
|
-
new([item])
|
19
|
-
end
|
20
|
-
|
21
|
-
# Returns a collection with all files matching the
|
22
|
-
# given pattern.
|
23
|
-
def select_items_matching(*pattern)
|
24
|
-
opts = pattern.last.is_a?(Hash) ? pattern.pop : {}
|
25
|
-
pattern = [pattern].flatten
|
26
|
-
arr = select { |f| pattern.empty? || matching?(f, pattern) }
|
27
|
-
arr = filter_array_by_options(arr, opts)
|
28
|
-
new(arr, opts)
|
29
|
-
end
|
30
|
-
alias filter select_items_matching
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
arr
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
}
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
end
|
1
|
+
#!/usr/bin/env ruby -wKU
|
2
|
+
|
3
|
+
module Sherlock
|
4
|
+
module Collection
|
5
|
+
class Base < Array
|
6
|
+
def initialize(arr = [], opts = {})
|
7
|
+
super(0)
|
8
|
+
self.concat filter_array_by_options(arr, opts)
|
9
|
+
end
|
10
|
+
|
11
|
+
# Returns the first value of the collection (matching the value, if given).
|
12
|
+
def first(*value)
|
13
|
+
item = if value.empty?
|
14
|
+
super
|
15
|
+
else
|
16
|
+
filter(value)[0]
|
17
|
+
end
|
18
|
+
new([item])
|
19
|
+
end
|
20
|
+
|
21
|
+
# Returns a collection with all files matching the
|
22
|
+
# given pattern.
|
23
|
+
def select_items_matching(*pattern)
|
24
|
+
opts = pattern.last.is_a?(Hash) ? pattern.pop : {}
|
25
|
+
pattern = [pattern].flatten
|
26
|
+
arr = select { |f| pattern.empty? || matching?(f, pattern) }
|
27
|
+
arr = filter_array_by_options(arr, opts)
|
28
|
+
new(arr, opts)
|
29
|
+
end
|
30
|
+
alias filter select_items_matching
|
31
|
+
|
32
|
+
# Filters the collection, if the first argument is an Array, Regexp, String or Hash.
|
33
|
+
def [](value, *args)
|
34
|
+
case value
|
35
|
+
when String, Regexp, Array, Hash
|
36
|
+
filter(value, *args)
|
37
|
+
else
|
38
|
+
super(value)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def -(other)
|
43
|
+
new(super)
|
44
|
+
end
|
45
|
+
|
46
|
+
def +(other)
|
47
|
+
new(super.uniq)
|
48
|
+
end
|
49
|
+
|
50
|
+
def &(other)
|
51
|
+
new(super)
|
52
|
+
end
|
53
|
+
|
54
|
+
def |(other)
|
55
|
+
new(super)
|
56
|
+
end
|
57
|
+
|
58
|
+
private
|
59
|
+
|
60
|
+
def filter_array_by_options(arr, opts = {})
|
61
|
+
arr = arr.select { |f| matching?(f, opts[:only]) } if opts[:only]
|
62
|
+
arr = arr.reject { |f| matching?(f, opts[:except]) } if opts[:except]
|
63
|
+
arr
|
64
|
+
end
|
65
|
+
|
66
|
+
def matching?(obj, string_or_regexp_or_array)
|
67
|
+
[string_or_regexp_or_array].flatten.detect { |pattern| obj.match(pattern) }
|
68
|
+
end
|
69
|
+
|
70
|
+
def new(*args)
|
71
|
+
self.class.new(*args)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
data/lib/collection/files.rb
CHANGED
@@ -1,62 +1,77 @@
|
|
1
|
-
#!/usr/bin/env ruby -wKU
|
2
|
-
|
3
|
-
module Sherlock
|
4
|
-
module Collection
|
5
|
-
class Files < Base
|
6
|
-
|
7
|
-
def initialize(glob_or_regex, opts = {})
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
end
|
59
|
-
alias
|
60
|
-
|
61
|
-
|
62
|
-
|
1
|
+
#!/usr/bin/env ruby -wKU
|
2
|
+
|
3
|
+
module Sherlock
|
4
|
+
module Collection
|
5
|
+
class Files < Base
|
6
|
+
|
7
|
+
def initialize(glob_or_regex, opts = {})
|
8
|
+
case glob_or_regex
|
9
|
+
when Hash
|
10
|
+
opts = glob_or_regex
|
11
|
+
when Array
|
12
|
+
opts[:arr] = glob_or_regex
|
13
|
+
when String
|
14
|
+
opts[:glob] = glob_or_regex
|
15
|
+
when Symbol
|
16
|
+
opts[:glob] = "**/*.#{glob_or_regex}"
|
17
|
+
when Regexp
|
18
|
+
if opts[:only]
|
19
|
+
raise "Cannot use regexp and :only-option at the same time."
|
20
|
+
else
|
21
|
+
opts[:only] = glob_or_regex
|
22
|
+
end
|
23
|
+
end
|
24
|
+
opts = {:glob => '**/*'}.merge(opts)
|
25
|
+
arr = opts[:arr] || Dir[opts[:glob]]
|
26
|
+
super(arr, opts)
|
27
|
+
end
|
28
|
+
|
29
|
+
# Returns a Lines collection with all lines containing the
|
30
|
+
# given content / matching the given pattern.
|
31
|
+
def collect_lines_matching(pattern = //, &block)
|
32
|
+
pattern = [pattern].flatten
|
33
|
+
lines = Lines.new
|
34
|
+
self.each { |f|
|
35
|
+
io = File.open(f)
|
36
|
+
io.each { |line|
|
37
|
+
if matching?(line, pattern)
|
38
|
+
lines << MatchedLine.new(line, :file => f, :line_number => io.lineno, :pattern => pattern)
|
39
|
+
end
|
40
|
+
}
|
41
|
+
}
|
42
|
+
lines
|
43
|
+
end
|
44
|
+
alias lines collect_lines_matching
|
45
|
+
|
46
|
+
def not_blank_lines
|
47
|
+
lines(/\S+/)
|
48
|
+
end
|
49
|
+
|
50
|
+
def blank_lines
|
51
|
+
lines(/^\s+$/)
|
52
|
+
end
|
53
|
+
|
54
|
+
# Returns a Files collection with all files containing the
|
55
|
+
# given content / matching the given pattern.
|
56
|
+
def select_files_containing(pattern)
|
57
|
+
select_files(pattern, :select)
|
58
|
+
end
|
59
|
+
alias containing select_files_containing
|
60
|
+
|
61
|
+
# Returns a Files collection with all files not containing the
|
62
|
+
# given content / matching the given pattern.
|
63
|
+
def select_files_not_containing(pattern)
|
64
|
+
select_files(pattern, :reject)
|
65
|
+
end
|
66
|
+
alias not_containing select_files_not_containing
|
67
|
+
|
68
|
+
private
|
69
|
+
|
70
|
+
def select_files(pattern, method)
|
71
|
+
pattern = [pattern].flatten
|
72
|
+
arr = send(method) { |f| matching?(File.read(f), pattern) }
|
73
|
+
new(arr)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
data/lib/collection/lines.rb
CHANGED
@@ -1,33 +1,33 @@
|
|
1
|
-
#!/usr/bin/env ruby -wKU
|
2
|
-
|
3
|
-
module Sherlock
|
4
|
-
module Collection
|
5
|
-
class Lines < Base
|
6
|
-
# Executes gsub on all lines in the collection and returns
|
7
|
-
# the modified collection.
|
8
|
-
def gsub(*args, &block)
|
9
|
-
arr = map { |line| line.gsub(*args, &block) }
|
10
|
-
new(arr)
|
11
|
-
end
|
12
|
-
|
13
|
-
# Returns an array of the lines' match_data objects without the
|
14
|
-
# 'overall' match (the first element of the MatchData object).
|
15
|
-
def matches
|
16
|
-
map { |line| line.match_data[1..line.match_data.length-1] }
|
17
|
-
end
|
18
|
-
|
19
|
-
def new(arr, opts = {}) # :nodoc:
|
20
|
-
self.class.new(arr)
|
21
|
-
end
|
22
|
-
|
23
|
-
def save!
|
24
|
-
sort_by { |line| line.line_number }.reverse.each(&:save!)
|
25
|
-
end
|
26
|
-
|
27
|
-
def to_s
|
28
|
-
map { |line| (line.changed? ? '[C] ' : '[ ] ') + line.inspect }.join("\n")
|
29
|
-
end
|
30
|
-
alias inspect to_s
|
31
|
-
end
|
32
|
-
end
|
1
|
+
#!/usr/bin/env ruby -wKU
|
2
|
+
|
3
|
+
module Sherlock
|
4
|
+
module Collection
|
5
|
+
class Lines < Base
|
6
|
+
# Executes gsub on all lines in the collection and returns
|
7
|
+
# the modified collection.
|
8
|
+
def gsub(*args, &block)
|
9
|
+
arr = map { |line| line.gsub(*args, &block) }
|
10
|
+
new(arr)
|
11
|
+
end
|
12
|
+
|
13
|
+
# Returns an array of the lines' match_data objects without the
|
14
|
+
# 'overall' match (the first element of the MatchData object).
|
15
|
+
def matches
|
16
|
+
map { |line| line.match_data[1..line.match_data.length-1] }
|
17
|
+
end
|
18
|
+
|
19
|
+
def new(arr, opts = {}) # :nodoc:
|
20
|
+
self.class.new(arr)
|
21
|
+
end
|
22
|
+
|
23
|
+
def save!
|
24
|
+
sort_by { |line| line.line_number }.reverse.each(&:save!)
|
25
|
+
end
|
26
|
+
|
27
|
+
def to_s
|
28
|
+
map { |line| (line.changed? ? '[C] ' : '[ ] ') + line.inspect }.join("\n")
|
29
|
+
end
|
30
|
+
alias inspect to_s
|
31
|
+
end
|
32
|
+
end
|
33
33
|
end
|
@@ -1,57 +1,57 @@
|
|
1
|
-
#!/usr/bin/env ruby -wKU
|
2
|
-
|
3
|
-
module Sherlock
|
4
|
-
module Collection
|
5
|
-
|
6
|
-
# ==== Attributes
|
7
|
-
#
|
8
|
-
# * <tt>:file</tt>
|
9
|
-
# * <tt>:line_number</tt>
|
10
|
-
# * <tt>:pattern</tt>
|
11
|
-
#
|
12
|
-
class MatchedLine < String
|
13
|
-
attr_accessor :attributes
|
14
|
-
|
15
|
-
def initialize(line, _attributes = {})
|
16
|
-
super(line)
|
17
|
-
self.attributes = {:original => line}.merge(_attributes)
|
18
|
-
end
|
19
|
-
|
20
|
-
def changed?
|
21
|
-
attributes[:original] != self
|
22
|
-
end
|
23
|
-
|
24
|
-
def gsub(*args, &block)
|
25
|
-
self.class.new(super, attributes)
|
26
|
-
end
|
27
|
-
|
28
|
-
def match_data
|
29
|
-
attributes[:pattern].each do |p|
|
30
|
-
if m = self.match(p)
|
31
|
-
return m
|
32
|
-
end
|
33
|
-
end
|
34
|
-
nil
|
35
|
-
end
|
36
|
-
|
37
|
-
def method_missing(m)
|
38
|
-
if attributes && value = attributes[m.to_s.intern]
|
39
|
-
value
|
40
|
-
else
|
41
|
-
super
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
def save!
|
46
|
-
all_lines = File.open(file, 'r') { |f| f.readlines }
|
47
|
-
index = line_number - 1
|
48
|
-
if original == all_lines[index]
|
49
|
-
all_lines[index] = self.to_s
|
50
|
-
else
|
51
|
-
raise "File seems modified: #{file}"
|
52
|
-
end
|
53
|
-
File.open(file, 'w') {|f| f.write(all_lines) }
|
54
|
-
end
|
55
|
-
end
|
56
|
-
end
|
1
|
+
#!/usr/bin/env ruby -wKU
|
2
|
+
|
3
|
+
module Sherlock
|
4
|
+
module Collection
|
5
|
+
|
6
|
+
# ==== Attributes
|
7
|
+
#
|
8
|
+
# * <tt>:file</tt>
|
9
|
+
# * <tt>:line_number</tt>
|
10
|
+
# * <tt>:pattern</tt>
|
11
|
+
#
|
12
|
+
class MatchedLine < String
|
13
|
+
attr_accessor :attributes
|
14
|
+
|
15
|
+
def initialize(line, _attributes = {})
|
16
|
+
super(line)
|
17
|
+
self.attributes = {:original => line}.merge(_attributes)
|
18
|
+
end
|
19
|
+
|
20
|
+
def changed?
|
21
|
+
attributes[:original] != self
|
22
|
+
end
|
23
|
+
|
24
|
+
def gsub(*args, &block)
|
25
|
+
self.class.new(super, attributes)
|
26
|
+
end
|
27
|
+
|
28
|
+
def match_data
|
29
|
+
attributes[:pattern].each do |p|
|
30
|
+
if m = self.match(p)
|
31
|
+
return m
|
32
|
+
end
|
33
|
+
end
|
34
|
+
nil
|
35
|
+
end
|
36
|
+
|
37
|
+
def method_missing(m)
|
38
|
+
if attributes && value = attributes[m.to_s.intern]
|
39
|
+
value
|
40
|
+
else
|
41
|
+
super
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def save!
|
46
|
+
all_lines = File.open(file, 'r') { |f| f.readlines }
|
47
|
+
index = line_number - 1
|
48
|
+
if original == all_lines[index]
|
49
|
+
all_lines[index] = self.to_s
|
50
|
+
else
|
51
|
+
raise "File seems modified: #{file}"
|
52
|
+
end
|
53
|
+
File.open(file, 'w') {|f| f.write(all_lines) }
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
57
|
end
|