cog 0.0.11 → 0.0.12

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.
data/bin/cog CHANGED
@@ -20,43 +20,45 @@ command :init do |c|
20
20
  end
21
21
  end
22
22
 
23
- desc 'Create a tool (or leave name blank to list available tools)'
23
+ desc 'Create a generator (or leave name blank to list project generators)'
24
24
  arg_name 'name'
25
- skips_pre
26
- command :tool do |c|
27
-
25
+ command :generator do |c|
26
+
27
+ c.desc 'which tool to use to create the generator'
28
+ c.arg_name 'tool_name'
29
+ c.default_value 'basic'
30
+ c.flag :tool
31
+
28
32
  c.action do |global_options, options, args|
29
33
  if args.empty?
30
- puts 'Available tools:'
31
- puts (Cog::Tool.available.collect {|tool| " #{tool}"}.join "\n")
34
+ # List
35
+ x = Cog::Generator.list
36
+ puts x.collect {|gen| " #{gen}"}.join "\n" unless x.empty?
32
37
  else
38
+ # Create
33
39
  args.each do |name|
34
- unless File.exists? name
35
- Cog::Tool.generate_tool name
36
- else
37
- puts "Could not create tool for '#{name}', a file or directory already exists with that name"
38
- end
40
+ Cog::Generator.create name, options
39
41
  end
40
42
  end
41
43
  end
42
44
  end
43
45
 
44
- desc 'Create a generator (or leave name blank to list project generators)'
46
+ desc 'Create a tool (or leave name blank to list available tools)'
45
47
  arg_name 'name'
46
- command :generator do |c|
47
-
48
- c.desc 'which tool to use to create the generator'
49
- c.arg_name 'tool_name'
50
- c.default_value 'generic'
51
- c.flag :tool
52
-
48
+ skips_pre
49
+ command :tool do |c|
50
+
53
51
  c.action do |global_options, options, args|
54
52
  if args.empty?
55
- puts 'Project generators:'
56
- puts (Cog::Generator.available.collect {|gen| " #{gen}"}.join "\n")
53
+ puts 'Available tools:'
54
+ puts (Cog::Tool.list.collect {|tool| " #{tool}"}.join "\n")
57
55
  else
58
56
  args.each do |name|
59
- # TODO: create the generator
57
+ unless File.exists? name
58
+ Cog::Tool.create name
59
+ else
60
+ puts "Could not create tool for '#{name}', a file or directory already exists with that name"
61
+ end
60
62
  end
61
63
  end
62
64
  end
@@ -74,6 +76,19 @@ end
74
76
  desc 'Run generators in the current project'
75
77
  arg_name 'generator_name'
76
78
  command :run do |c|
79
+
80
+ c.action do |global_options, options, args|
81
+ args = Cog::Generator.available if args.empty?
82
+ args.each do |gen|
83
+ filename = File.join Cog::Config.instance.project_generators_path, "#{gen}.rb"
84
+ if File.exists? filename
85
+ puts "Running generator #{gen}"
86
+ require filename
87
+ else
88
+ puts "No such generator #{gen}"
89
+ end
90
+ end
91
+ end
77
92
  end
78
93
 
79
94
  pre do |global_options, command, options, args|
@@ -3,9 +3,10 @@ require 'singleton'
3
3
 
4
4
  module Cog
5
5
 
6
- # This interface is intended for use within generators. Apps can customize
7
- # Instances of this type
8
- # can be configured via Cogfile files.
6
+ # This is a low level interface. It is mainly used by the Generator methods
7
+ # to determine where to find things, and where to put them. When +cog+ is used
8
+ # in a project the values of the singleton Config::instance should be configured using
9
+ # a Cogfile.
9
10
  class Config
10
11
 
11
12
  # Path to the project's +Cogfile+.
@@ -52,16 +53,16 @@ module Cog
52
53
 
53
54
  # The singleton instance.
54
55
  #
55
- # Initialized using the +Cogfile+ for the current project, if any can be
56
- # found. If not, then #project? will be +false+.
56
+ # Initialized using the Cogfile for the current project, if any can be
57
+ # found. If not, then #project? will be +false+ and all the +project_...+
58
+ # attributes will be +nil+.
57
59
  #
58
- # The +Cogfile+ will be looked for in the present working directory. If none
60
+ # The Cogfile will be looked for in the present working directory. If none
59
61
  # is found there the parent directory will be checked, and then the
60
62
  # grandparent, and so on.
61
63
  #
62
64
  # ==== Returns
63
- # An instance of Cogfile which has been configured with a +Cogfile+. If no
64
- # such file was found then +nil+.
65
+ # An instance of Config.
65
66
  def self.instance
66
67
  return @instance if @instance
67
68
  @instance = self.new
@@ -89,6 +90,7 @@ module Cog
89
90
 
90
91
  def initialize
91
92
  @project_root = nil
93
+ @language = 'c++'
92
94
  end
93
95
 
94
96
  end
@@ -4,15 +4,46 @@ require 'erb'
4
4
 
5
5
  module Cog
6
6
 
7
- # Generators have the ability to #stamp templates into source code.
7
+ # This module defines an interface which can be used by generator objects.
8
+ # Specifically, it makes it easy to find ERB templates and render them into
9
+ # generated source code files, using the #stamp method.
8
10
  #
9
- # This module defines a low-level interface for writing generators. To use it,
10
- # just include the Generator module in your class or object.
11
+ # For more details on writing generators see https://github.com/ktonon/cog#generators
11
12
  module Generator
12
13
 
13
14
  # A list of available project generators
14
- def self.available
15
- [:dummy1, :dummy2]
15
+ def self.list
16
+ if Config.instance.project?
17
+ Dir.glob(File.join Config.instance.project_generators_path, '*.rb').collect do |path|
18
+ File.basename(path).slice(0..-4)
19
+ end
20
+ else
21
+ []
22
+ end
23
+ end
24
+
25
+ # Create a new generator
26
+ #
27
+ # ==== Arguments
28
+ # * +name+ - the name to use for the new generator
29
+ #
30
+ # ==== Options
31
+ # * +tool+ - the name of the tool to use (default: basic)
32
+ #
33
+ # ==== Returns
34
+ # Whether or not the generator was created successfully
35
+ def self.create(name, opt={})
36
+ return false unless Config.instance.project?
37
+ filename = File.join Config.instance.project_generators_path, "#{name}.rb"
38
+ return false if File.exists? filename
39
+ tool = (opt[:tool] || :basic).to_s
40
+ Object.new.instance_eval do
41
+ extend Generator
42
+ @name = name
43
+ @class_name = name.to_s.camelize
44
+ stamp 'cog/generator/basic.rb', filename
45
+ end
46
+ true
16
47
  end
17
48
 
18
49
  # Get the template with the given name.
@@ -84,7 +115,7 @@ module Cog
84
115
  # File extension for a snippet of the given source code language.
85
116
  # ==== Example
86
117
  # snippet_extension 'c++' # => 'h'
87
- def snippet_extension(lang = 'text')
118
+ def snippet_extension(lang = 'text') # :nodoc:
88
119
  case lang
89
120
  when /(c\+\+|c|objc)/i
90
121
  'h'
@@ -94,22 +125,22 @@ module Cog
94
125
  end
95
126
 
96
127
  # A warning that indicates a file is maintained by a generator
97
- def generated_warning
128
+ def generated_warning # :nodoc:
98
129
  lang = Config.instance.language
99
130
  t = get_template "snippets/#{lang}/generated_warning.#{snippet_extension lang}", :cog_template => true
100
131
  t.result(binding)
101
132
  end
102
133
 
103
- def include_guard_begin(name)
134
+ def include_guard_begin(name) # :nodoc:
104
135
  full = "COG_INCLUDE_GUARD_#{name.upcase}"
105
136
  "#ifndef #{full}\n#define #{full}"
106
137
  end
107
138
 
108
- def include_guard_end
139
+ def include_guard_end # :nodoc:
109
140
  "#endif // COG_INCLUDE_GUARD_[...]"
110
141
  end
111
142
 
112
- def namespace_begin(name)
143
+ def namespace_begin(name) # :nodoc:
113
144
  return if name.nil?
114
145
  case Config.instance.language
115
146
  when /c\+\+/
@@ -117,7 +148,7 @@ module Cog
117
148
  end
118
149
  end
119
150
 
120
- def namespace_end(name)
151
+ def namespace_end(name) # :nodoc:
121
152
  return if name.nil?
122
153
  case Config.instance.language
123
154
  when /c\+\+/
@@ -9,14 +9,14 @@ module Cog
9
9
  # === Example
10
10
  # Requiring the helpers will make extra SpecHelpers::Matchers available to
11
11
  # your RSpec tests. These are useful for testing a SpecHelpers::Invocation,
12
- # which is returned from a call to SpecHelpers::App#run
12
+ # which is returned from a call to SpecHelpers::Runner#run
13
13
  #
14
14
  # require 'cog/spec_helpers'
15
15
  #
16
16
  # describe 'The command line interface' do
17
17
  #
18
18
  # before :all do
19
- # @cog = Cog::SpecHelpers::App.new 'bin/cog'
19
+ # @cog = Cog::SpecHelpers::Runner.new 'bin/cog'
20
20
  # end
21
21
  #
22
22
  # it 'should print help when no args are passed' do
@@ -46,6 +46,11 @@ module Cog
46
46
  File.join active_fixture_dir, 'cog'
47
47
  end
48
48
 
49
+ # Path to the generator with the given name
50
+ def generator(name)
51
+ File.join active_fixture_dir, 'cog', 'generators', "#{name}.rb"
52
+ end
53
+
49
54
  # The next cog spec will execute in a fresh copy of the given fixture directory.
50
55
  # Fixture directories are stored in <tt>spec/fixtures</tt>.
51
56
  def use_fixture(name)
@@ -5,20 +5,21 @@ module Cog
5
5
  module SpecHelpers
6
6
 
7
7
  # Extra should or should_not matchers for RSpec.
8
+ # Check out #match_maker for help writing new matchers.
8
9
  module Matchers
9
10
 
10
- # The target Invocation should output the default help text
11
- def show_help
11
+ # The target Invocation should complain about a missing +Cogfile+
12
+ def complain_about_missing_cogfile
12
13
  match_maker do
13
- message { "to [show|not show] the default help text, got #{lines.first.inspect}" }
14
- test { (/help.*code gen/ =~ lines[1]) }
14
+ message { "to [require|not require] a Cogfile. STDOUT: #{lines.inspect}" }
15
+ test { (/no cogfile could be found/i =~ lines.first) }
15
16
  end
16
17
  end
17
-
18
+
18
19
  # The target Invocation should create a +Cogfile+ where none existed before
19
20
  def make(path)
20
21
  match_maker do
21
- message { "to [create|not create] the #{path}" }
22
+ message { "to [create|not create] #{path}. STDOUT: #{lines.inspect}" }
22
23
  before do
23
24
  @existed = File.exists? path
24
25
  end
@@ -27,8 +28,24 @@ module Cog
27
28
  end
28
29
  end
29
30
  end
31
+
32
+ # The target Invocation should do something, as determined by standard output
33
+ def do_something
34
+ match_maker do
35
+ message { "to [write something|not write anything] to stdout. STDOUT: #{lines.inspect}" }
36
+ test { !lines.empty? }
37
+ end
38
+ end
39
+
40
+ # The target Invocation should output the default help text
41
+ def show_help
42
+ match_maker do
43
+ message { "to [show|not show] the default help text, got #{lines.first.inspect}. STDOUT: #{lines.inspect}" }
44
+ test { (/help.*code gen/ =~ lines[1]) }
45
+ end
46
+ end
47
+
30
48
  end
31
-
32
49
  end
33
50
  end
34
51
 
@@ -2,20 +2,39 @@ module Cog
2
2
  module SpecHelpers
3
3
  module Matchers
4
4
 
5
+ # Within Matchers#match_maker blocks, +self+ is set to an instance of this
6
+ # class.
5
7
  class MatchMaker
8
+ # A list of lines read from standard output after executing the Invocation.
6
9
  attr_reader :lines
7
10
 
8
- # Define the failure message
11
+ # Define a block which runs after a test fails and should return
12
+ # a failure message template.
13
+ #
14
+ # The template is used for both positive and negative failures.
15
+ # Substrings which look like this <tt>"[positive|negative]</tt>" will
16
+ # be replaced with the appropriate section. For example
17
+ # message { "to [show|not show] the default help text" }
18
+ #
19
+ # would read "expected cog to show the default help text"
20
+ # for a positive failure and "expected cog to not show the
21
+ # default help text" for a negative failure. The "expected cog"
22
+ # part is inserted automatically.
9
23
  def message(&block)
10
24
  @msg_block = block
11
25
  end
12
26
 
13
- # Define a block which runs before the Invocation
27
+ # Define a block which runs before the Invocation.
28
+ #
29
+ # This is not required, but can be used to save context that is used
30
+ # the in post invocation #test.
14
31
  def before(&block)
15
32
  @before_block = block
16
33
  end
17
34
 
18
35
  # Define the test which runs after the Invocation
36
+ #
37
+ # This can make use of instance variables set during #before.
19
38
  def test(&block)
20
39
  @test_block = block
21
40
  end
@@ -40,6 +59,18 @@ module Cog
40
59
  end
41
60
  end
42
61
 
62
+ # Makes it easy to write RSpec matchers
63
+ #
64
+ # Here is how the matcher for Matchers#show_help is written using this method
65
+ # #match_maker method.
66
+ # def show_help
67
+ # match_maker do
68
+ # message { "to [show|not show] the default help text, got #{lines.first.inspect}" }
69
+ # test { (/help.*code gen/ =~ lines[1]) }
70
+ # end
71
+ # end
72
+ #
73
+ # Within the +match_maker+ block, +self+ is set to an instance of MatchMaker.
43
74
  def match_maker(&block)
44
75
  m = MatchMaker.new
45
76
  m.instance_eval &block
@@ -22,7 +22,8 @@ module Cog
22
22
  end
23
23
 
24
24
  # Represents a +cog+ command line invocation, which can be tested with
25
- # +RSpec+ +should+ and +should_not+ custom Matchers
25
+ # +RSpec+ +should+ and +should_not+ custom Matchers. This is the kind of
26
+ # object returned by Runner#run.
26
27
  class Invocation
27
28
 
28
29
  def initialize(cmd) # :nodoc:
@@ -36,7 +37,7 @@ module Cog
36
37
  end
37
38
  end
38
39
 
39
- def to_s
40
+ def to_s # :nodoc:
40
41
  "`#{@s}`"
41
42
  end
42
43
  end
@@ -3,30 +3,17 @@ require 'cog/generator'
3
3
 
4
4
  module Cog
5
5
 
6
+ # For more details on writing tools see https://github.com/ktonon/cog#tools
6
7
  class Tool
7
8
 
8
- # Lower case command-line version of the name
9
- attr_reader :name
10
-
11
- # Capitalized module name
12
- attr_reader :module_name
13
-
14
- # Name of the person who will be given copyright for the generated code
15
- attr_reader :author
16
-
17
- # Email address of the author
18
- attr_reader :email
19
-
20
- # A one-line description of the tool
21
- attr_reader :description
22
-
23
9
  # A list of available tools
24
- def self.available
10
+ def self.list
25
11
  # TODO: use paths to instantiate a list of Tool objects
26
12
  paths = ENV['COG_TOOLS'] || []
27
13
  end
28
14
 
29
- def self.generate_tool(name)
15
+ # Generate a new tool with the given name
16
+ def self.create(name)
30
17
  Object.new.instance_eval do
31
18
  class << self ; include Generator ; end
32
19
  @name = name.to_s.downcase
@@ -1,3 +1,3 @@
1
1
  module Cog
2
- VERSION = '0.0.11' unless const_defined? :VERSION
2
+ VERSION = '0.0.12' unless const_defined? :VERSION
3
3
  end
@@ -0,0 +1,11 @@
1
+ require 'cog'
2
+
3
+ class <%= @class_name %>
4
+ include Cog::Generator
5
+
6
+ def generate
7
+ # TODO: create a template and use stamp here to generate source code
8
+ end
9
+ end
10
+
11
+ <%= @class_name %>.new.generate
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: 9
4
+ hash: 7
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
8
  - 0
9
- - 11
10
- version: 0.0.11
9
+ - 12
10
+ version: 0.0.12
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-03 00:00:00 Z
18
+ date: 2012-11-04 00:00:00 Z
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
21
21
  name: rake
@@ -57,6 +57,7 @@ files:
57
57
  - bin/cog
58
58
  - Default.cogfile
59
59
  - LICENSE
60
+ - templates/cog/generator/basic.rb.erb
60
61
  - templates/cog/snippets/c++/generated_warning.h.erb
61
62
  - templates/cog/snippets/generated_warning.txt
62
63
  - templates/cog/tool/API.rdoc.erb