inochi 0.1.0 → 0.2.0
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/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
|