inochi 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/bin/inochi +86 -38
- data/doc/api/Inochi.html +163 -86
- data/doc/history.erb +53 -8
- data/doc/index.xhtml +283 -73
- data/doc/setup.erb +0 -2
- data/doc/usage.erb +113 -35
- data/lib/inochi.rb +12 -10
- data/lib/inochi/inochi.rb +57 -16
- data/test/inochi/inochi.rb +106 -0
- metadata +18 -2
data/doc/setup.erb
CHANGED
data/doc/usage.erb
CHANGED
@@ -24,7 +24,7 @@
|
|
24
24
|
output_file=$1
|
25
25
|
shift
|
26
26
|
|
27
|
-
kdiff3 --
|
27
|
+
kdiff3 --merge "$old_file" "$new_file" --output "$output_file"
|
28
28
|
|
29
29
|
2. Make the file executable:
|
30
30
|
|
@@ -120,47 +120,60 @@
|
|
120
120
|
<% cd "word_count" %>
|
121
121
|
</pre>
|
122
122
|
|
123
|
-
|
123
|
+
<% paragraph "View Rake tasks" do %>
|
124
|
+
<pre>
|
125
|
+
# rake -T
|
126
|
+
<%= verbatim `rake -T` %>
|
127
|
+
</pre>
|
128
|
+
<% end %>
|
124
129
|
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
130
|
+
<% paragraph "Run unit tests" do %>
|
131
|
+
<pre>
|
132
|
+
# rake test
|
133
|
+
<%= verbatim `rake test` %>
|
134
|
+
</pre>
|
135
|
+
<% end %>
|
129
136
|
|
130
|
-
|
137
|
+
<% paragraph "Run project executable" do %>
|
138
|
+
<pre>
|
139
|
+
<% command = main_executable %>
|
140
|
+
# ruby <%= command %>
|
141
|
+
<%= verbatim `ruby #{command}` %>
|
142
|
+
</pre>
|
131
143
|
|
132
|
-
|
133
|
-
<% command = main_executable %>
|
134
|
-
# ruby <%= command %>
|
135
|
-
<%= verbatim `ruby #{command}` %>
|
136
|
-
</pre>
|
144
|
+
See usage information:
|
137
145
|
|
138
|
-
|
146
|
+
<pre>
|
147
|
+
<% command = "#{main_executable} --help" %>
|
148
|
+
# ruby <%= command %>
|
149
|
+
<%= verbatim `ruby #{command}` %>
|
150
|
+
</pre>
|
139
151
|
|
140
|
-
|
141
|
-
<% command = "#{main_executable} --help" %>
|
142
|
-
# ruby <%= command %>
|
143
|
-
<%= verbatim `ruby #{command}` %>
|
144
|
-
</pre>
|
152
|
+
See project & version information:
|
145
153
|
|
146
|
-
|
154
|
+
<pre>
|
155
|
+
<% command = "#{main_executable} --version" %>
|
156
|
+
# ruby <%= command %>
|
157
|
+
<%= verbatim `ruby #{command}` %>
|
158
|
+
</pre>
|
159
|
+
<% end %>
|
147
160
|
|
148
|
-
|
149
|
-
|
150
|
-
# ruby <%= command %>
|
151
|
-
<%= verbatim `ruby #{command}` %>
|
152
|
-
</pre>
|
161
|
+
<% paragraph "Show user manual" do %>
|
162
|
+
Build the user manual (please disregard any "unclosed span" warnings):
|
153
163
|
|
154
|
-
|
164
|
+
<pre>
|
165
|
+
# rake doc:man
|
166
|
+
</pre>
|
155
167
|
|
156
|
-
|
157
|
-
# rake doc:man 2>/dev/null
|
168
|
+
Launch the user manual:
|
158
169
|
|
159
|
-
|
160
|
-
|
161
|
-
|
170
|
+
<pre>
|
171
|
+
<% command = "#{main_executable} --manual" %>
|
172
|
+
# ruby <%= command %>
|
173
|
+
</pre>
|
162
174
|
|
163
|
-
|
175
|
+
The manual will now appear in your default web browser.
|
176
|
+
<% end %>
|
164
177
|
<% end %>
|
165
178
|
|
166
179
|
<% section "Configure your project" do %>
|
@@ -224,7 +237,7 @@
|
|
224
237
|
<% end %>
|
225
238
|
|
226
239
|
<% section "Implement your project" do %>
|
227
|
-
Add the following code to the bottom of the main project library:
|
240
|
+
Add the following code to the bottom of <tt>lib/word_count.rb</tt>, the main project library:
|
228
241
|
|
229
242
|
<code>
|
230
243
|
module WordCount
|
@@ -235,7 +248,7 @@
|
|
235
248
|
end
|
236
249
|
</code>
|
237
250
|
|
238
|
-
Add the following code to the bottom of the main project executable:
|
251
|
+
Add the following code to the bottom of <tt>bin/word_count</tt>, the main project executable:
|
239
252
|
|
240
253
|
<code>
|
241
254
|
input = ARGF.read
|
@@ -243,6 +256,39 @@
|
|
243
256
|
puts "There are #{total} words in the input."
|
244
257
|
</code>
|
245
258
|
|
259
|
+
Add the following code to the bottom of <tt>test/word_count.rb</tt>, a unit test for the main project library:
|
260
|
+
|
261
|
+
<code>
|
262
|
+
describe WordCount do
|
263
|
+
it 'handles empty input' do
|
264
|
+
WordCount.count(nil).must_equal(0)
|
265
|
+
WordCount.count('').must_equal(0)
|
266
|
+
WordCount.count(' ').must_equal(0)
|
267
|
+
end
|
268
|
+
|
269
|
+
it 'handles single words' do
|
270
|
+
WordCount.count('a').must_equal(1)
|
271
|
+
WordCount.count('foo').must_equal(1)
|
272
|
+
WordCount.count('bar').must_equal(1)
|
273
|
+
end
|
274
|
+
|
275
|
+
it 'handles multiple words' do
|
276
|
+
WordCount.count('a b').must_equal(2)
|
277
|
+
WordCount.count('a-b').must_equal(2)
|
278
|
+
WordCount.count('a/b').must_equal(2)
|
279
|
+
end
|
280
|
+
|
281
|
+
it 'ignores punctuation and space' do
|
282
|
+
WordCount.count('!').must_equal(0)
|
283
|
+
WordCount.count('! @ # % #!@#').must_equal(0)
|
284
|
+
WordCount.count(' !').must_equal(0)
|
285
|
+
WordCount.count('! ').must_equal(0)
|
286
|
+
WordCount.count(' ! ').must_equal(0)
|
287
|
+
WordCount.count(' ! ').must_equal(0)
|
288
|
+
end
|
289
|
+
end
|
290
|
+
</code>
|
291
|
+
|
246
292
|
<% paragraph "Goodbye `$LOAD_PATH`, hello `require()`" do %>
|
247
293
|
Notice that, in the Ruby files that you modified so far, there were no `$LOAD_PATH` manipulations and no explicit `require()` statements to pull in the various parts of your project. That is because **<%= $project %>** does this for you automatically.
|
248
294
|
|
@@ -261,9 +307,41 @@
|
|
261
307
|
<% end %>
|
262
308
|
|
263
309
|
<% section "Test your project" do %>
|
264
|
-
|
310
|
+
To reduce the amount of code you have to write, **<%= $project %>** defines the following convention for unit tests.
|
311
|
+
|
312
|
+
<% paragraph "Units and tests" do %>
|
313
|
+
Every Ruby source file in your project's <tt>lib/</tt> directory is considered to be a **unit**. Likewise, every Ruby source file in your project's <tt>test/</tt> is considered to be a **test**.
|
314
|
+
|
315
|
+
As a result, your project's <tt>test/</tt> directory structure *mirrors* the structure of your project's <tt>lib/</tt> directory. For example, if your project has a <tt>lib/foo/bar.rb</tt> unit, then <tt>test/foo/bar.rb</tt> would be its the corresponding test.
|
316
|
+
<% end %>
|
265
317
|
|
266
|
-
|
318
|
+
<% paragraph "Test execution" do %>
|
319
|
+
<pre>rake test</pre>
|
320
|
+
|
321
|
+
The above command begins the testing process, during which:
|
322
|
+
|
323
|
+
* Tests which lack corresponding units are *skipped* and not executed. A message specifying which test file was skipped is printed to the standard error stream whenever this occurs.
|
324
|
+
|
325
|
+
* Before a test is executed, its corresponding unit is automatically loaded into the Ruby environment using `require()`.
|
326
|
+
|
327
|
+
As for the details of test execution:
|
328
|
+
|
329
|
+
* Tests are executed by the [minitest] library, which allows you to write unit tests in a combination of styles: traditional TDD, modern BDD, alternative rSpec BDD, and mock-based validation styles.
|
330
|
+
|
331
|
+
* Within each test, test cases are executed in random order. This is the default behavior of the [minitest] library.
|
332
|
+
|
333
|
+
[minitest]: http://rubyforge.org/projects/bfts/
|
334
|
+
<% end %>
|
335
|
+
|
336
|
+
<% paragraph "Helper libraries" do %>
|
337
|
+
Your project's main directory is added to Ruby's load path. So if your tests have helper libraries stored in your project's <tt>test/</tt> directory, you can load them into your tests by adding a "test/" prefix.
|
338
|
+
|
339
|
+
For example, if your <tt>test/foo/bar.rb</tt> test has a <tt>test/foo/qux.rb</tt> helper library, then you would write the following code inside the test to load the helper library:
|
340
|
+
|
341
|
+
<code>
|
342
|
+
require 'test/foo/qux'
|
343
|
+
</code>
|
344
|
+
<% end %>
|
267
345
|
<% end %>
|
268
346
|
|
269
347
|
<% section "Publish your project" do %>
|
data/lib/inochi.rb
CHANGED
@@ -1,16 +1,18 @@
|
|
1
|
-
|
1
|
+
$LOAD_PATH << File.dirname(__FILE__)
|
2
|
+
require 'inochi/inochi'
|
2
3
|
|
3
4
|
Inochi.init :Inochi,
|
4
|
-
:version => '0.
|
5
|
-
:release => '2009-01-
|
6
|
-
:tagline => 'Gives life to RubyGems-based software',
|
5
|
+
:version => '0.2.0',
|
6
|
+
:release => '2009-01-25',
|
7
7
|
:website => 'http://snk.tuxfamily.org/lib/inochi',
|
8
|
+
:tagline => 'Gives life to RubyGems-based software',
|
8
9
|
:require => {
|
9
10
|
'rake' => '~> 0',
|
10
|
-
'rubyforge' => '~> 1',
|
11
|
-
'mechanize' => '~> 0',
|
12
|
-
'trollop' => '~> 1',
|
13
|
-
'launchy' => '~> 0',
|
14
|
-
'yard' => nil,
|
15
|
-
'addressable' => '~> 2',
|
11
|
+
'rubyforge' => '~> 1', # for publishing gems to RubyForge
|
12
|
+
'mechanize' => '~> 0', # for automating web browsing
|
13
|
+
'trollop' => '~> 1', # for parsing command-line options
|
14
|
+
'launchy' => '~> 0', # for launching a web browser
|
15
|
+
'yard' => nil, # for generating API documentation
|
16
|
+
'addressable' => '~> 2', # for parsing URIs properly
|
17
|
+
'minitest' => ['>= 1.3.1', '< 2'], # for unit testing
|
16
18
|
}
|
data/lib/inochi/inochi.rb
CHANGED
@@ -228,9 +228,10 @@ class << self
|
|
228
228
|
# where "name" is the name of a copyright holder and "info" is
|
229
229
|
# their contact information) is added to the project module.
|
230
230
|
#
|
231
|
-
#
|
232
|
-
#
|
233
|
-
#
|
231
|
+
# Unless this information is supplied via the :authors option,
|
232
|
+
# it is automatically extracted from copyright notices in the
|
233
|
+
# project license file, where the first copyright notice is
|
234
|
+
# expected to correspond to the primary project maintainer.
|
234
235
|
#
|
235
236
|
# Copyright notices must be in the following form:
|
236
237
|
#
|
@@ -247,6 +248,11 @@ class << self
|
|
247
248
|
# @param [Hash] options
|
248
249
|
# Additional method parameters, which are all optional:
|
249
250
|
#
|
251
|
+
# [Array] :authors =>
|
252
|
+
# A list of project authors and their contact information. This
|
253
|
+
# list must have the form "[[name, info]]" where "name" is the name
|
254
|
+
# of a project author and "info" is their contact information.
|
255
|
+
#
|
250
256
|
# [String] :license_file =>
|
251
257
|
# Path (relative to the main project directory which contains the
|
252
258
|
# project Rakefile) to the file which contains the project license.
|
@@ -305,24 +311,24 @@ class << self
|
|
305
311
|
|
306
312
|
# load the project module
|
307
313
|
program_name = File.basename(program_home)
|
314
|
+
project_libs = File.join('lib', program_name)
|
308
315
|
|
309
|
-
require
|
316
|
+
require project_libs
|
310
317
|
project_module = fetch_project_module(project_symbol)
|
311
318
|
|
312
319
|
# supply default options
|
313
320
|
options[:rubyforge_project] ||= program_name
|
314
321
|
options[:rubyforge_section] ||= program_name
|
315
|
-
options[:raa_project]
|
316
|
-
options[:license_file]
|
317
|
-
options[:logins_file]
|
318
|
-
options[:upload_delete]
|
319
|
-
options[:upload_options]
|
322
|
+
options[:raa_project] ||= program_name
|
323
|
+
options[:license_file] ||= 'LICENSE'
|
324
|
+
options[:logins_file] ||= File.join(ENV['HOME'], '.config', 'inochi', 'logins.yaml')
|
325
|
+
options[:upload_delete] ||= false
|
326
|
+
options[:upload_options] ||= []
|
320
327
|
|
321
328
|
# add AUTHORS constant to the project module
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
license.scan(/Copyright.*?\d+\s+(.*)/).flatten.
|
329
|
+
copyright_holders = options[:authors] ||
|
330
|
+
File.read(options[:license_file]).
|
331
|
+
scan(/Copyright.*?\d+\s+(.*)/).flatten.
|
326
332
|
map {|s| (s =~ /\s*<(.*?)>/) ? [$`, $1] : [s, ''] }
|
327
333
|
|
328
334
|
project_module.const_set :AUTHORS, copyright_holders
|
@@ -333,6 +339,38 @@ class << self
|
|
333
339
|
Rake::Task[name].instance_variable_set :@comment, nil
|
334
340
|
end
|
335
341
|
|
342
|
+
# testing
|
343
|
+
desc 'Run all unit tests.'
|
344
|
+
task :test do
|
345
|
+
ruby '-w', '-I.', '-Ilib', '-r', program_name, '-e', %q{
|
346
|
+
# set title of test suite
|
347
|
+
$0 = File.basename(Dir.pwd)
|
348
|
+
|
349
|
+
require 'minitest/unit'
|
350
|
+
require 'minitest/spec'
|
351
|
+
require 'minitest/mock'
|
352
|
+
MiniTest::Unit.autorun
|
353
|
+
|
354
|
+
Dir['test/**/*.rb'].sort.each do |test|
|
355
|
+
unit = test.sub('test/', 'lib/')
|
356
|
+
|
357
|
+
if File.exist? unit
|
358
|
+
# strip file extension because require()
|
359
|
+
# does not normalize its input and it
|
360
|
+
# will think that the two paths (with &
|
361
|
+
# without file extension) are different
|
362
|
+
unit_path = unit.sub(/\.rb$/, '').sub('lib/', '')
|
363
|
+
test_path = test.sub(/\.rb$/, '')
|
364
|
+
|
365
|
+
require unit_path
|
366
|
+
require test_path
|
367
|
+
else
|
368
|
+
warn "Skipped test #{test.inspect} because it lacks a corresponding #{unit.inspect} unit."
|
369
|
+
end
|
370
|
+
end
|
371
|
+
}
|
372
|
+
end
|
373
|
+
|
336
374
|
# documentation
|
337
375
|
desc 'Build all documentation.'
|
338
376
|
task :doc => %w[ doc:api doc:man ]
|
@@ -434,9 +472,9 @@ class << self
|
|
434
472
|
File.delete tmp_file
|
435
473
|
end
|
436
474
|
|
437
|
-
# improve readability of list items
|
438
|
-
#
|
439
|
-
text.gsub! %r{
|
475
|
+
# improve readability of list items
|
476
|
+
# by adding a blank line between them
|
477
|
+
text.gsub! %r{(\r?\n)( +\* \S)}, '\1\1\2'
|
440
478
|
|
441
479
|
text
|
442
480
|
end
|
@@ -482,6 +520,9 @@ class << self
|
|
482
520
|
# remove heading navigation menus
|
483
521
|
ann_html.gsub! %r{<div class="nav"[^>]*>(.*?)</div>}, ''
|
484
522
|
|
523
|
+
# remove latex-style heading numbers
|
524
|
+
ann_html.gsub! %r"(<(h\d)[^>]*>).+?(?: ){2}(.+?)(</\2>)"m, '\1\3\4'
|
525
|
+
|
485
526
|
ann_html = resolve_html_links[ann_html]
|
486
527
|
end
|
487
528
|
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
describe 'Inochi.calc_program_name' do
|
2
|
+
it 'converts input into lower-case' do
|
3
|
+
c('foo').must_equal('foo')
|
4
|
+
c('foO').must_equal('foo')
|
5
|
+
c('Foo').must_equal('foo')
|
6
|
+
c('FoO').must_equal('foo')
|
7
|
+
end
|
8
|
+
|
9
|
+
it 'converts camel case into snake case' do
|
10
|
+
c('FooBar').must_equal('foo_bar')
|
11
|
+
c('AnXMLParser').must_equal('an_xml_parser')
|
12
|
+
c('fOo').must_equal('f_oo')
|
13
|
+
c('FOo').must_equal('f_oo')
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def c *args
|
19
|
+
Inochi.calc_program_name(*args)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
describe 'Inochi.calc_project_symbol' do
|
24
|
+
it 'capitalizes first letter like a ruby constant' do
|
25
|
+
c('foo').must_equal('Foo')
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'preserves exisitng capitalization' do
|
29
|
+
c('FoO').must_equal('FoO')
|
30
|
+
c('fooBaR').must_equal('FooBaR')
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'converts non-word characters into underscores' do
|
34
|
+
c('a!b#c').must_equal('A_b_c')
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'squeezes mulitple underscores' do
|
38
|
+
c('foo!!bar$$qux').must_equal('Foo_bar_qux')
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'ignores surrounding whitespace' do
|
42
|
+
c(' a ').must_equal('A')
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'ignores surrounding underscores' do
|
46
|
+
c('_a').must_equal('A')
|
47
|
+
c('a_').must_equal('A')
|
48
|
+
c('_a_').must_equal('A')
|
49
|
+
c('__a__').must_equal('A')
|
50
|
+
end
|
51
|
+
|
52
|
+
it 'ignores surrounding non-word characters' do
|
53
|
+
c('!a').must_equal('A')
|
54
|
+
c('a!').must_equal('A')
|
55
|
+
c('!a!').must_equal('A')
|
56
|
+
c('!!a!!').must_equal('A')
|
57
|
+
c('!@a#$').must_equal('A')
|
58
|
+
end
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
def c *args
|
63
|
+
Inochi.calc_project_symbol(*args).to_s
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
describe 'Inochi.camel_to_snake_case' do
|
68
|
+
it 'supports empty input' do
|
69
|
+
c('').must_equal('')
|
70
|
+
end
|
71
|
+
|
72
|
+
it 'supports normal camel case' do
|
73
|
+
c('fooBar').must_equal('foo_Bar')
|
74
|
+
c('FooBar').must_equal('Foo_Bar')
|
75
|
+
c('Foobar').must_equal('Foobar')
|
76
|
+
end
|
77
|
+
|
78
|
+
it 'supports nested abbreviations' do
|
79
|
+
c('AnXMLParser').must_equal('An_XML_Parser')
|
80
|
+
c('ANXMLParser').must_equal('ANXML_Parser')
|
81
|
+
c('AnXmLPaRsEr').must_equal('An_Xm_L_Pa_Rs_Er')
|
82
|
+
end
|
83
|
+
|
84
|
+
it 'preserves non-word characters' do
|
85
|
+
c(' a!!b#c').must_equal(' a!!b#c')
|
86
|
+
end
|
87
|
+
|
88
|
+
it 'preserves exsiting underscores' do
|
89
|
+
c('foo_bar').must_equal('foo_bar')
|
90
|
+
c('foo_Bar').must_equal('foo_Bar')
|
91
|
+
c('Foo_Bar').must_equal('Foo_Bar')
|
92
|
+
c('Foo_bar').must_equal('Foo_bar')
|
93
|
+
|
94
|
+
c('Foo___b_a__r').must_equal('Foo___b_a__r')
|
95
|
+
c('_').must_equal('_')
|
96
|
+
c('_a').must_equal('_a')
|
97
|
+
c('a_').must_equal('a_')
|
98
|
+
c('_a_').must_equal('_a_')
|
99
|
+
end
|
100
|
+
|
101
|
+
private
|
102
|
+
|
103
|
+
def c *args
|
104
|
+
Inochi.camel_to_snake_case(*args)
|
105
|
+
end
|
106
|
+
end
|