inochi 0.2.0 → 0.3.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/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 = "".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
|