cog 0.2.1 → 0.2.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.
Files changed (56) hide show
  1. data/bin/cog +6 -6
  2. data/lib/cog.rb +7 -11
  3. data/lib/cog/built_in_tools/basic.rb +1 -1
  4. data/lib/cog/built_in_tools/basic/cog_tool.rb +5 -12
  5. data/lib/cog/config.rb +47 -200
  6. data/lib/cog/config/cogfile.rb +5 -7
  7. data/lib/cog/config/lang_info.rb +1 -1
  8. data/lib/cog/config/language_methods.rb +71 -0
  9. data/lib/cog/config/project_methods.rb +35 -0
  10. data/lib/cog/config/tool_methods.rb +94 -0
  11. data/lib/cog/controllers/generator_controller.rb +7 -8
  12. data/lib/cog/controllers/template_controller.rb +18 -21
  13. data/lib/cog/controllers/tool_controller.rb +19 -22
  14. data/lib/cog/embed_context.rb +131 -0
  15. data/lib/cog/embeds.rb +84 -58
  16. data/lib/cog/embeds/file_scanner.rb +28 -5
  17. data/lib/cog/errors.rb +3 -0
  18. data/lib/cog/generator.rb +65 -31
  19. data/lib/cog/generator/file_methods.rb +1 -1
  20. data/lib/cog/generator/filters.rb +1 -1
  21. data/lib/cog/generator/language_methods.rb +3 -3
  22. data/lib/cog/helpers/string.rb +3 -3
  23. data/lib/cog/languages.rb +2 -0
  24. data/lib/cog/languages/c_language.rb +3 -27
  25. data/lib/cog/languages/c_plus_plus_language.rb +3 -8
  26. data/lib/cog/languages/c_sharp_language.rb +3 -16
  27. data/lib/cog/languages/java_language.rb +3 -16
  28. data/lib/cog/languages/java_script_language.rb +3 -16
  29. data/lib/cog/languages/language.rb +12 -12
  30. data/lib/cog/languages/mixins.rb +10 -0
  31. data/lib/cog/languages/mixins/c_style_comments.rb +23 -0
  32. data/lib/cog/languages/mixins/hash_comments.rb +19 -0
  33. data/lib/cog/languages/python_language.rb +2 -33
  34. data/lib/cog/languages/qt_project_language.rb +3 -34
  35. data/lib/cog/languages/ruby_language.rb +6 -31
  36. data/lib/cog/spec_helpers/matchers/match_maker.rb +10 -6
  37. data/lib/cog/tool.rb +61 -0
  38. data/lib/cog/tool/dsl.rb +26 -0
  39. data/lib/cog/version.rb +1 -1
  40. data/templates/basic/generator.rb.erb +1 -7
  41. data/templates/cog/custom_tool/cog_tool.rb.erb +10 -8
  42. data/templates/cog/custom_tool/generator.rb.erb.erb +3 -3
  43. data/templates/cog/custom_tool/tool.rb.erb +1 -1
  44. metadata +13 -16
  45. data/lib/cog/config/tool.rb +0 -99
  46. data/lib/cog/embeds/context.rb +0 -86
  47. data/templates/basic/template.c.erb.erb +0 -1
  48. data/templates/basic/template.cpp.erb.erb +0 -6
  49. data/templates/basic/template.cs.erb.erb +0 -6
  50. data/templates/basic/template.h.erb.erb +0 -1
  51. data/templates/basic/template.hpp.erb.erb +0 -6
  52. data/templates/basic/template.java.erb.erb +0 -1
  53. data/templates/basic/template.js.erb.erb +0 -1
  54. data/templates/basic/template.py.erb.erb +0 -1
  55. data/templates/basic/template.rb.erb.erb +0 -6
  56. data/templates/basic/template.txt.erb.erb +0 -1
data/bin/cog CHANGED
@@ -60,7 +60,7 @@ command [:generator, :gen] do |c|
60
60
  args.each do |name|
61
61
  if opt[:language] && opt[:language] != 'in Cogfile'
62
62
  lang = Cog::Languages.get_language opt[:language]
63
- Cog::Config.instance.target_language = lang
63
+ Cog.target_language = lang
64
64
  end
65
65
  Cog::Controllers::GeneratorController.create name
66
66
  end
@@ -72,7 +72,7 @@ command [:generator, :gen] do |c|
72
72
  c.arg_name 'name'
73
73
  c.command :run do |sub|
74
74
  sub.action do |gopt, opt, args|
75
- raise Cog::Errors::ActionRequiresProject.new('run generator') unless Cog::Config.instance.project?
75
+ raise Cog::Errors::ActionRequiresProject.new('run generator') unless Cog.project?
76
76
  Cog::Embeds.gather_from_project
77
77
  args = Cog::Controllers::GeneratorController.list if args.empty?
78
78
  args.each do |name|
@@ -145,7 +145,7 @@ command [:language, :lang] do |c|
145
145
  c.desc 'List the supported languages'
146
146
  c.command :list do |sub|
147
147
  sub.action do
148
- summary = Cog::Config.instance.language_summary
148
+ summary = Cog.language_summary
149
149
  w = summary.collect {|info| info.name.length}.max
150
150
  summary.each do |info|
151
151
  puts info.to_s(w)
@@ -161,10 +161,10 @@ pre do |gopt, command, opt, args|
161
161
  STDERR.write "No such Cogfile at #{gopt[:cogfile]}\n"
162
162
  false
163
163
  else
164
- Cog::Config.instance = Cog::Config.new gopt[:cogfile] if gopt[:cogfile]
164
+ Cog.prepare :cogfile_path => gopt[:cogfile]
165
165
  unless command.name == :init
166
- Cog::Config.instance.register_tools
167
- Cog::Config.instance.activate_tool gopt[:tool]
166
+ Cog.register_tools
167
+ Cog.activate_tool gopt[:tool]
168
168
  end
169
169
  true
170
170
  end
data/lib/cog.rb CHANGED
@@ -5,24 +5,20 @@ require 'cog/errors'
5
5
  require 'cog/generator'
6
6
  require 'cog/helpers'
7
7
  require 'cog/languages'
8
+ require 'cog/tool'
8
9
  require 'cog/version'
9
10
 
10
- # +cog+ is a command line utility that makes it a bit easier to organize a project
11
- # which uses code generation. These are the API docs, but you might want to read
12
- # the {https://github.com/ktonon/cog#readme general introduction} first.
11
+ # This top level module serves as a singleton instance of the {Config} interface.
13
12
  module Cog
14
13
 
14
+ extend Config
15
+
15
16
  # Prepare the project in the present working directory for use with +cog+
16
17
  # @return [nil]
17
18
  def self.initialize_project
18
- Object.new.instance_eval do
19
- class << self ; include Generator ; end
20
- copy_file_if_missing File.join(Config.gem_dir, 'Default.cogfile'), 'Cogfile'
21
- config = Config.instance
22
- touch_directory config.project_generators_path
23
- touch_directory config.project_templates_path
24
- nil
25
- end
19
+ Generator.copy_file_if_missing File.join(Cog.gem_dir, 'Default.cogfile'), 'Cogfile'
20
+ Cog.prepare :force_reset => true
21
+ nil
26
22
  end
27
23
 
28
24
  end
@@ -2,7 +2,7 @@ module Cog
2
2
  module BuiltInTools
3
3
 
4
4
  # The default +cog+ tool.
5
- # Creates generator/template pairs.
5
+ # Creates an example generator.
6
6
  module Basic
7
7
  end
8
8
 
@@ -1,18 +1,11 @@
1
1
  require 'cog'
2
+ include Cog::Generator
2
3
 
3
- # Register basic as a tool with cog
4
- Cog::Config.instance.register_tool __FILE__, :built_in => true do |tool|
4
+ Cog.register_tool __FILE__, :built_in => true do |tool|
5
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
- @language = Cog::Config.instance.target_language
11
- stamp 'basic/generator.rb', generator_dest, :absolute_destination => true
12
- @language.module_extensions.each do |ext|
13
- template_dest = File.join config.project_templates_path, "#{name}.#{ext}.erb"
14
- stamp "basic/template.#{ext}.erb", template_dest, :absolute_destination => true
15
- end
6
+ tool.stamp_generator do |name, dest|
7
+ @name = name
8
+ stamp 'basic/generator.rb', dest, :absolute_destination => true
16
9
  end
17
10
 
18
11
  end
@@ -1,173 +1,27 @@
1
1
  require 'cog/config/cogfile'
2
- require 'cog/config/tool'
3
- require 'cog/config/lang_info'
2
+ require 'cog/config/language_methods'
3
+ require 'cog/config/project_methods'
4
+ require 'cog/config/tool_methods'
4
5
  require 'cog/languages'
5
6
  require 'cog/errors'
7
+ require 'cog/tool'
6
8
 
7
9
  module Cog
8
10
 
9
- # This is a low level interface. It is mainly used by the {Generator} methods
10
- # to determine where to find things, and where to put them. When +cog+ is used
11
- # in a project the values of the singleton {Config.instance} should be configured using
12
- # a {Cogfile}.
13
- class Config
14
-
15
- # @return [String] path to the project's {Cogfile}
16
- attr_reader :cogfile_path
11
+ # This is a low level interface. It is mainly used by the {Generator} methods to determine where to find things, and where to put them.
12
+ # When +cog+ is used in a project it will be configured with a {Cogfile}. The Cogfile is processed during a call to {#prepare}.
13
+ module Config
14
+ include ProjectMethods
15
+ include LanguageMethods
16
+ include ToolMethods
17
17
 
18
- # @return [String] directory in which to find project generators
19
- attr_reader :project_generators_path
20
-
21
- # @return [String] directory in which the project's {Cogfile} is found
22
- attr_reader :project_root
23
-
24
- # @return [String] directory to which project source code is generated
25
- attr_reader :project_source_path
26
-
27
- # @return [String] directory in which to find custom project templates
28
- attr_reader :project_templates_path
29
-
30
- # @return [Languages::Lanugage] target language which should be used when creating generators, and no language is explicitly specified
31
- attr_accessor :target_language
32
-
33
- # @return [Languages::Language] language which is active in the current context
34
- def active_language
35
- @active_languages.last
36
- end
37
-
38
- # @return [Tool] the active tool affects the creation of new generators
39
- def active_tool
40
- @active_tools.last
41
- end
42
-
43
- # @return [Boolean] whether or not we operating in the context of a project
44
- def project?
45
- !@project_root.nil?
46
- end
47
-
48
- # A list of directories in which to find ERB template files
49
- #
50
- # Templates should be looked for in the following order as determined by the list returned from this method
51
- #
52
- # * {#project_templates_path} which is present if {#project?}
53
- # * {Tool#templates_path} for each registered tool (in no particular order)
54
- # * {Config.cog_templates_path} which is *always* present
55
- #
56
- # @return [Array<String>] a list of directories order with ascending priority
57
- def template_paths
58
- [@project_templates_path, active_tool && active_tool.templates_path, Config.cog_templates_path].compact
59
- end
60
-
61
- # @return [Array<Tool>] a sorted list of available tools
62
- def tools
63
- @tools.values.sort
64
- end
65
-
66
- # Register built-in and custom tools.
67
- # @api developer
68
- #
69
- # Custom tools are specified in the +COG_TOOLS+ environment variable.
70
- # @return [nil]
71
- def register_tools
72
- # Register built-in tools
73
- [:basic].each do |built_in|
74
- require File.join(Config.gem_dir, 'lib', 'cog', 'built_in_tools', built_in.to_s, 'cog_tool.rb')
75
- end
76
- # Register custom tools defined in COG_TOOLS
77
- (ENV['COG_TOOLS'] || '').split(':').each do |path|
78
- explicit = path.end_with? '.rb'
79
- @next_tool_was_required_explicitly = explicit
80
- path = "#{path}/cog_tool" unless explicit
81
- begin
82
- require path
83
- rescue LoadError
84
- raise Errors::CouldNotLoadTool.new path
85
- end
86
- end
87
- nil
18
+ # @return [String] Location of the built-in templates
19
+ def cog_templates_path
20
+ File.join Cog.gem_dir, 'templates'
88
21
  end
89
22
 
90
- # Define a new +cog+ tool
91
- # @api developer
92
- # @param path [String] path to the <tt>cog_tool.rb</tt> file
93
- # @option opt [Boolean] :built_in (false) if +true+, then treat this tool as a built-in tool
94
- # @yield [Tool] define the tool
95
- # @return [nil]
96
- def register_tool(path, opt={}, &block)
97
- tool = Tool.new path, :built_in => opt[:built_in], :explicit_require => @next_tool_was_required_explicitly
98
- block.call tool
99
- @tools[tool.name] = tool
100
- nil
101
- end
102
-
103
- # @api developer
104
- # @return [Boolean] whether or not a tool is registered with the given name
105
- def tool_registered?(name)
106
- @tools.member? name
107
- end
108
-
109
- # Activate the registered tool with the given name with the scope of the provided block.
110
- # If no block is provided, the tool will remain active indefinitely.
111
- # @param name [String] name of the registered tool to activate
112
- # @yield the tool will be active within this block
113
- # @return [nil]
114
- def activate_tool(name, &block)
115
- name = name.to_s
116
- raise Errors::NoSuchTool.new(name) unless tool_registered?(name)
117
- @tools[name].load
118
- @active_tools << @tools[name]
119
- if block
120
- block.call
121
- @active_tools.pop
122
- end
123
- end
124
-
125
- # Activate a given language within the scope of the provided block.
126
- # Either provide <tt>:id</tt> or <tt>:ext</tt> but not both. If the extension does not match any of the supported languages, the {#active_language} will not change, but the block will still be called.
127
- # @option opt [:String] :id (nil) the lanuage identifier. Type <tt>cog language list</tt> to see the possible values
128
- # @option opt [:String] :ext (nil) a file extension which will map to a language identifier. Type <tt>cog language map</tt> to see mapped extensions
129
- # @yield within this block the {#active_language} will be set to the desired value
130
- # @return [Object] the value returned by the block
131
- def activate_language(opt={}, &block)
132
- lang_id = if opt[:ext]
133
- ext = opt[:ext].to_s
134
- ext = ext.slice(1..-1) if ext.start_with?('.')
135
- @language_extension_map[ext.downcase.to_sym] unless ext.empty?
136
- else
137
- opt[:id]
138
- end
139
- if lang_id
140
- @active_languages << Languages.get_language(lang_id)
141
- r = block.call
142
- @active_languages.pop
143
- r
144
- else
145
- block.call
146
- end
147
- end
148
-
149
- # @param ext [String] the file extension
150
- # @return [Languages::Language, nil] the language for the given extension
151
- def language_for_extension(ext)
152
- ext = ext.to_s.downcase.to_sym
153
- lang_id = @language_extension_map[ext]
154
- Languages.get_language lang_id unless lang_id.nil?
155
- end
156
-
157
- # @return [Array<LangInfo>] current configuration of supported languages
158
- def language_summary
159
- summary = {}
160
- @language_extension_map.each_pair do |ext, lang_id|
161
- lang_id = Languages::ALIAS[lang_id] || lang_id
162
- summary[lang_id] ||= LangInfo.new(lang_id, Languages::REV_ALIAS[lang_id] || [])
163
- summary[lang_id].extensions << ext
164
- end
165
- summary.values.sort
166
- end
167
-
168
- # Location of the installed cog gem
169
- # @return [String] path to the cog gem
170
- def self.gem_dir
23
+ # @return [String] Location of the installed cog gem
24
+ def gem_dir
171
25
  spec = Gem.loaded_specs['cog']
172
26
  if spec.nil?
173
27
  # The current __FILE__ is:
@@ -178,67 +32,60 @@ module Cog
178
32
  end
179
33
  end
180
34
 
181
- # Location of the built-in templates
182
- def self.cog_templates_path
183
- File.join Config.gem_dir, 'templates'
184
- end
185
-
186
- # @param cogfile_path [String] if provided the {Cogfile} at the given path
187
- # is used to initialize this instance, and {#project?} will be +true+
188
- def initialize(cogfile_path = nil)
35
+ # A list of directories in which to find ERB template files
36
+ #
37
+ # Templates should be looked for in the following order as determined by the list returned from this method
38
+ #
39
+ # * {#project_templates_path} which is present if {#project?}
40
+ # * {Tool#templates_path} for each registered tool (in no particular order)
41
+ # * {#cog_templates_path} which is *always* present
42
+ #
43
+ # @return [Array<String>] a list of directories order with ascending priority
44
+ def template_paths
45
+ [@project_templates_path, active_tool && active_tool.templates_path, Cog.cog_templates_path].compact
46
+ end
47
+
48
+ # Must be called once before using cog.
49
+ # In the context of a command-line invocation, this method will be called automatically. Outside of that context, for example in a unit test, it will have to be called manually.
50
+ # @option opt [String] :cogfile_path (nil) explicitly specify the location of the project {Cogfile}. If not provided, it will be searched for. If none can be found, {#project?} will be +false+
51
+ # @option opt [Boolean] :force_reset (false) unless this is +true+, calling prepare a second time will fail
52
+ def prepare(opt={})
53
+ throw :ConfigInstanceAlreadyPrepared if @prepared && !opt[:force_reset]
54
+ @prepared = true
55
+ @cogfile_path = nil
189
56
  @project_root = nil
57
+ @project_generators_path = nil
58
+ @project_templates_path = nil
59
+ @project_source_path = nil
190
60
  @tools = {}
191
61
  @active_tools = [] # active tool stack
192
62
  @target_language = Languages::Language.new
193
63
  @active_languages = [Languages::Language.new] # active language stack
194
64
  @language_extension_map = Languages::DEFAULT_LANGUAGE_EXTENSION_MAP
195
- if cogfile_path
196
- @cogfile_path = File.expand_path cogfile_path
65
+ opt[:cogfile_path] ||= find_default_cogfile
66
+ if opt[:cogfile_path]
67
+ @cogfile_path = File.expand_path opt[:cogfile_path]
197
68
  @project_root = File.dirname @cogfile_path
198
69
  cogfile = Cogfile.new self
199
70
  cogfile.interpret
200
71
  end
201
72
  end
202
-
203
- # Find or create the singleton {Config} instance.
204
- #
205
- # Initialized using the {Cogfile} for the current project, if any can be
206
- # found. If not, {#project?} will be +false+ and all the <tt>project_...</tt>
207
- # methods will return +nil+.
208
- #
73
+
74
+ private
75
+
209
76
  # The {Cogfile} will be looked for in the present working directory. If none
210
77
  # is found there the parent directory will be checked, and then the
211
78
  # grandparent, and so on.
212
79
  #
213
80
  # @return [Config] the singleton instance
214
- def self.instance
215
- return @instance if @instance
216
-
217
- # Attempt to find a Cogfile
81
+ def find_default_cogfile
218
82
  parts = Dir.pwd.split File::SEPARATOR
219
83
  i = parts.length
220
84
  while i >= 0 && !File.exists?(File.join(parts.slice(0, i) + ['Cogfile']))
221
85
  i -= 1
222
86
  end
223
87
  path = File.join(parts.slice(0, i) + ['Cogfile']) if i >= 0
224
-
225
- if path && File.exists?(path)
226
- @instance = self.new path
227
- else
228
- @instance = self.new
229
- end
230
- end
231
-
232
- # Explicitly set the singleton Config instance.
233
- #
234
- # The singleton must not already be set.
235
- #
236
- # @param config [Config] the instance to set as the singleton
237
- # @return [nil]
238
- def self.instance=(config)
239
- throw :ConfigInstanceAlreadySet unless @instance.nil?
240
- @instance = config
88
+ (path && File.exists?(path)) ? path : nil
241
89
  end
242
-
243
90
  end
244
91
  end
@@ -2,12 +2,10 @@ require 'active_support/core_ext'
2
2
  require 'cog/languages'
3
3
 
4
4
  module Cog
5
- class Config
5
+ module Config
6
6
 
7
7
  # In your project's +Cogfile+, +self+ has been set to an instance of this class.
8
- #
9
8
  # Typing <tt>cog init</tt> will create a +Cogfile+ in the present working directory.
10
- # +Cogfile+ files are used to configure an instance of {Config}.
11
9
  #
12
10
  # @example
13
11
  # # All paths are relative to the directory containing this file.
@@ -45,7 +43,7 @@ module Cog
45
43
  @config = config
46
44
  end
47
45
 
48
- # Interpret the +Cogfile+ at {Config#cogfile_path}
46
+ # Interpret the +Cogfile+ at {Config::ProjectMethods#cogfile_path}
49
47
  # @api developer
50
48
  # @return [nil]
51
49
  def interpret
@@ -57,7 +55,7 @@ module Cog
57
55
 
58
56
  # Define the directory in which to find project generators
59
57
  # @param path [String] a file system path
60
- # @param absolute [Boolean] if +false+, the path is relative to {Config#project_root}
58
+ # @param absolute [Boolean] if +false+, the path is relative to {Config::ProjectMethods#project_root}
61
59
  # @return [nil]
62
60
  def project_generators_path(path, absolute=false)
63
61
  @config.instance_eval do
@@ -68,7 +66,7 @@ module Cog
68
66
 
69
67
  # Define the directory in which to find custom project templates
70
68
  # @param path [String] a file system path
71
- # @param absolute [Boolean] if +false+, the path is relative to {Config#project_root}
69
+ # @param absolute [Boolean] if +false+, the path is relative to {Config::ProjectMethods#project_root}
72
70
  # @return [nil]
73
71
  def project_templates_path(path, absolute=false)
74
72
  @config.instance_eval do
@@ -79,7 +77,7 @@ module Cog
79
77
 
80
78
  # Define the directory to which project source code is generated
81
79
  # @param path [String] a file system path
82
- # @param absolute [Boolean] if +false+, the path is relative to {Config#project_root}
80
+ # @param absolute [Boolean] if +false+, the path is relative to {Config::ProjectMethods#project_root}
83
81
  # @return [nil]
84
82
  def project_source_path(path, absolute=false)
85
83
  @config.instance_eval do
@@ -1,5 +1,5 @@
1
1
  module Cog
2
- class Config
2
+ module Config
3
3
 
4
4
  # Describes configuration of a supported language
5
5
  class LangInfo