sherlock 0.1.1 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|