codger 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in codger.gemspec
4
+ gemspec
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
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'codger'
4
+ Codger::CLI.start
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
@@ -0,0 +1,3 @@
1
+ module Codger
2
+ VERSION = "0.0.1"
3
+ end
data/lib/codger.rb ADDED
@@ -0,0 +1,8 @@
1
+ require 'active_support/core_ext'
2
+ require 'deep_merge/rails_compat'
3
+
4
+ require 'codger/cli'
5
+ require 'codger/generator'
6
+ require 'codger/manager'
7
+ require 'codger/skeleton'
8
+ require 'codger/version'
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: []