bake 0.1.2 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +11 -0
  3. data/.rspec +3 -0
  4. data/.travis.yml +6 -0
  5. data/Gemfile +7 -0
  6. data/Gemfile.lock +40 -0
  7. data/README.md +99 -0
  8. data/Rakefile +6 -0
  9. data/bake.gemspec +25 -0
  10. data/bin/bake +25 -10
  11. data/lib/bake.rb +21 -140
  12. data/lib/bake/book.rb +79 -0
  13. data/lib/bake/command.rb +29 -0
  14. data/lib/bake/command/invoke.rb +67 -0
  15. data/lib/bake/command/list.rb +76 -0
  16. data/lib/bake/command/top.rb +111 -0
  17. data/lib/bake/context.rb +103 -110
  18. data/lib/bake/loader.rb +82 -0
  19. data/lib/bake/loaders.rb +110 -0
  20. data/lib/bake/recipe.rb +109 -0
  21. data/lib/bake/version.rb +23 -0
  22. metadata +73 -85
  23. data/CHANGELOG +0 -38
  24. data/CONCEPTS +0 -54
  25. data/MIT-LICENSE +0 -21
  26. data/README +0 -38
  27. data/REFERENCE +0 -2
  28. data/TUTORIAL +0 -128
  29. data/lib/bake/addon.rb +0 -20
  30. data/lib/bake/configuration.rb +0 -126
  31. data/lib/bake/extensions.rb +0 -3
  32. data/lib/bake/extensions/class.rb +0 -11
  33. data/lib/bake/extensions/object.rb +0 -22
  34. data/lib/bake/extensions/string.rb +0 -22
  35. data/lib/bake/file_target.rb +0 -19
  36. data/lib/bake/plugin.rb +0 -49
  37. data/lib/bake/plugins/cpp.rb +0 -188
  38. data/lib/bake/plugins/cpp/darwin.rb +0 -26
  39. data/lib/bake/plugins/cpp/gcc.rb +0 -14
  40. data/lib/bake/plugins/cpp/gcc_toolset_base.rb +0 -101
  41. data/lib/bake/plugins/cpp/msvc.rb +0 -118
  42. data/lib/bake/plugins/cpp/qt.rb +0 -53
  43. data/lib/bake/plugins/cpp/toolset_base.rb +0 -56
  44. data/lib/bake/plugins/macro.rb +0 -18
  45. data/lib/bake/plugins/runner.rb +0 -40
  46. data/lib/bake/plugins/system.rb +0 -30
  47. data/lib/bake/project.rb +0 -91
  48. data/lib/bake/project_loader.rb +0 -116
  49. data/lib/bake/system_utils.rb +0 -42
  50. data/lib/bake/target.rb +0 -155
  51. data/lib/bake/toolset.rb +0 -25
  52. data/lib/bake_version.rb +0 -5
  53. data/test/test_bake.rb +0 -2
  54. data/test/test_configuration.rb +0 -58
data/CHANGELOG DELETED
@@ -1,38 +0,0 @@
1
- = Bake Changelog
2
-
3
- == Version 0.1.2 (2007-05-17)
4
-
5
- * Implemented Target#products which returns the set of output files generated by the target
6
- * Using Target#products, implemented Target#stale? and Target#mtime in a general way
7
- * Moved C++ include file detection into IncludeList class which is now a dependency of all Cpp::Source
8
- * Created a Runner target class which can be used to run any commands, not just C++ executables
9
- * Added simple circular dependency detection during build phase
10
- * Implemented Target#to_s for more consistent error messages
11
- * Dependency resolution now uses :search_projects property to resolve unqualified target references (which always includes the current project)
12
- * Libraries and executables no longer re-link to changed dynamic libraries unless they are forced to by an altered header dependency
13
- * Target subclass initialization is now done via the post_initialization method, making the initialization methods much simpler
14
- * All target constructors now support a properties hash which initializes the given properties before post_initialization
15
- * Added Project#map method which maps target names to fully qualified dir:name paths
16
- * Implemented post-build dependencies which are built after their dependents are built (useful for unit tests)
17
- * Fixed QT Moc support
18
- * Trashed Configuration#req and associated "requirements" functionality as it proved not very useful
19
- * Major overhaul of plugin support, plugins are now searched for in any directories given in :plugin_paths
20
- * Moved all Ruby core class extensions into the bake/extensions directory
21
- * Toolsets now use a +SystemUtils+ instance for doing all file and shell operations
22
- * Introduced --dry-run and --verbose command line parameters
23
- * Dumped all the old useless unit tests (they will be re-introduced for 2.0)
24
-
25
- == Version 0.1.1 (2007-05-02)
26
-
27
- * Created a plugin infrastructure whereby missing constants now result in a search of the plugins/ directory
28
- * Implemented Addon module which enables adding commands to bakefile contexts via the import method
29
- * Removed scheme concept in favour of addon plugin classes so all concre Toolset subclasses (e.g. Cpp::Gcc) are now addon plugins
30
- * Context#macro and Context#glob were moved to addon classes named Macro and System respectively which are plugins that are automatically imported into bakefile contexts
31
- * Targets no longer found by moving up the target tree, instead all paths are relative to the current project, that is, the project owning the current target
32
- * Added some content to the CONCEPTS document
33
- * Introduced Context#using method which is similar to import, except that commands are looked up from addons stored in the :addons property of the current target
34
- * Removed Cpp::Library#src and Cpp::Executable#src in favor of listing file dependencies in the dep list
35
- * Added FileTarget class that represents simple file dependencies
36
- * Created Target#add_dep method that can be overridden to manage individual dependency additions (for example to insert a Cpp::Object between a FileTarget and main Cpp target)
37
- * Child targets are no longer considered dependencies and so are not built automatically when their parents are built
38
-
data/CONCEPTS DELETED
@@ -1,54 +0,0 @@
1
- = Concepts
2
-
3
- == Bake's Philosophy
4
-
5
- Bake is a Ruby based build system similar to Rake[http://rake.rubyforge.org] and Rant[http://rant.rubyforge.org]. Unlike either of these systems, however, there is a logical separation between the the components that are being built and the methods used to build them. This separation is important for large projects having many logical components such as executables and libraries, and also supporting many compilers or platforms.
6
-
7
- In the good old days when Make was king, adding another supported platform to a project was usually a traumatic experience. The chief reason for the difficulty was almost always that the declaration of a component and the actions executed to build that component were tightly coupled. So the structure of the project was highly dependent on the content of the actions that build it.
8
-
9
- The pitfalls of Make are readily apparent with C++ projects that support Microsoft Visual Studio and GCC. Simple projects are easy enough to accomodate in Make, but as soon as you need to support dynamic libraries and unit test runners and platform dependent build parameters you can quickly find the number of lines in your Make code outpacing the code for your project!
10
-
11
- The fundamental reason for this is that your project structure and the actions that build your project are orthogonal concepts. Make forces you to intertwine these two concepts causing your Makefiles to balloon in size. Bake, on the other hand, disentangles the target and toolset concepts and allows you to grow the set of targets and the toolsets that build them independently. This is the primary goal of the Bake project.
12
-
13
- Another goal is to provide users with a large set of pre-written toolsets that will perform the actions required to turn your project into built products. Thus, in most cases, the end user simply defines the structure of the their project, indicates which toolsets to use and Bake does the rest.
14
-
15
- The end result is that Bake requires a bare minimum of code to provide all the instructions that are needed to build a project. Furthermore, the bulk of the code defines the structure of the project rather than the behaviour of the build tools involved, so the definition files also act as a guide to the project layout, instead of being a distracting maze of complex build actions.
16
-
17
- == Targets
18
-
19
- In Bake, projects are broken up into components called *targets*. Targets are the basic unit of a project and can represent C libraries, zip files, Java classes or anything else that belongs in a project.
20
-
21
- Targets are tree-like. Each target has a single parent target and can have any number of child targets. Every target that belongs in a particular project is connected in a single tree.
22
-
23
- === Products
24
-
25
- Every target can have a number of *products*. The products of a target are the concrete set of files that are created during the build process.
26
-
27
- === Dependencies
28
-
29
- Targets are related to each other by two relations. The first is the parent-child relation that makes up the tree structure of a project. The other is the *dependency* relation.
30
-
31
- Before a particular target is built, there are zero or more dependencies that must be built first. If any of the dependencies fails to build, the target will fail to be built.
32
-
33
- Dependencies have two roles for a target. First, to partially determine the order in which targets will be built as outlined above. Second, their products are used by dependent targets to build its products. For example, an executable target may depend on the functionality available in a library and thus it must link against that library.
34
-
35
- === Properties
36
-
37
- === Requirements
38
-
39
- == Bakefiles
40
-
41
- === Commands
42
-
43
- === Projects
44
-
45
- == Toolsets
46
-
47
- == Features
48
-
49
- === Macros
50
-
51
- === Plugins
52
-
53
- === Addins
54
-
@@ -1,21 +0,0 @@
1
- Copyright (c) 2007 Dylan Trotter
2
-
3
- Permission is hereby granted, free of charge, to any person obtaining
4
- a copy of this software and associated documentation files (the
5
- "Software"), to deal in the Software without restriction, including
6
- without limitation the rights to use, copy, modify, merge, publish,
7
- distribute, sublicense, and/or sell copies of the Software, and to
8
- permit persons to whom the Software is furnished to do so, subject to
9
- the following conditions:
10
-
11
- The above copyright notice and this permission notice shall be
12
- included in all copies or substantial portions of the Software.
13
-
14
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
- LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
- OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
- WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
-
data/README DELETED
@@ -1,38 +0,0 @@
1
- = Bake
2
-
3
- Bake is a build automation utility somewhat akin to the Ruby tool Rake. Like Rake[http://rake.rubyforge.org/], Bake definition files (or <i>bakefiles</i>) are written in pure Ruby. The similarities between Rake and Bake pretty much end there, however. Bake generally takes a much higher level approach. Instead of defining tasks and specifying the commands that get executed by that task, you define high level products, such as C++ libraries or Java WAR files in your bakefiles. Thus bakefiles are simple, readable definitions of the final products of your project.
4
-
5
- == Download
6
-
7
- You can download the most recent version of Bake at here[http://rubyforge.org/frs/?group_id=3477]
8
-
9
- == Installation
10
-
11
- Currently, Bake only support Gem installs. Simply run:
12
-
13
- % gem install bake
14
-
15
- If you don't like how Gems taste, it's probably not difficult to set up Bake from source. Download one of the source distributions and let me know how it works out :)
16
-
17
- == Further Reading
18
-
19
- Tutorial Introduction:: TUTORIAL[link:files/TUTORIAL.html]
20
-
21
- Concepts:: CONCEPTS[link:files/CONCEPTS.html]
22
-
23
- Reference:: REFERENCE[link:files/REFERENCE.html]
24
-
25
- == History
26
-
27
- Bake took inspiration from the many great build tools that exist out there. In particular, the idea of using Ruby as a domain specific language for build systems was pioneered Jim Weirich in his Make-like utility, Rake. After working with Rake for some time, however, I found that it was difficult to maintain large projects effectively due to the fact that Rake is quite low-level.
28
-
29
- Soon after I abandoned Rake, I found another great Ruby-based system called Rant created by Stefan Lang. Rant was slightly better and it had many great ideas for how a Ruby-based build system should work such as improved error messages, good support for larger multi-file projects, etc. I tried for a time to write Bake as extensions to Rant since I felt it a good starting point. In the end, however, it had similar limitations to Rake and I abandoned further work on Rant.
30
-
31
- On the other end of the spectrum there's {Boost.Build}[http://www.boost.org/tools/build/jam_src/index.html] which is the build system used for the {Boost C++ Libraries}[http://boost.org/]. Boost.Build does have a reasonably good project-based approach, however, the syntax is abominable. It's based on {Perforce Jam}[http://www.perforce.com/jam/jam.html] which is quite possibly the most hideous build system ever conceived. Ugly doesn't begin to describe the syntax, nor incomprehensible the so-called Jamfiles.
32
-
33
- The panacea is Bake. I think it satisfies my rather loose requirements: pretty, simple for simple projects, powerful for large projects and fast. The items in this list are at various stages in their evolution, but I think it solves my build problems better than any of the others I listed above.
34
-
35
- == License
36
-
37
- :include: MIT-LICENSE
38
-
data/REFERENCE DELETED
@@ -1,2 +0,0 @@
1
- = Reference
2
-
data/TUTORIAL DELETED
@@ -1,128 +0,0 @@
1
- = Tutorial Introduction
2
-
3
- == A C++ Executable
4
-
5
- === Bakefiles and Targets
6
-
7
- Once you've installed Bake, you should be able to execute it by running the <tt>bake</tt> command. This will cause Bake to load a file called <i>root.bake</i> in the current working directory or some ancestor directory of the current directory. This <b>bakefile</b> defines the contents of the project including any settings required to properly make the build targets. Let's see the contents of <i>root.bake</i> for a simple C++ project consisting of a single source file, <i>main.cpp</i>, which gets compiled into an executable called <i>test</i>:
8
-
9
- # root.bake
10
- exe 'test' do
11
- dep 'main.cpp'
12
- end
13
-
14
- dep 'test'
15
-
16
- The <tt>exe</tt> command specifies that we'd like to create an executable <b>target</b>. A target is any product that gets created as a result of the build process. There are many kinds of targets, such as <tt>lib</tt>s, or C++ libraries, etc. To make this example a little more concrete, let's also create <i>main.cpp</i>:
17
-
18
- // main.cpp
19
- #include <iostream>
20
- int main()
21
- {
22
- std::cout << "hello bake" << std::endl;
23
- return 0;
24
- }
25
-
26
- Both these files should be in the same directory, call it <i>test/</i>. The layout is as follows:
27
-
28
- test/
29
- root.bake
30
- main.cpp
31
-
32
- If you run <tt>bake</tt> from the <i>test/</i> directory you should see output resembling "<tt>root.bake:1: unknown command 'exe'</tt>". The reason for this is that we have not specified what <b>tooset</b> we will be using to build C++ targets. Bake supports a number of C++ toolsets (consult the Reference for full details) and each toolset should treat our test project identically, so which toolset you use should not matter. For the purposes of this example, I'll use the <tt>gcc</tt> toolset.
33
-
34
- === The <tt>using</tt> Directive
35
-
36
- Generally, it is a good idea to keep your project definitions separate from which toolset you're using since your choice of toolset is conceptually distinct from your project layout. This is especially true from cross-platform projects. For this reason, in this project we'll keep this information in a separate bakefile called <i>config.bake</i> which will also live in the <i>test/</i> directory:
37
-
38
- # config.bake
39
- using Cpp::Gcc
40
-
41
- The <tt>using</tt> directive above tells Bake that when building C++ targets, it should use the <tt>gcc</tt> toolset. If you now run the <tt>bake</tt> command, and as long as your toolset is properly configured, you should get an executable file called <i>test</i> (or <i>test.exe</i> on Windows platforms) in the <i>test/</i> directory.
42
-
43
- === Properties
44
-
45
- Unfortunately, the <i>test</i> executable will probably be accompanied by a number of by-products of the build procedure and so our <i>test/</i> directory is now getting cluttered. It is common to keep products of the build in a separate output directory so that they don't get mixed up with our source files. The output directory is just one of a number of options supported by <tt>exe</tt> targets. To specify an output directory we set the <tt>:outdir</tt> <b>property</b> on <tt>test</tt>. Properties are just key/value pairs that are used by the toolset to output the desired product. The simplest way to set a property is to use the <tt>opt</tt> command on the <tt>test</tt> target, like this:
46
-
47
- # root.bake
48
-
49
- exe 'test' do
50
- opt :outdir => 'bin'
51
- dep 'main.cpp'
52
- end
53
-
54
- dep 'test'
55
-
56
- Note that property names are <b>symbols</b> preceded by a colon (:) whereas, in this case, the property value is a <b>string</b>. Property values can be any of a number of different types such as strings, booleans, numbers, etc.
57
-
58
- Delete all the product files generated by the last build so that your directory structure looks like:
59
-
60
- test/
61
- config.bake
62
- root.bake
63
- main.cpp
64
-
65
- Now run Bake again. Note that a new directory called <i>bin/</i> has been created and that all the products of the build have been placed inside. C++ executable targets have a number of other properties that affect different aspects of the build. For example, to turn off multithreading for a single threaded application, you would specify "<tt>opt :multithreaded? => false</tt>". Note that we've used a boolean value type instead of a string. The type is important as a value of <tt>'false'</tt> would result in the opposite behavior we would expect (this is because strings always evaluate to true when examined in a boolean context). For a full list of target properties and their types, see the Reference.
66
-
67
- == A More Complicated Example
68
-
69
- === Multiple Targets, One Bakefile
70
-
71
- So far we've seen Bake build a simple C++ executable, and it did the job pretty well. Bake's strengths, however, are only seen when we have more complicated projects to test it with. Bake is designed with large projects in mind and it makes managing these projects a snap.
72
-
73
- To see how Bake handles multi-directory projects, let's create a project composed of a C++ library and an executable that depends on the library. Let's try the following directory structure:
74
-
75
- test2/
76
- test_lib/
77
- source1.cpp
78
- source2.cpp
79
- test_exe/
80
- source1.cpp
81
-
82
- As a first try at managing this project, let's create a <i>root.bake</i> in the <i>test2</i> directory that contains the definitions for both <tt>test_lib</tt> and <tt>test_exe</tt>:
83
-
84
- # root.bake
85
- lib 'test_lib' do
86
- dep 'test_lib/source1.cpp', 'test_lib/source2.cpp'
87
- end
88
-
89
- exe 'test_exe' do
90
- dep 'test_lib', 'test_exe/source1.cpp'
91
- end
92
-
93
- dep 'test_exe'
94
-
95
- Here we have created a <tt>lib</tt> target called <tt>test_lib</tt> containing two source files, and an executable file that depends on the library and another source file. This is pretty simple and will probably seem to work, however, there's an insidious bug waiting to cause trouble when you least expect it. Note that there are two files called <i>source1.cpp</i>. In each case, a C++ object file called <i>source1.o</i> (or <i>source1.obj</i> on Windows) will be created in the <i>test2/</i> directory, the object file from <tt>test_exe</tt> will overwrite the object file from <tt>test_lib</tt>. This will not immediately cause a problem, since the library object file was added to the library before the executable object file was created but it will almost certainly cause problems later on.
96
-
97
- === More About Properties
98
-
99
- The easiest way to avoid conflicts where output files overwrite eachother is to set the <tt>:outdir</tt> property differently on each target so that the object files will live in different directories. To do this, however, we're going to take a shortcut and only set the output directory once:
100
-
101
- # root.bake
102
- opt :outdir => 'bin/${name}'
103
- lib 'test_lib' do
104
- opt :name => 'test_lib'
105
- dep 'test_lib/source1.cpp', 'test_lib/source2.cpp'
106
- end
107
-
108
- exe 'test_exe' do
109
- opt :name => 'test_exe'
110
- dep 'test_lib', 'test_exe/source1.cpp'
111
- end
112
-
113
- dep 'test_exe'
114
-
115
- If you run Bake now, the outputs from <tt>test_lib</tt> will end up in <i>test2/bin/test_lib/</i> and the outputs from <tt>test_exe</tt> will end up in <i>test2/bin/test_exe</i>. If you're confused, don't worry, we've taken two steps forward here. Not only is the value of the <tt>:outdir</tt> property not explicitly set on either target, but it's out in no-man's land, what gives? Furthermore, what's up with the <tt>${name}</tt> business?
116
-
117
- The answer to the first question is related to an important fact about targets: they are tree-like. Every target (except the root target, which we'll get into later) has a single parent target, and many targets have child targets. So what target is the parent of <tt>test_lib</tt> and <tt>test_exe</tt>? An implicit <b>project</b> target that is created when <i>root.bake</i> is processed. Therefore, the <tt>opt</tt> command is being executed on the implicit project target and so <tt>:outdir</tt> is set for the project.
118
-
119
- Furthermore, properties are inherited. So if a property is explicitly defined for a parent target but is not explicitly defined for the child, then the property for the child is the same as that for the parent. Properties can be overridden by explicitly using the <tt>opt</tt> command on the child, in which case the parent's property value will be ignored.
120
-
121
- So in the example above, the <tt>:outdir</tt> property is inherited by the <tt>test_lib</tt> and <tt>test_exe</tt> targets as <tt>'bin/${name}'</tt>.
122
-
123
- The answer to the second question is even simpler. String property values are dynamic. Any <tt>${...}</tt> tokens found in the string will be evaluated when the property is queried. In addition, it will be queried in the context of the target being queried, not the target where the property was originally defined. So when the GCC toolset builds <tt>test_lib</tt> and <tt>test_exe</tt>, it will query the <tt>:outdir</tt> property on each target and it will evaluate to <tt>'bin/test_lib'</tt> and <tt>'bin/test_exe'</tt> respectively since we've defined the <tt>:name</tt> property for each appropriately.
124
-
125
- === Modular Bakefiles
126
-
127
- TODO
128
-
@@ -1,20 +0,0 @@
1
- module Bake
2
- module Addon
3
- def command(name, method = nil, &block)
4
- if !block
5
- method ||= name
6
- addon = self
7
- block = Proc.new do |*args|
8
- block = args.last.is_a?(Proc) ? args.pop : nil
9
- addon.send(method, self, *args, &block)
10
- end
11
- end
12
- commands[name] = block
13
- end
14
-
15
- def commands
16
- return @commands ||= { }
17
- end
18
- end
19
- end
20
-
@@ -1,126 +0,0 @@
1
- module Bake
2
- class PropertyNotFoundException < RuntimeError; end
3
- class TemplateEvaluationException < RuntimeError; end
4
-
5
- module Configuration
6
- def has_prop?(key)
7
- cfg = self
8
- while cfg
9
- return true if cfg.has_prop_impl(key)
10
- cfg = cfg.parent
11
- end
12
- return false
13
- end
14
-
15
- def [](key)
16
- return get(key)
17
- end
18
-
19
- def get(key)
20
- if multival(key)
21
- cfg = self
22
- opts = []
23
- while cfg
24
- if cfg.options.has_key?(key)
25
- cfg.options[key].each { |val| opts << value_of(val) }
26
- end
27
- cfg = cfg.parent
28
- end
29
- return opts
30
- else
31
- cfg = self
32
- default = nil
33
- found_default = false
34
- while cfg
35
- if cfg.options.has_key?(key)
36
- return value_of(cfg.options[key])
37
- end
38
- if !found_default && cfg.defaults.has_key?(key)
39
- default = cfg.defaults[key]
40
- found_default = true
41
- end
42
- cfg = cfg.parent
43
- end
44
- if found_default
45
- val = value_of(default)
46
- return val
47
- end
48
- raise PropertyNotFoundException, "no such property '#{key}'"
49
- end
50
- end
51
-
52
- def is?(prop)
53
- key, val = key_val(prop)
54
- raise 'no multivalue comparisons' if multival(key)
55
- begin
56
- return get(key) == val
57
- rescue PropertyNotFoundException
58
- return false
59
- end
60
- end
61
-
62
- def opt(prop)
63
- key, val = key_val(prop)
64
- if multival(key)
65
- vals = options[key] ||= []
66
- if val.respond_to?(:to_ary)
67
- vals.concat(val)
68
- else
69
- vals << val
70
- end
71
- else
72
- options[key] = val
73
- end
74
- end
75
-
76
- def default(prop)
77
- key, val = key_val(prop)
78
- raise 'no multivalue defaults' if multival(key)
79
- defaults[key] = val
80
- end
81
-
82
- protected
83
- def options
84
- return @options ||= {}
85
- end
86
-
87
- def defaults
88
- return @defaults ||= {}
89
- end
90
-
91
- def has_prop_impl(key)
92
- return options.has_key?(key) ||
93
- defaults.has_key?(key)
94
- end
95
-
96
- def key_val(prop)
97
- raise 'invalid args' if !prop.respond_to?(:to_hash)
98
- prop = prop.to_hash
99
- raise 'bad' if prop.size != 1
100
- key = prop.keys[0]
101
- return [ key, prop[key] ]
102
- end
103
-
104
- def multival(key)
105
- return key.to_s[-1, 1] == 's'
106
- end
107
-
108
- def value_of(val)
109
- if val.instance_of?(String)
110
- return val.gsub(/\$\{(.*?)\}/) do
111
- name = $1
112
- if has_prop?(name.to_sym)
113
- get(name.to_sym)
114
- elsif ENV.has_key?(name)
115
- ENV[name]
116
- else
117
- raise TemplateEvaluationException,
118
- "no property or environment variable '#{name}'"
119
- end
120
- end
121
- end
122
- return val
123
- end
124
- end
125
- end
126
-
@@ -1,3 +0,0 @@
1
- Dir[File.join(File.dirname(__FILE__), 'extensions', '*.rb')].each do |file|
2
- require 'bake/extensions/' + File.basename(file, '.rb')
3
- end
@@ -1,11 +0,0 @@
1
- class Class
2
- # Returns true if +self+ inherits from +ancestor+
3
- def inherits?(ancestor)
4
- sup = self
5
- while sup
6
- return true if sup.equal?(ancestor)
7
- sup = sup.superclass
8
- end
9
- return false
10
- end
11
- end