tap 0.11.1 → 0.12.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (103) hide show
  1. data/History +35 -1
  2. data/MIT-LICENSE +1 -1
  3. data/README +16 -15
  4. data/bin/tap +1 -1
  5. data/cmd/console.rb +4 -3
  6. data/cmd/manifest.rb +2 -2
  7. data/cmd/run.rb +12 -15
  8. data/doc/Class Reference +120 -117
  9. data/doc/Command Reference +27 -27
  10. data/doc/Syntax Reference +55 -111
  11. data/doc/Tutorial +69 -26
  12. data/lib/tap.rb +3 -8
  13. data/lib/tap/app.rb +122 -146
  14. data/lib/tap/constants.rb +2 -2
  15. data/lib/tap/env.rb +178 -252
  16. data/lib/tap/exe.rb +67 -30
  17. data/lib/tap/file_task.rb +224 -411
  18. data/lib/tap/generator/arguments.rb +13 -0
  19. data/lib/tap/generator/base.rb +112 -30
  20. data/lib/tap/generator/destroy.rb +36 -13
  21. data/lib/tap/generator/generate.rb +69 -48
  22. data/lib/tap/generator/generators/command/templates/command.erb +3 -3
  23. data/lib/tap/generator/generators/config/config_generator.rb +82 -10
  24. data/lib/tap/generator/generators/generator/generator_generator.rb +16 -6
  25. data/lib/tap/generator/generators/generator/templates/task.erb +2 -2
  26. data/lib/tap/generator/generators/generator/templates/test.erb +26 -0
  27. data/lib/tap/generator/generators/root/root_generator.rb +24 -13
  28. data/lib/tap/generator/generators/root/templates/Rakefile +4 -4
  29. data/lib/tap/generator/generators/root/templates/{tapfile → Rapfile} +6 -6
  30. data/lib/tap/generator/generators/root/templates/gemspec +0 -1
  31. data/lib/tap/generator/generators/task/task_generator.rb +3 -3
  32. data/lib/tap/generator/generators/task/templates/test.erb +1 -1
  33. data/lib/tap/generator/manifest.rb +7 -1
  34. data/lib/tap/generator/preview.rb +76 -0
  35. data/lib/tap/root.rb +222 -156
  36. data/lib/tap/spec.rb +41 -0
  37. data/lib/tap/support/aggregator.rb +25 -28
  38. data/lib/tap/support/audit.rb +278 -357
  39. data/lib/tap/support/constant.rb +2 -1
  40. data/lib/tap/support/constant_manifest.rb +28 -25
  41. data/lib/tap/support/dependency.rb +1 -1
  42. data/lib/tap/support/executable.rb +52 -183
  43. data/lib/tap/support/executable_queue.rb +50 -20
  44. data/lib/tap/support/gems.rb +1 -1
  45. data/lib/tap/support/intern.rb +0 -6
  46. data/lib/tap/support/join.rb +49 -83
  47. data/lib/tap/support/joins.rb +0 -3
  48. data/lib/tap/support/joins/switch.rb +13 -11
  49. data/lib/tap/support/joins/sync_merge.rb +25 -50
  50. data/lib/tap/support/manifest.rb +1 -0
  51. data/lib/tap/support/node.rb +140 -20
  52. data/lib/tap/support/parser.rb +56 -42
  53. data/lib/tap/support/schema.rb +183 -157
  54. data/lib/tap/support/templater.rb +9 -1
  55. data/lib/tap/support/versions.rb +39 -0
  56. data/lib/tap/task.rb +150 -177
  57. data/lib/tap/tasks/dump.rb +4 -4
  58. data/lib/tap/tasks/load.rb +29 -29
  59. data/lib/tap/test.rb +66 -53
  60. data/lib/tap/test/env_vars.rb +3 -3
  61. data/lib/tap/test/extensions.rb +11 -17
  62. data/lib/tap/test/file_test.rb +74 -132
  63. data/lib/tap/test/file_test_class.rb +4 -1
  64. data/lib/tap/test/regexp_escape.rb +2 -2
  65. data/lib/tap/test/script_test.rb +2 -2
  66. data/lib/tap/test/subset_test.rb +6 -6
  67. data/lib/tap/test/tap_test.rb +28 -154
  68. metadata +30 -51
  69. data/bin/rap +0 -118
  70. data/cgi/run.rb +0 -97
  71. data/lib/tap/declarations.rb +0 -229
  72. data/lib/tap/generator/generators/config/templates/doc.erb +0 -12
  73. data/lib/tap/generator/generators/config/templates/nodoc.erb +0 -8
  74. data/lib/tap/generator/generators/file_task/file_task_generator.rb +0 -27
  75. data/lib/tap/generator/generators/file_task/templates/file.txt +0 -11
  76. data/lib/tap/generator/generators/file_task/templates/result.yml +0 -6
  77. data/lib/tap/generator/generators/file_task/templates/task.erb +0 -33
  78. data/lib/tap/generator/generators/file_task/templates/test.erb +0 -29
  79. data/lib/tap/generator/generators/root/templates/test/tap_test_suite.rb +0 -5
  80. data/lib/tap/patches/optparse/summarize.rb +0 -62
  81. data/lib/tap/support/assignments.rb +0 -173
  82. data/lib/tap/support/class_configuration.rb +0 -182
  83. data/lib/tap/support/combinator.rb +0 -125
  84. data/lib/tap/support/configurable.rb +0 -113
  85. data/lib/tap/support/configurable_class.rb +0 -271
  86. data/lib/tap/support/configuration.rb +0 -170
  87. data/lib/tap/support/gems/rake.rb +0 -111
  88. data/lib/tap/support/instance_configuration.rb +0 -173
  89. data/lib/tap/support/joins/fork.rb +0 -19
  90. data/lib/tap/support/joins/merge.rb +0 -22
  91. data/lib/tap/support/joins/sequence.rb +0 -21
  92. data/lib/tap/support/lazy_attributes.rb +0 -45
  93. data/lib/tap/support/lazydoc.rb +0 -386
  94. data/lib/tap/support/lazydoc/comment.rb +0 -503
  95. data/lib/tap/support/lazydoc/config.rb +0 -17
  96. data/lib/tap/support/lazydoc/definition.rb +0 -36
  97. data/lib/tap/support/lazydoc/document.rb +0 -152
  98. data/lib/tap/support/lazydoc/method.rb +0 -24
  99. data/lib/tap/support/tdoc.rb +0 -409
  100. data/lib/tap/support/tdoc/tdoc_html_generator.rb +0 -38
  101. data/lib/tap/support/tdoc/tdoc_html_template.rb +0 -42
  102. data/lib/tap/support/validation.rb +0 -479
  103. data/lib/tap/tasks/rake.rb +0 -57
@@ -1,8 +0,0 @@
1
- ###############################################################################
2
- # <%= receiver %> configuration<%= configurations.length > 1 ? 's' : '' %>
3
- ###############################################################################
4
- <% configurations.each do |key, config| %>
5
- <%= config.default == nil ? '#' : ''%><%= yamlize({key.to_s => config.default}) %>
6
-
7
- <% end %>
8
-
@@ -1,27 +0,0 @@
1
- require 'tap/generator/generators/task/task_generator'
2
-
3
- module Tap::Generator::Generators
4
-
5
- # :startdoc: Tap::Generator::Generators::FileTaskGenerator::generator a file_task and test
6
- #
7
- # Generates a new Tap::FileTask and associated test files.
8
- class FileTaskGenerator < TaskGenerator
9
-
10
- def manifest(m, const_name)
11
- const = super
12
-
13
- if test
14
- test_dir = app.filepath('test', const.path, "test_#{const.basename}")
15
-
16
- m.directories test_dir, %W{
17
- input
18
- expected
19
- }
20
-
21
- m.template File.join(test_dir, 'input/file.txt'), "file.txt", :const => const, :test_dir => test_dir
22
- m.template File.join(test_dir, 'expected/result.yml'), "result.yml", :const => const, :test_dir => test_dir
23
- end
24
- end
25
-
26
- end
27
- end
@@ -1,11 +0,0 @@
1
- absquatulate - verb: This amusing, vivid, and expressive word is a bit of a jocular, contrived slang. To absquatulate is to decamp, to scram, to take off in a hell of a hurry like a fugitive heading into the woods.
2
-
3
- algorism - noun: This is the name of the Arabic numbering system, using the figures 1 to 9 plus the zero. The derivation is from Middle Latin algorismus, from the Arabic al (the) plus Khuwarizmi, the surname of a ninth-century Arabic mathematician. Algorithm is sometimes used as a synonym, but is also used to designate a set of rules for the solution of a mathematical problem in a finite number of steps. These words are entirely unrelated to algolagnia, with its very different meaning and derivation.
4
-
5
- defenestration - verb: Defenestration is the act of throwing someone (yes, someone!) or something out of a window. To defenestrate a person or thing is to engage in this activity - a strange one indeed, since these words are more commonly applied to situations where what is thrown out of the window is a person, rather than a thing. It is surprising, in view of what must be the infrequency of this type of activity, that there exists word for it, but then, there exists a word for just about everything.
6
-
7
- macaronic - adj: This peculiar word, a jocular concoction from macaroni, is applied, in a narrow sense, to language characterized by a mixture of Latin and non-Latin words, or by non-Latin words given phony Latin endings; in a broader sense, to prose or verse composed of any mixture of languages; in its broadest sense, to anything mixed or jumbled.
8
-
9
- trumpery - noun: Trumpery is worthless stuff.
10
-
11
- usufruct - noun: Usufruct is a term used in law primarily, to denote one's right to enjoy the use and benefits flowing from the use of another's property, without the ownership of it and without the right to harm or waste or destroy it.
@@ -1,6 +0,0 @@
1
- ---
2
- - 111
3
- - 155
4
- - 123
5
- - 125
6
- - 56
@@ -1,33 +0,0 @@
1
- <% redirect do |target| %># <%= const.name %>::manifest <replace with manifest summary>
2
- # <replace with command line description>
3
-
4
- # <%= const.const_name %> Documentation
5
- # This example FileTask counts the specified letters
6
- # in a source file and writes the counts to a target
7
- # file as YAML.
8
- #
9
- class <%= const.const_name %> < Tap::FileTask
10
-
11
- # <config file documentation>
12
- config :letters, ['a','e','i','o','u'], &c.array # a list of letters to count
13
-
14
- def process(source, target)
15
-
16
- # prepare ensures the parent directory for target
17
- # exists and, if necessary, backs up the existing
18
- # target file (which is restored on error)
19
- prepare(target)
20
-
21
- # now perform the task...
22
- str = File.read(source)
23
- letter_count = letters.collect do |letter|
24
- str.count(letter)
25
- end
26
-
27
- File.open(target, "wb") do |file|
28
- file << YAML.dump(letter_count)
29
- end
30
-
31
- target
32
- end
33
- end <% module_nest(const.nesting, ' ') { target } end %>
@@ -1,29 +0,0 @@
1
- require File.join(File.dirname(__FILE__), '<%= '../' * const.nesting_depth %>tap_test_helper.rb')
2
- require '<%= const.path %>'
3
-
4
- class <%= const.name %>Test < Test::Unit::TestCase
5
- acts_as_tap_test
6
-
7
- def test_<%= const.basename %>
8
- # Use assert_files to test file transform tasks. The block
9
- # recieves the method input files and compares the results
10
- # to the method expected files.
11
-
12
- # Generated files are often placed in method output, as it
13
- # is cleaned up each test. To keep output files, set the
14
- # KEEP_OUTPUTS variable:
15
- # % rake test keep_outputs=true
16
-
17
- t = <%= const.name %>.new
18
- assert_files do |input_files|
19
- input_files.each do |source|
20
- target = method_root.filepath(:output, 'result.yml')
21
- t.enq(source, target)
22
- end
23
-
24
- app.run
25
- app.results(t)
26
- end
27
- end
28
-
29
- end
@@ -1,5 +0,0 @@
1
- $:.unshift File.join(File.dirname(__FILE__), '../lib')
2
-
3
- # runs all subsets (see Tap::Test::SubsetTest)
4
- ENV["ALL"] = "true"
5
- Dir.glob("./**/*_test.rb").each {|test| require test}
@@ -1,62 +0,0 @@
1
- #--
2
- # This patch fixes some formatting errors in OptParse.
3
- # In particular, long config names and config names of
4
- # 13 characters in length cause either ugly wrapping,
5
- # or an outright error. It could also wrap long comments,
6
- # although that feature is currently disabled.
7
- #
8
- # See:
9
- # - http://bahuvrihi.lighthouseapp.com/projects/9908/tickets/97-unlucky-13-character-config-name#ticket-97-1
10
-
11
- class OptionParser # :nodoc:
12
- class Switch # :nodoc:
13
- undef_method :summarize
14
-
15
- def summarize(sdone = [], ldone = [], width = 1, max = width - 1, indent = "")
16
- sopts, lopts = [], []
17
- @short.each {|s| sdone.fetch(s) {sopts << s}; sdone[s] = true} if @short
18
- @long.each {|s| ldone.fetch(s) {lopts << s}; ldone[s] = true} if @long
19
- return if sopts.empty? and lopts.empty? # completely hidden
20
-
21
- left = [sopts.join(', ')]
22
- right = desc.dup
23
-
24
- while str = lopts.shift
25
- l = left[-1].length + str.length
26
- l += arg.length if left.size == 1 && arg
27
- #l < max or left << ''
28
- left[-1] << if left[-1].empty? then ' ' * 4 else ', ' end << str
29
- end
30
-
31
- #left[0] << arg if arg
32
- left[-1] << arg if arg
33
-
34
- mlen = left.collect {|s| s.length}.max.to_i
35
- while mlen > width and l = left.shift
36
- mlen = left.collect {|s| s.length}.max.to_i if l.length == mlen
37
- yield(indent + l)
38
- end
39
-
40
- # uncomment to justify long comments
41
- # comment_indent = width + indent.length + 2
42
- # split_right = []
43
- # right.each do |obj|
44
- # start_index = 0
45
- # str = obj.to_str
46
- # while start_index < str.length
47
- # split_right << str[start_index, comment_indent].strip
48
- # start_index += comment_indent
49
- # end
50
- # end
51
- # right = split_right
52
-
53
- while begin l = left.shift; r = right.shift; l or r end
54
- l = l.to_s.ljust(width) + ' ' + r if r and !r.empty?
55
- #yield(indent + l)
56
- yield(indent + l) unless l == nil
57
- end
58
-
59
- self
60
- end
61
- end
62
- end
@@ -1,173 +0,0 @@
1
- module Tap
2
- module Support
3
-
4
- # Assignments defines an array of [key, values] pairs that tracks
5
- # which values are assigned to a particular key. A value may only
6
- # be assigned to one key at a time.
7
- #
8
- # Assignments tracks the order of key declaration, and the
9
- # order in which values are assigned to a key. This behavior is
10
- # used by ClassConfiguration to track the order of configurations
11
- # in a class; the order, in turn, is used in the formation
12
- # of config files, command line documentation, etc.
13
- #
14
- # a = Assignments.new
15
- # a.assign(:one, 'one')
16
- # a.assign(:two, 'two')
17
- # a.assign(:one, 'ONE')
18
- # a.to_a # => [[:one, ['one', 'ONE']], [:two, ['two']]]
19
- #
20
- # b = Assignments.new(a)
21
- # b.to_a # => [[:one, ['one', 'ONE']], [:two, ['two']]]
22
- #
23
- # b.unassign('one')
24
- # b.assign(:one, 1)
25
- # b.to_a # => [[:one, ['ONE', 1]], [:two, ['two']]]
26
- # a.to_a # => [[:one, ['one', 'ONE']], [:two, ['two']]]
27
- #
28
- #--
29
- # TODO:
30
- # Assignments may be optimizable... check if an alternate internal
31
- # storage can be made faster or to take up less memory. Not that
32
- # that much can be gained period...
33
- class Assignments
34
- include Enumerable
35
-
36
- # Generates a new Assignments using the parent array of
37
- # [key, values] pairs. Uses parent.array if parent is
38
- # an Assignments, or [] if parent is nil.
39
- def initialize(parent=nil)
40
- existing_array = case parent
41
- when Assignments then parent.array
42
- when Array then parent
43
- when nil then []
44
- else
45
- raise ArgumentError.new("cannot convert #{parent.class} to Assignments, Array, or nil")
46
- end
47
-
48
- @array = []
49
- existing_array.each do |key, values|
50
- assign(key, *values)
51
- end
52
- end
53
-
54
- # Adds the key to the declarations.
55
- def declare(key)
56
- array << [key, []] unless declared?(key)
57
- end
58
-
59
- # Removes all values for the specified key and
60
- # removes the key from declarations.
61
- def undeclare(key)
62
- array.delete_if {|k, values| k == key}
63
- end
64
-
65
- # Returns true if the key is declared.
66
- def declared?(key)
67
- array.each do |k, values|
68
- return true if k == key
69
- end
70
- false
71
- end
72
-
73
- # Returns an array of all the declared keys
74
- def declarations
75
- array.collect {|key, values| key }
76
- end
77
-
78
- # Assigns the specified values to the key. The key will
79
- # be declared, if necessary. Raises an error if the key
80
- # is nil.
81
- def assign(key, *values)
82
- raise ArgumentError.new("nil keys are not allowed") if key == nil
83
-
84
- # partition the input values into existing and new
85
- # values, then check for conflicts.
86
- current_values = self.values
87
- existing_values, new_values = values.partition {|value| current_values.include?(value) }
88
-
89
- conflicts = []
90
- existing_values.collect do |value|
91
- current_key = key_for(value)
92
- if current_key != key
93
- conflicts << "#{value} (#{key}) already assigned to #{current_key}"
94
- end
95
- end
96
-
97
- unless conflicts.empty?
98
- raise ArgumentError.new(conflicts.join("\n"))
99
- end
100
-
101
- declare(key)
102
- values_for(key).concat new_values
103
- end
104
-
105
- # Removes the specified value.
106
- def unassign(value)
107
- array.each do |key, values|
108
- values.delete(value)
109
- end
110
- end
111
-
112
- # Returns true if the value has been assigned to a key.
113
- def assigned?(value)
114
- array.each do |key, values|
115
- return true if values.include?(value)
116
- end
117
- false
118
- end
119
-
120
- # Returns the ordered values as an array
121
- def values
122
- array.collect {|key, values| values}.flatten
123
- end
124
-
125
- # Returns the key for the specified value, or nil
126
- # if the value is unassigned.
127
- def key_for(value)
128
- array.each do |key, values|
129
- return key if values.include?(value)
130
- end
131
- nil
132
- end
133
-
134
- # Returns the values for the specified key, or nil if
135
- # the key cannot be found.
136
- def values_for(key)
137
- array.each do |k, values|
138
- return values if k == key
139
- end
140
- nil
141
- end
142
-
143
- # Yields each [key, value] pair in the order in which
144
- # the keys were declared. Keys with no values are
145
- # skipped.
146
- def each
147
- array.each do |key, values|
148
- values.each {|value| yield(key, value) }
149
- end
150
- end
151
-
152
- # Yields each [key, values] pair in the order in which
153
- # the keys were declared.
154
- def each_pair
155
- array.each do |key, values|
156
- yield(key, values)
157
- end
158
- end
159
-
160
- # Returns self as an array
161
- def to_a
162
- array.collect {|key, values| [key, values.dup] }
163
- end
164
-
165
- protected
166
-
167
- # An array of [key, values] arrays tracking the
168
- # order in which values are assigned.
169
- attr_reader :array
170
-
171
- end
172
- end
173
- end
@@ -1,182 +0,0 @@
1
- require 'tap/support/assignments'
2
- require 'tap/support/instance_configuration'
3
- require 'tap/support/configuration'
4
-
5
- module Tap
6
- module Support
7
-
8
- # ClassConfiguration tracks configurations defined by a Configurable class.
9
- class ClassConfiguration
10
- include Enumerable
11
-
12
- config_templates_dir = File.expand_path File.dirname(__FILE__) + "/../generator/generators/config/templates"
13
-
14
- # The path to the :doc template (see inspect)
15
- DOC_TEMPLATE_PATH = File.join(config_templates_dir, 'doc.erb')
16
-
17
- # The path to the :nodoc template (see inspect)
18
- NODOC_TEMPLATE_PATH = File.join(config_templates_dir, 'nodoc.erb')
19
-
20
- # The Configurable class receiving new configurations
21
- attr_reader :receiver
22
-
23
- # An Assignments tracking the assignment of config keys to receivers
24
- attr_reader :assignments
25
-
26
- # A map of [key, Configuration] pairs
27
- attr_reader :map
28
-
29
- # Generates a new ClassConfiguration for the receiver. If a parent is
30
- # provided, configurations will be inherited from it.
31
- def initialize(receiver, parent=nil)
32
- @receiver = receiver
33
-
34
- if parent != nil
35
- @map = parent.map.inject({}) do |hash, (key, config)|
36
- hash[key] = config.dup
37
- hash
38
- end
39
- @assignments = Assignments.new(parent.assignments)
40
- else
41
- @map = {}
42
- @assignments = Assignments.new
43
- end
44
- end
45
-
46
- # Initializes a Configuration using the inputs and sets using name
47
- # as a key. Any existing config by the same name is overridden.
48
- # Returns the new config.
49
- def add(name, default=nil, attributes={})
50
- self[name] = Configuration.new(name.to_sym, default, attributes)
51
- end
52
-
53
- # Removes the specified configuration.
54
- def remove(key)
55
- self[key] = nil
56
- end
57
-
58
- # Gets the config specified by key. The key is symbolized.
59
- def [](key)
60
- map[key.to_sym]
61
- end
62
-
63
- # Assigns the config to key. A nil config unassigns the
64
- # configuration key. The key is symbolized.
65
- def []=(key, config)
66
- key = key.to_sym
67
-
68
- if config == nil
69
- assignments.unassign(key)
70
- map.delete(key)
71
- else
72
- assignments.assign(receiver, key) unless assignments.assigned?(key)
73
- map[key] = config
74
- end
75
- end
76
-
77
- # Returns true if key is a config key.
78
- def key?(key)
79
- map.has_key?(key)
80
- end
81
-
82
- # Returns all config keys.
83
- def keys
84
- map.keys
85
- end
86
-
87
- # Returns config keys in order.
88
- def ordered_keys
89
- assignments.values
90
- end
91
-
92
- # Returns all mapped configs.
93
- def values
94
- map.values
95
- end
96
-
97
- # True if map is empty.
98
- def empty?
99
- map.empty?
100
- end
101
-
102
- # Calls block once for each [receiver, key, config] in self,
103
- # passing those elements as parameters in the order in
104
- # which they were assigned.
105
- def each
106
- assignments.each do |receiver, key|
107
- yield(receiver, key, map[key])
108
- end
109
- end
110
-
111
- # Calls block once for each [key, config] pair in self,
112
- # passing those elements as parameters in the order in
113
- # which they were assigned.
114
- def each_pair
115
- assignments.each do |receiver, key|
116
- yield(key, map[key])
117
- end
118
- end
119
-
120
- # Initializes and returns a new InstanceConfiguration set to self
121
- # and bound to the receiver, if specified.
122
- def instance_config(receiver=nil, store={})
123
- InstanceConfiguration.new(self, receiver, store)
124
- end
125
-
126
- # Returns a hash of the [key, config.default] pairs in self.
127
- def to_hash
128
- hash = {}
129
- each_pair {|key, config| hash[key] = config.default }
130
- hash
131
- end
132
-
133
- # An array of config descriptions that are Comment objects.
134
- def code_comments
135
- code_comments = []
136
- values.each do |config|
137
- code_comments << config.desc if config.desc.kind_of?(Lazydoc::Comment)
138
- end
139
- code_comments
140
- end
141
-
142
- # Inspects the configurations using the specified template. Templates
143
- # are used for format each [receiver, configurations] pair in self.
144
- # See DEFAULT_TEMPLATE as a model. The results of each template cycle
145
- # are pushed to target.
146
- #
147
- # Two default templates are defined, <tt>:doc</tt> and <tt>:nodoc</tt>.
148
- # These map to the contents of DOC_TEMPLATE_PATH and NODOC_TEMPLATE_PATH
149
- # and correspond to the documented and undocumented
150
- # Tap::Generator::Generators::ConfigGenerator templates.
151
- def inspect(template=:doc, target="")
152
- Lazydoc.resolve_comments(code_comments)
153
-
154
- template = case template
155
- when :doc then File.read(DOC_TEMPLATE_PATH)
156
- when :nodoc then File.read(NODOC_TEMPLATE_PATH)
157
- else template
158
- end
159
-
160
- templater = Templater.new(template)
161
- assignments.each_pair do |receiver, keys|
162
- next if keys.empty?
163
-
164
- # set the template attributes
165
- templater.receiver = receiver
166
- templater.configurations = keys.collect do |key|
167
- # duplicate config so that any changes to it
168
- # during templation will not propogate back
169
- # into self
170
- [key, map[key].dup]
171
- end.compact
172
-
173
- yield(templater) if block_given?
174
- target << templater.build
175
- end
176
-
177
- target
178
- end
179
- end
180
- end
181
- end
182
-