facets 2.7.0 → 2.8.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/HISTORY.rdoc +135 -294
- data/MANIFEST +40 -91
- data/NOTES +1 -1
- data/README.rdoc +10 -8
- data/Rakefile +11 -34
- data/demo/{hook.rd → hook.rdoc} +2 -0
- data/demo/{scenario_require.rd → scenario_require.rdoc} +3 -0
- data/lib/core/facets-live.rb +7 -5
- data/lib/core/facets.rb +379 -359
- data/lib/core/facets/array/conjoin.rb +2 -2
- data/lib/core/facets/array/pad.rb +1 -1
- data/lib/core/facets/array/recursively.rb +2 -2
- data/lib/core/facets/array/splice.rb +1 -1
- data/lib/core/facets/binding/caller.rb +2 -4
- data/lib/core/facets/comparable/comparable.rb +2 -2
- data/lib/core/facets/dir/ascend.rb +3 -0
- data/lib/core/facets/dir/recurse.rb +4 -0
- data/lib/core/facets/duplicable.rb +6 -8
- data/lib/core/facets/enumerable/count.rb +22 -13
- data/lib/core/facets/enumerable/map_detect.rb +28 -0
- data/lib/core/facets/enumerable/mash.rb +13 -5
- data/lib/core/facets/enumerable/per.rb +3 -1
- data/lib/core/facets/hash/count.rb +14 -0
- data/lib/core/facets/hash/data.rb +14 -0
- data/lib/core/facets/kernel/__method__.rb +1 -1
- data/lib/core/facets/kernel/d.rb +9 -8
- data/lib/core/facets/kernel/eigenclass.rb +20 -0
- data/lib/core/facets/kernel/extend.rb +10 -0
- data/lib/core/facets/kernel/instance_class.rb +1 -0
- data/lib/core/facets/kernel/instance_variables.rb +6 -6
- data/lib/core/facets/kernel/meta_alias.rb +18 -0
- data/lib/core/facets/kernel/meta_class.rb +17 -0
- data/lib/core/facets/kernel/meta_def.rb +18 -0
- data/lib/core/facets/kernel/meta_eval.rb +18 -0
- data/lib/core/facets/kernel/object_hexid.rb +21 -6
- data/lib/core/facets/kernel/object_state.rb +4 -2
- data/lib/core/facets/kernel/populate.rb +3 -1
- data/lib/core/facets/kernel/with.rb +1 -1
- data/lib/core/facets/metaid.rb +6 -93
- data/lib/core/facets/module/class_def.rb +2 -0
- data/lib/core/facets/module/extend.rb +10 -11
- data/lib/core/facets/module/is.rb +5 -5
- data/lib/core/facets/module/module_def.rb +31 -0
- data/lib/core/facets/string/camelcase.rb +14 -12
- data/lib/core/facets/string/cleanlines.rb +35 -0
- data/lib/core/facets/string/edit_distance.rb +62 -0
- data/lib/core/facets/string/indent.rb +86 -4
- data/lib/core/facets/string/index_all.rb +24 -0
- data/lib/core/facets/string/lines.rb +3 -6
- data/lib/core/facets/string/margin.rb +2 -1
- data/lib/core/facets/string/newlines.rb +35 -0
- data/lib/core/facets/string/op_div.rb +14 -0
- data/lib/core/facets/string/range.rb +2 -22
- data/lib/core/facets/string/range_all.rb +1 -0
- data/lib/core/facets/string/range_of_line.rb +1 -0
- data/lib/core/facets/string/similarity.rb +92 -0
- data/lib/core/facets/string/start_with.rb +6 -6
- data/lib/core/facets/string/titlecase.rb +1 -1
- data/lib/more/facets/basicobject.rb +16 -15
- data/lib/more/facets/blankslate.rb +8 -0
- data/lib/more/facets/class_extend.rb +126 -1
- data/lib/more/facets/continuation.rb +53 -54
- data/lib/more/facets/dictionary.rb +9 -63
- data/lib/more/facets/erb.rb +63 -0
- data/lib/more/facets/filelist.rb +5 -5
- data/lib/more/facets/hashbuilder.rb +101 -0
- data/lib/more/facets/inheritor.rb +36 -45
- data/lib/more/facets/ini.rb +267 -0
- data/lib/more/facets/instance_eval.rb +4 -4
- data/lib/more/facets/ioredirect.rb +7 -60
- data/lib/more/facets/linkedlist.rb +195 -0
- data/lib/more/facets/matcher.rb +140 -0
- data/lib/more/facets/memoizer.rb +64 -0
- data/lib/more/facets/methodspace.rb +9 -4
- data/lib/more/facets/module/class_extend.rb +2 -121
- data/lib/more/facets/ostruct.rb +9 -9
- data/lib/more/facets/pathlist.rb +1 -9
- data/lib/more/facets/pathname.rb +11 -4
- data/lib/more/facets/plugin_manager.rb +50 -0
- data/lib/more/facets/random.rb +25 -3
- data/lib/more/facets/roman.rb +174 -0
- data/lib/more/facets/semaphore.rb +92 -0
- data/lib/more/facets/shellwords.rb +21 -48
- data/lib/more/facets/succ.rb +1 -1
- data/meta/{modified → released} +0 -0
- data/meta/repository +1 -0
- data/meta/suite +1 -0
- data/meta/version +1 -1
- data/script/conflicts +63 -0
- data/script/methods +49 -0
- data/test/core/binding/test_caller.rb +11 -4
- data/test/core/enumerable/test_count.rb +19 -10
- data/test/core/enumerable/test_map_detect.rb +75 -0
- data/test/core/enumerable/test_take.rb +1 -1
- data/test/core/kernel/test_object_hexid.rb +2 -1
- data/test/core/proc/test_to_method.rb +1 -1
- data/test/core/string/test_cleanlines.rb +11 -0
- data/test/core/string/test_indent.rb +66 -4
- data/test/core/string/test_lines.rb +2 -1
- data/test/core/string/test_newlines.rb +13 -0
- data/test/core/time/test_change.rb +1 -1
- data/test/core/time/test_stamp.rb +4 -7
- data/test/core/unboundmethod/test_name.rb +1 -1
- data/test/more/test_basicobject.rb +1 -20
- data/test/more/test_class_extend.rb +7 -0
- data/test/more/test_continuation.rb +8 -6
- data/test/more/test_inheritor.rb +12 -6
- data/test/more/test_random.rb +19 -10
- data/test/more/test_shellwords.rb +33 -0
- metadata +60 -31
- data/TODO +0 -5
- data/doc/README.core +0 -102
- data/doc/README.more +0 -61
- data/doc/manual/about.rb +0 -47
- data/doc/manual/annotations.rdoc +0 -60
- data/doc/manual/associations.rdoc +0 -55
- data/doc/manual/blockups.rdoc +0 -101
- data/doc/manual/capsule.rdoc +0 -34
- data/doc/manual/command.rdoc +0 -177
- data/doc/manual/core.rdoc +0 -37
- data/doc/manual/faq.rdoc +0 -32
- data/doc/manual/typecast.html +0 -112
- data/lib/more/facets/capsule.rb +0 -258
- data/lib/more/facets/coroutine.rb +0 -159
- data/lib/more/facets/enumerablepass.rb +0 -3
- data/lib/more/facets/fileable.rb +0 -162
- data/lib/more/facets/progressbar.rb +0 -253
- data/lib/more/facets/recorder.rb +0 -108
- data/meta/releases +0 -14
- data/test/more/test_coroutine.rb +0 -46
data/doc/manual/command.rdoc
DELETED
@@ -1,177 +0,0 @@
|
|
1
|
-
= Command
|
2
|
-
|
3
|
-
Command provides a clean and easy way to create a command
|
4
|
-
line interface for your program. The unique technique
|
5
|
-
utlizes a Commandline to Object Mapping (COM) to make
|
6
|
-
it quick and easy.
|
7
|
-
|
8
|
-
== Synopsis
|
9
|
-
|
10
|
-
Let's make an executable called 'mycmd'.
|
11
|
-
|
12
|
-
#!/usr/bin/env ruby
|
13
|
-
|
14
|
-
require 'facets/console/command'
|
15
|
-
|
16
|
-
class MyCmd < Console::Command
|
17
|
-
|
18
|
-
def _v
|
19
|
-
$VERBOSE = true
|
20
|
-
end
|
21
|
-
|
22
|
-
def jump
|
23
|
-
if $VERBOSE
|
24
|
-
puts "JUMP! JUMP! JUMP!"
|
25
|
-
else
|
26
|
-
puts "Jump"
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
end
|
31
|
-
|
32
|
-
MyCmd.execute
|
33
|
-
|
34
|
-
Then on the command line:
|
35
|
-
|
36
|
-
% mycmd jump
|
37
|
-
Jump
|
38
|
-
|
39
|
-
% mycmd -v jump
|
40
|
-
JUMP! JUMP! JUMP!
|
41
|
-
|
42
|
-
== Subcommands
|
43
|
-
|
44
|
-
Commands can take subcommand and suboptions. To do this
|
45
|
-
simply add a module to your class with the same name
|
46
|
-
as the subcommand, in which the suboption methods are defined.
|
47
|
-
|
48
|
-
MyCmd << Console::Command
|
49
|
-
|
50
|
-
def initialize
|
51
|
-
@height = 1
|
52
|
-
end
|
53
|
-
|
54
|
-
def _v
|
55
|
-
$VERBOSE = true
|
56
|
-
end
|
57
|
-
|
58
|
-
def jump
|
59
|
-
if $VERBOSE
|
60
|
-
puts "JUMP!" * @height
|
61
|
-
else
|
62
|
-
puts "Jump" * @height
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
module Jump
|
67
|
-
def __height(h)
|
68
|
-
@height = h.to_i
|
69
|
-
end
|
70
|
-
end
|
71
|
-
|
72
|
-
end
|
73
|
-
|
74
|
-
MyCmd.start
|
75
|
-
|
76
|
-
Then on the command line:
|
77
|
-
|
78
|
-
% mycmd jump -h 2
|
79
|
-
Jump Jump
|
80
|
-
|
81
|
-
% mycmd -v jump -h 3
|
82
|
-
JUMP! JUMP! JUMP!
|
83
|
-
|
84
|
-
Another thing to notice about this example is that #start is an alias
|
85
|
-
for #execute.
|
86
|
-
|
87
|
-
== Missing Subcommands
|
88
|
-
|
89
|
-
You can use #method_missing to catch missing subcommand calls.
|
90
|
-
|
91
|
-
== Main and Default
|
92
|
-
|
93
|
-
If your command does not take subcommands then simply define
|
94
|
-
a #main method to dispatch action. All options will be treated globablly
|
95
|
-
in this case and any remaining comman-line arguments will be passed
|
96
|
-
to #main.
|
97
|
-
|
98
|
-
If on the other hand your command does take subcommands but none is given,
|
99
|
-
the #default method will be called, if defined. If not defined
|
100
|
-
an error will be raised (but only reported if $DEBUG is true).
|
101
|
-
|
102
|
-
== Global Options
|
103
|
-
|
104
|
-
You can define <i>global options</i> which are options that will be
|
105
|
-
processed no matter where they occur in the command line. In the above
|
106
|
-
examples only the options occuring before the subcommand are processed
|
107
|
-
globally. Anything occuring after the subcommand belonds strictly to
|
108
|
-
the subcommand. For instance, if we had added the following to the above
|
109
|
-
example:
|
110
|
-
|
111
|
-
global_option :_v
|
112
|
-
|
113
|
-
Then -v could appear anywhere in the command line, even on the end,
|
114
|
-
and still work as expected.
|
115
|
-
|
116
|
-
% mycmd jump -h 3 -v
|
117
|
-
|
118
|
-
== Missing Options
|
119
|
-
|
120
|
-
You can use #option_missing to catch any options that are not explicility
|
121
|
-
defined.
|
122
|
-
|
123
|
-
The method signature should look like:
|
124
|
-
|
125
|
-
option_missing(option_name, args)
|
126
|
-
|
127
|
-
Example:
|
128
|
-
def option_missing(option_name, args)
|
129
|
-
p args if $debug
|
130
|
-
case option_name
|
131
|
-
when 'p'
|
132
|
-
@a = args[0].to_i
|
133
|
-
@b = args[1].to_i
|
134
|
-
2
|
135
|
-
else
|
136
|
-
raise InvalidOptionError(option_name, args)
|
137
|
-
end
|
138
|
-
end
|
139
|
-
|
140
|
-
Its return value should be the effective "arity" of that options -- that is,
|
141
|
-
how many arguments it consumed ("-p a b", for example, would consume 2 args:
|
142
|
-
"a" and "b"). An arity of 1 is assumed if nil or false is returned.
|
143
|
-
|
144
|
-
Be aware that when using subcommand modules, the same option_missing
|
145
|
-
method will catch missing options for global options and subcommand
|
146
|
-
options too unless an option_missing method is also defined in the
|
147
|
-
subcommand module.
|
148
|
-
|
149
|
-
== Help Documentation
|
150
|
-
|
151
|
-
You can also add help information quite easily. If the following code
|
152
|
-
is saved as 'foo' for instance.
|
153
|
-
|
154
|
-
MyCmd << Console::Command
|
155
|
-
|
156
|
-
help "Dispays the word JUMP!"
|
157
|
-
|
158
|
-
def jump
|
159
|
-
if $VERBOSE
|
160
|
-
puts "JUMP! JUMP! JUMP!"
|
161
|
-
else
|
162
|
-
puts "Jump"
|
163
|
-
end
|
164
|
-
end
|
165
|
-
|
166
|
-
end
|
167
|
-
|
168
|
-
MyCmd.execute
|
169
|
-
|
170
|
-
then by running 'foo help' on the command line, standard help information
|
171
|
-
will be displayed.
|
172
|
-
|
173
|
-
foo
|
174
|
-
|
175
|
-
jump Displays the word JUMP!
|
176
|
-
|
177
|
-
|
data/doc/manual/core.rdoc
DELETED
@@ -1,37 +0,0 @@
|
|
1
|
-
= Facets Core
|
2
|
-
|
3
|
-
Core contains the *essentials* of Facets. Core consists of a number
|
4
|
-
of generally useful core extension methods, and a couple small support
|
5
|
-
classes.
|
6
|
-
|
7
|
-
By definition Core contains anything that will load automatically when
|
8
|
-
issuing:
|
9
|
-
|
10
|
-
require 'facets'
|
11
|
-
|
12
|
-
== Facets by the Method
|
13
|
-
|
14
|
-
In the 1.0 series of Facets, all extensions were stored on a per-method
|
15
|
-
basis. This had some advantages, organization and complete fine-grain control
|
16
|
-
over requires was possible, but it proved in practice to be _too_ granular.
|
17
|
-
Some method simply too close in nature, or dependency, to go without others.
|
18
|
-
|
19
|
-
So version 2.0 has grouped the extensions method into small groups.
|
20
|
-
The library is still highly granular, but not excessively. But there's
|
21
|
-
still refinement being done in this regard. You need not worry about it
|
22
|
-
though, becuase per-method redirect libraries are provided. This is useful,
|
23
|
-
not only for backward compatability, but also if you know what method you
|
24
|
-
want, but don't recall exactly which core file it is in.
|
25
|
-
|
26
|
-
Here's an example:
|
27
|
-
|
28
|
-
require 'facets-by-method/hash/collate'
|
29
|
-
|
30
|
-
== Authors
|
31
|
-
|
32
|
-
This library more than any other part of Facets is full of contributions
|
33
|
-
from sources all across the Ruby community. For all who have code here,
|
34
|
-
the Facets Team salutes you.
|
35
|
-
|
36
|
-
For a list of names, look to the README in Facet's main documetation.
|
37
|
-
|
data/doc/manual/faq.rdoc
DELETED
@@ -1,32 +0,0 @@
|
|
1
|
-
= Facets FAQs
|
2
|
-
|
3
|
-
Q. How do I use the core mixins on object-by-object basis?
|
4
|
-
|
5
|
-
A. One way is to use Facets' Capsule library.
|
6
|
-
|
7
|
-
require 'facets/capsule'
|
8
|
-
|
9
|
-
MyStringExts = Capsule.load('facets/string/align')::String
|
10
|
-
|
11
|
-
s = "string"
|
12
|
-
|
13
|
-
s.extend(MyStringExts)
|
14
|
-
|
15
|
-
s.align_right(10) #=> " string"
|
16
|
-
|
17
|
-
Or handle it using in-module load methods.
|
18
|
-
|
19
|
-
require 'facets/module/require'
|
20
|
-
|
21
|
-
module MyStringExts
|
22
|
-
module_load 'facets/string/align'
|
23
|
-
include String
|
24
|
-
end
|
25
|
-
|
26
|
-
s = "string"
|
27
|
-
|
28
|
-
s.extend(MyStringExts)
|
29
|
-
|
30
|
-
s.align_right(10) #=> " string"
|
31
|
-
|
32
|
-
|
data/doc/manual/typecast.html
DELETED
@@ -1,112 +0,0 @@
|
|
1
|
-
<html>
|
2
|
-
|
3
|
-
<head>
|
4
|
-
<title>Facets Typecast</title>
|
5
|
-
|
6
|
-
<style>
|
7
|
-
body { font: 12pt sans-serif;
|
8
|
-
padding: 0; margin: 0;
|
9
|
-
}
|
10
|
-
#container {
|
11
|
-
margin: 0 auto;
|
12
|
-
}
|
13
|
-
#title {
|
14
|
-
color: #dddddd;
|
15
|
-
border-bottom: 1px solid gray;
|
16
|
-
padding: 20px;
|
17
|
-
}
|
18
|
-
#project {
|
19
|
-
font: 22pt sans-serif;
|
20
|
-
color: black;
|
21
|
-
}
|
22
|
-
#package {
|
23
|
-
font: bold 42pt sans-serif;
|
24
|
-
color: red;
|
25
|
-
}
|
26
|
-
#corpus {
|
27
|
-
padding: 20px;
|
28
|
-
}
|
29
|
-
</style>
|
30
|
-
</head>
|
31
|
-
|
32
|
-
<body>
|
33
|
-
<div id="container">
|
34
|
-
|
35
|
-
<div id="title">
|
36
|
-
<div id="project">Facets</div>
|
37
|
-
<div id="package">Typecast</div>
|
38
|
-
</div>
|
39
|
-
|
40
|
-
<div id="corpus">
|
41
|
-
<h2>Overview</h2>
|
42
|
-
<p>Typecast provides a simple generic type conversion system. All the ruby core
|
43
|
-
conversions are available by default.</p>
|
44
|
-
|
45
|
-
<p>To implement a new type conversion, you have two choices. Given:</p>
|
46
|
-
|
47
|
-
<pre>
|
48
|
-
class CustomType
|
49
|
-
def initialize(my_var)
|
50
|
-
@my_var = my_var
|
51
|
-
end
|
52
|
-
end
|
53
|
-
</pre>
|
54
|
-
|
55
|
-
<p> 1) Define a to_class_name instance method </p>
|
56
|
-
|
57
|
-
<pre>
|
58
|
-
class CustomType
|
59
|
-
def to_string
|
60
|
-
my_var.to_s
|
61
|
-
end
|
62
|
-
end
|
63
|
-
|
64
|
-
c = CustomType.new 1234
|
65
|
-
s.cast_to String => "1234" (String)
|
66
|
-
</pre>
|
67
|
-
|
68
|
-
<p> 2. Define a from_class_name class method </p>
|
69
|
-
|
70
|
-
<pre>
|
71
|
-
class CustomType
|
72
|
-
def self.from_string(str)
|
73
|
-
self.new(str)
|
74
|
-
end
|
75
|
-
end
|
76
|
-
|
77
|
-
"1234".cast_to CustomType => #<CustomType:0xb7d1958c @my_var="1234">
|
78
|
-
</pre>
|
79
|
-
|
80
|
-
<p>Those two methods are equivalent in the result. It was coded like that to
|
81
|
-
avoid the pollution of core classes with tons of to_* methods.</p>
|
82
|
-
|
83
|
-
<p>The standard methods to_s, to_f, to_i, to_a and to_sym are also used by
|
84
|
-
this system if available.</p>
|
85
|
-
|
86
|
-
<p>Usage looks like</p>
|
87
|
-
|
88
|
-
<pre>
|
89
|
-
"1234".cast_to Float => 1234.0 (Float)
|
90
|
-
Time.cast_from("6:30") => 1234.0 (Time)
|
91
|
-
</pre>
|
92
|
-
|
93
|
-
<h2>FAQ</h2>
|
94
|
-
|
95
|
-
<p>Why didn't you name the `cast_to` method to `to` ?</p>
|
96
|
-
|
97
|
-
<p>Even if it would make the syntax more friendly, I suspect it could cause
|
98
|
-
a lot of collisions with already existing code. The goal is that each
|
99
|
-
time you call cast_to, you either get your result, either a
|
100
|
-
TypeCastException.</p>
|
101
|
-
</div>
|
102
|
-
|
103
|
-
<div id="copy">
|
104
|
-
Copyright © 2004 Thomas Sawyer and all respective authors.
|
105
|
-
Ruby License
|
106
|
-
</div>
|
107
|
-
|
108
|
-
</div>
|
109
|
-
</body>
|
110
|
-
|
111
|
-
</html>
|
112
|
-
|
data/lib/more/facets/capsule.rb
DELETED
@@ -1,258 +0,0 @@
|
|
1
|
-
# = Capsule
|
2
|
-
#
|
3
|
-
# A Capsule is subclass of Module. It encapsulates an extenal script
|
4
|
-
# as a funcitons module.
|
5
|
-
#
|
6
|
-
# A module which is an instance of the Capsule class encapsulates in its scope
|
7
|
-
# the top-level methods, top-level constants, and instance variables defined in
|
8
|
-
# a ruby script file (and its subfiles) loaded by a ruby program. This allows
|
9
|
-
# use of script files to define objects that can be loaded into a program in
|
10
|
-
# much the same way that objects can be loaded from YAML or Marshal files.
|
11
|
-
#
|
12
|
-
# See intro.txt[link:files/intro_txt.html] for an overview.
|
13
|
-
#
|
14
|
-
# == Authors
|
15
|
-
#
|
16
|
-
# * Joel VanderWerf
|
17
|
-
# * Thomas Sawyer
|
18
|
-
#
|
19
|
-
# == Todo
|
20
|
-
#
|
21
|
-
# * The name of this is rather weak. Think of a better one.
|
22
|
-
#
|
23
|
-
# == Copying
|
24
|
-
#
|
25
|
-
# Copyright (c) 2005 Thomas Sawyer, Joel VanderWerf
|
26
|
-
#
|
27
|
-
# Ruby License
|
28
|
-
#
|
29
|
-
# This module is free software. You may use, modify, and/or redistribute this
|
30
|
-
# software under the same terms as Ruby.
|
31
|
-
#
|
32
|
-
# This program is distributed in the hope that it will be useful, but WITHOUT
|
33
|
-
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
34
|
-
# FOR A PARTICULAR PURPOSE.
|
35
|
-
|
36
|
-
#require 'rbconfig'
|
37
|
-
|
38
|
-
# = Capsule
|
39
|
-
#
|
40
|
-
# A Capsule is subclass of Module. It encapsulates an extenal script
|
41
|
-
# as a funcitons module.
|
42
|
-
#
|
43
|
-
# A module which is an instance of the Capsule class encapsulates in its scope
|
44
|
-
# the top-level methods, top-level constants, and instance variables defined in
|
45
|
-
# a ruby script file (and its subfiles) loaded by a ruby program. This allows
|
46
|
-
# use of script files to define objects that can be loaded into a program in
|
47
|
-
# much the same way that objects can be loaded from YAML or Marshal files.
|
48
|
-
#
|
49
|
-
# See intro.txt[link:files/intro_txt.html] for an overview.
|
50
|
-
|
51
|
-
class Capsule < Module
|
52
|
-
|
53
|
-
#DLEXT = Config::CONFIG['DLEXT']
|
54
|
-
|
55
|
-
# The script file with which the Import was instantiated.
|
56
|
-
attr_reader :main_file
|
57
|
-
|
58
|
-
# The directory in which main_file is located, and relative to which
|
59
|
-
# #load searches for files before falling back to Kernel#load.
|
60
|
-
#attr_reader :dir
|
61
|
-
|
62
|
-
# An array of paths to search for scripts. This has the same
|
63
|
-
# semantics as <tt>$:</tt>, alias <tt>$LOAD_PATH</tt>, excpet
|
64
|
-
# that it is local to this script. The path of the current
|
65
|
-
# script is added automatically (equivalent to '.')
|
66
|
-
attr_reader :load_path
|
67
|
-
|
68
|
-
# A hash that maps <tt>filename=>true</tt> for each file that has been
|
69
|
-
# required locally by the script. This has the same semantics as <tt>$"</tt>,
|
70
|
-
# alias <tt>$LOADED_FEATURES</tt>, except that it is local to this script.
|
71
|
-
attr_reader :loaded_features
|
72
|
-
|
73
|
-
class << self
|
74
|
-
# As with #new but will search Ruby's $LOAD_PATH first.
|
75
|
-
#--
|
76
|
-
# Will also try .rb, .so, .dll, et al extensions, like require does.
|
77
|
-
#++
|
78
|
-
def load(main_file, options=nil, &block)
|
79
|
-
file = nil
|
80
|
-
$LOAD_PATH.each do |path|
|
81
|
-
break if file = File.file?(File.join(path, main_file))
|
82
|
-
#break if file = Dir.glob(File.join(path, main_file)+'{,.rb,.'+DLEXT+'}')[0]
|
83
|
-
end
|
84
|
-
new(file || main_file, options=nil, &block)
|
85
|
-
end
|
86
|
-
end
|
87
|
-
|
88
|
-
# Creates new Capsule, and loads _main_file_ in the scope of the script. If a
|
89
|
-
# block is given, the script is passed to it before loading from the file, and
|
90
|
-
# constants can be defined as inputs to the script.
|
91
|
-
|
92
|
-
def initialize(main_file, options=nil, &block)
|
93
|
-
extend self
|
94
|
-
|
95
|
-
options ||= {}
|
96
|
-
|
97
|
-
@main_file = File.expand_path(main_file)
|
98
|
-
@load_path = options[:load_path] || []
|
99
|
-
#@load_path |= [File.dirname(@main_file)] # before or after?
|
100
|
-
@loaded_features = options[:loaded_features] || {}
|
101
|
-
|
102
|
-
# TODO In order to load/require at the instance level.
|
103
|
-
# This needs to be in a separate namespace however
|
104
|
-
# b/c it can interfere with what is expected.
|
105
|
-
#[ :require, :load ].each{ |meth|
|
106
|
-
# m = method(meth)
|
107
|
-
# define_method(meth) do |*args| m.call(*args) end
|
108
|
-
#}
|
109
|
-
|
110
|
-
module_eval(&block) if block
|
111
|
-
extend self
|
112
|
-
|
113
|
-
load_in_module(main_file)
|
114
|
-
end
|
115
|
-
|
116
|
-
# Lookup feature in load path.
|
117
|
-
|
118
|
-
def load_path_lookup(feature)
|
119
|
-
paths = File.join('{' + @load_path.join(',') + '}', feature + '{,.rb,.rbs}')
|
120
|
-
files = Dir.glob(paths)
|
121
|
-
match = files.find{ |f| ! @loaded_features.include?(f) }
|
122
|
-
return match
|
123
|
-
end
|
124
|
-
|
125
|
-
# Loads _file_ into the capsule. Searches relative to the local dir, that is,
|
126
|
-
# the dir of the file given in the original call to
|
127
|
-
# <tt>Capsule.load(file)</tt>, loads the file, if found, into this Capsule's
|
128
|
-
# scope, and returns true. If the file is not found, falls back to
|
129
|
-
# <tt>Kernel.load</tt>, which searches on <tt>$LOAD_PATH</tt>, loads the file,
|
130
|
-
# if found, into global scope, and returns true. Otherwise, raises
|
131
|
-
# <tt>LoadError</tt>.
|
132
|
-
#
|
133
|
-
# The _wrap_ argument is passed to <tt>Kernel.load</tt> in the fallback case,
|
134
|
-
# when the file is not found locally.
|
135
|
-
#
|
136
|
-
# Typically called from within the main file to load additional sub files, or
|
137
|
-
# from those sub files.
|
138
|
-
#
|
139
|
-
#--
|
140
|
-
# TODO Need to add load_path lookup.
|
141
|
-
#++
|
142
|
-
|
143
|
-
def load(file, wrap = false)
|
144
|
-
load_in_module(File.join(@dir, file))
|
145
|
-
true
|
146
|
-
rescue MissingFile
|
147
|
-
super
|
148
|
-
end
|
149
|
-
|
150
|
-
# Analogous to <tt>Kernel#require</tt>. First tries the local dir, then falls
|
151
|
-
# back to <tt>Kernel#require</tt>. Will load a given _feature_ only once.
|
152
|
-
#
|
153
|
-
# Note that extensions (*.so, *.dll) can be required in the global scope, as
|
154
|
-
# usual, but not in the local scope. (This is not much of a limitation in
|
155
|
-
# practice--you wouldn't want to load an extension more than once.) This
|
156
|
-
# implementation falls back to <tt>Kernel#require</tt> when the argument is an
|
157
|
-
# extension or is not found locally.
|
158
|
-
#
|
159
|
-
#--
|
160
|
-
# This was using load_in_module rather than include_script. Maybe is still should
|
161
|
-
# and one should have to call include_script instead? Think about this.
|
162
|
-
#++
|
163
|
-
|
164
|
-
def require(feature)
|
165
|
-
file = load_path_lookup(feature)
|
166
|
-
return super unless file
|
167
|
-
begin
|
168
|
-
@loaded_features[file] = true
|
169
|
-
load_in_module(file)
|
170
|
-
rescue MissingFile
|
171
|
-
@loaded_features[file] = false
|
172
|
-
super
|
173
|
-
end
|
174
|
-
end
|
175
|
-
|
176
|
-
# Raised by #load_in_module, caught by #load and #require.
|
177
|
-
class MissingFile < LoadError; end
|
178
|
-
|
179
|
-
# Loads _file_ in this module's context. Note that <tt>\_\_FILE\_\_</tt> and
|
180
|
-
# <tt>\_\_LINE\_\_</tt> work correctly in _file_.
|
181
|
-
# Called by #load and #require; not normally called directly.
|
182
|
-
|
183
|
-
def load_in_module(file)
|
184
|
-
module_eval(IO.read(file), File.expand_path(file))
|
185
|
-
rescue Errno::ENOENT => e
|
186
|
-
if /#{file}$/ =~ e.message
|
187
|
-
raise MissingFile, e.message
|
188
|
-
else
|
189
|
-
raise
|
190
|
-
end
|
191
|
-
end
|
192
|
-
|
193
|
-
def include_script(file)
|
194
|
-
include self.class.new(file, :load_path=>load_path, :loaded_features=>loaded_features)
|
195
|
-
rescue Errno::ENOENT => e
|
196
|
-
if /#{file}$/ =~ e.message
|
197
|
-
raise MissingFile, e.message
|
198
|
-
else
|
199
|
-
raise
|
200
|
-
end
|
201
|
-
end
|
202
|
-
|
203
|
-
#
|
204
|
-
def include(*mods)
|
205
|
-
super
|
206
|
-
extend self
|
207
|
-
end
|
208
|
-
|
209
|
-
def to_s # :nodoc:
|
210
|
-
"#<#{self.class}:#{main_file}>"
|
211
|
-
end
|
212
|
-
|
213
|
-
end
|
214
|
-
|
215
|
-
# TODO Is autoimport bets name for this?
|
216
|
-
|
217
|
-
class Module
|
218
|
-
|
219
|
-
const_missing_definition_for_autoimport = lambda do
|
220
|
-
#$autoimport_activated = true
|
221
|
-
alias const_missing_before_autoimport const_missing
|
222
|
-
|
223
|
-
def const_missing(sym) # :nodoc:
|
224
|
-
filename = @autoimport && @autoimport[sym]
|
225
|
-
if filename
|
226
|
-
mod = Import.load(filename)
|
227
|
-
const_set sym, mod
|
228
|
-
else
|
229
|
-
const_missing_before_autoimport(sym)
|
230
|
-
end
|
231
|
-
end
|
232
|
-
end
|
233
|
-
|
234
|
-
# When the constant named by symbol +mod+ is referenced, loads the script
|
235
|
-
# in filename using Capsule.load and defines the constant to be equal to the
|
236
|
-
# resulting Capsule module.
|
237
|
-
#
|
238
|
-
# Use like Module#autoload--however, the underlying opertation is #load rather
|
239
|
-
# than #require, because scripts, unlike libraries, can be loaded more than
|
240
|
-
# once. See examples/autoscript-example.rb
|
241
|
-
|
242
|
-
define_method(:autoimport) do |mod, file|
|
243
|
-
if @autoimport.empty? #unless $autoimport_activated
|
244
|
-
const_missing_definition_for_autoimport.call
|
245
|
-
end
|
246
|
-
(@autoimport ||= {})[mod] = file
|
247
|
-
end
|
248
|
-
end
|
249
|
-
|
250
|
-
|
251
|
-
module Kernel
|
252
|
-
|
253
|
-
# Calls Object.autoimport
|
254
|
-
def autoimport(mod, file)
|
255
|
-
Object.autoimport(mod, file)
|
256
|
-
end
|
257
|
-
|
258
|
-
end
|