cog 0.1.2 → 0.1.3

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 (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
- -------------------------------------------------------------------------- */