cog 0.0.20 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. data/bin/cog +54 -53
  2. data/lib/cog.rb +4 -3
  3. data/lib/cog/built_in_tools/basic.rb +10 -0
  4. data/lib/cog/built_in_tools/basic/cog_tool.rb +15 -0
  5. data/lib/cog/config.rb +111 -33
  6. data/lib/cog/config/tool.rb +99 -0
  7. data/lib/cog/controllers.rb +13 -0
  8. data/lib/cog/controllers/generator_controller.rb +45 -0
  9. data/lib/cog/controllers/template_controller.rb +31 -0
  10. data/lib/cog/controllers/tool_controller.rb +53 -0
  11. data/lib/cog/errors.rb +51 -9
  12. data/lib/cog/generator.rb +1 -74
  13. data/lib/cog/helpers.rb +1 -0
  14. data/lib/cog/helpers/cascading_template_set.rb +75 -0
  15. data/lib/cog/helpers/string.rb +9 -3
  16. data/lib/cog/version.rb +1 -1
  17. data/templates/basic/generator.rb.erb +12 -0
  18. data/templates/{cog/generator/basic-template.txt.erb.erb → basic/template.txt.erb.erb} +0 -0
  19. data/templates/cog/{tool → custom_tool}/Gemfile.erb +4 -0
  20. data/templates/cog/{tool → custom_tool}/LICENSE.erb +1 -1
  21. data/templates/cog/custom_tool/README.markdown.erb +18 -0
  22. data/templates/cog/custom_tool/Rakefile.erb +15 -0
  23. data/templates/cog/custom_tool/cog_tool.rb.erb +15 -0
  24. data/templates/cog/custom_tool/generator.rb.erb.erb +9 -0
  25. data/templates/cog/{tool → custom_tool}/template.txt.erb.erb +0 -0
  26. data/templates/cog/custom_tool/tool.gemspec.erb +18 -0
  27. data/templates/cog/{tool → custom_tool}/tool.rb.erb +5 -13
  28. data/templates/cog/{tool → custom_tool}/version.rb.erb +1 -1
  29. metadata +24 -17
  30. data/lib/cog/tool.rb +0 -81
  31. data/templates/cog/generator/basic.rb.erb +0 -12
  32. data/templates/cog/tool/API.rdoc.erb +0 -7
  33. data/templates/cog/tool/README.markdown.erb +0 -18
  34. data/templates/cog/tool/Rakefile.erb +0 -15
  35. data/templates/cog/tool/generator.rb.erb.erb +0 -6
  36. data/templates/cog/tool/tool.gemspec.erb +0 -18
@@ -0,0 +1,13 @@
1
+ require 'cog/controllers/generator_controller'
2
+ require 'cog/controllers/template_controller'
3
+ require 'cog/controllers/tool_controller'
4
+ require 'cog/errors'
5
+
6
+ module Cog
7
+
8
+ # Contains controllers for managing basic +cog+ objects like generators, templates, and tools
9
+ module Controllers
10
+ end
11
+
12
+ end
13
+
@@ -0,0 +1,45 @@
1
+ require 'cog/config'
2
+ require 'cog/errors'
3
+ require 'cog/helpers'
4
+ require 'rainbow'
5
+
6
+ module Cog
7
+ module Controllers
8
+
9
+ # Manage a project's generators
10
+ module GeneratorController
11
+
12
+ # Create a new generator
13
+ # @param name [String] the name to use for the new generator
14
+ # @return [Boolean] was the generator successfully created?
15
+ def self.create(name)
16
+ raise Errors::ActionRequiresProject.new('create generator') unless Config.instance.project?
17
+ generator_dest = File.join Config.instance.project_generators_path, "#{name}.rb"
18
+ raise Errors::DuplicateGenerator.new(generator_dest) if File.exists?(generator_dest)
19
+ gs = Config.instance.active_tool.generator_stamper
20
+ gs.stamp_generator name, generator_dest, Config.instance
21
+ end
22
+
23
+ # List the available project generators
24
+ # @option opt [Boolean] :verbose (false) list full paths to generator files
25
+ # @return [Array<String>] a list of generators
26
+ def self.list(opt={})
27
+ raise Errors::ActionRequiresProject.new('list generators') unless Config.instance.project?
28
+ x = Dir.glob(File.join Config.instance.project_generators_path, '*.rb')
29
+ opt[:verbose] ? x : (x.collect {|path| File.basename(path).slice(0..-4)})
30
+ end
31
+
32
+ # Run the generator with the given name
33
+ # @param name [String] name of the generator as returned by {GeneratorController.list}
34
+ # @return [nil]
35
+ def self.run(name)
36
+ raise Errors::ActionRequiresProject.new('run generator') unless Config.instance.project?
37
+ path = File.join Config.instance.project_generators_path, "#{name}.rb"
38
+ raise Errors::NoSuchGenerator.new(name) unless File.exists?(path)
39
+ require path
40
+ nil
41
+ end
42
+
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,31 @@
1
+ require 'cog/config'
2
+ require 'cog/errors'
3
+ require 'cog/helpers'
4
+ require 'rainbow'
5
+
6
+ module Cog
7
+ module Controllers
8
+
9
+ # Manage a project's templates
10
+ module TemplateController
11
+
12
+ # List the available templates
13
+ # @option opt [Boolean] :verbose (false) list full template paths
14
+ # @return [Array<String>] a list of templates
15
+ def self.list(opt={})
16
+ cts = Helpers::CascadingTemplateSet.new
17
+ cts.add_templates 'built-in', :built_in, Config.cog_templates_path, opt
18
+ Config.instance.tools.each do |tool|
19
+ unless tool.templates_path.nil?
20
+ cts.add_templates tool.name, :tool, tool.templates_path, opt
21
+ end
22
+ end
23
+ if Config.instance.project?
24
+ cts.add_templates 'project', :project, Config.instance.project_templates_path, opt
25
+ end
26
+ cts.to_a
27
+ end
28
+
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,53 @@
1
+ require 'cog/config'
2
+ require 'cog/errors'
3
+ require 'cog/generator'
4
+ require 'rainbow'
5
+
6
+ module Cog
7
+ module Controllers
8
+
9
+ # Manage +cog+ tools
10
+ #
11
+ # @see https://github.com/ktonon/cog#tools Introduction to Tools
12
+ module ToolController
13
+
14
+ # Generate a new tool with the given name
15
+ # @param name [String] name of the tool to create. Should not conflict with other tool names
16
+ # @return [nil]
17
+ def self.create(name)
18
+ raise Errors::DestinationAlreadyExists.new(name) if File.exists?(name)
19
+ raise Errors::DuplicateTool.new(name) if Config.instance.tool_registered?(name)
20
+ Object.new.instance_eval do
21
+ extend Generator
22
+ @tool_name = name.to_s.downcase
23
+ @tool_module = name.to_s.capitalize
24
+ @tool_author = '<Your name goes here>'
25
+ @tool_email = 'youremail@...'
26
+ @tool_description = 'A one-liner'
27
+ @cog_version = Cog::VERSION
28
+ stamp 'cog/custom_tool/tool.rb', "#{@tool_name}/lib/#{@tool_name}.rb", :absolute_destination => true
29
+ stamp 'cog/custom_tool/cog_tool.rb', "#{@tool_name}/lib/#{@tool_name}/cog_tool.rb", :absolute_destination => true
30
+ stamp 'cog/custom_tool/version.rb', "#{@tool_name}/lib/#{@tool_name}/version.rb", :absolute_destination => true
31
+ stamp 'cog/custom_tool/generator.rb.erb', "#{@tool_name}/cog/templates/#{@tool_name}/generator.rb.erb", :absolute_destination => true
32
+ stamp 'cog/custom_tool/template.txt.erb', "#{@tool_name}/cog/templates/#{@tool_name}/#{@tool_name}.txt.erb", :absolute_destination => true
33
+ stamp 'cog/custom_tool/Gemfile', "#{@tool_name}/Gemfile", :absolute_destination => true
34
+ stamp 'cog/custom_tool/Rakefile', "#{@tool_name}/Rakefile", :absolute_destination => true
35
+ stamp 'cog/custom_tool/tool.gemspec', "#{@tool_name}/#{@tool_name}.gemspec", :absolute_destination => true
36
+ stamp 'cog/custom_tool/LICENSE', "#{@tool_name}/LICENSE", :absolute_destination => true
37
+ stamp 'cog/custom_tool/README.markdown', "#{@tool_name}/README.markdown", :absolute_destination => true
38
+ end
39
+ nil
40
+ end
41
+
42
+ # @param opt [Boolean] :verbose (false) list full paths to tools
43
+ # @return [Array<String>] a list of available tools
44
+ def self.list(opt={})
45
+ Config.instance.tools.collect do |tool|
46
+ opt[:verbose] ? tool.path : tool.name
47
+ end
48
+ end
49
+
50
+
51
+ end
52
+ end
53
+ end
@@ -1,16 +1,58 @@
1
1
  module Cog
2
2
 
3
3
  module Errors
4
- # Indiciates an attempt to use a non-existant template.
5
- class MissingTemplate < Exception
6
- def initialize(template_path)
7
- @template_path = template_path
8
- end
9
-
10
- def message
11
- "could not find the template '#{@template_path}'\n#{super}"
4
+
5
+ # Root type for all cog errors
6
+ class CogError < Exception
7
+ end
8
+
9
+ # Define a +cog+ error class
10
+ # @api developer
11
+ #
12
+ # @param class_name [String] name of the error class
13
+ # @param arg [String] name of the argument to the constructor, will appear in error messages
14
+ # @yield +self+ will be set to an instance of the error class and <tt>@msg</tt> will contain
15
+ def self.define_error(class_name, arg, &block)
16
+ cls = Class.new CogError
17
+ Errors.instance_eval { const_set class_name, cls }
18
+ cls.instance_eval do
19
+ define_method(:initialize) {|value| @value = value}
20
+ define_method :message do
21
+ msg = if block.nil?
22
+ class_name.to_s.underscore.gsub '_', ' '
23
+ else
24
+ instance_eval &block
25
+ end
26
+ "#{msg} (#{arg} => #{@value})"
27
+ end
12
28
  end
13
29
  end
14
- end
15
30
 
31
+ define_error :ActionRequiresProject, 'action' do
32
+ "the action requires a project, but no Cogfile was found"
33
+ end
34
+
35
+ define_error :CouldNotLoadTool, 'tool'
36
+
37
+ define_error :DestinationAlreadyExists, 'path' do
38
+ "a file or directory at the given path already exists, cannot create anything there"
39
+ end
40
+
41
+ define_error :DuplicateGenerator, 'generator name'
42
+
43
+ define_error :DuplicateTool, 'tool'
44
+
45
+ define_error :InvalidToolConfiguration, 'path to cog_tool.rb file' do
46
+ "invalid directory structure for a cog tool"
47
+ end
48
+
49
+ define_error :NoSuchGenerator, 'generator'
50
+
51
+ define_error :NoSuchTemplate, 'template'
52
+
53
+ define_error :NoSuchTool, 'tool' do
54
+ "no such tool, make sure it appears in the COG_TOOLS environment variable"
55
+ end
56
+
57
+ end
16
58
  end
@@ -13,79 +13,6 @@ module Cog
13
13
  # @see https://github.com/ktonon/cog#generators Introduction to Generators
14
14
  module Generator
15
15
 
16
- # List the available project generators
17
- # @param verbose [Boolean] should full generator paths be listed?
18
- # @return [Array<String>] a list of generator names
19
- def self.list(verbose=false)
20
- if Config.instance.project?
21
- x = Dir.glob(File.join Config.instance.project_generators_path, '*.rb')
22
- verbose ? x : (x.collect {|path| File.basename(path).slice(0..-4)})
23
- else
24
- []
25
- end
26
- end
27
-
28
- # Create a new generator
29
- # @param name [String] the name to use for the new generator
30
- # @option opt [String] :tool ('basic') the name of the tool to use
31
- # @return [Boolean] was the generator successfully created?
32
- def self.create(name, opt={})
33
- return false unless Config.instance.project?
34
-
35
- gen_name = File.join Config.instance.project_generators_path, "#{name}.rb"
36
- if File.exists? gen_name
37
- STDERR.write "Generator '#{gen_name}' already exists\n".color(:red)
38
- return false
39
- end
40
-
41
- tool = (opt[:tool] || :basic).to_s
42
- template_name = File.join Config.instance.project_templates_path, "#{name}.txt.erb"
43
- if tool == 'basic' && File.exists?(template_name)
44
- STDERR.write "Template '#{template_name}' already exists\n".color(:red)
45
- return false
46
- end
47
-
48
- Object.new.instance_eval do
49
- extend Generator
50
- @name = name
51
- @class_name = name.to_s.camelize
52
- if tool == 'basic'
53
- stamp 'cog/generator/basic.rb', gen_name, :absolute_destination => true
54
- stamp 'cog/generator/basic-template.txt.erb', template_name, :absolute_destination => true
55
- else
56
- tool_path = Tool.find(tool)
57
- if tool_path.nil?
58
- STDERR.write "No such tool '#{tool}'"
59
- false
60
- else
61
- require tool_path
62
- @absolute_require = tool_path != tool
63
- @tool_parent_path = File.dirname(tool_path)
64
- stamp Config.instance.tool_generator_template, gen_name, :absolute_destination => true
65
- true
66
- end
67
- end
68
- end
69
- end
70
-
71
- # Run the generator with the given name
72
- # @param name [String] name of the generator as returned by {Generator.list}
73
- # @option opt [Boolean] :verbose (false) in the case of an exception, should a full stack trace be written?
74
- # @return [Boolean] was the generator run successfully?
75
- def self.run(name, opt={})
76
- filename = File.join Cog::Config.instance.project_generators_path, "#{name}.rb"
77
- if File.exists? filename
78
- require filename
79
- return true
80
- end
81
- STDERR.write "No such generator '#{name}'\n".color(:red)
82
- false
83
- rescue => e
84
- trace = opt[:verbose] ? "\n#{e.backtrace.join "\n"}" : ''
85
- STDERR.write "Generator '#{name}' failed: #{e}#{trace}\n".color(:red)
86
- false
87
- end
88
-
89
16
  # Get the template with the given name
90
17
  # @param path [String] path to template file relative one of the {Config#template_paths}
91
18
  # @option opt [Boolean] :absolute (false) is the +path+ argument absolute?
@@ -100,7 +27,7 @@ module Cog
100
27
  found.empty? && File.exists?(x) ? x : found
101
28
  end
102
29
  end
103
- raise Errors::MissingTemplate.new path unless File.exists? fullpath
30
+ raise Errors::NoSuchTemplate.new path unless File.exists? fullpath
104
31
  ERB.new File.read(fullpath), 0, '>'
105
32
  end
106
33
 
@@ -1 +1,2 @@
1
+ require 'cog/helpers/cascading_template_set'
1
2
  require 'cog/helpers/string'
@@ -0,0 +1,75 @@
1
+ require 'cog/helpers/string'
2
+ require 'rainbow'
3
+
4
+ module Cog
5
+ module Helpers
6
+
7
+ # @api developer
8
+ class TemplateInfo
9
+ attr_reader :name
10
+ attr_accessor :path
11
+
12
+ def initialize(name)
13
+ @sources = []
14
+ @source_types = []
15
+ @name = name
16
+ end
17
+
18
+ def add_source(source, source_type)
19
+ @sources << source
20
+ @source_types << source_type
21
+ end
22
+
23
+ def style(text, type)
24
+ case type
25
+ when :built_in
26
+ text.color :cyan
27
+ when :tool
28
+ text.color :yellow
29
+ when :project
30
+ text.color(:white).bright
31
+ end
32
+ end
33
+
34
+ def override_s(width=nil)
35
+ colorless = "[#{@sources.join ' < '}]"
36
+ if width
37
+ x = @sources.zip(@source_types).collect {|s, t| style s, t}
38
+ "[#{x.join ' < '}]" + " " * (width - colorless.length)
39
+ else
40
+ colorless
41
+ end
42
+ end
43
+
44
+ def <=>(other)
45
+ (@path || @name) <=> (other.path || other.name)
46
+ end
47
+
48
+ def to_s(override_column_width)
49
+ "#{override_s override_column_width} #{style @path || @name, @source_types.last}"
50
+ end
51
+ end
52
+
53
+ # @api developer
54
+ class CascadingTemplateSet
55
+ def initialize
56
+ @templates = {}
57
+ end
58
+
59
+ def add_templates(source, source_type, root, opt={})
60
+ Dir.glob("#{root}/**/*.erb") do |path|
61
+ name = path.relative_to(root).slice(0..-5)
62
+ @templates[name] ||= TemplateInfo.new name
63
+ @templates[name].path = path if opt[:verbose]
64
+ @templates[name].add_source source, source_type
65
+ end
66
+ end
67
+
68
+ def to_a
69
+ w = @templates.values.collect {|t| t.override_s.length}.max
70
+ @templates.values.sort.collect {|t| t.to_s(w)}
71
+ end
72
+ end
73
+
74
+ end
75
+ end
@@ -4,8 +4,14 @@ class String
4
4
 
5
5
  # @return [String] strips {Cog::Config#project_root} from the beginning of this string
6
6
  def relative_to_project_root
7
- return unless Cog::Config.instance.project?
8
- root = Cog::Config.instance.project_root
9
- start_with?(root) ? slice(root.length+1..-1) : dup
7
+ return dup unless Cog::Config.instance.project?
8
+ relative_to Cog::Config.instance.project_root
9
+ end
10
+
11
+ # @param prefix [String] path prefix to strip from the beginning of this string
12
+ # @return [String] this string as a file system path relative to the +prefix+
13
+ def relative_to(prefix)
14
+ return dup if prefix.nil?
15
+ start_with?(prefix) ? slice(prefix.length+1..-1) : dup
10
16
  end
11
17
  end
@@ -1,5 +1,5 @@
1
1
  module Cog
2
2
  unless const_defined? :VERSION
3
- VERSION = '0.0.20'
3
+ VERSION = '0.1.0'
4
4
  end
5
5
  end
@@ -0,0 +1,12 @@
1
+ require 'cog'
2
+
3
+ class <%= camelized %>
4
+ include Cog::Generator
5
+
6
+ def generate
7
+ @some_context = :my_context_value
8
+ stamp '<%= name %>.txt', 'generated_<%= name %>.txt'
9
+ end
10
+ end
11
+
12
+ <%= camelized %>.new.generate
@@ -2,3 +2,7 @@ source :rubygems
2
2
  gemspec
3
3
 
4
4
  gem "cog", "~> <%= @cog_version %>"
5
+
6
+ # Documentation
7
+ gem "yard"
8
+ gem "redcarpet"
@@ -1,4 +1,4 @@
1
- Copyright (c) 2012 <%= @author %>
1
+ Copyright (c) 2012 <%= @tool_author %>
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining a copy of
4
4
  this software and associated documentation files (the "Software"), to deal in
@@ -0,0 +1,18 @@
1
+ = <%= @tool_name %>
2
+
3
+ <%= @tool_description %>
4
+
5
+ Get it
6
+ ------
7
+
8
+ From a terminal
9
+
10
+ ```bash
11
+ gem install <%= @tool_name %>
12
+ ```
13
+
14
+ or in your Gemfile
15
+
16
+ ```ruby
17
+ gem "<%= @tool_name %>", "~> 0.0.1"
18
+ ```