codger 0.0.1
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/.gitignore +4 -0
- data/Gemfile +4 -0
- data/LICENSE +22 -0
- data/README.md +63 -0
- data/Rakefile +1 -0
- data/bin/codger +4 -0
- data/codger.gemspec +28 -0
- data/lib/codger/cli.rb +100 -0
- data/lib/codger/generator.rb +84 -0
- data/lib/codger/manager.rb +134 -0
- data/lib/codger/skeleton.rb +137 -0
- data/lib/codger/version.rb +3 -0
- data/lib/codger.rb +8 -0
- metadata +103 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2012 Jacob Williams
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
# codger
|
2
|
+
|
3
|
+
Goals:
|
4
|
+
|
5
|
+
* Provide a simple way to define and run project skeletons and other code generators.
|
6
|
+
* Help integrate later changes to the generators into a project.
|
7
|
+
|
8
|
+
## Creating Skeletons
|
9
|
+
|
10
|
+
Put the skeleton in a git repo. Before testing it, make sure to at least `git add` the files. Then:
|
11
|
+
|
12
|
+
codger skeleton path/to/your-repo-name --test
|
13
|
+
|
14
|
+
Now, to generate code inside the current working directory, do
|
15
|
+
|
16
|
+
codger gen your-repo-name
|
17
|
+
|
18
|
+
Here's how the skeleton repo will be used:
|
19
|
+
|
20
|
+
1. If there is a script named `generate.rb` in the root directory, it will be run.
|
21
|
+
2. Files ending in `.erb` will be [interpolated](http://ruby-doc.org/stdlib-1.9.3/libdoc/erb/rdoc/ERB.html) and written to the target directory.
|
22
|
+
3. Other files will be copied directly to the target directory. (Exceptions: README, README.md, README.markdown)
|
23
|
+
|
24
|
+
### Parameters
|
25
|
+
|
26
|
+
In the templates or generate.rb, use the method `param :parameter_name` to request values to configure the skeleton. The first time a particular parameter is requested, the user will be prompted for a value.
|
27
|
+
|
28
|
+
The first time a prompt is given, the skeleton repo's README will be printed (if it exists).
|
29
|
+
|
30
|
+
### Helpers
|
31
|
+
|
32
|
+
* In a template, you can use `<%- rename "relative_path" -%>` to override the output file name.
|
33
|
+
* Use `copy "path1", "path2"` to copy files "path1" and "path2" (relative the skeleton repo's root directory) into the target directory directly. Use `copy "path1" => "newpath1"` to override the destination path in the target directory.
|
34
|
+
* Use `interpolate "path1", "path2"` to interpolate ERB files "path1" and "path2" into the target directory. As with `copy` you can use a hash to override the destination paths.
|
35
|
+
* Use `ignore "path1", "path2"` to prevent automatic copying or interpolation of files.
|
36
|
+
|
37
|
+
## Using Skeletons
|
38
|
+
|
39
|
+
Register a skeleton:
|
40
|
+
|
41
|
+
codger skeleton git://example.com/boilerplate.git
|
42
|
+
|
43
|
+
Run it in a new folder:
|
44
|
+
|
45
|
+
codger create boilerplate monumental-endeavor
|
46
|
+
|
47
|
+
Or run it in the current working directory:
|
48
|
+
|
49
|
+
codger gen boilerplate
|
50
|
+
|
51
|
+
In either case the parameters used will be recorded in a file named `.codger`, so that later, after the project or the skeleton have changed, you can use
|
52
|
+
|
53
|
+
codger diff
|
54
|
+
|
55
|
+
to compare the current state of your project with the output of the current version of the skeleton. The command used for diffing can be changed:
|
56
|
+
|
57
|
+
codger config diff "diff -ur %SOURCE %DEST"
|
58
|
+
|
59
|
+
## TODO
|
60
|
+
|
61
|
+
* Better documentation; examples
|
62
|
+
* I'm hopeful that more useful diffing can be done through git integration, but I haven't worked on it much yet.
|
63
|
+
* Code generators shouldn't be restricted to whatever dependencies happen to be pulled in by codger.
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/bin/codger
ADDED
data/codger.gemspec
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "codger/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "codger"
|
7
|
+
s.version = Codger::VERSION
|
8
|
+
s.authors = ["Jacob Williams"]
|
9
|
+
s.email = ["jacobaw@gmail.com"]
|
10
|
+
s.homepage = ""
|
11
|
+
s.summary = %q{Manages invocation of code generators.}
|
12
|
+
s.description = %q{Manages invocation of code generators.}
|
13
|
+
|
14
|
+
s.rubyforge_project = "codger"
|
15
|
+
|
16
|
+
s.files = `git ls-files`.split("\n")
|
17
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
18
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
|
+
s.require_paths = ["lib"]
|
20
|
+
|
21
|
+
# specify any dependencies here; for example:
|
22
|
+
# s.add_development_dependency "rspec"
|
23
|
+
# s.add_runtime_dependency "rest-client"
|
24
|
+
s.add_runtime_dependency 'activesupport', '~> 3.2.1'
|
25
|
+
s.add_runtime_dependency 'deep_merge', '~> 1.0.0'
|
26
|
+
s.add_runtime_dependency 'git', '~> 1.2.5'
|
27
|
+
s.add_runtime_dependency 'thor', '~> 0.14.6'
|
28
|
+
end
|
data/lib/codger/cli.rb
ADDED
@@ -0,0 +1,100 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
require 'git'
|
3
|
+
require 'thor'
|
4
|
+
require 'tmpdir'
|
5
|
+
require 'yaml'
|
6
|
+
|
7
|
+
module Codger
|
8
|
+
class CLI < Thor
|
9
|
+
desc 'config [NAME [VALUE]]', 'lists, shows, or alters configuration'
|
10
|
+
def config(name = nil, value = nil)
|
11
|
+
if name
|
12
|
+
if value
|
13
|
+
Manager.default.global_settings[:config][name] = value
|
14
|
+
Manager.default.save_globals
|
15
|
+
else
|
16
|
+
puts Manager.default.settings[:config][name]
|
17
|
+
end
|
18
|
+
else
|
19
|
+
puts YAML.dump(Manager.default.settings[:config]).lines.drop(1).join
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
desc 'available', 'lists registered code generators'
|
24
|
+
def available
|
25
|
+
Manager.default.settings[:generators].each do |name, info|
|
26
|
+
puts "#{name}\t#{info.inspect}"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
desc 'skeleton LOCATION', 'register a git repository as a code generator, creating a clone from the given location'
|
31
|
+
method_option :name, desc: 'Name you wish to refer to the skeleton by.'
|
32
|
+
method_option :test, desc: 'Prevent cloning or pulling of the repository. Location should be a path on the file system.'
|
33
|
+
def skeleton(location)
|
34
|
+
info = {}
|
35
|
+
if options[:test]
|
36
|
+
location = File.expand_path(location)
|
37
|
+
info[:test] = true
|
38
|
+
end
|
39
|
+
info[:git] = location
|
40
|
+
Manager.default.register options[:name], info
|
41
|
+
end
|
42
|
+
|
43
|
+
desc 'create NAME PATH', 'run the named generator in a new folder at the given path'
|
44
|
+
def create(name, path)
|
45
|
+
FileUtils.mkdir path
|
46
|
+
Git.init File.expand_path(path)
|
47
|
+
manager = Manager.new(File.join(path, '.codger'))
|
48
|
+
generator = manager.generator(manager.settings[:generators][name])
|
49
|
+
generator.run path, project_name: path.split('/').last
|
50
|
+
manager.record_run generator
|
51
|
+
end
|
52
|
+
|
53
|
+
desc 'gen NAME', 'run the named generator'
|
54
|
+
def gen(name)
|
55
|
+
generator = Manager.default.generator(Manager.default.settings[:generators][name])
|
56
|
+
generator.run(Dir.pwd)
|
57
|
+
Manager.default.record_run(generator)
|
58
|
+
end
|
59
|
+
|
60
|
+
desc 'history', 'show the actions recorded for this directory'
|
61
|
+
def history
|
62
|
+
Manager.default.settings[:runs].each do |info|
|
63
|
+
puts "#{info[:generator]} [#{info[:tags].join(' ')}]"
|
64
|
+
puts Generator.format_params(info[:params])
|
65
|
+
puts
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
desc 'diff [TAGS...]', 'run part or all of the history in a temp directory and display a diff'
|
70
|
+
def diff(*tags)
|
71
|
+
Dir.mktmpdir do |dir|
|
72
|
+
Manager.default.settings[:runs].each do |info|
|
73
|
+
if tags.empty? or (tags & info[:tags]).any?
|
74
|
+
generator = Manager.default.generator(info[:generator])
|
75
|
+
generator.run dir, info[:params]
|
76
|
+
end
|
77
|
+
end
|
78
|
+
system Manager.default.diff_command(dir, Dir.pwd)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
desc 'repeat [TAGS...]', 're-run part or all of the history'
|
83
|
+
def repeat(*tags)
|
84
|
+
Manager.default.settings[:runs].each do |info|
|
85
|
+
if tags.empty? or (tags & info[:tags]).any?
|
86
|
+
puts "Running #{info[:generator]} [#{info[:tags].join(' ')}]"
|
87
|
+
puts Generator.format_params(info[:params])
|
88
|
+
puts
|
89
|
+
generator = Manager.default.generator(info[:generator])
|
90
|
+
generator.run Dir.pwd, info[:params]
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
desc 'unregister NAME', 'unregister a code generator and delete its clone'
|
96
|
+
def unregister(name)
|
97
|
+
Manager.default.unregister name
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
3
|
+
module Codger
|
4
|
+
# A code generator. The #run method is called to perform code generation;
|
5
|
+
# the parameters used (which may have been specified interactively during #run)
|
6
|
+
# can be determined afterwards using #params.
|
7
|
+
#
|
8
|
+
# Subclasses must implement:
|
9
|
+
# * a #generate method which will perform the code generation
|
10
|
+
# * a #help method which returns help text
|
11
|
+
#
|
12
|
+
# Methods for use by subclasses:
|
13
|
+
# * #dest_path
|
14
|
+
# * #ensure_folder
|
15
|
+
# * #param
|
16
|
+
# * #tags
|
17
|
+
class Generator
|
18
|
+
class << self
|
19
|
+
# Given a params map, print one param per line, indented.
|
20
|
+
def format_params(params)
|
21
|
+
YAML.dump(params).lines.drop(1).map do |line|
|
22
|
+
"\t#{line}"
|
23
|
+
end.join
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# The map of parameters used during the last call to #run.
|
28
|
+
attr_reader :params
|
29
|
+
# The output directory used during the last call to #run.
|
30
|
+
attr_reader :target
|
31
|
+
|
32
|
+
# Perform code generation in the given directory. Any parameters
|
33
|
+
# already known (e.g., if we're repeating a previous run) can be
|
34
|
+
# specified; any other parameters needed will be determined interactively.
|
35
|
+
def run(target, params = {})
|
36
|
+
@showed_help = false
|
37
|
+
@target = target
|
38
|
+
@params = params.with_indifferent_access
|
39
|
+
|
40
|
+
generate
|
41
|
+
end
|
42
|
+
|
43
|
+
# Given a path relative to the output directory root, returns the full path.
|
44
|
+
def dest_path(path)
|
45
|
+
File.join(target, path)
|
46
|
+
end
|
47
|
+
|
48
|
+
# Given a path relative to the output directory root, creates a folder
|
49
|
+
# at that location if one does not yet exist.
|
50
|
+
def ensure_folder(path)
|
51
|
+
FileUtils.mkdir_p(File.join(target, File.dirname(path)))
|
52
|
+
end
|
53
|
+
|
54
|
+
# Returns the value from the params map for the given name. If there
|
55
|
+
# is none, asks the user for a value. #help is called the first time
|
56
|
+
# the user is asked for a value.
|
57
|
+
# The parameter will also be saved in an instance variable of the same name.
|
58
|
+
def param(name)
|
59
|
+
until params[name]
|
60
|
+
unless @showed_help
|
61
|
+
puts help
|
62
|
+
puts
|
63
|
+
@showed_help = true
|
64
|
+
end
|
65
|
+
print "Specify #{name}: "
|
66
|
+
value = STDIN.gets.chomp
|
67
|
+
params[name] = value unless value.empty?
|
68
|
+
end
|
69
|
+
instance_variable_set("@#{name}", params[name])
|
70
|
+
params[name]
|
71
|
+
end
|
72
|
+
|
73
|
+
# Sets (with parameters) or returns (without parameters) tags for
|
74
|
+
# this generator. The tags will be associated to recorded runs.
|
75
|
+
# (This may be useless, we'll see.)
|
76
|
+
def tags(*tags)
|
77
|
+
if tags == []
|
78
|
+
@tags || []
|
79
|
+
else
|
80
|
+
@tags = tags.flatten
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,134 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
require 'git'
|
3
|
+
require 'yaml'
|
4
|
+
|
5
|
+
module Codger
|
6
|
+
# Responsible for:
|
7
|
+
# * Reading, writing, and to some degree interpreting configuration files.
|
8
|
+
# * Looking up code generators from their identifiers.
|
9
|
+
class Manager
|
10
|
+
class << self
|
11
|
+
# Return an instance using any settings in the .codger
|
12
|
+
# file (if one exists) of the working directory.
|
13
|
+
def default
|
14
|
+
@config ||= Manager.new(File.join(Dir.pwd, '.codger'))
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
# The global settings map (i.e. from ~/.codger/codger.yaml)
|
19
|
+
attr_reader :global_settings
|
20
|
+
# The project settings map (i.e. from .codger)
|
21
|
+
attr_reader :project_settings
|
22
|
+
|
23
|
+
# Create an instance with project-level settings stored at the specified path
|
24
|
+
# (does not need to exist yet, and will not be created unless necessary).
|
25
|
+
def initialize(path)
|
26
|
+
@project_path = path
|
27
|
+
@project_settings = {
|
28
|
+
runs: []
|
29
|
+
}.with_indifferent_access
|
30
|
+
if File.exists?(@project_path)
|
31
|
+
@project_settings.merge! YAML.load(File.read(@project_path))
|
32
|
+
end
|
33
|
+
|
34
|
+
@global_settings = {
|
35
|
+
config: {
|
36
|
+
diff: 'diff -ur %SOURCE %DEST'
|
37
|
+
},
|
38
|
+
clones: {},
|
39
|
+
generators: {}
|
40
|
+
}.with_indifferent_access
|
41
|
+
if File.exists?(globals_path)
|
42
|
+
@global_settings.merge! YAML.load(File.read(globals_path))
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
# Creates a Generator, currently always a Skeleton.
|
47
|
+
# info should contain :git, the path/URI of the repository.
|
48
|
+
# Unless it contains :test, the repository will be cloned to #clones_base
|
49
|
+
# (if it has not been already).
|
50
|
+
def generator(info)
|
51
|
+
if location = info[:git]
|
52
|
+
if info[:test]
|
53
|
+
clone = location
|
54
|
+
elsif !(clone = settings[:clones][location] and File.exists?(clone))
|
55
|
+
FileUtils.mkdir_p clones_base
|
56
|
+
next_id = Dir.entries(clones_base).map(&:to_i).max + 1
|
57
|
+
clone = File.join(clones_base, next_id.to_s)
|
58
|
+
Git.clone location, clone
|
59
|
+
@global_settings[:clones][location] = clone
|
60
|
+
save_globals
|
61
|
+
end
|
62
|
+
Skeleton.new clone, info
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
# Load a generator for the given attributes and register it
|
67
|
+
# in the global configuration under the given name, or its default
|
68
|
+
# name if name is nil.
|
69
|
+
def register(name, info)
|
70
|
+
gen = generator(info)
|
71
|
+
@global_settings[:generators][name || gen.name] = gen.info
|
72
|
+
save_globals
|
73
|
+
end
|
74
|
+
|
75
|
+
# Given a generator name, removes it from the config, and delete its
|
76
|
+
# local clone if one exists.
|
77
|
+
def unregister(name)
|
78
|
+
info = @global_settings[:generators].delete name # TODO graciously handle it not existing
|
79
|
+
clone = @global_settings[:clones].delete info[:git]
|
80
|
+
if clone and clone.start_with? clones_base # sanity check before rm_rf
|
81
|
+
FileUtils.rm_rf clone
|
82
|
+
end
|
83
|
+
save_globals
|
84
|
+
end
|
85
|
+
|
86
|
+
# Saves the tags, identifier, and params from the last run of the given generator instance
|
87
|
+
# in the project settings file.
|
88
|
+
def record_run(generator)
|
89
|
+
@project_settings[:runs] << {
|
90
|
+
tags: [generator.name] + generator.tags,
|
91
|
+
generator: generator.info,
|
92
|
+
params: generator.params
|
93
|
+
}.with_indifferent_access
|
94
|
+
save_project
|
95
|
+
end
|
96
|
+
|
97
|
+
# Save #project_settings.
|
98
|
+
def save_project
|
99
|
+
File.write @project_path, @project_settings.to_yaml
|
100
|
+
end
|
101
|
+
|
102
|
+
# Save #global_settings.
|
103
|
+
def save_globals
|
104
|
+
FileUtils.mkdir_p codger_home
|
105
|
+
File.write globals_path, @global_settings.to_yaml
|
106
|
+
end
|
107
|
+
|
108
|
+
# Return the folder where global settings and other resources can be saved.
|
109
|
+
# By default ~/.codger but this can be overridden using 'codger_home' in #project_settings.
|
110
|
+
def codger_home
|
111
|
+
@project_settings[:codger_home] || File.join(Dir.home, '.codger')
|
112
|
+
end
|
113
|
+
|
114
|
+
# Return the file where global settings should be saved - 'codger.yaml' in #codger_home.
|
115
|
+
def globals_path
|
116
|
+
File.join(codger_home, 'codger.yaml')
|
117
|
+
end
|
118
|
+
|
119
|
+
# Return the folder where skeleton clones can be saved - 'clones' in #codger_home.
|
120
|
+
def clones_base
|
121
|
+
File.join(codger_home, 'clones')
|
122
|
+
end
|
123
|
+
|
124
|
+
# Return a merged map of #global_settings and #project_settings.
|
125
|
+
def settings
|
126
|
+
@global_settings.deep_merge @project_settings
|
127
|
+
end
|
128
|
+
|
129
|
+
# Return the command to use for diffing two folders.
|
130
|
+
def diff_command(source, dest)
|
131
|
+
settings[:config][:diff].gsub('%SOURCE', source).gsub('%DEST', dest)
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
@@ -0,0 +1,137 @@
|
|
1
|
+
require 'erb'
|
2
|
+
require 'fileutils'
|
3
|
+
require 'git'
|
4
|
+
|
5
|
+
module Codger
|
6
|
+
# A generator that produces code by using a git repository as a template.
|
7
|
+
#
|
8
|
+
# By default:
|
9
|
+
# * README, README.md, README.markdown will be ignored, except to
|
10
|
+
# be printed as documentation if user input is required for the
|
11
|
+
# value of a param
|
12
|
+
# * generate.rb (if it exists) will be executed in the context of
|
13
|
+
# the Skeleton instance
|
14
|
+
# * Files ending in .erb will be interpolated in the context of
|
15
|
+
# the Skeleton instance
|
16
|
+
# * All other files will be copied directly
|
17
|
+
#
|
18
|
+
# Methods for use in generate.rb and templates:
|
19
|
+
# * #src_path
|
20
|
+
# * #copy
|
21
|
+
# * #interpolate
|
22
|
+
# * #ignore
|
23
|
+
# * #rename
|
24
|
+
class Skeleton < Generator
|
25
|
+
# Returns a (non-unique) name for the generator. For
|
26
|
+
# skeletons this is based on the last segment of the origin
|
27
|
+
# URI or of the clone's path.
|
28
|
+
attr_reader :name
|
29
|
+
# Returns the attributes used in creating this instance.
|
30
|
+
attr_reader :info
|
31
|
+
|
32
|
+
# Create an instance reading from the git repository at the specified
|
33
|
+
# path. Options for info:
|
34
|
+
# git:: Canonical source for the repo; required.
|
35
|
+
# test:: Unless truthy, an attempt will be made to perform a 'pull' for the repository.
|
36
|
+
def initialize(repo, info)
|
37
|
+
@info = info
|
38
|
+
@git = Git.open(repo)
|
39
|
+
# https://github.com/schacon/ruby-git/issues/32
|
40
|
+
@git.lib.send(:command, 'pull') unless info[:test] # TODO needs to be OK if this fails
|
41
|
+
@name = info[:git].split('/').last.sub(/\.git\z/,'')
|
42
|
+
end
|
43
|
+
|
44
|
+
# Perform code generation using the process outlined in the class documentation.
|
45
|
+
def generate
|
46
|
+
@to_copy = @git.ls_files.keys - ['README', 'README.md', 'README.markdown', 'generate.rb']
|
47
|
+
|
48
|
+
code_path = src_path('generate.rb')
|
49
|
+
if File.exists?(code_path)
|
50
|
+
eval(File.read(code_path), binding, code_path)
|
51
|
+
end
|
52
|
+
|
53
|
+
interpolate(@to_copy.select {|path| path =~ /\.erb\z/})
|
54
|
+
copy @to_copy
|
55
|
+
end
|
56
|
+
|
57
|
+
# Return the full path to the given file in the repo.
|
58
|
+
def src_path(path)
|
59
|
+
File.join(@git.dir.to_s, path)
|
60
|
+
end
|
61
|
+
|
62
|
+
# For each path or array of paths, copy the
|
63
|
+
# corresponding files directly from the repository to
|
64
|
+
# the target directory.
|
65
|
+
# Alternatively, a hash of paths may be given, in which
|
66
|
+
# keys specify the name in the source repository and
|
67
|
+
# values specify the desired name in the target directory.
|
68
|
+
def copy(*paths)
|
69
|
+
paths = paths.flatten
|
70
|
+
mappings = {}
|
71
|
+
paths.each do |path|
|
72
|
+
if path.is_a? Hash
|
73
|
+
mappings.merge! path
|
74
|
+
else
|
75
|
+
mappings[path] = path
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
mappings.each do |src, dest|
|
80
|
+
ensure_folder dest
|
81
|
+
FileUtils.cp src_path(src), dest_path(dest)
|
82
|
+
@to_copy.delete src
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
# For each path or array of paths, interpolate (in the
|
87
|
+
# context of this object) the corresponding files and
|
88
|
+
# write the output to the target directory, stripping
|
89
|
+
# .erb from the filename.
|
90
|
+
# Alternatively, a hash of paths may be given, in which
|
91
|
+
# keys specify the name in the source repository and
|
92
|
+
# values specify the desired name in the target directory.
|
93
|
+
#
|
94
|
+
# Note that calls to #rename may override the destination path.
|
95
|
+
def interpolate(*paths)
|
96
|
+
paths = paths.flatten
|
97
|
+
mappings = {}
|
98
|
+
paths.each do |path|
|
99
|
+
if path.is_a? Hash
|
100
|
+
mappings.merge! path
|
101
|
+
else
|
102
|
+
mappings[path] = path.sub(/\.erb\z/, '')
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
mappings.each do |src, dest|
|
107
|
+
@current_template_src = src
|
108
|
+
@current_template_dest = dest
|
109
|
+
template = ERB.new(File.read(src_path(src)), nil, '-')
|
110
|
+
ensure_folder @current_template_dest
|
111
|
+
result = template.result(binding)
|
112
|
+
File.write dest_path(@current_template_dest), result
|
113
|
+
@to_copy.delete src
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
# Should only be called from within a file being interpolated.
|
118
|
+
# The output path will be changed to dest, which should be
|
119
|
+
# relative to the template's folder.
|
120
|
+
def rename(dest)
|
121
|
+
@current_template_dest = File.join(File.dirname(@current_template_src), dest)
|
122
|
+
end
|
123
|
+
|
124
|
+
# For each path or array of paths, disable implicit copying.
|
125
|
+
def ignore(*paths)
|
126
|
+
@to_copy -= paths.flatten
|
127
|
+
end
|
128
|
+
|
129
|
+
# Returns the text of the README, README.md or README.markdown file, if any.
|
130
|
+
def help
|
131
|
+
path = Dir[src_path('README')].first || Dir[src_path('README.md')].first || Dir[src_path('README.markdown')].first
|
132
|
+
if path
|
133
|
+
File.read path
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
data/lib/codger.rb
ADDED
metadata
ADDED
@@ -0,0 +1,103 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: codger
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Jacob Williams
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-03-05 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: activesupport
|
16
|
+
requirement: &70337635384820 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 3.2.1
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *70337635384820
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: deep_merge
|
27
|
+
requirement: &70337635384160 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ~>
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 1.0.0
|
33
|
+
type: :runtime
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *70337635384160
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: git
|
38
|
+
requirement: &70337635383500 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ~>
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: 1.2.5
|
44
|
+
type: :runtime
|
45
|
+
prerelease: false
|
46
|
+
version_requirements: *70337635383500
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: thor
|
49
|
+
requirement: &70337635382820 !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ~>
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 0.14.6
|
55
|
+
type: :runtime
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: *70337635382820
|
58
|
+
description: Manages invocation of code generators.
|
59
|
+
email:
|
60
|
+
- jacobaw@gmail.com
|
61
|
+
executables:
|
62
|
+
- codger
|
63
|
+
extensions: []
|
64
|
+
extra_rdoc_files: []
|
65
|
+
files:
|
66
|
+
- .gitignore
|
67
|
+
- Gemfile
|
68
|
+
- LICENSE
|
69
|
+
- README.md
|
70
|
+
- Rakefile
|
71
|
+
- bin/codger
|
72
|
+
- codger.gemspec
|
73
|
+
- lib/codger.rb
|
74
|
+
- lib/codger/cli.rb
|
75
|
+
- lib/codger/generator.rb
|
76
|
+
- lib/codger/manager.rb
|
77
|
+
- lib/codger/skeleton.rb
|
78
|
+
- lib/codger/version.rb
|
79
|
+
homepage: ''
|
80
|
+
licenses: []
|
81
|
+
post_install_message:
|
82
|
+
rdoc_options: []
|
83
|
+
require_paths:
|
84
|
+
- lib
|
85
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
86
|
+
none: false
|
87
|
+
requirements:
|
88
|
+
- - ! '>='
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
version: '0'
|
91
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
92
|
+
none: false
|
93
|
+
requirements:
|
94
|
+
- - ! '>='
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
requirements: []
|
98
|
+
rubyforge_project: codger
|
99
|
+
rubygems_version: 1.8.6
|
100
|
+
signing_key:
|
101
|
+
specification_version: 3
|
102
|
+
summary: Manages invocation of code generators.
|
103
|
+
test_files: []
|