kodekopelli 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (74) hide show
  1. data/CHANGELOG +3 -0
  2. data/LICENSE +32 -0
  3. data/README +78 -0
  4. data/Rakefile +87 -0
  5. data/bin/kodekopelli +5 -0
  6. data/examples/faqomatic/config.xml +40 -0
  7. data/examples/faqomatic/content.rhtml +376 -0
  8. data/examples/faqomatic/generated/README.txt +1 -0
  9. data/examples/faqomatic/includes/shampoo_answer.txt +1 -0
  10. data/examples/faqomatic/templates/faqs.txt +22 -0
  11. data/examples/faqomatic/templates/great_big.txt +3 -0
  12. data/examples/faqomatic/templates/html_wrapper.txt +9 -0
  13. data/examples/thankyounotes/config.xml +18 -0
  14. data/examples/thankyounotes/content.rhtml +528 -0
  15. data/examples/thankyounotes/generated/README.txt +1 -0
  16. data/examples/thankyounotes/includes/poem.txt +3 -0
  17. data/examples/thankyounotes/templates/thanks.txt +14 -0
  18. data/examples/treemenu/config.xml +110 -0
  19. data/examples/treemenu/content.rhtml +324 -0
  20. data/examples/treemenu/generated/README.txt +1 -0
  21. data/examples/treemenu/templates/authorized.txt +1 -0
  22. data/examples/treemenu/templates/menu_category.txt +4 -0
  23. data/examples/treemenu/templates/menu_item.txt +3 -0
  24. data/examples/treemenu/templates/simple_menu.txt +3 -0
  25. data/lib/kodekopelli.rb +56 -0
  26. data/lib/kodekopelli/expandable_properties.rb +63 -0
  27. data/lib/kodekopelli/file_generator.rb +726 -0
  28. data/lib/kodekopelli/frozen_key_hash.rb +67 -0
  29. data/lib/kodekopelli/minimal_logger.rb +50 -0
  30. data/lib/kodekopelli/properties_file.rb +41 -0
  31. data/lib/kodekopelli/util.rb +30 -0
  32. data/rakefile +87 -0
  33. data/test/abstract_unit.rb +4 -0
  34. data/test/fixtures/definitions/invalid/empty +0 -0
  35. data/test/fixtures/definitions/invalid/gibberish.txt +6 -0
  36. data/test/fixtures/definitions/kodekopelli.xsd +95 -0
  37. data/test/fixtures/definitions/valid/empty_files.xml +49 -0
  38. data/test/fixtures/definitions/valid/kodekopelli_rocks_files.xml +359 -0
  39. data/test/fixtures/definitions/valid/simplest.xml +8 -0
  40. data/test/fixtures/includes/bang.txt +1 -0
  41. data/test/fixtures/includes/c.txt +1 -0
  42. data/test/fixtures/includes/d.txt +1 -0
  43. data/test/fixtures/includes/e.txt +1 -0
  44. data/test/fixtures/includes/empty.txt +0 -0
  45. data/test/fixtures/includes/i.txt +1 -0
  46. data/test/fixtures/includes/k.txt +1 -0
  47. data/test/fixtures/includes/k_upper.txt +1 -0
  48. data/test/fixtures/includes/kodekopelli_rocks.txt +1 -0
  49. data/test/fixtures/includes/l.txt +1 -0
  50. data/test/fixtures/includes/o.txt +1 -0
  51. data/test/fixtures/includes/p.txt +1 -0
  52. data/test/fixtures/includes/r.txt +1 -0
  53. data/test/fixtures/includes/s.txt +1 -0
  54. data/test/fixtures/includes/space.txt +1 -0
  55. data/test/fixtures/properties/comments.properties +17 -0
  56. data/test/fixtures/properties/empty.properties +0 -0
  57. data/test/fixtures/properties/expandable.properties +2 -0
  58. data/test/fixtures/properties/none_valid.properties +1 -0
  59. data/test/fixtures/properties/simple.properties +5 -0
  60. data/test/fixtures/templates/anything_att.txt +1 -0
  61. data/test/fixtures/templates/anything_att_prop.txt +1 -0
  62. data/test/fixtures/templates/anything_prop.txt +1 -0
  63. data/test/fixtures/templates/anything_prop_att.txt +1 -0
  64. data/test/fixtures/templates/blank.txt +0 -0
  65. data/test/fixtures/templates/child_output.txt +1 -0
  66. data/test/fixtures/templates/kodekopelli_blanks +1 -0
  67. data/test/tc_expandable_properties.rb +106 -0
  68. data/test/tc_file_generator.rb +20 -0
  69. data/test/tc_frozen_key_hash.rb +34 -0
  70. data/test/tc_properties_file.rb +52 -0
  71. data/test/tc_util.rb +55 -0
  72. data/test/ts_all_tests.rb +9 -0
  73. data/test/ts_functional.rb +86 -0
  74. metadata +133 -0
@@ -0,0 +1,67 @@
1
+ module Kodekopelli # :nodoc:
2
+ # A _FrozenKeyHash_ differs from a normal _Hash_ in that, once
3
+ # a value has been set for a particular key, subsequent attempts
4
+ # to assign values to the same key will be ignored.
5
+ #
6
+ # Please note that it is still possible to replace existing keyed values
7
+ # by first calling +delete+ on the relevant key and then adding
8
+ # the new value.
9
+ class FrozenKeyHash < Hash #
10
+ # Returns a new, empty hash.
11
+ #
12
+ # :call-seq:
13
+ # FrozenKeyHash.new -> frozen value hash
14
+ #
15
+ def initialize
16
+ super
17
+ end
18
+
19
+ # Element Assignment---Associates the value given
20
+ # by a value object with the key given by a key object,
21
+ # unless an object with the same key is already
22
+ # stored in the hash. In the event that an object
23
+ # is already stored in the hash using the key provided,
24
+ # the hash will not be altered.
25
+ #
26
+ # :call-seq:
27
+ # h[ aKeyObject ] = aValueObject -> aValueObject
28
+ #
29
+ def []=(key,value)
30
+ self.store(key,value)
31
+ end
32
+
33
+ # Synonym for element assignment.
34
+ #
35
+ # :call-seq:
36
+ # h.store( aKeyObject, aValueObject ) -> aValueObject
37
+ #
38
+ def store(key,value)
39
+ unless has_key?(key)
40
+ super(key,value)
41
+ end
42
+ end
43
+
44
+ # Convenience method to merge all
45
+ # entries from another hash into
46
+ # the current instance, while
47
+ # still preserving existing key
48
+ # immutability
49
+ def store_all(any_hash)
50
+ any_hash.each_pair { |key,value|
51
+ self.store(key,value)
52
+ }
53
+ end
54
+
55
+ def to_s
56
+ human_readable = ''
57
+ human_readable += sprintf("%-30s %s", "<KEY>", "<VALUE>")
58
+ human_readable += "\n"
59
+ each_pair {|key,value|
60
+ human_readable += sprintf("%-30s => %s", key, value)
61
+ human_readable += "\n"
62
+ }
63
+ human_readable
64
+ end
65
+ end
66
+ end
67
+
@@ -0,0 +1,50 @@
1
+ module Kodekopelli # :nodoc:
2
+ class MinimalLogger # :nodoc:
3
+ attr_reader :out
4
+ attr_accessor :silent, :verbose
5
+
6
+ def initialize(out = $stdout, silent = false, verbose = false)
7
+ @out = out
8
+ @silent = silent
9
+ @verbose = verbose
10
+ end
11
+
12
+ def debug(message)
13
+ log('DEBUG', message) if @verbose
14
+ end
15
+
16
+ def info(message)
17
+ log('INFO', message)
18
+ end
19
+
20
+ def error(message)
21
+ log('ERROR', message)
22
+ end
23
+
24
+ def fatal(message)
25
+ log('FATAL', message)
26
+ end
27
+
28
+ def raw(message)
29
+ log_raw(message)
30
+ end
31
+
32
+ def always(message)
33
+ log_always(message)
34
+ end
35
+
36
+ protected
37
+
38
+ def log_raw(message)
39
+ @out.print(message) unless @silent
40
+ end
41
+
42
+ def log_always(message)
43
+ @out.print("#{Time.now} -> %s\n" % [message])
44
+ end
45
+
46
+ def log(status, message)
47
+ log_always(message) unless @silent
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,41 @@
1
+ module Kodekopelli # :nodoc:
2
+ # This module encapsulates functionality related to
3
+ # manipulating properties files.
4
+ #
5
+ # Please note that this module supports only the
6
+ # simplest types of properties files: those files
7
+ # whose entries are of the <code>{key}={value}</code> variety.
8
+ #
9
+ module PropertiesFile
10
+ # Given the absolute or relative path to a properties
11
+ # file, returns a _Hash_ containing the properties found.
12
+ #
13
+ # :call-seq:
14
+ # PropertiesFile.to_hash(filename) -> hash
15
+ #
16
+ def PropertiesFile.to_hash(filename)
17
+ unless File.exists?(filename)
18
+ raise("Unable to locate file #{filename}#")
19
+ end
20
+
21
+ prop_file = File.open(filename)
22
+ h = Hash.new
23
+ begin
24
+ prop_file.readlines.each { |current_line|
25
+ is_comment = (current_line.strip.index('#') == 0)
26
+ equals_index = current_line.index("=")
27
+
28
+ unless is_comment || equals_index.nil?
29
+ current_property = current_line[0, equals_index].strip
30
+ current_value = current_line[equals_index+1..current_line.chomp("\n").size-1]
31
+ h[current_property] = current_value
32
+ end
33
+ }
34
+ ensure
35
+ prop_file.close
36
+ end
37
+ h
38
+ end
39
+
40
+ end
41
+ end
@@ -0,0 +1,30 @@
1
+ module Kodekopelli # :nodoc:
2
+ module Util # :nodoc:
3
+ # Given the location of a file, returns its
4
+ # contents.
5
+ #
6
+ # :call-seq:
7
+ # file_contents(location) -> contents
8
+ #
9
+ def Util.file_contents(location, ignore_if_missing=false)
10
+ unless File.exists?(location)
11
+ unless ignore_if_missing
12
+ raise "Could not locate file [#{location}]."
13
+ end
14
+ return nil
15
+ end
16
+ begin
17
+ file_handle = File.new(location)
18
+ file_contents = file_handle.read
19
+ ensure
20
+ file_handle.close
21
+ end
22
+ file_contents
23
+ end
24
+
25
+ # Mad props to Ruby on Rails developers for the following methods
26
+ def Util.escape_javascript(javascript)
27
+ (javascript || '').gsub(/\r\n|\n|\r/, "\\n").gsub(/["']/) { |m| "\\#{m}" }
28
+ end
29
+ end
30
+ end
data/rakefile ADDED
@@ -0,0 +1,87 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+ require 'rake/testtask'
4
+ require 'rake/rdoctask'
5
+ require 'rake/packagetask'
6
+ require 'rake/gempackagetask'
7
+ require 'rake/contrib/rubyforgepublisher'
8
+
9
+ PKG_NAME = 'kodekopelli'
10
+ PKG_VERSION = ENV['KODEKOPELLI_VERSION'] || '0.8.0'
11
+ PKG_FILE_NAME = "#{PKG_NAME}-#{PKG_VERSION}"
12
+ BUILD_DIR = "build"
13
+ TEST_OUTPUT_DIR = "test/output"
14
+ PACKAGE_DIR = "pkg"
15
+
16
+ RELEASE_NAME = "REL #{PKG_VERSION}"
17
+
18
+ RUBY_FORGE_PROJECT = 'kodekopelli'
19
+ RUBY_FORGE_USER = 'hastyb0y'
20
+
21
+ PKG_FILES = FileList[
22
+ "lib/**/*", "test/**/*", "doc/**/*", "examples/**/*", "[A-Z]*", "rakefile"
23
+ ].exclude(/\bCVS\b|-$/)
24
+
25
+ desc "Default Task"
26
+ task :default => [ :clean, :prepare, :test, :rdoc ]
27
+
28
+ desc "Scorch-the-earth removal of all build artifacts."
29
+ task :clean do
30
+ rm_rf BUILD_DIR
31
+ rm_rf TEST_OUTPUT_DIR
32
+ rm_rf PACKAGE_DIR
33
+ end
34
+
35
+ desc "Prepares the blank canvas for build process(es)."
36
+ task :prepare do
37
+ FileUtils.mkdir_p TEST_OUTPUT_DIR
38
+ end
39
+
40
+ # Run the unit and functional tests
41
+ Rake::TestTask.new { |t|
42
+ t.libs << "test"
43
+ t.pattern = 'test/ts_all_tests.rb'
44
+ t.verbose = true
45
+ }
46
+ desc "Run the unit tests."
47
+ task :test => [ :clean, :prepare ] do
48
+ end
49
+
50
+ # Generate the RDoc documentation
51
+ Rake::RDocTask.new { |rdoc|
52
+ rdoc.rdoc_dir = "#{BUILD_DIR}/doc/rdoc"
53
+ rdoc.title = "Kodekopelli"
54
+ rdoc.options << '--line-numbers' << '--inline-source' << '--main' << 'README'
55
+ rdoc.rdoc_files.include('README', 'LICENSE', 'CHANGELOG')
56
+ rdoc.rdoc_files.include('lib/**/*.rb')
57
+ }
58
+
59
+ # Create compressed packages
60
+ spec = Gem::Specification.new do |s|
61
+ s.platform = Gem::Platform::RUBY
62
+ s.name = PKG_NAME
63
+ s.summary = "Making code generation rock since 2003. Do it well. Do it once. Let Kodekopelli do the rest."
64
+ s.version = PKG_VERSION
65
+
66
+ s.author = "Rich Wertz"
67
+ s.email = "rich@kodekopelli.org"
68
+ s.rubyforge_project = RUBY_FORGE_PROJECT
69
+ s.homepage = "http://www.kodekopelli.org"
70
+
71
+ s.has_rdoc = true
72
+ s.extra_rdoc_files = [ "README", "CHANGELOG", "LICENSE" ]
73
+ s.test_file = "test/ts_all_tests.rb"
74
+ s.requirements << 'none'
75
+ s.require_path = "lib"
76
+ s.autorequire = PKG_NAME
77
+ s.files = PKG_FILES
78
+
79
+ s.bindir = "bin"
80
+ s.executables = ["kodekopelli"]
81
+ s.default_executable = "kodekopelli"
82
+ end
83
+
84
+ Rake::GemPackageTask.new(spec) do |pkg|
85
+ # pkg.need_tar = true
86
+ # pkg.need_zip = true
87
+ end
@@ -0,0 +1,4 @@
1
+ $:.unshift File.join(File.dirname(__FILE__), "../lib")
2
+
3
+ require 'test/unit'
4
+ require 'kodekopelli'
File without changes
@@ -0,0 +1,6 @@
1
+ asdfljaslkdjlsjlkdjlaskdjfoijafoisdjf ./zc,x
2
+ xzcv
3
+ xcajfawejopijdla;dfas
4
+ adfsfkl zx
5
+ cz
6
+ cxz
@@ -0,0 +1,95 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <xs:schema elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
3
+ <xs:element name="kodekopelli">
4
+ <xs:complexType mixed="true">
5
+ <xs:sequence>
6
+ <xs:element maxOccurs="unbounded" minOccurs="0" ref="property"/>
7
+ <xs:element maxOccurs="unbounded" minOccurs="0" ref="attribute"/>
8
+ <xs:element maxOccurs="unbounded" minOccurs="1" ref="filegroup"/>
9
+ </xs:sequence>
10
+ <xs:attributeGroup ref="attlist.kodekopelli"/>
11
+ </xs:complexType>
12
+ </xs:element>
13
+ <xs:element name="property">
14
+ <xs:complexType mixed="true">
15
+ <xs:attributeGroup ref="attlist.property"/>
16
+ </xs:complexType>
17
+ </xs:element>
18
+ <xs:element name="filegroup">
19
+ <xs:complexType mixed="true">
20
+ <xs:sequence>
21
+ <xs:element maxOccurs="unbounded" minOccurs="1" ref="file"/>
22
+ </xs:sequence>
23
+ <xs:attributeGroup ref="attlist.filegroup"/>
24
+ </xs:complexType>
25
+ </xs:element>
26
+ <xs:element name="attribute">
27
+ <xs:complexType mixed="true">
28
+ <xs:attributeGroup ref="attlist.attribute"/>
29
+ </xs:complexType>
30
+ </xs:element>
31
+ <xs:attributeGroup name="attlist.attribute">
32
+ <xs:attribute name="name" use="required"/>
33
+ <xs:attribute name="value" use="required"/>
34
+ </xs:attributeGroup>
35
+ <xs:element name="file">
36
+ <xs:complexType mixed="true">
37
+ <xs:choice maxOccurs="unbounded" minOccurs="0">
38
+ <xs:element ref="composite"/>
39
+ <xs:element ref="template"/>
40
+ <xs:element ref="include"/>
41
+ </xs:choice>
42
+ <xs:attributeGroup ref="attlist.file"/>
43
+ </xs:complexType>
44
+ </xs:element>
45
+ <xs:element name="composite">
46
+ <xs:complexType mixed="true">
47
+ <xs:choice maxOccurs="unbounded" minOccurs="1">
48
+ <xs:element ref="template"/>
49
+ <xs:element ref="composite"/>
50
+ <xs:element ref="include"/>
51
+ </xs:choice>
52
+ <xs:attributeGroup ref="attlist.composite"/>
53
+ </xs:complexType>
54
+ </xs:element>
55
+ <xs:attributeGroup name="attlist.kodekopelli">
56
+ <xs:anyAttribute processContents="skip"/>
57
+ </xs:attributeGroup>
58
+ <xs:attributeGroup name="attlist.filegroup">
59
+ <xs:attribute name="template" use="optional"/>
60
+ <xs:anyAttribute processContents="skip"/>
61
+ </xs:attributeGroup>
62
+ <xs:attributeGroup name="attlist.composite">
63
+ <xs:attribute name="template" use="optional"/>
64
+ <xs:anyAttribute processContents="skip"/>
65
+ </xs:attributeGroup>
66
+ <xs:attributeGroup name="attlist.property">
67
+ <xs:attribute name="name" use="optional"/>
68
+ <xs:attribute name="value" use="optional"/>
69
+ <xs:attribute name="file" use="optional"/>
70
+ <xs:attribute name="environment" use="optional"/>
71
+ <xs:attribute name="location" use="optional"/>
72
+ </xs:attributeGroup>
73
+ <xs:attributeGroup name="attlist.file">
74
+ <xs:attribute name="name" use="required"/>
75
+ <xs:attribute name="template" use="optional"/>
76
+ <xs:anyAttribute processContents="skip"/>
77
+ </xs:attributeGroup>
78
+ <xs:element name="template">
79
+ <xs:complexType mixed="true">
80
+ <xs:attributeGroup ref="attlist.template"/>
81
+ </xs:complexType>
82
+ </xs:element>
83
+ <xs:attributeGroup name="attlist.template">
84
+ <xs:attribute name="template" use="optional"/>
85
+ <xs:anyAttribute processContents="skip"/>
86
+ </xs:attributeGroup>
87
+ <xs:element name="include">
88
+ <xs:complexType mixed="true">
89
+ <xs:attributeGroup ref="attlist.include"/>
90
+ </xs:complexType>
91
+ </xs:element>
92
+ <xs:attributeGroup name="attlist.include">
93
+ <xs:attribute name="file" use="required"/>
94
+ </xs:attributeGroup>
95
+ </xs:schema>
@@ -0,0 +1,49 @@
1
+ <!--
2
+ All output files created by Kodekopelli per the directives in this
3
+ definitions file should be empty and should follow the naming convention
4
+ below:
5
+
6
+ empty_file_{n} => empty_file_1, empty_file_2, ...
7
+
8
+ Sequence numbers should increment by one (1) and no gaps should
9
+ be left in the sequence.
10
+
11
+ It follows that this definitions file should contain as many
12
+ "recipes" as possible for generating empty files consistent
13
+ with Kodekopelli's intended functionality.
14
+ -->
15
+ <kodekopelli xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
16
+ xsi:noNamespaceSchemaLocation="../kodekopelli.xsd">
17
+ <property location="test/fixtures" name="fixtures.dir"/>
18
+ <property location="${fixtures.dir}/includes" name="include.dir"/>
19
+ <property location="${fixtures.dir}/templates" name="template.dir"/>
20
+ <property location="${fixtures.dir}/properties" name="properties.dir"/>
21
+ <property location="test/output" name="output.dir"/>
22
+ <filegroup>
23
+ <file name="${output.dir}/empty_file_1"/>
24
+ <file name="${output.dir}/empty_file_2">
25
+ <leaf/>
26
+ </file>
27
+ <file name="${output.dir}/empty_file_3">
28
+ <leaf/>
29
+ <leaf/>
30
+ <leaf/>
31
+ </file>
32
+ <file name="${output.dir}/empty_file_4">
33
+ <include file="${include.dir}/empty.txt"/>
34
+ </file>
35
+ <file name="${output.dir}/empty_file_5">
36
+ <include file="${include.dir}/empty.txt"/>
37
+ <include file="${include.dir}/empty.txt"/>
38
+ <include file="${include.dir}/empty.txt"/>
39
+ </file>
40
+ <file name="${output.dir}/empty_file_6">
41
+ <include file="${include.dir}/empty.txt"/>
42
+ <leaf/>
43
+ </file>
44
+ <file name="${output.dir}/empty_file_7">
45
+ <leaf/>
46
+ <include file="${include.dir}/empty.txt"/>
47
+ </file>
48
+ </filegroup>
49
+ </kodekopelli>
@@ -0,0 +1,359 @@
1
+ <!--
2
+ All output files created by Kodekopelli per the directives in this
3
+ definitions file should contain the following content:
4
+
5
+ Kodekopelli rocks!
6
+
7
+ The files should not contain a line feed or carriage return and
8
+ no whitespace of any kind should be located on either side of the
9
+ "Kodekopelli rocks!" phrase.
10
+
11
+ Generated files should be named using the following naming
12
+ convention:
13
+
14
+ kodekopelli_rocks_{n} => kodekopelli_rocks_1, kodekopelli_rocks_2, ...
15
+
16
+ Sequence numbers should increment by one (1) and no gaps should
17
+ be left in the sequence.
18
+
19
+ It follows that this definitions file should contain as many
20
+ "recipes" as possible for generating "Kodekopelli rocks!"
21
+ files consistent Kodekopelli's intended functionality.
22
+ -->
23
+ <kodekopelli xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
24
+ xsi:noNamespaceSchemaLocation="../kodekopelli.xsd">
25
+ <property location="test/fixtures" name="fixtures.dir"/>
26
+ <property location="${fixtures.dir}/includes" name="include.dir"/>
27
+ <property location="${fixtures.dir}/templates" name="template.dir"/>
28
+ <property location="${fixtures.dir}/properties" name="properties.dir"/>
29
+ <property location="test/output" name="output.dir"/>
30
+ <property name="anything" value="Kodekopelli rocks!"/>
31
+ <property name="rocks" value="${anything}"/>
32
+ <attribute name="rocks-attribute" value="Kodekopelli rocks!"/>
33
+ <attribute name="kodekopelli-rocks-attribute" value="${anything}"/>
34
+ <filegroup>
35
+ <file name="${output.dir}/kodekopelli_rocks_1">
36
+ <template>Kodekopelli rocks!</template>
37
+ </file>
38
+ <file name="${output.dir}/kodekopelli_rocks_2">
39
+ <template>Kodekopelli</template>
40
+ <template> </template>
41
+ <template>rocks!</template>
42
+ </file>
43
+ <file name="${output.dir}/kodekopelli_rocks_3">
44
+ <template>K</template>
45
+ <template>o</template>
46
+ <template>d</template>
47
+ <template>e</template>
48
+ <template>k</template>
49
+ <template>o</template>
50
+ <template>p</template>
51
+ <template>e</template>
52
+ <template>l</template>
53
+ <template>l</template>
54
+ <template>i</template>
55
+ <template> </template>
56
+ <template>r</template>
57
+ <template>o</template>
58
+ <template>c</template>
59
+ <template>k</template>
60
+ <template>s</template>
61
+ <template>!</template>
62
+ </file>
63
+ <file name="${output.dir}/kodekopelli_rocks_4">
64
+ <include file="${include.dir}/k_upper.txt"/>
65
+ <include file="${include.dir}/o.txt"/>
66
+ <include file="${include.dir}/d.txt"/>
67
+ <include file="${include.dir}/e.txt"/>
68
+ <include file="${include.dir}/k.txt"/>
69
+ <include file="${include.dir}/o.txt"/>
70
+ <include file="${include.dir}/p.txt"/>
71
+ <include file="${include.dir}/e.txt"/>
72
+ <include file="${include.dir}/l.txt"/>
73
+ <include file="${include.dir}/l.txt"/>
74
+ <include file="${include.dir}/i.txt"/>
75
+ <include file="${include.dir}/space.txt"/>
76
+ <include file="${include.dir}/r.txt"/>
77
+ <include file="${include.dir}/o.txt"/>
78
+ <include file="${include.dir}/c.txt"/>
79
+ <include file="${include.dir}/k.txt"/>
80
+ <include file="${include.dir}/s.txt"/>
81
+ <include file="${include.dir}/bang.txt"/>
82
+ </file>
83
+ <file name="${output.dir}/kodekopelli_rocks_5">
84
+ <template>Kodekopelli</template>
85
+ <include file="${include.dir}/space.txt"/>
86
+ <include file="${include.dir}/r.txt"/>
87
+ <include file="${include.dir}/o.txt"/>
88
+ <include file="${include.dir}/c.txt"/>
89
+ <include file="${include.dir}/k.txt"/>
90
+ <include file="${include.dir}/s.txt"/>
91
+ <template>!</template>
92
+ </file>
93
+ <file name="${output.dir}/kodekopelli_rocks_6">
94
+ <template template="${template.dir}/kodekopelli_blanks" what-he-does="rocks"/>
95
+ </file>
96
+ <file name="${output.dir}/kodekopelli_rocks_7" what-he-does="rocks">
97
+ <template template="${template.dir}/kodekopelli_blanks"/>
98
+ </file>
99
+ <file name="${output.dir}/kodekopelli_rocks_8">
100
+ <template anything="Kodekopelli rocks!" template="${template.dir}/anything_att.txt"/>
101
+ </file>
102
+ <file anything="Kodekopelli rocks!" name="${output.dir}/kodekopelli_rocks_9">
103
+ <template template="${template.dir}/anything_att.txt"/>
104
+ </file>
105
+ <file name="${output.dir}/kodekopelli_rocks_10">
106
+ <template anything="Kodekopelli rocks!" template="${template.dir}/anything_att_prop.txt"/>
107
+ </file>
108
+ <file anything="Kodekopelli rocks!" name="${output.dir}/kodekopelli_rocks_11">
109
+ <template template="${template.dir}/anything_att_prop.txt"/>
110
+ </file>
111
+ <file name="${output.dir}/kodekopelli_rocks_12">
112
+ <template anything="Doesn't rock :-(" template="${template.dir}/anything_prop_att.txt"/>
113
+ </file>
114
+ <file name="${output.dir}/kodekopelli_rocks_13">
115
+ <template anything="Doesn't rock :-(" template="${template.dir}/anything_prop_att.txt"/>
116
+ </file>
117
+ <file name="${output.dir}/kodekopelli_rocks_14">
118
+ <template anything="Doesn't rock :-(" template="${template.dir}/anything_prop.txt"/>
119
+ </file>
120
+ <file name="${output.dir}/kodekopelli_rocks_15">
121
+ <template anything="Doesn't rock :-(" template="${template.dir}/anything_prop.txt"/>
122
+ </file>
123
+ <file name="${output.dir}/kodekopelli_rocks_16">
124
+ <template><![CDATA[<%= prop 'anything' %>]]></template>
125
+ </file>
126
+ <file name="${output.dir}/kodekopelli_rocks_17">
127
+ <template><![CDATA[<%= prop_att 'anything' %>]]></template>
128
+ </file>
129
+ <file name="${output.dir}/kodekopelli_rocks_18">
130
+ <template><![CDATA[<%= prop('missing_by_design', 'Kodekopelli rocks!') %>]]></template>
131
+ </file>
132
+ <file name="${output.dir}/kodekopelli_rocks_19">
133
+ <template><![CDATA[<%= prop_att('missing_by_design', 'Kodekopelli rocks!') %>]]></template>
134
+ </file>
135
+ <file name="${output.dir}/kodekopelli_rocks_20">
136
+ <template><![CDATA[<%= att('missing_by_design', 'Kodekopelli rocks!') %>]]></template>
137
+ </file>
138
+ <file name="${output.dir}/kodekopelli_rocks_21">
139
+ <template><![CDATA[<%= att_prop('missing_by_design', 'Kodekopelli rocks!') %>]]></template>
140
+ </file>
141
+ <file anything="${rocks}" name="${output.dir}/kodekopelli_rocks_22">
142
+ <template><![CDATA[<%= att 'anything' %>]]></template>
143
+ </file>
144
+ <file name="${output.dir}/kodekopelli_rocks_23">
145
+ <template anything="${rocks}"><![CDATA[<%= att 'anything' %>]]></template>
146
+ </file>
147
+ <file name="${output.dir}/kodekopelli_rocks_24">
148
+ <template><![CDATA[<%= att 'rocks-attribute' %>]]></template>
149
+ </file>
150
+ <file name="${output.dir}/kodekopelli_rocks_25">
151
+ <template><![CDATA[<%= att 'kodekopelli-rocks-attribute' %>]]></template>
152
+ </file>
153
+ <file name="${output.dir}/kodekopelli_rocks_26">
154
+ <template verbiage="Kodekopelli rocks!"><![CDATA[<%= att 'verbiage' %>]]></template>
155
+ </file>
156
+ <file name="${output.dir}/kodekopelli_rocks_27" verbiage="Kodekopelli rocks!">
157
+ <template><![CDATA[<%= att 'verbiage' %>]]></template>
158
+ </file>
159
+ <file name="${output.dir}/kodekopelli_rocks_28">
160
+ <template><![CDATA[Kodekopelli r]]></template>
161
+ <template><![CDATA[ocks!]]></template>
162
+ </file>
163
+ <file name="${output.dir}/kodekopelli_rocks_29" verbiage="Kodekopelli doesn't rock!">
164
+ <composite template="${template.dir}/child_output.txt" verbiage="Kodekopelli rocks!">
165
+ <template><![CDATA[<%= att 'verbiage' %>]]></template>
166
+ </composite>
167
+ </file>
168
+ <file name="${output.dir}/kodekopelli_rocks_30" verbiage="Kodekopelli rocks!">
169
+ <composite template="${template.dir}/child_output.txt">
170
+ <template><![CDATA[<%= att 'verbiage' %>]]></template>
171
+ </composite>
172
+ </file>
173
+ <file name="${output.dir}/kodekopelli_rocks_31">
174
+ <composite template="${template.dir}/child_output.txt">
175
+ <template>Kodekopelli rocks!</template>
176
+ </composite>
177
+ </file>
178
+ <file name="${output.dir}/kodekopelli_rocks_32">
179
+ <composite template="${template.dir}/child_output.txt">
180
+ <template>Kodekopelli</template>
181
+ <template> </template>
182
+ <template>rocks!</template>
183
+ </composite>
184
+ </file>
185
+ <file name="${output.dir}/kodekopelli_rocks_33">
186
+ <composite template="${template.dir}/child_output.txt">
187
+ <template>K</template>
188
+ <template>o</template>
189
+ <template>d</template>
190
+ <template>e</template>
191
+ <template>k</template>
192
+ <template>o</template>
193
+ <template>p</template>
194
+ <template>e</template>
195
+ <template>l</template>
196
+ <template>l</template>
197
+ <template>i</template>
198
+ <template> </template>
199
+ <template>r</template>
200
+ <template>o</template>
201
+ <template>c</template>
202
+ <template>k</template>
203
+ <template>s</template>
204
+ <template>!</template>
205
+ </composite>
206
+ </file>
207
+ <file name="${output.dir}/kodekopelli_rocks_34">
208
+ <composite template="${template.dir}/child_output.txt">
209
+ <include file="${include.dir}/k_upper.txt"/>
210
+ <include file="${include.dir}/o.txt"/>
211
+ <include file="${include.dir}/d.txt"/>
212
+ <include file="${include.dir}/e.txt"/>
213
+ <include file="${include.dir}/k.txt"/>
214
+ <include file="${include.dir}/o.txt"/>
215
+ <include file="${include.dir}/p.txt"/>
216
+ <include file="${include.dir}/e.txt"/>
217
+ <include file="${include.dir}/l.txt"/>
218
+ <include file="${include.dir}/l.txt"/>
219
+ <include file="${include.dir}/i.txt"/>
220
+ <include file="${include.dir}/space.txt"/>
221
+ <include file="${include.dir}/r.txt"/>
222
+ <include file="${include.dir}/o.txt"/>
223
+ <include file="${include.dir}/c.txt"/>
224
+ <include file="${include.dir}/k.txt"/>
225
+ <include file="${include.dir}/s.txt"/>
226
+ <include file="${include.dir}/bang.txt"/>
227
+ </composite>
228
+ </file>
229
+ <file name="${output.dir}/kodekopelli_rocks_35">
230
+ <composite template="${template.dir}/child_output.txt">
231
+ <template>Kodekopelli</template>
232
+ <include file="${include.dir}/space.txt"/>
233
+ <include file="${include.dir}/r.txt"/>
234
+ <include file="${include.dir}/o.txt"/>
235
+ <include file="${include.dir}/c.txt"/>
236
+ <include file="${include.dir}/k.txt"/>
237
+ <include file="${include.dir}/s.txt"/>
238
+ <template>!</template>
239
+ </composite>
240
+ </file>
241
+ <file name="${output.dir}/kodekopelli_rocks_36">
242
+ <composite template="${template.dir}/child_output.txt">
243
+ <template template="${template.dir}/kodekopelli_blanks" what-he-does="rocks"/>
244
+ </composite>
245
+ </file>
246
+ <file name="${output.dir}/kodekopelli_rocks_37">
247
+ <composite template="${template.dir}/child_output.txt">
248
+ <composite template="${template.dir}/child_output.txt">
249
+ <template>Kodekopelli</template>
250
+ </composite>
251
+ <composite template="${template.dir}/child_output.txt">
252
+ <include file="${include.dir}/space.txt"/>
253
+ <include file="${include.dir}/r.txt"/>
254
+ </composite>
255
+ <composite template="${template.dir}/child_output.txt">
256
+ <include file="${include.dir}/o.txt"/>
257
+ <include file="${include.dir}/c.txt"/>
258
+ <include file="${include.dir}/k.txt"/>
259
+ <include file="${include.dir}/s.txt"/>
260
+ </composite>
261
+ <composite template="${template.dir}/child_output.txt">
262
+ <template>!</template>
263
+ </composite>
264
+ </composite>
265
+ </file>
266
+ <file name="${output.dir}/kodekopelli_rocks_38" template="${template.dir}/kodekopelli_blanks"
267
+ what-he-does="rocks"/>
268
+ <file name="${output.dir}/kodekopelli_rocks_39" what-he-does="rocks">
269
+ <composite template="${template.dir}/kodekopelli_blanks">
270
+ <template>Should be ignored.</template>
271
+ </composite>
272
+ </file>
273
+ <file name="${output.dir}/kodekopelli_rocks_40" what-he-does="rocks">
274
+ <template template="${template.dir}/kodekopelli_blanks"/>
275
+ </file>
276
+ </filegroup>
277
+ <filegroup template="${template.dir}/kodekopelli_blanks">
278
+ <file name="${output.dir}/kodekopelli_rocks_41" what-he-does="rocks"/>
279
+ <file name="${output.dir}/kodekopelli_rocks_42" what-he-does="rocks"
280
+ ><![CDATA[Kodekopelli <%= att 'what-he-does' %>!]]></file>
281
+ <file name="${output.dir}/kodekopelli_rocks_43" what-he-does="rocks">
282
+ <template>Should be ignored.</template>
283
+ </file>
284
+ <file name="${output.dir}/kodekopelli_rocks_44" what-he-does="rocks">
285
+ <template><![CDATA[Kodekopelli <%= att 'what-he-does' %>!]]></template>
286
+ </file>
287
+ <file name="${output.dir}/kodekopelli_rocks_45" what-he-does="rocks">
288
+ <template what-he-does="does not rock"><![CDATA[Kodekopelli <%= att 'what-he-does' %>!]]></template>
289
+ </file>
290
+ <file name="${output.dir}/kodekopelli_rocks_46" template="${template.dir}/child_output.txt">
291
+ <template>Kodekopelli rocks!</template>
292
+ </file>
293
+ <file name="${output.dir}/kodekopelli_rocks_47" template="${template.dir}/child_output.txt">
294
+ <composite template="${template.dir}/child_output.txt">
295
+ <template>Kodekopelli rocks!</template>
296
+ </composite>
297
+ </file>
298
+ <file name="${output.dir}/kodekopelli_rocks_48" what-he-does="rocks">
299
+ <composite template="${template.dir}/kodekopelli_blanks" what-he-does="rocks">
300
+ <template>Should be ignored.</template>
301
+ </composite>
302
+ </file>
303
+ </filegroup>
304
+ <filegroup template="${template.dir}/blank.txt">
305
+ <file name="${output.dir}/kodekopelli_rocks_49" template="${template.dir}/child_output.txt">
306
+ <composite template="${template.dir}/child_output.txt" what-he-does="rocks">
307
+ <include file="${include.dir}/kodekopelli_rocks.txt"/>
308
+ </composite>
309
+ </file>
310
+ <file name="${output.dir}/kodekopelli_rocks_50" template="${template.dir}/child_output.txt">
311
+ <template>Kodekopelli rocks!</template>
312
+ </file>
313
+ <file name="${output.dir}/kodekopelli_rocks_51" template="${template.dir}/child_output.txt"
314
+ what-he-does="rocks">
315
+ <template what-he-does="rocks"><![CDATA[Kodekopelli <%= att 'what-he-does' %>!]]></template>
316
+ </file>
317
+ <file name="${output.dir}/kodekopelli_rocks_52" template="${template.dir}/child_output.txt"
318
+ what-he-does="rocks">
319
+ <template template="${template.dir}/kodekopelli_blanks"/>
320
+ </file>
321
+ <file name="${output.dir}/kodekopelli_rocks_53" template="${template.dir}/child_output.txt">
322
+ <template><![CDATA[Kodekopelli rocks!]]></template>
323
+ </file>
324
+ <file name="${output.dir}/kodekopelli_rocks_54" template="${template.dir}/child_output.txt"
325
+ what-he-does="rocks">
326
+ <template><![CDATA[Kodekopelli <%= att 'what-he-does' %>!]]></template>
327
+ </file>
328
+ <file name="${output.dir}/kodekopelli_rocks_55" template="${template.dir}/child_output.txt"
329
+ what-he-does="rocks">
330
+ <template what-he-does="rocks"><![CDATA[Kodekopelli <%= att 'what-he-does' %>!]]></template>
331
+ </file>
332
+ <file name="${output.dir}/kodekopelli_rocks_56" template="${template.dir}/child_output.txt"
333
+ what-he-does="doesn't rock">
334
+ <template what-he-does="rocks"><![CDATA[Kodekopelli <%= att 'what-he-does' %>!]]></template>
335
+ </file>
336
+ <file name="${output.dir}/kodekopelli_rocks_57" template="${template.dir}/kodekopelli_blanks"
337
+ what-he-does="rocks"/>
338
+ </filegroup>
339
+ <filegroup template="${template.dir}/kodekopelli_blanks" what-he-does="rocks">
340
+ <file name="${output.dir}/kodekopelli_rocks_58">Kodekopelil doesn't rock!</file>
341
+ </filegroup>
342
+ <filegroup>
343
+ <file name="${output.dir}/kodekopelli_rocks_59">Kodekopelli rocks!</file>
344
+ <file name="${output.dir}/kodekopelli_rocks_60">
345
+ <template>Kodekopelli rocks!</template>
346
+ </file>
347
+ <file name="${output.dir}/kodekopelli_rocks_61">
348
+ <composite>
349
+ <template>Kodekopelli rocks!</template>
350
+ </composite>
351
+ </file>
352
+ <file name="${output.dir}/kodekopelli_rocks_62">
353
+ <composite>
354
+ <include file="${include.dir}/kodekopelli_rocks.txt" />
355
+ </composite>
356
+ </file>
357
+ <file name="${output.dir}/kodekopelli_rocks_63">Kodekopelli rocks!</file>
358
+ </filegroup>
359
+ </kodekopelli>