what_now 0.0.5 → 0.0.6

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c129b4ea1aed4491608b1aa54462eb469f06f69b
4
- data.tar.gz: 25a68c0f5b0fd9048c495cdb18447050f846a43f
3
+ metadata.gz: 544af77f51167e74302cbd4bf98ca400d2b9a695
4
+ data.tar.gz: d89bba664223614756de397c960463218e483f36
5
5
  SHA512:
6
- metadata.gz: 16dec7d805e9ba4759b3b2835b597e7e31f57bed8828b74dbd3d00d8a8116db1e0d1425e881e12a1027c06aa962ea51c73ad3386abdf8fb3b5748107cab4652a
7
- data.tar.gz: 73ef733a215b66af92f7d3fadbc9b9deaed33be14f273480a4601273d2650a289ae05a29f17969e510e9e4a6855e08afb9c61203466ee2706fb8846cb1acb739
6
+ metadata.gz: 5f584e61ff6da4c4d6fcd99da6740086bff4cf0e3ffd10ef490b0268d6aed26d2bce98eee9a9586b0bf87874eaa23a552d5fa2a347c23e637c87944c02734c3c
7
+ data.tar.gz: 51ccf2fb7e922057fe0fdd0d2cce6c35228bcace881fef56572c87d0ccdbdfe967fbbc1c716ebb1288a58151e5709828211e93d8e55a6e9c39da1fdce85a2695
data/README.md CHANGED
@@ -26,10 +26,18 @@ Will return all the todos in the following format inside files:
26
26
 
27
27
  * TODO this is the text
28
28
 
29
- Where 'this is the text' will be returned, together with the path and line number
30
-
31
- You can also use the options *--dir, -d*, in order to specify the directory in which
32
- todos are going to be looked for, and *--ext -e* for checking only certain file extension
33
- (without prepending the '.', this means, call *--ext rb* instead of *--ext .rb*).
34
- You can optionally ignore casing for your *TODO* comments, in which case you may
35
- pass the option *--ignorecase, -i*.
29
+ Where 'this is the text' will be returned, together with the relative path and line number
30
+
31
+ The output is colored, but if redirected to a non TTY device, a simpler, colorless format
32
+ will be used.
33
+
34
+ Options
35
+ -------
36
+ * *--dir, -d*: Specify the directory in which to search the TODO's. It can be an absolute
37
+ path of anyhwere in the system, or a relative path to the current directory.
38
+ * *--ext, -e*: Specify the extension of the files to consider. You can pass it with or without
39
+ the dot (.rb or rb are both valid).
40
+ * *--regex, -r*: Specify the regular expression (Perl-like) that the file names
41
+ must match.
42
+ * *--ignorecase, -i*: When passed, this options matches both the strings *TODO* and *todo*.
43
+ By default, this options is deactivated.
data/bin/wnow CHANGED
@@ -2,21 +2,37 @@
2
2
  require 'thor'
3
3
  require 'colorize'
4
4
  require 'what_now'
5
+ require 'file_filter'
6
+ require 'pathname'
5
7
 
6
8
  class Wnow < Thor
9
+ include Filtering
7
10
  default_task :find
8
11
 
9
12
  desc 'find', 'search files in directory for todo elements (default command)'
10
13
  option :dir, aliases: '-d'
11
14
  option :ext, aliases: '-e'
15
+ option :regex, aliases: '-r'
12
16
  option :ignorecase, aliases: '-i'
13
17
  def find
18
+ # Directory handling
19
+ current_dir = Pathname.getwd
14
20
  dir = options[:dir] || Dir.pwd
15
- ext = options[:ext] ? "/**/*.#{options[:ext]}" : '/**/*.*'
16
- creator = TodoCreator.new(
17
- ignorecase: options[:ignorecase],
18
- pretty: STDOUT.tty?)
19
- TodoFinder.new(dir + ext, creator).find.each do |todo|
21
+ absolute_dir = Pathname.new(dir).expand_path.to_s
22
+
23
+ filter = NoDirectories
24
+ .chain(NoBinaries)
25
+ .chain(OnlyDirectory.new absolute_dir)
26
+ filter.chain(OnlyExtension.new options[:ext]) if options[:ext]
27
+ filter.chain(MatchRegex.new options[:regex]) if options[:regex]
28
+
29
+ relative_paths = Dir[absolute_dir + '/**/*'].map do |p|
30
+ Pathname.new(p).relative_path_from(current_dir).to_s
31
+ end
32
+ targets = filter.filter relative_paths
33
+
34
+ creator = TodoCreator.new(ignorecase: options[:ignorecase], pretty: STDOUT.tty?)
35
+ TodoFinder.new(targets, creator).find.each do |todo|
20
36
  puts todo
21
37
  puts if STDOUT.tty?
22
38
  end
@@ -0,0 +1,73 @@
1
+ # Module for handling filtering of
2
+ # files
3
+
4
+ require 'ptools'
5
+ require 'pathname'
6
+
7
+ module Filtering
8
+ class Filter
9
+ attr_reader :predicates
10
+
11
+ def initialize &predicate
12
+ @predicates = [predicate]
13
+ end
14
+
15
+ def apply file
16
+ @predicates.reduce(true) do |result, p|
17
+ result && p.call(file)
18
+ end
19
+ end
20
+
21
+ def chain other=nil
22
+ raise ArgumentError if (not other and not block_given?)
23
+ @predicates += other.predicates if other
24
+ @predicates << Proc.new if block_given?
25
+ self
26
+ end
27
+
28
+ def filter files
29
+ files.keep_if do |f|
30
+ self.apply f
31
+ end
32
+ end
33
+ end
34
+
35
+ NoDirectories = Filter.new do |path|
36
+ not File.directory? path
37
+ end
38
+
39
+ NoBinaries = Filter.new do |path|
40
+ not File.binary? path
41
+ end
42
+
43
+ class OnlyDirectory < Filter
44
+ def initialize subdirectory
45
+ base = Pathname.new(subdirectory).expand_path.to_s
46
+ @predicates = []
47
+ @predicates << proc do |path|
48
+ file = Pathname.new(path).expand_path.to_s
49
+ file.start_with? base
50
+ end
51
+ end
52
+ end
53
+
54
+ class OnlyExtension < Filter
55
+ def initialize ext
56
+ extension = ext.start_with?('.') ? ext[1..-1] : ext
57
+ @predicates = []
58
+ @predicates << proc do |path|
59
+ path.match(/\.#{extension}$/i) ? true : false
60
+ end
61
+ end
62
+ end
63
+
64
+ class MatchRegex < Filter
65
+ def initialize regex
66
+ @predicates = []
67
+ @predicates << proc do |path|
68
+ path.match(regex) ? true : false
69
+ end
70
+ end
71
+ end
72
+ end
73
+
data/lib/what_now.rb CHANGED
@@ -13,22 +13,15 @@ class TodoCreator
13
13
  def match(line, path, line_number)
14
14
  regex = @ignorecase ? /TODO:?\s*(.+)$/i : /TODO:?\s*(.+)$/
15
15
  text = regex.match(line)
16
- @todo_class.new(text[1], shortened_path(path), line_number) if text
16
+ @todo_class.new(text[1], path, line_number) if text
17
17
  rescue ArgumentError
18
18
  nil
19
19
  end
20
-
21
- private
22
- def shortened_path(path)
23
- path[Dir.pwd.length+1..path.length]
24
- end
25
20
  end
26
21
 
27
22
  class TodoFinder
28
- def initialize(pattern, creator)
29
- @paths = Dir[pattern].delete_if do |path|
30
- File.directory?(path) || File.binary?(path)
31
- end
23
+ def initialize(paths, creator)
24
+ @paths = paths
32
25
  @creator = creator
33
26
  end
34
27
 
@@ -0,0 +1,188 @@
1
+ require_relative 'spec_helper'
2
+ require 'pathname'
3
+ require 'fileutils'
4
+ require 'fakefs/safe'
5
+
6
+ module FakeFS
7
+ class File
8
+ def self.binary? file
9
+ file == '/sample/d2/f3'
10
+ end
11
+ end
12
+ end
13
+
14
+ FileFilter = Filtering::Filter
15
+
16
+ describe FileFilter do
17
+ subject do
18
+ FileFilter.new do |file|
19
+ true
20
+ end
21
+ end
22
+
23
+ describe 'public interface' do
24
+ it 'must respond to apply' do
25
+ subject.must_respond_to :apply
26
+ end
27
+
28
+ it 'must respond to chain' do
29
+ subject.must_respond_to :chain
30
+ end
31
+
32
+ it 'must respond to filter' do
33
+ subject.must_respond_to :filter
34
+ end
35
+ end
36
+
37
+ describe '#apply' do
38
+ it 'is expected to return result of predicate' do
39
+ subject.apply(nil).must_equal true
40
+ end
41
+ end
42
+
43
+ describe '#chain' do
44
+ subject do
45
+ FileFilter.new do |x|
46
+ x > 0
47
+ end.chain do |x|
48
+ x % 2 == 0
49
+ end
50
+ end
51
+
52
+ it 'returns an instance of FileFilter' do
53
+ subject.must_be_instance_of FileFilter
54
+ end
55
+
56
+ it 'applies all filters when called' do
57
+ subject.filter([-2, -1, 0, 1, 2, 3, 4]).must_equal [2, 4]
58
+ end
59
+
60
+ describe 'with no arguments' do
61
+ it 'raises an exception' do
62
+ proc do
63
+ FileFilter.new do
64
+ true
65
+ end.chain
66
+ end.must_raise ArgumentError
67
+ end
68
+ end
69
+
70
+ describe 'with instance of filter' do
71
+ subject do
72
+ f1 = FileFilter.new do |f|
73
+ f % 2 == 0
74
+ end
75
+ FileFilter.new do |f|
76
+ f > 0
77
+ end.chain f1
78
+ end
79
+
80
+ it 'returns an instance of Filter' do
81
+ subject.chain(FileFilter.new { |x| x > 0 }).must_be_instance_of FileFilter
82
+ end
83
+
84
+ it 'applies all filters when called' do
85
+ [-2, -1, 0, 1, 2, 3, 4].keep_if do |n|
86
+ subject.apply(n)
87
+ end.must_equal [2, 4]
88
+ end
89
+ end
90
+ end
91
+
92
+ describe '#filter' do
93
+ subject do
94
+ FileFilter.new do |x|
95
+ x > 2
96
+ end
97
+ end
98
+
99
+ it 'correctly filters the elements' do
100
+ subject.filter([-2, -1, 0, 1, 2, 3, 4]).must_equal [3, 4]
101
+ end
102
+ end
103
+ end
104
+
105
+ describe 'specific filters' do
106
+ before do
107
+ FakeFS.activate!
108
+ FileUtils.mkdir_p 'sample/d1'
109
+ FileUtils.mkdir_p 'sample/d2'
110
+ FileUtils.touch 'sample/d1/f1.rb'
111
+ FileUtils.touch 'sample/d1/f2_rb'
112
+ FileUtils.touch 'sample/d2/f3'
113
+ end
114
+
115
+ after do
116
+ FakeFS.deactivate!
117
+ end
118
+
119
+ let :paths do
120
+ Dir['sample/**/*']
121
+ end
122
+
123
+ describe 'directory filter' do
124
+ subject do
125
+ Filtering::NoDirectories
126
+ end
127
+
128
+ it 'only returns files' do
129
+ subject.filter(paths).sort!.must_equal ['/sample/d1/f1.rb', '/sample/d1/f2_rb', '/sample/d2/f3'].sort!
130
+ end
131
+ end
132
+
133
+ describe 'binary filter' do
134
+ subject do
135
+ Filtering::NoBinaries
136
+ end
137
+
138
+ it 'only returns non-binaries' do
139
+ subject.filter(paths).wont_include '/sample/d2/f3'
140
+ end
141
+ end
142
+
143
+ describe 'directory filter' do
144
+ subject do
145
+ Filtering::OnlyDirectory.new '/sample/d1'
146
+ end
147
+
148
+ it 'only returns elements in given subdirectory' do
149
+ subject.filter(paths).sort!.must_equal ['/sample/d1', '/sample/d1/f1.rb', '/sample/d1/f2_rb'].sort!
150
+ end
151
+ end
152
+
153
+ describe 'extension filter' do
154
+ subject do
155
+ Filtering::OnlyExtension.new 'rb'
156
+ end
157
+
158
+ it 'only returns elements with the given extension' do
159
+ subject.filter(paths).sort!.must_equal ['/sample/d1/f1.rb']
160
+ end
161
+
162
+ it 'still returns extension when extension specified with dot' do
163
+ Filtering::OnlyExtension.new('.rb').filter(paths).must_equal ['/sample/d1/f1.rb']
164
+ end
165
+
166
+ it 'does not match a file that ends with same letter as extension' do
167
+ subject.filter(paths).wont_include '/sample/d1/f2_rb'
168
+ end
169
+
170
+ it 'treats the extension case insensitively' do
171
+ Filtering::OnlyExtension.new('RB').filter(paths).must_equal ['/sample/d1/f1.rb']
172
+ end
173
+ end
174
+
175
+ describe 'regex filter' do
176
+ subject do
177
+ Filtering::MatchRegex.new(/f[0-9]/)
178
+ end
179
+
180
+ it 'only returns elements that match regular expression' do
181
+ subject.filter(paths).sort!.must_equal ['/sample/d1/f1.rb', '/sample/d1/f2_rb', '/sample/d2/f3'].sort!
182
+ end
183
+
184
+ it 'accepts a string as a regular expression' do
185
+ Filtering::MatchRegex.new('f[0-9]').filter(paths).sort!.must_equal ['/sample/d1/f1.rb', '/sample/d1/f2_rb', '/sample/d2/f3'].sort!
186
+ end
187
+ end
188
+ end
@@ -56,8 +56,8 @@ end
56
56
  describe TodoFinder do
57
57
  describe 'search single file' do
58
58
  subject do
59
- path = File.dirname(__FILE__) + '/example_file.txt'
60
- TodoFinder.new(path, TodoCreator.new).find
59
+ paths = Dir[File.dirname(__FILE__) + '/example_file.txt']
60
+ TodoFinder.new(paths, TodoCreator.new).find
61
61
  end
62
62
 
63
63
  it 'found 2 todos' do
@@ -74,15 +74,17 @@ describe TodoFinder do
74
74
 
75
75
  describe 'search with a pattern' do
76
76
  it 'considers only specified pattern' do
77
+ paths = Dir[File.dirname(__FILE__)+'/**/*.txt']
77
78
  results = TodoFinder.new(
78
- File.dirname(__FILE__)+'/**/*.txt',
79
+ paths,
79
80
  TodoCreator.new).find
80
81
  results.length.must_equal 2
81
82
  end
82
83
 
83
84
  it 'returns empty array if nothing was found' do
85
+ paths = Dir[File.dirname(__FILE__)+'/**/*.mooo']
84
86
  results = TodoFinder.new(
85
- File.dirname(__FILE__)+'/**/*.mooo',
87
+ paths,
86
88
  TodoCreator.new).find
87
89
  results.must_equal []
88
90
  end
data/what_now.gemspec CHANGED
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'what_now'
3
- s.version = '0.0.5'
3
+ s.version = '0.0.6'
4
4
  s.date = '2014-02-27'
5
5
  s.summary = 'Find todo comments in your code'
6
6
  s.description = 'Executable for finding todo comments on directories'
@@ -19,4 +19,5 @@ Gem::Specification.new do |s|
19
19
 
20
20
  s.add_development_dependency 'minitest-reporters'
21
21
  s.add_development_dependency 'rake'
22
+ s.add_development_dependency 'fakefs'
22
23
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: what_now
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.5
4
+ version: 0.0.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Edgar Cabrera
@@ -80,6 +80,20 @@ dependencies:
80
80
  - - ">="
81
81
  - !ruby/object:Gem::Version
82
82
  version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: fakefs
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
83
97
  description: Executable for finding todo comments on directories
84
98
  email: edgar@cafeinacode.com
85
99
  executables:
@@ -90,9 +104,11 @@ files:
90
104
  - LICENSE
91
105
  - README.md
92
106
  - bin/wnow
107
+ - lib/file_filter.rb
93
108
  - lib/todo.rb
94
109
  - lib/what_now.rb
95
110
  - spec/example_file.txt
111
+ - spec/file_filter_spec.rb
96
112
  - spec/spec_helper.rb
97
113
  - spec/todo_spec.rb
98
114
  - spec/what_now_spec.rb
@@ -126,3 +142,4 @@ test_files:
126
142
  - spec/example_file.txt
127
143
  - spec/spec_helper.rb
128
144
  - spec/todo_spec.rb
145
+ - spec/file_filter_spec.rb