cog 0.1.2 → 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. data/Default.cogfile +14 -2
  2. data/bin/cog +30 -3
  3. data/lib/cog.rb +4 -3
  4. data/lib/cog/built_in_tools/basic/cog_tool.rb +5 -2
  5. data/lib/cog/config.rb +63 -14
  6. data/lib/cog/config/cogfile.rb +26 -5
  7. data/lib/cog/config/lang_info.rb +40 -0
  8. data/lib/cog/controllers/template_controller.rb +4 -5
  9. data/lib/cog/errors.rb +8 -0
  10. data/lib/cog/generator.rb +33 -111
  11. data/lib/cog/generator/file_methods.rb +77 -0
  12. data/lib/cog/generator/filters.rb +30 -0
  13. data/lib/cog/generator/language_methods.rb +60 -0
  14. data/lib/cog/generator/language_methods/scope.rb +24 -0
  15. data/lib/cog/languages.rb +50 -0
  16. data/lib/cog/languages/c_language.rb +17 -0
  17. data/lib/cog/languages/c_plus_plus_language.rb +30 -0
  18. data/lib/cog/languages/c_sharp_language.rb +13 -0
  19. data/lib/cog/languages/java_language.rb +13 -0
  20. data/lib/cog/languages/java_script_language.rb +13 -0
  21. data/lib/cog/languages/language.rb +45 -0
  22. data/lib/cog/languages/p_h_p_language.rb +13 -0
  23. data/lib/cog/languages/python_language.rb +17 -0
  24. data/lib/cog/languages/ruby_language.rb +17 -0
  25. data/lib/cog/version.rb +1 -1
  26. data/templates/basic/generator.rb.erb +4 -2
  27. data/templates/basic/template.c.erb.erb +1 -0
  28. data/templates/basic/template.cpp.erb.erb +6 -0
  29. data/templates/basic/template.cs.erb.erb +6 -0
  30. data/templates/basic/template.h.erb.erb +1 -0
  31. data/templates/basic/template.hpp.erb.erb +6 -0
  32. data/templates/basic/template.java.erb.erb +1 -0
  33. data/templates/basic/template.js.erb.erb +1 -0
  34. data/templates/basic/template.php.erb.erb +1 -0
  35. data/templates/basic/template.py.erb.erb +1 -0
  36. data/templates/basic/template.rb.erb.erb +6 -0
  37. data/templates/basic/template.txt.erb.erb +1 -1
  38. data/templates/cog/custom_tool/tool.rb.erb +7 -1
  39. data/templates/warning.erb +11 -0
  40. metadata +30 -5
  41. data/templates/warning.h.erb +0 -9
@@ -9,5 +9,17 @@ project_templates_path 'cog/templates'
9
9
  # Define the directory to which project source code is generated
10
10
  project_source_path 'src'
11
11
 
12
- # Define the default language in which to generated application source code
13
- language 'c++'
12
+ # Explicitly specify a mapping from file extensions to languages
13
+ #
14
+ # key => value pairs from this mapping will override the default
15
+ # language map supplied by +cog+
16
+ #
17
+ # Type `cog language list` to see a list of supported languages
18
+ # and the current file extension mappings
19
+ language_extensions({
20
+ # :h => 'c++',
21
+ })
22
+
23
+ # Define the target language which should be used when
24
+ # creating generators, and no language is explicitly specified
25
+ default_target_language 'c++'
data/bin/cog CHANGED
@@ -10,10 +10,11 @@ include GLI::App
10
10
 
11
11
  program_desc 'This is a utility to help you write code generators.'
12
12
 
13
- # version Cog::VERSION
13
+ desc 'Current version of cog'
14
+ version Cog::VERSION
14
15
 
15
16
  desc 'Output more detailed information when running a command'
16
- switch [:verbose, :v]
17
+ switch [:verbose]
17
18
 
18
19
  desc 'Set the Cogfile explicitly'
19
20
  arg_name 'path'
@@ -22,7 +23,7 @@ flag :cogfile
22
23
  desc 'Set the active tool'
23
24
  arg_name 'name'
24
25
  default_value 'basic'
25
- flag :tool
26
+ flag [:tool, :t]
26
27
 
27
28
  desc 'Suppress the use of color in output'
28
29
  switch :colorless
@@ -51,8 +52,16 @@ command [:generator, :gen] do |c|
51
52
  c.desc 'Create a new project generator'
52
53
  c.arg_name 'name'
53
54
  c.command :new do |sub|
55
+ sub.desc 'Specify a target language other than the default'
56
+ sub.default_value 'in Cogfile'
57
+ sub.flag [:language, :l]
58
+
54
59
  sub.action do |gopt, opt, args|
55
60
  args.each do |name|
61
+ if opt[:language] && opt[:language] != 'in Cogfile'
62
+ lang = Cog::Languages.get_language opt[:language]
63
+ Cog::Config.instance.target_language = lang
64
+ end
56
65
  Cog::Controllers::GeneratorController.create name
57
66
  end
58
67
  end
@@ -126,6 +135,24 @@ command [:template, :tm] do |c|
126
135
  end
127
136
  end
128
137
 
138
+ desc 'Review supported languages'
139
+ command [:language, :lang] do |c|
140
+
141
+ c.default_command :list
142
+
143
+ c.desc 'List the supported languages'
144
+ c.command :list do |sub|
145
+ sub.action do
146
+ summary = Cog::Config.instance.language_summary
147
+ w = summary.collect {|info| info.name.length}.max
148
+ summary.each do |info|
149
+ puts info.to_s(w)
150
+ end
151
+ end
152
+ end
153
+
154
+ end
155
+
129
156
  pre do |gopt, command, opt, args|
130
157
  Sickill::Rainbow.enabled = false if gopt[:colorless]
131
158
  if gopt[:cogfile] && !File.exists?(gopt[:cogfile])
data/lib/cog.rb CHANGED
@@ -3,6 +3,7 @@ require 'cog/controllers'
3
3
  require 'cog/errors'
4
4
  require 'cog/generator'
5
5
  require 'cog/helpers'
6
+ require 'cog/languages'
6
7
  require 'cog/version'
7
8
 
8
9
  # +cog+ is a command line utility that makes it a bit easier to organize a project
@@ -15,10 +16,10 @@ module Cog
15
16
  def self.initialize_project
16
17
  Object.new.instance_eval do
17
18
  class << self ; include Generator ; end
18
- copy_if_missing File.join(Config.gem_dir, 'Default.cogfile'), 'Cogfile'
19
+ copy_file_if_missing File.join(Config.gem_dir, 'Default.cogfile'), 'Cogfile'
19
20
  config = Config.instance
20
- touch_path config.project_generators_path
21
- touch_path config.project_templates_path
21
+ touch_directory config.project_generators_path
22
+ touch_directory config.project_templates_path
22
23
  nil
23
24
  end
24
25
  end
@@ -7,9 +7,12 @@ Cog::Config.instance.register_tool __FILE__, :built_in => true do |tool|
7
7
  #
8
8
  # When the block is executed, +self+ will be an instance of Cog::Config::Tool::GeneratorStamper
9
9
  tool.stamp_generator do
10
- template_dest = File.join config.project_templates_path, "#{name}.txt.erb"
10
+ @language = Cog::Config.instance.target_language
11
11
  stamp 'basic/generator.rb', generator_dest, :absolute_destination => true
12
- stamp 'basic/template.txt.erb', template_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
13
16
  end
14
17
 
15
18
  end
@@ -1,5 +1,7 @@
1
1
  require 'cog/config/cogfile'
2
2
  require 'cog/config/tool'
3
+ require 'cog/config/lang_info'
4
+ require 'cog/languages'
3
5
  require 'cog/errors'
4
6
 
5
7
  module Cog
@@ -13,9 +15,6 @@ module Cog
13
15
  # @return [String] path to the project's {Cogfile}
14
16
  attr_reader :cogfile_path
15
17
 
16
- # @return [String] default language in which to generated application source code
17
- attr_reader :language
18
-
19
18
  # @return [String] directory in which to find project generators
20
19
  attr_reader :project_generators_path
21
20
 
@@ -28,8 +27,18 @@ module Cog
28
27
  # @return [String] directory in which to find custom project templates
29
28
  attr_reader :project_templates_path
30
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 [String] the target language which is currently active
34
+ def active_language
35
+ @active_languages.last
36
+ end
37
+
31
38
  # @return [Tool] the active tool affects the creation of new generators
32
- attr_reader :active_tool
39
+ def active_tool
40
+ @active_tools.last
41
+ end
33
42
 
34
43
  # @return [Boolean] whether or not we operating in the context of a project
35
44
  def project?
@@ -46,10 +55,7 @@ module Cog
46
55
  #
47
56
  # @return [Array<String>] a list of directories order with ascending priority
48
57
  def template_paths
49
- paths = [@project_templates_path]
50
- paths += tools.collect {|tool| tool.templates_path}
51
- paths << Config.cog_templates_path
52
- paths.compact
58
+ [@project_templates_path, active_tool && active_tool.templates_path, Config.cog_templates_path].compact
53
59
  end
54
60
 
55
61
  # @return [Array<Tool>] a sorted list of available tools
@@ -100,15 +106,55 @@ module Cog
100
106
  @tools.member? name
101
107
  end
102
108
 
103
- # Activate the registered tool with the given name
104
- # @api developer
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.
105
111
  # @param name [String] name of the registered tool to activate
112
+ # @yield the tool will be active within this block
106
113
  # @return [nil]
107
- def activate_tool(name)
108
- throw :ToolAlreadyActivated unless @active_tool.nil?
114
+ def activate_tool(name, &block)
115
+ name = name.to_s
109
116
  raise Errors::NoSuchTool.new(name) unless tool_registered?(name)
110
117
  @tools[name].load
111
- @active_tool = @tools[name]
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
+ # @return [Array<LangInfo>] current configuration of supported languages
150
+ def language_summary
151
+ summary = {}
152
+ @language_extension_map.each_pair do |ext, lang_id|
153
+ lang_id = Languages::ALIAS[lang_id] || lang_id
154
+ summary[lang_id] ||= LangInfo.new(lang_id, Languages::REV_ALIAS[lang_id] || [])
155
+ summary[lang_id].extensions << ext
156
+ end
157
+ summary.values.sort
112
158
  end
113
159
 
114
160
  # Location of the installed cog gem
@@ -134,7 +180,10 @@ module Cog
134
180
  def initialize(cogfile_path = nil)
135
181
  @project_root = nil
136
182
  @tools = {}
137
- @language = 'c++'
183
+ @active_tools = [] # active tool stack
184
+ @target_language = Languages::Language.new
185
+ @active_languages = [Languages::Language.new] # active language stack
186
+ @language_extension_map = Languages::DEFAULT_LANGUAGE_EXTENSION_MAP
138
187
  if cogfile_path
139
188
  @cogfile_path = File.expand_path cogfile_path
140
189
  @project_root = File.dirname @cogfile_path
@@ -1,3 +1,6 @@
1
+ require 'active_support/core_ext'
2
+ require 'cog/languages'
3
+
1
4
  module Cog
2
5
  class Config
3
6
 
@@ -23,8 +26,10 @@ module Cog
23
26
 
24
27
  # Interpret the +Cogfile+ at {Config#cogfile_path}
25
28
  # @api developer
29
+ # @return [nil]
26
30
  def interpret
27
31
  eval File.read(@config.cogfile_path), binding
32
+ nil
28
33
  rescue Exception => e
29
34
  raise CogfileError.new(e.to_s)
30
35
  end
@@ -32,41 +37,57 @@ module Cog
32
37
  # Define the directory in which to find project generators
33
38
  # @param path [String] a file system path
34
39
  # @param absolute [Boolean] if +false+, the path is relative to {Config#project_root}
40
+ # @return [nil]
35
41
  def project_generators_path(path, absolute=false)
36
42
  @config.instance_eval do
37
43
  @project_generators_path = absolute ? path : File.join(project_root, path)
38
44
  end
45
+ nil
39
46
  end
40
47
 
41
48
  # Define the directory in which to find custom project templates
42
49
  # @param path [String] a file system path
43
50
  # @param absolute [Boolean] if +false+, the path is relative to {Config#project_root}
51
+ # @return [nil]
44
52
  def project_templates_path(path, absolute=false)
45
53
  @config.instance_eval do
46
54
  @project_templates_path = absolute ? path : File.join(project_root, path)
47
55
  end
56
+ nil
48
57
  end
49
58
 
50
59
  # Define the directory to which project source code is generated
51
60
  # @param path [String] a file system path
52
61
  # @param absolute [Boolean] if +false+, the path is relative to {Config#project_root}
62
+ # @return [nil]
53
63
  def project_source_path(path, absolute=false)
54
64
  @config.instance_eval do
55
65
  @project_source_path = absolute ? path : File.join(project_root, path)
56
66
  end
67
+ nil
57
68
  end
58
69
 
59
- # Define the default language in which to generated application source code
60
- # @param lang [String] a code for the language. Acceptable values are <tt>c++</tt>
61
- def language(lang)
70
+ # Explicitly specify a mapping from file extensions to languages
71
+ # @param map [Hash] key-value pairs from this mapping will override the default language map supplied by +cog+
72
+ # @return [nil]
73
+ def language_extensions(map)
74
+ @config.instance_eval do
75
+ @language_extension_map.update map
76
+ end
77
+ nil
78
+ end
79
+
80
+ # Define the target language which should be used when
81
+ # creating generators, and no language is explicitly specified
82
+ # @param lang_id [String] a language identifier
83
+ def default_target_language(lang_id)
62
84
  @config.instance_eval do
63
- @language = lang
85
+ @target_language = Cog::Languages.get_language(lang_id)
64
86
  end
65
87
  end
66
88
  end
67
89
 
68
90
  # For wrapping errors which occur during the processing of a {Cogfile}
69
- # @api client
70
91
  class CogfileError < StandardError
71
92
  def message
72
93
  "in Cogfile, " + super
@@ -0,0 +1,40 @@
1
+ module Cog
2
+ class Config
3
+
4
+ # Describes configuration of a supported language
5
+ class LangInfo
6
+ # @return [String] a language identifier
7
+ attr_reader :lang_id
8
+
9
+ # @return [Array<String>] a list of aliases
10
+ attr_reader :aliases
11
+
12
+ # @return [Array<Symbol>] a list of extension which currently map to this language
13
+ attr_reader :extensions
14
+
15
+ # @return [String] readable name of the language
16
+ attr_reader :name
17
+
18
+ # @api developer
19
+ def initialize(lang_id, aliases)
20
+ @lang_id = lang_id
21
+ @aliases = aliases.dup
22
+ @name = @aliases.empty? ? @lang_id : @aliases.join(', ')
23
+ @extensions = []
24
+ end
25
+
26
+ # @param w [FixNum] width of the first column
27
+ # @return [String] one line summary in two columns
28
+ def to_s(w=nil)
29
+ w ||= name.length
30
+ "#{name.ljust w} -> #{@extensions.collect {|x| x.to_s}.sort.join ', '}"
31
+ end
32
+
33
+ # Sort by name
34
+ def <=>(other)
35
+ name <=> other.name
36
+ end
37
+ end
38
+
39
+ end
40
+ end
@@ -16,10 +16,9 @@ module Cog
16
16
  def self.list(opt={})
17
17
  cts = Helpers::CascadingTemplateSet.new
18
18
  cts.add_templates 'built-in', :built_in, Config.cog_templates_path, opt
19
- Config.instance.tools.each do |tool|
20
- unless tool.templates_path.nil?
21
- cts.add_templates tool.name, :tool, tool.templates_path, opt
22
- end
19
+ tool = Config.instance.active_tool
20
+ unless tool.templates_path.nil?
21
+ cts.add_templates tool.name, :tool, tool.templates_path, opt
23
22
  end
24
23
  if Config.instance.project?
25
24
  cts.add_templates 'project', :project, Config.instance.project_templates_path, opt
@@ -41,7 +40,7 @@ module Cog
41
40
  original = get_template name, :as_path => true
42
41
  return if original == dest # Nothing to create
43
42
  if opt[:force_override]
44
- copy_if_missing original, dest
43
+ copy_file_if_missing original, dest
45
44
  else
46
45
  raise Errors::DuplicateTemplate.new original
47
46
  end
@@ -48,7 +48,11 @@ module Cog
48
48
  "invalid directory structure for a cog tool"
49
49
  end
50
50
 
51
+ define_error :NoSuchFilter, 'filter'
52
+
51
53
  define_error :NoSuchGenerator, 'generator'
54
+
55
+ define_error :NoSuchLanguage, 'language'
52
56
 
53
57
  define_error :NoSuchTemplate, 'template'
54
58
 
@@ -56,5 +60,9 @@ module Cog
56
60
  "no such tool, make sure it appears in the COG_TOOLS environment variable"
57
61
  end
58
62
 
63
+ define_error :ScopeStackUnderflow, 'caller' do
64
+ "scope stack underflow: this can happen if you have too many *_end calls in a template"
65
+ end
66
+
59
67
  end
60
68
  end
@@ -1,5 +1,8 @@
1
1
  require 'cog/config'
2
2
  require 'cog/errors'
3
+ require 'cog/generator/file_methods'
4
+ require 'cog/generator/filters'
5
+ require 'cog/generator/language_methods'
3
6
  require 'cog/helpers'
4
7
  require 'erb'
5
8
  require 'rainbow'
@@ -13,27 +16,19 @@ module Cog
13
16
  # @see https://github.com/ktonon/cog#generators Introduction to Generators
14
17
  module Generator
15
18
 
16
- # Get the template with the given name
17
- # @param path [String] path to template file relative one of the {Config#template_paths}
18
- # @option opt [Boolean] :absolute (false) is the +path+ argument absolute?
19
- # @option opt [Boolean] :as_path (false) return the template as an ERB instance (+false+) or an absolute path to the file (+true+)
20
- # @return [ERB, String] an instance of {http://ruby-doc.org/stdlib-1.9.3/libdoc/erb/rdoc/ERB.html ERB} or an absolute path to the template
21
- def get_template(path, opt={})
22
- path += '.erb'
23
- fullpath = if opt[:absolute]
24
- path
25
- else
26
- Config.instance.template_paths.inject('') do |found, prefix|
27
- x = File.join prefix, path
28
- found.empty? && File.exists?(x) ? x : found
29
- end
30
- end
31
- raise Errors::NoSuchTemplate.new path unless File.exists? fullpath
32
- if opt[:as_path]
33
- File.expand_path fullpath
34
- else
35
- ERB.new File.read(fullpath), 0, '>'
19
+ include FileMethods
20
+ include Filters
21
+ include LanguageMethods
22
+
23
+ # @api developer
24
+ # @return [Hash] Generator context. Generator methods should place context into here instead of instance variables to avoid polluting the instance variable name space
25
+ def gcontext
26
+ if @generator_context.nil?
27
+ @generator_context = {
28
+ :scopes => []
29
+ }
36
30
  end
31
+ @generator_context
37
32
  end
38
33
 
39
34
  # Stamp a template into a file or return it as a string
@@ -41,18 +36,33 @@ module Cog
41
36
  # @param destination [String] path to which the generated file should be written, relative to the {Config#project_source_path}
42
37
  # @option opt [Boolean] :absolute_template_path (false) is the +template_path+ absolute?
43
38
  # @option opt [Boolean] :absolute_destination (false) is the +destination+ absolute?
39
+ # @option opt [String, Array<String>] :filter (nil) filter the result through the named methods
44
40
  # @option opt [Boolean] :quiet (false) suppress writing to STDOUT?
45
41
  # @return [nil or String] if +destination+ is not provided, the stamped template is returned as a string
46
42
  def stamp(template_path, destination=nil, opt={})
43
+ # Ignore destination if its a hash, its meant to be opt
44
+ opt, destination = destination, nil if destination.is_a? Hash
45
+
46
+ # Find and render the template
47
47
  t = get_template template_path, :absolute => opt[:absolute_template_path]
48
48
  b = opt[:binding] || binding
49
- return t.result(b) if destination.nil?
49
+ r = Config.instance.activate_language :ext => File.extname(template_path.to_s) do
50
+ t.result(b)
51
+ end
52
+
53
+ # Run r through filters
54
+ f = opt[:filter]
55
+ f = [f].compact unless f.is_a?(Array)
56
+ f.each {|name| r = call_filter name, r }
50
57
 
58
+ return r if destination.nil?
59
+
60
+ # Place it in a file
51
61
  dest = opt[:absolute_destination] ? destination : File.join(Config.instance.project_source_path, destination)
52
62
  FileUtils.mkpath File.dirname(dest) unless File.exists? dest
53
63
  scratch = "#{dest}.scratch"
54
- File.open(scratch, 'w') {|file| file.write t.result(b)}
55
- if same? dest, scratch
64
+ File.open(scratch, 'w') {|file| file.write r}
65
+ if files_are_same? dest, scratch
56
66
  FileUtils.rm scratch
57
67
  else
58
68
  updated = File.exists? dest
@@ -62,93 +72,5 @@ module Cog
62
72
  nil
63
73
  end
64
74
 
65
- # Copy a file from +src+ to +dest+, but only if +dest+ does not already exist.
66
- # @param src [String] where to copy from
67
- # @param dest [String] where to copy to
68
- # @option opt [Boolean] :quiet (false) suppress writing to STDOUT?
69
- # @return [nil]
70
- def copy_if_missing(src, dest, opt={})
71
- unless File.exists? dest
72
- touch_path File.dirname(dest), opt
73
- FileUtils.cp src, dest
74
- STDOUT.write "Created #{dest.relative_to_project_root}\n".color(:green) unless opt[:quiet]
75
- end
76
- end
77
-
78
- # Recursively create directories in the given path if they are missing.
79
- # @param path [String] a file system path representing a directory
80
- # @option opt [Boolean] :quiet (false) suppress writing to STDOUT?
81
- # @return [nil]
82
- def touch_path(path, opt={})
83
- unless File.exists? path
84
- FileUtils.mkdir_p path
85
- STDOUT.write "Created #{path.relative_to_project_root}\n".color(:green) unless opt[:quiet]
86
- end
87
- nil
88
- end
89
-
90
- # Create the file at the given path,
91
- # Creates directories along the path as required.
92
- # @param path [String] a file system path representing a file
93
- # @option opt [Boolean] :quiet (false) suppress writing to STDOUT?
94
- # @return [nil]
95
- def touch_file(path, opt={})
96
- touch_path File.dirname(path), opt
97
- FileUtils.touch path
98
- STDOUT.write "Created #{path.relative_to_project_root}\n".color(:green) unless opt[:quiet]
99
- nil
100
- end
101
-
102
- # File extension for a snippet of the given source code language.
103
- # @api unstable
104
- # @example
105
- # snippet_extension 'c++' # => 'h'
106
- def snippet_extension(lang = 'text') # :nodoc:
107
- case lang
108
- when /(c\+\+|c|objc)/i
109
- 'h'
110
- else
111
- 'txt'
112
- end
113
- end
114
-
115
- # @api unstable
116
- def include_guard_begin(name)
117
- full = "COG_INCLUDE_GUARD_#{name.upcase}"
118
- "#ifndef #{full}\n#define #{full}"
119
- end
120
-
121
- # @api unstable
122
- def include_guard_end
123
- "#endif // COG_INCLUDE_GUARD_[...]"
124
- end
125
-
126
- # @api unstable
127
- def namespace_begin(name)
128
- return if name.nil?
129
- case Config.instance.language
130
- when /c\+\+/
131
- "namespace #{name} {"
132
- end
133
- end
134
-
135
- # @api unstable
136
- def namespace_end(name)
137
- return if name.nil?
138
- case Config.instance.language
139
- when /c\+\+/
140
- "} // namespace #{name}"
141
- end
142
- end
143
-
144
- private
145
- def same?(original, scratch)
146
- if File.exists? original
147
- File.read(original) == File.read(scratch)
148
- else
149
- false
150
- end
151
- end
152
-
153
75
  end
154
76
  end
@@ -0,0 +1,77 @@
1
+ module Cog
2
+ module Generator
3
+
4
+ # Methods for working with files
5
+ module FileMethods
6
+
7
+ # Get the template with the given name
8
+ # @param path [String] path to template file relative one of the {Config#template_paths}
9
+ # @option opt [Boolean] :absolute (false) is the +path+ argument absolute?
10
+ # @option opt [Boolean] :as_path (false) return the template as an ERB instance (+false+) or an absolute path to the file (+true+)
11
+ # @return [ERB, String] an instance of {http://ruby-doc.org/stdlib-1.9.3/libdoc/erb/rdoc/ERB.html ERB} or an absolute path to the template
12
+ def get_template(path, opt={})
13
+ path = path.to_s
14
+ path += '.erb'
15
+ fullpath = if opt[:absolute]
16
+ path
17
+ else
18
+ Config.instance.template_paths.inject('') do |found, prefix|
19
+ x = File.join prefix, path
20
+ found.empty? && File.exists?(x) ? x : found
21
+ end
22
+ end
23
+ raise Errors::NoSuchTemplate.new path unless File.exists? fullpath
24
+ if opt[:as_path]
25
+ File.expand_path fullpath
26
+ else
27
+ ERB.new File.read(fullpath), 0, '>'
28
+ end
29
+ end
30
+
31
+ # Copy a file from +src+ to +dest+, but only if +dest+ does not already exist.
32
+ # @param src [String] where to copy from
33
+ # @param dest [String] where to copy to
34
+ # @option opt [Boolean] :quiet (false) suppress writing to STDOUT?
35
+ # @return [nil]
36
+ def copy_file_if_missing(src, dest, opt={})
37
+ unless File.exists? dest
38
+ touch_directory File.dirname(dest), opt
39
+ FileUtils.cp src, dest
40
+ STDOUT.write "Created #{dest.relative_to_project_root}\n".color(:green) unless opt[:quiet]
41
+ end
42
+ end
43
+
44
+ # Recursively create directories in the given path if they are missing.
45
+ # @param path [String] a file system path representing a directory
46
+ # @option opt [Boolean] :quiet (false) suppress writing to STDOUT?
47
+ # @return [nil]
48
+ def touch_directory(path, opt={})
49
+ unless File.exists? path
50
+ FileUtils.mkdir_p path
51
+ STDOUT.write "Created #{path.relative_to_project_root}\n".color(:green) unless opt[:quiet]
52
+ end
53
+ nil
54
+ end
55
+
56
+ # Create the file at the given path,
57
+ # Creates directories along the path as required.
58
+ # @param path [String] a file system path representing a file
59
+ # @option opt [Boolean] :quiet (false) suppress writing to STDOUT?
60
+ # @return [nil]
61
+ def touch_file(path, opt={})
62
+ touch_directory File.dirname(path), opt
63
+ FileUtils.touch path
64
+ STDOUT.write "Created #{path.relative_to_project_root}\n".color(:green) unless opt[:quiet]
65
+ nil
66
+ end
67
+
68
+ # @param file1 [File] a file
69
+ # @param file2 [File] another file
70
+ # @return [Boolean] whether or not the two files have the same content
71
+ def files_are_same?(file1, file2)
72
+ File.exists?(file1) && File.exists?(file2) && File.read(file1) == File.read(file2)
73
+ end
74
+
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,30 @@
1
+ require 'cog/errors'
2
+
3
+ module Cog
4
+ module Generator
5
+
6
+ # Filters are methods which translate text into more text
7
+ module Filters
8
+
9
+ # @param text [String] some text which should be rendered as a comment
10
+ # @return [String] a comment appropriate for the current language context
11
+ def comment(text)
12
+ Config.instance.active_language.comment text
13
+ end
14
+
15
+ # @api developer
16
+ # Adds a call_filter method which throws NoSuchFilter if
17
+ # the filter is invalid
18
+ def self.included(other)
19
+ valid_filters = Filters.instance_eval {instance_methods}
20
+ other.instance_eval do
21
+ define_method "call_filter" do |name, text|
22
+ raise Errors::NoSuchFilter.new(name) unless valid_filters.member?(name.to_s)
23
+ method(name).call text
24
+ end
25
+ end
26
+ end
27
+
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,60 @@
1
+ require 'cog/errors'
2
+ require 'cog/generator/language_methods/scope'
3
+
4
+ module Cog
5
+ module Generator
6
+
7
+ # Methods to help with generating language constructs
8
+ module LanguageMethods
9
+
10
+ # @return [String] a warning comment not to edit the generated file
11
+ def warning
12
+ stamp 'warning', :filter => 'comment'
13
+ end
14
+
15
+ # Begin a scope, pushing it onto the scope stack
16
+ # @param scope [Scope] the scope to begin
17
+ # @return [String] the scope begin statement
18
+ def scope_begin(scope)
19
+ gcontext[:scopes] << scope
20
+ Config.instance.active_language.method("#{scope.type}_begin").call(scope.name)
21
+ end
22
+
23
+ # End the scope, popping it off the scope stack
24
+ # @option opt [Boolean] :safe_pop (false) do not throw an exception if the stack is empty, instead, return +nil+
25
+ # @return [String, nil] the scope end statement, or +nil+ if <tt>:safe_pop</tt> and the stack is empty
26
+ def scope_end(opt={})
27
+ if gcontext[:scopes].empty?
28
+ raise Errors::ScopeStackUnderflow.new(self) unless opt[:safe_pop]
29
+ return nil
30
+ end
31
+ scope = gcontext[:scopes].pop
32
+ Config.instance.active_language.method("#{scope.type}_end").call(scope.name)
33
+ end
34
+
35
+ # End all scope currently on the stack
36
+ # @return [String]
37
+ def end_all_scopes
38
+ lines = []
39
+ while line = scope_end(:safe_pop => true)
40
+ lines << line
41
+ end
42
+ lines.join "\n"
43
+ end
44
+
45
+ # @param name [String] name of the module
46
+ # @return [String] an include guard statement for the active language
47
+ def include_guard_begin(name = nil)
48
+ scope_begin Scope.new(:include_guard, name)
49
+ end
50
+
51
+ def named_scope_begin(name = nil)
52
+ scope_begin Scope.new(:named_scope, name)
53
+ end
54
+
55
+ alias :named_scope_end :scope_end
56
+ alias :include_guard_end :scope_end
57
+
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,24 @@
1
+ module Cog
2
+ module Generator
3
+ module LanguageMethods
4
+
5
+ # Defines a program scope
6
+ class Scope
7
+
8
+ # @return [Symbol] type of the scope. For example, <tt>:include_guard</tt>
9
+ attr_reader :type
10
+
11
+ # @return [String, nil] name of the scope
12
+ attr_reader :name
13
+
14
+ # @param type [String] type of the scope
15
+ # @param name [String] name of the scope
16
+ def initialize(type, name=nil)
17
+ @type = type.to_sym
18
+ @name = name
19
+ end
20
+ end
21
+
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,50 @@
1
+ require 'cog/errors'
2
+ require 'cog/languages/language'
3
+
4
+ module Cog
5
+
6
+ # Submodules define helpers for the target languages supported by +cog+
7
+ module Languages
8
+
9
+ # @return [Hash] a mapping from file extensions to languages identifiers
10
+ DEFAULT_LANGUAGE_EXTENSION_MAP = {
11
+ :c => 'c',
12
+ :cpp => 'c++',
13
+ :cs => 'c#',
14
+ :h => 'c',
15
+ :hpp => 'c++',
16
+ :java => 'java',
17
+ :js => 'javascript',
18
+ :php => 'php',
19
+ :py => 'python',
20
+ :rb => 'ruby',
21
+ }
22
+
23
+ # @return [Hash] a mapping from language aliases to language identifiers
24
+ ALIAS = {
25
+ 'c++' => 'c_plus_plus',
26
+ 'c#' => 'c_sharp',
27
+ 'php' => 'p_h_p',
28
+ 'javascript' => 'java_script',
29
+ }
30
+
31
+ # @return [Hash] a mapping of language identifiers to lists of aliases
32
+ REV_ALIAS = {}
33
+ ALIAS.each_pair do |a, lang|
34
+ REV_ALIAS[lang] ||= []
35
+ REV_ALIAS[lang] << a
36
+ end
37
+
38
+ # @param lang_id [String] a langauge identifier
39
+ # @return [Language] a language helper corresponding to the given identifier
40
+ def self.get_language(lang_id)
41
+ lang_id = Languages::ALIAS[lang_id] || lang_id
42
+ require "cog/languages/#{lang_id.to_s.downcase}_language"
43
+ Languages.instance_eval {const_get "#{lang_id.camelize}Language"}.new
44
+ rescue LoadError
45
+ raise Errors::NoSuchLanguage.new lang_id
46
+ end
47
+
48
+ end
49
+
50
+ end
@@ -0,0 +1,17 @@
1
+ require 'cog/languages/language'
2
+
3
+ module Cog
4
+ module Languages
5
+
6
+ class CLanguage < Language
7
+
8
+ def comment(text)
9
+ "/*\n#{text}\n */"
10
+ end
11
+
12
+ def module_extensions
13
+ [:c, :h]
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,30 @@
1
+ require 'cog/languages/c_language'
2
+
3
+ module Cog
4
+ module Languages
5
+
6
+ class CPlusPlusLanguage < CLanguage
7
+
8
+ def module_extensions
9
+ [:cpp, :hpp]
10
+ end
11
+
12
+ def named_scope_begin(name)
13
+ "namespace #{name} {"
14
+ end
15
+
16
+ def named_scope_end(name)
17
+ "} // namespace #{name}"
18
+ end
19
+
20
+ def include_guard_begin(name)
21
+ "#ifndef #{name}\n#define #{name}"
22
+ end
23
+
24
+ def include_guard_end(name)
25
+ "#end // #{name}"
26
+ end
27
+
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,13 @@
1
+ require 'cog/languages/c_language'
2
+
3
+ module Cog
4
+ module Languages
5
+
6
+ class CSharpLanguage < CLanguage
7
+
8
+ def module_extensions
9
+ [:cs]
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ require 'cog/languages/c_language'
2
+
3
+ module Cog
4
+ module Languages
5
+
6
+ class JavaLanguage < CLanguage
7
+
8
+ def module_extensions
9
+ [:java]
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ require 'cog/languages/c_language'
2
+
3
+ module Cog
4
+ module Languages
5
+
6
+ class JavaScriptLanguage < CLanguage
7
+
8
+ def module_extensions
9
+ [:js]
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,45 @@
1
+ module Cog
2
+ module Languages
3
+
4
+ # Interface that must be supported by all +cog+ language helpers.
5
+ # This base class corresponds to a plain text language.
6
+ class Language
7
+
8
+ # @param text [String] some text which should be rendered as a comment
9
+ # @return [String] a comment appropriate for this language
10
+ def comment(text)
11
+ text
12
+ end
13
+
14
+ # @return a set of extensions needed to define a module in this language
15
+ def module_extensions
16
+ [:txt]
17
+ end
18
+
19
+ # @param name [String] name of the scope
20
+ # @return [String] begin a named scope
21
+ def named_scope_begin(name)
22
+ ""
23
+ end
24
+
25
+ # @param name [String] name of the scope
26
+ # @return [String] end the given named scope
27
+ def named_scope_end(name)
28
+ ""
29
+ end
30
+
31
+ # @param name [String] name of the module to protect
32
+ # @return [String] an include guard statement
33
+ def include_guard_begin(name)
34
+ ""
35
+ end
36
+
37
+ # @param name [String] name of the module to protect
38
+ # @return [String] an include guard end statement
39
+ def include_guard_end(name)
40
+ ""
41
+ end
42
+
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,13 @@
1
+ require 'cog/languages/c_language'
2
+
3
+ module Cog
4
+ module Languages
5
+
6
+ class PHPLanguage < CLanguage
7
+
8
+ def module_extensions
9
+ [:php]
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,17 @@
1
+ require 'cog/languages/language'
2
+
3
+ module Cog
4
+ module Languages
5
+
6
+ class PythonLanguage < Language
7
+
8
+ def comment(text)
9
+ "'''\n#{text}\n'''"
10
+ end
11
+
12
+ def module_extensions
13
+ [:py]
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,17 @@
1
+ require 'cog/languages/language'
2
+
3
+ module Cog
4
+ module Languages
5
+
6
+ class RubyLanguage < Language
7
+
8
+ def comment(text)
9
+ "=begin\n#{text}\n=end"
10
+ end
11
+
12
+ def module_extensions
13
+ [:rb]
14
+ end
15
+ end
16
+ end
17
+ end
@@ -1,5 +1,5 @@
1
1
  module Cog
2
2
  unless const_defined? :VERSION
3
- VERSION = '0.1.2'
3
+ VERSION = '0.1.3'
4
4
  end
5
5
  end
@@ -4,8 +4,10 @@ class <%= camelized %>
4
4
  include Cog::Generator
5
5
 
6
6
  def generate
7
- @some_context = :my_context_value
8
- stamp '<%= name %>.txt', 'generated_<%= name %>.txt'
7
+ @class = '<%= name.gsub ' ', '' %>'
8
+ <% @language.module_extensions.each do |ext| %>
9
+ stamp '<%= name %>.<%= ext %>', 'generated_<%= name %>.<%= ext %>'
10
+ <% end %>
9
11
  end
10
12
  end
11
13
 
@@ -0,0 +1 @@
1
+ <%%= warning %>
@@ -0,0 +1,6 @@
1
+ <%%= warning %>
2
+ #include "generated_<%= name %>.h"
3
+
4
+ <%%= @class %>::<%%= @class >()
5
+ {
6
+ }
@@ -0,0 +1,6 @@
1
+ <%%= warning %>
2
+
3
+ class <%%= @class %>
4
+ {
5
+ <%%= @class %>();
6
+ };
@@ -0,0 +1 @@
1
+ <%%= warning %>
@@ -0,0 +1,6 @@
1
+ <%%= warning %>
2
+
3
+ class <%%= @class %>
4
+ {
5
+ <%%= @class %>();
6
+ };
@@ -0,0 +1 @@
1
+ <%%= warning %>
@@ -0,0 +1 @@
1
+ <%%= warning %>
@@ -0,0 +1 @@
1
+ <%%= warning %>
@@ -0,0 +1 @@
1
+ <%%= warning %>
@@ -0,0 +1,6 @@
1
+ <%%= warning %>
2
+
3
+ class <%%= @class %>
4
+ {
5
+ <%%= @class %>();
6
+ };
@@ -1 +1 @@
1
- This is some context: <%%= @some_context %>!
1
+ <%%= warning %>
@@ -10,7 +10,13 @@ module <%= @tool_module %>
10
10
  def self.widget(generator_name, &block)
11
11
  w = Widget.new generator_name
12
12
  block.call w
13
- w.generate
13
+
14
+ # Activate <%= @tool_name %> while rendering templates
15
+ # so that cog will be able to find <%= @tool_name %> templates
16
+ Cog::Config.instance.activate_tool '<%= @tool_name %>' do
17
+ w.generate
18
+ end
19
+
14
20
  nil
15
21
  end
16
22
 
@@ -0,0 +1,11 @@
1
+ -------------------------------------------------------------------------------
2
+
3
+ WARNING
4
+
5
+ This is a generated file. DO NOT EDIT THIS FILE! Your changes will
6
+ be lost the next time this file is regenerated.
7
+
8
+ This file was generating using cog
9
+ https://github.com/ktonon/cog
10
+
11
+ -------------------------------------------------------------------------------
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cog
3
3
  version: !ruby/object:Gem::Version
4
- hash: 31
4
+ hash: 29
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
8
  - 1
9
- - 2
10
- version: 0.1.2
9
+ - 3
10
+ version: 0.1.3
11
11
  platform: ruby
12
12
  authors:
13
13
  - Kevin Tonon
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2012-11-12 00:00:00 Z
18
+ date: 2012-11-14 00:00:00 Z
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
21
21
  name: gli
@@ -114,6 +114,16 @@ files:
114
114
  - Default.cogfile
115
115
  - LICENSE
116
116
  - templates/basic/generator.rb.erb
117
+ - templates/basic/template.c.erb.erb
118
+ - templates/basic/template.cpp.erb.erb
119
+ - templates/basic/template.cs.erb.erb
120
+ - templates/basic/template.h.erb.erb
121
+ - templates/basic/template.hpp.erb.erb
122
+ - templates/basic/template.java.erb.erb
123
+ - templates/basic/template.js.erb.erb
124
+ - templates/basic/template.php.erb.erb
125
+ - templates/basic/template.py.erb.erb
126
+ - templates/basic/template.rb.erb.erb
117
127
  - templates/basic/template.txt.erb.erb
118
128
  - templates/cog/custom_tool/cog_tool.rb.erb
119
129
  - templates/cog/custom_tool/Gemfile.erb
@@ -125,11 +135,12 @@ files:
125
135
  - templates/cog/custom_tool/tool.gemspec.erb
126
136
  - templates/cog/custom_tool/tool.rb.erb
127
137
  - templates/cog/custom_tool/version.rb.erb
128
- - templates/warning.h.erb
138
+ - templates/warning.erb
129
139
  - lib/cog/built_in_tools/basic/cog_tool.rb
130
140
  - lib/cog/built_in_tools/basic.rb
131
141
  - lib/cog/built_in_tools.rb
132
142
  - lib/cog/config/cogfile.rb
143
+ - lib/cog/config/lang_info.rb
133
144
  - lib/cog/config/tool.rb
134
145
  - lib/cog/config.rb
135
146
  - lib/cog/controllers/generator_controller.rb
@@ -137,10 +148,24 @@ files:
137
148
  - lib/cog/controllers/tool_controller.rb
138
149
  - lib/cog/controllers.rb
139
150
  - lib/cog/errors.rb
151
+ - lib/cog/generator/file_methods.rb
152
+ - lib/cog/generator/filters.rb
153
+ - lib/cog/generator/language_methods/scope.rb
154
+ - lib/cog/generator/language_methods.rb
140
155
  - lib/cog/generator.rb
141
156
  - lib/cog/helpers/cascading_template_set.rb
142
157
  - lib/cog/helpers/string.rb
143
158
  - lib/cog/helpers.rb
159
+ - lib/cog/languages/c_language.rb
160
+ - lib/cog/languages/c_plus_plus_language.rb
161
+ - lib/cog/languages/c_sharp_language.rb
162
+ - lib/cog/languages/java_language.rb
163
+ - lib/cog/languages/java_script_language.rb
164
+ - lib/cog/languages/language.rb
165
+ - lib/cog/languages/p_h_p_language.rb
166
+ - lib/cog/languages/python_language.rb
167
+ - lib/cog/languages/ruby_language.rb
168
+ - lib/cog/languages.rb
144
169
  - lib/cog/spec_helpers/matchers/match_maker.rb
145
170
  - lib/cog/spec_helpers/matchers.rb
146
171
  - lib/cog/spec_helpers/runner.rb
@@ -1,9 +0,0 @@
1
- /* --------------------------------------------------------------------------
2
- WARNING
3
-
4
- This is a generated file. DO NOT EDIT THIS FILE! Your changes will be lost
5
- the next time this file is regenerated.
6
-
7
- This file was generating using cog
8
- https://github.com/ktonon/cog
9
- -------------------------------------------------------------------------- */