cog 0.2.1 → 0.2.2

Sign up to get free protection for your applications and to get access to all the features.
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