templater 0.1.6 → 0.2
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.
- data/README +13 -7
- data/Rakefile +30 -0
- data/lib/templater.rb +4 -2
- data/lib/templater/actions/action.rb +43 -0
- data/lib/templater/actions/empty_directory.rb +16 -14
- data/lib/templater/actions/file.rb +16 -21
- data/lib/templater/actions/template.rb +13 -22
- data/lib/templater/cli/generator.rb +13 -9
- data/lib/templater/core_ext/string.rb +1 -1
- data/lib/templater/description.rb +61 -0
- data/lib/templater/discovery.rb +16 -9
- data/lib/templater/generator.rb +115 -137
- data/lib/templater/spec/helpers.rb +1 -1
- data/spec/actions/empty_directory_spec.rb +105 -0
- data/spec/actions/file_spec.rb +112 -0
- data/spec/actions/template_spec.rb +141 -0
- data/spec/generator/actions_spec.rb +92 -43
- data/spec/generator/arguments_spec.rb +7 -3
- data/spec/generator/empty_directories_spec.rb +12 -4
- data/spec/generator/files_spec.rb +17 -26
- data/spec/generator/templates_spec.rb +17 -28
- data/spec/spec_helper.rb +24 -1
- metadata +18 -6
- data/lib/templater/proxy.rb +0 -62
- data/spec/empty_directory_spec.rb +0 -97
- data/spec/file_spec.rb +0 -97
- data/spec/template_spec.rb +0 -137
data/lib/templater/discovery.rb
CHANGED
@@ -53,18 +53,25 @@ module Templater
|
|
53
53
|
|
54
54
|
protected
|
55
55
|
|
56
|
-
def
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
56
|
+
def find_latest_gem_paths
|
57
|
+
# Minigems provides a simpler (and much faster) method for finding the
|
58
|
+
# latest gems.
|
59
|
+
if Gem.respond_to?(:latest_gem_paths)
|
60
|
+
Gem.latest_gem_paths
|
61
|
+
else
|
62
|
+
gems = Gem.cache.inject({}) do |latest_gems, cache|
|
63
|
+
name, gem = cache
|
64
|
+
currently_latest = latest_gems[gem.name]
|
65
|
+
latest_gems[gem.name] = gem if currently_latest.nil? or gem.version > currently_latest.version
|
66
|
+
latest_gems
|
67
|
+
end
|
68
|
+
gems.values.map{|g| g.full_gem_path}
|
69
|
+
end
|
63
70
|
end
|
64
71
|
|
65
72
|
def generator_files
|
66
|
-
|
67
|
-
path = ::File.join(
|
73
|
+
find_latest_gem_paths.inject([]) do |files, gem_path|
|
74
|
+
path = ::File.join(gem_path, "Generators")
|
68
75
|
files << path if ::File.exists?(path) and not ::File.directory?(path)
|
69
76
|
files
|
70
77
|
end
|
data/lib/templater/generator.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
module Templater
|
2
2
|
|
3
|
+
ACTION_RESERVED_OPTIONS = [:before, :after].freeze
|
4
|
+
|
3
5
|
class Generator
|
4
6
|
|
5
7
|
include Templater::CaptureHelpers
|
@@ -7,6 +9,7 @@ module Templater
|
|
7
9
|
class << self
|
8
10
|
|
9
11
|
attr_accessor :manifold
|
12
|
+
|
10
13
|
|
11
14
|
# Returns an array of hashes, where each hash describes a single argument.
|
12
15
|
#
|
@@ -14,56 +17,57 @@ module Templater
|
|
14
17
|
# Array[Hash{Symbol=>Object}]:: A list of arguments
|
15
18
|
def arguments; @arguments ||= []; end
|
16
19
|
|
20
|
+
# A shorthand method for adding the first argument, see +Templater::Generator.argument+
|
21
|
+
def first_argument(*args); argument(0, *args); end
|
22
|
+
|
23
|
+
# A shorthand method for adding the second argument, see +Templater::Generator.argument+
|
24
|
+
def second_argument(*args); argument(1, *args); end
|
25
|
+
|
26
|
+
# A shorthand method for adding the third argument, see +Templater::Generator.argument+
|
27
|
+
def third_argument(*args); argument(2, *args); end
|
28
|
+
|
29
|
+
# A shorthand method for adding the fourth argument, see +Templater::Generator.argument+
|
30
|
+
def fourth_argument(*args); argument(3, *args); end
|
31
|
+
|
32
|
+
|
17
33
|
# Returns an array of options, where each hash describes a single option.
|
18
34
|
#
|
19
35
|
# === Returns
|
20
36
|
# Array[Hash{Symbol=>Object}]:: A list of options
|
21
37
|
def options; @options ||= []; end
|
22
|
-
|
23
|
-
# Returns an array of hashes, where each hash describes a single template.
|
24
|
-
#
|
25
|
-
# === Returns
|
26
|
-
# Array[Hash{Symbol=>Object}]:: A list of template
|
27
|
-
def templates; @templates ||= []; end
|
28
|
-
|
29
|
-
# Returns an array of hashes, where each hash describes a single file.
|
30
|
-
#
|
31
|
-
# === Returns
|
32
|
-
# Array[Hash{Symbol=>Object}]:: A list of files
|
33
|
-
def files; @files ||= []; end
|
34
|
-
|
38
|
+
|
35
39
|
# Returns an array of hashes, where each hash describes a single invocation.
|
36
40
|
#
|
37
41
|
# === Returns
|
38
42
|
# Array[Hash{Symbol=>Object}]:: A list of invocations
|
39
43
|
def invocations; @invocations ||= []; end
|
44
|
+
|
40
45
|
|
41
|
-
# Returns an
|
46
|
+
# Returns an Hash that maps the type of action to a list of ActionDescriptions.
|
42
47
|
#
|
43
48
|
# ==== Returns
|
44
|
-
#
|
45
|
-
def
|
49
|
+
# Hash{Symbol=>Array[Templater::ActionDescription]}:: A Hash of actions
|
50
|
+
def actions; @actions ||= {} end
|
46
51
|
|
47
|
-
|
48
|
-
|
49
|
-
|
52
|
+
# Returns an array of ActionDescriptions, where each describes a single template.
|
53
|
+
#
|
54
|
+
# === Returns
|
55
|
+
# Array[Templater::ActionDescription]:: A list of template descriptions.
|
56
|
+
def templates; actions[:templates] ||= []; end
|
50
57
|
|
51
|
-
#
|
52
|
-
|
53
|
-
|
54
|
-
# A
|
55
|
-
def
|
56
|
-
|
57
|
-
# A shorthand method for adding the third argument, see +Templater::Generator.argument+
|
58
|
-
def third_argument(*args); argument(2, *args); end
|
58
|
+
# Returns an array of ActionDescriptions, where each describes a single file.
|
59
|
+
#
|
60
|
+
# === Returns
|
61
|
+
# Array[Templater::ActionDescription]:: A list of file descriptions.
|
62
|
+
def files; actions[:files] ||= []; end
|
59
63
|
|
60
|
-
#
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
+
# Returns an array of ActionDescriptions, where each describes a single empty directory created by generator.
|
65
|
+
#
|
66
|
+
# ==== Returns
|
67
|
+
# Array[Templater::ActionDescription]:: A list of empty directory descriptions.
|
68
|
+
def empty_directories; actions[:empty_directories] ||= []; end
|
64
69
|
|
65
70
|
|
66
|
-
|
67
71
|
# If the argument is omitted, simply returns the description for this generator, otherwise
|
68
72
|
# sets the description to the passed string.
|
69
73
|
#
|
@@ -96,11 +100,7 @@ module Templater
|
|
96
100
|
# :required<Boolean>:: If set to true, the generator will throw an error if it initialized without this argument
|
97
101
|
# :desc<Symbol>:: Provide a description for this argument
|
98
102
|
def argument(n, name, options={}, &block)
|
99
|
-
self.arguments[n] =
|
100
|
-
:name => name.to_sym,
|
101
|
-
:options => options,
|
102
|
-
:block => block
|
103
|
-
}
|
103
|
+
self.arguments[n] = ArgumentDescription.new(name.to_sym, options, &block)
|
104
104
|
class_eval <<-CLASS
|
105
105
|
def #{name}
|
106
106
|
get_argument(#{n})
|
@@ -124,10 +124,7 @@ module Templater
|
|
124
124
|
# :as<Symbol>:: If set to :boolean provides a hint to the interface using this generator.
|
125
125
|
# :desc<Symbol>:: Provide a description for this option
|
126
126
|
def option(name, options={})
|
127
|
-
self.options <<
|
128
|
-
:name => name.to_sym,
|
129
|
-
:options => options
|
130
|
-
}
|
127
|
+
self.options << Description.new(name.to_sym, options)
|
131
128
|
class_eval <<-CLASS
|
132
129
|
def #{name}
|
133
130
|
get_option(:#{name})
|
@@ -178,11 +175,7 @@ module Templater
|
|
178
175
|
# invoke :other_generator, :amimal => :bear
|
179
176
|
# end
|
180
177
|
def invoke(name, options={}, &block)
|
181
|
-
self.invocations <<
|
182
|
-
:name => name.to_sym,
|
183
|
-
:options => options,
|
184
|
-
:block => block
|
185
|
-
}
|
178
|
+
self.invocations << InvocationDescription.new(name.to_sym, options, &block)
|
186
179
|
end
|
187
180
|
|
188
181
|
# Adds a template to this generator. Templates are named and can later be retrieved by that name.
|
@@ -196,8 +189,8 @@ module Templater
|
|
196
189
|
# Source and destination can be set in a block, which makes it possible to call instance methods to
|
197
190
|
# determine the correct source and/or desination.
|
198
191
|
#
|
199
|
-
# A hash of options can be passed,
|
200
|
-
# generator.
|
192
|
+
# A hash of options can be passed, these options are matched against the options passed to the
|
193
|
+
# generator. Some special options, for callbacks for example, are also supported, see below.
|
201
194
|
#
|
202
195
|
# === Parameters
|
203
196
|
# name<Symbol>:: The name of this template
|
@@ -206,6 +199,10 @@ module Templater
|
|
206
199
|
# options<Hash>:: Options for this template
|
207
200
|
# &block<Proc>:: A block to execute when the generator is instantiated
|
208
201
|
#
|
202
|
+
# === Options
|
203
|
+
# :before<Symbol>:: Name of a method to execute before this template is invoked
|
204
|
+
# :after<Symbol>:: Name of a method to execute after this template is invoked
|
205
|
+
#
|
209
206
|
# ==== Examples
|
210
207
|
#
|
211
208
|
# class MyGenerator < Templater::Generator
|
@@ -225,14 +222,11 @@ module Templater
|
|
225
222
|
source, destination = args
|
226
223
|
source, destination = source + 't', source if args.size == 1
|
227
224
|
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
:block => block,
|
234
|
-
:render => true
|
235
|
-
}
|
225
|
+
templates << ActionDescription.new(name, options) do |generator|
|
226
|
+
template = Actions::Template.new(generator, name, source, destination, options)
|
227
|
+
generator.instance_exec(template, &block) if block
|
228
|
+
template
|
229
|
+
end
|
236
230
|
end
|
237
231
|
|
238
232
|
# Adds a template that is not rendered using ERB, but copied directly. Unlike Templater::Generator.template
|
@@ -244,19 +238,20 @@ module Templater
|
|
244
238
|
# destination<String>:: The destination where the result will be put.
|
245
239
|
# options<Hash>:: Options for this template
|
246
240
|
# &block<Proc>:: A block to execute when the generator is instantiated
|
241
|
+
#
|
242
|
+
# === Options
|
243
|
+
# :before<Symbol>:: Name of a method to execute before this template is invoked
|
244
|
+
# :after<Symbol>:: Name of a method to execute after this template is invoked
|
247
245
|
def file(name, *args, &block)
|
248
246
|
options = args.last.is_a?(Hash) ? args.pop : {}
|
249
247
|
source, destination = args
|
250
248
|
source, destination = source, source if args.size == 1
|
251
249
|
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
:block => block,
|
258
|
-
:render => false
|
259
|
-
}
|
250
|
+
files << ActionDescription.new(name, options) do |generator|
|
251
|
+
file = Actions::File.new(generator, name, source, destination, options)
|
252
|
+
generator.instance_exec(file, &block) if block
|
253
|
+
file
|
254
|
+
end
|
260
255
|
end
|
261
256
|
|
262
257
|
# Adds an empty directory that will be created when the generator is run.
|
@@ -266,16 +261,19 @@ module Templater
|
|
266
261
|
# destination<String>:: The destination where the empty directory will be created
|
267
262
|
# options<Hash>:: Options for this empty directory
|
268
263
|
# &block<Proc>:: A block to execute when the generator is instantiated
|
264
|
+
#
|
265
|
+
# === Options
|
266
|
+
# :before<Symbol>:: Name of a method to execute before this template is invoked
|
267
|
+
# :after<Symbol>:: Name of a method to execute after this template is invoked
|
269
268
|
def empty_directory(name, *args, &block)
|
270
269
|
options = args.last.is_a?(Hash) ? args.pop : {}
|
271
270
|
destination = args.first
|
272
271
|
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
}
|
272
|
+
empty_directories << ActionDescription.new(name, options) do |generator|
|
273
|
+
directory = Actions::EmptyDirectory.new(generator, name, destination, options)
|
274
|
+
generator.instance_exec(directory, &block) if block
|
275
|
+
directory
|
276
|
+
end
|
279
277
|
end
|
280
278
|
|
281
279
|
# An easy way to add many templates to a generator, each item in the list is added as a
|
@@ -356,15 +354,14 @@ module Templater
|
|
356
354
|
# === Returns
|
357
355
|
# Array[Templater::Generator]:: an array of generator classes.
|
358
356
|
def generators
|
357
|
+
generators = [self]
|
359
358
|
if manifold
|
360
|
-
generators
|
361
|
-
generator = manifold.generator(i
|
359
|
+
generators += invocations.map do |i|
|
360
|
+
generator = manifold.generator(i.name)
|
362
361
|
generator ? generator.generators : nil
|
363
362
|
end
|
364
|
-
generators.unshift(self).flatten.compact
|
365
|
-
else
|
366
|
-
[self]
|
367
363
|
end
|
364
|
+
generators.flatten.compact
|
368
365
|
end
|
369
366
|
|
370
367
|
# This should return the directory where source templates are located. This method must be overridden in
|
@@ -401,10 +398,15 @@ module Templater
|
|
401
398
|
|
402
399
|
# Initialize options to their default values.
|
403
400
|
self.class.options.each do |option|
|
404
|
-
@options[option
|
401
|
+
@options[option.name] ||= option.options[:default]
|
405
402
|
end
|
406
403
|
|
407
404
|
extract_arguments(*args)
|
405
|
+
|
406
|
+
# Initialize arguments to their default values.
|
407
|
+
self.class.arguments.each_with_index do |argument, i|
|
408
|
+
@arguments[i] ||= argument.options[:default]
|
409
|
+
end
|
408
410
|
|
409
411
|
valid_arguments?
|
410
412
|
end
|
@@ -418,7 +420,7 @@ module Templater
|
|
418
420
|
# === Returns
|
419
421
|
# Templater::Actions::Template:: The found template.
|
420
422
|
def template(name)
|
421
|
-
|
423
|
+
templates.find { |t| t.name == name }
|
422
424
|
end
|
423
425
|
|
424
426
|
# Finds and returns the file of the given name. If that file's options don't match the generator
|
@@ -430,7 +432,7 @@ module Templater
|
|
430
432
|
# === Returns
|
431
433
|
# Templater::Actions::File:: The found file.
|
432
434
|
def file(name)
|
433
|
-
|
435
|
+
files.find { |f| f.name == name }
|
434
436
|
end
|
435
437
|
|
436
438
|
# Finds and returns all empty directories whose options match the generator options.
|
@@ -438,7 +440,7 @@ module Templater
|
|
438
440
|
# === Returns
|
439
441
|
# [Templater::Actions::EmptyDirectory]:: The found empty directories that generator creates.
|
440
442
|
def empty_directory(name)
|
441
|
-
|
443
|
+
empty_directories.find { |d| d.name == name }
|
442
444
|
end
|
443
445
|
|
444
446
|
# Finds and returns all templates whose options match the generator options.
|
@@ -446,10 +448,7 @@ module Templater
|
|
446
448
|
# === Returns
|
447
449
|
# [Templater::Actions::Template]:: The found templates.
|
448
450
|
def templates
|
449
|
-
|
450
|
-
templates << Templater::Proxy.new(self, template).to_template if match_options?(template[:options])
|
451
|
-
templates
|
452
|
-
end
|
451
|
+
actions(:templates)
|
453
452
|
end
|
454
453
|
|
455
454
|
# Finds and returns all files whose options match the generator options.
|
@@ -457,10 +456,7 @@ module Templater
|
|
457
456
|
# === Returns
|
458
457
|
# [Templater::Actions::File]:: The found files.
|
459
458
|
def files
|
460
|
-
|
461
|
-
files << Templater::Proxy.new(self, file).to_file if match_options?(file[:options])
|
462
|
-
files
|
463
|
-
end
|
459
|
+
actions(:files)
|
464
460
|
end
|
465
461
|
|
466
462
|
# Finds and returns all empty directories generator creates.
|
@@ -468,10 +464,7 @@ module Templater
|
|
468
464
|
# === Returns
|
469
465
|
# [Templater::Actions::File]:: The found files.
|
470
466
|
def empty_directories
|
471
|
-
|
472
|
-
empty_directories << Templater::Proxy.new(self, action).to_empty_directory if match_options?(action[:options])
|
473
|
-
empty_directories
|
474
|
-
end
|
467
|
+
actions(:empty_directories)
|
475
468
|
end
|
476
469
|
|
477
470
|
# Finds and returns all templates whose options match the generator options.
|
@@ -481,18 +474,20 @@ module Templater
|
|
481
474
|
def invocations
|
482
475
|
return [] unless self.class.manifold
|
483
476
|
|
484
|
-
self.class.invocations.
|
485
|
-
|
486
|
-
|
487
|
-
|
488
|
-
|
489
|
-
|
490
|
-
|
491
|
-
|
492
|
-
|
493
|
-
|
494
|
-
|
495
|
-
|
477
|
+
self.class.invocations.map do |invocation|
|
478
|
+
invocation.get(self) if match_options?(invocation.options)
|
479
|
+
end.compact
|
480
|
+
end
|
481
|
+
|
482
|
+
# Finds and returns all templates and files for this generators whose options match its options.
|
483
|
+
#
|
484
|
+
# === Returns
|
485
|
+
# [Templater::Actions::*]:: The found templates and files.
|
486
|
+
def actions(type=nil)
|
487
|
+
actions = type ? self.class.actions[type] : self.class.actions.values.flatten
|
488
|
+
actions.inject([]) do |actions, description|
|
489
|
+
actions << description.compile(self) if match_options?(description.options)
|
490
|
+
actions
|
496
491
|
end
|
497
492
|
end
|
498
493
|
|
@@ -501,15 +496,15 @@ module Templater
|
|
501
496
|
#
|
502
497
|
# === Returns
|
503
498
|
# [Templater::Actions::File, Templater::Actions::Template]:: The found templates and files.
|
504
|
-
def
|
505
|
-
|
506
|
-
|
507
|
-
|
499
|
+
def all_actions(type=nil)
|
500
|
+
all_actions = actions(type)
|
501
|
+
all_actions += invocations.map { |i| i.all_actions(type) }
|
502
|
+
all_actions.flatten
|
508
503
|
end
|
509
504
|
|
510
505
|
# Invokes the templates for this generator
|
511
506
|
def invoke!
|
512
|
-
|
507
|
+
all_actions.each { |t| t.invoke! }
|
513
508
|
end
|
514
509
|
|
515
510
|
# Renders all actions in this generator. Use this to verify that rendering templates raises no errors.
|
@@ -517,7 +512,7 @@ module Templater
|
|
517
512
|
# === Returns
|
518
513
|
# [String]:: The results of the rendered actions
|
519
514
|
def render!
|
520
|
-
|
515
|
+
all_actions.map { |t| t.render }
|
521
516
|
end
|
522
517
|
|
523
518
|
# Returns this generator's source root
|
@@ -542,18 +537,17 @@ module Templater
|
|
542
537
|
|
543
538
|
protected
|
544
539
|
|
545
|
-
def set_argument(n,
|
546
|
-
|
547
|
-
|
548
|
-
@arguments[n] = arg
|
540
|
+
def set_argument(n, value)
|
541
|
+
self.class.arguments[n].valid?(value)
|
542
|
+
@arguments[n] = value
|
549
543
|
end
|
550
544
|
|
551
545
|
def get_argument(n)
|
552
|
-
@arguments[n]
|
546
|
+
@arguments[n]
|
553
547
|
end
|
554
548
|
|
555
|
-
def set_option(name,
|
556
|
-
@options[name] =
|
549
|
+
def set_option(name, value)
|
550
|
+
@options[name] = value
|
557
551
|
end
|
558
552
|
|
559
553
|
def get_option(name)
|
@@ -561,30 +555,14 @@ module Templater
|
|
561
555
|
end
|
562
556
|
|
563
557
|
def match_options?(options)
|
564
|
-
options.all?
|
565
|
-
|
566
|
-
|
567
|
-
def valid_argument?(arg, options, &block)
|
568
|
-
if arg.nil? and options[:required]
|
569
|
-
raise Templater::TooFewArgumentsError
|
570
|
-
elsif not arg.nil?
|
571
|
-
if options[:as] == :hash and not arg.is_a?(Hash)
|
572
|
-
raise Templater::MalformattedArgumentError, "Expected the argument to be a Hash, but was '#{arg.inspect}'"
|
573
|
-
elsif options[:as] == :array and not arg.is_a?(Array)
|
574
|
-
raise Templater::MalformattedArgumentError, "Expected the argument to be an Array, but was '#{arg.inspect}'"
|
575
|
-
end
|
576
|
-
|
577
|
-
invalid = catch :invalid do
|
578
|
-
yield if block_given?
|
579
|
-
throw :invalid, :not_invalid
|
580
|
-
end
|
581
|
-
raise Templater::ArgumentError, invalid unless invalid == :not_invalid
|
558
|
+
options.all? do |key, value|
|
559
|
+
key.to_sym.in?(Templater::ACTION_RESERVED_OPTIONS) or self.send(key) == value
|
582
560
|
end
|
583
561
|
end
|
584
|
-
|
562
|
+
|
585
563
|
def valid_arguments?
|
586
564
|
self.class.arguments.each_with_index do |arg, i|
|
587
|
-
|
565
|
+
arg.valid?(@arguments[i])
|
588
566
|
end
|
589
567
|
end
|
590
568
|
|
@@ -597,7 +575,7 @@ module Templater
|
|
597
575
|
|
598
576
|
# When one of the arguments has :as set to :hash or :list, the remaining arguments should be consumed
|
599
577
|
# and converted to a Hash or an Array respectively
|
600
|
-
case expected
|
578
|
+
case expected.options[:as]
|
601
579
|
when :hash
|
602
580
|
if arg.is_a?(String)
|
603
581
|
pairs = args[i..-1]
|