toys 0.2.2 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -29,9 +29,11 @@
29
29
 
30
30
  require "fileutils"
31
31
 
32
- module Toys::Helpers
33
- ##
34
- # File system utilities. See the "fileutils" standard library.
35
- #
36
- FileUtils = ::FileUtils
32
+ module Toys
33
+ module Helpers
34
+ ##
35
+ # File system utilities. See the "fileutils" standard library.
36
+ #
37
+ FileUtils = ::FileUtils
38
+ end
37
39
  end
@@ -31,45 +31,49 @@ module Toys
31
31
  ##
32
32
  # The lookup service that finds a tool given a set of arguments
33
33
  #
34
- class Lookup
34
+ class Loader
35
35
  def initialize(config_dir_name: nil, config_file_name: nil,
36
- index_file_name: nil, preload_file_name: nil)
36
+ index_file_name: nil, preload_file_name: nil,
37
+ middleware: [], root_desc: nil)
37
38
  @config_dir_name = config_dir_name
38
39
  @config_file_name = config_file_name
39
40
  @index_file_name = index_file_name
40
41
  @preload_file_name = preload_file_name
42
+ @middleware = middleware
41
43
  check_init_options
42
44
  @load_worklist = []
43
- @tools = {[] => [Tool.new(self, []), nil]}
45
+ root_tool = Tool.new([], middleware)
46
+ root_tool.long_desc = root_desc if root_desc
47
+ @tools = {[] => [root_tool, nil]}
44
48
  @max_priority = @min_priority = 0
45
49
  end
46
50
 
47
- def add_paths(paths, high_priority: false)
51
+ def add_config_paths(paths, high_priority: false)
48
52
  paths = Array(paths)
49
53
  paths = paths.reverse if high_priority
50
54
  paths.each do |path|
51
- add_path(path, high_priority: high_priority)
55
+ add_config_path(path, high_priority: high_priority)
52
56
  end
53
57
  self
54
58
  end
55
59
 
56
- def add_path(path, high_priority: false)
60
+ def add_config_path(path, high_priority: false)
57
61
  path = check_path(path)
58
62
  priority = high_priority ? (@max_priority += 1) : (@min_priority -= 1)
59
63
  @load_worklist << [path, [], priority]
60
64
  self
61
65
  end
62
66
 
63
- def add_config_paths(paths, high_priority: false)
67
+ def add_paths(paths, high_priority: false)
64
68
  paths = Array(paths)
65
69
  paths = paths.reverse if high_priority
66
70
  paths.each do |path|
67
- add_config_path(path, high_priority: high_priority)
71
+ add_path(path, high_priority: high_priority)
68
72
  end
69
73
  self
70
74
  end
71
75
 
72
- def add_config_path(path, high_priority: false)
76
+ def add_path(path, high_priority: false)
73
77
  path = check_path(path, type: :dir)
74
78
  priority = high_priority ? (@max_priority += 1) : (@min_priority -= 1)
75
79
  if @config_file_name
@@ -101,9 +105,9 @@ module Toys
101
105
  end
102
106
  end
103
107
 
104
- def execute(context_base, args)
108
+ def execute(context_base, args, verbosity: 0)
105
109
  tool = lookup(args)
106
- tool.execute(context_base, args.slice(tool.full_name.length..-1))
110
+ tool.execute(context_base, args.slice(tool.full_name.length..-1), verbosity: verbosity)
107
111
  end
108
112
 
109
113
  def exact_tool(words)
@@ -111,19 +115,26 @@ module Toys
111
115
  @tools[words].first
112
116
  end
113
117
 
114
- def get_tool(words, priority)
118
+ def get_tool(words, priority, assume_parent: false)
115
119
  if tool_defined?(words)
116
120
  tool, tool_priority = @tools[words]
117
- return tool if tool_priority.nil? || tool_priority == priority
121
+ return tool if priority.nil? || tool_priority.nil? || tool_priority == priority
118
122
  return nil if tool_priority > priority
119
123
  end
120
- parent = get_tool(words[0..-2], priority)
121
- return nil if parent.nil?
122
- tool = Tool.new(self, words)
124
+ unless assume_parent
125
+ parent = get_tool(words[0..-2], priority)
126
+ return nil if parent.nil?
127
+ end
128
+ tool = Tool.new(words, @middleware)
123
129
  @tools[words] = [tool, priority]
124
130
  tool
125
131
  end
126
132
 
133
+ def put_tool!(tool, priority = nil)
134
+ @tools[tool.full_name] = [tool, priority]
135
+ self
136
+ end
137
+
127
138
  def tool_defined?(words)
128
139
  @tools.key?(words)
129
140
  end
@@ -194,7 +205,7 @@ module Toys
194
205
  if ::File.extname(path) == ".rb"
195
206
  tool = get_tool(words, priority)
196
207
  if tool
197
- Builder.build(path, tool, remaining_words, priority, self, ::IO.read(path))
208
+ Builder.build(path, tool, remaining_words, priority, self, ::IO.read(path), :tool)
198
209
  end
199
210
  else
200
211
  require_preload_in(path)
@@ -225,7 +236,7 @@ module Toys
225
236
  child_path = check_path(::File.join(path, child))
226
237
  child_word = ::File.basename(child, ".rb")
227
238
  next_words = words + [child_word]
228
- next_remaining = Lookup.next_remaining_words(remaining_words, child_word)
239
+ next_remaining = Loader.next_remaining_words(remaining_words, child_word)
229
240
  handle_path(child_path, next_words, next_remaining, priority)
230
241
  end
231
242
 
@@ -0,0 +1,41 @@
1
+ # Copyright 2018 Daniel Azuma
2
+ #
3
+ # All rights reserved.
4
+ #
5
+ # Redistribution and use in source and binary forms, with or without
6
+ # modification, are permitted provided that the following conditions are met:
7
+ #
8
+ # * Redistributions of source code must retain the above copyright notice,
9
+ # this list of conditions and the following disclaimer.
10
+ # * Redistributions in binary form must reproduce the above copyright notice,
11
+ # this list of conditions and the following disclaimer in the documentation
12
+ # and/or other materials provided with the distribution.
13
+ # * Neither the name of the copyright holder, nor the names of any other
14
+ # contributors to this software, may be used to endorse or promote products
15
+ # derived from this software without specific prior written permission.
16
+ #
17
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20
+ # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21
+ # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22
+ # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23
+ # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25
+ # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26
+ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27
+ # POSSIBILITY OF SUCH DAMAGE.
28
+ ;
29
+
30
+ require "toys/utils/module_lookup"
31
+
32
+ module Toys
33
+ ##
34
+ # Namespace for common middleware
35
+ #
36
+ module Middleware
37
+ def self.lookup(name)
38
+ Utils::ModuleLookup.lookup(:middleware, name)
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,45 @@
1
+ # Copyright 2018 Daniel Azuma
2
+ #
3
+ # All rights reserved.
4
+ #
5
+ # Redistribution and use in source and binary forms, with or without
6
+ # modification, are permitted provided that the following conditions are met:
7
+ #
8
+ # * Redistributions of source code must retain the above copyright notice,
9
+ # this list of conditions and the following disclaimer.
10
+ # * Redistributions in binary form must reproduce the above copyright notice,
11
+ # this list of conditions and the following disclaimer in the documentation
12
+ # and/or other materials provided with the distribution.
13
+ # * Neither the name of the copyright holder, nor the names of any other
14
+ # contributors to this software, may be used to endorse or promote products
15
+ # derived from this software without specific prior written permission.
16
+ #
17
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20
+ # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21
+ # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22
+ # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23
+ # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25
+ # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26
+ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27
+ # POSSIBILITY OF SUCH DAMAGE.
28
+ ;
29
+
30
+ module Toys
31
+ module Middleware
32
+ ##
33
+ # A base middleware with a no-op implementation
34
+ #
35
+ class Base
36
+ def config(_tool)
37
+ yield
38
+ end
39
+
40
+ def execute(_context)
41
+ yield
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,57 @@
1
+ # Copyright 2018 Daniel Azuma
2
+ #
3
+ # All rights reserved.
4
+ #
5
+ # Redistribution and use in source and binary forms, with or without
6
+ # modification, are permitted provided that the following conditions are met:
7
+ #
8
+ # * Redistributions of source code must retain the above copyright notice,
9
+ # this list of conditions and the following disclaimer.
10
+ # * Redistributions in binary form must reproduce the above copyright notice,
11
+ # this list of conditions and the following disclaimer in the documentation
12
+ # and/or other materials provided with the distribution.
13
+ # * Neither the name of the copyright holder, nor the names of any other
14
+ # contributors to this software, may be used to endorse or promote products
15
+ # derived from this software without specific prior written permission.
16
+ #
17
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20
+ # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21
+ # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22
+ # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23
+ # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25
+ # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26
+ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27
+ # POSSIBILITY OF SUCH DAMAGE.
28
+ ;
29
+
30
+ require "toys/middleware/base"
31
+ require "toys/utils/usage"
32
+
33
+ module Toys
34
+ module Middleware
35
+ ##
36
+ # A middleware that provides a default implementation for groups
37
+ #
38
+ class GroupDefault < Base
39
+ def config(tool)
40
+ if tool.includes_executor?
41
+ yield
42
+ else
43
+ tool.add_switch(:_recursive, "-r", "--[no-]recursive",
44
+ doc: "Show all subcommands recursively")
45
+ end
46
+ end
47
+
48
+ def execute(context)
49
+ if context[Context::TOOL].includes_executor?
50
+ yield
51
+ else
52
+ puts(Utils::Usage.from_context(context).string(recursive: context[:_recursive]))
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,51 @@
1
+ # Copyright 2018 Daniel Azuma
2
+ #
3
+ # All rights reserved.
4
+ #
5
+ # Redistribution and use in source and binary forms, with or without
6
+ # modification, are permitted provided that the following conditions are met:
7
+ #
8
+ # * Redistributions of source code must retain the above copyright notice,
9
+ # this list of conditions and the following disclaimer.
10
+ # * Redistributions in binary form must reproduce the above copyright notice,
11
+ # this list of conditions and the following disclaimer in the documentation
12
+ # and/or other materials provided with the distribution.
13
+ # * Neither the name of the copyright holder, nor the names of any other
14
+ # contributors to this software, may be used to endorse or promote products
15
+ # derived from this software without specific prior written permission.
16
+ #
17
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20
+ # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21
+ # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22
+ # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23
+ # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25
+ # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26
+ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27
+ # POSSIBILITY OF SUCH DAMAGE.
28
+ ;
29
+
30
+ require "toys/middleware/base"
31
+
32
+ module Toys
33
+ module Middleware
34
+ ##
35
+ # A middleware that provides switches for editing the verbosity
36
+ #
37
+ class SetVerbosity < Base
38
+ def config(tool)
39
+ tool.add_switch(Context::VERBOSITY, "-v", "--verbose",
40
+ doc: "Increase verbosity",
41
+ handler: ->(_val, cur) { cur + 1 },
42
+ only_unique: true)
43
+ tool.add_switch(Context::VERBOSITY, "-q", "--quiet",
44
+ doc: "Decrease verbosity",
45
+ handler: ->(_val, cur) { cur - 1 },
46
+ only_unique: true)
47
+ yield
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,57 @@
1
+ # Copyright 2018 Daniel Azuma
2
+ #
3
+ # All rights reserved.
4
+ #
5
+ # Redistribution and use in source and binary forms, with or without
6
+ # modification, are permitted provided that the following conditions are met:
7
+ #
8
+ # * Redistributions of source code must retain the above copyright notice,
9
+ # this list of conditions and the following disclaimer.
10
+ # * Redistributions in binary form must reproduce the above copyright notice,
11
+ # this list of conditions and the following disclaimer in the documentation
12
+ # and/or other materials provided with the distribution.
13
+ # * Neither the name of the copyright holder, nor the names of any other
14
+ # contributors to this software, may be used to endorse or promote products
15
+ # derived from this software without specific prior written permission.
16
+ #
17
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20
+ # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21
+ # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22
+ # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23
+ # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25
+ # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26
+ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27
+ # POSSIBILITY OF SUCH DAMAGE.
28
+ ;
29
+
30
+ require "toys/middleware/base"
31
+ require "toys/utils/usage"
32
+
33
+ module Toys
34
+ module Middleware
35
+ ##
36
+ # A middleware that shows usage documentation
37
+ #
38
+ class ShowToolHelp < Base
39
+ def config(tool)
40
+ if tool.includes_executor?
41
+ tool.add_switch(:_help, "-?", "--help",
42
+ doc: "Show help message",
43
+ only_unique: true)
44
+ end
45
+ yield
46
+ end
47
+
48
+ def execute(context)
49
+ if context[:_help]
50
+ puts(Utils::Usage.from_context(context).string(recursive: context[:_recursive]))
51
+ else
52
+ yield
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,51 @@
1
+ # Copyright 2018 Daniel Azuma
2
+ #
3
+ # All rights reserved.
4
+ #
5
+ # Redistribution and use in source and binary forms, with or without
6
+ # modification, are permitted provided that the following conditions are met:
7
+ #
8
+ # * Redistributions of source code must retain the above copyright notice,
9
+ # this list of conditions and the following disclaimer.
10
+ # * Redistributions in binary form must reproduce the above copyright notice,
11
+ # this list of conditions and the following disclaimer in the documentation
12
+ # and/or other materials provided with the distribution.
13
+ # * Neither the name of the copyright holder, nor the names of any other
14
+ # contributors to this software, may be used to endorse or promote products
15
+ # derived from this software without specific prior written permission.
16
+ #
17
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20
+ # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21
+ # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22
+ # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23
+ # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25
+ # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26
+ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27
+ # POSSIBILITY OF SUCH DAMAGE.
28
+ ;
29
+
30
+ require "toys/middleware/base"
31
+ require "toys/utils/usage"
32
+
33
+ module Toys
34
+ module Middleware
35
+ ##
36
+ # A middleware that shows usage errors
37
+ #
38
+ class ShowUsageErrors < Base
39
+ def execute(context)
40
+ if context[Context::USAGE_ERROR]
41
+ puts(context[Context::USAGE_ERROR])
42
+ puts("")
43
+ puts(Utils::Usage.from_context(context).string)
44
+ context.exit(-1)
45
+ else
46
+ yield
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,41 @@
1
+ # Copyright 2018 Daniel Azuma
2
+ #
3
+ # All rights reserved.
4
+ #
5
+ # Redistribution and use in source and binary forms, with or without
6
+ # modification, are permitted provided that the following conditions are met:
7
+ #
8
+ # * Redistributions of source code must retain the above copyright notice,
9
+ # this list of conditions and the following disclaimer.
10
+ # * Redistributions in binary form must reproduce the above copyright notice,
11
+ # this list of conditions and the following disclaimer in the documentation
12
+ # and/or other materials provided with the distribution.
13
+ # * Neither the name of the copyright holder, nor the names of any other
14
+ # contributors to this software, may be used to endorse or promote products
15
+ # derived from this software without specific prior written permission.
16
+ #
17
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20
+ # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21
+ # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22
+ # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23
+ # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25
+ # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26
+ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27
+ # POSSIBILITY OF SUCH DAMAGE.
28
+ ;
29
+
30
+ require "toys/utils/module_lookup"
31
+
32
+ module Toys
33
+ ##
34
+ # Namespace for common templates
35
+ #
36
+ module Templates
37
+ def self.lookup(name)
38
+ Utils::ModuleLookup.lookup(:templates, name)
39
+ end
40
+ end
41
+ end