autobuild 0.4 → 0.5
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGES +57 -0
- data/README +29 -46
- data/Rakefile +161 -0
- data/lib/autobuild/config-interpolator.rb +80 -91
- data/lib/autobuild/config.rb +21 -6
- data/lib/autobuild/environment.rb +13 -11
- data/lib/autobuild/exceptions.rb +46 -45
- data/lib/autobuild/import/cvs.rb +34 -39
- data/lib/autobuild/import/svn.rb +23 -29
- data/lib/autobuild/import/tar.rb +120 -0
- data/lib/autobuild/importer.rb +4 -6
- data/lib/autobuild/options.rb +18 -11
- data/lib/autobuild/package.rb +1 -1
- data/lib/autobuild/packages/autotools.rb +107 -121
- data/lib/autobuild/packages/genom.rb +56 -62
- data/lib/autobuild/packages/import.rb +14 -12
- data/lib/autobuild/reporting.rb +91 -55
- data/lib/autobuild/subcommand.rb +89 -46
- data/lib/autobuild/timestamps.rb +47 -37
- metadata +43 -78
- data/bin/autobuild +0 -83
- data/test/base.rb +0 -8
- data/test/tc_config.rb +0 -40
- data/test/tc_config_interpolation.rb +0 -57
- data/test/tc_import.rb +0 -77
- data/test/tc_subcommand.rb +0 -61
- data/test/tools.rb +0 -39
data/CHANGES
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
= Autobuild changelog
|
2
|
+
|
3
|
+
== Version 0.5
|
4
|
+
|
5
|
+
Fixes the mail default behaviour. Added the 'tar' importer.
|
6
|
+
|
7
|
+
* all the API is now in a separate module
|
8
|
+
* genflags has been renamed back to genomflags. The convention is now to
|
9
|
+
have a <tool>flags option. For instance: genomflags, configureflags
|
10
|
+
* added the --[no-]build option to do only import
|
11
|
+
* changed behaviour for mail reports:
|
12
|
+
- set sensible default options for mail
|
13
|
+
- mail: true uses default options
|
14
|
+
- mail: <string> is equivalent to
|
15
|
+
mail:
|
16
|
+
to: <string>
|
17
|
+
* if a value is undefined in the config file, parameter expansion tries to get
|
18
|
+
it from the program environment, and raises an error if it is not present in
|
19
|
+
the environment vars
|
20
|
+
* changed the names of log files. All importers now uses <package>-<import>.log
|
21
|
+
* added the 'tar' importer, which downloads and uncompress a tarball
|
22
|
+
|
23
|
+
|
24
|
+
== Version 0.4
|
25
|
+
|
26
|
+
* added support to split import and build. For instance
|
27
|
+
|
28
|
+
whole_tree:
|
29
|
+
type: import
|
30
|
+
import: cvs
|
31
|
+
source: [ a, repository ]
|
32
|
+
|
33
|
+
package1:
|
34
|
+
type: autotools
|
35
|
+
srcdir: whole_tree/package1
|
36
|
+
depends: whole_tree
|
37
|
+
|
38
|
+
package2:
|
39
|
+
type: autotools
|
40
|
+
srcdir: whole_tree/package2
|
41
|
+
depends: whole_tree
|
42
|
+
|
43
|
+
Works as it should
|
44
|
+
|
45
|
+
* the <tt>autotools</tt> package has now an <tt>autogen</tt> options, which gives a name for a script
|
46
|
+
which creates the autotools environment
|
47
|
+
* renamed 'genomflags' -> 'genflags'
|
48
|
+
* variable interpolation checks for environment variables
|
49
|
+
* bugfixes
|
50
|
+
|
51
|
+
== Version 0.3
|
52
|
+
|
53
|
+
* added support for patching source code. Add patch: [ patches ] to the package configuration
|
54
|
+
* renamed autobuild-config, common-config and clean-log to autobuild, common and clean_log. Autobuild
|
55
|
+
warns if it finds one the previous spelling but ignores it anyway
|
56
|
+
|
57
|
+
|
data/README
CHANGED
@@ -109,6 +109,7 @@ Autobuild uses three sections:
|
|
109
109
|
*update*:: if false, do not update the packages that are already imported (default: true). You
|
110
110
|
can also use the <tt>--no-update</tt> on the command line
|
111
111
|
|
112
|
+
|
112
113
|
=== Directories (<tt>autobuild/srcdir</tt>, <tt>autobuild/prefix</tt> and <tt>autobuild/logdir</tt>)
|
113
114
|
*srcdir*:: the path where programs are to be imported. See <b>Packages configuration</b> for
|
114
115
|
more information on how this option is used.
|
@@ -144,30 +145,27 @@ sets
|
|
144
145
|
|
145
146
|
|
146
147
|
=== Mail (<tt>autobuild/mail</tt>)
|
147
|
-
|
148
|
-
at least the +to+ option, like this:
|
148
|
+
Use this options if you want to receive a mail when the build has finished (on success and failures)
|
149
149
|
|
150
150
|
autobuild:
|
151
|
-
mail:
|
152
|
-
from: autobuild@mymachine.rubyrules.org
|
153
|
-
to: myself+autobuild@rubyrules.org
|
154
|
-
smtp: localhost
|
151
|
+
mail: true
|
155
152
|
|
156
|
-
|
157
|
-
*
|
153
|
+
Valid options are:
|
154
|
+
*to*:: the mail destination, default is <tt>user@hostname</tt> (for instance sylvain@localhost for a user 'sylvain')
|
155
|
+
*from*:: the mail source, default is <tt>user@hostname</tt>
|
158
156
|
*smtp*:: the stmp server to use. Default is +localhost+
|
157
|
+
*port*:: the port the server is running on. Default is the smtp port (25)
|
159
158
|
|
160
159
|
All log files relative to the current build are attached to the mail.
|
161
160
|
|
162
161
|
|
163
|
-
|
164
162
|
== Configuring packages (<tt>packages/*</tt>)
|
165
163
|
=== The <tt>packages/config</tt> section
|
166
164
|
If you want to add common options in each package, just set it them here. Note that the options
|
167
|
-
are /merged/ in the package config. It neither replaces the values in the package nor
|
168
|
-
|
169
|
-
* if it is an array, the package option is converted to an array and the common
|
170
|
-
* if it is a string, the package option is converted to a string and the common option
|
165
|
+
are /merged/ in the package config. It neither replaces the values in the package nor the package
|
166
|
+
options replaces them. The merging strategy depends on the way the option is specified in this common section:
|
167
|
+
* if it is an array, the package option is converted to an array and the common options are appended
|
168
|
+
* if it is a string, the package option is converted to a string and the common option are appended
|
171
169
|
with a space inserted between the two
|
172
170
|
* if it is a boolean value, it is <em>overriden</em> by the package value
|
173
171
|
* any other values are forbidden
|
@@ -231,6 +229,22 @@ source and the builder to build and install it.
|
|
231
229
|
*svnup*:: options to add to svn up. Defaults to ''
|
232
230
|
*svnco*:: options to add to svn co. Defaults to ''
|
233
231
|
|
232
|
+
=== Tar (<tt>type: tar</tt>)
|
233
|
+
This importer gets a tarball file, which may be on a remote server, and un-tars
|
234
|
+
it. For now, it cannot determine itself what is the directory included in the tarball,
|
235
|
+
so you should set the srcdir: appropriately.
|
236
|
+
|
237
|
+
For instance, a tarball with one directory <tt>package-0.1</tt> in it will
|
238
|
+
need a <tt>srcdir</tt> option of <tt>package-0.1</tt>. If you do
|
239
|
+
not set +srcdir+, autobuild will untar the package in the global srcdir
|
240
|
+
(as intended) but will search for <tt>$global_srcdir/package</tt>
|
241
|
+
|
242
|
+
*source*:: the source URL. For now, http, ftp and file URLs are supported
|
243
|
+
*cachedir*:: the directory where the local copy of the file should be saved
|
244
|
+
(for http and ftp URLs only)
|
245
|
+
|
246
|
+
|
247
|
+
|
234
248
|
== Available package types (<tt>packages/</tt><em>name</em><tt>/type</tt>)
|
235
249
|
=== Source only (<tt>type: import</tt>)
|
236
250
|
Use +import+ if you need the package sources but don't need to build it. You just need
|
@@ -275,8 +289,8 @@ The only program used during the build phase is +make+. The make command can too
|
|
275
289
|
make: gnumake
|
276
290
|
|
277
291
|
==== Other options
|
278
|
-
*builddir*:: the directory where the build takes place. For now, it has to be a relative path,
|
279
|
-
which
|
292
|
+
*builddir*:: the directory where the build takes place. For now, it has to be a relative path,
|
293
|
+
which will be considered relative to the source directory.
|
280
294
|
*configureflags*:: array of options to add to the +configure+ command line
|
281
295
|
configureflags: [ --with-bar-source=$srcdir/$bar_srcdir ]
|
282
296
|
depends: bar
|
@@ -284,37 +298,6 @@ The only program used during the build phase is +make+. The make command can too
|
|
284
298
|
= Running autobuild in daemon mode
|
285
299
|
The <tt>--daemon</tt> command line options makes autobuild go into daemon mode.
|
286
300
|
|
287
|
-
= Changes
|
288
|
-
== 0.3 to 0.4
|
289
|
-
* added support to split import and build. For instance
|
290
|
-
|
291
|
-
whole_tree:
|
292
|
-
type: import
|
293
|
-
import: cvs
|
294
|
-
source: [ a, repository ]
|
295
|
-
|
296
|
-
package1:
|
297
|
-
type: autotools
|
298
|
-
srcdir: whole_tree/package1
|
299
|
-
depends: whole_tree
|
300
|
-
|
301
|
-
package2:
|
302
|
-
type: autotools
|
303
|
-
srcdir: whole_tree/package2
|
304
|
-
depends: whole_tree
|
305
|
-
|
306
|
-
Now works well
|
307
|
-
|
308
|
-
* the <tt>autotools</tt> package has now an <tt>autogen</tt> options, which gives a name for the script
|
309
|
-
to run to create the autoconf environment
|
310
|
-
* renamed 'genomflags' -> 'genflags'
|
311
|
-
* variable interpolation checks for environment variables
|
312
|
-
* bugfixes
|
313
|
-
== 0.2 to 0.3
|
314
|
-
* added support for patching source code. Add patch: [ patches ] to the package configuration
|
315
|
-
* renamed autobuild-config, common-config and clean-log to autobuild, common and clean_log. Autobuild
|
316
|
-
warns if it finds one the previous spelling but ignores it anyway
|
317
|
-
|
318
301
|
= Copyright and license
|
319
302
|
Author:: Sylvain Joyeux <sylvain.joyeux@m4x.org>
|
320
303
|
Copyright:: Copyright (c) 2005 Sylvain Joyeux
|
data/Rakefile
ADDED
@@ -0,0 +1,161 @@
|
|
1
|
+
# Rakefile for Autobuild
|
2
|
+
# Copyright 2005 by Sylvain Joyeux (sylvain.joyeux@m4x.org)
|
3
|
+
|
4
|
+
# Based on the Rakefile for MetaProject
|
5
|
+
# Copyright 2005 by Aslak Hellesoy (aslak.hellesoy@gmail.org)
|
6
|
+
# All rights reserved.
|
7
|
+
|
8
|
+
# This file is may be distributed under an MIT style license. See
|
9
|
+
# MIT-LICENSE for details.
|
10
|
+
|
11
|
+
$:.unshift('lib')
|
12
|
+
require 'meta_project'
|
13
|
+
require 'rake/gempackagetask'
|
14
|
+
require 'rake/contrib/rubyforgepublisher'
|
15
|
+
require 'rake/contrib/xforge'
|
16
|
+
require 'rake/clean'
|
17
|
+
require 'rake/testtask'
|
18
|
+
require 'rake/rdoctask'
|
19
|
+
|
20
|
+
# Versioning scheme: MAJOR.MINOR.PATCH
|
21
|
+
# MAJOR bumps when API is broken backwards
|
22
|
+
# MINOR bumps when the API is broken backwards in a very slight/subtle (but not fatal) way
|
23
|
+
# -OR when a new release is made and propaganda is sent out.
|
24
|
+
# PATCH is bumped for every API addition and/or bugfix (ideally for every commit)
|
25
|
+
# Later DamageControl can bump PATCH automatically.
|
26
|
+
#
|
27
|
+
# REMEMBER TO KEEP PKG_VERSION IN SYNC WITH THE CHANGES FILE!
|
28
|
+
PKG_NAME = "autobuild"
|
29
|
+
PKG_VERSION = "0.5"
|
30
|
+
PKG_FILE_NAME = "#{PKG_NAME}-#{PKG_VERSION}"
|
31
|
+
PKG_FILES = FileList[
|
32
|
+
'[A-Z]*',
|
33
|
+
'lib/**/*.rb',
|
34
|
+
'doc/**/*'
|
35
|
+
]
|
36
|
+
|
37
|
+
task :default => [:gem]
|
38
|
+
|
39
|
+
# Create a task to build the RDOC documentation tree.
|
40
|
+
rd = Rake::RDocTask.new("rdoc") do |rdoc|
|
41
|
+
rdoc.rdoc_dir = 'html'
|
42
|
+
# rdoc.template = 'kilmer'
|
43
|
+
# rdoc.template = 'css2'
|
44
|
+
# rdoc.template = 'doc/jamis.rb'
|
45
|
+
rdoc.title = "Autobuild"
|
46
|
+
rdoc.options << '--main' << 'README'
|
47
|
+
rdoc.rdoc_files.include('README', 'CHANGES')
|
48
|
+
rdoc.rdoc_files.include('lib/**/*.rb', 'doc/**/*.rdoc')
|
49
|
+
rdoc.rdoc_files.exclude('doc/**/*_attrs.rdoc')
|
50
|
+
end
|
51
|
+
|
52
|
+
# ====================================================================
|
53
|
+
# Create a task that will package the Rake software into distributable
|
54
|
+
# tar, zip and gem files.
|
55
|
+
|
56
|
+
spec = Gem::Specification.new do |s|
|
57
|
+
|
58
|
+
#### Basic information.
|
59
|
+
|
60
|
+
s.name = PKG_NAME
|
61
|
+
s.version = PKG_VERSION
|
62
|
+
s.summary = 'Rake-based utility to build and install multiple packages with dependencies'
|
63
|
+
s.description = <<EOF
|
64
|
+
Autobuild imports, configures, builds and installs various kinds of software packages.
|
65
|
+
It can be used in software development to make sure that nothing is broken in the
|
66
|
+
build process of a set of packages, or can be used as an automated installation tool.
|
67
|
+
EOF
|
68
|
+
|
69
|
+
s.files = PKG_FILES.to_a
|
70
|
+
s.require_path = 'lib'
|
71
|
+
|
72
|
+
#### Documentation and testing.
|
73
|
+
|
74
|
+
s.has_rdoc = true
|
75
|
+
s.extra_rdoc_files = rd.rdoc_files.reject { |fn| fn =~ /\.rb$/ }.to_a
|
76
|
+
s.rdoc_options <<
|
77
|
+
'--title' << 'Autobuild' <<
|
78
|
+
'--main' << 'README'
|
79
|
+
|
80
|
+
#### Author and project details.
|
81
|
+
|
82
|
+
s.author = "Sylvain Joyeux"
|
83
|
+
s.email = "sylvain.joyeux@m4x.org"
|
84
|
+
s.homepage = "http://autobuild.rubyforge.org"
|
85
|
+
s.rubyforge_project = "autobuild"
|
86
|
+
end
|
87
|
+
|
88
|
+
# Fix 1.8.4 - 1.8.3 issue
|
89
|
+
class << spec
|
90
|
+
def to_yaml
|
91
|
+
out = super
|
92
|
+
out = '--- ' + out unless out =~ /^---/
|
93
|
+
out
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
desc "Build Gem"
|
98
|
+
Rake::GemPackageTask.new(spec) do |pkg|
|
99
|
+
pkg.need_zip = true
|
100
|
+
pkg.need_tar = true
|
101
|
+
end
|
102
|
+
|
103
|
+
# Support Tasks ------------------------------------------------------
|
104
|
+
|
105
|
+
desc "Look for TODO and FIXME tags in the code"
|
106
|
+
task :todo do
|
107
|
+
Pathname.new(File.dirname(__FILE__)).egrep(/#.*(FIXME|TODO|TBD|DEPRECATED)/) do |match|
|
108
|
+
puts match
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
task :release => [:release_files, :publish_doc, :tag] # :publish_news,
|
113
|
+
|
114
|
+
task :verify_env_vars do
|
115
|
+
raise "RUBYFORGE_USER environment variable not set!" unless ENV['RUBYFORGE_USER']
|
116
|
+
raise "RUBYFORGE_PASSWORD environment variable not set!" unless ENV['RUBYFORGE_PASSWORD']
|
117
|
+
end
|
118
|
+
|
119
|
+
task :publish_doc => :verify_env_vars do
|
120
|
+
publisher = Rake::RubyForgePublisher.new('autobuild', ENV['RUBYFORGE_USER'])
|
121
|
+
publisher.upload
|
122
|
+
end
|
123
|
+
|
124
|
+
desc "Release files on RubyForge"
|
125
|
+
task :release_files => [:gem, :verify_env_vars] do
|
126
|
+
release_files = FileList[
|
127
|
+
"pkg/#{PKG_FILE_NAME}.gem"
|
128
|
+
]
|
129
|
+
|
130
|
+
Rake::XForge::Release.new(MetaProject::Project::XForge::RubyForge.new('autobuild')) do |release|
|
131
|
+
# Never hardcode user name and password in the Rakefile!
|
132
|
+
release.user_name = ENV['RUBYFORGE_USER']
|
133
|
+
release.password = ENV['RUBYFORGE_PASSWORD']
|
134
|
+
release.files = release_files.to_a
|
135
|
+
release.release_name = "Autobuild #{PKG_VERSION}"
|
136
|
+
# The rest of the options are defaults (among others, release_notes and release_changes, parsed from CHANGES)
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
desc "Publish news on RubyForge"
|
141
|
+
task :publish_news => [:gem, :verify_env_vars] do
|
142
|
+
release_files = FileList[
|
143
|
+
"pkg/#{PKG_FILE_NAME}.gem"
|
144
|
+
]
|
145
|
+
|
146
|
+
Rake::XForge::NewsPublisher.new(MetaProject::Project::XForge::RubyForge.new('autobuild')) do |news|
|
147
|
+
# Never hardcode user name and password in the Rakefile!
|
148
|
+
news.user_name = ENV['RUBYFORGE_USER']
|
149
|
+
news.password = ENV['RUBYFORGE_PASSWORD']
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
desc "Tag all the svn files with the latest release number (REL=x.y.z)"
|
154
|
+
task :tag do
|
155
|
+
reltag = "RELEASE_#{PKG_VERSION.gsub(/\./, '_')}"
|
156
|
+
puts "Tagging svn with [#{reltag}]"
|
157
|
+
base_url = %{svn+ssh://#{RUBYFORGE_USER}@rubyforge.org/var/svn/autobuild}
|
158
|
+
sh %{svn cp #{base_url}/trunk/autobuild #{base_url}/tags/#{reltag}}
|
159
|
+
end
|
160
|
+
|
161
|
+
|
@@ -1,117 +1,106 @@
|
|
1
1
|
require 'autobuild/exceptions'
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
3
|
+
module Autobuild
|
4
|
+
class UndefinedVariable < ConfigException
|
5
|
+
attr_reader :name
|
6
|
+
attr_accessor :reference
|
7
|
+
def initialize(name, reference = [])
|
8
|
+
@name = name
|
9
|
+
@reference = reference
|
9
10
|
end
|
10
|
-
end
|
11
|
-
end
|
12
11
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
def initialize(name, reference = [])
|
17
|
-
@name = name
|
18
|
-
@reference = reference
|
12
|
+
def to_s
|
13
|
+
"undefined variable '#{name}' in #{reference.join('/')}"
|
14
|
+
end
|
19
15
|
end
|
20
16
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
17
|
+
class Interpolator
|
18
|
+
VarDefKey = 'defines'
|
19
|
+
MatchExpr = '\$\{([^}]+)\}|\$(\w+)'
|
20
|
+
PartialMatch = Regexp.new(MatchExpr)
|
21
|
+
WholeMatch = Regexp.new("^(?:#{MatchExpr})$")
|
25
22
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
PartialMatch = Regexp.new(MatchExpr)
|
30
|
-
WholeMatch = Regexp.new("^(?:#{MatchExpr})$")
|
23
|
+
def self.interpolate(config, parent = nil)
|
24
|
+
Interpolator.new(config, parent).interpolate
|
25
|
+
end
|
31
26
|
|
32
|
-
|
33
|
-
|
34
|
-
|
27
|
+
def initialize(node, parent = nil, variables = {})
|
28
|
+
@node = node
|
29
|
+
@variables = {}
|
30
|
+
@defines = {}
|
31
|
+
@parent = parent
|
32
|
+
end
|
35
33
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
34
|
+
def interpolate
|
35
|
+
case @node
|
36
|
+
when Hash
|
37
|
+
@defines = (@node[VarDefKey] || {})
|
38
|
+
|
39
|
+
interpolated = Hash.new
|
40
|
+
@node.each do |k, v|
|
41
|
+
begin
|
42
|
+
next if k == VarDefKey
|
43
|
+
interpolated[k] = Interpolator.interpolate(v, self)
|
44
|
+
rescue UndefinedVariable => e
|
45
|
+
e.reference.unshift k
|
46
|
+
raise e
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
interpolated
|
42
51
|
|
43
|
-
|
44
|
-
|
45
|
-
when Hash
|
46
|
-
@defines = (@node[VarDefKey] || {})
|
52
|
+
when Array
|
53
|
+
@node.collect { |v| Interpolator.interpolate(v, self) }
|
47
54
|
|
48
|
-
|
49
|
-
@node.each do |k, v|
|
55
|
+
else
|
50
56
|
begin
|
51
|
-
|
52
|
-
interpolated[k] = Interpolator.interpolate(v, self)
|
57
|
+
each_interpolation(@node) { |varname| value_of(varname) }
|
53
58
|
rescue UndefinedVariable => e
|
54
|
-
e.reference.unshift
|
59
|
+
e.reference.unshift @node.to_str if @node.respond_to?(:to_str)
|
55
60
|
raise e
|
56
61
|
end
|
57
62
|
end
|
58
|
-
|
59
|
-
interpolated
|
60
|
-
|
61
|
-
when Array
|
62
|
-
@node.collect { |v| Interpolator.interpolate(v, self) }
|
63
|
-
|
64
|
-
else
|
65
|
-
begin
|
66
|
-
each_interpolation(@node) { |varname| value_of(varname) }
|
67
|
-
rescue UndefinedVariable => e
|
68
|
-
e.reference.unshift @node.to_str if @node.respond_to?(:to_str)
|
69
|
-
raise e
|
70
|
-
end
|
71
63
|
end
|
72
|
-
end
|
73
64
|
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
65
|
+
def value_of(name)
|
66
|
+
if @defines.has_key?(name)
|
67
|
+
value = @defines.delete(name)
|
68
|
+
@variables[name] = each_interpolation(value) { |varname|
|
69
|
+
begin
|
70
|
+
value_of(varname)
|
71
|
+
rescue UndefinedVariable => e
|
72
|
+
if e.varname == name
|
73
|
+
raise ConfigException, "cyclic reference found in definition of '#{name}'"
|
74
|
+
else
|
75
|
+
raise
|
76
|
+
end
|
85
77
|
end
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
@
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
78
|
+
}
|
79
|
+
elsif @variables.has_key?(name)
|
80
|
+
@variables[name]
|
81
|
+
elsif @parent
|
82
|
+
@parent.value_of(name)
|
83
|
+
elsif ENV[name.to_s]
|
84
|
+
ENV[name.to_s]
|
85
|
+
else
|
86
|
+
raise UndefinedVariable.new(name)
|
87
|
+
end
|
96
88
|
end
|
97
|
-
end
|
98
89
|
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
90
|
+
def each_interpolation(value)
|
91
|
+
return value if (!value.respond_to?(:to_str) || value.empty?)
|
92
|
+
|
93
|
+
# Special case: if 'value' is *only* an interpolation, avoid
|
94
|
+
# conversion to string
|
95
|
+
if match = WholeMatch.match(value)
|
96
|
+
return yield($1 || $2)
|
97
|
+
end
|
107
98
|
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
interpolated << data.pre_match << yield(varname)
|
99
|
+
return value.gsub(PartialMatch) { |match|
|
100
|
+
varname = $1 || $2
|
101
|
+
yield(varname)
|
102
|
+
}
|
113
103
|
end
|
114
|
-
return data ? (interpolated << data.post_match) : value
|
115
104
|
end
|
116
105
|
end
|
117
106
|
|