cog 0.0.20 → 0.1.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.
- data/bin/cog +54 -53
- data/lib/cog.rb +4 -3
- data/lib/cog/built_in_tools/basic.rb +10 -0
- data/lib/cog/built_in_tools/basic/cog_tool.rb +15 -0
- data/lib/cog/config.rb +111 -33
- data/lib/cog/config/tool.rb +99 -0
- data/lib/cog/controllers.rb +13 -0
- data/lib/cog/controllers/generator_controller.rb +45 -0
- data/lib/cog/controllers/template_controller.rb +31 -0
- data/lib/cog/controllers/tool_controller.rb +53 -0
- data/lib/cog/errors.rb +51 -9
- data/lib/cog/generator.rb +1 -74
- data/lib/cog/helpers.rb +1 -0
- data/lib/cog/helpers/cascading_template_set.rb +75 -0
- data/lib/cog/helpers/string.rb +9 -3
- data/lib/cog/version.rb +1 -1
- data/templates/basic/generator.rb.erb +12 -0
- data/templates/{cog/generator/basic-template.txt.erb.erb → basic/template.txt.erb.erb} +0 -0
- data/templates/cog/{tool → custom_tool}/Gemfile.erb +4 -0
- data/templates/cog/{tool → custom_tool}/LICENSE.erb +1 -1
- data/templates/cog/custom_tool/README.markdown.erb +18 -0
- data/templates/cog/custom_tool/Rakefile.erb +15 -0
- data/templates/cog/custom_tool/cog_tool.rb.erb +15 -0
- data/templates/cog/custom_tool/generator.rb.erb.erb +9 -0
- data/templates/cog/{tool → custom_tool}/template.txt.erb.erb +0 -0
- data/templates/cog/custom_tool/tool.gemspec.erb +18 -0
- data/templates/cog/{tool → custom_tool}/tool.rb.erb +5 -13
- data/templates/cog/{tool → custom_tool}/version.rb.erb +1 -1
- metadata +24 -17
- data/lib/cog/tool.rb +0 -81
- data/templates/cog/generator/basic.rb.erb +0 -12
- data/templates/cog/tool/API.rdoc.erb +0 -7
- data/templates/cog/tool/README.markdown.erb +0 -18
- data/templates/cog/tool/Rakefile.erb +0 -15
- data/templates/cog/tool/generator.rb.erb.erb +0 -6
- data/templates/cog/tool/tool.gemspec.erb +0 -18
data/bin/cog
CHANGED
@@ -11,58 +11,72 @@ include GLI::App
|
|
11
11
|
program_desc 'This is a utility to help you write code generators.'
|
12
12
|
|
13
13
|
# version Cog::VERSION
|
14
|
+
|
14
15
|
desc 'Output more detailed information when running a command'
|
15
|
-
switch :v
|
16
|
+
switch [:verbose, :v]
|
17
|
+
|
18
|
+
desc 'Set the Cogfile explicitly'
|
19
|
+
arg_name 'path'
|
20
|
+
flag :cogfile
|
21
|
+
|
22
|
+
desc 'Set the active tool'
|
23
|
+
arg_name 'name'
|
24
|
+
default_value 'basic'
|
25
|
+
flag :tool
|
16
26
|
|
17
27
|
desc 'Add cog to the project in the present working directory'
|
18
|
-
skips_pre
|
19
28
|
command :init do |c|
|
20
29
|
|
21
|
-
c.action do |
|
30
|
+
c.action do |gopt, opt, args|
|
22
31
|
Cog.initialize_project
|
23
32
|
end
|
24
33
|
end
|
25
34
|
|
26
|
-
desc '
|
35
|
+
desc 'Manage project generators'
|
27
36
|
command [:generator, :gen] do |c|
|
28
37
|
|
29
38
|
c.default_command :list
|
30
39
|
|
31
|
-
c.desc 'List generators
|
40
|
+
c.desc 'List project generators'
|
32
41
|
c.command :list do |sub|
|
33
|
-
sub.action do |
|
34
|
-
x = Cog::
|
42
|
+
sub.action do |gopt, opt, args|
|
43
|
+
x = Cog::Controllers::GeneratorController.list :verbose => gopt[:v]
|
35
44
|
puts x.join "\n" unless x.empty?
|
36
45
|
end
|
37
46
|
end
|
38
47
|
|
39
|
-
c.desc 'Create a new generator
|
40
|
-
c.arg_name '
|
48
|
+
c.desc 'Create a new project generator'
|
49
|
+
c.arg_name 'name'
|
41
50
|
c.command :new do |sub|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
51
|
+
sub.action do |gopt, opt, args|
|
52
|
+
args.each do |name|
|
53
|
+
Cog::Controllers::GeneratorController.create name
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
c.desc 'Run project generators'
|
59
|
+
c.long_desc 'Omit generator name to run all of them'
|
60
|
+
c.arg_name 'name'
|
61
|
+
c.command :run do |sub|
|
62
|
+
sub.action do |gopt, opt, args|
|
63
|
+
args = Cog::Controllers::GeneratorController.list if args.empty?
|
49
64
|
args.each do |name|
|
50
|
-
Cog::
|
65
|
+
Cog::Controllers::GeneratorController.run name
|
51
66
|
end
|
52
67
|
end
|
53
68
|
end
|
54
69
|
end
|
55
70
|
|
56
71
|
desc 'List or create DSLs known as cog tools'
|
57
|
-
skips_pre
|
58
72
|
command :tool do |c|
|
59
73
|
|
60
74
|
c.default_command :list
|
61
75
|
|
62
76
|
c.desc 'List the available tools'
|
63
77
|
c.command :list do |sub|
|
64
|
-
sub.action do |
|
65
|
-
x = Cog::
|
78
|
+
sub.action do |gopt, opt, args|
|
79
|
+
x = Cog::Controllers::ToolController.list :verbose => gopt[:verbose]
|
66
80
|
puts x.join "\n" unless x.empty?
|
67
81
|
end
|
68
82
|
end
|
@@ -70,46 +84,38 @@ command :tool do |c|
|
|
70
84
|
c.desc 'Create a new tool'
|
71
85
|
c.arg_name 'tool_name'
|
72
86
|
c.command :new do |sub|
|
73
|
-
sub.action do |
|
87
|
+
sub.action do |gopt, opt, args|
|
74
88
|
args.each do |name|
|
75
|
-
Cog::
|
89
|
+
Cog::Controllers::ToolController.create name
|
76
90
|
end
|
77
91
|
end
|
78
92
|
end
|
79
93
|
end
|
80
94
|
|
81
|
-
desc '
|
82
|
-
|
83
|
-
command :run do |c|
|
95
|
+
desc 'Manage templates'
|
96
|
+
command :template do |c|
|
84
97
|
|
85
|
-
c.
|
86
|
-
|
87
|
-
|
88
|
-
|
98
|
+
c.default_command :list
|
99
|
+
|
100
|
+
c.desc 'List the available templates'
|
101
|
+
c.command :list do |sub|
|
102
|
+
sub.action do |gopt, opt, args|
|
103
|
+
x = Cog::Controllers::TemplateController.list :verbose => gopt[:verbose]
|
104
|
+
puts x.join "\n" unless x.empty?
|
89
105
|
end
|
90
106
|
end
|
91
107
|
end
|
92
108
|
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
c.action do
|
98
|
-
puts 'c++'
|
99
|
-
end
|
100
|
-
end
|
101
|
-
|
102
|
-
pre do |global_options, command, options, args|
|
103
|
-
# Pre logic here
|
104
|
-
# Return true to proceed; false to abort and not call the
|
105
|
-
# chosen command
|
106
|
-
# Use skips_pre before a command to skip this block
|
107
|
-
# on that command only
|
108
|
-
unless Cog::Config.instance.project?
|
109
|
-
STDERR.write "No Cogfile could be found\n".color(:red)
|
110
|
-
STDOUT.write "Run `cog init` to prepare a project for use with cog\n"
|
109
|
+
pre do |gopt, command, opt, args|
|
110
|
+
if gopt[:cogfile] && !File.exists?(gopt[:cogfile])
|
111
|
+
STDERR.write "No such Cogfile at #{gopt[:cogfile]}\n"
|
111
112
|
false
|
112
113
|
else
|
114
|
+
Cog::Config.instance = Cog::Config.new gopt[:cogfile] if gopt[:cogfile]
|
115
|
+
unless command.name == :init
|
116
|
+
Cog::Config.instance.register_tools
|
117
|
+
Cog::Config.instance.activate_tool gopt[:tool]
|
118
|
+
end
|
113
119
|
true
|
114
120
|
end
|
115
121
|
end
|
@@ -126,9 +132,4 @@ on_error do |exception|
|
|
126
132
|
true
|
127
133
|
end
|
128
134
|
|
129
|
-
|
130
|
-
exit run(ARGV)
|
131
|
-
rescue
|
132
|
-
# Don't show stack traces during normal use
|
133
|
-
raise unless ENV['COG_DEBUG'].nil? || /^(|0|false|no|off)$/i =~ ENV['COG_DEBUG']
|
134
|
-
end
|
135
|
+
exit run(ARGV)
|
data/lib/cog.rb
CHANGED
@@ -1,8 +1,9 @@
|
|
1
1
|
require 'cog/config'
|
2
|
+
require 'cog/controllers'
|
3
|
+
require 'cog/errors'
|
2
4
|
require 'cog/generator'
|
3
|
-
require 'cog/
|
5
|
+
require 'cog/helpers'
|
4
6
|
require 'cog/version'
|
5
|
-
require 'fileutils'
|
6
7
|
|
7
8
|
# +cog+ is a command line utility that makes it a bit easier to organize a project
|
8
9
|
# which uses code generation. These are the API docs, but you might want to read
|
@@ -21,5 +22,5 @@ module Cog
|
|
21
22
|
nil
|
22
23
|
end
|
23
24
|
end
|
24
|
-
|
25
|
+
|
25
26
|
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'cog'
|
2
|
+
|
3
|
+
# Register basic as a tool with cog
|
4
|
+
Cog::Config.instance.register_tool __FILE__, :built_in => true do |tool|
|
5
|
+
|
6
|
+
# Define how new baisc generators are created
|
7
|
+
#
|
8
|
+
# When the block is executed, +self+ will be an instance of Cog::Config::Tool::GeneratorStamper
|
9
|
+
tool.stamp_generator do
|
10
|
+
template_dest = File.join config.project_templates_path, "#{name}.txt.erb"
|
11
|
+
stamp 'basic/generator.rb', generator_dest, :absolute_destination => true
|
12
|
+
stamp 'basic/template.txt.erb', template_dest, :absolute_destination => true
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
data/lib/cog/config.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'cog/config/cogfile'
|
2
|
-
require '
|
2
|
+
require 'cog/config/tool'
|
3
|
+
require 'cog/errors'
|
3
4
|
|
4
5
|
module Cog
|
5
6
|
|
@@ -27,28 +28,87 @@ module Cog
|
|
27
28
|
# @return [String] directory in which to find custom project templates
|
28
29
|
attr_reader :project_templates_path
|
29
30
|
|
30
|
-
# @return [
|
31
|
+
# @return [Tool] the active tool affects the creation of new generators
|
32
|
+
attr_reader :active_tool
|
33
|
+
|
34
|
+
# @return [Boolean] whether or not we operating in the context of a project
|
31
35
|
def project?
|
32
36
|
!@project_root.nil?
|
33
37
|
end
|
34
|
-
|
35
|
-
# @param value [String] a value which is set by the active tool
|
36
|
-
attr_writer :tool_templates_path
|
37
|
-
|
38
|
-
# @return [String] a value which is set by the active tool
|
39
|
-
attr_accessor :tool_generator_template
|
40
38
|
|
41
39
|
# A list of directories in which to find ERB template files
|
42
40
|
#
|
43
41
|
# Templates should be looked for in the following order as determined by the list returned from this method
|
44
42
|
#
|
45
|
-
# * {#project_templates_path}
|
46
|
-
# *
|
47
|
-
# *
|
43
|
+
# * {#project_templates_path} which is present if {#project?}
|
44
|
+
# * {Tool#templates_path} for each registered tool (in no particular order)
|
45
|
+
# * {Config.cog_templates_path} which is *always* present
|
48
46
|
#
|
49
47
|
# @return [Array<String>] a list of directories order with ascending priority
|
50
48
|
def template_paths
|
51
|
-
[@project_templates_path
|
49
|
+
paths = [@project_templates_path]
|
50
|
+
paths += tools.collect {|tool| tool.templates_path}
|
51
|
+
paths << Config.cog_templates_path
|
52
|
+
paths.compact
|
53
|
+
end
|
54
|
+
|
55
|
+
# @return [Array<Tool>] a sorted list of available tools
|
56
|
+
def tools
|
57
|
+
@tools.values.sort
|
58
|
+
end
|
59
|
+
|
60
|
+
# Register built-in and custom tools.
|
61
|
+
# @api developer
|
62
|
+
#
|
63
|
+
# Custom tools are specified in the +COG_TOOLS+ environment variable.
|
64
|
+
# @return [nil]
|
65
|
+
def register_tools
|
66
|
+
# Register built-in tools
|
67
|
+
[:basic].each do |built_in|
|
68
|
+
require File.join(Config.gem_dir, 'lib', 'cog', 'built_in_tools', built_in.to_s, 'cog_tool.rb')
|
69
|
+
end
|
70
|
+
# Register custom tools defined in COG_TOOLS
|
71
|
+
(ENV['COG_TOOLS'] || '').split(':').each do |path|
|
72
|
+
explicit = path.end_with? '.rb'
|
73
|
+
@next_tool_was_required_explicitly = explicit
|
74
|
+
path = "#{path}/cog_tool" unless explicit
|
75
|
+
begin
|
76
|
+
require path
|
77
|
+
rescue LoadError
|
78
|
+
raise Errors::CouldNotLoadTool.new path
|
79
|
+
end
|
80
|
+
end
|
81
|
+
nil
|
82
|
+
end
|
83
|
+
|
84
|
+
# Define a new +cog+ tool
|
85
|
+
# @api developer
|
86
|
+
# @param path [String] path to the <tt>cog_tool.rb</tt> file
|
87
|
+
# @option opt [Boolean] :built_in (false) if +true+, then treat this tool as a built-in tool
|
88
|
+
# @yield [Tool] define the tool
|
89
|
+
# @return [nil]
|
90
|
+
def register_tool(path, opt={}, &block)
|
91
|
+
tool = Tool.new path, :built_in => opt[:built_in], :explicit_require => @next_tool_was_required_explicitly
|
92
|
+
block.call tool
|
93
|
+
@tools[tool.name] = tool
|
94
|
+
nil
|
95
|
+
end
|
96
|
+
|
97
|
+
# @api developer
|
98
|
+
# @return [Boolean] whether or not a tool is registered with the given name
|
99
|
+
def tool_registered?(name)
|
100
|
+
@tools.member? name
|
101
|
+
end
|
102
|
+
|
103
|
+
# Activate the registered tool with the given name
|
104
|
+
# @api developer
|
105
|
+
# @param name [String] name of the registered tool to activate
|
106
|
+
# @return [nil]
|
107
|
+
def activate_tool(name)
|
108
|
+
throw :ToolAlreadyActivated unless @active_tool.nil?
|
109
|
+
raise Errors::NoSuchTool.new(name) unless tool_registered?(name)
|
110
|
+
@tools[name].load
|
111
|
+
@active_tool = @tools[name]
|
52
112
|
end
|
53
113
|
|
54
114
|
# Location of the installed cog gem
|
@@ -64,20 +124,38 @@ module Cog
|
|
64
124
|
end
|
65
125
|
end
|
66
126
|
|
67
|
-
#
|
127
|
+
# Location of the built-in templates
|
128
|
+
def self.cog_templates_path
|
129
|
+
File.join Config.gem_dir, 'templates'
|
130
|
+
end
|
131
|
+
|
132
|
+
# @param cogfile_path [String] if provided the {Cogfile} at the given path
|
133
|
+
# is used to initialize this instance, and {#project?} will be +true+
|
134
|
+
def initialize(cogfile_path = nil)
|
135
|
+
@project_root = nil
|
136
|
+
@tools = {}
|
137
|
+
@language = 'c++'
|
138
|
+
if cogfile_path
|
139
|
+
@cogfile_path = File.expand_path cogfile_path
|
140
|
+
@project_root = File.dirname @cogfile_path
|
141
|
+
cogfile = Cogfile.new self
|
142
|
+
cogfile.interpret
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
# Find or create the singleton {Config} instance.
|
68
147
|
#
|
69
|
-
# Initialized using the Cogfile for the current project, if any can be
|
70
|
-
# found. If not,
|
71
|
-
#
|
148
|
+
# Initialized using the {Cogfile} for the current project, if any can be
|
149
|
+
# found. If not, {#project?} will be +false+ and all the <tt>project_...</tt>
|
150
|
+
# methods will return +nil+.
|
72
151
|
#
|
73
|
-
# The Cogfile will be looked for in the present working directory. If none
|
152
|
+
# The {Cogfile} will be looked for in the present working directory. If none
|
74
153
|
# is found there the parent directory will be checked, and then the
|
75
154
|
# grandparent, and so on.
|
76
155
|
#
|
77
|
-
# @return [Config] the singleton
|
156
|
+
# @return [Config] the singleton instance
|
78
157
|
def self.instance
|
79
158
|
return @instance if @instance
|
80
|
-
@instance = self.new
|
81
159
|
|
82
160
|
# Attempt to find a Cogfile
|
83
161
|
parts = Dir.pwd.split File::SEPARATOR
|
@@ -86,23 +164,23 @@ module Cog
|
|
86
164
|
i -= 1
|
87
165
|
end
|
88
166
|
path = File.join(parts.slice(0, i) + ['Cogfile']) if i >= 0
|
167
|
+
|
89
168
|
if path && File.exists?(path)
|
90
|
-
@instance.
|
91
|
-
|
92
|
-
|
93
|
-
cogfile = Cogfile.new self
|
94
|
-
cogfile.interpret
|
95
|
-
end
|
169
|
+
@instance = self.new path
|
170
|
+
else
|
171
|
+
@instance = self.new
|
96
172
|
end
|
97
|
-
|
98
|
-
@instance
|
99
173
|
end
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
174
|
+
|
175
|
+
# Explicitly set the singleton Config instance.
|
176
|
+
#
|
177
|
+
# The singleton must not already be set.
|
178
|
+
#
|
179
|
+
# @param config [Config] the instance to set as the singleton
|
180
|
+
# @return [nil]
|
181
|
+
def self.instance=(config)
|
182
|
+
throw :ConfigInstanceAlreadySet unless @instance.nil?
|
183
|
+
@instance = config
|
106
184
|
end
|
107
185
|
|
108
186
|
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
require 'cog/errors'
|
2
|
+
require 'cog/generator'
|
3
|
+
|
4
|
+
module Cog
|
5
|
+
class Config
|
6
|
+
|
7
|
+
class Tool
|
8
|
+
|
9
|
+
# @return [String] name of the tool
|
10
|
+
attr_reader :name
|
11
|
+
|
12
|
+
# @return [String] explicit path to the tool
|
13
|
+
attr_reader :path
|
14
|
+
|
15
|
+
# @return [String] directory in which to find tool templates
|
16
|
+
attr_reader :templates_path
|
17
|
+
|
18
|
+
# @return [Boolean] the tool needs to be explicitly required
|
19
|
+
attr_reader :explicit_require
|
20
|
+
|
21
|
+
# @param path [String] path to the <tt>cog_tool.rb</tt> file
|
22
|
+
# @option opt [Boolean] :built_in (false) if +true+, {#templates_path} will be +nil+ for this tool, as the templates should be included with +cog+
|
23
|
+
# @option opt [Boolean] :explicit_require (false) the tool needs to be explicitly required
|
24
|
+
def initialize(path, opt={})
|
25
|
+
unless File.basename(path) == 'cog_tool.rb' && File.exists?(path)
|
26
|
+
raise Errors::InvalidToolConfiguration.new(path)
|
27
|
+
end
|
28
|
+
dir = File.dirname(path)
|
29
|
+
@name = File.basename dir
|
30
|
+
@path = File.expand_path File.join(dir, '..', "#{@name}.rb")
|
31
|
+
@explicit_require = opt[:explicit_require]
|
32
|
+
unless opt[:built_in]
|
33
|
+
@templates_path = File.expand_path File.join(dir, '..', '..', 'cog', 'templates')
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# Fully load the tool
|
38
|
+
def load
|
39
|
+
require @path
|
40
|
+
end
|
41
|
+
|
42
|
+
# Encapsulates the block which stamps the generator for this tool
|
43
|
+
class GeneratorStamper
|
44
|
+
|
45
|
+
include Generator
|
46
|
+
|
47
|
+
# @return [Config] singleton instance
|
48
|
+
attr_accessor :config
|
49
|
+
|
50
|
+
# @return [String] path to the generator file which should be created
|
51
|
+
attr_reader :generator_dest
|
52
|
+
|
53
|
+
# @return [String] +underscore_version+ of the generator name
|
54
|
+
attr_reader :name
|
55
|
+
|
56
|
+
# @return [Tool] the tool for which this stamps generators
|
57
|
+
attr_reader :tool
|
58
|
+
|
59
|
+
# @return [String] +CamelizedVersion+ of the generator name
|
60
|
+
def camelized
|
61
|
+
@name.camelize
|
62
|
+
end
|
63
|
+
|
64
|
+
# @api developer
|
65
|
+
# @param tool [Tool]
|
66
|
+
# @param block [Block]
|
67
|
+
def initialize(tool, block)
|
68
|
+
@tool = tool
|
69
|
+
@block = block
|
70
|
+
end
|
71
|
+
|
72
|
+
# Stamp the generator
|
73
|
+
# @api developer
|
74
|
+
def stamp_generator(name, generator_dest, config)
|
75
|
+
@name = name.to_s.underscore
|
76
|
+
@config = config
|
77
|
+
@generator_dest = generator_dest
|
78
|
+
instance_eval &@block
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
# @api developer
|
83
|
+
# @return [GeneratorStamper]
|
84
|
+
attr_reader :generator_stamper
|
85
|
+
|
86
|
+
# Define a block to call when stamping a generator for this tool
|
87
|
+
#
|
88
|
+
# @yield The block should do the work of stamping the generator file, and any custom templates. The block's +self+ object will be a {GeneratorStamper}
|
89
|
+
def stamp_generator(&block)
|
90
|
+
@generator_stamper = GeneratorStamper.new self, block
|
91
|
+
end
|
92
|
+
|
93
|
+
# Sort tools by name
|
94
|
+
def <=>(other)
|
95
|
+
@name <=> other.name
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|