linecook 1.2.1 → 2.0.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 → History.rdoc} +3 -2
- data/README.rdoc +93 -0
- data/bin/linecook +32 -56
- data/bin/linecook_run +19 -6
- data/bin/linecook_scp +12 -4
- data/doc/vm_setup.rdoc +75 -0
- data/lib/linecook.rb +3 -2
- data/lib/linecook/attributes.rb +33 -8
- data/lib/linecook/command.rb +61 -0
- data/lib/linecook/command_set.rb +85 -0
- data/lib/linecook/command_utils.rb +20 -0
- data/lib/linecook/commands/build.rb +108 -57
- data/lib/linecook/commands/compile.rb +181 -0
- data/lib/linecook/commands/{helper.rb → compile_helper.rb} +123 -94
- data/lib/linecook/commands/run.rb +43 -39
- data/lib/linecook/commands/snapshot.rb +24 -24
- data/lib/linecook/commands/ssh.rb +7 -7
- data/lib/linecook/commands/start.rb +10 -10
- data/lib/linecook/commands/state.rb +7 -7
- data/lib/linecook/commands/stop.rb +3 -3
- data/lib/linecook/commands/{vbox_command.rb → virtual_box_command.rb} +31 -29
- data/lib/linecook/cookbook.rb +149 -131
- data/lib/linecook/executable.rb +28 -0
- data/lib/linecook/package.rb +177 -361
- data/lib/linecook/proxy.rb +4 -10
- data/lib/linecook/recipe.rb +289 -369
- data/lib/linecook/test.rb +114 -98
- data/lib/linecook/utils.rb +31 -41
- data/lib/linecook/version.rb +2 -6
- metadata +120 -68
- data/HowTo/Control Virtual Machines +0 -106
- data/HowTo/Generate Scripts +0 -268
- data/HowTo/Run Scripts +0 -87
- data/HowTo/Setup Virtual Machines +0 -76
- data/README +0 -117
- data/lib/linecook/commands.rb +0 -11
- data/lib/linecook/commands/command.rb +0 -58
- data/lib/linecook/commands/command_error.rb +0 -12
- data/lib/linecook/commands/env.rb +0 -89
- data/lib/linecook/commands/init.rb +0 -86
- data/lib/linecook/commands/package.rb +0 -57
- data/lib/linecook/template.rb +0 -17
- data/lib/linecook/test/command_parser.rb +0 -75
- data/lib/linecook/test/file_test.rb +0 -197
- data/lib/linecook/test/regexp_escape.rb +0 -86
- data/lib/linecook/test/shell_test.rb +0 -177
- data/lib/linecook/test/shim.rb +0 -71
- data/templates/Gemfile +0 -3
- data/templates/Rakefile +0 -146
- data/templates/_gitignore +0 -4
- data/templates/attributes/project_name.rb +0 -3
- data/templates/config/ssh +0 -14
- data/templates/cookbook +0 -10
- data/templates/files/example.txt +0 -1
- data/templates/helpers/project_name/echo.erb +0 -4
- data/templates/packages/abox.yml +0 -2
- data/templates/project_name.gemspec +0 -30
- data/templates/recipes/abox.rb +0 -16
- data/templates/templates/example.erb +0 -1
- data/templates/test/project_name_test.rb +0 -24
- data/templates/test/test_helper.rb +0 -14
data/lib/linecook/proxy.rb
CHANGED
@@ -1,19 +1,13 @@
|
|
1
1
|
module Linecook
|
2
2
|
# A proxy used to chain method calls back to a recipe.
|
3
|
-
class Proxy
|
3
|
+
class Proxy < BasicObject
|
4
4
|
def initialize(recipe)
|
5
5
|
@recipe = recipe
|
6
6
|
end
|
7
|
-
|
8
|
-
#
|
7
|
+
|
8
|
+
# Invokes method via recipe.chain.
|
9
9
|
def method_missing(*args, &block)
|
10
|
-
@recipe.chain(*args, &block)
|
11
|
-
end
|
12
|
-
|
13
|
-
# Returns an empty string, such that the proxy makes no text when it is
|
14
|
-
# accidentally put into a target by a helper.
|
15
|
-
def to_s
|
16
|
-
''
|
10
|
+
@recipe.chain.__send__(*args, &block)
|
17
11
|
end
|
18
12
|
end
|
19
13
|
end
|
data/lib/linecook/recipe.rb
CHANGED
@@ -1,369 +1,289 @@
|
|
1
|
-
require '
|
2
|
-
require '
|
3
|
-
require 'linecook/
|
4
|
-
require '
|
5
|
-
require '
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
#
|
11
|
-
#
|
12
|
-
#
|
13
|
-
#
|
14
|
-
# #
|
15
|
-
# #
|
16
|
-
# # compiler
|
17
|
-
# # compiler.
|
18
|
-
# #
|
19
|
-
#
|
20
|
-
#
|
21
|
-
#
|
22
|
-
#
|
23
|
-
#
|
24
|
-
#
|
25
|
-
#
|
26
|
-
#
|
27
|
-
#
|
28
|
-
#
|
29
|
-
# echo '
|
30
|
-
#
|
31
|
-
#
|
32
|
-
#
|
33
|
-
#
|
34
|
-
# #
|
35
|
-
# # echo '
|
36
|
-
# #
|
37
|
-
#
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
attr_reader :
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
@
|
63
|
-
@
|
64
|
-
@
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
end
|
75
|
-
|
76
|
-
#
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
end
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
#
|
169
|
-
#
|
170
|
-
#
|
171
|
-
def
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
#
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
#
|
248
|
-
def
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
#
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
#
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
#
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
#
|
273
|
-
#
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
#
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
str.gsub!(/^/, indent)
|
291
|
-
|
292
|
-
if @indents.empty?
|
293
|
-
@outdents.each do |flag|
|
294
|
-
str.gsub!(/#{flag}(\d+):(.*?)#{flag}/m) do
|
295
|
-
$2.gsub!(/^.{#{$1.to_i}}/, '')
|
296
|
-
end
|
297
|
-
end
|
298
|
-
@outdents.clear
|
299
|
-
end
|
300
|
-
|
301
|
-
writeln str
|
302
|
-
end
|
303
|
-
|
304
|
-
self
|
305
|
-
end
|
306
|
-
|
307
|
-
# Resets indentation to nothing for a section of text indented by indent.
|
308
|
-
#
|
309
|
-
# === Notes
|
310
|
-
#
|
311
|
-
# Outdent works by setting a text flag around the outdented section; the
|
312
|
-
# flag and indentation is later stripped out using regexps. For that
|
313
|
-
# reason, be sure flag is not something that will appear anywhere else in
|
314
|
-
# the section.
|
315
|
-
#
|
316
|
-
# The default flag is like ':outdent_N:' where N is a big random number.
|
317
|
-
def outdent(flag=nil)
|
318
|
-
current_indent = @indents.last
|
319
|
-
|
320
|
-
if current_indent.nil?
|
321
|
-
yield
|
322
|
-
else
|
323
|
-
flag ||= ":outdent_#{rand(10000000)}:"
|
324
|
-
@outdents << flag
|
325
|
-
|
326
|
-
write "#{flag}#{current_indent.length}:#{rstrip}"
|
327
|
-
@indents << ''
|
328
|
-
|
329
|
-
yield
|
330
|
-
|
331
|
-
@indents.pop
|
332
|
-
|
333
|
-
write "#{flag}#{rstrip}"
|
334
|
-
end
|
335
|
-
|
336
|
-
self
|
337
|
-
end
|
338
|
-
|
339
|
-
# Sets chain? to true and calls the method (thereby allowing the method to
|
340
|
-
# invoke chain-specific behavior). Chain is invoked via the chain_proxy
|
341
|
-
# which is returned by helper methods.
|
342
|
-
def chain(method_name, *args, &block)
|
343
|
-
@chain = true
|
344
|
-
send(method_name, *args, &block)
|
345
|
-
end
|
346
|
-
|
347
|
-
# Returns true if the current context was invoked through chain.
|
348
|
-
def chain?
|
349
|
-
@chain
|
350
|
-
end
|
351
|
-
|
352
|
-
# Sets chain to false and returns the proxy.
|
353
|
-
def chain_proxy
|
354
|
-
@chain = false
|
355
|
-
_proxy_
|
356
|
-
end
|
357
|
-
|
358
|
-
# Captures a block of output and concats to the named callback.
|
359
|
-
def callback(name)
|
360
|
-
target = _package_.callbacks[name]
|
361
|
-
capture_block(target) { yield }
|
362
|
-
end
|
363
|
-
|
364
|
-
# Writes the specified callback to the current target.
|
365
|
-
def write_callback(name)
|
366
|
-
write _package_.callbacks[name].string
|
367
|
-
end
|
368
|
-
end
|
369
|
-
end
|
1
|
+
require 'erb'
|
2
|
+
require 'tilt'
|
3
|
+
require 'linecook/attributes'
|
4
|
+
require 'linecook/cookbook'
|
5
|
+
require 'linecook/package'
|
6
|
+
require 'linecook/utils'
|
7
|
+
require 'linecook/proxy'
|
8
|
+
|
9
|
+
module Linecook
|
10
|
+
# Recipe is the context in which recipes are evaluated (literally). Recipe
|
11
|
+
# uses compiled ERB snippets to build text using method calls. For example:
|
12
|
+
#
|
13
|
+
# module Helper
|
14
|
+
# # This is an ERB template compiled to write to a Recipe.
|
15
|
+
# #
|
16
|
+
# # compiler = ERB::Compiler.new('<>')
|
17
|
+
# # compiler.put_cmd = "write"
|
18
|
+
# # compiler.insert_cmd = "write"
|
19
|
+
# # compiler.compile("echo '<%= args.join(' ') %>'\n")
|
20
|
+
# #
|
21
|
+
# def echo(*args)
|
22
|
+
# write "echo '"; write(( args.join(' ') ).to_s); write "'\n"
|
23
|
+
# end
|
24
|
+
# end
|
25
|
+
#
|
26
|
+
# recipe = Recipe.new do
|
27
|
+
# _extend_ Helper
|
28
|
+
# echo 'a', 'b c'
|
29
|
+
# echo 'X Y'.downcase, :z
|
30
|
+
# end
|
31
|
+
#
|
32
|
+
# "\n" + recipe.to_s
|
33
|
+
# # => %{
|
34
|
+
# # echo 'a b c'
|
35
|
+
# # echo 'x y z'
|
36
|
+
# # }
|
37
|
+
#
|
38
|
+
class Recipe < BasicObject
|
39
|
+
# The recipe Proxy
|
40
|
+
attr_reader :_proxy_
|
41
|
+
|
42
|
+
# The recipe Package
|
43
|
+
attr_reader :_package_
|
44
|
+
|
45
|
+
attr_reader :_package_path_
|
46
|
+
|
47
|
+
attr_reader :_package_opts_
|
48
|
+
|
49
|
+
# The recipe Cookbook
|
50
|
+
attr_reader :_cookbook_
|
51
|
+
|
52
|
+
# The target recieving writes
|
53
|
+
attr_reader :target
|
54
|
+
|
55
|
+
def initialize(package = Package.new, cookbook = Cookbook.new, target = "")
|
56
|
+
@_proxy_ = Proxy.new(self)
|
57
|
+
@_package_ = package
|
58
|
+
@_cookbook_ = cookbook
|
59
|
+
@_package_path_ = nil
|
60
|
+
@_package_opts_ = nil
|
61
|
+
@target = target
|
62
|
+
@chain = false
|
63
|
+
@attributes = {}
|
64
|
+
@attrs = nil
|
65
|
+
|
66
|
+
if Kernel.block_given?
|
67
|
+
instance_eval(&Proc.new)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
# Overridden to look up constants as normal.
|
72
|
+
def self.const_missing(name)
|
73
|
+
::Object.const_get(name)
|
74
|
+
end
|
75
|
+
|
76
|
+
# Returns the singleton class for self. Used by clone to access modules
|
77
|
+
# included in self (ex via _extend_).
|
78
|
+
def _singleton_class_
|
79
|
+
class << self
|
80
|
+
SINGLETON_CLASS = self
|
81
|
+
def _singleton_class_
|
82
|
+
SINGLETON_CLASS
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
# this and future calls go to the _singleton_class_ as defined above.
|
87
|
+
_singleton_class_
|
88
|
+
end
|
89
|
+
|
90
|
+
# Returns the class for self.
|
91
|
+
def _class_
|
92
|
+
_singleton_class_.superclass
|
93
|
+
end
|
94
|
+
|
95
|
+
# Extends self with the module.
|
96
|
+
def _extend_(mod)
|
97
|
+
mod.__send__(:extend_object, self)
|
98
|
+
end
|
99
|
+
|
100
|
+
# Callback to initialize a clone of self. Passes forward all state,
|
101
|
+
# including local data and attributes.
|
102
|
+
def _initialize_clone_(orig)
|
103
|
+
@_proxy_ = Proxy.new(self)
|
104
|
+
@_package_ = orig._package_
|
105
|
+
@_cookbook_ = orig._cookbook_
|
106
|
+
@_package_path_ = orig._package_path_
|
107
|
+
@_package_opts_ = orig._package_path_
|
108
|
+
@target = orig.target
|
109
|
+
@chain = orig.chain?
|
110
|
+
@attributes = orig.attributes
|
111
|
+
@attrs = nil
|
112
|
+
end
|
113
|
+
|
114
|
+
# Returns a clone of self, kind of like Object#clone.
|
115
|
+
#
|
116
|
+
# Note that unlike Object.clone this currently does not carry forward
|
117
|
+
# tainted/frozen state, nor can it carry forward singleton methods.
|
118
|
+
# Modules and internal state only.
|
119
|
+
def _clone_
|
120
|
+
clone = _class_.allocate
|
121
|
+
clone._initialize_clone_(self)
|
122
|
+
_singleton_class_.included_modules.each {|mod| clone._extend_ mod }
|
123
|
+
clone
|
124
|
+
end
|
125
|
+
|
126
|
+
# Callback to initialize children created by _beget_. Sets a new target
|
127
|
+
# by calling dup.clear on the original target, and unchains. Note that
|
128
|
+
# the child shares the same attributes as the parent, and so can
|
129
|
+
# (un)intentionally cause changes in the parent.
|
130
|
+
def _initialize_child_(orig)
|
131
|
+
@target = orig.target.dup.clear
|
132
|
+
@_package_path_ = nil
|
133
|
+
@_package_opts_ = nil
|
134
|
+
unchain
|
135
|
+
end
|
136
|
+
|
137
|
+
# Returns a clone of self created by _clone_, but also calls
|
138
|
+
# _initialize_child_ on the clone.
|
139
|
+
def _beget_
|
140
|
+
clone = _clone_
|
141
|
+
clone._initialize_child_(self)
|
142
|
+
clone
|
143
|
+
end
|
144
|
+
|
145
|
+
# Returns a child of self with a new target. Writes str to the child, and
|
146
|
+
# evaluates the block in the context of the child, if given.
|
147
|
+
def _(str=nil, &block)
|
148
|
+
child = _beget_
|
149
|
+
child.write str if str
|
150
|
+
child.instance_eval(&block) if block
|
151
|
+
child
|
152
|
+
end
|
153
|
+
|
154
|
+
def register_as(path, options={})
|
155
|
+
@_package_path_ = path
|
156
|
+
@_package_opts_ = options
|
157
|
+
self
|
158
|
+
end
|
159
|
+
|
160
|
+
def register_to(package, path = _package_path_, options = _package_opts_)
|
161
|
+
package.add(path, options) {|io| io << to_s }
|
162
|
+
end
|
163
|
+
|
164
|
+
# Loads the specified attributes file and merges the results into attrs. A
|
165
|
+
# block may be given to specify attrs as well; it will be evaluated in the
|
166
|
+
# context of an Attributes instance.
|
167
|
+
#
|
168
|
+
# Returns a hash representing all attributes loaded thusfar (specifically
|
169
|
+
# attrs prior to merging in the package env). The attributes hash should
|
170
|
+
# be treated as if it were read-only.
|
171
|
+
def attributes(source_name=nil, &block)
|
172
|
+
if source_name || block
|
173
|
+
attributes = Attributes.new
|
174
|
+
|
175
|
+
if source_name
|
176
|
+
if source_path = _cookbook_.find(:attributes, source_name, attributes.load_attrs_extnames)
|
177
|
+
attributes.load_attrs(source_path)
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
if block
|
182
|
+
attributes.instance_eval(&block)
|
183
|
+
end
|
184
|
+
|
185
|
+
@attributes = Utils.deep_merge(@attributes, attributes.to_hash)
|
186
|
+
@attrs = nil
|
187
|
+
end
|
188
|
+
|
189
|
+
@attributes
|
190
|
+
end
|
191
|
+
|
192
|
+
# Returns the package env merged over any attrs specified by attributes.
|
193
|
+
#
|
194
|
+
# The attrs hash should be treated as if it were read-only because changes
|
195
|
+
# could alter the package env and thereby spill over into other recipes.
|
196
|
+
def attrs
|
197
|
+
@attrs ||= Utils.deep_merge(@attributes, _package_.env)
|
198
|
+
end
|
199
|
+
|
200
|
+
# Looks up and extends self with the specified helper(s).
|
201
|
+
def helpers(*helper_names)
|
202
|
+
helper_names.each do |helper|
|
203
|
+
unless helper.respond_to?(:extend_object)
|
204
|
+
helper_name = helper
|
205
|
+
module_name = Utils.camelize(helper_name)
|
206
|
+
|
207
|
+
helper = Utils.constantize(module_name) do
|
208
|
+
# Don't use Kernel because that may evade RubyGems
|
209
|
+
Utils.__send__(:require, Utils.underscore(helper_name))
|
210
|
+
Utils.constantize(module_name)
|
211
|
+
end
|
212
|
+
end
|
213
|
+
helper.__send__(:extend_object, self)
|
214
|
+
end
|
215
|
+
self
|
216
|
+
end
|
217
|
+
|
218
|
+
def register(package_path, options={})
|
219
|
+
source_path = _cookbook_.find(:files, options[:source] || package_path)
|
220
|
+
_package_.register(package_path, source_path, options)
|
221
|
+
end
|
222
|
+
|
223
|
+
# Captures writes during the block to a new target. Returns the target.
|
224
|
+
def capture(target = "")
|
225
|
+
current = @target
|
226
|
+
begin
|
227
|
+
@target = target
|
228
|
+
yield
|
229
|
+
ensure
|
230
|
+
@target = current
|
231
|
+
end
|
232
|
+
target
|
233
|
+
end
|
234
|
+
|
235
|
+
def capture_to(package_path, options={})
|
236
|
+
str = capture { yield }
|
237
|
+
_package_.add(package_path, options) {|io| io << str }
|
238
|
+
end
|
239
|
+
|
240
|
+
# Writes input to target using `<<`. Stringifies input using to_s. Returns
|
241
|
+
# self.
|
242
|
+
def write(input)
|
243
|
+
target << input.to_s
|
244
|
+
self
|
245
|
+
end
|
246
|
+
|
247
|
+
# Writes input to self, writes a newline, and returns last.
|
248
|
+
def writeln(input=nil)
|
249
|
+
write input
|
250
|
+
write "\n"
|
251
|
+
self
|
252
|
+
end
|
253
|
+
|
254
|
+
# Looks up a template in _cookbook_ and renders it.
|
255
|
+
def render(template_name, locals=attrs)
|
256
|
+
file = _cookbook_.find(:templates, template_name, ['.erb'])
|
257
|
+
Tilt.new(file).render(Object.new, locals)
|
258
|
+
end
|
259
|
+
|
260
|
+
# Causes chain? to return true. Returns self.
|
261
|
+
def chain
|
262
|
+
@chain = true
|
263
|
+
self
|
264
|
+
end
|
265
|
+
|
266
|
+
# Causes chain? to return false. Returns self.
|
267
|
+
def unchain
|
268
|
+
@chain = false
|
269
|
+
self
|
270
|
+
end
|
271
|
+
|
272
|
+
# Returns the proxy. Unchains first to ensure that if the proxy is not
|
273
|
+
# called, then the previous chain is stopped.
|
274
|
+
def chain_proxy
|
275
|
+
unchain
|
276
|
+
_proxy_
|
277
|
+
end
|
278
|
+
|
279
|
+
# Returns true as per chain/unchain.
|
280
|
+
def chain?
|
281
|
+
@chain
|
282
|
+
end
|
283
|
+
|
284
|
+
# Returns target.to_s.
|
285
|
+
def to_s
|
286
|
+
target.to_s
|
287
|
+
end
|
288
|
+
end
|
289
|
+
end
|