millisami-thor 0.14.6

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.
Files changed (82) hide show
  1. data/.autotest +8 -0
  2. data/.gemtest +0 -0
  3. data/.gitignore +9 -0
  4. data/.rspec +1 -0
  5. data/CHANGELOG.rdoc +103 -0
  6. data/Gemfile +11 -0
  7. data/LICENSE.md +20 -0
  8. data/README.md +26 -0
  9. data/Thorfile +13 -0
  10. data/bin/rake2thor +86 -0
  11. data/bin/thor +6 -0
  12. data/lib/thor/actions/create_file.rb +105 -0
  13. data/lib/thor/actions/create_link.rb +57 -0
  14. data/lib/thor/actions/directory.rb +93 -0
  15. data/lib/thor/actions/empty_directory.rb +134 -0
  16. data/lib/thor/actions/file_manipulation.rb +270 -0
  17. data/lib/thor/actions/inject_into_file.rb +109 -0
  18. data/lib/thor/actions.rb +314 -0
  19. data/lib/thor/base.rb +598 -0
  20. data/lib/thor/core_ext/file_binary_read.rb +9 -0
  21. data/lib/thor/core_ext/hash_with_indifferent_access.rb +75 -0
  22. data/lib/thor/core_ext/ordered_hash.rb +100 -0
  23. data/lib/thor/error.rb +30 -0
  24. data/lib/thor/group.rb +276 -0
  25. data/lib/thor/invocation.rb +168 -0
  26. data/lib/thor/parser/argument.rb +67 -0
  27. data/lib/thor/parser/arguments.rb +165 -0
  28. data/lib/thor/parser/option.rb +120 -0
  29. data/lib/thor/parser/options.rb +181 -0
  30. data/lib/thor/parser.rb +4 -0
  31. data/lib/thor/rake_compat.rb +70 -0
  32. data/lib/thor/runner.rb +309 -0
  33. data/lib/thor/shell/basic.rb +302 -0
  34. data/lib/thor/shell/color.rb +108 -0
  35. data/lib/thor/shell/html.rb +121 -0
  36. data/lib/thor/shell.rb +88 -0
  37. data/lib/thor/task.rb +129 -0
  38. data/lib/thor/util.rb +229 -0
  39. data/lib/thor/version.rb +3 -0
  40. data/lib/thor.rb +336 -0
  41. data/spec/actions/create_file_spec.rb +170 -0
  42. data/spec/actions/directory_spec.rb +136 -0
  43. data/spec/actions/empty_directory_spec.rb +98 -0
  44. data/spec/actions/file_manipulation_spec.rb +317 -0
  45. data/spec/actions/inject_into_file_spec.rb +135 -0
  46. data/spec/actions_spec.rb +322 -0
  47. data/spec/base_spec.rb +274 -0
  48. data/spec/core_ext/hash_with_indifferent_access_spec.rb +43 -0
  49. data/spec/core_ext/ordered_hash_spec.rb +115 -0
  50. data/spec/fixtures/application.rb +2 -0
  51. data/spec/fixtures/bundle/execute.rb +6 -0
  52. data/spec/fixtures/bundle/main.thor +1 -0
  53. data/spec/fixtures/doc/%file_name%.rb.tt +1 -0
  54. data/spec/fixtures/doc/README +3 -0
  55. data/spec/fixtures/doc/block_helper.rb +3 -0
  56. data/spec/fixtures/doc/components/.empty_directory +0 -0
  57. data/spec/fixtures/doc/config.rb +1 -0
  58. data/spec/fixtures/doc/config.yaml.tt +1 -0
  59. data/spec/fixtures/group.thor +114 -0
  60. data/spec/fixtures/invoke.thor +112 -0
  61. data/spec/fixtures/path with spaces +0 -0
  62. data/spec/fixtures/script.thor +184 -0
  63. data/spec/fixtures/task.thor +10 -0
  64. data/spec/group_spec.rb +216 -0
  65. data/spec/invocation_spec.rb +100 -0
  66. data/spec/parser/argument_spec.rb +47 -0
  67. data/spec/parser/arguments_spec.rb +65 -0
  68. data/spec/parser/option_spec.rb +202 -0
  69. data/spec/parser/options_spec.rb +329 -0
  70. data/spec/rake_compat_spec.rb +72 -0
  71. data/spec/register_spec.rb +92 -0
  72. data/spec/runner_spec.rb +210 -0
  73. data/spec/shell/basic_spec.rb +223 -0
  74. data/spec/shell/color_spec.rb +41 -0
  75. data/spec/shell/html_spec.rb +27 -0
  76. data/spec/shell_spec.rb +47 -0
  77. data/spec/spec_helper.rb +54 -0
  78. data/spec/task_spec.rb +74 -0
  79. data/spec/thor_spec.rb +362 -0
  80. data/spec/util_spec.rb +163 -0
  81. data/thor.gemspec +25 -0
  82. metadata +241 -0
@@ -0,0 +1,98 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+ require 'thor/actions'
3
+
4
+ describe Thor::Actions::EmptyDirectory do
5
+ before(:each) do
6
+ ::FileUtils.rm_rf(destination_root)
7
+ end
8
+
9
+ def empty_directory(destination, options={})
10
+ @action = Thor::Actions::EmptyDirectory.new(base, destination)
11
+ end
12
+
13
+ def invoke!
14
+ capture(:stdout){ @action.invoke! }
15
+ end
16
+
17
+ def revoke!
18
+ capture(:stdout){ @action.revoke! }
19
+ end
20
+
21
+ def base
22
+ @base ||= MyCounter.new([1,2], {}, { :destination_root => destination_root })
23
+ end
24
+
25
+ describe "#destination" do
26
+ it "returns the full destination with the destination_root" do
27
+ empty_directory('doc').destination.should == File.join(destination_root, 'doc')
28
+ end
29
+
30
+ it "takes relative root into account" do
31
+ base.inside('doc') do
32
+ empty_directory('contents').destination.should == File.join(destination_root, 'doc', 'contents')
33
+ end
34
+ end
35
+ end
36
+
37
+ describe "#relative_destination" do
38
+ it "returns the relative destination to the original destination root" do
39
+ base.inside('doc') do
40
+ empty_directory('contents').relative_destination.should == 'doc/contents'
41
+ end
42
+ end
43
+ end
44
+
45
+ describe "#given_destination" do
46
+ it "returns the destination supplied by the user" do
47
+ base.inside('doc') do
48
+ empty_directory('contents').given_destination.should == 'contents'
49
+ end
50
+ end
51
+ end
52
+
53
+ describe "#invoke!" do
54
+ it "copies the file to the specified destination" do
55
+ empty_directory("doc")
56
+ invoke!
57
+ File.exists?(File.join(destination_root, "doc")).should be_true
58
+ end
59
+
60
+ it "shows created status to the user" do
61
+ empty_directory("doc")
62
+ invoke!.should == " create doc\n"
63
+ end
64
+
65
+ it "does not create a directory if pretending" do
66
+ base.inside("foo", :pretend => true) do
67
+ empty_directory("ghost")
68
+ end
69
+ File.exists?(File.join(base.destination_root, "ghost")).should be_false
70
+ end
71
+
72
+ describe "when directory exists" do
73
+ it "shows exist status" do
74
+ empty_directory("doc")
75
+ invoke!
76
+ invoke!.should == " exist doc\n"
77
+ end
78
+ end
79
+ end
80
+
81
+ describe "#revoke!" do
82
+ it "removes the destination file" do
83
+ empty_directory("doc")
84
+ invoke!
85
+ revoke!
86
+ File.exists?(@action.destination).should be_false
87
+ end
88
+ end
89
+
90
+ describe "#exists?" do
91
+ it "returns true if the destination file exists" do
92
+ empty_directory("doc")
93
+ @action.exists?.should be_false
94
+ invoke!
95
+ @action.exists?.should be_true
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,317 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ class Application; end
4
+
5
+ describe Thor::Actions do
6
+ def runner(options={})
7
+ @runner ||= MyCounter.new([1], options, { :destination_root => destination_root })
8
+ end
9
+
10
+ def action(*args, &block)
11
+ capture(:stdout){ runner.send(*args, &block) }
12
+ end
13
+
14
+ def exists_and_identical?(source, destination)
15
+ destination = File.join(destination_root, destination)
16
+ File.exists?(destination).should be_true
17
+
18
+ source = File.join(source_root, source)
19
+ FileUtils.should be_identical(source, destination)
20
+ end
21
+
22
+ def file
23
+ File.join(destination_root, "foo")
24
+ end
25
+
26
+ before(:each) do
27
+ ::FileUtils.rm_rf(destination_root)
28
+ end
29
+
30
+ describe "#chmod" do
31
+ it "executes the command given" do
32
+ FileUtils.should_receive(:chmod_R).with(0755, file)
33
+ action :chmod, "foo", 0755
34
+ end
35
+
36
+ it "does not execute the command if pretending given" do
37
+ FileUtils.should_not_receive(:chmod_R)
38
+ runner(:pretend => true)
39
+ action :chmod, "foo", 0755
40
+ end
41
+
42
+ it "logs status" do
43
+ FileUtils.should_receive(:chmod_R).with(0755, file)
44
+ action(:chmod, "foo", 0755).should == " chmod foo\n"
45
+ end
46
+
47
+ it "does not log status if required" do
48
+ FileUtils.should_receive(:chmod_R).with(0755, file)
49
+ action(:chmod, "foo", 0755, :verbose => false).should be_empty
50
+ end
51
+ end
52
+
53
+ describe "#copy_file" do
54
+ it "copies file from source to default destination" do
55
+ action :copy_file, "task.thor"
56
+ exists_and_identical?("task.thor", "task.thor")
57
+ end
58
+
59
+ it "copies file from source to the specified destination" do
60
+ action :copy_file, "task.thor", "foo.thor"
61
+ exists_and_identical?("task.thor", "foo.thor")
62
+ end
63
+
64
+ it "copies file from the source relative to the current path" do
65
+ runner.inside("doc") do
66
+ action :copy_file, "README"
67
+ end
68
+ exists_and_identical?("doc/README", "doc/README")
69
+ end
70
+
71
+ it "logs status" do
72
+ action(:copy_file, "task.thor").should == " create task.thor\n"
73
+ end
74
+
75
+ it "accepts a block to change output" do
76
+ action :copy_file, "task.thor" do |content|
77
+ "OMG" + content
78
+ end
79
+ File.read(File.join(destination_root, "task.thor")).should =~ /^OMG/
80
+ end
81
+ end
82
+
83
+ describe "#link_file" do
84
+ it "links file from source to default destination" do
85
+ action :link_file, "task.thor"
86
+ exists_and_identical?("task.thor", "task.thor")
87
+ end
88
+
89
+ it "links file from source to the specified destination" do
90
+ action :link_file, "task.thor", "foo.thor"
91
+ exists_and_identical?("task.thor", "foo.thor")
92
+ end
93
+
94
+ it "links file from the source relative to the current path" do
95
+ runner.inside("doc") do
96
+ action :link_file, "README"
97
+ end
98
+ exists_and_identical?("doc/README", "doc/README")
99
+ end
100
+
101
+ it "logs status" do
102
+ action(:link_file, "task.thor").should == " create task.thor\n"
103
+ end
104
+ end
105
+
106
+ describe "#get" do
107
+ it "copies file from source to the specified destination" do
108
+ action :get, "doc/README", "docs/README"
109
+ exists_and_identical?("doc/README", "docs/README")
110
+ end
111
+
112
+ it "uses just the source basename as destination if none is specified" do
113
+ action :get, "doc/README"
114
+ exists_and_identical?("doc/README", "README")
115
+ end
116
+
117
+ it "allows the destination to be set as a block result" do
118
+ action(:get, "doc/README"){ |c| "docs/README" }
119
+ exists_and_identical?("doc/README", "docs/README")
120
+ end
121
+
122
+ it "yields file content to a block" do
123
+ action :get, "doc/README" do |content|
124
+ content.should == "__start__\nREADME\n__end__\n"
125
+ end
126
+ end
127
+
128
+ it "logs status" do
129
+ action(:get, "doc/README", "docs/README").should == " create docs/README\n"
130
+ end
131
+
132
+ it "accepts http remote sources" do
133
+ body = "__start__\nHTTPFILE\n__end__\n"
134
+ FakeWeb.register_uri(:get, 'http://example.com/file.txt', :body => body)
135
+ action :get, 'http://example.com/file.txt' do |content|
136
+ content.should == body
137
+ end
138
+ FakeWeb.clean_registry
139
+ end
140
+
141
+ it "accepts https remote sources" do
142
+ body = "__start__\nHTTPSFILE\n__end__\n"
143
+ FakeWeb.register_uri(:get, 'https://example.com/file.txt', :body => body)
144
+ action :get, 'https://example.com/file.txt' do |content|
145
+ content.should == body
146
+ end
147
+ FakeWeb.clean_registry
148
+ end
149
+ end
150
+
151
+ describe "#template" do
152
+ it "allows using block helpers in the template" do
153
+ action :template, "doc/block_helper.rb"
154
+
155
+ file = File.join(destination_root, "doc/block_helper.rb")
156
+ File.read(file).should == "Hello world!"
157
+ end
158
+
159
+ it "evaluates the template given as source" do
160
+ runner.instance_variable_set("@klass", "Config")
161
+ action :template, "doc/config.rb"
162
+
163
+ file = File.join(destination_root, "doc/config.rb")
164
+ File.read(file).should == "class Config; end\n"
165
+ end
166
+
167
+ it "copies the template to the specified destination" do
168
+ action :template, "doc/config.rb", "doc/configuration.rb"
169
+ file = File.join(destination_root, "doc/configuration.rb")
170
+ File.exists?(file).should be_true
171
+ end
172
+
173
+ it "converts enconded instructions" do
174
+ runner.should_receive(:file_name).and_return("rdoc")
175
+ action :template, "doc/%file_name%.rb.tt"
176
+ file = File.join(destination_root, "doc/rdoc.rb")
177
+ File.exists?(file).should be_true
178
+ end
179
+
180
+ it "logs status" do
181
+ capture(:stdout){ runner.template("doc/config.rb") }.should == " create doc/config.rb\n"
182
+ end
183
+
184
+ it "accepts a block to change output" do
185
+ action :template, "doc/config.rb" do |content|
186
+ "OMG" + content
187
+ end
188
+ File.read(File.join(destination_root, "doc/config.rb")).should =~ /^OMG/
189
+ end
190
+
191
+ it "guesses the destination name when given only a source" do
192
+ action :template, "doc/config.yaml.tt"
193
+
194
+ file = File.join(destination_root, "doc/config.yaml")
195
+ File.exists?(file).should be_true
196
+ end
197
+ end
198
+
199
+ describe "when changing existent files" do
200
+ before(:each) do
201
+ ::FileUtils.cp_r(source_root, destination_root)
202
+ end
203
+
204
+ def file
205
+ File.join(destination_root, "doc", "README")
206
+ end
207
+
208
+ describe "#remove_file" do
209
+ it "removes the file given" do
210
+ action :remove_file, "doc/README"
211
+ File.exists?(file).should be_false
212
+ end
213
+
214
+ it "removes directories too" do
215
+ action :remove_dir, "doc"
216
+ File.exists?(File.join(destination_root, "doc")).should be_false
217
+ end
218
+
219
+ it "does not remove if pretending" do
220
+ runner(:pretend => true)
221
+ action :remove_file, "doc/README"
222
+ File.exists?(file).should be_true
223
+ end
224
+
225
+ it "logs status" do
226
+ action(:remove_file, "doc/README").should == " remove doc/README\n"
227
+ end
228
+
229
+ it "does not log status if required" do
230
+ action(:remove_file, "doc/README", :verbose => false).should be_empty
231
+ end
232
+ end
233
+
234
+ describe "#gsub_file" do
235
+ it "replaces the content in the file" do
236
+ action :gsub_file, "doc/README", "__start__", "START"
237
+ File.binread(file).should == "START\nREADME\n__end__\n"
238
+ end
239
+
240
+ it "does not replace if pretending" do
241
+ runner(:pretend => true)
242
+ action :gsub_file, "doc/README", "__start__", "START"
243
+ File.binread(file).should == "__start__\nREADME\n__end__\n"
244
+ end
245
+
246
+ it "accepts a block" do
247
+ action(:gsub_file, "doc/README", "__start__"){ |match| match.gsub('__', '').upcase }
248
+ File.binread(file).should == "START\nREADME\n__end__\n"
249
+ end
250
+
251
+ it "logs status" do
252
+ action(:gsub_file, "doc/README", "__start__", "START").should == " gsub doc/README\n"
253
+ end
254
+
255
+ it "does not log status if required" do
256
+ action(:gsub_file, file, "__", :verbose => false){ |match| match * 2 }.should be_empty
257
+ end
258
+ end
259
+
260
+ describe "#append_to_file" do
261
+ it "appends content to the file" do
262
+ action :append_to_file, "doc/README", "END\n"
263
+ File.binread(file).should == "__start__\nREADME\n__end__\nEND\n"
264
+ end
265
+
266
+ it "accepts a block" do
267
+ action(:append_to_file, "doc/README"){ "END\n" }
268
+ File.binread(file).should == "__start__\nREADME\n__end__\nEND\n"
269
+ end
270
+
271
+ it "logs status" do
272
+ action(:append_to_file, "doc/README", "END").should == " append doc/README\n"
273
+ end
274
+ end
275
+
276
+ describe "#prepend_to_file" do
277
+ it "prepends content to the file" do
278
+ action :prepend_to_file, "doc/README", "START\n"
279
+ File.binread(file).should == "START\n__start__\nREADME\n__end__\n"
280
+ end
281
+
282
+ it "accepts a block" do
283
+ action(:prepend_to_file, "doc/README"){ "START\n" }
284
+ File.binread(file).should == "START\n__start__\nREADME\n__end__\n"
285
+ end
286
+
287
+ it "logs status" do
288
+ action(:prepend_to_file, "doc/README", "START").should == " prepend doc/README\n"
289
+ end
290
+ end
291
+
292
+ describe "#inject_into_class" do
293
+ def file
294
+ File.join(destination_root, "application.rb")
295
+ end
296
+
297
+ it "appends content to a class" do
298
+ action :inject_into_class, "application.rb", Application, " filter_parameters :password\n"
299
+ File.binread(file).should == "class Application < Base\n filter_parameters :password\nend\n"
300
+ end
301
+
302
+ it "accepts a block" do
303
+ action(:inject_into_class, "application.rb", Application){ " filter_parameters :password\n" }
304
+ File.binread(file).should == "class Application < Base\n filter_parameters :password\nend\n"
305
+ end
306
+
307
+ it "logs status" do
308
+ action(:inject_into_class, "application.rb", Application, " filter_parameters :password\n").should == " insert application.rb\n"
309
+ end
310
+
311
+ it "does not append if class name does not match" do
312
+ action :inject_into_class, "application.rb", "App", " filter_parameters :password\n"
313
+ File.binread(file).should == "class Application < Base\nend\n"
314
+ end
315
+ end
316
+ end
317
+ end
@@ -0,0 +1,135 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+ require 'thor/actions'
3
+
4
+ describe Thor::Actions::InjectIntoFile do
5
+ before(:each) do
6
+ ::FileUtils.rm_rf(destination_root)
7
+ ::FileUtils.cp_r(source_root, destination_root)
8
+ end
9
+
10
+ def invoker(options={})
11
+ @invoker ||= MyCounter.new([1,2], options, { :destination_root => destination_root })
12
+ end
13
+
14
+ def revoker
15
+ @revoker ||= MyCounter.new([1,2], {}, { :destination_root => destination_root, :behavior => :revoke })
16
+ end
17
+
18
+ def invoke!(*args, &block)
19
+ capture(:stdout){ invoker.insert_into_file(*args, &block) }
20
+ end
21
+
22
+ def revoke!(*args, &block)
23
+ capture(:stdout){ revoker.insert_into_file(*args, &block) }
24
+ end
25
+
26
+ def file
27
+ File.join(destination_root, "doc/README")
28
+ end
29
+
30
+ describe "#invoke!" do
31
+ it "changes the file adding content after the flag" do
32
+ invoke! "doc/README", "\nmore content", :after => "__start__"
33
+ File.read(file).should == "__start__\nmore content\nREADME\n__end__\n"
34
+ end
35
+
36
+ it "changes the file adding content before the flag" do
37
+ invoke! "doc/README", "more content\n", :before => "__end__"
38
+ File.read(file).should == "__start__\nREADME\nmore content\n__end__\n"
39
+ end
40
+
41
+ it "accepts data as a block" do
42
+ invoke! "doc/README", :before => "__end__" do
43
+ "more content\n"
44
+ end
45
+
46
+ File.read(file).should == "__start__\nREADME\nmore content\n__end__\n"
47
+ end
48
+
49
+ it "logs status" do
50
+ invoke!("doc/README", "\nmore content", :after => "__start__").should == " insert doc/README\n"
51
+ end
52
+
53
+ it "does not change the file if pretending" do
54
+ invoker :pretend => true
55
+ invoke! "doc/README", "\nmore content", :after => "__start__"
56
+ File.read(file).should == "__start__\nREADME\n__end__\n"
57
+ end
58
+
59
+ it "does not change the file if already include content" do
60
+ invoke! "doc/README", :before => "__end__" do
61
+ "more content\n"
62
+ end
63
+
64
+ File.read(file).should == "__start__\nREADME\nmore content\n__end__\n"
65
+
66
+ invoke! "doc/README", :before => "__end__" do
67
+ "more content\n"
68
+ end
69
+
70
+ File.read(file).should == "__start__\nREADME\nmore content\n__end__\n"
71
+ end
72
+
73
+ it "does change the file if already include content and :force == true" do
74
+ invoke! "doc/README", :before => "__end__" do
75
+ "more content\n"
76
+ end
77
+
78
+ File.read(file).should == "__start__\nREADME\nmore content\n__end__\n"
79
+
80
+ invoke! "doc/README", :before => "__end__", :force => true do
81
+ "more content\n"
82
+ end
83
+
84
+ File.read(file).should == "__start__\nREADME\nmore content\nmore content\n__end__\n"
85
+ end
86
+
87
+ end
88
+
89
+ describe "#revoke!" do
90
+ it "substracts the destination file after injection" do
91
+ invoke! "doc/README", "\nmore content", :after => "__start__"
92
+ revoke! "doc/README", "\nmore content", :after => "__start__"
93
+ File.read(file).should == "__start__\nREADME\n__end__\n"
94
+ end
95
+
96
+ it "substracts the destination file before injection" do
97
+ invoke! "doc/README", "more content\n", :before => "__start__"
98
+ revoke! "doc/README", "more content\n", :before => "__start__"
99
+ File.read(file).should == "__start__\nREADME\n__end__\n"
100
+ end
101
+
102
+ it "substracts even with double after injection" do
103
+ invoke! "doc/README", "\nmore content", :after => "__start__"
104
+ invoke! "doc/README", "\nanother stuff", :after => "__start__"
105
+ revoke! "doc/README", "\nmore content", :after => "__start__"
106
+ File.read(file).should == "__start__\nanother stuff\nREADME\n__end__\n"
107
+ end
108
+
109
+ it "substracts even with double before injection" do
110
+ invoke! "doc/README", "more content\n", :before => "__start__"
111
+ invoke! "doc/README", "another stuff\n", :before => "__start__"
112
+ revoke! "doc/README", "more content\n", :before => "__start__"
113
+ File.read(file).should == "another stuff\n__start__\nREADME\n__end__\n"
114
+ end
115
+
116
+ it "substracts when prepending" do
117
+ invoke! "doc/README", "more content\n", :after => /\A/
118
+ invoke! "doc/README", "another stuff\n", :after => /\A/
119
+ revoke! "doc/README", "more content\n", :after => /\A/
120
+ File.read(file).should == "another stuff\n__start__\nREADME\n__end__\n"
121
+ end
122
+
123
+ it "substracts when appending" do
124
+ invoke! "doc/README", "more content\n", :before => /\z/
125
+ invoke! "doc/README", "another stuff\n", :before => /\z/
126
+ revoke! "doc/README", "more content\n", :before => /\z/
127
+ File.read(file).should == "__start__\nREADME\n__end__\nanother stuff\n"
128
+ end
129
+
130
+ it "shows progress information to the user" do
131
+ invoke!("doc/README", "\nmore content", :after => "__start__")
132
+ revoke!("doc/README", "\nmore content", :after => "__start__").should == " subtract doc/README\n"
133
+ end
134
+ end
135
+ end