inochi 0.2.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +2 -0
- data/bin/inochi +30 -29
- data/doc/api/Inochi.html +439 -323
- data/doc/api/Inochi/Manual.html +230 -0
- data/doc/api/Inochi/Phrases.html +409 -0
- data/doc/api/Inochi/Version.html +222 -0
- data/doc/api/all-methods.html +97 -9
- data/doc/api/all-namespaces.html +7 -1
- data/doc/api/readme.html +3 -0
- data/doc/history.erb +50 -20
- data/doc/index.xhtml +355 -141
- data/doc/intro.erb +14 -14
- data/doc/setup.erb +8 -7
- data/doc/usage.erb +110 -5
- data/lib/inochi.rb +14 -3
- data/lib/inochi/book.rb +84 -0
- data/lib/inochi/init.rb +239 -0
- data/lib/inochi/main.rb +75 -0
- data/lib/inochi/rake.rb +777 -0
- data/lib/inochi/util.rb +77 -0
- data/test/{inochi/inochi.rb → inochi.rb} +0 -0
- metadata +32 -5
- data/lib/inochi/inochi.rb +0 -1064
data/doc/intro.erb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
<% chapter "Introduction" do %>
|
2
2
|
<% project_summary do %>
|
3
|
-
**<%= $project %>** is an infrastructure for [RubyGems](http://www.rubygems.org)-based software projects that encourages good documentation
|
3
|
+
**<%= $project %>** is an infrastructure for [RubyGems](http://www.rubygems.org)-based software projects that encourages good documentation and reduces programming effort by automating common tasks.
|
4
4
|
<% end %>
|
5
5
|
|
6
6
|
**<%= $project %>** is exciting because:
|
@@ -22,27 +22,21 @@
|
|
22
22
|
* [hoe](http://seattlerb.rubyforge.org/hoe/)
|
23
23
|
* [newgem](http://newgem.rubyforge.org)
|
24
24
|
* [Mr Bones](http://codeforpeople.rubyforge.org/bones/)
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
require File.join(File.dirname(__FILE__), 'project', 'library')
|
30
|
-
|
31
|
-
With **<%= $project %>** you can require any library in your project:
|
32
|
-
|
33
|
-
require 'project/library'
|
34
|
-
-->
|
25
|
+
* [Gemify](http://gitorious.org/projects/gemify/)
|
26
|
+
* [Jeweler](http://technicalpickles.github.com/jeweler/)
|
27
|
+
* [GemMake](https://simonmenke.github.com/gm/)
|
28
|
+
* [SimpleGem](http://github.com/reagent/simple-gem/tree/master)
|
35
29
|
|
36
30
|
<% paragraph "Etymology" do %>
|
37
31
|
In the past, software development was thought to be like mathematical modeling or building construction: the assembly of inanimate objects. Nowadays, it is thought to be more like gardening: the cultivation of life!
|
38
32
|
|
39
33
|
In this manner, I consider this project not as a generator of skeletons or as a builder of scaffolds, but as a *giver of life*. That is why I named this project "inochi", the Japanese word for *life*.
|
40
34
|
|
41
|
-
Happy
|
35
|
+
Happy cultivation!
|
42
36
|
<% end %>
|
43
37
|
|
44
38
|
<% section "Logistics" do %>
|
45
|
-
* <%= xref "
|
39
|
+
* <%= xref "History", "Release notes" %> --- history of project releases.
|
46
40
|
* [Source code](http://github.com/sunaku/<%= $program %>) --- obtain via [Git](http://git.or.cz) or browse online.
|
47
41
|
* [API reference](api/index.html) --- documentation for source code.
|
48
42
|
* [Project home](<%= $website %>) --- the **<%= $project %>** project home page.
|
@@ -99,5 +93,11 @@
|
|
99
93
|
<% section "Credits" do %>
|
100
94
|
<%= $logo = "![project logo](#{$program}.png)".to_inline_xhtml %>
|
101
95
|
<%# include README #%>
|
96
|
+
|
97
|
+
**<%= $project %>** is made possible by
|
98
|
+
<%= xref "History", "contributions" %>
|
99
|
+
from users like you:
|
100
|
+
|
101
|
+
* Florian Gilcher
|
102
102
|
<% end %>
|
103
|
-
<% end %>
|
103
|
+
<% end %>
|
data/doc/setup.erb
CHANGED
@@ -2,18 +2,17 @@
|
|
2
2
|
<% section "Requirements" do %>
|
3
3
|
Your system needs the following software to run **<%= $project %>**.
|
4
4
|
|
5
|
-
| Software
|
6
|
-
| --------
|
7
|
-
| [Ruby](http://ruby-lang.org)
|
8
|
-
| [RubyGems](http://rubygems.org)
|
9
|
-
| [
|
10
|
-
| [Lynx](http://lynx.isc.org) | Text-mode web browser | Version 2.8.6 or newer is required to convert HTML into plain text. |
|
5
|
+
| Software | Description | Notes |
|
6
|
+
| -------- | ----------- | ----- |
|
7
|
+
| [Ruby](http://ruby-lang.org) | Ruby language interpreter | Version 1.8.6 or 1.8.7 is required. |
|
8
|
+
| [RubyGems](http://rubygems.org) | Ruby packaging system | Version 1.x.x is required. |
|
9
|
+
| [Lynx](http://lynx.isc.org) | Text-mode web browser | Version 2.8.6 or newer is required to convert HTML into plain text. |
|
11
10
|
<% end %>
|
12
11
|
|
13
12
|
<% section "Installation" do %>
|
14
13
|
You can install **<%= $project %>** by running this command:
|
15
14
|
|
16
|
-
gem install
|
15
|
+
gem install -f <%= $program %>
|
17
16
|
|
18
17
|
To check whether the installation was sucessful, run this command:
|
19
18
|
|
@@ -47,6 +46,8 @@
|
|
47
46
|
|
48
47
|
* <tt>index.erb</tt> --- source of this user manual.
|
49
48
|
|
49
|
+
* <tt>lang/</tt> --- translations of language phrases.
|
50
|
+
|
50
51
|
* <tt>LICENSE</tt> --- copyright notice and legal conditions.
|
51
52
|
<% end %>
|
52
53
|
<% end %>
|
data/doc/usage.erb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
<% yaml_addr = "http://yaml.kwiki.org/?YamlInFiveMinutes" %>
|
2
|
+
|
1
3
|
<% part "Usage" do %>
|
2
4
|
<% section "Command-line interface" do %>
|
3
5
|
When you run this command:
|
@@ -312,7 +314,7 @@
|
|
312
314
|
<% paragraph "Units and tests" do %>
|
313
315
|
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
316
|
|
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
|
317
|
+
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 corresponding test.
|
316
318
|
<% end %>
|
317
319
|
|
318
320
|
<% paragraph "Test execution" do %>
|
@@ -326,7 +328,7 @@
|
|
326
328
|
|
327
329
|
As for the details of test execution:
|
328
330
|
|
329
|
-
* Tests are executed by the [minitest] library, which allows you to write unit tests in a combination of styles: traditional TDD,
|
331
|
+
* Tests are executed by the [minitest] library, which allows you to write unit tests in a combination of styles: traditional xUnit TDD, alternative rSpec BDD, and mock-based validation styles.
|
330
332
|
|
331
333
|
* Within each test, test cases are executed in random order. This is the default behavior of the [minitest] library.
|
332
334
|
|
@@ -344,13 +346,116 @@
|
|
344
346
|
<% end %>
|
345
347
|
<% end %>
|
346
348
|
|
347
|
-
<% section "
|
348
|
-
|
349
|
+
<% section "Translate your project" do %>
|
350
|
+
<% phrases_file = "<tt>lang/phrases.yaml</tt>" %>
|
351
|
+
|
352
|
+
Although English is the *lingua franca* of today, your project's users may prefer to interact with it in their native language. **<%= $project %>** makes it easy to translate your project and also makes it easy for users to correct and contribute translations to your project.
|
353
|
+
|
354
|
+
<% section "Language phrases" do %>
|
355
|
+
**<%= $project %>** equips your project module with a `PHRASES` constant (see the [`Inochi::Phrases` class](api/Inochi/Phrases.html)) which provides access to translations of language phrases used in your project.
|
356
|
+
|
357
|
+
The [`Inochi::Phrases#[]` method](api/Inochi/Phrases.html#[]-instance_method) translates a given language phrase into the user's preferred language, which is automatically inferred from their environment, but may be explictly overridden by the user via the <tt>--locale</tt> option of <%= xref "Run project executable", "your project's main executable" %>:
|
358
|
+
|
359
|
+
<code>
|
360
|
+
your_project::PHRASES['Have a nice day!']
|
361
|
+
</code>
|
362
|
+
|
363
|
+
If there is no <%= xref "Translation files", "translation file" %> for the user's preferred language, or it does not define a translation for a particular language phrase, then the language phrase will be used untranslated:
|
364
|
+
|
365
|
+
<code>
|
366
|
+
your_project::PHRASES['No translation for this']
|
367
|
+
#=> 'No translation for this'
|
368
|
+
</code>
|
369
|
+
|
370
|
+
<% paragraph "Parameterizing language phrases" do %>
|
371
|
+
Language phrases can be parameterized using [`printf` format placeholders](http://en.wikipedia.org/wiki/Printf#printf_format_placeholders) to ease translation:
|
372
|
+
|
373
|
+
<code>
|
374
|
+
your_project::PHRASES['Good afternoon, %s.', user_name]
|
375
|
+
your_project::PHRASES['You are %d years old.', user_age]
|
376
|
+
</code>
|
377
|
+
<% end %>
|
378
|
+
|
379
|
+
<% paragraph "Explicit translation into a language" do %>
|
380
|
+
If a language phrase must be translated into a specific language, regardless of the user's preference, you can invoke the respective method (whose name is the same as the [ISO-639 language code](http://en.wikipedia.org/wiki/ISO_639) of the language into which you wish to translate) on your `PHRASES` object:
|
381
|
+
|
382
|
+
<code>
|
383
|
+
# explictly translate into Japanese (ja)
|
384
|
+
your_project::PHRASES.ja('Goodbye %s!', user_name)
|
385
|
+
|
386
|
+
# explictly translate into French (fr)
|
387
|
+
your_project::PHRASES.fr('Farewell %s!', user_name)
|
388
|
+
</code>
|
389
|
+
<% end %>
|
390
|
+
<% end %>
|
391
|
+
|
392
|
+
<% section "Translation files" do %>
|
393
|
+
Translation files are [YAML documents](<%= yaml_addr %>) that reside in your project's <tt>lang/</tt> directory. They provide translations for <%= xref "Language phrases", "language phrases" %> used in your project.
|
394
|
+
|
395
|
+
For example, suppose that your language phrases are written in English, the <tt>lang/es.yaml</tt> (Spanish) translation file would appear like this:
|
396
|
+
|
397
|
+
<pre>
|
398
|
+
#
|
399
|
+
# (this is a comment)
|
400
|
+
#
|
401
|
+
# language phrase : translation
|
402
|
+
#
|
403
|
+
Hello %s! : ¡Hola %s!
|
404
|
+
Money : Dinero
|
405
|
+
Ticket : Tarjeta
|
406
|
+
See you later %s! : ¡Hasta la vista %s!
|
407
|
+
"%s: Quickly, please!" : "%s: ¡Rápidamente, por favor!"
|
408
|
+
</pre>
|
409
|
+
|
410
|
+
On each line, the original language phrase (as used in your project) appears first, then a single semicolon (:), followed by the translation.
|
411
|
+
|
412
|
+
Also, notice that if a language phrase contains a semicolon, then the entire phrase must be enclosed in quotation marks. The same rule applies to its corresponding translation.
|
413
|
+
<% end %>
|
414
|
+
|
415
|
+
<% section "Extracting language phrases" do %>
|
416
|
+
<pre>
|
417
|
+
# rake lang:dump
|
418
|
+
<%= verbatim `rake lang:dump` %>
|
419
|
+
</pre>
|
420
|
+
|
421
|
+
The above command exercises your project's code and extracts all *utilized* language phrases into the <%= phrases_file %> file. Continue reading to learn how this is accomplished.
|
422
|
+
|
423
|
+
<% paragraph "Dynamic analysis" do %>
|
424
|
+
Because Ruby is a dynamically interpreted language, the easiest way to extract language phrases is to evaluate the code that defines them and keep track of which phrases are defined.
|
425
|
+
|
426
|
+
But how can **<%= $project %>** exercise all Ruby code in your project? The answer is through *unit tests*. Because unit tests already exercise your project's code, **<%= $project %>** can use them to reach and extract all language phrases from your project.
|
427
|
+
|
428
|
+
However, note that if your unit tests *do not* exercise a part of your project that defines language phrases, then those phrases *will not* be extracted by **<%= $project %>**.
|
429
|
+
|
430
|
+
This gives you extra motivation to improve the coverage of your test suite---at least to the point where all code that defines language phrases is covered.
|
431
|
+
<% end %>
|
349
432
|
|
433
|
+
<% paragraph "Static analysis" do %>
|
434
|
+
In a future release, I plan to extract language phrases through static analysis of Ruby code. This approach will supplement the current practice of reaching language phrases through unit tests.
|
435
|
+
|
436
|
+
Patches are welcome! :-)
|
437
|
+
<% end %>
|
438
|
+
<% end %>
|
439
|
+
|
440
|
+
<% section "Translating language phrases" do %>
|
441
|
+
After you have extracted all language phrases from your project (either manually or via <%= xref "Extracting language phrases" %>) into the <%= phrases_file %> file, **<%= $project %>** can automatically translate them into various languages using the [Yahoo! BabelFish translation service](http://babelfish.yahoo.com):
|
442
|
+
|
443
|
+
<pre>
|
444
|
+
# rake lang:conv from=LANGUAGE_CODE
|
445
|
+
<%= verbatim `rake lang:conv from=LANGUAGE_CODE 2>&1` %>
|
446
|
+
</pre>
|
447
|
+
|
448
|
+
Notice that you must specify the language in which your phrases are written, via the <tt>from=</tt> parameter. **<%= $project %>** cannot determine this automatically.
|
449
|
+
<% end %>
|
450
|
+
<% end %>
|
451
|
+
|
452
|
+
<% section "Publish your project" do %>
|
350
453
|
<pre>
|
351
454
|
# rake pub
|
352
455
|
</pre>
|
353
456
|
|
457
|
+
The above command performs all automated steps described in the following sections.
|
458
|
+
|
354
459
|
<% section "Build a RubyGem" do %>
|
355
460
|
Build a RubyGem by running:
|
356
461
|
|
@@ -391,7 +496,7 @@
|
|
391
496
|
|
392
497
|
<% logins_file = "~/.config/inochi/logins.yaml" %>
|
393
498
|
|
394
|
-
This information is expected to be stored in a <tt><%= logins_file %></tt> file (this location can be overridden by passing the `:logins_file` option to the [`Inochi.rake()` method](api/Inochi.html#rake-class_method)), where <tt>~</tt> denotes the path to your home directory. This file is a [YAML](
|
499
|
+
This information is expected to be stored in a <tt><%= logins_file %></tt> file (this location can be overridden by passing the `:logins_file` option to the [`Inochi.rake()` method](api/Inochi.html#rake-class_method)), where <tt>~</tt> denotes the path to your home directory. This file is a [YAML document](<%= yaml_addr %>) containing the following parameters:
|
395
500
|
|
396
501
|
<code lang="yaml">
|
397
502
|
www.ruby-forum.com:
|
data/lib/inochi.rb
CHANGED
@@ -1,9 +1,18 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
|
3
|
+
module Inochi
|
4
|
+
end
|
5
|
+
|
1
6
|
$LOAD_PATH << File.dirname(__FILE__)
|
2
|
-
require 'inochi/
|
7
|
+
require 'inochi/init'
|
8
|
+
require 'inochi/main'
|
9
|
+
require 'inochi/rake'
|
10
|
+
require 'inochi/book'
|
11
|
+
require 'inochi/util'
|
3
12
|
|
4
13
|
Inochi.init :Inochi,
|
5
|
-
:version => '0.
|
6
|
-
:release => '2009-
|
14
|
+
:version => '0.3.0',
|
15
|
+
:release => '2009-02-12',
|
7
16
|
:website => 'http://snk.tuxfamily.org/lib/inochi',
|
8
17
|
:tagline => 'Gives life to RubyGems-based software',
|
9
18
|
:require => {
|
@@ -11,8 +20,10 @@ Inochi.init :Inochi,
|
|
11
20
|
'rubyforge' => '~> 1', # for publishing gems to RubyForge
|
12
21
|
'mechanize' => '~> 0', # for automating web browsing
|
13
22
|
'trollop' => '~> 1', # for parsing command-line options
|
23
|
+
'erbook' => '~> 6', # for processing the user manual
|
14
24
|
'launchy' => '~> 0', # for launching a web browser
|
15
25
|
'yard' => nil, # for generating API documentation
|
16
26
|
'addressable' => '~> 2', # for parsing URIs properly
|
17
27
|
'minitest' => ['>= 1.3.1', '< 2'], # for unit testing
|
28
|
+
'babelfish' => '~> 0', # for human language translation
|
18
29
|
}
|
data/lib/inochi/book.rb
ADDED
@@ -0,0 +1,84 @@
|
|
1
|
+
class << Inochi
|
2
|
+
##
|
3
|
+
# Provides a common configuration for the project's user manual:
|
4
|
+
#
|
5
|
+
# * Assigns the title, subtitle, date, and authors for the document.
|
6
|
+
#
|
7
|
+
# You may override these assignments by reassigning these
|
8
|
+
# document parameters AFTER this method is invoked.
|
9
|
+
#
|
10
|
+
# Refer to the "document parameters" for the XHTML
|
11
|
+
# format in the "erbook" user manual for details.
|
12
|
+
#
|
13
|
+
# * Provides the project's configuration as global variables in the document.
|
14
|
+
#
|
15
|
+
# For example, <%= $version %> is the same as
|
16
|
+
# <%= project_module::VERSION %> in the document.
|
17
|
+
#
|
18
|
+
# * Defines a "project_summary" node for use in the document. The body
|
19
|
+
# of this node should contain a brief introduction to the project.
|
20
|
+
#
|
21
|
+
# * Defines a "project_history" node for use in the document. The body
|
22
|
+
# of this node should contain other nodes, each of which represent a
|
23
|
+
# single set of release notes for one of the project's releases.
|
24
|
+
#
|
25
|
+
# It is assumed that this method is called
|
26
|
+
# from within the Inochi.rake() environment.
|
27
|
+
#
|
28
|
+
# @param [Symbol] project_symbol
|
29
|
+
# Name of the Ruby constant which serves
|
30
|
+
# as a namespace for the entire project.
|
31
|
+
#
|
32
|
+
# @param [ERBook::Document::Template] book_template
|
33
|
+
# The eRuby template which serves as the documentation for the project.
|
34
|
+
#
|
35
|
+
def book project_symbol, book_template
|
36
|
+
project_module = fetch_project_module(project_symbol)
|
37
|
+
|
38
|
+
# provide project constants as global variables to the user manual
|
39
|
+
project_module::INOCHI.each_pair do |param, value|
|
40
|
+
eval "$#{param} = value", binding
|
41
|
+
end
|
42
|
+
|
43
|
+
# set document parameters for the user manual
|
44
|
+
$title = project_module::DISPLAY
|
45
|
+
$subtitle = project_module::TAGLINE
|
46
|
+
$feeds = { File.join(project_module::DOCSITE, 'ann.xml') => :rss }
|
47
|
+
$authors = Hash[
|
48
|
+
*project_module::AUTHORS.map do |name, addr|
|
49
|
+
# convert raw e-mail addresses into URLs for the erbook XHTML format
|
50
|
+
addr = "mailto:#{addr}" unless addr =~ /^\w+:/
|
51
|
+
|
52
|
+
[name, addr]
|
53
|
+
end.flatten
|
54
|
+
]
|
55
|
+
|
56
|
+
book_template.extend Manual
|
57
|
+
end
|
58
|
+
|
59
|
+
module Manual
|
60
|
+
##
|
61
|
+
# Defines a brief summary of this project.
|
62
|
+
#
|
63
|
+
def project_summary
|
64
|
+
raise ArgumentError, 'block must be given' unless block_given?
|
65
|
+
|
66
|
+
node do
|
67
|
+
$project_summary_node = @nodes.last
|
68
|
+
yield
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
##
|
73
|
+
# Contains release notes for all project releases.
|
74
|
+
#
|
75
|
+
def project_history
|
76
|
+
raise ArgumentError, 'block must be given' unless block_given?
|
77
|
+
|
78
|
+
node do
|
79
|
+
$project_history_node = @nodes.last
|
80
|
+
yield
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
data/lib/inochi/init.rb
ADDED
@@ -0,0 +1,239 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
3
|
+
class << Inochi
|
4
|
+
##
|
5
|
+
# Establishes your project in Ruby's runtime environment by defining
|
6
|
+
# the project module (which serves as a namespace for all code in the
|
7
|
+
# project) and providing a common configuration for the project module:
|
8
|
+
#
|
9
|
+
# * Adds the project lib/ directory to the Ruby load path.
|
10
|
+
#
|
11
|
+
# * Defines the INOCHI constant in the project module. This constant
|
12
|
+
# contains the effective configuration parameters (@see project_config).
|
13
|
+
#
|
14
|
+
# * Defines all configuration parameters as constants in the project module.
|
15
|
+
#
|
16
|
+
# This method must be invoked from immediately within (that is, not from
|
17
|
+
# within any of its descendant directories) the project lib/ directory.
|
18
|
+
# Ideally, this method would be invoked from the main project library.
|
19
|
+
#
|
20
|
+
# @param [Symbol] project_symbol
|
21
|
+
# Name of the Ruby constant which serves
|
22
|
+
# as a namespace for the entire project.
|
23
|
+
#
|
24
|
+
# @param [Hash] project_config
|
25
|
+
# Project configuration parameters:
|
26
|
+
#
|
27
|
+
# [String] :project =>
|
28
|
+
# Name of the project.
|
29
|
+
#
|
30
|
+
# The default value is the value of the project_symbol parameter.
|
31
|
+
#
|
32
|
+
# [String] :tagline =>
|
33
|
+
# An enticing, single line description of the project.
|
34
|
+
#
|
35
|
+
# The default value is an empty string.
|
36
|
+
#
|
37
|
+
# [String] :website =>
|
38
|
+
# URL of the published project website.
|
39
|
+
#
|
40
|
+
# The default value is an empty string.
|
41
|
+
#
|
42
|
+
# [String] :docsite =>
|
43
|
+
# URL of the published user manual.
|
44
|
+
#
|
45
|
+
# The default value is the same value as the :website parameter.
|
46
|
+
#
|
47
|
+
# [String] :program =>
|
48
|
+
# Name of the main project executable.
|
49
|
+
#
|
50
|
+
# The default value is the value of the :project parameter
|
51
|
+
# in lowercase and CamelCase converted into snake_case.
|
52
|
+
#
|
53
|
+
# [String] :version =>
|
54
|
+
# Version of the project.
|
55
|
+
#
|
56
|
+
# The default value is "0.0.0".
|
57
|
+
#
|
58
|
+
# [String] :release =>
|
59
|
+
# Date when this version was released.
|
60
|
+
#
|
61
|
+
# The default value is the current time.
|
62
|
+
#
|
63
|
+
# [String] :display =>
|
64
|
+
# How the project name should be displayed.
|
65
|
+
#
|
66
|
+
# The default value is the project name and version together.
|
67
|
+
#
|
68
|
+
# [String] :install =>
|
69
|
+
# Path to the directory which contains the project.
|
70
|
+
#
|
71
|
+
# The default value is one directory above the parent
|
72
|
+
# directory of the file from which this method was called.
|
73
|
+
#
|
74
|
+
# [Hash] :require =>
|
75
|
+
# The names and version constraints of ruby gems required by
|
76
|
+
# this project. This information must be expressed as follows:
|
77
|
+
#
|
78
|
+
# * Each hash key must be the name of a ruby gem.
|
79
|
+
#
|
80
|
+
# * Each hash value must be either +nil+, a single version number
|
81
|
+
# requirement string (see Gem::Requirement) or an Array thereof.
|
82
|
+
#
|
83
|
+
# The default value is an empty Hash.
|
84
|
+
#
|
85
|
+
# @return [Module] The newly configured project module.
|
86
|
+
#
|
87
|
+
def init project_symbol, project_config = {}
|
88
|
+
project_module = fetch_project_module(project_symbol)
|
89
|
+
|
90
|
+
# this method is not re-entrant
|
91
|
+
@already_seen ||= []
|
92
|
+
return project_module if @already_seen.include? project_module
|
93
|
+
@already_seen << project_module
|
94
|
+
|
95
|
+
# put project on Ruby load path
|
96
|
+
project_file = File.expand_path(first_caller_file)
|
97
|
+
project_libs = File.dirname(project_file)
|
98
|
+
$LOAD_PATH << project_libs unless $LOAD_PATH.include? project_libs
|
99
|
+
|
100
|
+
# supply configuration defaults
|
101
|
+
project_config[:project] ||= project_symbol.to_s
|
102
|
+
project_config[:tagline] ||= ''
|
103
|
+
project_config[:version] ||= '0.0.0'
|
104
|
+
project_config[:release] ||= Time.now.strftime('%F')
|
105
|
+
project_config[:website] ||= ''
|
106
|
+
project_config[:docsite] ||= project_config[:website]
|
107
|
+
project_config[:display] ||= "#{project_config[:project]} #{project_config[:version]}"
|
108
|
+
project_config[:program] ||= calc_program_name(project_symbol)
|
109
|
+
project_config[:install] ||= File.dirname(project_libs)
|
110
|
+
project_config[:require] ||= {}
|
111
|
+
|
112
|
+
# establish gem version dependencies and
|
113
|
+
# sanitize the values while we're at it
|
114
|
+
src = project_config[:require].dup
|
115
|
+
dst = project_config[:require].clear
|
116
|
+
|
117
|
+
src.each_pair do |gem_name, version_reqs|
|
118
|
+
gem_name = gem_name.to_s
|
119
|
+
version_reqs = [version_reqs].flatten.compact
|
120
|
+
|
121
|
+
dst[gem_name] = version_reqs
|
122
|
+
gem gem_name, *version_reqs
|
123
|
+
end
|
124
|
+
|
125
|
+
# make configuration parameters available as constants
|
126
|
+
project_config[:inochi] = project_config
|
127
|
+
project_config[:phrases] = Phrases.new project_config[:install]
|
128
|
+
project_config[:version].extend Version
|
129
|
+
|
130
|
+
project_config.each_pair do |param, value|
|
131
|
+
project_module.const_set param.to_s.upcase, value
|
132
|
+
end
|
133
|
+
|
134
|
+
project_module
|
135
|
+
end
|
136
|
+
|
137
|
+
module Version
|
138
|
+
# Returns the major number in this version.
|
139
|
+
def major
|
140
|
+
to_s[/^\d+/]
|
141
|
+
end
|
142
|
+
|
143
|
+
# Returns a string describing any version with the current major number.
|
144
|
+
def series
|
145
|
+
"#{major}.x.x"
|
146
|
+
end
|
147
|
+
|
148
|
+
# Returns a Gem::Requirement expression.
|
149
|
+
def requirement
|
150
|
+
"~> #{major}"
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
##
|
155
|
+
# Interface to translations of human text used in a project.
|
156
|
+
#
|
157
|
+
class Phrases
|
158
|
+
def initialize project_install_dir
|
159
|
+
# load language translations dynamically
|
160
|
+
lang_dir = File.join(project_install_dir, 'lang')
|
161
|
+
|
162
|
+
@phrases_by_language = Hash.new do |cache, language|
|
163
|
+
# store the phrase upon failure so that
|
164
|
+
# the phrases() method will know about it
|
165
|
+
phrases = Hash.new {|h,k| h[k] = nil }
|
166
|
+
|
167
|
+
lang_file = File.join(lang_dir, "#{language}.yaml")
|
168
|
+
lang_data = YAML.load_file(lang_file) rescue nil
|
169
|
+
phrases.merge! lang_data if lang_data
|
170
|
+
|
171
|
+
cache[language] = phrases
|
172
|
+
end
|
173
|
+
|
174
|
+
# detect user's preferred locale
|
175
|
+
self.locale = ENV['LC_ALL'] || ENV['LC_MESSAGES'] || ENV['LANG']
|
176
|
+
end
|
177
|
+
|
178
|
+
# The locale into which the #[] method will translate phrases.
|
179
|
+
attr_reader :locale
|
180
|
+
|
181
|
+
def locale= locale
|
182
|
+
@locale = locale.to_s
|
183
|
+
|
184
|
+
# extract the language portion of the locale
|
185
|
+
language = @locale[/^[[:alpha:]]+/].to_s
|
186
|
+
@language = language =~ /^(C|POSIX)?$/i ? :en : language.downcase.to_sym
|
187
|
+
end
|
188
|
+
|
189
|
+
##
|
190
|
+
# Returns all phrases that underwent (or
|
191
|
+
# attempted) translation via this object.
|
192
|
+
#
|
193
|
+
def phrases
|
194
|
+
@phrases_by_language.values.map {|h| h.keys }.flatten.uniq.sort
|
195
|
+
end
|
196
|
+
|
197
|
+
##
|
198
|
+
# Translates the given phrase into the target
|
199
|
+
# locale (see #locale and #locale=) and then
|
200
|
+
# substitutes the given placeholder arguments
|
201
|
+
# into the translation (see Kernel#sprintf).
|
202
|
+
#
|
203
|
+
# If a translation is not available for the given phrase,
|
204
|
+
# then the given phrase will be used as-is, untranslated.
|
205
|
+
#
|
206
|
+
def [] phrase, *words
|
207
|
+
translate @language, phrase, *words
|
208
|
+
end
|
209
|
+
|
210
|
+
##
|
211
|
+
# Provides access to translations in any language, regardless
|
212
|
+
# of the target locale (see #locale and #locale=).
|
213
|
+
#
|
214
|
+
# For example, you can access Japanese translations via
|
215
|
+
# the #jp method even if the target locale is French.
|
216
|
+
#
|
217
|
+
def method_missing meth, *args
|
218
|
+
# ISO 639 language codes come in alpha-2 and alpha-3 forms
|
219
|
+
if meth.to_s =~ /^[a-z]{2,3}$/
|
220
|
+
translate meth, *args
|
221
|
+
else
|
222
|
+
super
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
private
|
227
|
+
|
228
|
+
##
|
229
|
+
# Translates the given phrase into the given language and then substitutes
|
230
|
+
# the given placeholder arguments into the translation (see Kernel#sprintf).
|
231
|
+
#
|
232
|
+
# If the translation is not available, then
|
233
|
+
# the given string will be used instead.
|
234
|
+
#
|
235
|
+
def translate language, phrase, *words
|
236
|
+
(@phrases_by_language[language][phrase.to_s] || phrase).to_s % words
|
237
|
+
end
|
238
|
+
end
|
239
|
+
end
|